@luutuankiet/mcp-proxy-shim 1.0.7 → 1.1.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Proxy Shim — HTTP Streamable Server Entry Point
4
+ *
5
+ * Runs the schema-transforming MCP proxy as an HTTP Streamable server.
6
+ * Remote agents connect via HTTP POST/GET/DELETE to /mcp.
7
+ *
8
+ * Architecture:
9
+ * Remote Agent ──HTTP──▶ this server (:3000/mcp) ──HTTP──▶ mcpproxy-go (upstream)
10
+ *
11
+ * Each downstream client session gets its own MCP Server + Transport pair,
12
+ * but they all share a SINGLE upstream mcpproxy-go connection (module-level
13
+ * state in core.ts). This is efficient: one upstream session, many downstream.
14
+ *
15
+ * Environment variables:
16
+ * MCP_URL (required) Upstream mcpproxy-go StreamableHTTP endpoint
17
+ * MCP_PORT (optional) Port to listen on (default: 3000)
18
+ * MCP_HOST (optional) Host to bind to (default: 0.0.0.0)
19
+ * MCP_APIKEY (optional) API key for downstream clients. When set, requests
20
+ * must include ?apikey=KEY in the URL. Unset = open.
21
+ * https_proxy (optional) HTTPS proxy for upstream connection
22
+ *
23
+ * Usage:
24
+ * MCP_URL="https://mcpproxy.kenluu.org/mcp/?apikey=KEY" npx @luutuankiet/mcp-proxy-shim-http
25
+ *
26
+ * Then point your MCP client at:
27
+ * http://localhost:3000/mcp
28
+ *
29
+ * For production, put a reverse proxy (Caddy/nginx) in front for TLS:
30
+ * https://shim.yourdomain.com/mcp ──▶ http://localhost:3000/mcp
31
+ */
32
+ import { randomUUID } from "node:crypto";
33
+ import http from "node:http";
34
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
35
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
36
+ import { createShimServer, log, maskUrl, UPSTREAM_URL } from "./core.js";
37
+ const PORT = parseInt(process.env.MCP_PORT || "3000", 10);
38
+ const HOST = process.env.MCP_HOST || "0.0.0.0";
39
+ const APIKEY = process.env.MCP_APIKEY || null;
40
+ // ---------------------------------------------------------------------------
41
+ // Session management
42
+ // ---------------------------------------------------------------------------
43
+ // Each downstream client gets its own MCP Server + Transport pair.
44
+ // All of them share the SAME upstream mcpproxy-go session (module-level in core.ts).
45
+ const transports = new Map();
46
+ /**
47
+ * Create a new downstream session: fresh Server + Transport pair.
48
+ * The upstream connection is shared via core.ts module state.
49
+ */
50
+ async function createSessionTransport() {
51
+ const transport = new StreamableHTTPServerTransport({
52
+ sessionIdGenerator: () => randomUUID(),
53
+ onsessioninitialized: (sessionId) => {
54
+ log(`HTTP session initialized: ${sessionId.slice(0, 12)}...`);
55
+ transports.set(sessionId, transport);
56
+ },
57
+ });
58
+ transport.onclose = () => {
59
+ const sid = transport.sessionId;
60
+ if (sid && transports.has(sid)) {
61
+ log(`HTTP session closed: ${sid.slice(0, 12)}...`);
62
+ transports.delete(sid);
63
+ }
64
+ };
65
+ // Each session gets its own shim server with lazy upstream init.
66
+ // core.ts ensures the upstream session is shared (module-level singleton).
67
+ const server = await createShimServer({ lazyInit: true });
68
+ await server.connect(transport);
69
+ return transport;
70
+ }
71
+ // ---------------------------------------------------------------------------
72
+ // HTTP request handler
73
+ // ---------------------------------------------------------------------------
74
+ function parseBody(req) {
75
+ return new Promise((resolve) => {
76
+ const chunks = [];
77
+ req.on("data", (chunk) => chunks.push(chunk));
78
+ req.on("end", () => {
79
+ try {
80
+ const raw = Buffer.concat(chunks).toString("utf-8");
81
+ resolve(raw ? JSON.parse(raw) : null);
82
+ }
83
+ catch {
84
+ resolve(null);
85
+ }
86
+ });
87
+ req.on("error", () => resolve(null));
88
+ });
89
+ }
90
+ async function handleMcpRequest(req, res) {
91
+ // CORS headers for browser-based clients
92
+ res.setHeader("Access-Control-Allow-Origin", "*");
93
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
94
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Mcp-Session-Id, Last-Event-ID");
95
+ res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");
96
+ if (req.method === "OPTIONS") {
97
+ res.writeHead(204);
98
+ res.end();
99
+ return;
100
+ }
101
+ const sessionId = req.headers["mcp-session-id"];
102
+ try {
103
+ if (req.method === "POST") {
104
+ const body = await parseBody(req);
105
+ if (sessionId && transports.has(sessionId)) {
106
+ // Existing session
107
+ const transport = transports.get(sessionId);
108
+ await transport.handleRequest(req, res, body);
109
+ }
110
+ else if (!sessionId && isInitializeRequest(body)) {
111
+ // New client — create session
112
+ const transport = await createSessionTransport();
113
+ await transport.handleRequest(req, res, body);
114
+ }
115
+ else {
116
+ res.writeHead(400, { "Content-Type": "application/json" });
117
+ res.end(JSON.stringify({
118
+ jsonrpc: "2.0",
119
+ error: { code: -32000, message: "Bad Request: No valid session ID provided" },
120
+ id: null,
121
+ }));
122
+ }
123
+ }
124
+ else if (req.method === "GET") {
125
+ // SSE stream reconnection
126
+ if (!sessionId || !transports.has(sessionId)) {
127
+ res.writeHead(400, { "Content-Type": "text/plain" });
128
+ res.end("Invalid or missing session ID");
129
+ return;
130
+ }
131
+ const lastEventId = req.headers["last-event-id"];
132
+ if (lastEventId) {
133
+ log(`Client reconnecting with Last-Event-ID: ${lastEventId}`);
134
+ }
135
+ const transport = transports.get(sessionId);
136
+ await transport.handleRequest(req, res);
137
+ }
138
+ else if (req.method === "DELETE") {
139
+ // Session termination
140
+ if (!sessionId || !transports.has(sessionId)) {
141
+ res.writeHead(400, { "Content-Type": "text/plain" });
142
+ res.end("Invalid or missing session ID");
143
+ return;
144
+ }
145
+ log(`Session termination request: ${sessionId.slice(0, 12)}...`);
146
+ const transport = transports.get(sessionId);
147
+ await transport.handleRequest(req, res);
148
+ }
149
+ else {
150
+ res.writeHead(405, { "Content-Type": "text/plain" });
151
+ res.end("Method Not Allowed");
152
+ }
153
+ }
154
+ catch (error) {
155
+ log("HTTP handler error:", error.message);
156
+ if (!res.headersSent) {
157
+ res.writeHead(500, { "Content-Type": "application/json" });
158
+ res.end(JSON.stringify({
159
+ jsonrpc: "2.0",
160
+ error: { code: -32603, message: "Internal server error" },
161
+ id: null,
162
+ }));
163
+ }
164
+ }
165
+ }
166
+ // ---------------------------------------------------------------------------
167
+ // Server startup
168
+ // ---------------------------------------------------------------------------
169
+ async function main() {
170
+ log(`Starting HTTP Streamable server on ${HOST}:${PORT}`);
171
+ log(`Upstream: ${maskUrl(UPSTREAM_URL)}`);
172
+ log(`Auth: ${APIKEY ? "apikey required (?apikey=...)" : "OPEN (no MCP_APIKEY set)"}`);
173
+ const httpServer = http.createServer((req, res) => {
174
+ const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
175
+ if (url.pathname === "/mcp" || url.pathname === "/mcp/") {
176
+ // Apikey gate — reject early if MCP_APIKEY is set and key doesn't match
177
+ if (APIKEY && url.searchParams.get("apikey") !== APIKEY) {
178
+ res.writeHead(401, { "Content-Type": "application/json" });
179
+ res.end(JSON.stringify({
180
+ jsonrpc: "2.0",
181
+ error: { code: -32001, message: "Unauthorized: invalid or missing apikey" },
182
+ id: null,
183
+ }));
184
+ return;
185
+ }
186
+ handleMcpRequest(req, res).catch((err) => {
187
+ log("Unhandled error in MCP handler:", err.message);
188
+ if (!res.headersSent) {
189
+ res.writeHead(500);
190
+ res.end("Internal Server Error");
191
+ }
192
+ });
193
+ }
194
+ else if (url.pathname === "/health" || url.pathname === "/healthz") {
195
+ res.writeHead(200, { "Content-Type": "application/json" });
196
+ res.end(JSON.stringify({
197
+ status: "ok",
198
+ sessions: transports.size,
199
+ uptime: process.uptime(),
200
+ }));
201
+ }
202
+ else {
203
+ res.writeHead(404, { "Content-Type": "text/plain" });
204
+ res.end("Not Found — MCP endpoint is at /mcp");
205
+ }
206
+ });
207
+ httpServer.listen(PORT, HOST, () => {
208
+ log(`HTTP Streamable server listening on http://${HOST}:${PORT}/mcp`);
209
+ log(`Health check: http://${HOST}:${PORT}/health`);
210
+ log("Waiting for MCP client connections...");
211
+ });
212
+ // Graceful shutdown
213
+ const shutdown = async () => {
214
+ log("Shutting down HTTP server...");
215
+ for (const [sid, transport] of transports) {
216
+ try {
217
+ log(`Closing session ${sid.slice(0, 12)}...`);
218
+ await transport.close();
219
+ }
220
+ catch (err) {
221
+ log(`Error closing session ${sid.slice(0, 12)}:`, err.message);
222
+ }
223
+ }
224
+ transports.clear();
225
+ httpServer.close(() => {
226
+ log("HTTP server stopped");
227
+ process.exit(0);
228
+ });
229
+ setTimeout(() => process.exit(1), 5000).unref();
230
+ };
231
+ process.on("SIGINT", shutdown);
232
+ process.on("SIGTERM", shutdown);
233
+ }
234
+ main().catch((err) => {
235
+ log("Fatal:", err);
236
+ process.exit(1);
237
+ });
238
+ //# sourceMappingURL=http-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,28 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * MCP Stdio Shim
3
+ * MCP Proxy Shim — Unified Entry Point
4
4
  *
5
- * A schema-transforming MCP proxy that sits between Claude Code (stdio)
6
- * and mcpproxy-go (StreamableHTTP).
7
- *
8
- * What it does:
9
- * - Passes through ALL upstream tools unchanged (retrieve_tools, upstream_servers, etc.)
10
- * - Transforms call_tool_read / call_tool_write / call_tool_destructive schemas:
11
- * upstream args_json:string → downstream args:object
12
- * - On tool call: serializes args back to args_json before forwarding upstream
13
- *
14
- * Why not use SDK StreamableHTTPClientTransport:
15
- * - Bug #396: 2nd callTool times out (broken session multiplexing)
16
- * - We use plain fetch for upstream — reliable, simple, zero SDK client bugs
17
- *
18
- * Why low-level Server class (not McpServer):
19
- * - Bug #893: McpServer.registerTool() breaks dynamic registration post-connect
20
- * - Low-level Server.setRequestHandler() works correctly
5
+ * Subcommands:
6
+ * (default) stdio transport for local MCP clients (Claude Code, Cursor, etc.)
7
+ * serve HTTP Streamable transport — for remote agents over HTTP
21
8
  *
22
9
  * Usage:
10
+ * # Stdio mode (default)
23
11
  * MCP_URL="https://proxy.example.com/mcp/?apikey=KEY" npx @luutuankiet/mcp-proxy-shim
24
12
  *
25
- * .mcp.json entry:
13
+ * # HTTP server mode
14
+ * MCP_URL="https://proxy.example.com/mcp/?apikey=KEY" npx @luutuankiet/mcp-proxy-shim serve
15
+ * MCP_URL="..." MCP_PORT=8080 npx @luutuankiet/mcp-proxy-shim serve
16
+ *
17
+ * .mcp.json entry (stdio):
26
18
  * { "mcpServers": { "proxy": { "type": "stdio", "command": "npx", "args": ["-y", "@luutuankiet/mcp-proxy-shim"], "env": { "MCP_URL": "..." } } } }
27
19
  */
28
20
  export {};