Go full lazy with http transport
This also means we need to default to sse-first
This commit is contained in:
parent
1908c203ff
commit
02305b3d1c
3 changed files with 31 additions and 39 deletions
|
@ -31,7 +31,7 @@ async function runClient(
|
||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
callbackPort: number,
|
callbackPort: number,
|
||||||
headers: Record<string, string>,
|
headers: Record<string, string>,
|
||||||
transportStrategy: TransportStrategy = 'http-first',
|
transportStrategy: TransportStrategy = 'sse-first',
|
||||||
) {
|
) {
|
||||||
// Set up event emitter for auth flow
|
// Set up event emitter for auth flow
|
||||||
const events = new EventEmitter()
|
const events = new EventEmitter()
|
||||||
|
@ -66,10 +66,10 @@ async function runClient(
|
||||||
// Define an auth initializer function
|
// Define an auth initializer function
|
||||||
const authInitializer = async () => {
|
const authInitializer = async () => {
|
||||||
const authState = await authCoordinator.initializeAuth()
|
const authState = await authCoordinator.initializeAuth()
|
||||||
|
|
||||||
// Store server in outer scope for cleanup
|
// Store server in outer scope for cleanup
|
||||||
server = authState.server
|
server = authState.server
|
||||||
|
|
||||||
// If auth was completed by another instance, just log that we'll use the auth from disk
|
// If auth was completed by another instance, just log that we'll use the auth from disk
|
||||||
if (authState.skipBrowserAuth) {
|
if (authState.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...')
|
||||||
|
@ -77,23 +77,16 @@ async function runClient(
|
||||||
// so we're slightly too early
|
// so we're slightly too early
|
||||||
await new Promise((res) => setTimeout(res, 1_000))
|
await new Promise((res) => setTimeout(res, 1_000))
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
waitForAuthCode: authState.waitForAuthCode,
|
waitForAuthCode: authState.waitForAuthCode,
|
||||||
skipBrowserAuth: authState.skipBrowserAuth
|
skipBrowserAuth: authState.skipBrowserAuth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Connect to remote server with lazy authentication
|
// Connect to remote server with lazy authentication
|
||||||
const transport = await connectToRemoteServer(
|
const transport = await connectToRemoteServer(client, serverUrl, authProvider, headers, authInitializer, transportStrategy)
|
||||||
client,
|
|
||||||
serverUrl,
|
|
||||||
authProvider,
|
|
||||||
headers,
|
|
||||||
authInitializer,
|
|
||||||
transportStrategy,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set up message and error handlers
|
// Set up message and error handlers
|
||||||
transport.onmessage = (message) => {
|
transport.onmessage = (message) => {
|
||||||
|
|
|
@ -93,12 +93,12 @@ export type AuthInitializer = () => Promise<{
|
||||||
* @returns The connected transport
|
* @returns The connected transport
|
||||||
*/
|
*/
|
||||||
export async function connectToRemoteServer(
|
export async function connectToRemoteServer(
|
||||||
client: Client,
|
client: Client | null,
|
||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
authProvider: OAuthClientProvider,
|
authProvider: OAuthClientProvider,
|
||||||
headers: Record<string, string>,
|
headers: Record<string, string>,
|
||||||
authInitializer: AuthInitializer,
|
authInitializer: AuthInitializer,
|
||||||
transportStrategy: TransportStrategy = 'http-first',
|
transportStrategy: TransportStrategy = 'sse-first',
|
||||||
recursionReasons: Set<string> = new Set(),
|
recursionReasons: Set<string> = new Set(),
|
||||||
): Promise<Transport> {
|
): Promise<Transport> {
|
||||||
log(`[${pid}] Connecting to remote server: ${serverUrl}`)
|
log(`[${pid}] Connecting to remote server: ${serverUrl}`)
|
||||||
|
@ -140,7 +140,11 @@ export async function connectToRemoteServer(
|
||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.connect(transport)
|
if (client) {
|
||||||
|
await client.connect(transport)
|
||||||
|
} else {
|
||||||
|
await transport.start()
|
||||||
|
}
|
||||||
log(`Connected to remote server using ${transport.constructor.name}`)
|
log(`Connected to remote server using ${transport.constructor.name}`)
|
||||||
|
|
||||||
return transport
|
return transport
|
||||||
|
@ -380,7 +384,7 @@ export async function parseCommandLineArgs(args: string[], defaultPort: number,
|
||||||
const allowHttp = args.includes('--allow-http')
|
const allowHttp = args.includes('--allow-http')
|
||||||
|
|
||||||
// Parse transport strategy
|
// Parse transport strategy
|
||||||
let transportStrategy: TransportStrategy = 'http-first' // Default
|
let transportStrategy: TransportStrategy = 'sse-first' // Default
|
||||||
const transportIndex = args.indexOf('--transport')
|
const transportIndex = args.indexOf('--transport')
|
||||||
if (transportIndex !== -1 && transportIndex < args.length - 1) {
|
if (transportIndex !== -1 && transportIndex < args.length - 1) {
|
||||||
const strategy = args[transportIndex + 1]
|
const strategy = args[transportIndex + 1]
|
||||||
|
|
33
src/proxy.ts
33
src/proxy.ts
|
@ -23,12 +23,16 @@ import {
|
||||||
} from './lib/utils'
|
} from './lib/utils'
|
||||||
import { NodeOAuthClientProvider } from './lib/node-oauth-client-provider'
|
import { NodeOAuthClientProvider } from './lib/node-oauth-client-provider'
|
||||||
import { createLazyAuthCoordinator } from './lib/coordination'
|
import { createLazyAuthCoordinator } from './lib/coordination'
|
||||||
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main function to run the proxy
|
* Main function to run the proxy
|
||||||
*/
|
*/
|
||||||
async function runProxy(serverUrl: string, callbackPort: number, headers: Record<string, string>, transportStrategy: TransportStrategy = 'http-first') {
|
async function runProxy(
|
||||||
|
serverUrl: string,
|
||||||
|
callbackPort: number,
|
||||||
|
headers: Record<string, string>,
|
||||||
|
transportStrategy: TransportStrategy = 'sse-first',
|
||||||
|
) {
|
||||||
// Set up event emitter for auth flow
|
// Set up event emitter for auth flow
|
||||||
const events = new EventEmitter()
|
const events = new EventEmitter()
|
||||||
|
|
||||||
|
@ -54,10 +58,10 @@ async function runProxy(serverUrl: string, callbackPort: number, headers: Record
|
||||||
// Define an auth initializer function
|
// Define an auth initializer function
|
||||||
const authInitializer = async () => {
|
const authInitializer = async () => {
|
||||||
const authState = await authCoordinator.initializeAuth()
|
const authState = await authCoordinator.initializeAuth()
|
||||||
|
|
||||||
// Store server in outer scope for cleanup
|
// Store server in outer scope for cleanup
|
||||||
server = authState.server
|
server = authState.server
|
||||||
|
|
||||||
// If auth was completed by another instance, just log that we'll use the auth from disk
|
// If auth was completed by another instance, just log that we'll use the auth from disk
|
||||||
if (authState.skipBrowserAuth) {
|
if (authState.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')
|
||||||
|
@ -65,25 +69,16 @@ async function runProxy(serverUrl: string, callbackPort: number, headers: Record
|
||||||
// so we're slightly too early
|
// so we're slightly too early
|
||||||
await new Promise((res) => setTimeout(res, 1_000))
|
await new Promise((res) => setTimeout(res, 1_000))
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
waitForAuthCode: authState.waitForAuthCode,
|
waitForAuthCode: authState.waitForAuthCode,
|
||||||
skipBrowserAuth: authState.skipBrowserAuth
|
skipBrowserAuth: authState.skipBrowserAuth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const client = new Client(
|
|
||||||
{
|
|
||||||
name: 'mcp-remote',
|
|
||||||
version: MCP_REMOTE_VERSION,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
capabilities: {},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
// Connect to remote server with lazy authentication
|
// Connect to remote server with lazy authentication
|
||||||
const remoteTransport = await connectToRemoteServer(client, serverUrl, authProvider, headers, authInitializer, transportStrategy)
|
const remoteTransport = await connectToRemoteServer(null, serverUrl, authProvider, headers, authInitializer, transportStrategy)
|
||||||
|
|
||||||
// Set up bidirectional proxy between local and remote transports
|
// Set up bidirectional proxy between local and remote transports
|
||||||
mcpProxy({
|
mcpProxy({
|
||||||
|
@ -94,7 +89,7 @@ async function runProxy(serverUrl: string, callbackPort: number, headers: Record
|
||||||
// Start the local STDIO server
|
// Start the local STDIO server
|
||||||
await localTransport.start()
|
await localTransport.start()
|
||||||
log('Local STDIO server running')
|
log('Local STDIO server running')
|
||||||
log('Proxy established successfully between local STDIO and remote SSE')
|
log(`Proxy established successfully between local STDIO and remote ${remoteTransport.constructor.name}`)
|
||||||
log('Press Ctrl+C to exit')
|
log('Press Ctrl+C to exit')
|
||||||
|
|
||||||
// Setup cleanup handler
|
// Setup cleanup handler
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue