Skip to content

Releases: txn2/mcp-data-platform

mcp-data-platform-v0.37.6

09 Mar 17:40
23f7c17

Choose a tag to compare

What's New

Bug Fixes

Portal logo now renders in sandboxed MCP app iframes (#211)

  • When portal.logo is a URL, the server now fetches the SVG content at startup and injects it inline as logo_svg
  • Previously, the sandboxed iframe blocked external image requests, showing the default icon instead of the configured logo
  • Deployments with explicit logo_svg in config are unaffected

Asset card titles no longer overlap share icons (#212)

  • Long asset names are now properly truncated before the share/public-link icons
  • Added min-w-0 to fix flex container truncation and pr-12 padding to clear icon positions

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:v0.37.6

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.37.6_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.37.6_linux_amd64.tar.gz

mcp-data-platform-v0.37.2

09 Mar 06:44
7bc3d00

Choose a tag to compare

What's Changed

Two bug fixes from #209: admin tool call authentication and asset viewer rendering.

Bug Fixes

Admin tool calls fail with "invalid API key" on browser sessions

Admin tool calls (Tools > Explore) were failing with "authentication failed: invalid API key" when using browser session auth. connectInternalSession was re-extracting the raw OIDC id_token from the session cookie and forcing it through the full MCP auth chain (OAuth JWT → OIDC → API Key). The OIDC authenticator could reject the token (e.g. expired id_token, JWKS cache stale), but ChainedAuthenticator only reports the last error — the unhelpful "invalid API key" from the API key authenticator.

Fix: connectInternalSession now calls BrowserAuth.AuthenticateHTTP(r) to get the already-validated UserInfo and passes it via WithPreAuthenticatedUser(). The MCP auth middleware checks for a pre-authenticated user before running the auth chain, skipping token validation while preserving the full authorization check (persona/role-based tool filtering).

Also adds per-authenticator slog.Debug logging to ChainedAuthenticator for diagnosability — previously only the last error was kept.

Files: pkg/admin/tools.go, pkg/middleware/mcp.go, pkg/middleware/context.go, pkg/auth/middleware.go

Asset viewer "No component found" flash on first render

The asset viewer showed a brief "No component found" error when loading JSX/TSX assets. editedContent initialized as "" while contentStr had the loaded content, so hasChanges evaluated true on first render, passing empty content to ContentRendererJsxRenderer.

Fix: Added a dirty state flag that is only set true when the user actually edits in the SourceEditor. hasChanges now requires dirty && editedContent !== contentStr, preventing the false-positive on initial render.

Files: ui/src/components/AssetViewer.tsx

Test Coverage

  • TestPreAuthenticatedUserContext — round-trip and nil-context for new context helpers
  • TestMCPToolCallMiddleware_PreAuthenticatedUser — pre-auth user bypasses auth chain, populates PlatformContext correctly
  • TestMCPToolCallMiddleware_PreAuthenticatedUser_AuthzDenied — pre-auth user still goes through authorization; denied users get error result

Stats

  • 7 files changed, 186 additions, 17 deletions

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:v0.37.2

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.37.2_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.37.2_linux_amd64.tar.gz

mcp-data-platform-v0.37.1

09 Mar 05:44
a6fee12

Choose a tag to compare

What's Changed

In-browser source editing for portal assets, plus admin assets search and owner visibility improvements (#208).

New Feature

Source editor in asset viewer

Users and admins can now view and edit the raw source of text-based assets (HTML, JSX, Markdown, SVG, plain text) directly in the browser. A Preview/Source tab toggle appears automatically for text-based content types, with an integrated code editor and Save button.

Editor capabilities:

  • CodeMirror 6 with language-aware syntax highlighting (JSX, HTML, Markdown, XML/SVG)
  • Lazy-loaded via React.lazy() to keep the main bundle small (~200KB gzip addition)
  • Dark mode support — detects theme from the document root class
  • Unsaved edits survive tab switches — switching between Preview and Source preserves your changes
  • Live preview — unsaved edits render in Preview mode before saving

New API endpoints (2):

Method Path Auth Description
PUT /api/v1/admin/assets/{id}/content Admin Replace asset S3 content
PUT /api/v1/portal/assets/{id}/content Owner only Replace asset S3 content

Both endpoints read raw request body via io.LimitReader (10 MB cap), upload to S3 at the existing bucket/key, and update size_bytes in the database.

Error handling:

Status Condition
401 No authenticated user (portal only)
403 Non-owner attempting update (portal only)
404 Asset not found
410 Asset has been soft-deleted
413 Content exceeds 10 MB
503 S3 not configured or S3 upload failure
500 Database update failure

Frontend components:

  • SourceEditor.tsx — new CodeMirror wrapper with automatic language detection
  • AssetViewer.tsx — new shared component extracted from both viewer pages, with Preview/Source tabs, Save button with status feedback, download, share, delete confirmation modal, and metadata sidebar
  • useUpdateAssetContent() and useAdminUpdateAssetContent() — new mutation hooks

Files: pkg/admin/assets.go, pkg/portal/handler.go, pkg/portal/types.go, ui/src/components/SourceEditor.tsx, ui/src/components/AssetViewer.tsx, ui/src/api/portal/hooks.ts, ui/src/api/admin/hooks.ts, ui/src/pages/viewer/AssetViewerPage.tsx, ui/src/pages/viewer/AdminAssetViewerPage.tsx

Improvements

Admin assets: unified search

The admin assets list endpoint replaces individual owner_id, content_type, and tag query params with a single search parameter. The search queries across name, description, owner email, and tags with server-side ILIKE filtering. The frontend search input is debounced (300ms).

Files: pkg/portal/store.go, ui/src/pages/assets/AdminAssetsPage.tsx, ui/src/api/admin/hooks.ts

Owner email on assets

A new owner_email column on portal_assets stores the authenticated user's email at asset creation time. This is displayed in the admin assets table and asset viewer instead of the opaque owner_id, improving admin visibility into who created each asset.

Migration: 000017_portal_assets_owner_email — adds owner_email TEXT NOT NULL DEFAULT ''

Files: pkg/portal/types.go, pkg/portal/store.go, pkg/toolkits/portal/toolkit.go, ui/src/api/portal/types.ts, ui/src/mocks/data/assets.ts

Viewer page refactor

Both AssetViewerPage and AdminAssetViewerPage were refactored from ~220 lines each down to ~30 lines by extracting the shared AssetViewer component. This eliminates duplicated viewer logic (sidebar, editing, delete modal, download, share dialog) and makes both viewers consistent.

Dependencies

  • @uiw/react-codemirror ^4.25.8 — React wrapper for CodeMirror 6
  • @codemirror/lang-html ^6.4.11
  • @codemirror/lang-javascript ^6.2.5
  • @codemirror/lang-markdown ^6.5.0
  • @codemirror/lang-xml ^6.1.0
  • @tailwindcss/typography ^0.5.19

Test Coverage

  • Admin handler (7 new tests): content update success, no S3, not found, soft-deleted asset, oversized content (413), S3 error, DB update error
  • Portal handler (9 new tests): content update success, no user, not found, deleted, not owner, oversized content (413), nil S3, S3 error, DB update error
  • Store (1 new test): applyAssetFilter with search parameter
  • Toolkit (1 new test): resolveOwnerEmail context extraction
  • Coverage: updateAdminAssetContent 92.3%, updateAssetContent 93.9%

CI

  • Bump docker/login-action from 3.7.0 to 4.0.0 (#204)

Stats

  • 27 files changed, 1,595 additions, 527 deletions (net -390 lines from viewer refactor)

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:v0.37.1

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.37.1_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.37.1_linux_amd64.tar.gz

mcp-data-platform-v0.37.0

08 Mar 23:16
ba9f4cd

Choose a tag to compare

What's Changed

Three improvements spanning OIDC auth, portal UX, and admin capabilities (#203).

Bug Fix

OIDC logout redirect

Keycloak (and many OIDC providers) rejects relative post_logout_redirect_uri values, causing a "Invalid redirect uri" error when users clicked Sign Out. The logout handler now sends an absolute URL constructed from PublicBaseURL, matching how the login callback already works.

A new PostLogoutRedirect field on FlowConfig separates the OIDC post-logout URI from the general PostLoginRedirect. When PostLogoutRedirect is empty, it falls back to PostLoginRedirect for backward compatibility.

Files: pkg/browsersession/oidcflow.go, pkg/platform/platform.go

New Features

Asset sharing indicators on My Assets

My Assets cards now display sharing status at a glance:

  • Users icon — asset is shared with one or more specific users
  • Globe icon — asset has an active public link

Sharing status is fetched via a new batch ListActiveShareSummaries query that uses BOOL_OR aggregation grouped by asset_id, avoiding N+1 lookups regardless of how many assets are on the page.

Files: pkg/portal/types.go, pkg/portal/store.go, pkg/portal/handler.go, ui/src/pages/assets/MyAssetsPage.tsx, ui/src/api/portal/types.ts

Admin assets management

Admins can now browse, inspect, edit, and delete any platform asset regardless of owner. This provides full visibility into all user-created assets from the admin interface.

API endpoints (5 new routes):

Method Path Description
GET /api/v1/admin/assets List all assets with filters (owner, content type, tag) and pagination
GET /api/v1/admin/assets/{id} Get asset metadata
GET /api/v1/admin/assets/{id}/content Retrieve asset content from S3
PUT /api/v1/admin/assets/{id} Update asset name, description, or tags
DELETE /api/v1/admin/assets/{id} Soft-delete an asset

All endpoints are protected by the admin auth middleware. The list endpoint includes share summaries for each asset, so admins can see sharing status in the table view.

UI pages (2 new):

  • Admin Assets page — table view with content type icons, owner column, sharing indicators (Users/Globe), and size/date columns. Accessible from the new "Assets" sidebar item under Admin.
  • Admin Asset Viewer — full asset viewer with content rendering, metadata sidebar (edit/delete), owner badge, and provenance panel.

Files: pkg/admin/assets.go, pkg/admin/handler.go, cmd/mcp-data-platform/main.go, ui/src/pages/assets/AdminAssetsPage.tsx, ui/src/pages/viewer/AdminAssetViewerPage.tsx, ui/src/api/admin/hooks.ts, ui/src/api/admin/types.ts, ui/src/components/layout/Sidebar.tsx, ui/src/components/layout/AppShell.tsx

Test Coverage

  • 3 new OIDC logout tests — PostLogoutRedirect used in redirect URL, default fallback to PostLoginRedirect, no-end-session fallback
  • 17 new admin asset tests — route registration, list/get/content/update/delete success and error paths, validation, nil share store
  • 5 new store tests — ListActiveShareSummaries postgres implementation (success, empty input, query error, scan error, row iteration error)
  • 1 new portal handler test — listAssets includes share_summaries in response

Stats

  • 20 files changed, 1,613 additions, 20 deletions

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:v0.37.0

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.37.0_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.37.0_linux_amd64.tar.gz

mcp-data-platform-v0.36.2

08 Mar 20:22
2cc3d66

Choose a tag to compare

What's Changed

Five post-v0.36.0 fixes for the portal and admin UI (#202).

Bug Fixes

Admin UI: OIDC authentication for Tools Explore

When an admin logged in via OIDC (browser session cookie), the Tools > Explore tab failed with "no API key found in context" because the internal MCP session only extracted tokens from X-API-Key / Authorization headers. The cookie-based OIDC flow never set those headers, so the MCP auth middleware rejected every tool call.

connectInternalSession now falls back to extracting the id_token stored in the HMAC-signed session cookie via BrowserAuth.ExtractIDToken(), which flows through the MCP ChainedAuthenticator normally.

Files: pkg/admin/tools.go, pkg/admin/handler.go, pkg/browsersession/authenticator.go, cmd/mcp-data-platform/main.go

Portal: My Knowledge page showing "PROD" instead of table names

Entity URN tags displayed the environment suffix (e.g., PROD) instead of the actual table name. The old inline parsing urn.split(",").pop() extracted the last comma-separated segment which is the environment, not the name.

A new shared formatEntityUrn() utility correctly parses urn:li:dataset:(urn:li:dataPlatform:trino,catalog.schema.table,PROD) into catalog.schema.table. Full URN is visible on hover via title attribute.

Files: ui/src/lib/formatEntityUrn.ts, ui/src/pages/knowledge/MyKnowledgePage.tsx

Admin UI: Audit Log tool names displayed as raw snake_case

The Overview tab's Top Tools bar chart and Recent Errors list displayed raw tool names like trino_query instead of human-readable titles. Added useToolTitleMap() to the OverviewTab component and passed the title mapping to both BreakdownBarChart (labelMap) and RecentErrorsList (titleMap).

Files: ui/src/pages/audit/AuditLogPage.tsx, ui/src/components/RecentErrorsList.tsx

Portal: Sidebar label consistency

Renamed sidebar label from "Activity" to "My Activity" for consistency with "My Assets" and "My Knowledge".

Files: ui/src/components/layout/Sidebar.tsx

Test Coverage

  • 4 new tests for ExtractIDToken — valid cookie, no cookie, no id_token in session, expired cookie
  • 3 new tests for cookie fallback in connectInternalSession — fallback works, header preferred over cookie, nil BrowserAuth

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:v0.36.2

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.36.2_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.36.2_linux_amd64.tar.gz

mcp-data-platform-v0.36.1

08 Mar 19:34
d5a1cee

Choose a tag to compare

Fix: Zero-Fill Timeseries Chart Gaps for Sparse Activity Data (#201)

Activity timeseries charts (admin dashboard and portal user activity) collapsed to just the data points when usage was sparse, losing all temporal context on the X-axis. For example, 2 tool calls in a 24-hour window produced a chart with only 2 points instead of a full 24-hour timeline.

Root Cause

The Timeseries() SQL query uses GROUP BY date_trunc(resolution, timestamp), which only returns buckets that contain data. With sparse usage, the chart rendered a compressed line between the few populated points with no sense of scale.

Fix

Added a Go-side ZeroFill helper that expands sparse SQL results into a complete series covering [start, end] at the requested resolution. Missing buckets are filled with zero values.

Before: 2 events in a 24h window → chart with 2 points, no time scale
After: 2 events in a 24h window → chart with 24 hourly buckets, two visible spikes against a zero baseline

Why Go-side instead of SQL generate_series

  • Keeps the existing squirrel-based SQL builder unchanged (lower risk)
  • Pure Go logic is trivially testable with table-driven tests
  • Not PostgreSQL-specific — works with any future store implementation

Frontend: Sparse Data Dots

When there are 10 or fewer non-zero data points, dots (r: 3) are shown on the success and error lines so sparse spikes are visible against the zero baseline.

Files Changed

File Change
pkg/audit/zerofill.go New: ZeroFill, resolutionInterval, truncateTime helpers
pkg/audit/zerofill_test.go New: 8 table-driven cases + data preservation, invalid resolution, helper unit tests
pkg/audit/postgres/metrics.go Call audit.ZeroFill() after SQL query
pkg/audit/postgres/metrics_test.go Updated 3 tests to use fixed times and verify zero-filled output
ui/src/components/charts/TimeseriesChart.tsx Conditional dots on sparse data

Total: 5 files changed, 317 insertions, 21 deletions


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:v0.36.1

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.36.1_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.36.1_linux_amd64.tar.gz

mcp-data-platform-v0.36.0

08 Mar 06:32
e18eab9

Choose a tag to compare

Portal UX Enhancements — User Activity, Knowledge, Tool Titles, Help Rewrite (#200)

This release adds two new user-facing portal sections (Activity and My Knowledge), surfaces human-readable tool display names across the entire UI, fixes a sidebar navigation bug, and rewrites all admin help content for non-technical users.


New: User Activity Page

Portal users now have a personal Activity dashboard at /portal/activity showing their own usage metrics:

  • Summary cards — Total Calls, Avg Duration, Tools Used
  • Activity Timeline — Interactive time-series chart of tool calls over time (reuses the admin TimeseriesChart component)
  • Top Tools — Horizontal bar chart showing most-used tools with human-readable names (reuses BreakdownBarChart)
  • Time range selector — 1h, 6h, 24h, 7d presets

Design decision: Success Rate is intentionally excluded from the user view. In AI-assisted workflows, "errors" are typically the agent self-correcting — trying a table name, getting a not-found, then adjusting. This is normal agent behavior, not something users should worry about. Success rate remains available in the admin dashboard where it's useful for platform tuning.

Backend

New portal endpoints auto-filtered to the authenticated user's user_id:

Endpoint Description
GET /api/v1/portal/activity/overview Aggregate stats (total calls, avg duration, unique tools)
GET /api/v1/portal/activity/timeseries Time-bucketed call counts with resolution parameter
GET /api/v1/portal/activity/breakdown Top tools/connections grouped by dimension

All three accept start_time, end_time query parameters (RFC 3339). The timeseries endpoint also accepts resolution (minute, hour, day) and the breakdown endpoint accepts group_by and limit.

Implementation: Added UserID string field to audit.TimeseriesFilter, audit.BreakdownFilter, and a new audit.MetricsFilter struct (replacing the previous startTime, endTime *time.Time parameters on Overview() and Performance()). The PostgreSQL metrics queries add WHERE user_id = $N when UserID is set. This is a breaking change to the AuditMetricsQuerier interface — all callers updated.


New: My Knowledge Page

Users whose persona includes the capture_insight tool now see a My Knowledge section in the portal sidebar, showing their own captured insights:

  • Summary cards — Total Insights, Pending, Approved, Applied
  • Status filter buttons — All, Pending, Approved, Applied, Rejected
  • Insights list — Each insight shows status badge, category label, insight text, entity URN chips, review notes, and creation date
  • Pagination — 20 items per page with previous/next navigation
  • Conditional visibility — The sidebar item only appears when the user's resolved persona includes capture_insight in its tool list

Backend

Endpoint Description
GET /api/v1/portal/knowledge/insights List user's insights (filtered by captured_by = user_id)
GET /api/v1/portal/knowledge/insights/stats Insight counts by status, category, confidence

Both endpoints use the existing knowledge.InsightStore.List() and Stats() methods with CapturedBy pre-set to the authenticated user.

Persona & Tools in /me Response

The GET /api/v1/portal/me endpoint now returns two additional fields:

{
  "user_id": "sarah.chen@acme-corp.com",
  "roles": ["analyst"],
  "is_admin": false,
  "persona": "data-analyst",
  "tools": ["trino_query", "datahub_search", "capture_insight", "..."]
}

The tools list is resolved by running the persona's Allow/Deny patterns against the full toolkit registry, giving the frontend the exact set of tools available to the user. This enables conditional UI rendering without additional API calls.

New types: PersonaResolver func(roles []string) *PersonaInfo and PersonaInfo{Name, Tools} in the portal package. The resolver is built from the persona and toolkit registries during platform initialization.


New: Tool Display Names

Tools are now displayed with human-readable titles throughout the UI instead of raw snake_case identifiers (e.g., "Execute SQL Query" instead of trino_query).

Backend

Every tool registered by the upstream toolkits already has a Title field set:

Toolkit Example Titles
Trino Execute SQL Query, Execute SQL (Write), Explain Query Plan, Describe Table, Browse Catalog
DataHub Search Catalog, Get Entity, Get Schema, Get Lineage, Get Queries
S3 List Buckets, List Objects, Get Object, Generate Presigned URL
Knowledge Capture Insight, Apply Knowledge
Portal Save Artifact, Manage Artifact

The Title field is now included in two admin API responses:

  • GET /api/v1/admin/toolstitle field on each toolInfo object
  • GET /api/v1/admin/tools/schemastitle field on each toolSchema object

For the tools list endpoint, buildToolTitleMap() calls session.ListTools() internally to resolve titles from the MCP server.

Frontend

New utility formatToolName(name, title?) — uses the backend-provided title when available, falls back to converting snake_case to Title Case.

Applied across all UI surfaces where tool names appear:

Page What changed
Tools (inventory table) Tool names show titles
Tools (tool selector) Dropdown shows titles
Tools (explore tab) Schema names show titles
Audit Log (events table) tool_name column shows titles
Dashboard (top tools chart) Bar chart labels show titles
Activity (top tools chart) Bar chart labels show titles via labelMap prop
ProvenancePanel Unified with formatToolName, removed hardcoded mapping

The BreakdownBarChart component now accepts an optional labelMap prop (Record<string, string>) for mapping raw dimension values to display labels.


Fix: Sidebar Dashboard Highlight Bug

Bug: When navigating from Dashboard to another admin section (e.g., Tools), Dashboard remained highlighted alongside the actual active section.

Root cause: The isActive() function in Sidebar.tsx matched both exact path AND prefix for admin routes. So /admin/tools matched /admin via route.startsWith("/admin" + "/"), causing Dashboard to always appear active.

Fix: /admin now uses exact match only, consistent with / and /shared.


Rewritten: Admin Help Sections

All five admin help tabs have been rewritten for non-technical administrators:

Page Lines changed
Dashboard (Home) Simplified from developer reference to user-oriented overview
Tools Removed YAML config examples, API endpoint docs
Audit Log Focused on "what you can learn" not "how it's stored"
Knowledge Explained the insight lifecycle in plain language
Personas Removed config file references, explained role mapping simply

Guidelines applied:

  • No references to YAML, configuration files, config_mode, DSN, or PostgreSQL
  • No admin API endpoint documentation (admins are not developers)
  • Replaced "injection" with "enrichment" (2 instances)
  • Focus on what it does for you, not how it's configured
  • Plain language, short paragraphs, practical examples

Improved: Onboarding Empty States

My Assets (no assets yet):

Assets are interactive dashboards, visualizations, and documents created during your conversations. Try asking your assistant to "create an interactive dashboard" or say "save this as an asset" to get started.

My Knowledge (no insights yet):

When you share knowledge about your data — corrections, business context, or quality observations — it gets captured here for review. Try telling your assistant something like "the revenue column excludes returns" or "this table is refreshed weekly". Approved insights improve the data catalog for everyone.


Portal Wiring

New optional dependencies on the portal handler, all nil-safe:

Dependency Source Purpose
AuditMetrics platform.AuditStore() User-scoped activity metrics
InsightStore platform.KnowledgeInsightStore() User-scoped insight listing
PersonaResolver persona.Registry + registry.Registry Resolve roles → persona + tools

Extracted wirePortalOptionalDeps() and buildPersonaResolver() helper functions from mountPortalAPI() to stay under the cognitive complexity limit (gocognit ≤ 15).


Files Changed

Area Files Delta
Backend wiring cmd/mcp-data-platform/main.go +38
Admin API pkg/admin/system.go, tools.go, handler.go, audit_metrics.go +59
Audit metrics pkg/audit/metrics.go, postgres/metrics.go +47
Portal API pkg/portal/handler.go +239
Portal tests pkg/portal/handler_test.go +417
Metrics tests pkg/audit/postgres/metrics_test.go +125
Swagger docs internal/apidocs/ +20
Frontend types & hooks ui/src/api/ +186
New pages ActivityPage.tsx, MyKnowledgePage.tsx +334
Layout & nav Sidebar.tsx, AppShell.tsx +23
Tool formatting formatToolName.ts, BarChart.tsx, ProvenancePanel.tsx +72
Help rewrites 5 admin page files -730
Mock data ui/src/mocks/handlers.ts +95
Auth store ui/src/stores/auth.ts +2

Total: 34 files changed, 1,810 insertions, 1,010 deletions


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:v0.36.0

Verification

All release artifacts are signed with Cosign. Verify with:

cosign ...
Read more

mcp-data-platform-v0.35.10

08 Mar 03:21
519973a

Choose a tag to compare

Bug Fixes

JSX public viewer: fix broken component rendering (#199)

JSX public view links (/portal/view/{token}) were completely broken — the browser threw TypeError: Failed to fetch dynamically imported module and the component never rendered.

Root cause: Per the CSP3 spec, srcdoc iframes inherit the parent page's CSP headers. The effective CSP is the intersection of the parent's CSP header and the iframe's own <meta> CSP. The parent's publicCSP() was far more restrictive than the iframe's meta CSP, so the intersection blocked:

Directive What was blocked
script-src esm.sh module loading (Sucrase, React), eval (Sucrase transform), blob: (dynamic import of transformed code)
style-src Google Fonts CSS
connect-src fetch() to esm.sh
font-src Google Fonts files

Fix: Aligned the parent page's CSP with the iframe's meta CSP so the intersection no longer strips required permissions. Also added blob: to script-src in the iframe meta CSP — the public viewer wraps Sucrase-transformed JSX in a Blob and runs await import(blobUrl), which requires blob: in script-src.

Security note: The expanded CSP (unsafe-eval, unsafe-inline, blob:) is scoped only to the JSX content type branch and applies to a sandboxed iframe (sandbox="allow-scripts" without allow-same-origin), so the iframe cannot access parent-page cookies, storage, or origin.

Files changed

  • pkg/portal/public.go — expanded publicCSP() JSX branch; added blob: to iframe meta CSP
  • pkg/portal/public_test.go — updated TestPublicCSP and TestJsxIframe to verify all CSP directives

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:v0.35.10

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.35.10_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.35.10_linux_amd64.tar.gz

mcp-data-platform-v0.35.9

08 Mar 02:32
4a5111b

Choose a tag to compare

What's New

Four portal UX improvements plus hardening fixes for share-by-email.

Public JSX Rendering

Shared JSX assets now render as live React components instead of raw source code. The public viewer generates a sandboxed iframe with a full client-side React runtime:

  • Import maps for React 19, Recharts, and Lucide (matching the authenticated portal)
  • Sucrase transpilation loaded from esm.sh for JSX-to-JS conversion
  • Automatic component detection (exported default, then PascalCase declarations)
  • Auto-mounting via createRoot().render() unless the source contains its own mount call
  • Error display for transpilation and runtime failures
  • Content-type-aware CSP: JSX content gets frame-src blob: data: while other types use the default strict policy
  • CodeQL-safe injection via html/template + json.Marshal + template.JS

Session Expiration Handling

API clients now detect 401 responses globally and display a "session expired" banner:

  • Both apiFetch and apiFetchRaw call expireSession() on 401
  • Auth state is cleared and sessionExpired flag is set
  • Login form shows an amber "Your session has expired" banner
  • React Query retry function skips 401s (no retry loops)
  • Flag resets on successful re-login

Share by Email

Users can share assets by email address instead of opaque user IDs:

  • New shared_with_email column on portal_shares (migration 016)
  • Partial index on non-null email values for query performance
  • Email is validated (format check, 254-char RFC 5321 limit) and normalized to lowercase on write
  • Case-insensitive matching on read via strings.EqualFold (Go) and LOWER() (SQL)
  • "Shared With Me" queries match on both user ID (backward compat) and email
  • Access checks (isSharedWithUser) also check both paths

Share Dialog Polish

  • Active shares show "Public Link" labels (not truncated tokens)
  • Time remaining until expiration displayed (days, hours, or minutes)
  • Sub-hour display fixed: shows "Expires in 23m" instead of "Expires in 0h"
  • "Copy Link" text button with clipboard fallback for non-HTTPS contexts
  • Email input field for sharing with users

Help Section

  • Help tab heading and description now use the configured portal title via useBranding() instead of hardcoded "MCP Data Platform"

Migration

This release includes migration 016 which adds a nullable shared_with_email TEXT column to portal_shares with a partial index. The migration is backward-compatible -- existing shares by user ID continue to work.

Changelog

  • feat: portal UX enhancements -- JSX public links, session expiry, share-by-email (#198) @cjimti
  • fix: resolve CodeQL unsafe-quoting in JSX public viewer @cjimti
  • fix: harden share-by-email with validation, case normalization, and UX fixes @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:v0.35.9

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.35.9_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.35.9_linux_amd64.tar.gz

mcp-data-platform-v0.35.8

07 Mar 23:29
42f0572

Choose a tag to compare

Highlights

Consolidates portal/admin configuration into a single-responsibility layout.

Breaking: Portal/Admin Config Consolidation (#197)

Branding fields have moved from the admin: block to portal:. This is a clean break — old keys silently stop working.

Before:

portal:
  enabled: true
  ui: true

admin:
  enabled: true
  portal: true
  portal_title: "My Platform"
  portal_logo: "https://..."

After:

portal:
  enabled: true
  title: "My Platform"
  logo: "https://..."
  logo_light: "https://..."
  logo_dark: "https://..."

admin:
  enabled: true
  persona: admin
  path_prefix: /api/v1/admin

Migration checklist:

  • Move admin.portal_title to portal.title (new default: "MCP Data Platform")
  • Move admin.portal_logo to portal.logo
  • Move admin.portal_logo_light / admin.portal_logo_dark to portal.logo_light / portal.logo_dark
  • Remove admin.portal (no longer used)
  • Remove portal.ui (replaced by portal.enabled as the single gate)

The JSON API response from /api/v1/admin/system/info and /api/v1/admin/public/branding is unchanged — no frontend changes needed.

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:v0.35.8

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.35.8_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.35.8_linux_amd64.tar.gz

Changelog

Others

  • 42f0572: refactor: consolidate portal/admin config and templatize platform name (#197) (@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:v0.35.8

Verification

All release artifacts are signed with Cosign. Verify with:

cosign verify-blob --bundle mcp-data-platform_0.35.8_linux_amd64.tar.gz.sigstore.json \
  mcp-data-platform_0.35.8_linux_amd64.tar.gz