Skip to content

Fix CE mode OAuth and preserve raw tool arguments through gateway#454

Open
nathanielosullivanmolloy wants to merge 2 commits intodocker:mainfrom
nathanielosullivanmolloy:fix/ce-mode-oauth-and-argument-forwarding
Open

Fix CE mode OAuth and preserve raw tool arguments through gateway#454
nathanielosullivanmolloy wants to merge 2 commits intodocker:mainfrom
nathanielosullivanmolloy:fix/ce-mode-oauth-and-argument-forwarding

Conversation

@nathanielosullivanmolloy
Copy link
Copy Markdown

@nathanielosullivanmolloy nathanielosullivanmolloy commented Mar 22, 2026

Summary

Builds on the work from #366 by @Pnkcaht — thanks for the initial investigation and approach.

Fixes issues when running the MCP Gateway without Docker Desktop (CE mode):

  • Raw argument forwarding in handlers: The gateway previously unmarshaled CallToolParamsRaw.Arguments (json.RawMessage) into any before forwarding to tool handlers. This loses type fidelity for tools with structured/typed inputs. Arguments are now forwarded as raw JSON unchanged, keeping the gateway schema-agnostic.

  • Argument type normalization in clientpool: runToolContainer used a single type assertion (map[string]any) which silently dropped arguments arriving as json.RawMessage or []byte. A normalizeArguments function now safely handles all expected representations via type switch.

  • CE mode OAuth redirect URI: When DOCKER_MCP_USE_CE=true, the redirect URI now defaults to http://localhost:5000/callback (local gateway callback) instead of the SaaS endpoint (mcp.docker.com), with override via DOCKER_MCP_OAUTH_REDIRECT_URI.

  • OAuth state parameter validation: ExchangeCode now strips the mcp-gateway:PORT: prefix from the state parameter before validation. BuildAuthorizationURL adds this prefix for proxy routing, but StateManager only stores the base UUID, causing validation to always fail in CE mode.

  • CLI feature checks respect DOCKER_MCP_USE_CE: RunningInDockerCE() and IsRunningInDockerDesktop() hardcoded platform assumptions that blocked all CLI commands (including docker mcp oauth ls/authorize) without Docker Desktop. Both now check DOCKER_MCP_USE_CE=true early to skip Desktop feature probes.

  • CE mode oauth ls: docker mcp oauth ls now has a CE mode path that reads from local DCR credential storage instead of the Docker Desktop auth socket.

Test plan

  • Added 8 unit tests for normalizeArguments covering map[string]any, json.RawMessage, []byte, nil, unexpected types, and invalid JSON
  • Added 2 tests for ExchangeCode state prefix stripping (prefixed and plain states)
  • Added 4 tests for CE mode redirect URI selection (default, CE, CE+custom, non-CE)
  • Added tests for IsRunningInDockerDesktop with DOCKER_MCP_USE_CE, DOCKER_MCP_IN_CONTAINER, and WithNoDockerDesktop context
  • Added tests for RunningInDockerCE with DOCKER_MCP_USE_CE env var
  • Added tests for Manager.ListDCRClients and Manager.HasValidToken
  • All existing tests continue to pass

🤖 Generated with Claude Code

Three fixes for running the MCP Gateway without Docker Desktop (CE mode):

1. **Forward tool arguments as raw JSON** (`handlers.go`):
   The gateway previously unmarshaled `CallToolParamsRaw.Arguments` into
   `any` before forwarding to tool handlers. This loses type fidelity for
   tools that rely on structured/typed inputs. Arguments are now forwarded
   as `json.RawMessage` unchanged, keeping the gateway schema-agnostic.

2. **Normalize argument types in clientpool** (`clientpool.go`):
   `runToolContainer` used a single type assertion (`map[string]any`) which
   silently dropped arguments arriving as `json.RawMessage` or `[]byte`.
   A `normalizeArguments` function now handles all expected argument
   representations safely via type switch.

3. **CE mode OAuth redirect URI and state validation** (`manager.go`):
   - When `DOCKER_MCP_USE_CE=true`, the redirect URI now defaults to the
     local callback (`http://localhost:5000/callback`) instead of the SaaS
     endpoint (`mcp.docker.com`), with override via
     `DOCKER_MCP_OAUTH_REDIRECT_URI`.
   - `ExchangeCode` now strips the `mcp-gateway:PORT:` prefix from the
     state parameter before validation, fixing a mismatch where
     `BuildAuthorizationURL` adds the prefix for proxy routing but
     `StateManager` only stores the base UUID.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nathanielosullivanmolloy nathanielosullivanmolloy requested a review from a team as a code owner March 22, 2026 04:02
RunningInDockerCE() and IsRunningInDockerDesktop() hardcoded platform
assumptions that blocked all CLI commands without Docker Desktop.
Add early DOCKER_MCP_USE_CE=true checks so the PersistentPreRunE gate in
root.go skips the Desktop feature probe when running with non-Desktop
Docker engines. Also add a CE mode path for `docker mcp oauth ls` that
reads from local credential storage instead of the Desktop auth socket.

Co-Authored-By: Claude Opus 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