tamabahan

This commit is contained in:
bipproduction
2025-10-08 19:41:57 +08:00
parent f580dba49d
commit f4e5bff621
4 changed files with 270 additions and 36 deletions

View File

@@ -0,0 +1,94 @@
import { Elysia, t } from 'elysia';
import { randomUUID } from 'node:crypto';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
// Map untuk menyimpan transport berdasarkan sessionId
const transports: Record<string, StreamableHTTPServerTransport> = {};
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(
'/mcp',
async ({ body, request, set }) => {
const sessionId = request.headers.get('mcp-session-id') ?? undefined;
let transport: StreamableHTTPServerTransport;
// Jika ada sessionId, pakai transport lama
if (sessionId && transports[sessionId]) {
transport = transports[sessionId];
} else if (!sessionId && isInitializeRequest(body)) {
// Jika belum ada session & ini request inisialisasi
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (sid) => {
transports[sid] = transport;
},
});
// Cleanup transport jika ditutup
transport.onclose = () => {
if (transport.sessionId) {
delete transports[transport.sessionId];
}
};
// Inisialisasi MCP server
const server = new McpServer({
name: 'example-server',
version: '1.0.0',
});
// ... di sini bisa ditambahkan tools, prompts, dsb ...
await server.connect(transport);
} else {
set.status = 400;
return {
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: No valid session ID provided',
},
id: null,
};
}
// Jalankan handler HTTP MCP
return await transport.handleRequest(
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
}
)
// Handler reusable untuk GET & DELETE
.derive(({ request, set }) => {
const sessionId = request.headers.get('mcp-session-id') ?? undefined;
const transport = sessionId ? transports[sessionId] : undefined;
if (!transport) {
set.status = 400;
throw new Error('Invalid or missing session ID');
}
return { transport };
})
// 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('/mcp', async ({ transport, request }) => {
return await transport.handleRequest(request as any, new Response() as any);
})
export default McpRoute