Skip to content

Commit b096ad8

Browse files
committed
Made debugLog sync, and fixing a lot of usages to stop passing serverHash
1 parent 4e16843 commit b096ad8

File tree

5 files changed

+122
-112
lines changed

5 files changed

+122
-112
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mcp-remote",
3-
"version": "0.1.9",
3+
"version": "0.1.10",
44
"description": "Remote proxy for Model Context Protocol, allowing local-only clients to connect to remote servers using oAuth",
55
"keywords": [
66
"mcp",
@@ -33,7 +33,7 @@
3333
"open": "^10.1.0"
3434
},
3535
"devDependencies": {
36-
"@modelcontextprotocol/sdk": "^1.11.2",
36+
"@modelcontextprotocol/sdk": "https://pkg.pr.new/geelen/typescript-sdk/@modelcontextprotocol/sdk@49c155a",
3737
"@types/express": "^5.0.0",
3838
"@types/node": "^22.13.10",
3939
"prettier": "^3.5.3",

pnpm-lock.yaml

Lines changed: 21 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/coordination.ts

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fs from 'fs'
12
import { checkLockfile, createLockfile, deleteLockfile, getConfigFilePath, LockfileData } from './mcp-auth-config'
23
import { EventEmitter } from 'events'
34
import { Server } from 'http'
@@ -17,10 +18,10 @@ export type AuthCoordinator = {
1718
export async function isPidRunning(pid: number): Promise<boolean> {
1819
try {
1920
process.kill(pid, 0) // Doesn't kill the process, just checks if it exists
20-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Process ${pid} is running`)
21+
if (DEBUG) debugLog(`Process ${pid} is running`)
2122
return true
2223
} catch (err) {
23-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Process ${pid} is not running`, err)
24+
if (DEBUG) debugLog(`Process ${pid} is not running`, err)
2425
return false
2526
}
2627
}
@@ -31,14 +32,14 @@ export async function isPidRunning(pid: number): Promise<boolean> {
3132
* @returns True if the lockfile is valid, false otherwise
3233
*/
3334
export async function isLockValid(lockData: LockfileData): Promise<boolean> {
34-
if (DEBUG) await debugLog(global.currentServerUrlHash!, 'Checking if lockfile is valid', lockData)
35+
if (DEBUG) debugLog('Checking if lockfile is valid', lockData)
3536

3637
// Check if the lockfile is too old (over 30 minutes)
3738
const MAX_LOCK_AGE = 30 * 60 * 1000 // 30 minutes
3839
if (Date.now() - lockData.timestamp > MAX_LOCK_AGE) {
3940
log('Lockfile is too old')
4041
if (DEBUG)
41-
await debugLog(global.currentServerUrlHash!, 'Lockfile is too old', {
42+
debugLog('Lockfile is too old', {
4243
age: Date.now() - lockData.timestamp,
4344
maxAge: MAX_LOCK_AGE,
4445
})
@@ -48,13 +49,13 @@ export async function isLockValid(lockData: LockfileData): Promise<boolean> {
4849
// Check if the process is still running
4950
if (!(await isPidRunning(lockData.pid))) {
5051
log('Process from lockfile is not running')
51-
if (DEBUG) await debugLog(global.currentServerUrlHash!, 'Process from lockfile is not running', { pid: lockData.pid })
52+
if (DEBUG) debugLog('Process from lockfile is not running', { pid: lockData.pid })
5253
return false
5354
}
5455

5556
// Check if the endpoint is accessible
5657
try {
57-
if (DEBUG) await debugLog(global.currentServerUrlHash!, 'Checking if endpoint is accessible', { port: lockData.port })
58+
if (DEBUG) debugLog('Checking if endpoint is accessible', { port: lockData.port })
5859

5960
const controller = new AbortController()
6061
const timeout = setTimeout(() => controller.abort(), 1000)
@@ -66,12 +67,11 @@ export async function isLockValid(lockData: LockfileData): Promise<boolean> {
6667
clearTimeout(timeout)
6768

6869
const isValid = response.status === 200 || response.status === 202
69-
if (DEBUG)
70-
await debugLog(global.currentServerUrlHash!, `Endpoint check result: ${isValid ? 'valid' : 'invalid'}`, { status: response.status })
70+
if (DEBUG) debugLog(`Endpoint check result: ${isValid ? 'valid' : 'invalid'}`, { status: response.status })
7171
return isValid
7272
} catch (error) {
7373
log(`Error connecting to auth server: ${(error as Error).message}`)
74-
if (DEBUG) await debugLog(global.currentServerUrlHash!, 'Error connecting to auth server', error)
74+
if (DEBUG) debugLog('Error connecting to auth server', error)
7575
return false
7676
}
7777
}
@@ -83,44 +83,44 @@ export async function isLockValid(lockData: LockfileData): Promise<boolean> {
8383
*/
8484
export async function waitForAuthentication(port: number): Promise<boolean> {
8585
log(`Waiting for authentication from the server on port ${port}...`)
86-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Waiting for authentication from server on port ${port}`)
86+
if (DEBUG) debugLog(`Waiting for authentication from server on port ${port}`)
8787

8888
try {
8989
let attempts = 0
9090
while (true) {
9191
attempts++
9292
const url = `http://127.0.0.1:${port}/wait-for-auth`
9393
log(`Querying: ${url}`)
94-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Poll attempt ${attempts}: ${url}`)
94+
if (DEBUG) debugLog(`Poll attempt ${attempts}: ${url}`)
9595

9696
try {
9797
const response = await fetch(url)
98-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Poll response status: ${response.status}`)
98+
if (DEBUG) debugLog(`Poll response status: ${response.status}`)
9999

100100
if (response.status === 200) {
101101
// Auth completed, but we don't return the code anymore
102102
log(`Authentication completed by other instance`)
103-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Authentication completed by other instance`)
103+
if (DEBUG) debugLog(`Authentication completed by other instance`)
104104
return true
105105
} else if (response.status === 202) {
106106
// Continue polling
107107
log(`Authentication still in progress`)
108-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Authentication still in progress, will retry in 1s`)
108+
if (DEBUG) debugLog(`Authentication still in progress, will retry in 1s`)
109109
await new Promise((resolve) => setTimeout(resolve, 1000))
110110
} else {
111111
log(`Unexpected response status: ${response.status}`)
112-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Unexpected response status`, { status: response.status })
112+
if (DEBUG) debugLog(`Unexpected response status`, { status: response.status })
113113
return false
114114
}
115115
} catch (fetchError) {
116-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Fetch error during poll`, fetchError)
116+
if (DEBUG) debugLog(`Fetch error during poll`, fetchError)
117117
// If we can't connect, we'll try again after a delay
118118
await new Promise((resolve) => setTimeout(resolve, 2000))
119119
}
120120
}
121121
} catch (error) {
122122
log(`Error waiting for authentication: ${(error as Error).message}`)
123-
if (DEBUG) await debugLog(global.currentServerUrlHash!, `Error waiting for authentication`, error)
123+
if (DEBUG) debugLog(`Error waiting for authentication`, error)
124124
return false
125125
}
126126
}
@@ -139,16 +139,16 @@ export function createLazyAuthCoordinator(serverUrlHash: string, callbackPort: n
139139
initializeAuth: async () => {
140140
// If auth has already been initialized, return the existing state
141141
if (authState) {
142-
if (DEBUG) await debugLog(serverUrlHash, 'Auth already initialized, reusing existing state')
142+
if (DEBUG) debugLog('Auth already initialized, reusing existing state')
143143
return authState
144144
}
145145

146146
log('Initializing auth coordination on-demand')
147-
if (DEBUG) await debugLog(serverUrlHash, 'Initializing auth coordination on-demand', { serverUrlHash, callbackPort })
147+
if (DEBUG) debugLog('Initializing auth coordination on-demand', { serverUrlHash, callbackPort })
148148

149149
// Initialize auth using the existing coordinateAuth logic
150150
authState = await coordinateAuth(serverUrlHash, callbackPort, events)
151-
if (DEBUG) await debugLog(serverUrlHash, 'Auth coordination completed', { skipBrowserAuth: authState.skipBrowserAuth })
151+
if (DEBUG) debugLog('Auth coordination completed', { skipBrowserAuth: authState.skipBrowserAuth })
152152
return authState
153153
},
154154
}
@@ -166,42 +166,42 @@ export async function coordinateAuth(
166166
callbackPort: number,
167167
events: EventEmitter,
168168
): Promise<{ server: Server; waitForAuthCode: () => Promise<string>; skipBrowserAuth: boolean }> {
169-
if (DEBUG) await debugLog(serverUrlHash, 'Coordinating authentication', { serverUrlHash, callbackPort })
169+
if (DEBUG) debugLog('Coordinating authentication', { serverUrlHash, callbackPort })
170170

171171
// Check for a lockfile (disabled on Windows for the time being)
172172
const lockData = process.platform === 'win32' ? null : await checkLockfile(serverUrlHash)
173173

174174
if (DEBUG) {
175175
if (process.platform === 'win32') {
176-
await debugLog(serverUrlHash, 'Skipping lockfile check on Windows')
176+
debugLog('Skipping lockfile check on Windows')
177177
} else {
178-
await debugLog(serverUrlHash, 'Lockfile check result', { found: !!lockData, lockData })
178+
debugLog('Lockfile check result', { found: !!lockData, lockData })
179179
}
180180
}
181181

182182
// If there's a valid lockfile, try to use the existing auth process
183183
if (lockData && (await isLockValid(lockData))) {
184184
log(`Another instance is handling authentication on port ${lockData.port}`)
185-
if (DEBUG) await debugLog(serverUrlHash, 'Another instance is handling authentication', { port: lockData.port, pid: lockData.pid })
185+
if (DEBUG) debugLog('Another instance is handling authentication', { port: lockData.port, pid: lockData.pid })
186186

187187
try {
188188
// Try to wait for the authentication to complete
189-
if (DEBUG) await debugLog(serverUrlHash, 'Waiting for authentication from other instance')
189+
if (DEBUG) debugLog('Waiting for authentication from other instance')
190190
const authCompleted = await waitForAuthentication(lockData.port)
191191

192192
if (authCompleted) {
193193
log('Authentication completed by another instance')
194-
if (DEBUG) await debugLog(serverUrlHash, 'Authentication completed by another instance, will use tokens from disk')
194+
if (DEBUG) debugLog('Authentication completed by another instance, will use tokens from disk')
195195

196196
// Setup a dummy server - the client will use tokens directly from disk
197197
const dummyServer = express().listen(0) // Listen on any available port
198198
const dummyPort = (dummyServer.address() as AddressInfo).port
199-
if (DEBUG) await debugLog(serverUrlHash, 'Started dummy server', { port: dummyPort })
199+
if (DEBUG) debugLog('Started dummy server', { port: dummyPort })
200200

201201
// This shouldn't actually be called in normal operation, but provide it for API compatibility
202202
const dummyWaitForAuthCode = () => {
203203
log('WARNING: waitForAuthCode called in secondary instance - this is unexpected')
204-
if (DEBUG) debugLog(serverUrlHash, 'WARNING: waitForAuthCode called in secondary instance - this is unexpected').catch(() => {})
204+
if (DEBUG) debugLog('WARNING: waitForAuthCode called in secondary instance - this is unexpected')
205205
// Return a promise that never resolves - the client should use the tokens from disk instead
206206
return new Promise<string>(() => {})
207207
}
@@ -213,25 +213,25 @@ export async function coordinateAuth(
213213
}
214214
} else {
215215
log('Taking over authentication process...')
216-
if (DEBUG) await debugLog(serverUrlHash, 'Taking over authentication process')
216+
if (DEBUG) debugLog('Taking over authentication process')
217217
}
218218
} catch (error) {
219219
log(`Error waiting for authentication: ${error}`)
220-
if (DEBUG) await debugLog(serverUrlHash, 'Error waiting for authentication', error)
220+
if (DEBUG) debugLog('Error waiting for authentication', error)
221221
}
222222

223223
// If we get here, the other process didn't complete auth successfully
224-
if (DEBUG) await debugLog(serverUrlHash, 'Other instance did not complete auth successfully, deleting lockfile')
224+
if (DEBUG) debugLog('Other instance did not complete auth successfully, deleting lockfile')
225225
await deleteLockfile(serverUrlHash)
226226
} else if (lockData) {
227227
// Invalid lockfile, delete it
228228
log('Found invalid lockfile, deleting it')
229-
if (DEBUG) await debugLog(serverUrlHash, 'Found invalid lockfile, deleting it')
229+
if (DEBUG) debugLog('Found invalid lockfile, deleting it')
230230
await deleteLockfile(serverUrlHash)
231231
}
232232

233233
// Create our own lockfile
234-
if (DEBUG) await debugLog(serverUrlHash, 'Setting up OAuth callback server', { port: callbackPort })
234+
if (DEBUG) debugLog('Setting up OAuth callback server', { port: callbackPort })
235235
const { server, waitForAuthCode, authCompletedPromise } = setupOAuthCallbackServerWithLongPoll({
236236
port: callbackPort,
237237
path: '/oauth/callback',
@@ -241,29 +241,29 @@ export async function coordinateAuth(
241241
// Get the actual port the server is running on
242242
const address = server.address() as AddressInfo
243243
const actualPort = address.port
244-
if (DEBUG) await debugLog(serverUrlHash, 'OAuth callback server running', { port: actualPort })
244+
if (DEBUG) debugLog('OAuth callback server running', { port: actualPort })
245245

246246
log(`Creating lockfile for server ${serverUrlHash} with process ${process.pid} on port ${actualPort}`)
247-
if (DEBUG) await debugLog(serverUrlHash, 'Creating lockfile', { serverUrlHash, pid: process.pid, port: actualPort })
247+
if (DEBUG) debugLog('Creating lockfile', { serverUrlHash, pid: process.pid, port: actualPort })
248248
await createLockfile(serverUrlHash, process.pid, actualPort)
249249

250250
// Make sure lockfile is deleted on process exit
251251
const cleanupHandler = async () => {
252252
try {
253253
log(`Cleaning up lockfile for server ${serverUrlHash}`)
254-
if (DEBUG) await debugLog(serverUrlHash, 'Cleaning up lockfile')
254+
if (DEBUG) debugLog('Cleaning up lockfile')
255255
await deleteLockfile(serverUrlHash)
256256
} catch (error) {
257257
log(`Error cleaning up lockfile: ${error}`)
258-
if (DEBUG) await debugLog(serverUrlHash, 'Error cleaning up lockfile', error)
258+
if (DEBUG) debugLog('Error cleaning up lockfile', error)
259259
}
260260
}
261261

262262
process.once('exit', () => {
263263
try {
264264
// Synchronous version for 'exit' event since we can't use async here
265265
const configPath = getConfigFilePath(serverUrlHash, 'lock.json')
266-
require('fs').unlinkSync(configPath)
266+
fs.unlinkSync(configPath)
267267
if (DEBUG) console.error(`[DEBUG] Removed lockfile on exit: ${configPath}`)
268268
} catch (error) {
269269
if (DEBUG) console.error(`[DEBUG] Error removing lockfile on exit:`, error)
@@ -272,11 +272,11 @@ export async function coordinateAuth(
272272

273273
// Also handle SIGINT separately
274274
process.once('SIGINT', async () => {
275-
if (DEBUG) await debugLog(serverUrlHash, 'Received SIGINT signal, cleaning up')
275+
if (DEBUG) debugLog('Received SIGINT signal, cleaning up')
276276
await cleanupHandler()
277277
})
278278

279-
if (DEBUG) await debugLog(serverUrlHash, 'Auth coordination complete, returning primary instance handlers')
279+
if (DEBUG) debugLog('Auth coordination complete, returning primary instance handlers')
280280
return {
281281
server,
282282
waitForAuthCode,

0 commit comments

Comments
 (0)