# What Are MCP Servers and How Craft Agents Integrates With Them

> Learn about MCP servers and how Craft Agents seamlessly integrates by launching them as child processes that manage filesystem access, credentials, and UI callbacks for LLM backends.

- Repository: [Craft Ai Agents/craft-agents-oss](https://github.com/craft-ai-agents/craft-agents-oss)
- Tags: how-to-guide
- Published: 2026-07-04

---

**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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/scripts/electron-dev.ts) compiles MCP servers before starting the UI. It resolves source directories and runs **esbuild** to bundle the TypeScript:

```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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/.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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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:

```typescript
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:

```typescript
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`:

```typescript
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`:

```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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/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`](https://github.com/craft-ai-agents/craft-agents-oss/blob/main/.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.