tamabahan
This commit is contained in:
@@ -9,7 +9,6 @@ import Auth from "./server/routes/auth_route";
|
||||
import CredentialRoute from "./server/routes/credential_route";
|
||||
import DarmasabaRoute from "./server/routes/darmasaba_route";
|
||||
import { convertOpenApiToMcp } from "./server/lib/mcp-converter";
|
||||
import McpRoute from "./server/routes/mcp_route";
|
||||
|
||||
const Docs = new Elysia()
|
||||
.use(Swagger({
|
||||
@@ -48,7 +47,7 @@ const app = new Elysia()
|
||||
tags: ["MCP"],
|
||||
}
|
||||
})
|
||||
.use(McpRoute)
|
||||
// .use(McpRoute)
|
||||
.get("*", html)
|
||||
.listen(3000, () => {
|
||||
console.log("Server running at http://localhost:3000");
|
||||
|
||||
@@ -55,7 +55,8 @@ const ApiKeyRoute = new Elysia({
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
summary: 'create api key',
|
||||
summary: 'create',
|
||||
description: 'create api key by user',
|
||||
},
|
||||
body: t.Object({
|
||||
name: t.String(),
|
||||
@@ -77,7 +78,8 @@ const ApiKeyRoute = new Elysia({
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
summary: 'get api key list',
|
||||
summary: 'list',
|
||||
description: 'get api key list by user',
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -94,7 +96,8 @@ const ApiKeyRoute = new Elysia({
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
summary: 'delete api key',
|
||||
summary: 'delete',
|
||||
description: 'delete api key by id',
|
||||
},
|
||||
body: t.Object({
|
||||
id: t.String(),
|
||||
|
||||
@@ -133,8 +133,8 @@ const Auth = new Elysia({
|
||||
password: t.String(),
|
||||
}),
|
||||
detail: {
|
||||
description: 'Login with phone; auto-register if not found',
|
||||
summary: 'login',
|
||||
description: 'Login with phone; auto-register if not found',
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -146,8 +146,9 @@ const Auth = new Elysia({
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
description: 'Logout (clear token cookie)',
|
||||
summary: 'logout',
|
||||
description: 'Logout (clear token cookie)',
|
||||
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -20,7 +20,11 @@ const CredentialRoute = new Elysia({
|
||||
body: t.Object({
|
||||
name: t.String(),
|
||||
value: t.String(),
|
||||
})
|
||||
}),
|
||||
detail: {
|
||||
summary: 'create',
|
||||
description: 'create credential',
|
||||
}
|
||||
})
|
||||
.get("/list", async (ctx) => {
|
||||
const list = await prisma.credential.findMany()
|
||||
@@ -28,6 +32,11 @@ const CredentialRoute = new Elysia({
|
||||
message: "success",
|
||||
list
|
||||
}
|
||||
}, {
|
||||
detail: {
|
||||
summary: 'list',
|
||||
description: 'get credential list',
|
||||
}
|
||||
})
|
||||
.delete("/rm", async (ctx) => {
|
||||
const { id } = ctx.body
|
||||
@@ -40,7 +49,11 @@ const CredentialRoute = new Elysia({
|
||||
}, {
|
||||
body: t.Object({
|
||||
id: t.String()
|
||||
})
|
||||
}),
|
||||
detail: {
|
||||
summary: 'rm',
|
||||
description: 'delete credential by id',
|
||||
}
|
||||
})
|
||||
|
||||
export default CredentialRoute
|
||||
@@ -30,7 +30,7 @@ const DarmasabaRoute = new Elysia({
|
||||
})
|
||||
}, {
|
||||
detail: {
|
||||
summary: "/repos",
|
||||
summary: "repos",
|
||||
description: "get list of repositories"
|
||||
}
|
||||
})
|
||||
@@ -57,7 +57,7 @@ const DarmasabaRoute = new Elysia({
|
||||
})
|
||||
}, {
|
||||
detail: {
|
||||
summary: "/ls",
|
||||
summary: "ls",
|
||||
description: "get list of dir in darmasaba"
|
||||
}
|
||||
})
|
||||
@@ -88,7 +88,7 @@ const DarmasabaRoute = new Elysia({
|
||||
dir: t.String()
|
||||
}),
|
||||
detail: {
|
||||
summary: "/ls/:dir",
|
||||
summary: "ls",
|
||||
description: "get list of files in darmasaba/<dir>"
|
||||
}
|
||||
})
|
||||
@@ -122,7 +122,7 @@ const DarmasabaRoute = new Elysia({
|
||||
file_name: t.String()
|
||||
}),
|
||||
detail: {
|
||||
summary: "/file/:dir/:file_name",
|
||||
summary: "file",
|
||||
description: "get content of file in darmasaba/<dir>/<file_name>"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
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()
|
||||
.post(
|
||||
'/mcp',
|
||||
async ({ request, body, set }) => {
|
||||
const sessionId = request.headers.get('mcp-session-id') ?? undefined;
|
||||
let transport: StreamableHTTPServerTransport;
|
||||
|
||||
// Reuse existing session jika ada
|
||||
if (sessionId && transports[sessionId]) {
|
||||
transport = transports[sessionId];
|
||||
}
|
||||
// Jika ini permintaan inisialisasi MCP baru
|
||||
else if (!sessionId && isInitializeRequest(body)) {
|
||||
transport = new StreamableHTTPServerTransport({
|
||||
sessionIdGenerator: () => randomUUID(),
|
||||
onsessioninitialized: (sid) => {
|
||||
transports[sid] = transport;
|
||||
console.log(`🟢 Session initialized: ${sid}`);
|
||||
},
|
||||
});
|
||||
|
||||
transport.onclose = () => {
|
||||
if (transport.sessionId) {
|
||||
console.log(`🔴 Session closed: ${transport.sessionId}`);
|
||||
delete transports[transport.sessionId];
|
||||
}
|
||||
};
|
||||
|
||||
// Buat instance MCP server
|
||||
const server = new McpServer({
|
||||
name: 'elysia-mcp-server',
|
||||
version: '1.0.0',
|
||||
});
|
||||
|
||||
// Contoh: tambahkan dummy tool/resource di sini jika mau
|
||||
// server.addTool('ping', async () => 'pong');
|
||||
|
||||
await server.connect(transport);
|
||||
|
||||
// Tunggu hingga session ID terbentuk
|
||||
await new Promise<void>((resolve) => {
|
||||
const wait = () => {
|
||||
if (transport.sessionId) resolve();
|
||||
else setTimeout(wait, 5);
|
||||
};
|
||||
wait();
|
||||
});
|
||||
|
||||
// Kirim sessionId ke client
|
||||
set.headers['mcp-session-id'] = transport.sessionId!;
|
||||
set.status = 200;
|
||||
return { sessionId: transport.sessionId };
|
||||
}
|
||||
// Jika tidak valid
|
||||
else {
|
||||
set.status = 400;
|
||||
return {
|
||||
jsonrpc: '2.0',
|
||||
error: {
|
||||
code: -32000,
|
||||
message: 'Bad Request: No valid session ID provided',
|
||||
},
|
||||
id: null,
|
||||
};
|
||||
}
|
||||
|
||||
// ✅ Gunakan interface Web (Bun/Elysia) langsung
|
||||
const webTransport = transport as any;
|
||||
if (typeof webTransport.handleRequestWeb === 'function') {
|
||||
// handleRequestWeb() adalah versi WebAPI (Request/Response)
|
||||
return await webTransport.handleRequestWeb(request);
|
||||
} else {
|
||||
// fallback – manual handle body
|
||||
return new Response(JSON.stringify({ ok: true }), {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
},
|
||||
{ body: t.Any() }
|
||||
)
|
||||
// Server-sent events (SSE)
|
||||
.get('/mcp', async ({ request, set }) => {
|
||||
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';
|
||||
}
|
||||
|
||||
const webTransport = transport as any;
|
||||
if (typeof webTransport.handleRequestWeb === 'function') {
|
||||
return await webTransport.handleRequestWeb(request);
|
||||
}
|
||||
|
||||
set.status = 200;
|
||||
return new Response('SSE not supported by this transport');
|
||||
})
|
||||
// Session cleanup
|
||||
.delete('/mcp', async ({ request, set }) => {
|
||||
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';
|
||||
}
|
||||
|
||||
const webTransport = transport as any;
|
||||
if (typeof webTransport.handleRequestWeb === 'function') {
|
||||
return await webTransport.handleRequestWeb(request);
|
||||
}
|
||||
|
||||
set.status = 200;
|
||||
return new Response('Session deleted');
|
||||
})
|
||||
|
||||
export default McpRoute
|
||||
Reference in New Issue
Block a user