diff --git a/docs/adding_local_servers.md b/docs/adding_local_servers.md new file mode 100644 index 0000000..843f285 --- /dev/null +++ b/docs/adding_local_servers.md @@ -0,0 +1,249 @@ +# 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`: + +```typescript +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`: + +```typescript +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: + +```typescript +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: + +```typescript +// 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: + +```typescript +// 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: + +```typescript +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. \ No newline at end of file