example-remote-client/docs/adding_local_servers.md
Jerome e746c42f8d
Add documentation for creating in-memory MCP servers
- Explain how to create and register in-memory servers
- Provide examples using the Server class and tool() method
- Include best practices and debugging tips
- Document limitations of in-memory servers
- Add complete calculator server example
2025-06-19 17:12:50 +01:00

5.9 KiB
Raw Blame History

Adding In-Memory MCP Servers

This guide explains how to add in-memory MCP servers that run within the browser, using the InMemoryTransport from the MCP SDK.

Overview

In-memory servers are useful for:

  • Testing MCP functionality without external servers
  • Providing demo capabilities
  • Development and debugging
  • Offline functionality

These servers run in the same JavaScript process as the client and communicate via the InMemoryTransport, eliminating network overhead and CORS issues.

Creating an In-Memory Server

1. Create Your Server Implementation

Create a new file in src/mcp/servers/your-server/index.ts:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { z } from "zod";

export function createServer() {
    // Create an MCP server instance
    const server = new Server({
        name: "your-server-name",
        version: "1.0.0"
    }, {
        capabilities: {
            tools: {}  // Enable tools capability
        }
    });

    // Register tools using the McpFunction helper
    server.tool(
        "tool_name",
        "Tool description",
        {
            // Zod schema for input validation
            param1: z.string().describe("Parameter description"),
            param2: z.number().optional()
        },
        async ({ param1, param2 }) => {
            // Tool implementation
            return {
                content: [{ 
                    type: "text", 
                    text: `Result: ${param1}` 
                }]
            };
        }
    );

    return server;
}

2. Register Your Server

Add your server to the available servers list in src/mcp/servers/index.ts:

import { createServer as createTestServer } from "./test";
import { createServer as createYourServer } from "./your-server";
import type { MCPServerConfig } from "@/types/mcp";

export const availableServers: MCPServerConfig[] = [
    {
        name: "In-Memory Test Server",
        url: "local",
        localServer: createTestServer
    },
    {
        name: "Your Server Name",
        url: "local",
        localServer: createYourServer
    }
];

Server Implementation Details

Tool Registration

The MCP SDK provides a convenient tool() method for registering tools:

server.tool(
    "tool_name",           // Tool identifier
    "Tool description",    // Human-readable description
    {                      // Zod schema for parameters
        param: z.string()
    },
    async (args) => {      // Implementation function
        // Tool logic here
        return {
            content: [{
                type: "text",
                text: "Result"
            }]
        };
    }
);

Available Content Types

Tools can return different content types:

// Text content
return {
    content: [{
        type: "text",
        text: "Hello, world!"
    }]
};

// Error content
return {
    content: [{
        type: "text",
        text: "Error: Something went wrong"
    }],
    isError: true
};

// Multiple content blocks
return {
    content: [
        { type: "text", text: "Line 1" },
        { type: "text", text: "Line 2" }
    ]
};

Resources and Prompts

You can also implement resources and prompts:

// Resources
server.resource(
    "resource_uri",
    "Resource name",
    "Resource description",
    async () => ({
        content: [{
            type: "text",
            text: "Resource content"
        }]
    })
);

// Prompts
server.prompt(
    "prompt_name",
    "Prompt description",
    {
        param: z.string()
    },
    async ({ param }) => ({
        messages: [{
            role: "user",
            content: { type: "text", text: `Prompt with ${param}` }
        }]
    })
);

Best Practices

  1. Naming: Use descriptive names for your servers and tools
  2. Error Handling: Always handle errors gracefully and return meaningful error messages
  3. Validation: Use Zod schemas to validate input parameters
  4. Documentation: Include clear descriptions for tools and parameters
  5. Testing: Test your server implementation before adding it to the production list

Example: Calculator Server

Here's a complete example of a calculator server:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { z } from "zod";

export function createServer() {
    const server = new Server({
        name: "calculator",
        version: "1.0.0"
    }, {
        capabilities: {
            tools: {}
        }
    });

    server.tool(
        "add",
        "Add two numbers",
        {
            a: z.number().describe("First number"),
            b: z.number().describe("Second number")
        },
        async ({ a, b }) => ({
            content: [{
                type: "text",
                text: `${a} + ${b} = ${a + b}`
            }]
        })
    );

    server.tool(
        "multiply",
        "Multiply two numbers",
        {
            a: z.number().describe("First number"),
            b: z.number().describe("Second number")
        },
        async ({ a, b }) => ({
            content: [{
                type: "text",
                text: `${a} × ${b} = ${a * b}`
            }]
        })
    );

    return server;
}

Debugging

In-memory servers will automatically connect when the application starts. You can see their status in the MCP tab of the UI, where they'll be marked with an "In-Memory" badge.

To debug your server:

  1. Check the browser console for connection errors
  2. Use the MCP message monitor to see tool calls and responses
  3. Add console.log statements in your tool implementations

Limitations

  • In-memory servers are cleared when the page refreshes
  • They cannot persist data between sessions
  • They run in the browser's JavaScript environment, so they cannot access filesystem or system resources
  • Performance is limited by the browser's capabilities

For production use cases requiring persistence or system access, use external MCP servers instead.