Chapter 3: MCP Protocol Specification Explained

Haiyue
29min

Chapter 3: MCP Protocol Specification Explained

Learning Objectives

  1. Deep understanding of MCP protocol message formats
  2. Master request-response patterns and event streams
  3. Learn protocol versioning and compatibility
  4. Understand error handling and exceptional situations
  5. Master protocol extension mechanisms

3.1 MCP Protocol Basics

Protocol Architecture Overview

// MCP protocol is based on JSON-RPC 2.0 with the following features:
interface MCPProtocolFeatures {
  // Transport layer support
  transport: {
    stdio: 'Standard input/output';
    websocket: 'WebSocket connection';
    http: 'HTTP long polling';
  };

  // Message format
  messageFormat: 'JSON-RPC 2.0';

  // Bidirectional communication
  bidirectional: true;

  // Streaming support
  streaming: boolean;

  // Protocol version
  version: '2024-11-05';
}

// Protocol version definition
const MCP_PROTOCOL_VERSION = '2024-11-05';

// Supported transport methods
enum TransportType {
  STDIO = 'stdio',
  WEBSOCKET = 'websocket',
  HTTP = 'http'
}

JSON-RPC 2.0 Basics

// JSON-RPC 2.0 basic message structure
interface JSONRPCMessage {
  jsonrpc: '2.0';  // Protocol version, must be '2.0'
  id?: string | number | null;  // Message ID, can be omitted for notifications
}

// Request message
interface JSONRPCRequest extends JSONRPCMessage {
  method: string;     // Method name
  params?: any;       // Parameters, can be object or array
  id: string | number; // Request ID, must exist
}

// Response message
interface JSONRPCResponse extends JSONRPCMessage {
  id: string | number | null; // Corresponding request ID
  result?: any;       // Success result
  error?: {           // Error information
    code: number;
    message: string;
    data?: any;
  };
}

// Notification message
interface JSONRPCNotification extends JSONRPCMessage {
  method: string;     // Method name
  params?: any;       // Parameters
  // Note: Notification messages do not have an id field
}

3.2 MCP Message Types and Formats

Initialization Flow

// 1. Initialize request (client -> server)
interface InitializeRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'initialize';
  params: {
    protocolVersion: string;  // MCP protocol version
    capabilities: {
      tools?: {
        listChanged?: boolean;  // Support tool list change notifications
      };
      resources?: {
        subscribe?: boolean;    // Support resource subscriptions
        listChanged?: boolean;  // Support resource list change notifications
      };
      prompts?: {
        listChanged?: boolean;  // Support prompt template list change notifications
      };
      logging?: {};             // Logging support
      experimental?: Record<string, any>; // Experimental features
    };
    clientInfo: {
      name: string;     // Client name
      version: string;  // Client version
    };
  };
}

// 2. Initialize response (server -> client)
interface InitializeResponse {
  jsonrpc: '2.0';
  id: string | number;
  result: {
    protocolVersion: string;  // Protocol version supported by server
    capabilities: {
      tools?: {
        listChanged?: boolean;
      };
      resources?: {
        subscribe?: boolean;
        listChanged?: boolean;
      };
      prompts?: {
        listChanged?: boolean;
      };
      logging?: {};
      experimental?: Record<string, any>;
    };
    serverInfo: {
      name: string;     // Server name
      version: string;  // Server version
    };
    instructions?: string; // Optional server usage instructions
  };
}

// 3. Initialization complete notification (client -> server)
interface InitializedNotification {
  jsonrpc: '2.0';
  method: 'notifications/initialized';
  params?: {};
}

// Initialization flow example
class MCPInitializationFlow {
  async performHandshake(): Promise<void> {
    // Step 1: Client sends initialization request
    const initRequest: InitializeRequest = {
      jsonrpc: '2.0',
      id: 'init-1',
      method: 'initialize',
      params: {
        protocolVersion: '2024-11-05',
        capabilities: {
          tools: { listChanged: true },
          resources: { subscribe: true, listChanged: true },
          prompts: { listChanged: true },
          logging: {}
        },
        clientInfo: {
          name: 'example-client',
          version: '1.0.0'
        }
      }
    };

    console.log('Sending initialization request:', JSON.stringify(initRequest, null, 2));

    // Step 2: Server responds
    const initResponse: InitializeResponse = {
      jsonrpc: '2.0',
      id: 'init-1',
      result: {
        protocolVersion: '2024-11-05',
        capabilities: {
          tools: { listChanged: true },
          resources: { subscribe: false, listChanged: true },
          prompts: { listChanged: false },
          logging: {}
        },
        serverInfo: {
          name: 'example-server',
          version: '1.0.0'
        },
        instructions: 'This is an example MCP server providing file operations and calculation capabilities.'
      }
    };

    console.log('Received initialization response:', JSON.stringify(initResponse, null, 2));

    // Step 3: Client sends initialization complete notification
    const initializedNotification: InitializedNotification = {
      jsonrpc: '2.0',
      method: 'notifications/initialized',
      params: {}
    };

    console.log('Sending initialization complete notification:', JSON.stringify(initializedNotification, null, 2));
  }
}
// List tools request
interface ListToolsRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'tools/list';
  params?: {
    cursor?: string;  // Pagination cursor
  };
}

// List tools response
interface ListToolsResponse {
  jsonrpc: '2.0';
  id: string | number;
  result: {
    tools: Array<{
      name: string;
      description?: string;
      inputSchema: {
        type: 'object';
        properties?: Record<string, any>;
        required?: string[];
      };
    }>;
    nextCursor?: string;  // Next page cursor
  };
}

// Call tool request
interface CallToolRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'tools/call';
  params: {
    name: string;
    arguments?: Record<string, any>;
  };
}

// Call tool response
interface CallToolResponse {
  jsonrpc: '2.0';
  id: string | number;
  result: {
    content: Array<{
      type: 'text' | 'image' | 'resource';
      text?: string;
      data?: string;      // Base64 encoded data
      mimeType?: string;
      uri?: string;       // Resource URI
    }>;
    isError?: boolean;    // Indicates if tool execution had an error
  };
}

// Tool list changed notification
interface ToolsListChangedNotification {
  jsonrpc: '2.0';
  method: 'notifications/tools/list_changed';
  params?: {};
}

// Tool message handling example
class MCPToolsHandler {
  private tools: Map<string, any> = new Map();

  // Handle list tools request
  async handleListTools(request: ListToolsRequest): Promise<ListToolsResponse> {
    const toolsList = Array.from(this.tools.values()).map(tool => ({
      name: tool.name,
      description: tool.description,
      inputSchema: tool.inputSchema
    }));

    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {
        tools: toolsList
      }
    };
  }

  // Handle tool call request
  async handleCallTool(request: CallToolRequest): Promise<CallToolResponse> {
    const { name, arguments: args = {} } = request.params;
    const tool = this.tools.get(name);

    if (!tool) {
      throw new Error(`Unknown tool: ${name}`);
    }

    try {
      const result = await tool.handler(args);

      return {
        jsonrpc: '2.0',
        id: request.id,
        result: {
          content: [
            {
              type: 'text',
              text: typeof result === 'string' ? result : JSON.stringify(result, null, 2)
            }
          ]
        }
      };
    } catch (error) {
      return {
        jsonrpc: '2.0',
        id: request.id,
        result: {
          content: [
            {
              type: 'text',
              text: `Error: ${error.message}`
            }
          ],
          isError: true
        }
      };
    }
  }

  // Send tool list changed notification
  notifyToolsListChanged(): ToolsListChangedNotification {
    return {
      jsonrpc: '2.0',
      method: 'notifications/tools/list_changed',
      params: {}
    };
  }
}
// List resources request
interface ListResourcesRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'resources/list';
  params?: {
    cursor?: string;
  };
}

// List resources response
interface ListResourcesResponse {
  jsonrpc: '2.0';
  id: string | number;
  result: {
    resources: Array<{
      uri: string;
      name: string;
      description?: string;
      mimeType?: string;
    }>;
    nextCursor?: string;
  };
}

// Read resource request
interface ReadResourceRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'resources/read';
  params: {
    uri: string;
  };
}

// Read resource response
interface ReadResourceResponse {
  jsonrpc: '2.0';
  id: string | number;
  result: {
    contents: Array<{
      uri: string;
      mimeType?: string;
      text?: string;
      blob?: string;  // Base64 encoded binary data
    }>;
  };
}

// Subscribe resource request
interface SubscribeResourceRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'resources/subscribe';
  params: {
    uri: string;
  };
}

// Unsubscribe resource request
interface UnsubscribeResourceRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'resources/unsubscribe';
  params: {
    uri: string;
  };
}

// Resource updated notification
interface ResourceUpdatedNotification {
  jsonrpc: '2.0';
  method: 'notifications/resources/updated';
  params: {
    uri: string;
  };
}

// Resource list changed notification
interface ResourcesListChangedNotification {
  jsonrpc: '2.0';
  method: 'notifications/resources/list_changed';
  params?: {};
}

// Resource handling example
class MCPResourcesHandler {
  private resources: Map<string, any> = new Map();
  private subscribers: Map<string, Set<string>> = new Map();

  // Handle resource subscription
  async handleSubscribe(request: SubscribeResourceRequest): Promise<any> {
    const { uri } = request.params;

    if (!this.resources.has(uri)) {
      throw new Error(`Resource not found: ${uri}`);
    }

    // Record subscription
    if (!this.subscribers.has(uri)) {
      this.subscribers.set(uri, new Set());
    }
    this.subscribers.get(uri)!.add(request.id.toString());

    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {}
    };
  }

  // Notify resource update
  notifyResourceUpdate(uri: string): ResourceUpdatedNotification[] {
    const subscribers = this.subscribers.get(uri);
    if (!subscribers || subscribers.size === 0) {
      return [];
    }

    return Array.from(subscribers).map(subscriberId => ({
      jsonrpc: '2.0',
      method: 'notifications/resources/updated',
      params: { uri }
    }));
  }
}
// List prompts request
interface ListPromptsRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'prompts/list';
  params?: {
    cursor?: string;
  };
}

// List prompts response
interface ListPromptsResponse {
  jsonrpc: '2.0';
  id: string | number;
  result: {
    prompts: Array<{
      name: string;
      description?: string;
      arguments?: Array<{
        name: string;
        description: string;
        required?: boolean;
      }>;
    }>;
    nextCursor?: string;
  };
}

// Get prompt request
interface GetPromptRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'prompts/get';
  params: {
    name: string;
    arguments?: Record<string, any>;
  };
}

// Get prompt response
interface GetPromptResponse {
  jsonrpc: '2.0';
  id: string | number;
  result: {
    description?: string;
    messages: Array<{
      role: 'user' | 'assistant' | 'system';
      content: {
        type: 'text' | 'image';
        text?: string;
        data?: string;
        mimeType?: string;
      };
    }>;
  };
}

// Prompt list changed notification
interface PromptsListChangedNotification {
  jsonrpc: '2.0';
  method: 'notifications/prompts/list_changed';
  params?: {};
}

3.3 Error Handling and Status Codes

MCP Error Codes

// Standard error codes defined by MCP
enum MCPErrorCode {
  // JSON-RPC standard errors
  PARSE_ERROR = -32700,
  INVALID_REQUEST = -32600,
  METHOD_NOT_FOUND = -32601,
  INVALID_PARAMS = -32602,
  INTERNAL_ERROR = -32603,

  // MCP-specific errors
  INVALID_TOOL = -32000,
  TOOL_EXECUTION_ERROR = -32001,
  RESOURCE_NOT_FOUND = -32002,
  RESOURCE_ACCESS_DENIED = -32003,
  PROMPT_NOT_FOUND = -32004,
  INVALID_PROMPT_ARGS = -32005
}

// Error response format
interface MCPErrorResponse {
  jsonrpc: '2.0';
  id: string | number | null;
  error: {
    code: MCPErrorCode;
    message: string;
    data?: {
      type?: string;
      description?: string;
      details?: any;
    };
  };
}

// Error handling utility class
class MCPErrorHandler {
  // Create standard error response
  static createErrorResponse(
    id: string | number | null,
    code: MCPErrorCode,
    message: string,
    data?: any
  ): MCPErrorResponse {
    return {
      jsonrpc: '2.0',
      id,
      error: {
        code,
        message,
        data
      }
    };
  }

  // Create tool error
  static createToolError(
    id: string | number,
    toolName: string,
    error: Error
  ): MCPErrorResponse {
    return this.createErrorResponse(
      id,
      MCPErrorCode.TOOL_EXECUTION_ERROR,
      `Tool execution failed: ${toolName}`,
      {
        type: 'tool_error',
        description: error.message,
        details: {
          toolName,
          originalError: error.stack
        }
      }
    );
  }

  // Create resource error
  static createResourceError(
    id: string | number,
    uri: string,
    message: string
  ): MCPErrorResponse {
    return this.createErrorResponse(
      id,
      MCPErrorCode.RESOURCE_NOT_FOUND,
      message,
      {
        type: 'resource_error',
        uri
      }
    );
  }
}

// Error handling example
class MCPServerErrorHandling {
  async handleRequest(request: any): Promise<any> {
    try {
      // Validate request format
      if (!request.jsonrpc || request.jsonrpc !== '2.0') {
        return MCPErrorHandler.createErrorResponse(
          request.id || null,
          MCPErrorCode.INVALID_REQUEST,
          'Invalid JSON-RPC version'
        );
      }

      if (!request.method) {
        return MCPErrorHandler.createErrorResponse(
          request.id || null,
          MCPErrorCode.INVALID_REQUEST,
          'Missing method'
        );
      }

      // Route to specific handler method
      switch (request.method) {
        case 'tools/call':
          return await this.handleToolCall(request);
        case 'resources/read':
          return await this.handleResourceRead(request);
        default:
          return MCPErrorHandler.createErrorResponse(
            request.id,
            MCPErrorCode.METHOD_NOT_FOUND,
            `Method not found: ${request.method}`
          );
      }
    } catch (error) {
      return MCPErrorHandler.createErrorResponse(
        request.id || null,
        MCPErrorCode.INTERNAL_ERROR,
        'Internal server error',
        {
          type: 'internal_error',
          description: error.message
        }
      );
    }
  }

  private async handleToolCall(request: any): Promise<any> {
    try {
      // Tool call logic
      return { /* success response */ };
    } catch (error) {
      return MCPErrorHandler.createToolError(
        request.id,
        request.params?.name || 'unknown',
        error
      );
    }
  }

  private async handleResourceRead(request: any): Promise<any> {
    const uri = request.params?.uri;
    if (!uri) {
      return MCPErrorHandler.createErrorResponse(
        request.id,
        MCPErrorCode.INVALID_PARAMS,
        'Missing required parameter: uri'
      );
    }

    // Resource read logic
    return { /* success response */ };
  }
}

3.4 Protocol Versioning and Compatibility

Version Negotiation

// Version compatibility check
class MCPVersionManager {
  private readonly supportedVersions = ['2024-11-05', '2024-10-07'];
  private readonly currentVersion = '2024-11-05';

  // Check version compatibility
  isVersionSupported(clientVersion: string): boolean {
    return this.supportedVersions.includes(clientVersion);
  }

  // Get compatible version
  getNegotiatedVersion(clientVersion: string): string | null {
    if (this.isVersionSupported(clientVersion)) {
      return clientVersion;
    }

    // Return highest supported version
    return this.supportedVersions[0];
  }

  // Version feature check
  hasFeature(version: string, feature: string): boolean {
    const features = {
      '2024-11-05': [
        'streaming_support',
        'resource_subscriptions',
        'tool_list_changes',
        'enhanced_error_handling'
      ],
      '2024-10-07': [
        'basic_tools',
        'basic_resources',
        'basic_prompts'
      ]
    };

    return features[version]?.includes(feature) || false;
  }

  // Version negotiation during initialization
  negotiateVersion(initRequest: InitializeRequest): {
    version: string;
    capabilities: any;
    errors?: string[];
  } {
    const clientVersion = initRequest.params.protocolVersion;
    const negotiatedVersion = this.getNegotiatedVersion(clientVersion);
    const errors: string[] = [];

    if (!negotiatedVersion) {
      errors.push(`Unsupported protocol version: ${clientVersion}`);
      return { version: this.currentVersion, capabilities: {}, errors };
    }

    if (negotiatedVersion !== clientVersion) {
      errors.push(`Version downgraded from ${clientVersion} to ${negotiatedVersion}`);
    }

    // Adjust capabilities based on negotiated version
    const capabilities = this.getCapabilitiesForVersion(
      negotiatedVersion,
      initRequest.params.capabilities
    );

    return { version: negotiatedVersion, capabilities, errors };
  }

  private getCapabilitiesForVersion(version: string, clientCapabilities: any): any {
    const baseCapabilities = {
      tools: {},
      resources: {},
      prompts: {}
    };

    if (this.hasFeature(version, 'tool_list_changes')) {
      baseCapabilities.tools = { listChanged: true };
    }

    if (this.hasFeature(version, 'resource_subscriptions')) {
      baseCapabilities.resources = { subscribe: true, listChanged: true };
    }

    if (this.hasFeature(version, 'streaming_support')) {
      baseCapabilities.experimental = {
        streaming: true
      };
    }

    return baseCapabilities;
  }
}

Backward Compatibility Handling

// Compatibility adapter
class MCPCompatibilityAdapter {
  // Adapt message format for different versions
  adaptMessage(message: any, fromVersion: string, toVersion: string): any {
    if (fromVersion === toVersion) {
      return message;
    }

    // Adapt from old version to new version
    if (fromVersion === '2024-10-07' && toVersion === '2024-11-05') {
      return this.adaptFrom20241007To20241105(message);
    }

    // Adapt from new version to old version
    if (fromVersion === '2024-11-05' && toVersion === '2024-10-07') {
      return this.adaptFrom20241105To20241007(message);
    }

    return message;
  }

  private adaptFrom20241007To20241105(message: any): any {
    // Add fields supported by new version
    if (message.method === 'tools/call' && message.result) {
      if (!message.result.content) {
        message.result.content = [
          {
            type: 'text',
            text: message.result.text || JSON.stringify(message.result)
          }
        ];
        delete message.result.text;
      }
    }

    return message;
  }

  private adaptFrom20241105To20241007(message: any): any {
    // Remove fields not supported by old version
    if (message.method === 'tools/call' && message.result?.content) {
      const firstContent = message.result.content[0];
      if (firstContent?.type === 'text') {
        message.result.text = firstContent.text;
        delete message.result.content;
      }
    }

    return message;
  }
}

3.5 Streaming and Batch Operations

Streaming Support

// Streaming response interface
interface StreamingResponse {
  jsonrpc: '2.0';
  id: string | number;
  result?: {
    stream: true;
    streamId: string;
  };
  error?: any;
}

// Stream chunk
interface StreamChunk {
  jsonrpc: '2.0';
  method: 'notifications/stream/chunk';
  params: {
    streamId: string;
    chunk: {
      type: 'text' | 'image' | 'data';
      content: any;
      final?: boolean;  // Whether this is the last chunk
    };
  };
}

// Stream manager
class MCPStreamManager {
  private streams: Map<string, any> = new Map();

  // Create streaming response
  createStream(requestId: string | number): { response: StreamingResponse; streamId: string } {
    const streamId = `stream_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;

    this.streams.set(streamId, {
      requestId,
      startTime: Date.now(),
      chunks: []
    });

    return {
      response: {
        jsonrpc: '2.0',
        id: requestId,
        result: {
          stream: true,
          streamId
        }
      },
      streamId
    };
  }

  // Send stream chunk
  sendChunk(streamId: string, content: any, type: 'text' | 'image' | 'data' = 'text', final: boolean = false): StreamChunk {
    const stream = this.streams.get(streamId);
    if (!stream) {
      throw new Error(`Stream not found: ${streamId}`);
    }

    const chunk: StreamChunk = {
      jsonrpc: '2.0',
      method: 'notifications/stream/chunk',
      params: {
        streamId,
        chunk: {
          type,
          content,
          final
        }
      }
    };

    stream.chunks.push(chunk);

    if (final) {
      this.streams.delete(streamId);
    }

    return chunk;
  }

  // Streaming tool call example
  async handleStreamingToolCall(request: CallToolRequest): Promise<StreamingResponse> {
    const { response, streamId } = this.createStream(request.id);

    // Execute tool asynchronously and return results as stream
    this.executeToolWithStreaming(request.params.name, request.params.arguments || {}, streamId);

    return response;
  }

  private async executeToolWithStreaming(toolName: string, args: any, streamId: string): Promise<void> {
    try {
      // Simulate long-running tool
      const results = await this.simulateLongRunningTool(toolName, args);

      for (let i = 0; i < results.length; i++) {
        const isLast = i === results.length - 1;
        this.sendChunk(streamId, results[i], 'text', isLast);

        // Simulate processing delay
        await new Promise(resolve => setTimeout(resolve, 100));
      }
    } catch (error) {
      this.sendChunk(streamId, { error: error.message }, 'text', true);
    }
  }

  private async simulateLongRunningTool(toolName: string, args: any): Promise<string[]> {
    // Simulate tool execution, returning results in chunks
    return [
      'Step 1: Initializing...',
      'Step 2: Processing data...',
      'Step 3: Computing results...',
      'Step 4: Finalizing...',
      'Completed successfully!'
    ];
  }
}

Batch Operations Support

// Batch request
interface BatchRequest {
  jsonrpc: '2.0';
  id: string | number;
  method: 'batch';
  params: {
    requests: Array<{
      method: string;
      params?: any;
      id: string | number;
    }>;
  };
}

// Batch response
interface BatchResponse {
  jsonrpc: '2.0';
  id: string | number;
  result: {
    responses: Array<{
      id: string | number;
      result?: any;
      error?: any;
    }>;
  };
}

// Batch operation handler
class MCPBatchHandler {
  // Handle batch request
  async handleBatch(request: BatchRequest): Promise<BatchResponse> {
    const responses = [];

    for (const subRequest of request.params.requests) {
      try {
        const response = await this.handleSingleRequest({
          jsonrpc: '2.0',
          id: subRequest.id,
          method: subRequest.method,
          params: subRequest.params
        });

        responses.push({
          id: subRequest.id,
          result: response.result,
          error: response.error
        });
      } catch (error) {
        responses.push({
          id: subRequest.id,
          error: {
            code: MCPErrorCode.INTERNAL_ERROR,
            message: error.message
          }
        });
      }
    }

    return {
      jsonrpc: '2.0',
      id: request.id,
      result: {
        responses
      }
    };
  }

  private async handleSingleRequest(request: any): Promise<any> {
    // Single request handling logic
    return { result: { success: true } };
  }
}

3.6 Protocol Extension Mechanism

Experimental Feature Support

// Experimental features definition
interface ExperimentalFeatures {
  streaming?: {
    supported: boolean;
    maxStreams?: number;
  };

  batch?: {
    supported: boolean;
    maxBatchSize?: number;
  };

  customTransports?: {
    supported: boolean;
    transports: string[];
  };

  advancedAuth?: {
    supported: boolean;
    methods: string[];
  };
}

// Extension capability negotiation
class MCPExtensionManager {
  private supportedExtensions: Map<string, any> = new Map();

  registerExtension(name: string, definition: any): void {
    this.supportedExtensions.set(name, definition);
  }

  // Handle extension feature initialization
  negotiateExtensions(clientCapabilities: any): ExperimentalFeatures {
    const experimental: ExperimentalFeatures = {};

    // Streaming extension
    if (clientCapabilities.experimental?.streaming && this.supportedExtensions.has('streaming')) {
      experimental.streaming = {
        supported: true,
        maxStreams: 10
      };
    }

    // Batch operations extension
    if (clientCapabilities.experimental?.batch && this.supportedExtensions.has('batch')) {
      experimental.batch = {
        supported: true,
        maxBatchSize: 100
      };
    }

    return experimental;
  }

  // Handle extension messages
  async handleExtensionMessage(method: string, params: any): Promise<any> {
    const [namespace, action] = method.split('/');

    if (namespace === 'experimental') {
      return await this.handleExperimentalMessage(action, params);
    }

    throw new Error(`Unknown extension namespace: ${namespace}`);
  }

  private async handleExperimentalMessage(action: string, params: any): Promise<any> {
    switch (action) {
      case 'stream_start':
        return await this.handleStreamStart(params);
      case 'batch_execute':
        return await this.handleBatchExecute(params);
      default:
        throw new Error(`Unknown experimental action: ${action}`);
    }
  }

  private async handleStreamStart(params: any): Promise<any> {
    // Implement stream start logic
    return { streamId: 'stream_123', started: true };
  }

  private async handleBatchExecute(params: any): Promise<any> {
    // Implement batch execution logic
    return { batchId: 'batch_456', status: 'processing' };
  }
}

Summary

Through this chapter, we’ve gained a deep understanding of the MCP protocol technical specifications:

  1. Protocol Basics: Bidirectional communication protocol based on JSON-RPC 2.0
  2. Message Types: Message formats for initialization, tools, resources, and prompt templates
  3. Error Handling: Standardized error codes and handling mechanisms
  4. Version Control: Version negotiation and backward compatibility
  5. Advanced Features: Streaming, batch operations, and protocol extensions

These specifications lay a solid foundation for developing robust and reliable MCP Servers. In the next sections, we will learn how to develop specific tool functionalities.

Further Reading