mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-21 23:19:09 +00:00
expose mcp server in ontime
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||
|
||||
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
||||
import express from 'express';
|
||||
import type { Request, Response, Router } from 'express';
|
||||
import { LogOrigin } from 'ontime-types';
|
||||
|
||||
import { logger } from '../classes/Logger.js';
|
||||
import { createMcpServer } from './mcp.server.js';
|
||||
|
||||
export const mcpRouter: Router = express.Router();
|
||||
|
||||
mcpRouter.post('/', async (req, res) => {
|
||||
// A new Server instance is created per request — required for stateless mode where
|
||||
// each POST is independent and concurrent requests must not share transport state.
|
||||
const transport = new StreamableHTTPServerTransport({
|
||||
sessionIdGenerator: undefined, // stateless: no session tracking
|
||||
enableJsonResponse: true,
|
||||
});
|
||||
const server = createMcpServer();
|
||||
|
||||
let cleanedUp = false;
|
||||
const cleanup = async () => {
|
||||
if (cleanedUp) return;
|
||||
cleanedUp = true;
|
||||
transport.close();
|
||||
await server.close?.();
|
||||
};
|
||||
|
||||
res.on('close', () => void cleanup());
|
||||
res.on('finish', () => void cleanup());
|
||||
|
||||
try {
|
||||
await server.connect(transport);
|
||||
await transport.handleRequest(req as IncomingMessage, res as ServerResponse, req.body);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
logger.error(LogOrigin.Server, `MCP request failed: ${message}`);
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message }, id: req.body?.id ?? null });
|
||||
}
|
||||
} finally {
|
||||
await cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
// Stateless mode: GET (SSE) and DELETE (session teardown) are not applicable.
|
||||
// All MCP interactions happen via POST in a single request/response cycle.
|
||||
const methodNotAllowed = (_req: Request, res: Response) =>
|
||||
void res.status(405).json({ jsonrpc: '2.0', error: { code: -32000, message: 'Method not allowed.' }, id: null });
|
||||
|
||||
mcpRouter.get('/', methodNotAllowed);
|
||||
mcpRouter.delete('/', methodNotAllowed);
|
||||
Reference in New Issue
Block a user