mirror of
https://github.com/codeaashu/claude-code.git
synced 2026-04-08 22:28:48 +03:00
rebrand: rename and publish as warrioraashuu-codemaster
This commit is contained in:
21
mcp-server/api/index.ts
Normal file
21
mcp-server/api/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Vercel serverless function — proxies requests to the Express HTTP server.
|
||||
*
|
||||
* This file re-exports the Express app as a Vercel serverless handler.
|
||||
* Vercel automatically routes /api/* to this function.
|
||||
*
|
||||
* Deploy:
|
||||
* cd mcp-server && npx vercel
|
||||
*
|
||||
* Environment variables (set in Vercel dashboard):
|
||||
* CLAUDE_CODE_SRC_ROOT — absolute path where src/ is deployed
|
||||
* MCP_API_KEY — optional bearer token for auth
|
||||
*
|
||||
* NOTE: Vercel serverless functions are stateless, so the Streamable HTTP
|
||||
* transport (which requires sessions) won't persist across invocations.
|
||||
* For production use with session-based MCP clients, prefer Railway/Render/VPS.
|
||||
* The legacy SSE transport and stateless tool calls work fine on Vercel.
|
||||
*/
|
||||
|
||||
export { app as default } from "./vercelApp.js";
|
||||
|
||||
96
mcp-server/api/vercelApp.ts
Normal file
96
mcp-server/api/vercelApp.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Express app exported for Vercel serverless.
|
||||
* Shares the same logic as http.ts but is importable as a module.
|
||||
*/
|
||||
|
||||
import express from "express";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
||||
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
||||
import { createServer, SRC_ROOT } from "../src/server.js";
|
||||
|
||||
const API_KEY = process.env.MCP_API_KEY;
|
||||
|
||||
export const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// Auth
|
||||
app.use((req, res, next) => {
|
||||
if (!API_KEY || req.path === "/health" || req.path === "/api") return next();
|
||||
const auth = req.headers.authorization;
|
||||
if (!auth || auth !== `Bearer ${API_KEY}`) {
|
||||
res.status(401).json({ error: "Unauthorized" });
|
||||
return;
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// Health
|
||||
app.get("/health", (_req, res) => {
|
||||
res.json({ status: "ok", server: "claude-code-explorer", version: "1.1.0", srcRoot: SRC_ROOT });
|
||||
});
|
||||
app.get("/api", (_req, res) => {
|
||||
res.json({ status: "ok", server: "claude-code-explorer", version: "1.1.0", srcRoot: SRC_ROOT });
|
||||
});
|
||||
|
||||
// Streamable HTTP
|
||||
const transports = new Map<string, StreamableHTTPServerTransport>();
|
||||
|
||||
app.post("/mcp", async (req, res) => {
|
||||
const sessionId = (req.headers["mcp-session-id"] as string) ?? undefined;
|
||||
let transport = sessionId ? transports.get(sessionId) : undefined;
|
||||
|
||||
if (!transport) {
|
||||
const server = createServer();
|
||||
transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() });
|
||||
await server.connect(transport);
|
||||
transport.onclose = () => {
|
||||
if (transport!.sessionId) transports.delete(transport!.sessionId);
|
||||
};
|
||||
}
|
||||
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
|
||||
if (transport.sessionId && !transports.has(transport.sessionId)) {
|
||||
transports.set(transport.sessionId, transport);
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/mcp", async (req, res) => {
|
||||
const sessionId = req.headers["mcp-session-id"] as string | undefined;
|
||||
if (!sessionId || !transports.has(sessionId)) {
|
||||
res.status(400).json({ error: "Invalid or missing session ID" });
|
||||
return;
|
||||
}
|
||||
await transports.get(sessionId)!.handleRequest(req, res);
|
||||
});
|
||||
|
||||
app.delete("/mcp", async (req, res) => {
|
||||
const sessionId = req.headers["mcp-session-id"] as string | undefined;
|
||||
if (sessionId && transports.has(sessionId)) {
|
||||
await transports.get(sessionId)!.close();
|
||||
transports.delete(sessionId);
|
||||
}
|
||||
res.status(200).json({ ok: true });
|
||||
});
|
||||
|
||||
// Legacy SSE
|
||||
const sseTransports = new Map<string, SSEServerTransport>();
|
||||
|
||||
app.get("/sse", async (_req, res) => {
|
||||
const server = createServer();
|
||||
const transport = new SSEServerTransport("/messages", res);
|
||||
sseTransports.set(transport.sessionId, transport);
|
||||
transport.onclose = () => sseTransports.delete(transport.sessionId);
|
||||
await server.connect(transport);
|
||||
});
|
||||
|
||||
app.post("/messages", async (req, res) => {
|
||||
const sessionId = req.query.sessionId as string;
|
||||
const transport = sseTransports.get(sessionId);
|
||||
if (!transport) {
|
||||
res.status(400).json({ error: "Unknown session" });
|
||||
return;
|
||||
}
|
||||
await transport.handlePostMessage(req, res, req.body);
|
||||
});
|
||||
Reference in New Issue
Block a user