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:

  1. CLI Argument Parsing – Accepts --session-id, --workspace-root, and --plans-folder to establish the execution context.
  2. Context Building – Constructs a SessionToolContext that wraps the filesystem, credential manager, and UI callbacks (sendCallback).
  3. Tool Registration – Registers the canonical session tool registry via getSessionToolRegistry and connects upstream documentation tools via connectDocsUpstream.
  4. Custom Handlers – Provides backend-specific implementations for call_llm and spawn_session that 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_llm and spawn_session receive special handling that may use pre-computed results (Codex) or HTTP callbacks to the UI via CRAFT_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-server package (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_llm or spawn_session, with special routing for UI interactions via stderr callbacks.
  • Build automation in scripts/electron-dev.ts compiles 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →