87 lines
2.1 KiB
TypeScript

/**
* 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<void> {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Xero MCP Server running on stdio');
}
}