/** * Xero MCP Server * Provides modular tools for Xero Accounting API operations */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, Tool } from '@modelcontextprotocol/sdk/types.js'; import { XeroClient } from './clients/xero.js'; import { getAllTools, handleToolCall as handleTool } from './tools/index.js'; export class XeroMCPServer { private server: Server; private client: XeroClient; private toolsCache: Tool[] | null = null; constructor(client: XeroClient) { this.client = client; this.server = new Server( { name: 'xero-mcp', version: '1.0.0' }, { capabilities: { tools: {} } } ); this.setupHandlers(); } private setupHandlers(): void { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: this.getTools() })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const result = await handleTool(name, args || {}, this.client); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: 'text', text: JSON.stringify({ error: errorMessage }, null, 2) } ], isError: true }; } }); } private getTools(): Tool[] { if (this.toolsCache) { return this.toolsCache; } this.toolsCache = getAllTools(this.client); console.error(`Loaded ${this.toolsCache.length} Xero tools`); return this.toolsCache; } async run(): Promise { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('Xero MCP Server running on stdio'); } }