# MCP Server Architecture — Research Findings ## Official SDK: @modelcontextprotocol/sdk ### Basic Server Pattern ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; const server = new McpServer({ name: "my-server", version: "1.0.0", }); // Register a tool server.tool( "tool-name", "Tool description for AI agent", { param: z.string() }, async ({ param }) => ({ content: [{ type: "text", text: `Result: ${param}` }], }), ); // Connect via stdio const transport = new StdioServerTransport(); await server.connect(transport); ``` ### Transport Options 1. **stdio** — local process communication (Claude Desktop, Cursor) 2. **Streamable HTTP** — network transport (replaces deprecated HTTP+SSE) - `NodeStreamableHTTPServerTransport` for stateful sessions ### Three MCP Primitives 1. **Tools** — Functions the AI can call (primary focus for ERP integration) 2. **Resources** — Data the AI can read (documentation, configs, schemas) 3. **Prompts** — Template conversations for common scenarios ## Production MCP Server Requirements ### What the spec covers: - Capability negotiation (initialize) - Tool listing/execution (tools/list, tools/call) - Resource listing/reading (resources/list, resources/read) - Transport: stdio and Streamable HTTP ### What production requires beyond spec: - Authentication and authorization (OAuth2, JWT) - Rate limiting per IP/token/tool - Input schema validation before execution - Concurrency control - Backpressure when saturated - Observability (Prometheus metrics, OpenTelemetry traces) - CORS, CSP, max request body size - Signal handling (SIGTERM, graceful shutdown) - Error handling and retry patterns ## Tool Design Best Practices ### Schema Precision ```typescript // BAD — vague schema inputSchema: { type: "object" } // GOOD — precise and documented inputSchema: { type: "object", properties: { query: { type: "string", description: "SQL SELECT query to execute", }, limit: { type: "number", minimum: 1, maximum: 100, default: 10, description: "Maximum number of rows to return", }, }, required: ["query"], additionalProperties: false, } ``` ### Tool Granularity for ERP - **Fine-grained** tools: `get_invoice`, `search_customers`, `check_stock` - Each tool has **clear purpose** and **precise schema** - AI agent uses schema + description to decide when to call ### Resource Patterns for Documentation ```typescript server.registerResource( { uri: "sage://help/invoicing", name: "Invoice Help", description: "Sage X3 invoicing documentation", mimeType: "text/markdown", }, async () => ({ text: "# Invoice Help\n...", }), ); ``` ## Existing ERP MCP Server: @casys/mcp-erpnext - Connects AI agents to ERPNext (open-source ERP) - Exposes invoices, purchase orders, stock levels, accounting data - Good reference for design patterns: - Focused scope per tool - Strong input validation - Read-only defaults with explicit write permissions ## Testing - **mcp-inspector**: Official CLI testing tool - **Programmatic testing**: Use SDK's Client class ```bash npx @modelcontextprotocol/inspector ``` ## Key Design Decisions for Sage X3 MCP Server 1. **Which API(s) to use**: GraphQL (newest, typed) vs REST vs SOAP (legacy but comprehensive) 2. **Tool granularity**: Domain-specific (get_invoice, search_orders) vs generic (query_graphql) 3. **Auth strategy**: How to manage Sage X3 credentials (env vars, config file) 4. **Resource layer**: Sage X3 documentation, schema info as resources 5. **Prompt templates**: Common troubleshooting scenarios ## IMPORTANT NOTE FOR AGENTS When using `background_task` or similar functions, **timeouts are in MILLISECONDS not seconds**. - 60 seconds = 60000 ms - 120 seconds = 120000 ms - Default timeout: 120000 ms (2 minutes)