feat(mcp): adopt mainstream server-qualified MCP tool naming

Research across 8 multi-server agent clients (Claude Code, Codex, Gemini
CLI, VS Code, Cline, Roo Code, Goose, OpenCode) showed all of them keep
the server namespace in model-facing MCP tool names; the RFC's premise
for raw names ("servers already prefix their tools") is false for the
official GitHub/filesystem/Sentry servers.

- Config: drop toolPrefix; require serverName ([A-Za-z0-9_-]{1,32}),
  duplicate serverName fails the later instance at load (per-root
  reservation, released on dispose)
- Names: always mcp__<serverName>__<rawName>; normalize to the DeepSeek
  64-char [A-Za-z0-9_-] contract with a deterministic 12-hex identity
  hash on lossy normalization; raw name is the only thing sent on the
  wire (tools/call)
- Sync: two-phase fetch/swap — fetch failure keeps the previous
  generation; a swap conflict rolls back the whole generation (never a
  partial set); duplicate raw names reject the tool list
- RFC: moved to implemented/ (status + skeleton rewritten per the
  format contract), naming design + tier-level test coverage recorded
- Tests: naming algorithm unit suite; keyless Streamable HTTP e2e
  against an in-process StreamableHTTPServerTransport (namespace
  discovery, execution, per-request auth headers); dotted-name
  normalization e2e via a new fixture tool
This commit is contained in:
lintianle
2026-07-13 23:39:02 +08:00
parent 7fff51d848
commit af3152fefe
11 changed files with 923 additions and 422 deletions
+13 -5
View File
@@ -365,6 +365,12 @@ export type Config = StdioConfig | StreamableHttpConfig
export interface StdioConfig {
/** Transport type: spawn a child process and communicate over stdio. */
transport: 'stdio'
/**
* Stable local namespace for this server's model-facing tool names
* (`mcp__<serverName>__<rawName>`). Must match `[A-Za-z0-9_-]{1,32}` and be
* unique across live mcp-client instances.
*/
serverName: string
/** Executable to spawn. */
command: string
/** Arguments passed to the command. */
@@ -373,8 +379,6 @@ export interface StdioConfig {
env: Record<string, string>
/** Working directory for the child process. */
cwd: string
/** Prefix prepended to each tool name before registration. */
toolPrefix: string
/** Timeout per callTool invocation (ms). */
toolCallTimeoutMs: number
}
@@ -383,18 +387,22 @@ export interface StdioConfig {
export interface StreamableHttpConfig {
/** Transport type: connect to an MCP server over Streamable HTTP (SSE). */
transport: 'streamable-http'
/**
* Stable local namespace for this server's model-facing tool names
* (`mcp__<serverName>__<rawName>`). Must match `[A-Za-z0-9_-]{1,32}` and be
* unique across live mcp-client instances.
*/
serverName: string
/** MCP server URL. */
url: string
/** Extra headers (e.g. auth tokens). */
headers: Record<string, string>
/** Prefix prepended to each tool name before registration. */
toolPrefix: string
/** Timeout per callTool invocation (ms). */
toolCallTimeoutMs: number
}
```
Source: [`packages/mcp/mcp-client/src/index.ts:66`](../packages/mcp/mcp-client/src/index.ts)
Source: [`packages/mcp/mcp-client/src/index.ts:91`](../packages/mcp/mcp-client/src/index.ts)
## `@deepseek-ai/dsh-session-persistence-jsonl`