tamabahan

This commit is contained in:
bipproduction
2025-10-09 14:45:35 +08:00
parent 3d0bcea948
commit 6fe2e9a3fc
6 changed files with 29 additions and 140 deletions

View File

@@ -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");

View File

@@ -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(),

View File

@@ -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)',
},
}
)

View File

@@ -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

View File

@@ -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>"
}
})

View File

@@ -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