Add .denoignore file and update implementation plan with additional tasks for type safety, dependency management, testing, documentation, and build configuration.
This commit is contained in:
parent
00b1d15cfd
commit
4394c0773d
10 changed files with 1815 additions and 1096 deletions
100
src/proxy.ts
100
src/proxy.ts
|
@ -10,69 +10,95 @@
|
|||
* If callback-port is not specified, an available port will be automatically selected.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'node:events'
|
||||
import { StdioServerTransport } from 'npm:@modelcontextprotocol/sdk/server/stdio.js'
|
||||
import { connectToRemoteServer, log, mcpProxy, parseCommandLineArgs, setupSignalHandlers, getServerUrlHash } from './lib/utils.ts'
|
||||
import { NodeOAuthClientProvider } from './lib/node-oauth-client-provider.ts'
|
||||
import { coordinateAuth } from './lib/coordination.ts'
|
||||
import { EventEmitter } from "node:events";
|
||||
import { StdioServerTransport } from "npm:@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import {
|
||||
connectToRemoteServer,
|
||||
getServerUrlHash,
|
||||
log,
|
||||
mcpProxy,
|
||||
parseCommandLineArgs,
|
||||
setupSignalHandlers,
|
||||
} from "./lib/utils.ts";
|
||||
import { NodeOAuthClientProvider } from "./lib/node-oauth-client-provider.ts";
|
||||
import { coordinateAuth } from "./lib/coordination.ts";
|
||||
|
||||
/**
|
||||
* Main function to run the proxy
|
||||
*/
|
||||
async function runProxy(serverUrl: string, callbackPort: number, headers: Record<string, string>) {
|
||||
async function runProxy(
|
||||
serverUrl: string,
|
||||
callbackPort: number,
|
||||
headers: Record<string, string>,
|
||||
) {
|
||||
// Set up event emitter for auth flow
|
||||
const events = new EventEmitter()
|
||||
const events = new EventEmitter();
|
||||
|
||||
// Get the server URL hash for lockfile operations
|
||||
const serverUrlHash = getServerUrlHash(serverUrl)
|
||||
const serverUrlHash = getServerUrlHash(serverUrl);
|
||||
|
||||
// Coordinate authentication with other instances
|
||||
const { server, waitForAuthCode, skipBrowserAuth } = await coordinateAuth(serverUrlHash, callbackPort, events)
|
||||
const { server, waitForAuthCode, skipBrowserAuth } = await coordinateAuth(
|
||||
serverUrlHash,
|
||||
callbackPort,
|
||||
events,
|
||||
);
|
||||
|
||||
// Create the OAuth client provider
|
||||
const authProvider = new NodeOAuthClientProvider({
|
||||
serverUrl,
|
||||
callbackPort,
|
||||
clientName: 'MCP CLI Proxy',
|
||||
})
|
||||
clientName: "MCP CLI Proxy",
|
||||
});
|
||||
|
||||
// If auth was completed by another instance, just log that we'll use the auth from disk
|
||||
if (skipBrowserAuth) {
|
||||
log('Authentication was completed by another instance - will use tokens from disk')
|
||||
log(
|
||||
"Authentication was completed by another instance - will use tokens from disk",
|
||||
);
|
||||
// TODO: remove, the callback is happening before the tokens are exchanged
|
||||
// so we're slightly too early
|
||||
await new Promise((res) => setTimeout(res, 1_000))
|
||||
await new Promise((res) => setTimeout(res, 1_000));
|
||||
}
|
||||
|
||||
// Create the STDIO transport for local connections
|
||||
const localTransport = new StdioServerTransport()
|
||||
const localTransport = new StdioServerTransport();
|
||||
|
||||
try {
|
||||
// Connect to remote server with authentication
|
||||
const remoteTransport = await connectToRemoteServer(serverUrl, authProvider, headers, waitForAuthCode, skipBrowserAuth)
|
||||
const remoteTransport = await connectToRemoteServer(
|
||||
serverUrl,
|
||||
authProvider,
|
||||
headers,
|
||||
waitForAuthCode,
|
||||
skipBrowserAuth,
|
||||
);
|
||||
|
||||
// Set up bidirectional proxy between local and remote transports
|
||||
mcpProxy({
|
||||
transportToClient: localTransport,
|
||||
transportToServer: remoteTransport,
|
||||
})
|
||||
});
|
||||
|
||||
// Start the local STDIO server
|
||||
await localTransport.start()
|
||||
log('Local STDIO server running')
|
||||
log('Proxy established successfully between local STDIO and remote SSE')
|
||||
log('Press Ctrl+C to exit')
|
||||
await localTransport.start();
|
||||
log("Local STDIO server running");
|
||||
log("Proxy established successfully between local STDIO and remote SSE");
|
||||
log("Press Ctrl+C to exit");
|
||||
|
||||
// Setup cleanup handler
|
||||
const cleanup = async () => {
|
||||
await remoteTransport.close()
|
||||
await localTransport.close()
|
||||
server.close()
|
||||
}
|
||||
setupSignalHandlers(cleanup)
|
||||
await remoteTransport.close();
|
||||
await localTransport.close();
|
||||
server.close();
|
||||
};
|
||||
setupSignalHandlers(cleanup);
|
||||
} catch (error) {
|
||||
log('Fatal error:', error)
|
||||
if (error instanceof Error && error.message.includes('self-signed certificate in certificate chain')) {
|
||||
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
|
||||
|
@ -92,19 +118,23 @@ to the CA certificate file. If using claude_desktop_config.json, this might look
|
|||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
`);
|
||||
}
|
||||
server.close()
|
||||
Deno.exit(1)
|
||||
server.close();
|
||||
Deno.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse command-line arguments and run the proxy
|
||||
parseCommandLineArgs(Deno.args, 3334, 'Usage: deno run src/proxy.ts <https://server-url> [callback-port]')
|
||||
parseCommandLineArgs(
|
||||
Deno.args,
|
||||
3334,
|
||||
"Usage: deno run src/proxy.ts <https://server-url> [callback-port]",
|
||||
)
|
||||
.then(({ serverUrl, callbackPort, headers }) => {
|
||||
return runProxy(serverUrl, callbackPort, headers)
|
||||
return runProxy(serverUrl, callbackPort, headers);
|
||||
})
|
||||
.catch((error) => {
|
||||
log('Fatal error:', error)
|
||||
Deno.exit(1)
|
||||
})
|
||||
log("Fatal error:", error);
|
||||
Deno.exit(1);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue