Skip to main content

Model Context Protocol Integration

AgentOS includes a Model Context Protocol (MCP) client that allows agents to connect to external MCP servers and use their tools. MCP provides a standardized way to extend LLM capabilities with external data sources, APIs, and services.

Overview

Implemented in src/mcp-client.ts:1, the MCP integration provides:
  • Stdio and SSE transports for connecting to MCP servers
  • Tool discovery via the tools/list RPC method
  • Tool invocation with automatic request/response handling
  • Connection management with automatic cleanup
  • MCP server mode - Expose AgentOS functions as MCP tools

What is MCP?

Model Context Protocol is a standard for connecting AI assistants to external tools and data sources. An MCP server exposes:
  • Tools - Functions the LLM can call
  • Resources - Data sources the LLM can read
  • Prompts - Pre-built prompt templates
AgentOS focuses on the tools capability.

Available Integrations

From workspace/source/integrations/, AgentOS includes 25+ pre-configured MCP integrations:

GitHub

Repository management, PRs, issues

GitLab

Project management, pipelines, merge requests

Slack

Send messages, read channels

Discord

Bot integration, channel management

Jira

Issue tracking, project management

Linear

Issue tracking, roadmap planning

Notion

Knowledge base, database queries

Google Drive

File access, document management

Gmail

Email sending, inbox reading

Google Calendar

Event creation, schedule management

AWS

S3, EC2, Lambda management

Azure

Azure resource management

GCP

Google Cloud operations

PostgreSQL

Database queries, schema inspection

MongoDB

Document queries, collection management

Redis

Cache operations, pub/sub

Elasticsearch

Search, indexing, analytics

SQLite

Local database access

Sentry

Error tracking, issue management

Dropbox

File storage, sharing

Brave Search

Web search API

Exa Search

Semantic search

Bitbucket

Repository management

Microsoft Teams

Chat, channel management

Todoist

Task management

Connecting to an MCP Server

1

Connect via Stdio

For MCP servers that run as local processes:
import { trigger } from "iii-sdk";

await trigger("mcp::connect", {
  name: "github",
  transport: "stdio",
  command: "npx",
  args: ["-y", "@modelcontextprotocol/server-github"]
});
From src/mcp-client.ts:138-163, this:
  • Validates the command for security
  • Spawns the process with stripped environment variables
  • Parses stdout for JSON-RPC messages
  • Calls initialize to negotiate capabilities
  • Calls tools/list to discover available tools
2

Connect via SSE

For MCP servers that expose HTTP endpoints:
await trigger("mcp::connect", {
  name: "remote-tools",
  transport: "sse",
  url: "https://mcp-server.example.com/sse"
});
Note: SSE transport is defined but not fully implemented in the current version.
3

List discovered tools

const { tools } = await trigger("mcp::list_tools", {});

console.log(`Discovered ${tools.length} tools:`);
for (const tool of tools) {
  console.log(`- [${tool.server}] ${tool.name}: ${tool.description}`);
}
Tools are namespaced as mcp_{server}_{toolName} (see src/mcp-client.ts:267).

Calling MCP Tools

const result = await trigger("mcp::call_tool", {
  server: "github",
  tool: "create_issue",
  arguments: {
    owner: "iii-hq",
    repo: "agentos",
    title: "Add MCP integration tests",
    body: "We need comprehensive tests for the MCP client",
    labels: ["testing", "mcp"]
  }
});

console.log(result);
From src/mcp-client.ts:277-304, the client:
  1. Validates the server connection exists
  2. Checks the tool is available
  3. Sends tools/call RPC to the MCP server
  4. Logs the invocation to security audit
  5. Returns the result

Managing Connections

List Active Connections

const { connections, count } = await trigger("mcp::list_connections", {});

console.log(`${count} active MCP connections:`);
for (const conn of connections) {
  console.log(`- ${conn.name}: ${conn.toolCount} tools (uptime: ${conn.uptime}ms)`);
}
From src/mcp-client.ts:313-325, this returns:
  • Connection ID
  • Server name
  • Transport type
  • Tool count
  • Connection timestamp
  • Uptime in milliseconds

Disconnect from a Server

await trigger("mcp::disconnect", {
  name: "github"
});
From src/mcp-client.ts:212-244, this:
  • Terminates the child process (SIGTERM)
  • Removes the connection from the map
  • Deletes state storage
  • Rejects all pending RPC requests

MCP Server Mode

Expose AgentOS functions as MCP tools to external clients:
1

Define tools to expose

const exposedTools = [
  {
    name: "web_search",
    description: "Search the web for information",
    functionId: "tool::web_search",
    inputSchema: {
      type: "object",
      properties: {
        query: { type: "string", description: "Search query" },
        limit: { type: "number", description: "Max results" }
      },
      required: ["query"]
    }
  },
  {
    name: "agent_chat",
    description: "Chat with an AgentOS agent",
    functionId: "agent::chat",
    inputSchema: {
      type: "object",
      properties: {
        agentId: { type: "string" },
        message: { type: "string" }
      },
      required: ["agentId", "message"]
    }
  }
];
2

Start the MCP server

await trigger("mcp::serve", {
  tools: exposedTools
});

console.log("AgentOS is now an MCP server at http://localhost:3111/mcp/rpc");
From src/mcp-client.ts:328-433, this:
  • Registers a handler function for MCP JSON-RPC requests
  • Handles initialize, tools/list, and tools/call methods
  • Maps tool calls to AgentOS trigger invocations
  • Exposes an HTTP endpoint at /mcp/rpc
3

Stop serving

await trigger("mcp::unserve", {});

Real-World Example: GitHub Integration

// Connect to GitHub MCP server
await trigger("mcp::connect", {
  name: "github",
  transport: "stdio",
  command: "npx",
  args: [
    "-y",
    "@modelcontextprotocol/server-github",
    "--token",
    process.env.GITHUB_TOKEN
  ]
});

// List available GitHub tools
const { tools } = await trigger("mcp::list_tools", {});
const githubTools = tools.filter(t => t.server === "github");

console.log("GitHub tools:", githubTools.map(t => t.name));
// ["create_issue", "list_issues", "create_pull_request", "search_repositories", ...]

// Search for repositories
const repos = await trigger("mcp::call_tool", {
  server: "github",
  tool: "search_repositories",
  arguments: {
    query: "agent framework language:typescript",
    sort: "stars",
    limit: 5
  }
});

console.log("Top agent frameworks:", repos);

// Create an issue
const issue = await trigger("mcp::call_tool", {
  server: "github",
  tool: "create_issue",
  arguments: {
    owner: "iii-hq",
    repo: "agentos",
    title: "Add PostgreSQL MCP integration",
    body: "Users want to query databases from agents",
    labels: ["enhancement", "database"]
  }
});

console.log(`Created issue #${issue.number}`);

// Clean up
await trigger("mcp::disconnect", { name: "github" });

JSON-RPC Implementation

From src/mcp-client.ts:60-99, the client implements JSON-RPC 2.0:
function sendRpc(
  conn: McpConnection,
  method: string,
  params?: Record<string, unknown>
): Promise<unknown> {
  const id = conn.nextRpcId++;
  const message = { jsonrpc: "2.0", id, method, params };
  
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      pendingRequests.delete(`${conn.id}:${id}`);
      reject(new Error(`RPC timeout: ${method}`));
    }, 30_000);

    pendingRequests.set(`${conn.id}:${id}`, { resolve, reject, timer });

    if (conn.transport === "stdio" && conn.process?.stdin?.writable) {
      conn.process.stdin.write(JSON.stringify(message) + "\n");
    }
  });
}
Responses are parsed from stdout and matched to pending requests (see src/mcp-client.ts:101-109).

Security

From src/mcp-client.ts:140, all MCP commands are validated with validateMcpCommand() to prevent command injection.
Child processes run with stripped environment variables (stripSecretsFromEnv()) to prevent credential leakage.
All MCP endpoints require authentication via requireAuth() (see src/mcp-client.ts:118).
All MCP operations are logged to the security audit trail:
  • mcp_connect - Connection established
  • mcp_disconnect - Connection closed
  • mcp_tool_call - Tool invocation

HTTP API Endpoints

# Connect to MCP server
curl -X POST http://localhost:3111/api/mcp/connect \
  -H "Content-Type: application/json" \
  -d '{
    "name": "github",
    "transport": "stdio",
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-github"]
  }'

# List connections
curl http://localhost:3111/api/mcp/connections

# List tools
curl http://localhost:3111/api/mcp/tools

# Call a tool
curl -X POST http://localhost:3111/api/mcp/call \
  -d '{
    "server": "github",
    "tool": "create_issue",
    "arguments": {
      "owner": "iii-hq",
      "repo": "agentos",
      "title": "Test issue"
    }
  }'

# Disconnect
curl -X POST http://localhost:3111/api/mcp/disconnect \
  -d '{ "name": "github" }'

# Start MCP server mode
curl -X POST http://localhost:3111/api/mcp/serve \
  -d '{ "tools": [...] }'

# Stop MCP server mode
curl -X POST http://localhost:3111/api/mcp/unserve

CLI Commands

From the README:
agentos mcp                     # Start in MCP server mode
agentos integrations [query]    # Browse available integrations
agentos add <name> [--key K]    # Add an integration
agentos remove <name>           # Remove an integration

MCP Protocol Specification

AgentOS implements MCP protocol version 2024-11-05 with:
  • Initialize: { protocolVersion, capabilities, clientInfo }
  • Tools/List: Returns array of { name, description, inputSchema }
  • Tools/Call: { name, arguments }{ content: [...] }
See the Model Context Protocol specification for full details.

Best Practices

One Connection per Integration

Don’t create multiple connections to the same MCP server

Handle Connection Failures

MCP processes can crash. Monitor and reconnect as needed

Namespace Tools

Tools are automatically namespaced as mcp_{server}_{tool}

Clean Up Connections

Disconnect when done to free resources

Troubleshooting

The MCP server process may not be starting. Check that the command and args are correct, and that required packages are installed.
Use mcp::list_tools to see what tools are actually available. Tool names must match exactly.
The MCP server isn’t responding. Check if the process is still running and hasn’t crashed.
Many MCP servers need API tokens. Pass them via args or ensure they’re in the environment before starting AgentOS.
  • A2A Protocol - Connect AgentOS instances together
  • SkillKit - Alternative to MCP for extending agent capabilities
  • Tools - Built-in AgentOS tools

Build docs developers (and LLMs) love