Why this matters
MCPTool.ts is intentionally generic. If you only read that file, you do not
yet know what a real per-server MCP tool looks like.
Big picture first
The MCP story has two layers:
tools/MCPTool/MCPTool.tsdefines a reusable shell with generic prompt, schema, permission, and rendering behavior.services/mcp/client.tsclones that shell and overrides it with real server names, schemas, and call behavior.
The client bridge starts in fetchToolsForClient(...).
The generic wrapper
// Actual prompt and description are overridden in mcpClient.ts
export const PROMPT = ''
export const DESCRIPTION = ''
export const MCPTool = buildTool({
isMcp: true,
name: 'mcp',
maxResultSizeChars: 100_000,
async description() {
return DESCRIPTION
},
async prompt() {
return PROMPT
},
async checkPermissions(): Promise<PermissionResult> {
return {
behavior: 'passthrough',
message: 'MCPTool requires permission.',
}
},
This is the wrapper pattern in one glance. The generic tool exists, but it is waiting for real server-specific data.
The client layer injects the real tool
return toolsToProcess
.map((tool): Tool => {
const fullyQualifiedName = buildMcpToolName(client.name, tool.name)
return {
...MCPTool,
name: skipPrefix ? tool.name : fullyQualifiedName,
mcpInfo: { serverName: client.name, toolName: tool.name },
isMcp: true,
searchHint:
typeof tool._meta?.['anthropic/searchHint'] === 'string'
? tool._meta['anthropic/searchHint']
.replace(/\\s+/g, ' ')
.trim() || undefined
: undefined,
alwaysLoad: tool._meta?.['anthropic/alwaysLoad'] === true,
async description() {
return tool.description ?? ''
},
async prompt() {
const desc = tool.description ?? ''
return desc.length > MAX_MCP_DESCRIPTION_LENGTH
? desc.slice(0, MAX_MCP_DESCRIPTION_LENGTH) + '… [truncated]'
: desc
},
This is the real bridge. services/mcp/client.ts takes the generic shell and
fills in:
- the fully qualified tool name via
buildMcpToolName(...) - the server/tool identity in
mcpInfo - the real prompt and description
- schema metadata like
alwaysLoad - the real
call(...)behavior that eventually invokes the MCP server
That is why MCPTool.ts is useful but incomplete on its own.
Takeaways
- MCPTool is a generic shell, not the full per-server tool definition.
- The real MCP tool shape is assembled in services/mcp/client.ts.
- Names, prompts, schemas, and call behavior are all injected at the client layer.