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:
Minoru Mizutani 2025-04-29 03:42:59 +09:00
parent 00b1d15cfd
commit 4394c0773d
No known key found for this signature in database
10 changed files with 1815 additions and 1096 deletions

View file

@ -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);
});