3.9 KiB
3.9 KiB
MCP Server Architecture — Research Findings
Official SDK: @modelcontextprotocol/sdk
Basic Server Pattern
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
- stdio — local process communication (Claude Desktop, Cursor)
- Streamable HTTP — network transport (replaces deprecated HTTP+SSE)
NodeStreamableHTTPServerTransportfor stateful sessions
Three MCP Primitives
- Tools — Functions the AI can call (primary focus for ERP integration)
- Resources — Data the AI can read (documentation, configs, schemas)
- 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
// 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
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
npx @modelcontextprotocol/inspector
Key Design Decisions for Sage X3 MCP Server
- Which API(s) to use: GraphQL (newest, typed) vs REST vs SOAP (legacy but comprehensive)
- Tool granularity: Domain-specific (get_invoice, search_orders) vs generic (query_graphql)
- Auth strategy: How to manage Sage X3 credentials (env vars, config file)
- Resource layer: Sage X3 documentation, schema info as resources
- 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)