Files
MCP-OpenProject/src/index.ts
T
2026-03-12 16:56:56 +08:00

75 lines
2.0 KiB
JavaScript

#!/usr/bin/env node
/**
* OpenProject MCP Server
*
* Connects Claude to OpenProject via the v3 REST API.
*
* Environment variables:
* OPENPROJECT_URL — Base URL of your OpenProject instance (e.g. https://op.example.com)
* OPENPROJECT_API_KEY — API key (generated under My Account > Access Tokens)
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { OpenProjectClient } from "./client.js";
import { toolDefs } from "./tools.js";
import { createHandlers } from "./handlers.js";
function getEnvOrThrow(name: string): string {
const value = process.env[name];
if (!value) {
console.error(`Missing required environment variable: ${name}`);
process.exit(1);
}
return value;
}
const client = new OpenProjectClient({
baseUrl: getEnvOrThrow("OPENPROJECT_URL"),
apiKey: getEnvOrThrow("OPENPROJECT_API_KEY"),
});
const handlers = createHandlers(client);
const server = new McpServer({
name: "openproject",
version: "0.1.0",
});
// Register each tool from toolDefs with its corresponding handler.
for (const [name, def] of Object.entries(toolDefs)) {
const handler = handlers[name as keyof typeof handlers];
if (!handler) {
console.error(`No handler for tool: ${name}`);
continue;
}
server.tool(
name,
def.description,
def.inputSchema,
async (args: any) => {
try {
const result = await (handler as Function)(args);
return { content: [{ type: "text" as const, text: String(result) }] };
} catch (err: any) {
return {
content: [{ type: "text" as const, text: `Error: ${err.message}` }],
isError: true,
};
}
},
);
}
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("OpenProject MCP server running on stdio");
}
main().catch((err) => {
console.error("Fatal error:", err);
process.exit(1);
});