Overview
ManyAI Desktop implements an MCP (Model Context Protocol) client. It connects to external MCP servers — stdio child processes or HTTP endpoints — and exposes their tools dynamically to the agent loop. MCP tools are namespaced and merged with the 9 native agent tools at the start of every agent run.
McpClientManager (src/main/mcp.ts)
Singleton in the main process. Manages connection lifecycle for all configured MCP servers. Server configurations are persisted to userData/mcp-servers.json and all saved servers are reconnected on app start.
| Method | Description |
|---|---|
connect(config) | Spawns or connects to a server, lists its tools, stores the client |
disconnect(name) | Closes the transport and removes the client from memory |
addServer(config) | Upserts config to disk, disconnects any existing connection, reconnects |
removeServer(name) | Disconnects and removes config from disk |
connectAll() | Called at app start — reconnects all saved configs silently |
listAllTools() | Returns flat list of all tools from all connected servers |
callTool(serverName, toolName, args) | Forwards a tool call to the named server; returns result string |
SDK & Transports
Uses @modelcontextprotocol/sdk@1.29.0 — Anthropic's official MCP client SDK.
- stdio:
StdioClientTransport— spawns a child process, communicates over stdin/stdout. Suitable for local MCP servers (e.g.npx @modelcontextprotocol/server-filesystem). - HTTP:
StreamableHTTPClientTransport— connects to a remote HTTP endpoint. Suitable for cloud-hosted MCP servers.
Server Config Schema
interface McpServerConfig {
name: string // unique identifier — used as the namespace prefix
transport: 'stdio' | 'http'
// stdio fields:
command?: string // e.g. "npx"
args?: string[] // e.g. ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
env?: Record<string, string> // extra environment variables for the child process
// http fields:
url?: string // e.g. "http://localhost:3000"
}
IPC Channels (src/main/ipc/mcpIpc.ts)
| Channel | Description |
|---|---|
mcp-list-servers | Returns all configs + live status (connected/error) and tool count per server |
mcp-add-server | Upserts a server config and connects; returns { ok, error? } |
mcp-remove-server | Disconnects and removes config from disk |
mcp-reconnect | Disconnects and reconnects a named server; returns { ok, error? } |
mcp-list-tools | Returns all tools from all connected servers: fullName, description, inputSchema, serverName |
mcp-call-tool | Calls a tool on a named server with args; returns { result } or { error } |
Tool Naming Convention
All MCP tools are prefixed to prevent collisions with native agent tools:
mcp__<serverName>__<toolName>
Examples: mcp__filesystem__read_file, mcp__my-db__query_table. Native tools never begin with mcp__, so dispatch routing is unambiguous.
Agent Loop Integration
At the start of every runAgentLoop() call (src/renderer/src/lib/agentLoop.ts):
- Calls
window.api.listTools()to discover all currently-connected MCP tools - Builds a
mcpToolIndex: Map<string, { serverName, toolName }> - Converts each MCP tool to OpenAI function format via
buildMcpToolDef() - Merges MCP defs with the 9 native tools into
allTools - Sends the merged list to the model in every API call within the run
When the model calls an MCP tool, executeTool() detects the mcp__ prefix, looks up the entry in mcpToolIndex, and forwards to window.api.callTool(serverName, toolName, args). The result is a plain string tool result returned to the model. MCP tools display the 🔌 emoji in the agent event log.
McpTool Interface (src/preload/types/mcp.ts)
interface McpTool {
name: string // raw tool name as reported by the server
fullName: string // namespaced: mcp__serverName__name
description?: string
inputSchema: Record<string, unknown> // JSON Schema for parameters
serverName: string // which server this tool came from
}
Settings UI (src/renderer/src/features/settings/McpScreen.tsx)
Accessible via Settings → MCP tab. Features:
- Server list: name, status dot (colored by connected/error), tool count, command+args or URL
- Add Server form: name, transport selector, command/args/env fields (stdio) or URL field (HTTP)
- Edit button: pre-fills the form with the existing config; name field is locked (
readOnly) during edit; save button label changes to "Save & Reconnect" - Reconnect button: triggers a disconnect + reconnect cycle in place
- Remove button: disconnects and deletes the config permanently
- Tool viewer (ToolList): shown at the bottom when at least one server has connected tools — lists each tool's fullName and description