thv run local proxy doesn't advertise itself as OAuth protected resource, breaking MCP client re-authentication
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 2.2k
- Forks
- 300
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 184
Description
Bug Description
When using thv run to create a local proxy for a remote MCP server that uses OAuth, the initial authentication works fine. However, when the MCP client triggers re-authentication (e.g., after token expiry), it fails because the local proxy doesn't serve /.well-known/oauth-protected-resource with its own URL. The MCP SDK discovers the remote server's metadata instead, causing an origin mismatch.
Error
Error: Protected resource https://mcp.stacklok.dev/github/mcp does not match expected http://localhost:41339/github/mcp (or origin)
Steps to Reproduce
-
Start a local proxy with
thv run:thv run --name github-test --transport streamable-http https://mcp.stacklok.dev/github/mcpThis creates a local proxy at
http://localhost:<PORT>/github/mcp. -
The initial OAuth authentication flow completes successfully and the proxy is usable.
-
When re-authentication is triggered (e.g., via
/mcpreauth in Claude Code), the MCP SDK fetches/.well-known/oauth-protected-resourcefrom the local proxy. -
The local proxy doesn't serve this endpoint (returns 404), so the SDK falls back to discovering the remote server's metadata, which returns
https://mcp.stacklok.dev/github/mcpas the resource. -
The SDK compares this against the server URL it connected to (
http://localhost:<PORT>/github/mcp), finds an origin mismatch, and rejects it.
Working Comparison
Connecting directly to the remote server (bypassing thv run) works correctly:
claude mcp add --scope user --transport http github-test https://mcp.stacklok.dev/github/mcp
Re-authentication succeeds because the resource field matches the server URL the client connected to.
Root Cause
In pkg/auth/token.go, NewAuthInfoHandler returns a 404 when resourceURL is empty:
if resourceURL == "" {
w.WriteHeader(http.StatusNotFound)
return
}
When thv run is used for remote servers, TokenValidatorConfig.ResourceURL defaults to empty, so the local proxy never serves RFC 9728 protected resource metadata. The MCP SDK then discovers the remote server's metadata, whose resource field doesn't match the local proxy origin.
Suggested Fix
thv run should automatically set ResourceURL to the local proxy's own URL (e.g., http://localhost:<PORT>/path) when creating the proxy for a remote server, so that /.well-known/oauth-protected-resource correctly identifies the local proxy as the resource.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with pkg/auth/token.go and the NewAuthInfoHandler behavior when resourceURL is empty, then trace the thv run proxy setup and TokenValidatorConfig.ResourceURL for remote servers. Done means the local proxy serves /.well-known/oauth-protected-resource with its own URL and MCP client re-authentication no longer fails with an origin mismatch.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, authentication
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100