Merge branch 'main' into main
This commit is contained in:
commit
baac4b5b79
2 changed files with 26 additions and 6 deletions
|
@ -1,9 +1,8 @@
|
||||||
import open from 'open'
|
import open from 'open'
|
||||||
import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js'
|
import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js'
|
||||||
import {
|
import {
|
||||||
OAuthClientInformation,
|
|
||||||
OAuthClientInformationFull,
|
OAuthClientInformationFull,
|
||||||
OAuthClientInformationSchema,
|
OAuthClientInformationFullSchema,
|
||||||
OAuthTokens,
|
OAuthTokens,
|
||||||
OAuthTokensSchema,
|
OAuthTokensSchema,
|
||||||
} from '@modelcontextprotocol/sdk/shared/auth.js'
|
} from '@modelcontextprotocol/sdk/shared/auth.js'
|
||||||
|
@ -57,9 +56,9 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
||||||
* Gets the client information if it exists
|
* Gets the client information if it exists
|
||||||
* @returns The client information or undefined
|
* @returns The client information or undefined
|
||||||
*/
|
*/
|
||||||
async clientInformation(): Promise<OAuthClientInformation | undefined> {
|
async clientInformation(): Promise<OAuthClientInformationFull | undefined> {
|
||||||
// log('Reading client info')
|
// log('Reading client info')
|
||||||
return readJsonFile<OAuthClientInformation>(this.serverUrlHash, 'client_info.json', OAuthClientInformationSchema)
|
return readJsonFile<OAuthClientInformationFull>(this.serverUrlHash, 'client_info.json', OAuthClientInformationFullSchema)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,6 +6,8 @@ import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import os from 'os'
|
import os from 'os'
|
||||||
|
import { OAuthClientInformationFull, OAuthClientInformationFullSchema } from '@modelcontextprotocol/sdk/shared/auth.js'
|
||||||
|
|
||||||
|
|
||||||
// Connection constants
|
// Connection constants
|
||||||
export const REASON_AUTH_NEEDED = 'authentication-needed'
|
export const REASON_AUTH_NEEDED = 'authentication-needed'
|
||||||
|
@ -15,6 +17,7 @@ export const SHORT_TIMEOUT_DURATION = 50000
|
||||||
// Transport strategy types
|
// Transport strategy types
|
||||||
export type TransportStrategy = 'sse-only' | 'http-only' | 'sse-first' | 'http-first'
|
export type TransportStrategy = 'sse-only' | 'http-only' | 'sse-first' | 'http-first'
|
||||||
import { OAuthCallbackServerOptions } from './types'
|
import { OAuthCallbackServerOptions } from './types'
|
||||||
|
import { readJsonFile } from './mcp-auth-config'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import net from 'net'
|
import net from 'net'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
|
@ -399,6 +402,21 @@ export function setupOAuthCallbackServer(options: OAuthCallbackServerOptions) {
|
||||||
return { server, authCode, waitForAuthCode }
|
return { server, authCode, waitForAuthCode }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function findExistingClientPort(serverUrl: string): Promise<number | undefined> {
|
||||||
|
const serverUrlHash = getServerUrlHash(serverUrl)
|
||||||
|
const clientInfo = await readJsonFile<OAuthClientInformationFull>(serverUrlHash, 'client_info.json', OAuthClientInformationFullSchema)
|
||||||
|
if (!clientInfo) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const localhostRedirectUri = clientInfo.redirect_uris.map((uri) => new URL(uri)).find(({ hostname }) => hostname === 'localhost')
|
||||||
|
if (!localhostRedirectUri) {
|
||||||
|
throw new Error('Cannot find localhost callback URI from existing client information')
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseInt(localhostRedirectUri.port)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds an available port on the local machine
|
* Finds an available port on the local machine
|
||||||
* @param preferredPort Optional preferred port to try first
|
* @param preferredPort Optional preferred port to try first
|
||||||
|
@ -488,11 +506,14 @@ export async function parseCommandLineArgs(args: string[], defaultPort: number,
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the specified port, or find an available one
|
// Use the specified port, or the existing client port or fallback to find an available one
|
||||||
const callbackPort = specifiedPort || (await findAvailablePort(defaultPort))
|
const [existingClientPort, availablePort] = await Promise.all([findExistingClientPort(serverUrl), findAvailablePort(defaultPort)])
|
||||||
|
const callbackPort = specifiedPort || existingClientPort || availablePort
|
||||||
|
|
||||||
if (specifiedPort) {
|
if (specifiedPort) {
|
||||||
log(`Using specified callback port: ${callbackPort}`)
|
log(`Using specified callback port: ${callbackPort}`)
|
||||||
|
} else if (existingClientPort) {
|
||||||
|
log(`Using existing client port: ${existingClientPort}`)
|
||||||
} else {
|
} else {
|
||||||
log(`Using automatically selected callback port: ${callbackPort}`)
|
log(`Using automatically selected callback port: ${callbackPort}`)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue