Skip to main content
The Model Context Protocol (MCP) is a JSON-RPC 2.0 based protocol that standardizes how LLM applications discover and invoke tools. OpenFang supports MCP in both directions:

MCP Client

Connect to external MCP servers and use their tools

MCP Server

Expose OpenFang agents as MCP tools to IDEs
OpenFang implements MCP protocol version 2024-11-05.

MCP Client

The MCP client allows OpenFang to connect to any MCP-compatible server and use its tools as if they were built-in.

Configuration

MCP servers are configured in config.toml using the [[mcp_servers]] array:
[[mcp_servers]]
name = "github"
timeout_secs = 30
env = ["GITHUB_PERSONAL_ACCESS_TOKEN"]

[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]

Configuration Fields

FieldTypeDefaultDescription
nameStringrequiredDisplay name, used in tool namespacing
transportMcpTransportEntryrequiredHow to connect (stdio or SSE)
timeout_secsu6430JSON-RPC request timeout
envVec<String>[]Env vars to pass through to subprocess

Transport Types

Spawns a subprocess and communicates via stdin/stdout with newline-delimited JSON-RPC:
[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
The subprocess environment is cleared and only explicitly whitelisted variables (in env field) plus PATH are passed through.
Connects to a remote HTTP endpoint and sends JSON-RPC via POST:
[mcp_servers.transport]
type = "sse"
url = "https://mcp.example.com/api"
URLs are validated to prevent SSRF attacks against metadata endpoints.

Tool Namespacing

All tools discovered from MCP servers are namespaced using the pattern mcp_{server}_{tool} to prevent collisions:

Example 1

Server: github
Tool: create_issue
Result: mcp_github_create_issue

Example 2

Server: my-server
Tool: do_thing
Result: mcp_my_server_do_thing
Helper functions (exported from openfang_runtime::mcp):
  • format_mcp_tool_name(server, tool) — builds the namespaced name
  • is_mcp_tool(name) — checks if a tool name starts with mcp_
  • extract_mcp_server(tool_name) — extracts the server name from a namespaced tool

Auto-Connection on Kernel Boot

When the kernel starts, it automatically connects to configured MCP servers:
1

Read configuration

Iterates each McpServerConfigEntry in the config
2

Establish connection

Spawns subprocess (stdio) or creates HTTP client (SSE)
3

Initialize handshake

Sends initialize request with client info, followed by notifications/initialized
4

Discover tools

Calls tools/list to discover all available tools and namespaces them
5

Cache tools

Stores discovered ToolDefinition entries in kernel.mcp_tools and live connections in kernel.mcp_connections

Connection Lifecycle

The McpConnection struct manages the lifetime:
pub struct McpConnection {
    config: McpServerConfig,
    tools: Vec<ToolDefinition>,
    transport: McpTransportHandle,  // Stdio or SSE
    next_id: u64,                   // JSON-RPC request counter
}
When dropped, stdio subprocesses are automatically killed:
impl Drop for McpConnection {
    fn drop(&mut self) {
        if let McpTransportHandle::Stdio { ref mut child, .. } = self.transport {
            let _ = child.start_kill();
        }
    }
}

Configuration Examples

Provides file, issue, and PR tools:
[[mcp_servers]]
name = "github"
timeout_secs = 30
env = ["GITHUB_PERSONAL_ACCESS_TOKEN"]

[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
Provides file read/write tools:
[[mcp_servers]]
name = "filesystem"
timeout_secs = 10
env = []

[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
Provides database query tools:
[[mcp_servers]]
name = "postgres"
timeout_secs = 30
env = ["DATABASE_URL"]

[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-postgres"]
Provides browser automation tools:
[[mcp_servers]]
name = "puppeteer"
timeout_secs = 60

[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-puppeteer"]
Connect to remote MCP server:
[[mcp_servers]]
name = "remote-tools"
timeout_secs = 30

[mcp_servers.transport]
type = "sse"
url = "https://tools.example.com/mcp"
Configure multiple MCP servers simultaneously:
[[mcp_servers]]
name = "github"
env = ["GITHUB_PERSONAL_ACCESS_TOKEN"]
[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]

[[mcp_servers]]
name = "filesystem"
[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]

[[mcp_servers]]
name = "postgres"
env = ["DATABASE_URL"]
[mcp_servers.transport]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-postgres"]

Tool Discovery and Execution

MCP tools are merged into the agent’s available tool set:
built-in tools (23) + skill tools + MCP tools = full tool list
When an agent calls an MCP tool during its loop:
1

Recognize prefix

Tool runner recognizes the mcp_ prefix
2

Find connection

Locates the appropriate McpConnection by server name
3

Strip namespace

Removes the mcp_{server}_ prefix
4

Forward request

Sends tools/call request to the external MCP server

MCP Server

OpenFang can act as an MCP server, exposing its agents as callable tools to external MCP clients.

How It Works

Each OpenFang agent becomes an MCP tool named openfang_agent_{name} (with hyphens replaced by underscores). The tool accepts a single message string parameter and returns the agent’s response.
Example: An agent named code-reviewer becomes the MCP tool openfang_agent_code_reviewer.

CLI: openfang mcp

The primary way to run the MCP server:
openfang mcp
This command:
1

Check for daemon

Looks for a running OpenFang daemon
2

Choose backend

If daemon found, proxies to it via HTTP. Otherwise, boots an in-process kernel.
3

Start stdio server

Reads Content-Length framed JSON-RPC messages from stdin
4

Process requests

Handles MCP requests and writes responses to stdout

HTTP MCP Endpoint

OpenFang also exposes an MCP endpoint over HTTP at POST /mcp.
Unlike the stdio server (which only exposes agents), the HTTP endpoint exposes the full tool set: built-in tools, skills, and MCP tools. This means the HTTP MCP endpoint supports all 23 built-in tools plus installed skill tools and connected MCP server tools.

Supported JSON-RPC Methods

MethodDescription
initializeHandshake; returns server capabilities and info
notifications/initializedClient confirmation; no response
tools/listReturns all available tools with names, descriptions, and input schemas
tools/callExecutes a tool and returns the result
Unknown methods receive a -32601 (Method not found) error.

Protocol Details

Message Framing (stdio mode)

Content-Length: 123\r\n
\r\n
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}
Messages are limited to 10 MB. Oversized messages are drained and rejected.

Initialize Handshake

Request:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": { "name": "cursor", "version": "1.0" }
  }
}
Response:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": { "tools": {} },
    "serverInfo": { "name": "openfang", "version": "0.1.0" }
  }
}

Tool Call

Request:
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "openfang_agent_code_reviewer",
    "arguments": {
      "message": "Review this Python function for security issues..."
    }
  }
}
Response:
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{
      "type": "text",
      "text": "I found 3 potential security issues..."
    }]
  }
}

Connecting from IDEs

Add to your MCP configuration file (.cursor/mcp.json or VS Code MCP settings):
{
  "mcpServers": {
    "openfang": {
      "command": "openfang",
      "args": ["mcp"]
    }
  }
}
Add to claude_desktop_config.json:
{
  "mcpServers": {
    "openfang": {
      "command": "openfang",
      "args": ["mcp"],
      "env": {}
    }
  }
}
After configuration, all OpenFang agents appear as tools in the IDE.

MCP API Endpoints

MethodPathDescription
GET/api/mcp/serversList configured and connected MCP servers with their tools
POST/mcpHandle MCP JSON-RPC requests over HTTP (full tool execution)

GET /api/mcp/servers

Response:
{
  "configured": [
    {
      "name": "github",
      "transport": { "type": "stdio", "command": "npx", "args": [...] },
      "timeout_secs": 30,
      "env": ["GITHUB_PERSONAL_ACCESS_TOKEN"]
    }
  ],
  "connected": [
    {
      "name": "github",
      "tools_count": 12,
      "tools": [
        { "name": "mcp_github_create_issue", "description": "[MCP:github] Create a GitHub issue" },
        { "name": "mcp_github_search_repos", "description": "[MCP:github] Search repositories" }
      ],
      "connected": true
    }
  ]
}

Security

Subprocess Sandboxing

Stdio MCP servers run with env_clear() — environment is completely cleared. Only whitelisted env vars plus PATH are passed through.

Path Traversal Prevention

Command paths are validated to reject .. sequences.

SSRF Protection

SSE transport URLs are checked against metadata endpoints (169.254.169.254, metadata.google).

Request Timeout

All MCP requests have configurable timeout (default 30 seconds).

Message Size Limit

Stdio MCP server enforces 10 MB maximum message size.

Kernel-Level Protection

MCP tool execution flows through the same security pipeline: capability-based access control, tool result truncation (50K cap), 60-second timeout, loop guard detection, and taint tracking.

Source Files

  • Client: crates/openfang-runtime/src/mcp.rs
  • Server handler: crates/openfang-runtime/src/mcp_server.rs
  • CLI server: crates/openfang-cli/src/mcp.rs
  • Config types: crates/openfang-types/src/config.rs