Skip to content

MCP Protocol Reference

Understanding how Orchestre implements and uses the Model Context Protocol.

Overview

The Model Context Protocol (MCP) is a standard protocol for communication between AI assistants and external tools. Orchestre implements MCP to expose its orchestration capabilities to Claude Code.

Protocol Implementation

Server Initialization

typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new Server(
  {
    name: "orchestre",
    version: "3.0.0"
  },
  {
    capabilities: {
      tools: {}
    }
  }
);

Message Format

All MCP communications use JSON-RPC 2.0 format:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "analyze_project",
    "arguments": {
      "requirements": "Build a SaaS application"
    }
  }
}

Tool Registration

Tool Definition Schema

typescript
interface MCPTool {
  name: string;
  description: string;
  inputSchema: {
    type: "object";
    properties: Record<string, any>;
    required?: string[];
  };
}

Registering Tools

typescript
server.addTool(
  {
    name: "analyze_project",
    description: "Analyze project requirements using AI",
    inputSchema: {
      type: "object",
      properties: {
        requirements: {
          type: "string",
          description: "Project requirements to analyze"
        }
      },
      required: ["requirements"]
    }
  },
  async (params) => {
    // Tool implementation
    const result = await analyzeProject(params);
    return {
      content: [{
        type: "text",
        text: JSON.stringify(result, null, 2)
      }]
    };
  }
);

Request/Response Cycle

1. Tool Discovery

Claude Code discovers available tools:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}

Response:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "initialize_project",
        "description": "Initialize a new project with a template",
        "inputSchema": { /* ... */ }
      },
      // ... more tools
    ]
  }
}

2. Tool Invocation

Claude Code calls a tool:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "generate_plan",
    "arguments": {
      "analysis": { /* analysis result */ },
      "requirements": "Build SaaS with auth and billing"
    }
  }
}

3. Tool Response

Tool returns result:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [{
      "type": "text",
      "text": "{\"phases\": [...]}"
    }]
  }
}

Error Handling

Error Response Format

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": {
      "details": "Missing required field: requirements"
    }
  }
}

Standard Error Codes

CodeMessageDescription
-32700Parse errorInvalid JSON
-32600Invalid RequestInvalid request object
-32601Method not foundUnknown method
-32602Invalid paramsInvalid method parameters
-32603Internal errorInternal server error

Tool-Specific Errors

typescript
// In tool implementation
if (!params.requirements) {
  return {
    content: [{
      type: "text",
      text: JSON.stringify({
        error: "Requirements are required",
        code: "MISSING_REQUIREMENTS",
        suggestion: "Provide project requirements as a string"
      })
    }],
    isError: true
  };
}

Transport Layer

Stdio Transport

Orchestre uses stdio transport for communication:

typescript
const transport = new StdioServerTransport();
await server.connect(transport);

Message Flow

  1. Claude Code spawns Orchestre process
  2. Communication via stdin/stdout
  3. Structured JSON-RPC messages
  4. Async request/response handling

Security Considerations

Input Validation

All inputs are validated using Zod schemas:

typescript
const schema = z.object({
  requirements: z.string().min(10).max(5000),
  constraints: z.array(z.string()).optional()
});

const validated = schema.parse(params);

API Key Protection

Sensitive keys are never exposed in responses:

typescript
// Never log or return API keys
const sanitized = {
  ...result,
  apiKey: "[REDACTED]"
};

Rate Limiting

Implement rate limiting for expensive operations:

typescript
const rateLimiter = new Map<string, number[]>();

function checkRateLimit(operation: string): boolean {
  const now = Date.now();
  const requests = rateLimiter.get(operation) || [];
  const recentRequests = requests.filter(t => now - t < 60000);
  
  if (recentRequests.length >= 10) {
    return false;
  }
  
  rateLimiter.set(operation, [...recentRequests, now]);
  return true;
}

Best Practices

1. Consistent Response Format

Always return structured JSON:

typescript
return {
  content: [{
    type: "text",
    text: JSON.stringify({
      success: true,
      data: result,
      metadata: {
        timestamp: new Date().toISOString(),
        version: "3.0.0"
      }
    }, null, 2)
  }]
};

2. Comprehensive Error Messages

Provide actionable error information:

typescript
return {
  content: [{
    type: "text",
    text: JSON.stringify({
      error: "Template not found",
      code: "TEMPLATE_NOT_FOUND",
      availableTemplates: ["makerkit-nextjs", "cloudflare-hono"],
      suggestion: "Choose one of the available templates"
    })
  }],
  isError: true
};

3. Async Operation Handling

Handle long-running operations gracefully:

typescript
async function longOperation(params: any) {
  // Return progress updates
  return {
    content: [{
      type: "text",
      text: JSON.stringify({
        status: "in_progress",
        message: "Analyzing requirements...",
        estimatedTime: "30 seconds"
      })
    }]
  };
}

Integration with Claude Code

Configuration

In Claude Code settings:

json
{
  "mcpServers": {
    "orchestre": {
      "command": "node",
      "args": ["/path/to/orchestre/dist/server.js"],
      "env": {
        "GEMINI_API_KEY": "your-key",
        "OPENAI_API_KEY": "your-key"
      }
    }
  }
}

Usage in Prompts

Tools are invoked through natural language:

/orchestrate "Build a SaaS application with user authentication and subscription billing"

Claude Code translates this to MCP tool calls.

Advanced Features

Tool Composition

Tools can be composed for complex operations:

typescript
const analysis = await analyzeProject({ requirements });
const plan = await generatePlan({ analysis, requirements });
const review = await multiLlmReview({ plan });

Streaming Responses

For real-time updates (future enhancement):

typescript
return {
  content: [{
    type: "text",
    text: "Starting analysis...",
    stream: true
  }]
};

Context Preservation

Maintain context across tool calls:

typescript
const context = new Map<string, any>();

server.addTool({
  name: "set_context",
  // ... tool definition
}, async (params) => {
  context.set(params.key, params.value);
  return { success: true };
});

Debugging

Enable Debug Logging

bash
ORCHESTRE_DEBUG=true node dist/server.js

Log Message Flow

typescript
if (process.env.ORCHESTRE_DEBUG) {
  console.error(`[MCP] <- ${JSON.stringify(request)}`);
  console.error(`[MCP] -> ${JSON.stringify(response)}`);
}

Common Issues

  1. Tool Not Found

    • Verify tool name matches registration
    • Check tool list response
  2. Invalid Parameters

    • Validate against input schema
    • Check required fields
  3. Timeout Errors

    • Increase timeout settings
    • Optimize tool performance

See Also

Built with ❤️ for the AI Coding community, by Praney Behl