Embed the install widget
The install widget shows visitors how to add your MCP server to the apps they use. It covers 40+ apps, including Claude Code, Claude, ChatGPT, Cursor and VS Code. They pick their apps and get the exact steps or one command to copy. You can see it live on the Theozard homepage.
Quick start
Add an element with your server's URL, then load the script once per page.
<div data-theozard-install="https://mcp.example.com/mcp"></div>
<script src="https://theozard.com/install/v1.js" async></script>
The widget reads your server's name, auth and tool sets from its URL. Servers listed in the Theozard registry also get a short install command by name.
Load /install/v1.js, not /install.js. The v1 address only gets changes that keep working with your existing setup. Breaking changes will ship as v2.
Attributes
Set these on the element.
data-theozard-install: your MCP server's URL. Required.data-apps: apps picked by default, comma separated, for exampleclaude-code,cursor. A visitor's own picks, saved in their browser, win.data-toolsets: tool sets picked by default, comma separated, using the ids your server lists. Leave it out to load every tool.data-view: the tab to open on,setup(Step by step) orconfig(Config file).data-header:title(default) shows "Add [server] to your AI agent",fulladds your description,nonehides it.data-key-url: a page where visitors get an API key. Used when the page sets nothing inwindow.theozard.data-empty-text: a short hint shown in brackets after "Pick your apps" until something is picked.data-theme:lightordark. Without it the widget follows adarkorlightclass on<html>, then the visitor's system setting.
Colors
The widget draws inside its own shadow DOM, so your page's CSS doesn't leak in. Two CSS variables pass through:
<div data-theozard-install="https://mcp.example.com/mcp"
style="--theozard-accent: #f5c518; --theozard-radius: 12px"></div>
The accent colors buttons, and outlines selected apps and tool sets.
API keys
If your server needs a key, tell the widget how visitors get one with window.theozard. Set it before the script loads, or call TheozardInstall.refresh() after changing it, for example once your login session loads. Use gate for signed-out visitors and createKey for signed-in ones.
window.theozard = {
// Signed in: create a key in place. Return the key as a string.
createKey: async ({ apps }) => (await api.createKey({ name: apps.join(", ") })).key,
};
window.theozard = {
// Signed out: put your plan in front of the steps.
gate: {
title: "You'll need a plan first",
text: "Optional line under the title.",
primary: { label: "Get started", href: "/pricing" },
secondary: { label: "Sign in", href: "/login?next=%2F%23install" },
},
};
Other options:
key: a key you already have for this visitor, or a function that returns one (a promise is fine). It's read once when the widget loads and filled into every command. To change it later, callTheozardInstall.setKey().signInUrlandsignUpUrl: without agate, the key step shows Sign in and See plans buttons pointing here.
Keys a visitor pastes stay in memory on that page. The widget never stores them or sends them anywhere.
Events
The widget fires DOM events on its element. They bubble, so you can listen on document. They're only for your own analytics. Nothing is sent to Theozard.
document.addEventListener("theozard:copy", (e) => {
analytics.track("mcp_command_copied", { apps: e.detail.apps });
});
theozard:pick: an app was picked or unpicked.detail.appanddetail.picked.theozard:toolsets: the tool set selection changed.theozard:copy: a command, config or field was copied.detail.viewsays which tab.theozard:key: a key was added.detail.howiscreatedorpasted. The key itself is never included.
Every event's detail also has server, apps and toolsets.
JavaScript API
TheozardInstall.mount(element, options): mount on an element yourself. Options match the attributes:url,apps,toolsets,view,header,keyUrl,emptyText,key.TheozardInstall.setKey(key): fill a key into every widget on the page. Passnullto clear it.TheozardInstall.refresh(): re-render after changingwindow.theozard.TheozardInstall.scan(): look for new elements now. Usually not needed, since the widget also watches for elements your app adds later.