|
|
@@ -1,10 +1,14 @@
|
|
|
import { createConnection } from "net"
|
|
|
import { createServer } from "http"
|
|
|
import { Log } from "../util/log"
|
|
|
-import { OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH } from "./oauth-provider"
|
|
|
+import { OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH, parseRedirectUri } from "./oauth-provider"
|
|
|
|
|
|
const log = Log.create({ service: "mcp.oauth-callback" })
|
|
|
|
|
|
+// Current callback server configuration (may differ from defaults if custom redirectUri is used)
|
|
|
+let currentPort = OAUTH_CALLBACK_PORT
|
|
|
+let currentPath = OAUTH_CALLBACK_PATH
|
|
|
+
|
|
|
const HTML_SUCCESS = `<!DOCTYPE html>
|
|
|
<html>
|
|
|
<head>
|
|
|
@@ -71,9 +75,9 @@ export namespace McpOAuthCallback {
|
|
|
}
|
|
|
|
|
|
function handleRequest(req: import("http").IncomingMessage, res: import("http").ServerResponse) {
|
|
|
- const url = new URL(req.url || "/", `http://localhost:${OAUTH_CALLBACK_PORT}`)
|
|
|
+ const url = new URL(req.url || "/", `http://localhost:${currentPort}`)
|
|
|
|
|
|
- if (url.pathname !== OAUTH_CALLBACK_PATH) {
|
|
|
+ if (url.pathname !== currentPath) {
|
|
|
res.writeHead(404)
|
|
|
res.end("Not found")
|
|
|
return
|
|
|
@@ -135,19 +139,31 @@ export namespace McpOAuthCallback {
|
|
|
res.end(HTML_SUCCESS)
|
|
|
}
|
|
|
|
|
|
- export async function ensureRunning(): Promise<void> {
|
|
|
+ export async function ensureRunning(redirectUri?: string): Promise<void> {
|
|
|
+ // Parse the redirect URI to get port and path (uses defaults if not provided)
|
|
|
+ const { port, path } = parseRedirectUri(redirectUri)
|
|
|
+
|
|
|
+ // If server is running on a different port/path, stop it first
|
|
|
+ if (server && (currentPort !== port || currentPath !== path)) {
|
|
|
+ log.info("stopping oauth callback server to reconfigure", { oldPort: currentPort, newPort: port })
|
|
|
+ await stop()
|
|
|
+ }
|
|
|
+
|
|
|
if (server) return
|
|
|
|
|
|
- const running = await isPortInUse()
|
|
|
+ const running = await isPortInUse(port)
|
|
|
if (running) {
|
|
|
- log.info("oauth callback server already running on another instance", { port: OAUTH_CALLBACK_PORT })
|
|
|
+ log.info("oauth callback server already running on another instance", { port })
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+ currentPort = port
|
|
|
+ currentPath = path
|
|
|
+
|
|
|
server = createServer(handleRequest)
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
|
- server!.listen(OAUTH_CALLBACK_PORT, () => {
|
|
|
- log.info("oauth callback server started", { port: OAUTH_CALLBACK_PORT })
|
|
|
+ server!.listen(currentPort, () => {
|
|
|
+ log.info("oauth callback server started", { port: currentPort, path: currentPath })
|
|
|
resolve()
|
|
|
})
|
|
|
server!.on("error", reject)
|
|
|
@@ -182,9 +198,9 @@ export namespace McpOAuthCallback {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- export async function isPortInUse(): Promise<boolean> {
|
|
|
+ export async function isPortInUse(port: number = OAUTH_CALLBACK_PORT): Promise<boolean> {
|
|
|
return new Promise((resolve) => {
|
|
|
- const socket = createConnection(OAUTH_CALLBACK_PORT, "127.0.0.1")
|
|
|
+ const socket = createConnection(port, "127.0.0.1")
|
|
|
socket.on("connect", () => {
|
|
|
socket.destroy()
|
|
|
resolve(true)
|