Skip to content

fix: load production widgets in sandboxed MCP hosts #115

Description

@nickytonline

Summary

Production widget resources still assume the host will execute a static <script type="module" src="…"> (and a stylesheet <link>) from BASE_URL. That works in MCPJam and a normal browser tab. It does not work in ChatGPT or Claude, which render MCP App HTML in a srcdoc iframe and often ignore those static tags.

Dev already has an escape hatch for this (WIDGET_BOOTSTRAP_CLIENTS / inlined HTML). Production currently does not, and the README still says production is unaffected.

What happens

  1. npm run build writes hashed JS/CSS URLs into assets/<widget>.html.
  2. In production the server fetches that HTML from BASE_URL and returns it as the MCP resource.
  3. Sandboxed hosts never run the external module script, so the widget root stays empty.

A two-route Docker deploy (auth'd MCP on 8080, public assets on 4444, serve providing CORS) can still look fine in MCPJam. The same image fails in ChatGPT/Claude.

Proposed fix

When NODE_ENV=production, rewrite the fetched widget HTML before returning it:

  • Embed the built CSS in a <style> tag (stylesheet links are blocked the same way).
  • Replace the static module <script src> with an inline import("https://assets…/widget.js"). Relative chunks then keep resolving from BASE_URL.
  • Keep the standalone assets/*.html unchanged for direct browser checks.

Cover this with unit tests around the HTML rewriter (prefixing the module URL is optional; useful later for cache-busting).

Out of scope for this issue

  • Kubernetes sidecar / two-route docs (follow-up).
  • Docker ARG BASE_URL packaging (already required at build and runtime; separate from the host bug).
  • App-specific catalog files or CSS chunk names.

Test plan

  • Unit: production rewriter embeds CSS, emits import("…/widget.js"), strips stylesheet/modulepreload tags.
  • Manual: production build + public BASE_URL in MCPJam (still works) and in ChatGPT or Claude (widget actually mounts).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions