Skip to main content

MCP Client Plugin

Overview

The @tokenring-ai/mcp package provides MCP client functionality to connect TokenRing agents with MCP servers. It automatically registers MCP server tools with the TokenRing chat service, making them available for agent use. The plugin supports multiple transport types (stdio, SSE, HTTP) and provides comprehensive configuration validation.

Key Features

  • Multiple transport types: Support for stdio, SSE, and HTTP transports
  • Automatic tool registration: MCP server tools are automatically registered with TokenRing chat service
  • Seamless integration: Works with existing TokenRing application framework
  • Zod schema validation: Comprehensive configuration validation with detailed error messages
  • Type-safe configuration: Strong typing for all configuration options
  • Error handling: Proper error handling for transport connections and tool registration
  • Tool schema preservation: Maintains original MCP tool schemas during registration
  • Plugin-based architecture: Integrates as a TokenRing plugin with automatic service registration

Core Components

MCPService

Main service for managing MCP server connections and tool registration.

import { MCPService } from '@tokenring-ai/mcp';
import TokenRingApp from '@tokenring-ai/app';

const mcpService = new MCPService();

Properties:

PropertyTypeDescription
namestringService identifier ("MCPService")
descriptionstringService description ("Service for MCP (Model Context Protocol) servers")

Configuration Schemas

MCPConfigSchema

export const MCPConfigSchema = z.object({
transports: z.record(z.string(), MCPTransportConfigSchema)
}).optional();

MCPTransportConfigSchema

export const MCPTransportConfigSchema = z.discriminatedUnion("type", [
z.object({type: z.literal("stdio")}).passthrough(),
z.object({type: z.literal("sse"), url: z.url()}).passthrough(),
z.object({type: z.literal("http"), url: z.url()}).passthrough(),
]);

MCPTransportConfig Type

type MCPTransportConfig = 
| { type: "stdio"; command: string; args?: string[]; env?: Record<string, string>; cwd?: string }
| { type: "sse"; url: string; headers?: Record<string, string>; timeout?: number }
| { type: "http"; url: string; method?: "GET" | "POST" | "PUT" | "DELETE"; headers?: Record<string, string>; timeout?: number };

Usage Examples

Plugin Configuration

Configure MCP servers in your TokenRing application:

// In your TokenRing app configuration
{
plugins: [
{
name: "@tokenring-ai/mcp",
config: {
mcp: {
transports: {
myserver: {
type: "stdio",
command: "mcp-server",
args: ["--config", "config.json"],
env: {
DEBUG: "true"
}
},
remoteserver: {
type: "sse",
url: "http://localhost:3000/sse",
headers: {
"Authorization": "Bearer token123"
}
},
apiserver: {
type: "http",
url: "http://localhost:3001/api/mcp",
method: "POST",
headers: {
"Content-Type": "application/json"
}
}
}
}
}
}
]
}

Programmatic Integration

import { MCPService } from '@tokenring-ai/mcp';
import TokenRingApp from '@tokenring-ai/app';

const app = new TokenRingApp();
const mcpService = new MCPService();

// Register an MCP server with stdio transport
await mcpService.register('myserver', {
type: 'stdio',
command: 'node',
args: ['path/to/mcp-server.js']
}, app);

// Register an MCP server with SSE transport
await mcpService.register('another-server', {
type: 'sse',
url: 'http://localhost:3000/sse'
}, app);

Configuration

Installation

bun install @tokenring-ai/mcp

Transport Types

Stdio Transport

{
type: 'stdio',
command: 'mcp-server', // Required: Command to execute
args?: string[], // Optional: Command arguments
env?: Record<string, string>, // Optional: Environment variables
cwd?: string // Optional: Working directory
}

SSE Transport

{
type: 'sse',
url: 'http://localhost:3000/sse', // Required: SSE endpoint URL
headers?: Record<string, string>, // Optional: Custom headers
timeout?: number // Optional: Connection timeout in ms
}

HTTP Transport

{
type: 'http',
url: 'http://localhost:3001/api/mcp', // Required: HTTP endpoint URL
method?: 'GET' | 'POST' | 'PUT' | 'DELETE', // Optional: HTTP method (default: GET)
headers?: Record<string, string>, // Optional: Custom headers
timeout?: number // Optional: Connection timeout in ms
}

Complete Configuration Example

{
"mcp": {
"transports": {
"stdio-server": {
"type": "stdio",
"command": "node",
"args": ["path/to/mcp-server.js"]
},
"sse-server": {
"type": "sse",
"url": "http://localhost:3000/sse"
},
"http-server": {
"type": "http",
"url": "http://localhost:3001/api/mcp",
"method": "POST"
}
}
}
}

Integration

Plugin Integration

The MCP plugin integrates with the TokenRing application framework through the standard plugin pattern:

import { default as MCPPlugin } from '@tokenring-ai/mcp';

// In your TokenRing application configuration
plugins: [MCPPlugin]

Service Registration

The plugin automatically registers the MCPService with the TokenRing application when the configuration is provided:

async install(app: TokenRingApp) {
const config = app.getConfigSlice('mcp', MCPConfigSchema);
if (config) {
const mcpService = new MCPService();
app.addServices(mcpService);

for (const name in config.transports) {
await mcpService.register(name, config.transports[name] as any, app);
}
}
}

API Reference

Exports

ExportTypeDescription
defaultTokenRingPluginTokenRing plugin object
MCPServiceclassService class for manual MCP server registration
MCPConfigSchemaz.ZodSchemaZod schema for plugin configuration
MCPTransportConfigSchemaz.ZodSchemaZod schema for transport configuration
MCPTransportConfigTypeAliasType alias for transport configuration

MCPService Methods

register(name: string, config: MCPTransportConfig, app: TokenRingApp): Promise<void>

Registers an MCP server with the TokenRing application.

Parameters:

ParameterTypeDescription
namestringUnique identifier for the MCP server
configMCPTransportConfigTransport configuration object
appTokenRingAppTokenRingApp instance to register tools with

Example:

import { MCPService } from '@tokenring-ai/mcp';
import TokenRingApp from '@tokenring-ai/app';

const mcpService = new MCPService();
const app = new TokenRingApp();

// Register with stdio transport
await mcpService.register('myserver', {
type: 'stdio',
command: 'mcp-server',
args: ['--config', 'config.json']
}, app);

// Register with SSE transport
await mcpService.register('remoteserver', {
type: 'sse',
url: 'http://localhost:3000/sse',
headers: {
'Authorization': 'Bearer token123'
}
}, app);

// Register with HTTP transport
await mcpService.register('apiserver', {
type: 'http',
url: 'http://localhost:3001/api/mcp',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}, app);

Development

Testing

# Run all tests
bun run test

# Run tests in watch mode
bun run test:watch

# Run tests with coverage
bun run test:coverage

Building

bun run build

Package Structure

pkg/mcp/
├── index.ts # Type exports and configuration schema
├── MCPService.ts # Main service implementation
├── plugin.ts # Plugin registration
├── package.json # Package metadata
├── README.md # Package README
├── LICENSE # MIT License
├── vitest.config.ts # Test configuration
├── MCPService.test.ts # Unit tests
├── configuration.test.ts # Configuration schema tests
└── integration.test.ts # Integration tests

Error Handling

The package provides comprehensive error handling:

  • Invalid Configuration: Throws clear validation errors for invalid transport configurations
  • Transport Failures: Handles connection errors with descriptive messages
  • Tool Registration Failures: Returns errors when tools cannot be registered with chat service
  • Service Dependencies: Checks for required services before registration

License

MIT License - see LICENSE for details.