feat: skip client registration via cli args
This commit is contained in:
parent
bd75a1cdf0
commit
6fc2d0d7c3
3 changed files with 66 additions and 6 deletions
|
@ -22,18 +22,23 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
||||||
private clientUri: string
|
private clientUri: string
|
||||||
private softwareId: string
|
private softwareId: string
|
||||||
private softwareVersion: string
|
private softwareVersion: string
|
||||||
|
private clientId: string | undefined
|
||||||
|
private clientSecret: string | undefined
|
||||||
|
private scope: string | undefined
|
||||||
/**
|
/**
|
||||||
* Creates a new NodeOAuthClientProvider
|
* Creates a new NodeOAuthClientProvider
|
||||||
* @param options Configuration options for the provider
|
* @param options Configuration options for the provider
|
||||||
*/
|
*/
|
||||||
constructor(readonly options: OAuthProviderOptions) {
|
constructor(readonly options: OAuthProviderOptions & { clientId?: string, clientSecret?: string, scope?: string }) {
|
||||||
this.serverUrlHash = getServerUrlHash(options.serverUrl)
|
this.serverUrlHash = getServerUrlHash(options.serverUrl)
|
||||||
this.callbackPath = options.callbackPath || '/oauth/callback'
|
this.callbackPath = options.callbackPath || '/oauth/callback'
|
||||||
this.clientName = options.clientName || 'MCP CLI Client'
|
this.clientName = options.clientName || 'MCP CLI Client'
|
||||||
this.clientUri = options.clientUri || 'https://github.com/modelcontextprotocol/mcp-cli'
|
this.clientUri = options.clientUri || 'https://github.com/modelcontextprotocol/mcp-cli'
|
||||||
this.softwareId = options.softwareId || '2e6dc280-f3c3-4e01-99a7-8181dbd1d23d'
|
this.softwareId = options.softwareId || '2e6dc280-f3c3-4e01-99a7-8181dbd1d23d'
|
||||||
this.softwareVersion = options.softwareVersion || MCP_REMOTE_VERSION
|
this.softwareVersion = options.softwareVersion || MCP_REMOTE_VERSION
|
||||||
|
this.clientId = options.clientId
|
||||||
|
this.clientSecret = options.clientSecret
|
||||||
|
this.scope = options.scope
|
||||||
}
|
}
|
||||||
|
|
||||||
get redirectUrl(): string {
|
get redirectUrl(): string {
|
||||||
|
@ -50,6 +55,7 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
||||||
client_uri: this.clientUri,
|
client_uri: this.clientUri,
|
||||||
software_id: this.softwareId,
|
software_id: this.softwareId,
|
||||||
software_version: this.softwareVersion,
|
software_version: this.softwareVersion,
|
||||||
|
scope: this.scope,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +65,12 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
||||||
*/
|
*/
|
||||||
async clientInformation(): Promise<OAuthClientInformation | undefined> {
|
async clientInformation(): Promise<OAuthClientInformation | undefined> {
|
||||||
// log('Reading client info')
|
// log('Reading client info')
|
||||||
|
if (this.clientId) {
|
||||||
|
return {
|
||||||
|
client_id: this.clientId,
|
||||||
|
client_secret: this.clientSecret,
|
||||||
|
}
|
||||||
|
}
|
||||||
return readJsonFile<OAuthClientInformation>(this.serverUrlHash, 'client_info.json', OAuthClientInformationSchema)
|
return readJsonFile<OAuthClientInformation>(this.serverUrlHash, 'client_info.json', OAuthClientInformationSchema)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -392,9 +392,49 @@ export async function findAvailablePort(preferredPort?: number): Promise<number>
|
||||||
export async function parseCommandLineArgs(args: string[], defaultPort: number, usage: string) {
|
export async function parseCommandLineArgs(args: string[], defaultPort: number, usage: string) {
|
||||||
// Process headers
|
// Process headers
|
||||||
const headers: Record<string, string> = {}
|
const headers: Record<string, string> = {}
|
||||||
|
let clientId: string | undefined = undefined
|
||||||
|
let clientSecret: string | undefined = undefined
|
||||||
|
let callbackPath: string | undefined = undefined
|
||||||
|
let scope: string | undefined = undefined
|
||||||
let i = 0
|
let i = 0
|
||||||
while (i < args.length) {
|
while (i < args.length) {
|
||||||
if (args[i] === '--header' && i < args.length - 1) {
|
if (args[i] === '--client-id' && i < args.length - 1) {
|
||||||
|
const value = args[i + 1]
|
||||||
|
if (value) {
|
||||||
|
clientId = value
|
||||||
|
} else {
|
||||||
|
log('Warning: ignoring empty client-id argument')
|
||||||
|
}
|
||||||
|
args.splice(i, 2)
|
||||||
|
continue
|
||||||
|
} else if (args[i] === '--client-secret' && i < args.length - 1) {
|
||||||
|
const value = args[i + 1]
|
||||||
|
if (value) {
|
||||||
|
clientSecret = value
|
||||||
|
} else {
|
||||||
|
log('Warning: ignoring empty client-secret argument')
|
||||||
|
}
|
||||||
|
args.splice(i, 2)
|
||||||
|
continue
|
||||||
|
} else if (args[i] === '--callback-path' && i < args.length - 1) {
|
||||||
|
const value = args[i + 1]
|
||||||
|
if (value) {
|
||||||
|
callbackPath = value
|
||||||
|
} else {
|
||||||
|
log('Warning: ignoring empty callback-path argument')
|
||||||
|
}
|
||||||
|
args.splice(i, 2)
|
||||||
|
continue
|
||||||
|
} else if (args[i] === '--scope' && i < args.length - 1) {
|
||||||
|
const value = args[i + 1]
|
||||||
|
if (value) {
|
||||||
|
scope = value
|
||||||
|
} else {
|
||||||
|
log('Warning: ignoring empty scope argument')
|
||||||
|
}
|
||||||
|
args.splice(i, 2)
|
||||||
|
continue
|
||||||
|
} else if (args[i] === '--header' && i < args.length - 1) {
|
||||||
const value = args[i + 1]
|
const value = args[i + 1]
|
||||||
const match = value.match(/^([A-Za-z0-9_-]+):(.*)$/)
|
const match = value.match(/^([A-Za-z0-9_-]+):(.*)$/)
|
||||||
if (match) {
|
if (match) {
|
||||||
|
@ -468,7 +508,7 @@ export async function parseCommandLineArgs(args: string[], defaultPort: number,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return { serverUrl, callbackPort, headers, transportStrategy }
|
return { serverUrl, callbackPort, headers, transportStrategy, callbackPath, clientId, clientSecret, scope }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
12
src/proxy.ts
12
src/proxy.ts
|
@ -32,6 +32,10 @@ async function runProxy(
|
||||||
callbackPort: number,
|
callbackPort: number,
|
||||||
headers: Record<string, string>,
|
headers: Record<string, string>,
|
||||||
transportStrategy: TransportStrategy = 'http-first',
|
transportStrategy: TransportStrategy = 'http-first',
|
||||||
|
callbackPath?: string,
|
||||||
|
clientId?: string,
|
||||||
|
clientSecret?: string,
|
||||||
|
scope?: string,
|
||||||
) {
|
) {
|
||||||
// Set up event emitter for auth flow
|
// Set up event emitter for auth flow
|
||||||
const events = new EventEmitter()
|
const events = new EventEmitter()
|
||||||
|
@ -46,7 +50,11 @@ async function runProxy(
|
||||||
const authProvider = new NodeOAuthClientProvider({
|
const authProvider = new NodeOAuthClientProvider({
|
||||||
serverUrl,
|
serverUrl,
|
||||||
callbackPort,
|
callbackPort,
|
||||||
|
callbackPath,
|
||||||
clientName: 'MCP CLI Proxy',
|
clientName: 'MCP CLI Proxy',
|
||||||
|
clientId: clientId,
|
||||||
|
clientSecret: clientSecret,
|
||||||
|
scope: scope,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create the STDIO transport for local connections
|
// Create the STDIO transport for local connections
|
||||||
|
@ -136,8 +144,8 @@ to the CA certificate file. If using claude_desktop_config.json, this might look
|
||||||
|
|
||||||
// Parse command-line arguments and run the proxy
|
// Parse command-line arguments and run the proxy
|
||||||
parseCommandLineArgs(process.argv.slice(2), 3334, 'Usage: npx tsx proxy.ts <https://server-url> [callback-port]')
|
parseCommandLineArgs(process.argv.slice(2), 3334, 'Usage: npx tsx proxy.ts <https://server-url> [callback-port]')
|
||||||
.then(({ serverUrl, callbackPort, headers, transportStrategy }) => {
|
.then(({ serverUrl, callbackPort, headers, transportStrategy, callbackPath, clientId, clientSecret, scope }) => {
|
||||||
return runProxy(serverUrl, callbackPort, headers, transportStrategy)
|
return runProxy(serverUrl, callbackPort, headers, transportStrategy, callbackPath, clientId, clientSecret, scope)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
log('Fatal error:', error)
|
log('Fatal error:', error)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue