mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-30 03:19:11 +00:00
fix(mcp): session ID mismatch, rename_rundown data loss, DELETE status
- Session ID: deterministic UUID passed to sessionIdGenerator so the
map key matches the mcp-session-id header sent to clients; previously
two independent randomUUID() calls produced different IDs, breaking
all post-initialize requests
- rename_rundown: use spread { ...rundown, title } instead of narrow
structuredClone cast that silently stripped order/entries/revision
- DELETE /mcp: return 204 No Content instead of 200 with body
https://claude.ai/code/session_01U24MeuUacYXeQhbX3tatEe
This commit is contained in:
@@ -355,12 +355,11 @@ async function handleToolCall(name: string, args: Record<string, unknown>): Prom
|
|||||||
try {
|
try {
|
||||||
const { id, title } = args as { id: string; title: string };
|
const { id, title } = args as { id: string; title: string };
|
||||||
const dataProvider = getDataProvider();
|
const dataProvider = getDataProvider();
|
||||||
const rundown = structuredClone(dataProvider.getRundown(id)) as { id: string; title: string };
|
const rundown = dataProvider.getRundown(id);
|
||||||
rundown.title = title;
|
if (!rundown) throw new Error(`Rundown ${id} not found`);
|
||||||
await dataProvider.setRundown(id, rundown as never);
|
await dataProvider.setRundown(id, { ...rundown, title });
|
||||||
if (id === getCurrentRundown().id) {
|
if (id === getCurrentRundown().id) {
|
||||||
const customFields = dataProvider.getCustomFields();
|
await initRundown(dataProvider.getRundown(id), dataProvider.getCustomFields());
|
||||||
await initRundown(rundown as never, customFields);
|
|
||||||
}
|
}
|
||||||
return ok(rundownListResponse());
|
return ok(rundownListResponse());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -536,17 +535,15 @@ mcpRouter.post('/', async (req, res) => {
|
|||||||
const sessionId = req.headers['mcp-session-id'] as string | undefined;
|
const sessionId = req.headers['mcp-session-id'] as string | undefined;
|
||||||
|
|
||||||
if (isInitializeRequest(body)) {
|
if (isInitializeRequest(body)) {
|
||||||
// New session: create server + transport
|
// New session: pin the session ID so the map key matches what the transport
|
||||||
|
// sends back to the client in the mcp-session-id response header.
|
||||||
|
const sessionId = randomUUID();
|
||||||
const transport = new StreamableHTTPServerTransport({
|
const transport = new StreamableHTTPServerTransport({
|
||||||
sessionIdGenerator: () => randomUUID(),
|
sessionIdGenerator: () => sessionId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const id = randomUUID();
|
sessions.set(sessionId, transport);
|
||||||
sessions.set(id, transport);
|
transport.onclose = () => sessions.delete(sessionId);
|
||||||
|
|
||||||
transport.onclose = () => {
|
|
||||||
sessions.delete(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const mcpServer = createMcpServer();
|
const mcpServer = createMcpServer();
|
||||||
await mcpServer.connect(transport);
|
await mcpServer.connect(transport);
|
||||||
@@ -587,5 +584,5 @@ mcpRouter.delete('/', async (req, res) => {
|
|||||||
const transport = sessions.get(sessionId)!;
|
const transport = sessions.get(sessionId)!;
|
||||||
sessions.delete(sessionId);
|
sessions.delete(sessionId);
|
||||||
await transport.close();
|
await transport.close();
|
||||||
res.status(200).json({ ok: true });
|
res.status(204).send();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user