Skip to content

mcp-data-platform-v1.61.3

Choose a tag to compare

@github-actions github-actions released this 14 May 07:43
· 121 commits to main since this release
e72de14

Highlights

This release fixes a long-standing OAuth refresh-token loss bug in the gateway toolkits and adds a second authentication slot for upstream APIs that require it.

Fix: stale refresh-token cache caused invalid_grant revocation (#404)

The MCP and API gateway toolkits each held their own in-memory cache of the OAuth refresh token. The background refresher in connoauth.Refresher rotated the persisted refresh token every few minutes, but the in-toolkit cache never re-read it. When a tool call later forced a refresh through the in-toolkit path, it sent the stale refresh token to the IdP — which treats stale-RT use as token replay, revokes the entire RT family, returns invalid_grant, and forces the operator to re-Connect.

Both toolkits now build an ephemeral connoauth.Source per outbound request from the unified store. There is no in-memory RT cache to drift. The client_credentials path keeps a mutex-guarded in-memory access-token cache (cc has no rotation contract, so caching is correct there).

Net effect: roughly 5,000 lines of duplicated per-kind OAuth state-machine code deleted; one shared connoauth.Source implementation across both gateway kinds.

Related changes:

  • OAuthConfig.EndpointAuthStyle (basic / params) so operators can pick HTTP Basic vs form-body at the token endpoint. Defaulted to HTTP Basic broke IdPs that only accept form-body; this knob makes parity with apigateway's oauth2_endpoint_auth_style.
  • ctx now threaded through admin Status calls so client disconnect cancels the underlying DB read.
  • Migration 000041 drops the now-orphaned gateway_oauth_tokens and apigateway_oauth_tokens tables; 000039 already moved every row to connection_oauth_tokens.

Feature: static_headers for APIs that need a second auth header (#403)

Some REST upstreams require both an OAuth/Bearer Authorization header and a separate per-call header (e.g. a vendor-specific subscription key, Google's x-goog-user-project, and similar). The apigateway toolkit's auth_mode is a single value, so a connection could carry one or the other, not both. static_headers is the second slot.

Values in static_headers are operator-supplied, AES-256-GCM encrypted at rest with the same FieldEncryptor that protects credential and client_secret, applied to every outbound request, and unreachable to the model. Header precedence on the wire (later wins): model-supplied per-call headers -> static_headers -> auth_mode contribution. The model is blocked at request-validation time from supplying any header name that collides with static_headers.

Validation rejects:

  • Authorization (use auth_mode)
  • The API-key header when auth_mode: api_key with api_key_placement: header
  • Hop-by-hop / net/http-managed names (Host, Content-Length, Connection, etc.)
  • Header names that violate RFC 7230 token characters
  • CRLF / NUL in values (header-smuggling defense)

The portal kind: api connection form has a new sensitive key/value editor that masks existing values and supports add/delete without inline edit — same pattern as credential / client_secret.

See docs/server/api-gateway.md for walkthroughs covering common upstream auth patterns.

Changelog

Features

  • b60953a: feat(apigateway): add static_headers for APIs needing a second auth header (#403) (@cjimti)

Refactor

  • e72de14: refactor(gateway): unify OAuth on connoauth.Source, fix stale-RT cache bug (#404) (@cjimti)

Installation

Homebrew (macOS)

brew install txn2/tap/mcp-data-platform

Claude Code CLI

claude mcp add mcp-data-platform -- mcp-data-platform

Docker

docker pull ghcr.io/txn2/mcp-data-platform:v1.61.3

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_1.61.3_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_1.61.3_linux_amd64.tar.gz