What Are MCP Servers and How Craft Agents Integrates With Them
MCP (Model Context Protocol) servers are stdio-based subprocesses that expose session-scoped tools to LLM backends via JSON-RPC, and Craft Agents integrates with them by launching these servers as child processes that bridge filesystem access, credential management, and UI callbacks.
Craft Agents OSS uses the Model Context Protocol to decouple LLM tool execution from the main Electron application. According to the craft-ai-agents/craft-agents-oss source code, MCP servers run as isolated subprocesses that communicate over stdin/stdout, allowing the LLM (Claude, Pi) to invoke tools like call_llm and spawn_session while maintaining secure session isolation.
Understanding MCP Servers in Craft Agents
An MCP server in Craft Agents is a Node.js subprocess that implements the Model Context Protocol specification. It runs as a stdio transport subprocess, meaning all JSON-RPC messages pass through the process's standard input and output streams.
The architecture follows this pattern:
Craft Agents (Electron main process)
│
├─ builds MCP servers (session-mcp-server, pi-agent-server)
│
├─ launches the MCP servers as child processes
│
│ ↳ each server creates a SessionToolContext that provides
│ • access to workspace files (sessions, sources, skills)
│ • credential cache reading via .credential-cache.json
│ • callbacks to the Electron UI (plan submitted, auth requests)
│
└─ LLM SDK (Claude Agent SDK / Pi SDK) invokes tools via the
MCP JSON-RPC endpoint (stdin/stdout)
Core MCP Server Implementation
The primary implementation resides in packages/session-mcp-server/src/index.ts. This file handles CLI argument parsing, tool registration, and the stdio server lifecycle.
Key Responsibilities
The session MCP server performs four critical functions:
- CLI Argument Parsing – Accepts
--session-id,--workspace-root, and--plans-folderto establish the execution context. - Context Building – Constructs a
SessionToolContextthat wraps the filesystem, credential manager, and UI callbacks (sendCallback). - Tool Registration – Registers the canonical session tool registry via
getSessionToolRegistryand connects upstream documentation tools viaconnectDocsUpstream. - Custom Handlers – Provides backend-specific implementations for
call_llmandspawn_sessionthat may use pre-computed results or HTTP callbacks.
The server runs using @modelcontextprotocol/sdk/server/stdio, ensuring all communication occurs over the subprocess's stdin/stdout streams.
Building the MCP Servers
The Electron development script at scripts/electron-dev.ts compiles MCP servers before starting the UI. It resolves source directories and runs esbuild to bundle the TypeScript:
const SESSION_SERVER_DIR = join(ROOT_DIR, "packages/session-mcp-server");
const SESSION_SERVER_OUTPUT = join(SESSION_SERVER_DIR, "dist/index.js");
const sessionResult = await runEsbuild(
"packages/session-mcp-server/src/index.ts",
"packages/session-mcp-server/dist/index.js",
{},
{ packagesExternal: true }
);
After building, the script launches the Electron renderer alongside MCP server processes, wiring environment variables like CRAFT_LLM_CALLBACK_PORT for UI communication.
How Craft Agents Consumes MCP Tools
The integration follows a four-stage pipeline for tool discovery and execution.
1. Tool Discovery
When a session starts, the Electron main process queries the MCP server for available tools using ListToolsRequestSchema. The server returns the union of session tools (from getSessionToolRegistry) and docs-upstream tools (from the Craft Agents Docs MCP).
2. Tool Execution
The LLM SDK sends a CallToolRequest over the MCP channel. The server's request handler routes the request accordingly:
call_llmandspawn_sessionreceive special handling that may use pre-computed results (Codex) or HTTP callbacks to the UI viaCRAFT_LLM_CALLBACK_PORT.- All other tools dispatch to canonical handlers in
@craft-agent/session-tools-core.
3. Callbacks to the UI
For actions requiring UI interaction—such as displaying a plan or prompting OAuth authorization—the server writes a line prefixed with __CALLBACK__ to stderr. The Electron main process reads this line, parses the JSON, and updates the UI accordingly (see packages/session-mcp-server/src/index.ts lines 69-77).
4. Credential Handling
The server reads stored credentials from per-source cache files (.credential-cache.json), created by the main process after decrypting the user's vault. This design avoids direct keychain access from the subprocess (see packages/session-mcp-server/src/index.ts lines 91-104).
Practical Integration Examples
Starting a Session MCP Server Programmatically
You can spawn the MCP server directly from Node.js using the child_process API:
import { spawn } from "child_process";
const proc = spawn("node", [
"packages/session-mcp-server/dist/index.js",
"--session-id", "sess-01",
"--workspace-root", "~/.craft-agent/workspaces/ws-01",
"--plans-folder", "~/.craft-agent/workspaces/ws-01/plans",
]);
proc.stdout.on("data", data => console.log("[MCP STDOUT]", data.toString()));
proc.stderr.on("data", data => console.log("[MCP CALLBACK]", data.toString()));
Listing Tools from the MCP Server
Client-side code uses the MCP SDK to discover available tools:
import { Client } from "@modelcontextprotocol/sdk/client";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio";
const client = new Client({ name: "demo", version: "1.0" }, { capabilities: {} });
await client.connect(new StdioClientTransport(proc.stdin, proc.stdout));
const { tools } = await client.listTools();
console.log("Available MCP tools:", tools.map(t => t.name));
Invoking an MCP Tool
To execute a tool like call_llm:
const result = await client.callTool({
name: "call_llm",
arguments: { prompt: "Summarise the last 5 messages." },
});
console.log("LLM reply:", result.content);
MCP Source Configuration
Users configure MCP servers via JSON in ~/.craft-agent/workspaces/<workspace>/sources/craft/config.json:
{
"id": "craft",
"name": "Craft",
"slug": "craft",
"enabled": true,
"provider": "craft",
"type": "mcp",
"mcp": {
"transport": "stdio",
"command": "node",
"args": [
"packages/session-mcp-server/dist/index.js",
"--session-id", "{sessionId}",
"--workspace-root", "{workspaceRoot}",
"--plans-folder", "{plansFolder}"
]
}
}
The source-builder at packages/shared/src/sources/server-builder.ts parses this configuration to spin up the appropriate MCP server when the workspace opens.
Summary
- MCP servers in Craft Agents are stdio-based subprocesses that expose tools via JSON-RPC, keeping LLM interactions isolated from the main application.
- The
session-mcp-serverpackage (packages/session-mcp-server/src/index.ts) implements the core protocol, handling tool registration, credential caching, and UI callbacks. - Tool execution flows from the LLM SDK through the MCP JSON-RPC layer to specific handlers like
call_llmorspawn_session, with special routing for UI interactions via stderr callbacks. - Build automation in
scripts/electron-dev.tscompiles the MCP servers using esbuild and manages their lifecycle alongside the Electron main process. - Configuration uses JSON files defining stdio transport parameters, parsed by the server-builder to establish workspace-specific tool contexts.
Frequently Asked Questions
What transport protocol does Craft Agents use for MCP servers?
Craft Agents uses stdio transport for all MCP server communication. The server processes read JSON-RPC requests from stdin and write responses to stdout, with UI callbacks sent via stderr using the __CALLBACK__ prefix. This approach is defined in packages/session-mcp-server/src/index.ts and configured in the MCP source JSON via "transport": "stdio".
How does Craft Agents handle authentication credentials in MCP servers?
MCP servers read credentials from .credential-cache.json files rather than accessing the system keychain directly. The Electron main process decrypts the user's vault and writes these cache files before launching the MCP server, which then reads them via the SessionToolContext. This isolation prevents the subprocess from needing direct keychain access while maintaining secure credential availability.
Can I run the Craft Agents MCP server manually outside of Electron?
Yes. You can start the session MCP server manually using Node.js with the required CLI arguments: --session-id, --workspace-root, and --plans-folder. The command follows this pattern: node packages/session-mcp-server/dist/index.js --session-id <id> --workspace-root <path> --plans-folder <path>. This is useful for debugging or integrating with external toolchains.
What is the difference between session tools and docs-upstream tools in the MCP server?
Session tools are defined in the canonical registry (getSessionToolRegistry) and provide core functionality like call_llm and spawn_session. Docs-upstream tools are fetched via connectDocsUpstream and provide documentation-specific capabilities. The MCP server merges both collections when responding to ListToolsRequestSchema, presenting them as a unified tool set to the LLM backend.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →