Files
openproject-mcp/src/server.ts
T

68 lines
2.2 KiB
TypeScript

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import type { AppConfig } from "./config";
import { OpenProjectClient } from "./client/api-client";
import { runWithContext } from "./context";
import { registerAllTools } from "./tools";
import { formatToolError } from "./tools/common";
import { OpenProjectError } from "./client/errors";
export interface OpenProjectMcpServer {
server: McpServer;
client: OpenProjectClient;
start: (transport?: Transport) => Promise<void>;
stop: () => Promise<void>;
}
export const SERVER_NAME = "openproject-mcp";
export const SERVER_VERSION = "0.1.0";
/**
* Creates and configures an OpenProject MCP server instance.
*
* @param config - Server configuration including baseUrl, apiKey, and readOnly flag.
* @returns Configured OpenProjectMcpServer instance with lifecycle methods.
*/
export function createServer(config: AppConfig): OpenProjectMcpServer {
const server = new McpServer({
name: SERVER_NAME,
version: SERVER_VERSION,
});
const client = new OpenProjectClient({
baseUrl: config.baseUrl,
apiKey: config.apiKey,
});
// Register all tools with ambient context execution and read-only guards
registerAllTools(server, {
readOnly: config.readOnly,
wrapExecute: async (fn, tool) => {
if (config.readOnly && !tool.readOnly) {
return formatToolError(
new OpenProjectError(
"SERVER_READ_ONLY",
"Operation rejected. OpenProject MCP server is running in read-only mode."
)
);
}
return runWithContext({ client, isReadOnly: config.readOnly }, fn);
},
});
return {
server,
client,
start: async (transport?: Transport) => {
const activeTransport = transport ?? new StdioServerTransport();
await server.connect(activeTransport);
console.error(`[${SERVER_NAME}] Server started (readOnly=${config.readOnly})`);
},
stop: async () => {
await server.close();
console.error(`[${SERVER_NAME}] Server stopped`);
},
};
}