tamabahan
This commit is contained in:
@@ -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
|
||||||
Reference in New Issue
Block a user