Skip to content

feat(mcp): add --token flag and fix .mcp.json auth for Claude Code#90

Merged
edgarriba merged 2 commits into
mainfrom
fix/mcp-token-race
May 12, 2026
Merged

feat(mcp): add --token flag and fix .mcp.json auth for Claude Code#90
edgarriba merged 2 commits into
mainfrom
fix/mcp-token-race

Conversation

@edgarriba

Copy link
Copy Markdown
Member

Summary

  • bubbaloop mcp --token: new early-exit flag that prints the MCP bearer token (generating it if missing) — no Zenoh session needed. Enables export BUBBALOOP_MCP_TOKEN=$(bubbaloop mcp --token) in shell profiles.
  • .mcp.json auth fix: adds "headers": {"Authorization": "Bearer ${BUBBALOOP_MCP_TOKEN}"} so Claude Code can connect to the running daemon's HTTP MCP endpoint. Previously the server returned 401 Unauthorized and never appeared in Claude Code.
  • Docs: README one-time setup snippet + docs/troubleshooting.md env vars table updated.

Why the server wasn't showing up

The project .mcp.json used streamable-http transport (connects to the running daemon on port 8088), but the HTTP endpoint requires a bearer token. Claude Code sent the MCP init request without auth → 401 → server never registered. The project config was also shadowing the global ~/.claude/.mcp.json stdio config (same server name "bubbaloop"), so neither worked.

The ${BUBBALOOP_MCP_TOKEN} pattern is the standard approach used by Hugging Face, Notion, and other MCP servers with auth.

Test plan

  • bubbaloop mcp --token prints the token from ~/.bubbaloop/mcp-token
  • export BUBBALOOP_MCP_TOKEN=$(bubbaloop mcp --token) then start Claude Code in this project — bubbaloop server appears in the MCP tool list
  • bubbaloop mcp --token on a fresh machine (no token file) generates and prints a new token
  • bubbaloop --help shows --token: Print bearer token (for BUBBALOOP_MCP_TOKEN)

🤖 Generated with Claude Code

edgarriba and others added 2 commits May 12, 2026 17:09
The daemon starts both the gateway and agent runtime concurrently. Both
called load_or_generate_token() at the same time, hitting a two-step
race: O_EXCL creates the file atomically, but the data write is a
separate syscall — leaving a brief window where AlreadyExists was
returned but the file was still empty.

Two layers of defence:
- OnceLock in load_or_generate_token() so same-process callers never
  race to the filesystem after the first call
- wait_for_token() replaces the hard error on AlreadyExists, spinning
  up to 100 ms for the winning writer to flush (handles cross-process
  races)

Adds test_concurrent_token_generation: 8 threads race to create the
token and must all receive the same value.

Also suppresses pre-existing clippy::const_is_empty lint in
agent_setup tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `bubbaloop mcp --token` to print the bearer token without starting
a server, enabling the BUBBALOOP_MCP_TOKEN env var pattern. Fix the
project .mcp.json to include the Authorization header so Claude Code
can connect to the running daemon's HTTP MCP endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@edgarriba edgarriba merged commit 4dadb64 into main May 12, 2026
1 check passed
@edgarriba edgarriba deleted the fix/mcp-token-race branch May 12, 2026 17:18
edgarriba added a commit that referenced this pull request May 19, 2026
Ships 10 commits worth of features and fixes since v0.0.13:

Features
- agent: grab_frame tool + Gemini Vision provider + image-in-chat (#96)
- dashboard: Chat tab with HTTP+SSE agent gateway (#91)
- agent: client-side turn cancellation via Zenoh cancel topic (#94, #95)
- chat: multi-provider login status, 404 on unknown agent, Claude OAuth
  risk warning (#93)
- mcp: 'bubbaloop mcp --token' prints bearer token for .mcp.json (#90)

Fixes
- agent: grab_frame reads binary JPEG payload + JSON metadata
  attachment from camera nodes (#99)
- chat: clear Responding state after multi-camera grab_frame (#98)
- mcp: eliminate token race between gateway and agent runtime (#89)

Chores
- dashboard: remove LibraryView component (#92, replaced by Chat tab)

Docs
- Comprehensive sync across README, CHANGELOG (backfilled v0.0.8 to
  v0.0.13), CLAUDE.md, ARCHITECTURE.md, ROADMAP.md, concept/reference/
  dashboard docs to match the new feature surface (#100)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant