fix(mcp): carry requestIdFormat through MCP config discovery

The option was only present on the transport-facing `MCPServerConfig`, so a
value written in `.omp/mcp.json` or a standalone `.mcp.json` never reached the
transports: discovery normalizes config into the canonical `MCPServer` shape and
`convertToLegacyConfig()` rebuilds the transport config from it, and neither step
knew about the field. Setting `"number"` in the documented config path silently
kept the snowflake-string default, which is the hang the option exists to avoid.

Wire it through the same four places `timeout` already uses: the canonical
`MCPServer` shape, the two OMP-native loaders (with validate-and-warn on an
unrecognized value), and the legacy conversion. Foreign-format providers are
untouched, since the key is OMP-specific.

Also point the `MCPServerConfigBase` doc comment at `RequestIdAllocator` rather
than a helper name that never existed.
This commit is contained in:
Jérémy Marchand
2026-07-31 21:03:06 +02:00
parent fa9aa68218
commit 3cb6e5df9c
6 changed files with 113 additions and 1 deletions
@@ -23,6 +23,7 @@ import { type SlashCommand, slashCommandCapability } from "../capability/slash-c
import { type SystemPrompt, systemPromptCapability } from "../capability/system-prompt";
import { type CustomTool, toolCapability } from "../capability/tool";
import type { LoadContext, LoadResult } from "../capability/types";
import type { MCPRequestIdFormat } from "../mcp/types";
import { expandTilde } from "../tools/path-utils";
import {
buildRuleFromMarkdown,
@@ -154,10 +155,23 @@ async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>>
timeout = undefined;
}
// Validate requestIdFormat: only the two documented encodings
let requestIdFormat: MCPRequestIdFormat | undefined;
if (serverConfig.requestIdFormat !== undefined && serverConfig.requestIdFormat !== null) {
if (serverConfig.requestIdFormat === "string" || serverConfig.requestIdFormat === "number") {
requestIdFormat = serverConfig.requestIdFormat;
} else {
logger.warn(
`MCP server "${serverName}": invalid requestIdFormat ${JSON.stringify(serverConfig.requestIdFormat)}, ignoring`,
);
}
}
result.push({
name: serverName,
enabled,
timeout,
requestIdFormat,
command: serverConfig.command as string | undefined,
args: serverConfig.args as string[] | undefined,
env: serverConfig.env as Record<string, string> | undefined,
@@ -26,6 +26,7 @@ interface MCPConfigFile {
{
enabled?: boolean;
timeout?: number;
requestIdFormat?: "string" | "number";
command?: string;
args?: string[];
env?: Record<string, string>;
@@ -83,10 +84,23 @@ function transformMCPConfig(config: MCPConfigFile, source: SourceMeta): MCPServe
}
}
let requestIdFormat: "string" | "number" | undefined;
if (serverConfig.requestIdFormat !== undefined) {
if (serverConfig.requestIdFormat === "string" || serverConfig.requestIdFormat === "number") {
requestIdFormat = serverConfig.requestIdFormat;
} else {
logger.warn("MCP server has invalid 'requestIdFormat' value, ignoring", {
name,
value: serverConfig.requestIdFormat,
});
}
}
const server: MCPServer = {
name,
enabled,
timeout,
requestIdFormat,
command: serverConfig.command,
args: serverConfig.args,
env: serverConfig.env,