Skip to main content
MCPJam ships built-in host presets for Claude, ChatGPT, Cursor, Copilot, Codex, and MCPJam itself. Each preset captures what a real host publishes during MCP initialize and ui/initializeclientInfo, hostInfo, capability advertise, hostContext (theme, viewport, device, locale), and sandbox policy (CSP directives, permissions, allow-features). With a preset selected, a widget rendered in the Playground behaves the way it would in production under that host. If your host isn’t in the list yet — or if Microsoft, Anthropic, OpenAI, etc. ship a new capability and the inspector hasn’t caught up — adding a preset is a small, self-contained contribution. This page walks through it.
Host presets are values, not code. There’s no runtime to write. A new preset is a TypeScript object that conforms to two interfaces, plus a logo file.

What a preset includes

A host preset has two pieces:
  1. Host style — branding, label, chatbox chrome, font CSS, and the capability surface the host supports (which MCP Apps and OpenAI Apps SDK features it implements). Defined in client/src/lib/client-styles/built-ins.ts.
  2. Catalog host — the backend-owned host row used for creation, compare, caniuse, and “update to latest”. It includes label/provenance facts plus the full HostConfigInputV2 template: clientCapabilities, hostContext, mcpProfile, image policy, sandbox policy, model defaults, and other host fields. Defined in mcpjam-backend/convex/marketHostCatalog/templates.ts and mcpjam-backend/convex/marketHostCatalog/seed.ts.
The backend catalog is canonical at runtime. The SDK carries a generated fallback snapshot for CLI/offline/dev paths; do not hand-edit SDK fallback data when changing host facts.

The probe-driven philosophy

The single most important rule when adding a host: capture values from a live probe, don’t invent them. Every existing preset has inline comments citing a real source — a captured ui/initialize response, a DevTools Network capture of the host’s response Content-Security-Policy header, or an official vendor doc. Examples from the codebase:
  • CLAUDE_HOST_STYLE_VARIABLES — verbatim from Claude’s published design tokens.
  • CHATGPT template cspDirectives — “captured 2026-05-18 via DevTools → Network → oaiusercontent.com response”.
  • COPILOT template — links to Microsoft Learn’s “Supported MCP Apps capabilities in Copilot” table.
Inventing values silently misrepresents the host. A widget that works in MCPJam-as-YourHost but fails in production YourHost is the failure mode we’re avoiding.
When a field can’t be probed (no live capture, no public doc), say so in a code comment. Several existing presets use phrases like “Undocumented; chosen to match the ChatGPT convention” — that’s honest. Don’t hide guesses behind clean values.

Steps

1

Probe the real host

Capture as much as you can from the live host before writing any code:
  • MCP initialize responseserverInfo, clientInfo, advertised capabilities (including the experimental block and the MCP UI extension).
  • ui/initialize responsehostInfo, hostCapabilities, hostContext (theme, displayMode, containerDimensions, locale, timeZone, userAgent, platform, deviceCapabilities, safeAreaInsets, styles).
  • Outer iframesandbox= attribute, allow= attribute, and the response Content-Security-Policy header.
  • Inner iframe (if the host nests) — same three things.
DevTools → Network → Response Headers + the inspector’s own JSON-RPC logger (Playground) are the easiest capture surfaces. Save these somewhere referenceable — you’ll cite them in code comments.
2

Add the host style

Open client/src/lib/client-styles/built-ins.ts and add a HostStyleDefinition for your host alongside CLAUDE_HOST_STYLE, CHATGPT_HOST_STYLE, etc.
Then register it in BUILT_IN_HOST_STYLES (same file, bottom):
3

Drop in the logo

Add the host’s logo to client/public/ as yourhost_logo.png (or .svg). Existing presets use 256-512px square assets.Then register it in the inspector’s host UI metadata so picker/compare surfaces can show the right icon. Logos are presentation-only; they do not live in the backend catalog template.
4

Add the backend catalog host

In mcpjam-backend/convex/marketHostCatalog/templates.ts, add the full HostConfigInputV2 template keyed by host id. In mcpjam-backend/convex/marketHostCatalog/seed.ts, add the catalog metadata for that same id: label, provenance, MCP Apps rendering, protocol versions, verification date, and image support.The template should include every host field that can change — model, colors/styles, host context, sandbox, visibility, progressive tool discovery, image policy, and MCP Apps capability matrix. Fill in what you probed, delete what doesn’t apply (see Field guide for what each one does):
5

Regenerate the SDK fallback

After backend catalog/template changes, regenerate the SDK fallback snapshot from the backend seed:
The generated SDK catalog is fallback data only. Product UI and API template creation should fetch the live backend catalog first.
6

Test it

Run the inspector locally, create a new host using your preset, and try a widget under it:
  • Does the brand pill render with your logo?
  • Does app.getHostContext() (or window.openai.theme, etc.) report what you’d expect from the real host?
  • Does a widget that probes hostInfo.name === "YourHost" take that branch?
  • Are CSP violations reported in DevTools the same ones the real host would emit?
The Playground’s “Compare hosts” mode lets you render the same tool call under YourHost alongside Claude or ChatGPT side-by-side — useful for catching capability gaps.

Field guide

A non-exhaustive reference for the fields most often gotten wrong:

Gotchas

Almost never set restrictTo on sandbox.csp. SEP-1865 makes restrictTo an intersection with the view’s declared _meta.ui.csp, not a union. Adding the host’s production allowlist here can only narrow widgets — never help them. A view declaring connect-src https://api.example.com silently goes to zero if your restrictTo.connectDomains doesn’t list api.example.com. Use mode: "declared" and trust the view’s CSP. The only legitimate use of restrictTo is to express a deny intent via empty arrays (see the Copilot preset’s frameDomains: []).
mcpProfile.apps.mcpAppsOverrides is what the host advertises for MCP Apps. Listing capabilities the renderer doesn’t actually implement misleads widget authors — they’ll gate on the advertised flag, hit a dead path at runtime, and blame their widget. If a capability’s listChanged notifications aren’t forwarded by the renderer yet, omit the sub-field. Several existing presets call this out explicitly in comments — match that discipline.
When mirroring a host that doesn’t render widgets at all (e.g. Codex CLI), replace clientCapabilities instead of spreading — a spread leaks the SDK-default MCP UI extension back in and misrepresents the host as UI-capable. See the Codex preset for the pattern.

Open a PR

When the preset is working locally:
  1. Add a screenshot of a widget rendered under your preset to the PR description.
  2. Cite the sources for each non-default value (capture date for probes, doc URL for vendor specs).
  3. If any field is a guess, mark it as such in a comment.
The maintainers will eyeball the values against the cited captures, run a couple of widgets under the preset, and merge. If your host evolves later — a new capability, a CSP change — open a follow-up PR with a fresh probe.
Stuck on a probe? Open a thread in the MCPJam Discord — the team can usually help with capture techniques or sanity-check what a vendor’s docs actually mean.