MCP & A2A Integration Guide

OpenFang implements both the Model Context Protocol (MCP) and Agent-to-Agent (A2A) protocol, enabling deep interoperability with external tools, IDEs, and other agent frameworks.

Table of Contents

Part 1: MCP (Model Context Protocol)

MCP Overview

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:

  • As a client: OpenFang connects to external MCP servers (GitHub, filesystem, databases, Puppeteer, etc.) and makes their tools available to all agents.
  • As a server: OpenFang exposes its own agents as MCP tools, so IDEs like Cursor, VS Code, and Claude Desktop can call OpenFang agents directly.

OpenFang implements MCP protocol version 2024-11-05.

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 (McpServerConfigEntry, McpTransportEntry)

MCP Client

The MCP client (McpConnection in openfang-runtime) 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"]

Advanced MCP Server Configuration

Each entry maps to a McpServerConfigEntry struct:

Field Type Default Description
name String required Display name, used in tool namespacing
transport McpTransportEntry required How to connect (stdio or SSE)
timeout_secs u64 30 JSON-RPC request timeout
env Vec<String> [] Env vars to pass through to the subprocess

Transport Types

OpenFang supports two MCP transports, defined by McpTransport:

Stdio -- 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"]

SSE -- Connects to a remote HTTP endpoint and sends JSON-RPC via POST:

[mcp_servers.transport]
type = "sse"
url = "https://mcp.example.com/api"

Tool Connectivity Lifecycle

The McpConnection struct manages the lifetime of the connection:

pub struct McpConnection {
    config: McpServerConfig,
    tools: Vec<ToolDefinition>,
    transport: McpTransportHandle,  // Stdio or SSE
    next_id: u64,                   // JSON-RPC request counter
}

When the connection is dropped, stdio subprocesses are automatically killed via Drop:

impl Drop for McpConnection {
    fn drop(&mut self) {
        if let McpTransportHandle::Stdio { ref mut child, .. } = self.transport {
            let _ = child.start_kill();
        }
    }
}

MCP Server

OpenFang can also 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.

For example, an agent named code-reviewer becomes the MCP tool openfang_agent_code_reviewer.

Supported JSON-RPC Methods

Method Description
initialize Handshake; returns server capabilities and info
notifications/initialized Client confirmation; no response
tools/list Returns all available tools with names, descriptions, and input schemas
tools/call Executes a tool and returns the result

Task Lifecycle

An A2aTask tracks the full lifecycle of a cross-agent interaction.

Status Description
Submitted Task received but not yet started
Working Task is being actively processed by the agent
Completed Task finished successfully
Cancelled Task was cancelled by the caller
Failed Task encountered an error

Part 2: A2A (Agent-to-Agent Protocol)

A2A Overview

The Agent-to-Agent (A2A) protocol enables cross-framework agent interoperability, allowing agents built with different frameworks to discover each other's capabilities and exchange tasks.

OpenFang implements A2A in both directions:

  • As a server: Publishes Agent Cards describing each agent's capabilities, accepts task submissions, and tracks task lifecycle.
  • As a client: Discovers external A2A agents at boot time, sends tasks to them, and polls for results.

Agent Card

An Agent Card is a JSON document that describes an agent's identity, capabilities, and supported interaction modes. It is served at the well-known path /.well-known/agent.json per the A2A specification.

Example card:

{
  "name": "code-reviewer",
  "description": "Reviews code for bugs, security issues, and style",
  "url": "http://127.0.0.1:50051/a2a",
  "version": "0.1.0",
  "capabilities": {
    "streaming": true,
    "pushNotifications": false,
    "stateTransitionHistory": true
  },
  "skills": [
    {
      "id": "file_read",
      "name": "file read",
      "description": "Can use the file_read tool",
      "tags": ["tool"],
      "examples": []
    }
  ],
  "defaultInputModes": ["text"],
  "defaultOutputModes": ["text"]
}

A2A API Endpoints

Method Path Auth Description
GET /.well-known/agent.json Public Agent Card for the primary agent
POST /a2a/tasks/send Public Submit a task to an agent

A2A Configuration

A2A is configured in config.toml under the [a2a] section:

[a2a]
enabled = true
listen_path = "/a2a"

[[a2a.external_agents]]
name = "research-agent"
url = "https://research.example.com"

Security

MCP Security

  • Subprocess Sandboxing: Stdio MCP servers run with env_clear() to prevent leaking secrets to untrusted MCP server processes.
  • Request Timeout: All MCP requests have a configurable timeout (default 30 seconds) to prevent hung connections.

A2A Security

  • Rate Limiting: A2A endpoints go through the same GCRA rate limiter as all other API endpoints.
  • Task Store Bounds: The A2aTaskStore is bounded with FIFO eviction of completed/failed/cancelled tasks, preventing memory exhaustion from task accumulation.