mcp-data-platform-v1.98.0
Highlights
This release adopts the MCP 2026-07-28 explicit-handle pattern for session identity and fixes the search-first gate for clients that open a new session per tool call. Both are default-on and backward-compatible — no configuration or migration is required to upgrade.
Explicit session handles from platform_info (#792)
The platform's session identity no longer depends on the transport-level Mcp-Session-Id header, which the MCP 2026-07-28 release candidate removes (SEP-2567). Instead, platform_info mints an explicit session_id that the model threads back as an ordinary argument on every subsequent tool call — the pattern the spec now recommends.
platform_infois now the session mint. It returns asession_id(adps_-prefixed, unguessable handle) andsession_expires_at, and its agent instructions tell the model to passsession_idon every following call.- Every tool advertises
session_idon its input schema (exceptplatform_info). The platform validates the handle (must exist, be unexpired, and belong to the same authenticated identity) and strips it before the tool runs, so upstream toolkits (Trino, DataHub, S3, gateway-proxied tools) never see it. platform_infobecomes structurally unskippable — no handle exists until it runs, and gated tools require one. This closes the gap where the init and search-first gates depended on transport session stability.- Deliberate session key for audit and provenance. Every audit row and provenance record for a logical session now shares one intentional
session_idwith a known start event, making session-scoped analysis reliable. - Structured errors an agent can self-correct from:
SESSION_REQUIRED(no handle and no legacy transport session) andSESSION_EXPIRED(unknown, expired, or cross-identity handle), both returned before the handler runs.
Configuration (all default-on; no block needed to enable):
sessions:
handles:
enabled: true # mint, advertise, and validate handles
ttl: 8h # handle lifetime, refreshed on use
require: true # refuse calls with neither a handle nor a legacy transport sessionSet sessions.handles.enabled: false for byte-identical legacy transport-session behavior.
Compatibility. No client is blocked by the new requirement during the deprecation window. require is a presence check, not a stability check: any non-empty transport session satisfies it — including the fresh, per-request Mcp-Session-Id that clients like the claude.ai web connector mint on every call (the same per-call churn addressed for the search-first gate in #791) — as does the stdio sentinel. So a client whose model does not yet thread the handle keeps working exactly as before, with the same per-call session behavior.
What the handle adds on top is a stable session identity for the whole conversation. Because the model threads the returned session_id as a tool argument rather than relying on the transport header, it survives that per-call churn, and it is validated against the authenticated identity (stable across calls) rather than the session — so audit rows, provenance, and gates for one logical session finally share one deliberate key.
Proxied tools that legitimately define their own session_id argument are untouched — only values carrying the dps_ handle prefix are consumed. A new mcp_session_resolution_total{source} metric (explicit / transport / stdio / none) shows migration progress toward explicit handles.
Search-first gate now keyed on the authenticated user (#791)
The search-first hard gate (#787) could refuse trino_query / trino_execute with SEARCH_REQUIRED even after search was called, for MCP clients that open a new session per tool call (notably the claude.ai web connector). The gate keyed its "has performed discovery" signal on the raw MCP session, so search was recorded under one throwaway session and the follow-up query was checked under a different one.
Discovery is now recorded and checked under a user-first scope (PlatformContext.DiscoveryScopeKey): a single search opens the gate for that authenticated user's subsequent per-call sessions. Stdio and stable-session anonymous callers keep the prior per-session behavior. When authentication is disabled (a shared anonymous/noop identity), the gate falls back to the per-session key so one caller's search can't open the gate for everyone.
Read errors fail open (a total store outage allows queries rather than walling off every request); write outages fail closed (discovery does not persist, so the caller stays gated until writes recover — this never bypasses the gate). Operators who must run queries during a store-write outage can set workflow.require_search: false.
Upgrade notes
- No action required. Both changes are default-on and backward-compatible. There is no database migration.
- To opt out of explicit session handles, set
sessions.handles.enabled: false. - To disable the search-first gate entirely, set
workflow.require_search: false.
Changelog
Features
Bug Fixes
- 2c962b5: fix(middleware): scope the search-first gate to the authenticated user, not the raw session (#791) (@cjimti)
Installation
Homebrew (macOS)
brew install txn2/tap/mcp-data-platformClaude Code CLI
claude mcp add mcp-data-platform -- mcp-data-platformDocker
docker pull ghcr.io/txn2/mcp-data-platform:v1.98.0Verification
All release artifacts are signed with Cosign. Verify with:
cosign verify-blob --bundle mcp-data-platform_1.98.0_linux_amd64.tar.gz.sigstore.json \
mcp-data-platform_1.98.0_linux_amd64.tar.gz