MCPJam / MCPJam/inspector

OAuth connect fails for internal MCP servers on private/reserved IPs (guard vs. resource-origin check conflict)

Open
#4,364 2 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
TypeScript
Stars
2.2k
Forks
283
Avg merge
11h 47m
Merged PRs (30d)
737

Description

## What I'm trying to do

Connect Inspector to an internal, OAuth-protected MCP server. I've independently verified the server itself is healthy and spec-compliant (raw HTTP checks confirm `/.well-known/oauth-protected-resource`, `/.well-known/oauth-authorization-server`, and Dynamic Client Registration via `/register` all return valid RFC 9728 / RFC 8414 metadata, with `Access-Control-Allow-Origin: *`). The blocker seems to be entirely on the Inspector side.

## The blocker

The server's hostname resolves to an IP in a private/reserved range (RFC 6598 CGNAT space, `100.64.0.0/10` — common for internal corporate VPNs/load balancers). When I try to connect (Auth = Auto), every OAuth metadata discovery call fails with:

```json
{"error":"OAuth metadata target resolves to a private/reserved IP address ()", ...}
```

...regardless of Registration Strategy (Automatic/Preregistration/CIMD/DCR all hit this same guard, since it's on the discovery fetch itself). The UI just shows a generic "could not find a usable CIMD or DCR flow" toast — the real reason only shows up in the Network tab.

## What I tried

I stood up a local reverse proxy on `127.0.0.1` (forwarding to the real host) so the configured Server URL would be loopback and pass that guard, rewriting only the minimum in the metadata responses (leaving `resource`, `authorization_endpoint`, `token_endpoint`, `registration_endpoint` pointed at the real host, since the real server needs the real `resource` value or it errors out).

That got further — discovery and CIMD/DCR succeeded, a real `/authorize` URL got built — but the interactive connect flow then rejected it:

```
Rejected OAuth resource indicator from protected resource metadata: Resource indicator
"" is on a different origin than the server URL "http://127.0.0.1:/mcp"
— honoring it would let the server steer tokens to an audience it doesn't own.
```

Which makes sense as a check in isolation, but it seems to directly conflict with the loopback requirement from the first guard — I can't find a configuration where both are satisfied at once for a server like this.

## What I'm asking

Is there an intended way to connect to a private/internal MCP server through local Inspector today that I'm missing (some flag, env var, or config)? I noticed a `MCPJAM_ALLOWED_HOSTS` env var in the shipped bundle but couldn't find anywhere it's actually consulted — is that meant to help here, or is it for something unrelated / not wired up yet?

Any pointers on the recommended path (or whether this is just a known gap right now) would be appreciated.

## Environment

- `@mcpjam/inspector` v2.47.0
- Local/self-hosted mode (`npx @mcpjam/inspector@latest`), macOS
- Node v26

Contributor guide

Open the contributing guide

Research direction

Trace the metadata discovery guard for private/reserved IPs and the later OAuth resource-origin validation in the Inspector connection flow. Search the shipped bundle and source for MCPJAM_ALLOWED_HOSTS to determine whether it is consulted, then reproduce the loopback and internal-host cases. Done should mean a documented or implemented supported path for private MCP servers with tests covering both checks.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
api, authentication, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.