Model Context Protocol

Standardize AI agent tool integrations and resource access using Anthropic open-standard Model Context Protocol.

TL;DR

  1. Use MCP to plug tools and data into any compatible app.
  2. Start local servers over stdio, the simplest transport.
  3. Expose tools, resources, and reusable prompt templates from one server.

MCP Server Architecture

    Server Initialization

    Create an MCP server instance with identity metadata.

    import {
      McpServer,
    } from '@modelcontextprotocol/sdk/server/mcp.js';
    import {
      StdioServerTransport,
    } from '@modelcontextprotocol/sdk/server/stdio.js';
    
    const server = new McpServer({
      name: 'inventory-server',
      version: '1.0.0',
    });
    Register Executable Tool

    Expose typed tool endpoint with Zod schema validation.

    import { z } from 'zod';
    server.tool(
      'get_stock',
      { sku: z.string() },
      async ({ sku }) => ({
        content: [{ type: 'text', text: `SKU: ${sku}` }],
      })
    );
    Stdio Transport Connect

    Connect server to standard input and output streams.

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

Resources And Prompts

    Expose Static Resource

    Provide read-only contextual document identified by URI.

    server.resource(
      'schema',
      'schema://database/main',
      async uri => ({
        contents: [{
          uri: uri.href,
          text: 'CREATE TABLE users (id INT, email TEXT);',
        }],
      })
    );
    Reusable Prompt Template

    Expose standardized prompt workflows to MCP clients.

    server.prompt(
      'review_code',
      { code: z.string() },
      ({ code }) => ({
        messages: [{
          role: 'user',
          content: { type: 'text', text: `Code: ${code}` },
        }],
      })
    );
    Dynamic URI Template

    Route parameterized resource URIs dynamically.

    import {
      ResourceTemplate,
    } from '@modelcontextprotocol/sdk/server/mcp.js';
    const tmpl = new ResourceTemplate(
      'users://{id}/profile',
      { list: undefined }
    );
    server.resource(
      'user-profile',
      tmpl,
      async (u, { id }) => ({
        contents: [{ uri: u.href, text: `User ${id}` }],
      })
    );

MCP Client Consumption

    Client Connection Setup

    Establish client link to local MCP server process.

    import {
      Client,
    } from '@modelcontextprotocol/sdk/client/index.js';
    import {
      StdioClientTransport,
    } from '@modelcontextprotocol/sdk/client/stdio.js';
    
    const transport = new StdioClientTransport({
      command: 'node',
      args: ['./dist/server.js'],
    });
    const client = new Client(
      { name: 'agent-client', version: '1.0' }
    );
    await client.connect(transport);
    List Available Tools

    Query server for active tools and their JSON schemas.

    const { tools } = await client.listTools();
    console.log(`Discovered ${tools.length} MCP tools`);
    Invoke Remote Tool

    Dispatch tool execution call and receive content payload.

    const result = await client.callTool({
      name: 'get_stock',
      arguments: { sku: 'WIDGET-01' },
    });
    console.log(result.content[0].text);

Production MCP Hygiene

    Stderr Logging Rule

    Redirect application logs to stderr to avoid stream corruption.

    console.error('[MCP DEBUG] Processing tool execution');
    // NEVER use console.log in Stdio mode
    // It corrupts JSON-RPC stdout communication
    Transport Error Recovery

    Handle server process disconnection and automatic restart.

    transport.onclose = () => {
      logger.warn('MCP closed. Reconnecting...');
      reconnectClient();
    };
    Security Sandboxing

    Validate client path requests against restricted directory.

    function safePath(userPath: string, rootDir: string) {
      const resolved = path.resolve(rootDir, userPath);
      if (!resolved.startsWith(rootDir)) {
        throw new Error('Access denied');
      }
      return resolved;
    }

Tips

  1. Use the official @modelcontextprotocol/sdk to build type-safe MCP servers with automatic JSON-RPC protocol compliance.
  2. Run local MCP servers over StdioServerTransport so they talk through standard input and output with no open network port.

Warnings

  1. Validate every tool input with zod before acting, because MCP clients can send parameters that trigger unauthorized local actions.
  2. Do not call console.log in stdio mode, because stray text on standard output corrupts the JSON-RPC stream. Use console.error.

In Practice

FAQ