Skip to content

Releases: txn2/mcp-data-platform

mcp-data-platform-v1.39.3

11 Mar 22:06
06e591e

Choose a tag to compare

Shared Content Renderer with Single CSS Build

This release unifies how the public content viewer renders all content types. Instead of server-side rendering with separate Go libraries, the public viewer now uses the same React components and Tailwind CSS as the authenticated portal — eliminating an entire class of styling bugs caused by divergent Tailwind builds.

Highlights

Unified client-side rendering — The public viewer now renders markdown, SVG, JSX, HTML, and plain text using the same ContentRenderer React component as the internal portal. Server-side rendering via goldmark and bluemonday has been removed entirely. Content is passed as JSON to an embedded IIFE bundle that hydrates client-side.

Single CSS build — Previously, the content viewer had its own @import "tailwindcss" entry point, producing a second CSS build with different prose styles. Now the Makefile builds the SPA first, then copies its CSS output as content-viewer.css. The IIFE Vite config (vite.content-viewer.config.ts) produces JS only.

Dark mode fix — Added @custom-variant dark (&:where(.dark, .dark *)) to index.css so Tailwind's dark: variants key off the .dark class instead of @media(prefers-color-scheme:dark). This fixes white-on-white markdown text when the OS is in dark mode but the page is toggled to light.

What Changed

Content rendering (pkg/portal/public.go):

  • Replaced renderContent(), renderMarkdown(), sanitizeSVG(), jsxIframe(), sandboxedIframe(), blobIframe() with a single JSON payload passed to the client-side content viewer bundle
  • Unified publicCSP() to a single policy for all content types (client-side rendering makes per-type CSP unnecessary)
  • Removed goldmark and bluemonday Go dependencies (-4 direct deps, -8 transitive deps from go.sum)

Public viewer template (pkg/portal/templates/public_viewer.html):

  • Added shadcn HSL CSS variables (--background, --foreground, --card, --muted, --border, --primary, etc.) for light and dark modes so the SPA CSS resolves colors correctly
  • Renamed page shell --border to --page-border to avoid collision with the shadcn HSL --border triplet
  • Added .dark class toggle alongside data-theme attribute for Tailwind compatibility

New: content viewer embed package (internal/contentviewer/):

  • embed.go — Go embed for JS + CSS bundles with loadBundles() for testability
  • Gracefully handles missing bundles (empty strings when dist only has .gitkeep)

New: content viewer entry point (ui/src/content-viewer-entry.tsx):

  • Reads content from embedded <script type="application/json"> data element
  • Renders via the shared ContentRenderer component
  • Includes a MutationObserver as a defensive fallback for data-theme.dark class bridging

New: Vite IIFE build config (ui/vite.content-viewer.config.ts):

  • Builds content-viewer-entry.tsx as an IIFE bundle (JS only, no CSS)
  • Output goes to ui/dist-content-viewer/

New: dev preview server (cmd/preview-content-viewer/main.go):

  • Standalone HTTP server at localhost:9090 for testing the content viewer
  • Sample content for all 5 content types (markdown, SVG, JSX, HTML, plain text)
  • Light/dark theme toggle with theme persistence

Build system (Makefile):

  • New frontend-build-content-viewer target for standalone JS bundle builds
  • frontend-build now builds SPA first, then content viewer JS, then copies SPA CSS
  • Resilient CSS file discovery using find instead of fragile ls index-*.css glob
  • clean and embed-clean targets updated for the new internal/contentviewer/dist/ directory

Dev environment (dev/):

  • Added SeaweedFS S3-compatible object store to docker-compose for local portal testing
  • Pinned SeaweedFS image to 3.88@sha256:98e034...
  • Added portal config to dev/platform.yaml with S3 connection
  • Added dev/seaweedfs-s3.json for SeaweedFS S3 credentials

Security Notes

  • SVG content is now sanitized client-side via DOMPurify (SVG profile) instead of server-side bluemonday
  • HTML content continues to render in sandboxed <iframe> via blob: URL (sandbox="allow-scripts")
  • Markdown uses react-markdown (no dangerouslySetInnerHTML), safe by default
  • Content JSON injection uses json.Marshal which escapes <, >, & as \uXXXX, preventing </script> breakout

Files Changed

18 files changed, 682 additions, 476 deletions

File Change
pkg/portal/public.go -216 lines: removed 6 server-side rendering functions
pkg/portal/public_test.go Replaced render-specific tests with unified template tests
internal/contentviewer/embed.go New: Go embed package for JS/CSS bundles
internal/contentviewer/embed_test.go New: tests with fstest.MapFS for full coverage
cmd/preview-content-viewer/main.go New: dev preview server
cmd/preview-content-viewer/main_test.go New: table-driven handler tests
ui/src/content-viewer-entry.tsx New: React IIFE entry point
ui/vite.content-viewer.config.ts New: Vite IIFE build config
ui/src/index.css @custom-variant dark for class-based dark mode
pkg/portal/templates/public_viewer.html HSL variables, .dark class bridge
Makefile Content viewer build targets, resilient CSS glob
go.mod / go.sum Removed goldmark, bluemonday, and transitive deps
dev/docker-compose.yml Added pinned SeaweedFS service
dev/platform.yaml Portal + S3 config for local dev
dev/seaweedfs-s3.json New: SeaweedFS S3 credentials

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.39.3

Verification

All release artifacts are signed with Cosign. Verify with:

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

mcp-data-platform-v1.39.2

11 Mar 16:23
6ce571d

Choose a tag to compare

Public Viewer Layout and Share Dialog Fixes

The public viewer (/portal/view/{token}) now renders dashboards at full viewport width, matching the internal portal viewer. Previously, a max-width: 1200px constraint on the content container caused responsive dashboards to collapse into single-column mode.

What changed

  • Full-width public viewer: Removed the fixed max-width from the content container so embedded dashboards use the full viewport, rendering KPI grids and side-by-side charts correctly
  • Readable implementor logos: Implementor logos in the public viewer header now scale proportionally (height: 28px; width: auto) instead of being forced to 24x24px, making text-based logos (e.g., "ACME CORPORATION") legible
  • Better share dialog defaults: "Show expiration" is now checked by default and the notice text is pre-filled with the standard confidentiality message, reducing clicks for the common case

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.39.2

Verification

All release artifacts are signed with Cosign. Verify with:

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

mcp-data-platform-v1.39.1

11 Mar 08:14
e780907

Choose a tag to compare

Critical Fix: Charts and External Content in Public Viewer

v1.39.0 introduced the public viewer with a Content-Security-Policy that was too restrictive for HTML content. User-uploaded dashboards that load external libraries (Chart.js, D3, Plotly, Google Fonts, etc.) from CDNs rendered blank charts because the CSP blocked all external script sources.

Root cause: The public viewer wraps content in a blob: URL iframe. The previous code assumed blob: iframes do not inherit the parent document's CSP — this is incorrect. Modern browsers (Chromium, Firefox) propagate CSP to blob: origin iframes, so the parent's script-src 'unsafe-inline' policy blocked every <script src="https://..."> tag inside the iframe.

Fix: publicCSP() now allows https: sources for scripts, styles, fonts, images, and network requests for both HTML and JSX content types. Security isolation for embedded content is provided by the iframe's sandbox="allow-scripts" attribute (opaque origin, no top navigation, no form submission), not by CSP.

Before / After

Content Type v1.39.0 v1.39.1
HTML with inline JS only Works Works
HTML loading Chart.js from CDN Blank charts Works
HTML loading D3/Plotly from CDN Blank visualizations Works
JSX with esm.sh imports Works (allow-listed) Works (generalized)

Share Dialog Options

The backend already supported hide_expiration and notice_text fields on shares (added in v1.39.0), but the Share Dialog had no UI controls for them. This release adds a collapsible Options section to the dialog:

  • Hide expiration notice — checkbox, suppresses the countdown in the public viewer
  • Notice text — text input for custom notice text (replaces the default "Proprietary & Confidential..." message)

Options are only sent when creating public links (not user shares).

Iframe Layout Fix

The public viewer iframe used a hardcoded height:80vh inline style that cut off tall content and left empty space below short content. Replaced with a flex layout:

  • .content is now a flex column container
  • Iframes use flex: 1; min-height: 60vh — they expand to fill available vertical space with a 60vh floor
  • Non-iframe content (markdown, inline SVG) is unaffected

Files Changed

File What
pkg/portal/public.go Fixed CSP for blob: iframe inheritance; removed hardcoded height:80vh
pkg/portal/public_test.go Updated CSP assertions
pkg/portal/templates/public_viewer.html Flex layout CSS for .content container
ui/src/components/ShareDialog.tsx Collapsible Options section with checkbox + text input
ui/src/api/portal/types.ts Added hide_expiration, notice_text to Share interface
ui/src/api/portal/hooks.ts Added fields to useCreateShare mutation type
ui/src/mocks/handlers.ts Mock echoes new fields in share creation response

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.39.1

Verification

All release artifacts are signed with Cosign. Verify with:

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

mcp-data-platform-v1.39.0

11 Mar 05:49
2980bc9

Choose a tag to compare

Public Viewer Overhaul

This release transforms the public viewer (/portal/view/{token}) with theme support, expiration awareness, configurable notices, and search engine protection.

Light/Dark Mode

The public viewer now respects the system prefers-color-scheme setting and includes a toggle button in the header. The selected theme persists to localStorage across visits. Theme affects page chrome (header, notice bar, background) and text content — HTML iframe content is fully isolated with a white background regardless of theme.

Expiration Countdown

When a share has an expiration, a notice bar displays the relative time remaining (e.g., "This page expires in 6 hours"). The countdown updates automatically. Suppress it per-share with hide_expiration: true at creation time.

Per-Share Notice Text

The notice bar text is now configurable per-share via the notice_text field:

{
  "expires_in": "24h",
  "notice_text": "Internal use only.",
  "hide_expiration": false
}
  • Omit notice_text → defaults to "Proprietary & Confidential. Only share with authorized viewers."
  • Set to "" → hides the notice text entirely
  • Set to custom string → displayed as-is (max 500 characters)

When both notice text is empty and there is no expiration (or expiration is hidden), the notice bar is removed entirely.

Robots.txt

A /robots.txt endpoint now returns Disallow: / for all user agents, preventing search engines from indexing the portal, API, or shared links.

Layout & Styling Fixes

  • Content area fills remaining viewport height via flexbox — no excess whitespace below short content
  • Iframe border adapts to theme via CSS custom properties instead of hardcoded color

Database Migrations

Two new migrations run automatically on startup:

Migration Description
000018 ALTER TABLE portal_shares ADD COLUMN hide_expiration BOOLEAN NOT NULL DEFAULT FALSE
000019 ALTER TABLE portal_shares ADD COLUMN notice_text TEXT NOT NULL DEFAULT 'Proprietary & Confidential. Only share with authorized viewers.'

Both are backward-compatible — existing shares retain default behavior.

API Changes

The POST /api/v1/portal/assets/{id}/shares endpoint accepts two new optional fields:

Field Type Default Description
hide_expiration bool false Suppress expiration countdown in public viewer
notice_text string "Proprietary & Confidential..." Custom notice text; "" hides the notice

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.39.0

Verification

All release artifacts are signed with Cosign. Verify with:

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

mcp-data-platform-v1.38.5

10 Mar 22:47
4b837d9

Choose a tag to compare

What's New

Branded Two-Zone Header for Public Viewer

The public share viewer (/portal/view/:token) now supports a branded two-zone header:

  • Far left (optional): Implementor brand — show your organization's name, logo, and link
  • Far right (always shown): Platform brand — defaults to MCP Data Platform; overridable to your platform brand (e.g., "Plexara")

Both zones support clickable links when URLs are configured.

Configuration

portal:
  implementor:          # optional — omit to hide the left zone
    name: "ACME Corp"
    logo: "https://acme.com/logo.svg"   # fetched at startup, inlined as SVG
    url: "https://acme.com"

mcpapps:
  apps:
    platform-info:
      config:
        brand_name: "Plexara"            # overrides default "MCP Data Platform"
        brand_url: "https://plexara.io"  # makes the platform brand clickable

Changelog

  • feat: branded two-zone header for public viewer (#222) (@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.38.5

Verification

All release artifacts are signed with Cosign. Verify with:

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

mcp-data-platform-v1.38.4

10 Mar 19:03
c57f88a

Choose a tag to compare

What's New

Fix: Prompt Templates Now Visible in Platform Info UI (#221)

v1.38.3 added the "Show prompt template" toggle to the Prompts tab, but it only worked for workflow and custom prompts. Toolkit prompts (portal and knowledge) had their content constants defined but never included them in the PromptInfos() return values. Because the Content field uses json:"content,omitempty", it was silently dropped from the platform_info JSON response, and the toggle never appeared.

Root Cause

The portal and knowledge toolkit PromptInfos() methods returned PromptInfo structs without the Content field:

// Before — content constant defined but not used
func (*Toolkit) PromptInfos() []registry.PromptInfo {
    return []registry.PromptInfo{
        {Name: saveAssetPromptName, Description: "...", Category: "toolkit"},
    }
}

Fix

Both toolkits now populate Content from their existing constants:

  • Portal toolkit: saveAssetPromptContent and showAssetsPromptContent
  • Knowledge toolkit: knowledgeCapturePrompt and captureKnowledgePromptContent

Added TestPromptContentInJSON which marshals prompt infos to JSON and asserts the "content" key is present, preventing this regression in the future.


Changelog

Bug Fixes

  • c57f88a: fix: populate Content in toolkit PromptInfos and add JSON proof test (#221) (@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.38.4

Verification

All release artifacts are signed with Cosign. Verify with:

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

mcp-data-platform-v1.38.3

10 Mar 18:29
b4f2ff7

Choose a tag to compare

What's New

Prompt Template Visibility (#220)

The platform-info Prompts tab now lets users see the actual prompt template behind each card. Previously, prompt cards showed only the name and description — users had no way to learn what the prompt actually instructs the AI to do.

Changes

  • New content field in platform_info response: The prompts array now includes a content field containing the raw prompt template text with argument placeholders (e.g., {topic})
  • Collapsible template viewer: Each prompt card in the Prompts tab shows a "Show prompt template" toggle. Clicking it reveals the full prompt content in a styled code block; clicking again collapses it
  • Inspire custom prompts: Users can read existing templates to understand the patterns and write their own

Screenshot Walkthrough

  1. Open the Prompts tab in the platform-info app
  2. Click "Show prompt template" on any prompt card
  3. The template content expands below the description
  4. Click "Hide prompt template" to collapse

Changelog

Features

  • b4f2ff71: feat: show prompt template content in platform-info UI (#220) (@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.38.3

Verification

All release artifacts are signed with Cosign. Verify with:

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

mcp-data-platform-v1.38.2

10 Mar 17:31
7ad3444

Choose a tag to compare

What's New

Copy Button Fix (#219)

The Copy button on the platform-info Prompts tab now actually copies text to the clipboard. Previously it showed "Copied!" feedback but silently failed because:

  1. The built-in platform-info app was registered without clipboard permissions, so the Clipboard API was blocked inside the sandboxed MCP App iframe
  2. The JavaScript navigator.clipboard.writeText() Promise rejection was unhandled — the "Copied!" feedback ran unconditionally regardless of whether the copy succeeded

Changes

  • CSP permission: The platform-info app now declares clipboard-write permission, which tells MCP hosts to set allow="clipboard-write" on the iframe
  • Proper async handling: copyPrompt() now uses .then() / .catch() on the Clipboard API Promise — "Copied!" only appears after confirmed success
  • Fallback with validation: When the Clipboard API is unavailable or rejected, falls back to document.execCommand('copy') with result checking

Changelog

Bug Fixes

  • 7ad3444: fix: platform-info Copy button now actually copies to clipboard (#219) (@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.38.2

Verification

All release artifacts are signed with Cosign. Verify with:

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

mcp-data-platform-v1.38.1

10 Mar 08:30
68b306f

Choose a tag to compare

What's New

Prompts Tab UX Improvements (#218)

The Prompts tab in the platform-info MCP App received several usability improvements addressing issues introduced with the dynamic prompt system in v1.38.0.

Category grouping: Prompts are now organized into two sections — Workflows (multi-step guided prompts with arguments like explore-available-data and create-interactive-dashboard) and Quick Actions (single-action toolkit prompts like save-this-as-an-asset). Section headers only appear when both categories have prompts.

Human-readable titles: Machine slugs like explore-available-data now display as "Explore Available Data" in title case, with the original slug shown below in monospace for reference when copying.

Brand-aware intro text: The generic intro ("Available prompts — select one to copy...") has been replaced with a contextual description that incorporates the platform brand name and describes what the platform can do.

Removed platform-overview from Prompts tab: The auto-invoked platform-overview prompt no longer appears in the Prompts tab since it runs automatically on session start and has no useful copy-to-clipboard action. It remains registered as an MCP prompt.

Backend changes

  • Added Category field to PromptInfo struct with three values: "workflow", "toolkit", "custom"
  • All prompt registration paths now set a category: operator-configured prompts get "custom", workflow prompts get "workflow", toolkit-registered prompts get "toolkit"
  • Portal and Knowledge toolkits set Category: "toolkit" on their PromptInfos() output
  • Category is serialized as category in the platform_info JSON response (omitempty — backward compatible)

Frontend changes

  • Added humanize() function to convert slugs to title case
  • Refactored renderPrompts() to group by category with section headers
  • Extracted renderPromptCard() for cleaner rendering
  • Cards show human-readable title + monospace slug instead of just the slug
  • Intro text set dynamically using the platform brand name
  • New CSS classes: .prompt-section-header, .prompt-card-title, .prompt-card-slug

Before / After

Before (v1.38.0) After (v1.38.1)
All prompts in a flat list Grouped into Workflows and Quick Actions
Machine slugs as titles (explore-available-data) Human titles ("Explore Available Data") with slug below
Generic intro text Brand-aware intro describing platform capabilities
platform-overview shown (not useful to copy) platform-overview hidden from tab

Upgrading

Drop-in replacement for v1.38.0. No configuration changes required. The new category field in prompt metadata is additive and backward compatible.

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.38.1

Verification

All release artifacts are signed with Cosign and include SBOM attestations:

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

Full Changelog

  • 68b306f fix: improve Prompts tab UX with categories, human-readable names, and better intro (#218)

mcp-data-platform-v0.37.7

10 Mar 00:19
d60b75a

Choose a tag to compare

What's New

Bug Fixes

Prevent double-generation when saving artifacts (#215)

  • Added prompt guidance to the save_artifact tool description instructing the LLM to call the tool directly with content rather than first outputting it to the conversation and then saving separately
  • Previously, agents would generate the full artifact (dashboard, report, chart) in the conversation text and then regenerate it token-by-token when calling save_artifact — doubling latency and token cost
  • The tool description now includes an IMPORTANT directive to call save_artifact directly with the content inline

Replace custom markdown parser with marked in platform-info app (#214)

  • Replaced the hand-rolled line-by-line markdown parser (renderMd) with inlined marked v15.0.12 (~40KB, MIT) for robust CommonMark + GFM rendering
  • Fixes broken rendering of headings, code fences, tables, and lists when agent_instructions content has leading whitespace from YAML block scalar indentation
  • The old parser anchored all regex patterns to ^ (start of line), so any line with leading whitespace silently fell through to paragraph handling — this was particularly problematic with YAML block scalars that strip the base indent but leave 2-space prefixes on many lines
  • Updated CSS for standard heading levels (h1h6), direct <table> styling (removed .tbl-wrap wrapper assumption), and added styles for blockquote, del, and img elements

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.7

Verification

All release artifacts are signed with Cosign. Verify with:

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