/** * Local MCP (Model Context Protocol) Client Manager for stdio transport * * This module manages local MCP servers that run as child processes using stdio transport. * Local MCP servers are defined in mcp.json configuration file in the working directory. * * Tool naming follows the same convention as remote MCPs: * - Tools are prefixed with server name: `mcp__servername__toolname` * - This prevents conflicts with built-in tools and other MCP tools */ import type { ContentMessageItemImage, ContentMessageItemText, MCPClientStatus, MCPServerConfig } from "#ai-utils"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import type { DevToolsSys } from "../core"; export interface MCPServerStdioDefinition { name: string; command: string; args?: string[]; env?: Record; envFile?: string; retries?: number; /** * Where this server was discovered. Drives precedence on name collision: * `project` > `user` > `plugin`. Set by the loader, not by the config file. */ scope?: "project" | "user" | "plugin"; /** * Name of the plugin that contributed this server, if any. Set by the * plugin loader (Phase 2); always `undefined` for project-level and * user-level standalone configs (Phase 1). */ pluginName?: string; } export interface MCPServerRemoteDefinition { name: string; type: "http" | "sse"; url: string; headers?: Record; sessionId?: string; envFile?: string; /** * Where this server was discovered. Drives precedence on name collision: * `project` > `user` > `plugin`. Set by the loader, not by the config file. */ scope?: "project" | "user" | "plugin"; /** * Name of the plugin that contributed this server, if any. Set by the * plugin loader (Phase 2); always `undefined` for project-level and * user-level standalone configs (Phase 1). */ pluginName?: string; } export type MCPServerDefinition = MCPServerStdioDefinition | MCPServerRemoteDefinition; export interface MCPConfig { mcpServers: Record | Omit>; } export interface LocalMCPClient { client: Client | undefined; transport: StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport | undefined; status: MCPClientStatus; serverName: string; normalizedServerName: string; serverType: "stdio" | "http" | "sse"; command?: string; url?: string; resources?: { uri: string; name?: string; description?: string; mimeType?: string; }[]; } export interface LocalMCPClientManager { clients: LocalMCPClient[]; listTools: () => { name: string; description?: string; inputSchema?: any; serverName: string; }[]; callTool: (name: string, args?: any, signal?: AbortSignal) => Promise<{ content: (ContentMessageItemText | ContentMessageItemImage)[]; isError?: boolean; }>; getResources: (serverName?: string) => Array<{ uri: string; name?: string; description?: string; mimeType?: string; serverName: string; text?: string; }>; getStatus: () => Record; cleanup: () => Promise; } /** * Create a local MCP client manager from server definitions */ export declare function createLocalMCPClientManager(servers: MCPServerDefinition[], sys: DevToolsSys, workingDirectory: string, signal?: AbortSignal): Promise; /** * Apply environment variable substitution to MCP server configuration * This is separated from loadMCPConfig to allow easy unit testing */ export declare function applyEnvSubstitution(serverConfig: Omit, name: string, baseEnv: Record, envFileVars: Record): MCPServerStdioDefinition; /** * Apply environment variable substitution to remote MCP server configuration * This is separated from loadMCPConfig to allow easy unit testing */ export declare function applyEnvSubstitutionRemote(serverConfig: Omit, name: string, baseEnv: Record, envFileVars: Record): MCPServerRemoteDefinition; /** * Discover and load MCP configuration from working directory and fusionConfig * Servers from fusionConfig will be merged with servers from mcp.json * If a server with the same name exists in both, fusionConfig takes precedence * Supports both stdio (command-based) and remote (http/sse) server definitions * * Precedence (lowest → highest): * 1. ~/.builder/mcp.json (user-level) * 2. /mcp.json (project-level) * 3. serverConfigs from fusionConfig * * @param homeDir Override for the user's home directory (for testing). */ export declare function loadMCPConfig(sys: DevToolsSys, workingDirectory: string, serverConfigs: MCPServerConfig, autoImportLocalMCPs: boolean, signal?: AbortSignal, homeDir?: string): Promise;