144 lines
4.0 KiB
TypeScript
144 lines
4.0 KiB
TypeScript
/**
|
|
* Basecamp MCP Server
|
|
*/
|
|
|
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
import {
|
|
CallToolRequestSchema,
|
|
ListToolsRequestSchema,
|
|
ErrorCode,
|
|
McpError,
|
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
import { BasecampClient } from './clients/basecamp.js';
|
|
import { registerProjectsTools } from './tools/projects-tools.js';
|
|
import { registerTodolistsTools } from './tools/todolists-tools.js';
|
|
import { registerTodosTools } from './tools/todos-tools.js';
|
|
import { registerMessagesTools } from './tools/messages-tools.js';
|
|
import { registerCommentsTools } from './tools/comments-tools.js';
|
|
import { registerCampfiresTools } from './tools/campfires-tools.js';
|
|
import { registerSchedulesTools } from './tools/schedules-tools.js';
|
|
import { registerDocumentsTools } from './tools/documents-tools.js';
|
|
import { registerUploadsTools } from './tools/uploads-tools.js';
|
|
import { registerPeopleTools } from './tools/people-tools.js';
|
|
import { registerQuestionnairesTools } from './tools/questionnaires-tools.js';
|
|
import { registerWebhooksTools } from './tools/webhooks-tools.js';
|
|
import { registerRecordingsTools } from './tools/recordings-tools.js';
|
|
|
|
interface BasecampServerConfig {
|
|
accountId: string;
|
|
accessToken: string;
|
|
userAgent?: string;
|
|
}
|
|
|
|
export class BasecampServer {
|
|
private server: Server;
|
|
private client: BasecampClient;
|
|
private tools: Map<string, any>;
|
|
|
|
constructor(config: BasecampServerConfig) {
|
|
this.server = new Server(
|
|
{
|
|
name: 'basecamp-mcp-server',
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
capabilities: {
|
|
tools: {},
|
|
},
|
|
}
|
|
);
|
|
|
|
this.client = new BasecampClient({
|
|
accountId: config.accountId,
|
|
accessToken: config.accessToken,
|
|
userAgent: config.userAgent,
|
|
});
|
|
|
|
this.tools = new Map();
|
|
this.registerAllTools();
|
|
this.setupHandlers();
|
|
|
|
// Error handling
|
|
this.server.onerror = (error) => {
|
|
console.error('[MCP Error]', error);
|
|
};
|
|
|
|
process.on('SIGINT', async () => {
|
|
await this.server.close();
|
|
process.exit(0);
|
|
});
|
|
}
|
|
|
|
private registerAllTools() {
|
|
const toolRegistrars = [
|
|
registerProjectsTools,
|
|
registerTodolistsTools,
|
|
registerTodosTools,
|
|
registerMessagesTools,
|
|
registerCommentsTools,
|
|
registerCampfiresTools,
|
|
registerSchedulesTools,
|
|
registerDocumentsTools,
|
|
registerUploadsTools,
|
|
registerPeopleTools,
|
|
registerQuestionnairesTools,
|
|
registerWebhooksTools,
|
|
registerRecordingsTools,
|
|
];
|
|
|
|
for (const registrar of toolRegistrars) {
|
|
const tools = registrar(this.client);
|
|
for (const tool of tools) {
|
|
this.tools.set(tool.name, tool);
|
|
}
|
|
}
|
|
|
|
console.error(`[Basecamp MCP] Registered ${this.tools.size} tools`);
|
|
}
|
|
|
|
private setupHandlers() {
|
|
// List available tools
|
|
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
const tools = Array.from(this.tools.values()).map((tool) => ({
|
|
name: tool.name,
|
|
description: tool.description,
|
|
inputSchema: tool.inputSchema,
|
|
}));
|
|
|
|
return { tools };
|
|
});
|
|
|
|
// Handle tool calls
|
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
const { name, arguments: args } = request.params;
|
|
|
|
const tool = this.tools.get(name);
|
|
if (!tool) {
|
|
throw new McpError(
|
|
ErrorCode.MethodNotFound,
|
|
`Tool not found: ${name}`
|
|
);
|
|
}
|
|
|
|
try {
|
|
return await tool.handler(args || {});
|
|
} catch (error: any) {
|
|
const errorMessage = error.message || 'Unknown error occurred';
|
|
console.error(`[Tool Error] ${name}:`, errorMessage);
|
|
|
|
throw new McpError(
|
|
ErrorCode.InternalError,
|
|
`Tool execution failed: ${errorMessage}`
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
async run() {
|
|
const transport = new StdioServerTransport();
|
|
await this.server.connect(transport);
|
|
console.error('[Basecamp MCP] Server running on stdio');
|
|
}
|
|
}
|