Skip to content

fix(mcp): disable interactive OAuth in embedded MCP server handler#4444

Merged
peppescg merged 1 commit intomainfrom
fix/mcp-handler-interactive-oauth
Mar 30, 2026
Merged

fix(mcp): disable interactive OAuth in embedded MCP server handler#4444
peppescg merged 1 commit intomainfrom
fix/mcp-handler-interactive-oauth

Conversation

@peppescg
Copy link
Copy Markdown
Contributor

@peppescg peppescg commented Mar 30, 2026

Summary

When thv serve starts with --experimental-mcp (always enabled by ToolHive Studio), the MCP server handler was the first code path to create the shared singleton registry.Provider via registry.GetDefaultProvider(). Because NewRegistryProvider defaults to interactive: true and the provider is guarded by sync.Once, this "poisoned" the singleton — all subsequent callers (including the HTTP API routes that explicitly pass WithInteractive(false)) inherited interactive mode.

The result: every time the desktop app restarted with invalid registry credentials (e.g. wrong client_id), the browser opened automatically for an OAuth flow that would always fail.

  • Pass registry.WithInteractive(false) explicitly in the MCP handler, aligning it with how all other thv serve code paths create the provider.

Type of change

  • Bug fix

Test plan

  • Manual testing (describe below)

Tested with ToolHive Studio connected to a thv serve instance with a misconfigured registry (client_id wrong). Before the fix, restarting the app opened the browser for OAuth. After the fix, the app correctly shows a registry configuration error without opening the browser.

Changes

File Change
pkg/mcp/server/handler.go Use GetDefaultProviderWithConfig with WithInteractive(false) instead of GetDefaultProvider()

Does this introduce a user-facing change?

Yes — when thv serve is started with --experimental-mcp and the registry has invalid OAuth credentials, the browser no longer opens automatically for an OAuth flow that cannot succeed. Instead, the error is returned to the caller (API or MCP client) for proper handling.

Special notes for reviewers

The root cause is that registry.Provider is a sync.Once singleton. Whichever caller creates it first sets interactive for all subsequent users. In thv serve, the MCP handler goroutine consistently wins the race against lazySkillLookup and the API routes. This fix ensures the MCP handler creates the singleton with interactive: false, which is the correct behavior for all server-side code paths.

The POST /auth/login endpoint is unaffected because it creates its own standalone provider (not the singleton) with WithInteractive(true) explicitly.

The MCP server handler was calling registry.GetDefaultProvider() without
explicitly setting WithInteractive(false). Because the registry provider
is a singleton (sync.Once), and the MCP handler is typically the first
caller during `thv serve --experimental-mcp`, it "poisoned" the shared
provider with interactive=true. All subsequent callers — including the
HTTP API routes that intentionally disable interactive mode — inherited
this setting, causing the browser to open for OAuth on every registry
access when credentials were invalid.

Made-with: Cursor
@github-actions github-actions bot added the size/XS Extra small PR: < 100 lines changed label Mar 30, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.54%. Comparing base (7868d49) to head (10a71d5).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4444      +/-   ##
==========================================
+ Coverage   69.48%   69.54%   +0.05%     
==========================================
  Files         486      486              
  Lines       50017    50029      +12     
==========================================
+ Hits        34755    34792      +37     
+ Misses      12577    12551      -26     
- Partials     2685     2686       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions bot added size/XS Extra small PR: < 100 lines changed and removed size/XS Extra small PR: < 100 lines changed labels Mar 30, 2026
@peppescg peppescg merged commit 4557382 into main Mar 30, 2026
43 of 44 checks passed
@peppescg peppescg deleted the fix/mcp-handler-interactive-oauth branch March 30, 2026 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XS Extra small PR: < 100 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants