Spaces:
Sleeping
Sleeping
File size: 6,353 Bytes
d4f5807 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
#!/usr/bin/env node
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);
});
|