Spaces:
Sleeping
Sleeping
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); | |
}); | |