Skip to content

mcp-data-platform-v1.39.3

Choose a tag to compare

@github-actions github-actions released this 11 Mar 22:06
· 52 commits to main since this release
06e591e

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