Skip to content
This repository was archived by the owner on May 21, 2026. It is now read-only.

Commit c188144

Browse files
committed
feat(inspector): implement OAuth callback handling and improve redirect logic
- Add a custom Vite plugin to manage OAuth callback redirects in development mode - Update InspectorDashboard and McpContext to dynamically set the redirect URL based on the current environment - Enhance server middleware to redirect OAuth callbacks to the correct inspector path - Modify the MCP authorization callback to determine the base path for redirection after authentication
1 parent fbbd018 commit c188144

5 files changed

Lines changed: 53 additions & 6 deletions

File tree

packages/inspector/src/client/components/InspectorDashboard.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ export function InspectorDashboard() {
3333

3434
// OAuth fields
3535
const [clientId, setClientId] = useState('')
36-
const [redirectUrl, setRedirectUrl] = useState('http://localhost:6274/oauth/callback')
36+
const [redirectUrl, setRedirectUrl] = useState(
37+
typeof window !== 'undefined'
38+
? new URL('/oauth/callback', window.location.origin).toString()
39+
: 'http://localhost:3000/oauth/callback',
40+
)
3741
const [scope, setScope] = useState('')
3842

3943
// UI state

packages/inspector/src/client/context/McpContext.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,14 @@ function McpConnectionWrapper({ url, name, onUpdate, onRemove: _onRemove }: {
3939
onUpdate: (connection: MCPConnection) => void
4040
onRemove: () => void
4141
}) {
42-
const mcpHook = useMcp({ url })
42+
// Configure OAuth callback URL
43+
// Use /oauth/callback (which redirects to /inspector/oauth/callback) for compatibility
44+
// with existing OAuth app configurations
45+
const callbackUrl = typeof window !== 'undefined'
46+
? new URL('/oauth/callback', window.location.origin).toString()
47+
: '/oauth/callback'
48+
49+
const mcpHook = useMcp({ url, callbackUrl })
4350
const onUpdateRef = useRef(onUpdate)
4451
const prevConnectionRef = useRef<MCPConnection | null>(null)
4552

packages/inspector/src/server/middleware.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Express, Request, Response } from 'express'
2+
import { Buffer } from 'node:buffer'
23
import { existsSync } from 'node:fs'
34
import { dirname, join } from 'node:path'
45
import { fileURLToPath } from 'node:url'
@@ -129,6 +130,18 @@ export function mountInspector(app: Express, path: string = '/inspector', mcpSer
129130
res.redirect(301, basePath)
130131
})
131132

133+
// Handle OAuth callback redirects - redirect /oauth/callback to /inspector/oauth/callback
134+
// This helps when OAuth providers are configured with the wrong redirect URL
135+
if (basePath !== '') {
136+
app.get('/oauth/callback', (req: Request, res: Response) => {
137+
const queryString = req.url.split('?')[1] || ''
138+
const redirectUrl = queryString
139+
? `${basePath}/oauth/callback?${queryString}`
140+
: `${basePath}/oauth/callback`
141+
res.redirect(302, redirectUrl)
142+
})
143+
}
144+
132145
// Serve the main HTML file for all inspector routes
133146
app.get(`${basePath}*`, (_req: Request, res: Response) => {
134147
const indexPath = join(clientDistPath, 'index.html')
@@ -141,6 +154,4 @@ export function mountInspector(app: Express, path: string = '/inspector', mcpSer
141154
// Serve the HTML file (Vite built with base: '/inspector')
142155
res.sendFile(indexPath)
143156
})
144-
145-
console.log(`MCP Inspector mounted at ${basePath}`)
146157
}

packages/inspector/vite.config.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,26 @@ const packageJson = JSON.parse(readFileSync(path.resolve(__dirname, 'package.jso
99

1010
export default defineConfig({
1111
base: '/inspector',
12-
plugins: [react(), tailwindcss()],
12+
plugins: [
13+
react(),
14+
tailwindcss(),
15+
// Custom plugin to handle OAuth callback redirects in dev mode
16+
{
17+
name: 'oauth-callback-redirect',
18+
configureServer(server) {
19+
server.middlewares.use((req, res, next) => {
20+
if (req.url?.startsWith('/oauth/callback')) {
21+
const url = new URL(req.url, 'http://localhost')
22+
const queryString = url.search
23+
res.writeHead(302, { Location: `/inspector/oauth/callback${queryString}` })
24+
res.end()
25+
return
26+
}
27+
next()
28+
})
29+
},
30+
},
31+
],
1332
resolve: {
1433
alias: {
1534
'@': path.resolve(__dirname, './src'),

packages/mcp-use/src/auth/callback.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,13 @@ export async function onMcpAuthorization() {
7777
window.close()
7878
} else {
7979
console.warn(`${logPrefix} No opener window detected. Redirecting to root.`)
80-
window.location.href = '/' // Or a configured post-auth destination
80+
// Try to determine the base path from the current URL
81+
// e.g., if we're at /inspector/oauth/callback, redirect to /inspector
82+
const pathParts = window.location.pathname.split('/').filter(Boolean)
83+
const basePath = pathParts.length > 0 && pathParts[pathParts.length - 1] === 'callback'
84+
? '/' + pathParts.slice(0, -2).join('/')
85+
: '/'
86+
window.location.href = basePath || '/'
8187
}
8288
// Clean up state ONLY on success and after notifying opener
8389
localStorage.removeItem(stateKey)

0 commit comments

Comments
 (0)