Anthropic MCP to OSSA
Migration Guide: Extending Anthropic MCP with OSSA
Version: 1.0 Last Updated: 2025-11-10 Status: Production-Ready
π Table of Contents
- Overview
- Why Extend MCP with OSSA?
- Key Concepts
- Migration Strategy
- Example 1: Simple MCP Server β OSSA Agent
- Example 2: MCP Tools β OSSA Capabilities
- Example 3: MCP Resources β OSSA Data Sources
- Integration Patterns
- Best Practices
- Troubleshooting
Overview
This guide helps you extend your existing Anthropic Model Context Protocol (MCP) servers with the Open Standards for Scalable Agents (OSSA) specification. OSSA is not a replacement for MCPβit's a superset that adds:
- Multi-protocol support (HTTP, gRPC, WebSocket, A2A)
- Production features (monitoring, metrics, policies, compliance)
- OpenAPI integration for REST API exposure
- Agent orchestration capabilities
- Kubernetes deployment support
- Enterprise governance (encryption, audit, RBAC)
Key Insight: OSSA agents can natively speak MCP while also supporting other protocols. You get MCP compatibility + production-ready infrastructure.
Why Extend MCP with OSSA?
MCP Alone (Good for Claude Desktop)
| Feature | MCP Native | Notes |
|---|---|---|
| Claude Desktop Integration | β | Perfect for local use |
| Stdio Transport | β | Simple, local execution |
| Tools | β | Function calls |
| Resources | β | Data access |
| Prompts | β | Template support |
| HTTP/REST API | β | Limited to MCP protocol |
| Kubernetes Deployment | β | No native support |
| Monitoring/Metrics | β | Manual implementation |
| Multi-LLM Support | β | Claude-specific |
| Agent Orchestration | β | Single-agent only |
| Compliance/Audit | β | No built-in support |
MCP + OSSA (Production-Ready)
| Feature | MCP + OSSA | Notes |
|---|---|---|
| Claude Desktop Integration | β | Full backward compatibility |
| Stdio Transport | β | MCP native support |
| Tools | β | Via MCP bridge |
| Resources | β | Via MCP bridge |
| Prompts | β | Via MCP bridge |
| HTTP/REST API | β | OpenAPI-first design |
| Kubernetes Deployment | β | Native YAML manifests |
| Monitoring/Metrics | β | Prometheus, Grafana, traces |
| Multi-LLM Support | β | OpenAI, Anthropic, etc. |
| Agent Orchestration | β | Multi-agent coordination |
| Compliance/Audit | β | ISO42001, SOC2, GDPR |
Key Concepts
MCP β OSSA Mapping
| MCP Concept | OSSA Equivalent | Relationship |
|---|---|---|
| MCP Server | OSSA Agent | Agent wraps MCP server functionality |
| MCP Tool | OSSA Capability | 1:1 mapping via bridge config |
| MCP Resource | OSSA Data Source | Exposed via integration endpoints |
| Stdio Transport | MCP Bridge (stdio) | Native MCP protocol support |
| Tool Parameters | Capability Input Schema | JSON Schema compatible |
| Tool Response | Capability Output Schema | Typed responses |
| N/A | OpenAPI Bridge | REST API exposure |
| N/A | Monitoring | Traces, metrics, logs |
| N/A | Policies | Compliance, encryption, audit |
How OSSA Extends MCP
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OSSA Agent β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β β β β β β β
β β MCP Bridge β β OpenAPI REST β β A2A P2P β β
β β (stdio) β β (HTTP) β β Protocol β β
β β β β β β β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β β
β ββββββββββββββββββββΌβββββββββββββββββββ β
β β β
β βββββββββββΌββββββββββ β
β β β β
β β Core Runtime β β
β β (Capabilities) β β
β β β β
β βββββββββββ¬βββββββββββ β
β β β
β ββββββββββββββββββββΌβββββββββββββββββββ β
β β β β β
β ββββββββΌββββββββ ββββββββΌββββββββ ββββββββΌββββββββ β
β β β β β β β β
β β Monitoring β β Policies β β Metrics β β
β β (Traces) β β (Audit) β β (Prometheus) β β
β β β β β β β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Migration Strategy
Phase 1: Assessment
-
Inventory existing MCP servers
# List MCP servers in Claude Desktop config cat ~/Library/Application\ Support/Claude/claude_desktop_config.json -
Document MCP tools and resources
# For each server, document: # - Tool names and signatures # - Resource URIs and schemas # - Transport type (stdio/sse) # - Dependencies -
Identify production requirements
# Questions to answer: - Need HTTP API access? β OpenAPI bridge - Need Kubernetes deployment? β OSSA runtime config - Need monitoring/metrics? β OSSA monitoring - Need multi-agent coordination? β OSSA orchestration - Need compliance tracking? β OSSA policies
Phase 2: Create OSSA Agent
# Interactive agent creation (recommended) buildkit agents create --interactive # Or non-interactive with MCP enabled buildkit agents create my-agent \ --type worker \ --description "My MCP server as OSSA agent" \ --mcp \ --mcp-transport stdio \ --openapi
Phase 3: Migrate Logic
- Copy MCP server code to agent's
src/directory - Map MCP tools to OSSA capabilities in
agent.yml - Configure MCP bridge for stdio transport
- Add OpenAPI spec for HTTP access (optional)
- Enable monitoring (traces, metrics, logs)
Phase 4: Test Both Modes
# Test HTTP mode cd .agents/my-agent npm install && npm run build npm start curl http://localhost:3000/health # Test MCP mode (stdio) MCP_MODE=stdio npm start # (Connect from Claude Desktop)
Phase 5: Update Claude Desktop Config
# Generate updated config buildkit mcpb claude-config # Or manually add to claude_desktop_config.json { "mcpServers": { "my-agent": { "command": "node", "args": ["/path/to/.agents/my-agent/dist/index.js"], "env": { "MCP_MODE": "stdio" } } } }
Example 1: Simple MCP Server β OSSA Agent
Before: Pure MCP Server
// simple-mcp-server.ts import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types'; const server = new Server( { name: 'simple-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // List tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'greet', description: 'Greet a user', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Name to greet' } }, required: ['name'] } } ] }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === 'greet') { const { name } = request.params.arguments as { name: string }; return { content: [ { type: 'text', text: `Hello, ${name}!` } ] }; } throw new Error(`Unknown tool: ${request.params.name}`); }); const transport = new StdioServerTransport(); server.connect(transport); console.log('MCP server running on stdio');
Usage:
// claude_desktop_config.json { "mcpServers": { "simple-server": { "command": "node", "args": ["simple-mcp-server.js"] } } }
Limitations:
- β No HTTP API
- β No monitoring
- β No metrics
- β No health checks
- β Manual deployment
- β No orchestration
After: OSSA Agent with MCP Bridge
1. Create OSSA Agent:
buildkit agents create simple-agent \ --type worker \ --description "Simple greeting agent with MCP support" \ --mcp \ --openapi
2. Agent Manifest (agent.yml):
ossaVersion: "0.3.0" agent: id: simple-agent name: simple-agent version: 1.0.0 description: Simple greeting agent with MCP support role: workflow tags: - greeting - worker - mcp runtime: type: local command: [node, dist/index.js] resources: cpu: 500m memory: 512Mi capabilities: - name: greet description: Greet a user by name input_schema: type: object properties: name: type: string description: Name to greet required: [name] output_schema: type: object properties: message: type: string integration: protocol: http endpoints: base_url: http://localhost:3000 health: /health metrics: /metrics monitoring: traces: true metrics: true logs: true policies: encryption: true audit: true bridge: # MCP Bridge for Claude Desktop mcp: enabled: true server_type: stdio tools: - name: greet description: Greet a user by name capability: greet config: max_message_size: 1048576 timeout_ms: 30000 retry_count: 3 # OpenAPI Bridge for REST API openapi: enabled: true spec_url: ./openapi.yaml spec_version: "3.1"
3. Agent Implementation (src/index.ts):
import express from 'express'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types'; const app = express(); const PORT = process.env.PORT || 3000; app.use(express.json()); // ======================================== // HTTP Mode (OpenAPI REST API) // ======================================== app.get('/health', (req, res) => { res.json({ status: 'healthy', agent: 'simple-agent', version: '1.0.0', timestamp: new Date().toISOString(), }); }); app.get('/metrics', (req, res) => { // Prometheus metrics res.set('Content-Type', 'text/plain'); res.send(` # HELP simple_agent_requests_total Total requests # TYPE simple_agent_requests_total counter simple_agent_requests_total 42 `.trim()); }); // Capability: greet app.post('/capabilities/greet', async (req, res) => { try { const { name } = req.body; if (!name) { return res.status(400).json({ error: 'name is required' }); } const result = { message: `Hello, ${name}!`, timestamp: new Date().toISOString(), }; res.json(result); } catch (error: any) { res.status(500).json({ error: error.message }); } }); // ======================================== // MCP Mode (stdio transport) // ======================================== if (process.env.MCP_MODE === 'stdio') { const server = new Server( { name: 'simple-agent', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'greet', description: 'Greet a user by name', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Name to greet' }, }, required: ['name'], }, }, ], }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const toolName = request.params.name; if (toolName === 'greet') { const { name } = request.params.arguments as { name: string }; return { content: [ { type: 'text', text: JSON.stringify({ message: `Hello, ${name}!`, timestamp: new Date().toISOString(), }), }, ], }; } throw new Error(`Unknown tool: ${toolName}`); }); const transport = new StdioServerTransport(); server.connect(transport); console.log('MCP server running on stdio'); } else { // HTTP mode app.listen(PORT, () => { console.log(`Agent listening on port ${PORT} (HTTP mode)`); console.log(`Health: http://localhost:${PORT}/health`); console.log(`Metrics: http://localhost:${PORT}/metrics`); }); }
4. OpenAPI Spec (openapi.yaml):
openapi: 3.1.0 info: title: simple-agent API version: 1.0.0 description: Simple greeting agent with MCP support servers: - url: http://localhost:3000 description: Local development paths: /health: get: summary: Health check responses: '200': description: Agent is healthy content: application/json: schema: type: object properties: status: type: string agent: type: string version: type: string timestamp: type: string /capabilities/greet: post: summary: Greet a user requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: Name to greet required: [name] responses: '200': description: Greeting response content: application/json: schema: type: object properties: message: type: string timestamp: type: string
Benefits:
- β Claude Desktop works (MCP stdio mode)
- β HTTP API available (curl, Postman, web apps)
- β
Health checks (
/health) - β
Metrics (
/metricsfor Prometheus) - β OpenAPI spec (auto-generated docs)
- β Monitoring ready (traces, logs)
- β Kubernetes ready (via OSSA runtime config)
Usage:
# HTTP mode npm start curl -X POST http://localhost:3000/capabilities/greet \ -H "Content-Type: application/json" \ -d '{"name": "World"}' # β {"message": "Hello, World!", "timestamp": "..."} # MCP mode (Claude Desktop) MCP_MODE=stdio npm start # β Works in Claude Desktop as before
Example 2: MCP Tools β OSSA Capabilities
Before: MCP Server with Multiple Tools
// filesystem-mcp-server.ts import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types'; import fs from 'fs/promises'; const server = new Server( { name: 'filesystem-server', version: '1.0.0' }, { capabilities: { tools: {} } } ); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'read_file', description: 'Read a file from disk', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'File path' } }, required: ['path'] } }, { name: 'write_file', description: 'Write content to a file', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'File path' }, content: { type: 'string', description: 'File content' } }, required: ['path', 'content'] } }, { name: 'list_directory', description: 'List files in a directory', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Directory path' } }, required: ['path'] } } ] }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case 'read_file': { const content = await fs.readFile(args.path as string, 'utf-8'); return { content: [{ type: 'text', text: content }] }; } case 'write_file': { await fs.writeFile(args.path as string, args.content as string); return { content: [{ type: 'text', text: 'File written successfully' }] }; } case 'list_directory': { const files = await fs.readdir(args.path as string); return { content: [{ type: 'text', text: JSON.stringify(files) }] }; } default: throw new Error(`Unknown tool: ${name}`); } }); const transport = new StdioServerTransport(); server.connect(transport);
After: OSSA Agent with Mapped Capabilities
Agent Manifest (agent.yml):
ossaVersion: "0.3.0" agent: id: filesystem-agent name: filesystem-agent version: 1.0.0 description: Filesystem operations agent role: workflow tags: [filesystem, io, worker] runtime: type: local command: [node, dist/index.js] resources: cpu: 500m memory: 512Mi capabilities: # Capability 1: Read File - name: read-file description: Read a file from disk input_schema: type: object properties: path: type: string description: File path to read required: [path] output_schema: type: object properties: content: type: string size: type: number # Capability 2: Write File - name: write-file description: Write content to a file input_schema: type: object properties: path: type: string description: File path to write content: type: string description: Content to write required: [path, content] output_schema: type: object properties: success: type: boolean bytes_written: type: number # Capability 3: List Directory - name: list-directory description: List files in a directory input_schema: type: object properties: path: type: string description: Directory path required: [path] output_schema: type: object properties: files: type: array items: type: string integration: protocol: http endpoints: base_url: http://localhost:3000 health: /health metrics: /metrics monitoring: traces: true metrics: true logs: true policies: encryption: true audit: true # Filesystem access requires audit logging compliance: [SOC2, GDPR] bridge: mcp: enabled: true server_type: stdio tools: # Map OSSA capabilities to MCP tools - name: read_file description: Read a file from disk capability: read-file - name: write_file description: Write content to a file capability: write-file - name: list_directory description: List files in a directory capability: list-directory config: max_message_size: 10485760 # 10MB for large files timeout_ms: 60000 # 60s for large operations retry_count: 3 openapi: enabled: true spec_url: ./openapi.yaml spec_version: "3.1"
Implementation (src/index.ts):
import express from 'express'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types'; import fs from 'fs/promises'; const app = express(); const PORT = process.env.PORT || 3000; app.use(express.json()); // ======================================== // Shared Business Logic // ======================================== class FilesystemService { async readFile(path: string) { const content = await fs.readFile(path, 'utf-8'); const stats = await fs.stat(path); return { content, size: stats.size, modified: stats.mtime.toISOString(), }; } async writeFile(path: string, content: string) { await fs.writeFile(path, content); const stats = await fs.stat(path); return { success: true, bytes_written: stats.size, path, }; } async listDirectory(path: string) { const entries = await fs.readdir(path, { withFileTypes: true }); return { files: entries.map(e => ({ name: e.name, type: e.isDirectory() ? 'directory' : 'file', })), count: entries.length, }; } } const service = new FilesystemService(); // ======================================== // HTTP Mode (OpenAPI REST API) // ======================================== app.get('/health', (req, res) => { res.json({ status: 'healthy', agent: 'filesystem-agent', version: '1.0.0', }); }); app.post('/capabilities/read-file', async (req, res) => { try { const { path } = req.body; const result = await service.readFile(path); res.json(result); } catch (error: any) { res.status(500).json({ error: error.message }); } }); app.post('/capabilities/write-file', async (req, res) => { try { const { path, content } = req.body; const result = await service.writeFile(path, content); res.json(result); } catch (error: any) { res.status(500).json({ error: error.message }); } }); app.post('/capabilities/list-directory', async (req, res) => { try { const { path } = req.body; const result = await service.listDirectory(path); res.json(result); } catch (error: any) { res.status(500).json({ error: error.message }); } }); // ======================================== // MCP Mode (stdio transport) // ======================================== if (process.env.MCP_MODE === 'stdio') { const server = new Server( { name: 'filesystem-agent', version: '1.0.0' }, { capabilities: { tools: {} } } ); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'read_file', description: 'Read a file from disk', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'File path' }, }, required: ['path'], }, }, { name: 'write_file', description: 'Write content to a file', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'File path' }, content: { type: 'string', description: 'Content' }, }, required: ['path', 'content'], }, }, { name: 'list_directory', description: 'List files in a directory', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Directory path' }, }, required: ['path'], }, }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { let result; switch (name) { case 'read_file': result = await service.readFile(args.path as string); break; case 'write_file': result = await service.writeFile( args.path as string, args.content as string ); break; case 'list_directory': result = await service.listDirectory(args.path as string); break; default: throw new Error(`Unknown tool: ${name}`); } return { content: [ { type: 'text', text: JSON.stringify(result), }, ], }; } catch (error: any) { return { content: [ { type: 'text', text: JSON.stringify({ error: error.message }), }, ], isError: true, }; } }); const transport = new StdioServerTransport(); server.connect(transport); console.log('MCP server running on stdio'); } else { app.listen(PORT, () => { console.log(`Filesystem agent listening on port ${PORT}`); }); }
Key Benefits:
- β Single codebase serves both MCP and HTTP
- β Shared business logic (FilesystemService)
- β OpenAPI docs auto-generated from schema
- β Audit logging enabled for compliance
- β Metrics tracking for filesystem operations
- β Error handling consistent across protocols
Example 3: MCP Resources β OSSA Data Sources
Before: MCP Server with Resources
// database-mcp-server.ts import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types'; const server = new Server( { name: 'database-server', version: '1.0.0' }, { capabilities: { resources: {} } } ); // List available resources server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: [ { uri: 'db://users', name: 'Users Table', description: 'All users in the database', mimeType: 'application/json' }, { uri: 'db://posts', name: 'Posts Table', description: 'All blog posts', mimeType: 'application/json' } ] }; }); // Read a specific resource server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const uri = request.params.uri; if (uri === 'db://users') { const users = await fetchUsers(); // Mock DB query return { contents: [ { uri, mimeType: 'application/json', text: JSON.stringify(users) } ] }; } if (uri === 'db://posts') { const posts = await fetchPosts(); // Mock DB query return { contents: [ { uri, mimeType: 'application/json', text: JSON.stringify(posts) } ] }; } throw new Error(`Unknown resource: ${uri}`); }); const transport = new StdioServerTransport(); server.connect(transport);
After: OSSA Agent with Data Source Integration
Agent Manifest (agent.yml):
ossaVersion: "0.3.0" agent: id: database-agent name: database-agent version: 1.0.0 description: Database access agent with MCP resources role: workflow tags: [database, data-source, worker] runtime: type: local command: [node, dist/index.js] environment: DATABASE_URL: postgresql://localhost:5432/mydb resources: cpu: 1000m memory: 1Gi capabilities: - name: query-users description: Query users table input_schema: type: object properties: filter: type: object limit: type: number default: 100 output_schema: type: object properties: users: type: array items: type: object - name: query-posts description: Query posts table input_schema: type: object properties: author_id: type: string limit: type: number default: 50 output_schema: type: object properties: posts: type: array items: type: object integration: protocol: http endpoints: base_url: http://localhost:3000 health: /health metrics: /metrics # Data source endpoints data_sources: - uri: /data/users description: Users table resource - uri: /data/posts description: Posts table resource monitoring: traces: true metrics: true logs: true alerts: - name: slow_query condition: query_duration_ms > 1000 severity: warning policies: encryption: true audit: true compliance: [SOC2, GDPR, HIPAA] # Database access requires strict compliance data_retention_days: 90 rate_limits: - endpoint: /data/* max_requests_per_minute: 100 bridge: mcp: enabled: true server_type: stdio # Map resources to OSSA capabilities resources: - uri: db://users name: Users Table description: All users in the database capability: query-users - uri: db://posts name: Posts Table description: All blog posts capability: query-posts config: max_message_size: 10485760 # 10MB for large datasets timeout_ms: 30000 retry_count: 3 openapi: enabled: true spec_url: ./openapi.yaml spec_version: "3.1"
Implementation (src/index.ts):
import express from 'express'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types'; const app = express(); const PORT = process.env.PORT || 3000; app.use(express.json()); // ======================================== // Database Service (Shared Logic) // ======================================== class DatabaseService { async queryUsers(filter?: any, limit: number = 100) { // Mock implementation - replace with real DB query const users = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' }, ]; return { users: users.slice(0, limit), count: users.length, timestamp: new Date().toISOString(), }; } async queryPosts(authorId?: string, limit: number = 50) { // Mock implementation - replace with real DB query const posts = [ { id: 1, title: 'Hello World', author_id: '1' }, { id: 2, title: 'OSSA Guide', author_id: '1' }, ]; return { posts: posts.slice(0, limit), count: posts.length, timestamp: new Date().toISOString(), }; } } const db = new DatabaseService(); // ======================================== // HTTP Mode (OpenAPI REST API) // ======================================== app.get('/health', (req, res) => { res.json({ status: 'healthy', agent: 'database-agent', version: '1.0.0', database: 'connected', }); }); app.get('/metrics', (req, res) => { res.set('Content-Type', 'text/plain'); res.send(` # HELP db_queries_total Total database queries # TYPE db_queries_total counter db_queries_total{table="users"} 1234 db_queries_total{table="posts"} 567 `.trim()); }); // Data source endpoints (RESTful resources) app.get('/data/users', async (req, res) => { try { const limit = parseInt(req.query.limit as string) || 100; const result = await db.queryUsers({}, limit); res.json(result); } catch (error: any) { res.status(500).json({ error: error.message }); } }); app.get('/data/posts', async (req, res) => { try { const authorId = req.query.author_id as string; const limit = parseInt(req.query.limit as string) || 50; const result = await db.queryPosts(authorId, limit); res.json(result); } catch (error: any) { res.status(500).json({ error: error.message }); } }); // Capability endpoints app.post('/capabilities/query-users', async (req, res) => { try { const { filter, limit } = req.body; const result = await db.queryUsers(filter, limit); res.json(result); } catch (error: any) { res.status(500).json({ error: error.message }); } }); app.post('/capabilities/query-posts', async (req, res) => { try { const { author_id, limit } = req.body; const result = await db.queryPosts(author_id, limit); res.json(result); } catch (error: any) { res.status(500).json({ error: error.message }); } }); // ======================================== // MCP Mode (stdio transport) // ======================================== if (process.env.MCP_MODE === 'stdio') { const server = new Server( { name: 'database-agent', version: '1.0.0' }, { capabilities: { resources: {} } } ); // List resources server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: [ { uri: 'db://users', name: 'Users Table', description: 'All users in the database', mimeType: 'application/json', }, { uri: 'db://posts', name: 'Posts Table', description: 'All blog posts', mimeType: 'application/json', }, ], }; }); // Read resource server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; try { let data; if (uri === 'db://users') { data = await db.queryUsers(); } else if (uri === 'db://posts') { data = await db.queryPosts(); } else { throw new Error(`Unknown resource: ${uri}`); } return { contents: [ { uri, mimeType: 'application/json', text: JSON.stringify(data), }, ], }; } catch (error: any) { throw new Error(`Failed to read resource ${uri}: ${error.message}`); } }); const transport = new StdioServerTransport(); server.connect(transport); console.log('MCP server running on stdio'); } else { app.listen(PORT, () => { console.log(`Database agent listening on port ${PORT}`); }); }
Key Benefits:
- β MCP resources mapped to REST endpoints
- β Data source discovery via OpenAPI
- β Query metrics tracked (Prometheus)
- β Rate limiting for data access
- β Compliance tracking (GDPR, HIPAA)
- β Audit logs for all queries
Integration Patterns
Pattern 1: Hybrid Access (MCP + HTTP)
Use Case: Tool accessible from both Claude Desktop and web applications.
# agent.yml bridge: mcp: enabled: true server_type: stdio openapi: enabled: true spec_url: ./openapi.yaml
Benefits:
- Claude Desktop users get native MCP experience
- Web apps can use REST API
- Single agent, dual protocols
Pattern 2: Agent Orchestration
Use Case: OSSA orchestrator coordinates multiple MCP agents.
# orchestrator-agent.yml ossaVersion: "0.3.0" agent: id: orchestrator role: orchestration capabilities: - name: coordinate-workflow description: Orchestrate multiple agents input_schema: type: object properties: agents: type: array items: type: string bridge: # Orchestrator doesn't need MCP # It coordinates other agents via OSSA A2A protocol a2a: enabled: true discovery: mode: registry registry_url: http://localhost:8080
Workflow:
- Orchestrator receives task via HTTP
- Discovers available agents (some MCP-enabled)
- Coordinates execution via A2A protocol
- Aggregates results
Pattern 3: MCP Server Gateway
Use Case: Single OSSA agent exposes multiple MCP servers.
# gateway-agent.yml ossaVersion: "0.3.0" agent: id: mcp-gateway role: workflow capabilities: - name: route-to-mcp description: Route requests to appropriate MCP server input_schema: type: object properties: server: type: string enum: [filesystem, database, git] operation: type: string bridge: mcp: enabled: true server_type: stdio # Multiple MCP backends upstreams: - name: filesystem command: [node, mcp-filesystem.js] - name: database command: [node, mcp-database.js] - name: git command: [node, mcp-git.js]
Best Practices
1. [object Object]
// β GOOD: Shared service layer class FilesystemService { async readFile(path: string) { // Business logic here } } // Use in both HTTP and MCP modes const service = new FilesystemService();
2. [object Object]
// β GOOD: Single entry point, mode-aware if (process.env.MCP_MODE === 'stdio') { startMcpServer(); } else { startHttpServer(); }
3. [object Object]
# agent.yml capabilities: - name: read-file # Kebab-case in OSSA bridge: mcp: tools: - name: read_file # Snake_case in MCP capability: read-file # Maps to OSSA
4. [object Object]
monitoring: traces: true # OpenTelemetry traces metrics: true # Prometheus metrics logs: true # Structured logging
5. [object Object]
metadata: documentation_url: https://docs.example.com/agent # Include both MCP and OpenAPI docs
6. [object Object]
capabilities: - name: greet input_schema: type: object properties: name: type: string minLength: 1 required: [name]
7. [object Object]
# Test HTTP mode npm start curl http://localhost:3000/health # Test MCP mode MCP_MODE=stdio npm start # Connect from Claude Desktop
Troubleshooting
Issue: MCP tools not showing in Claude Desktop
Solution:
- Verify
bridge.mcp.enabled: trueinagent.yml - Check
server_type: stdio - Ensure
MCP_MODE=stdioenvironment variable - Restart Claude Desktop
- Check logs:
~/Library/Logs/Claude/
# Debug MCP_MODE=stdio node dist/index.js # Should output: "MCP server running on stdio"
Issue: HTTP endpoints return 404
Solution:
- Verify agent is running in HTTP mode (not stdio)
- Check
integration.endpoints.base_urlinagent.yml - Ensure Express routes match capability names
# Start in HTTP mode npm start # (no MCP_MODE env var) # Test curl http://localhost:3000/health
Issue: Tools work in HTTP but not MCP
Solution:
- Check tool name mapping (snake_case in MCP)
- Verify
CallToolRequestSchemahandler - Ensure JSON response format:
return { content: [ { type: 'text', text: JSON.stringify(result) // Must be stringified } ] };
Issue: Large payloads fail in MCP mode
Solution:
Increase max_message_size in bridge config:
bridge: mcp: config: max_message_size: 10485760 # 10MB (default: 1MB)
Issue: Metrics not showing in Prometheus
Solution:
- Ensure
/metricsendpoint exists - Use
text/plaincontent type - Follow Prometheus format:
app.get('/metrics', (req, res) => { res.set('Content-Type', 'text/plain'); res.send(` # HELP my_metric_total Total count # TYPE my_metric_total counter my_metric_total 123 `.trim()); });
Summary
| Aspect | MCP Alone | MCP + OSSA |
|---|---|---|
| Claude Desktop | β Native | β Native (via bridge) |
| HTTP API | β Manual | β Auto-generated |
| Monitoring | β Manual | β Built-in |
| Orchestration | β N/A | β Multi-agent |
| Compliance | β Manual | β Policy-driven |
| Kubernetes | β Manual | β Native support |
| OpenAPI Docs | β N/A | β Auto-generated |
| Metrics | β Manual | β Prometheus-ready |
Next Steps:
- Assess your existing MCP servers
- Create OSSA agents with MCP bridges
- Migrate business logic to shared services
- Test both MCP (stdio) and HTTP modes
- Deploy with monitoring enabled
- Monitor metrics and traces
- Scale with Kubernetes (optional)
Resources:
- OSSA Specification: Schema Reference
- MCP Protocol: https://modelcontextprotocol.io
- BuildKit Commands:
buildkit agents --help - Agent BuildKit: https://gitlab.com/blueflyio/agent-platform/agent-buildkit
Version: 1.0 Maintained By: Agent BuildKit Team License: MIT