Skip to content

MCP Integration

The MCP (Model Context Protocol) module provides bidirectional integration with the MCP ecosystem. You can consume tools from remote MCP servers and expose your framework tools as an MCP server -- all through the unified ToolRegistry.

Import

import {
  // Consuming remote tools
  registerMcpRemoteTools,
  McpRemoteServerConfig,
  McpAuth,
  RegisterMcpRemoteToolsResult,

  // Exposing tools as MCP server
  createMcpStatelessHandlerFromToolRegistry,
  McpProviderConfig,

  // Schema resources
  registerToolSchemaResourcesOnMcpServer,

  // Types
  McpToolDescriptor,
} from "@modernpath/agent-framework";

Architecture

graph LR
    subgraph "Your Application"
        TR[ToolRegistry]
        Agent[BaseAgent]
    end

    subgraph "MCP Consumer"
        RC[registerMcpRemoteTools] -->|imports tools| TR
    end

    subgraph "Remote MCP Server"
        RMS["Remote Server<br/>(tools/list, tools/call)"]
    end

    subgraph "MCP Provider"
        MP[createMcpStatelessHandler] -->|exposes tools| TR
    end

    subgraph "MCP Client"
        MC["MCP Client<br/>(tools/list, tools/call)"]
    end

    RC -->|Streamable HTTP| RMS
    MC -->|JSON-RPC POST| MP
    Agent -->|uses| TR

Components

Consuming Remote Tools

registerMcpRemoteTools() imports tools from a remote MCP server into the ToolRegistry as proxy tools. It performs the MCP initialize handshake, discovers available tools via tools/list, and registers each as a local proxy that delegates to tools/call.

Exposing Tools

createMcpStatelessHandlerFromToolRegistry() creates a stateless MCP Streamable HTTP handler backed by the ToolRegistry. It implements tools/list, tools/call, resources/list, and resources/read.

Schema Resources

registerToolSchemaResourcesOnMcpServer() registers tool input/output schemas as MCP resources, enabling clients to discover schemas via resources/list and resources/read.

Loop Safety

Built-in recursion prevention using denyToolPrefix and callStack propagation to prevent infinite MCP-to-MCP call loops.

Quick Start

Consuming Remote Tools

import { ToolRegistry, registerMcpRemoteTools } from "@modernpath/agent-framework";

const registry = new ToolRegistry();

const result = await registerMcpRemoteTools(registry, {
  name: "acme-iot",
  url: "https://api.acme.com/mcp",
  auth: {
    type: "bearer",
    getToken: async ({ userId }) => getServiceToken(userId),
  },
  toolPrefix: "acme.",
  category: "external",
  allowTools: ["getTelemetryBundle", "getAlerts"],
  timeoutMs: 30000,
  retries: 2,
});

console.log(`Registered: ${result.registered.join(", ")}`);
// "acme.getTelemetryBundle, acme.getAlerts"

Exposing Tools

import { createMcpStatelessHandlerFromToolRegistry } from "@modernpath/agent-framework";

const mcpHandler = createMcpStatelessHandlerFromToolRegistry(registry, {
  serverName: "my-agent-tools",
  serverVersion: "1.0.0",
  allowCategories: ["public"],
});

// Use with any HTTP server
app.post("/mcp", async (req, res) => {
  const result = await mcpHandler({
    method: req.method,
    headers: req.headers,
    body: JSON.stringify(req.body),
  });
  res.status(result.statusCode).set(result.headers).send(result.body);
});