Spaces:
Paused
Paused
| import { | |
| JSONRPCMessageSchema, | |
| NodeOAuthClientProvider, | |
| connectToRemoteServer, | |
| createLazyAuthCoordinator, | |
| getServerUrlHash, | |
| log, | |
| mcpProxy, | |
| parseCommandLineArgs, | |
| setupSignalHandlers | |
| } from "./chunk-4PNJQ7WT.js"; | |
| // src/proxy.ts | |
| import { EventEmitter } from "events"; | |
| // node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js | |
| import process2 from "node:process"; | |
| // node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js | |
| var ReadBuffer = class { | |
| append(chunk) { | |
| this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk; | |
| } | |
| readMessage() { | |
| if (!this._buffer) { | |
| return null; | |
| } | |
| const index = this._buffer.indexOf("\n"); | |
| if (index === -1) { | |
| return null; | |
| } | |
| const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, ""); | |
| this._buffer = this._buffer.subarray(index + 1); | |
| return deserializeMessage(line); | |
| } | |
| clear() { | |
| this._buffer = void 0; | |
| } | |
| }; | |
| function deserializeMessage(line) { | |
| return JSONRPCMessageSchema.parse(JSON.parse(line)); | |
| } | |
| function serializeMessage(message) { | |
| return JSON.stringify(message) + "\n"; | |
| } | |
| // node_modules/.pnpm/@modelcontextprotocol+sdk@https+++pkg.pr.new+geelen+typescript-sdk+@modelcontextprotocol+sdk@cdf3508/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js | |
| var StdioServerTransport = class { | |
| constructor(_stdin = process2.stdin, _stdout = process2.stdout) { | |
| this._stdin = _stdin; | |
| this._stdout = _stdout; | |
| this._readBuffer = new ReadBuffer(); | |
| this._started = false; | |
| this._ondata = (chunk) => { | |
| this._readBuffer.append(chunk); | |
| this.processReadBuffer(); | |
| }; | |
| this._onerror = (error) => { | |
| var _a; | |
| (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); | |
| }; | |
| } | |
| /** | |
| * Starts listening for messages on stdin. | |
| */ | |
| async start() { | |
| if (this._started) { | |
| throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically."); | |
| } | |
| this._started = true; | |
| this._stdin.on("data", this._ondata); | |
| this._stdin.on("error", this._onerror); | |
| } | |
| processReadBuffer() { | |
| var _a, _b; | |
| while (true) { | |
| try { | |
| const message = this._readBuffer.readMessage(); | |
| if (message === null) { | |
| break; | |
| } | |
| (_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message); | |
| } catch (error) { | |
| (_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error); | |
| } | |
| } | |
| } | |
| async close() { | |
| var _a; | |
| this._stdin.off("data", this._ondata); | |
| this._stdin.off("error", this._onerror); | |
| const remainingDataListeners = this._stdin.listenerCount("data"); | |
| if (remainingDataListeners === 0) { | |
| this._stdin.pause(); | |
| } | |
| this._readBuffer.clear(); | |
| (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this); | |
| } | |
| send(message) { | |
| return new Promise((resolve) => { | |
| const json = serializeMessage(message); | |
| if (this._stdout.write(json)) { | |
| resolve(); | |
| } else { | |
| this._stdout.once("drain", resolve); | |
| } | |
| }); | |
| } | |
| }; | |
| // src/proxy.ts | |
| async function runProxy(serverUrl, callbackPort, headers, transportStrategy = "http-first", host, staticOAuthClientMetadata, staticOAuthClientInfo) { | |
| const events = new EventEmitter(); | |
| const serverUrlHash = getServerUrlHash(serverUrl); | |
| const authCoordinator = createLazyAuthCoordinator(serverUrlHash, callbackPort, events); | |
| const authProvider = new NodeOAuthClientProvider({ | |
| serverUrl, | |
| callbackPort, | |
| host, | |
| clientName: "MCP CLI Proxy", | |
| staticOAuthClientMetadata, | |
| staticOAuthClientInfo | |
| }); | |
| const localTransport = new StdioServerTransport(); | |
| let server = null; | |
| const authInitializer = async () => { | |
| const authState = await authCoordinator.initializeAuth(); | |
| server = authState.server; | |
| if (authState.skipBrowserAuth) { | |
| log("Authentication was completed by another instance - will use tokens from disk"); | |
| await new Promise((res) => setTimeout(res, 1e3)); | |
| } | |
| return { | |
| waitForAuthCode: authState.waitForAuthCode, | |
| skipBrowserAuth: authState.skipBrowserAuth | |
| }; | |
| }; | |
| try { | |
| const remoteTransport = await connectToRemoteServer(null, serverUrl, authProvider, headers, authInitializer, transportStrategy); | |
| mcpProxy({ | |
| transportToClient: localTransport, | |
| transportToServer: remoteTransport | |
| }); | |
| await localTransport.start(); | |
| log("Local STDIO server running"); | |
| log(`Proxy established successfully between local STDIO and remote ${remoteTransport.constructor.name}`); | |
| log("Press Ctrl+C to exit"); | |
| const cleanup = async () => { | |
| await remoteTransport.close(); | |
| await localTransport.close(); | |
| if (server) { | |
| server.close(); | |
| } | |
| }; | |
| setupSignalHandlers(cleanup); | |
| } catch (error) { | |
| log("Fatal error:", error); | |
| if (error instanceof Error && error.message.includes("self-signed certificate in certificate chain")) { | |
| log(`You may be behind a VPN! | |
| If you are behind a VPN, you can try setting the NODE_EXTRA_CA_CERTS environment variable to point | |
| to the CA certificate file. If using claude_desktop_config.json, this might look like: | |
| { | |
| "mcpServers": { | |
| "\${mcpServerName}": { | |
| "command": "npx", | |
| "args": [ | |
| "mcp-remote", | |
| "https://remote.mcp.server/sse" | |
| ], | |
| "env": { | |
| "NODE_EXTRA_CA_CERTS": "\${your CA certificate file path}.pem" | |
| } | |
| } | |
| } | |
| } | |
| `); | |
| } | |
| if (server) { | |
| server.close(); | |
| } | |
| process.exit(1); | |
| } | |
| } | |
| parseCommandLineArgs(process.argv.slice(2), "Usage: npx tsx proxy.ts <https://server-url> [callback-port] [--debug]").then(({ serverUrl, callbackPort, headers, transportStrategy, host, debug, staticOAuthClientMetadata, staticOAuthClientInfo }) => { | |
| return runProxy(serverUrl, callbackPort, headers, transportStrategy, host, staticOAuthClientMetadata, staticOAuthClientInfo); | |
| }).catch((error) => { | |
| log("Fatal error:", error); | |
| process.exit(1); | |
| }); | |