tamabahan

This commit is contained in:
bipproduction
2025-10-08 19:51:40 +08:00
parent f4e5bff621
commit 4bf052b15e

View File

@@ -8,22 +8,18 @@ import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
const transports: Record<string, StreamableHTTPServerTransport> = {}; const transports: Record<string, StreamableHTTPServerTransport> = {};
const McpRoute = new Elysia() const McpRoute = new Elysia()
// Middleware global untuk JSON parsing & header access
.onRequest(({ set }) => {
set.headers['Content-Type'] = 'application/json';
})
// Route utama untuk komunikasi client → server
.post( .post(
'/mcp', '/mcp',
async ({ body, request, set }) => { async ({ body, request, set }) => {
const sessionId = request.headers.get('mcp-session-id') ?? undefined; const sessionId = request.headers.get('mcp-session-id') ?? undefined;
let transport: StreamableHTTPServerTransport; let transport: StreamableHTTPServerTransport;
// Jika ada sessionId, pakai transport lama // Jika ada sessionId lama, gunakan ulang transport-nya
if (sessionId && transports[sessionId]) { if (sessionId && transports[sessionId]) {
transport = transports[sessionId]; transport = transports[sessionId];
} else if (!sessionId && isInitializeRequest(body)) { }
// Jika belum ada session & ini request inisialisasi // Jika request inisialisasi baru
else if (!sessionId && isInitializeRequest(body)) {
transport = new StreamableHTTPServerTransport({ transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(), sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (sid) => { onsessioninitialized: (sid) => {
@@ -31,22 +27,35 @@ const McpRoute = new Elysia()
}, },
}); });
// Cleanup transport jika ditutup
transport.onclose = () => { transport.onclose = () => {
if (transport.sessionId) { if (transport.sessionId) delete transports[transport.sessionId];
delete transports[transport.sessionId];
}
}; };
// Inisialisasi MCP server // Inisialisasi MCP Server
const server = new McpServer({ const server = new McpServer({
name: 'example-server', name: 'example-server',
version: '1.0.0', version: '1.0.0',
}); });
// ... di sini bisa ditambahkan tools, prompts, dsb ... // Tambahkan resource, tools, dsb di sini jika perlu
await server.connect(transport); await server.connect(transport);
} else {
// Tunggu sampai session terbentuk
await new Promise<void>((resolve) => {
const check = () => {
if (transport.sessionId) return resolve();
setTimeout(check, 5);
};
check();
});
// Kirim sessionId kembali ke client
set.headers['mcp-session-id'] = transport.sessionId!;
set.status = 200;
return { sessionId: transport.sessionId };
}
// Jika request invalid
else {
set.status = 400; set.status = 400;
return { return {
jsonrpc: '2.0', jsonrpc: '2.0',
@@ -59,36 +68,37 @@ const McpRoute = new Elysia()
} }
// Jalankan handler HTTP MCP // Jalankan handler HTTP MCP
return await transport.handleRequest( return await transport.handleRequest(request, new Response(), body);
request as any,
// Simulasi `Response` agar Elysia bisa mengembalikan hasil
new Response(null, { status: 200 }) as any,
body
);
}, },
{ {
body: t.Any(), // fleksibel untuk JSON-RPC body: t.Any(),
} }
) )
// Handler reusable untuk GET & DELETE // Handler GET untuk SSE (server → client)
.derive(({ request, set }) => { .get('/mcp', async ({ request, set }) => {
const sessionId = request.headers.get('mcp-session-id') ?? undefined; const sessionId = request.headers.get('mcp-session-id') ?? undefined;
const transport = sessionId ? transports[sessionId] : undefined; const transport = sessionId ? transports[sessionId] : undefined;
if (!transport) { if (!transport) {
set.status = 400; set.status = 400;
throw new Error('Invalid or missing session ID'); return 'Invalid or missing session ID';
} }
return { transport }; set.status = 200;
}) return await transport.handleRequest(request, new Response());
// GET untuk server → client via SSE
.get('/mcp', async ({ transport, request }) => {
return await transport.handleRequest(request as any, new Response() as any);
}) })
// DELETE untuk terminasi session // DELETE untuk terminasi session
.delete('/mcp', async ({ transport, request }) => { .delete('/mcp', async ({ request, set }) => {
return await transport.handleRequest(request as any, new Response() as any); const sessionId = request.headers.get('mcp-session-id') ?? undefined;
const transport = sessionId ? transports[sessionId] : undefined;
if (!transport) {
set.status = 400;
return 'Invalid or missing session ID';
}
set.status = 200;
return await transport.handleRequest(request, new Response());
}) })
export default McpRoute export default McpRoute