mcp-chat-cards
Summary: mcp-chat-cards is an MCP server that renders interactive HTML cards (tabs, tables, charts, forms, video, documents, code tours, and more) inline inside chat clients instead of walls of text.
Tab cards (
create_tab_card): tabbed views of one subject with plain text, sanitized HTML, or copyable code per tab.Table cards (
create_table_card): HTML tables from explicit rows or loosely delimited text with auto-detected delimiters, balanced columns, and URL-to-link cells.Chart cards (
create_chart_card): generated SVG bar, line, pie, and donut charts with legends, labels, and a collapsible data table.Form cards (
create_form_card): user-filled forms whose submission becomes the next conversation prompt via{{fieldName}}templating.Mirrored website forms:
mirror_web_formrebuilds a real page's form as a card andsubmit_web_formsubmits user-confirmed values to the actual site.Video cards (
create_video_card): HTML players for direct mp4/webm URLs,data:video/*, orblob:sources (streaming page URLs rejected).Animation cards (
create_animation_card): model-composed 16:9 animated clips built from text, bullets, SVG shapes, and zooming single-series charts with play/pause/replay/progress.Show/hide cards (
create_reveal_card): collapsible sections with show-all/hide-all controls.Sequential list cards (
create_list_card): nested ordered outlines numbered 1., 1.1., 1.1.1. via CSS counters.Document cards (
create_markdown_card): render markdown (inline or from a server-side file path) with styled tables, copyable code, and foldable H2 sections.Code tour cards (
create_code_tour_card): one tab per source file, syntax-highlighted and line-numbered behind a Raw | Code toggle;.mdfiles get Raw | Rendered; accepts explicit files or a zip archive path.Efficient prompt flow:
create_prompt_gist_card(≤350-char gist),create_prompt_refine_card(up to 3 multiple-choice rounds), andcreate_efficient_prompt_card(editable prompt with char/token count, copy, and confirm-gated send).Local file ingestion:
read_local_filereads server-side text files andunpack_archivelists a zip and returns its text entries, so model-generated deliverables plug straight into cards.Reference fetching (
fetch_reference): pull a public page and get structured headings, text, tables, images, links, and form specs to feed the card tools.Placement and reuse:
get_insert_bookmarkletreturns a bookmarklet that injects a copied card at a chosen spot on a page (page-local preview).Multi-part splitting: oversized documents and tours pack into parts under a card size budget; every result reports
structuredContent.parts {current, total, hasMore}for a single completeness check.Interaction extras: tutor terms with hover tooltips, per-card right-click context actions (including
{{selection}}), drag-reorderable blocks, copy-card HTML, and header</>source / collapse toggles.Delivery flexibility: renders inline via MCP Apps on supporting hosts, falls back to standalone HTML resources, and ships a visualizer widget for hosts that never mount the template; also runnable over Streamable HTTP as a bearer-token-gated remote connector.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-chat-cardsCreate a chart card showing quarterly revenue trends"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
An MCP (Model Context Protocol) server that renders interactive HTML cards inside desktop chat clients. Instead of walls of text, conversations get tab boxes, tables, charts, forms, short video clips, collapsible sections, and numbered outlines. On hosts that support the MCP Apps extension (SEP-1865), cards render inline in the conversation as sandboxed iframes; other hosts receive each card as a self-contained embedded HTML resource.
Features
Tab cards: view different contexts of one subject side by side (per language, per OS, per skill level), including code samples with copy buttons.
Table cards: build HTML tables from explicit rows or loosely delimited raw text. Delimiters are auto-detected, columns are balanced, and URL cells become links.
Chart cards: dynamically generated SVG bar, line, pie, and donut charts with legends and a collapsible data table for accessibility.
Form cards: forms the user fills in to give the conversation context and direction. Submitting sends the values back to the chat as the next prompt.
Mirrored website forms: fetch a real page, rebuild one of its forms as a card, then submit the actual website form with the user-entered values via
submit_web_form.Video cards: HTML
<video>players for short clips.Animation cards: model-composed animated clips for when no direct video URL exists - sequential scenes of text, staggered bullet builds, simple SVG diagrams that trace themselves in, and single-series charts that zoom into the data range under discussion, all with video-style play/pause, replay, and progress controls.
Show/hide cards: collapsible sections with show-all/hide-all controls.
Sequential list cards: nested ordered lists numbered 1., 1.1., 1.1.1. via CSS counters.
Document cards: render a markdown document (a guide or walkthrough the model wrote) as one interactive card with collapsible sections, styled tables, and copyable code.
Code tour cards: present a project as one tab per source file, in the order the files are given (README and manifests hoisted first). Source files are syntax-highlighted for their detected language and line-numbered behind a Raw | Code toggle, the way a repository browser shows a file. Markdown files render as a formatted page instead, behind a Raw | Rendered toggle - a README in a tour reads as documentation, and the source is still one click away.
Model-generated file ingestion: read local text files and unpack zip archives the model produced earlier in the conversation, so its own deliverables plug straight into cards without retyping anything.
Automatic multi-part splitting: large documents and projects are packed into parts that each stay under a card size budget, so hosts never truncate an oversized result. Each part renders as its own card and the result says exactly how to fetch the next.
Reference fetching:
fetch_referencepulls a public page and returns structured data (headings, text, tables, images, links, form specs) ready to feed into card tools.Card tutor: educational cards can mark terms that show tooltips after a hover dwell, and define right-click context actions that send model-anticipated prompts.
Movable content: card blocks can be drag-reordered, drag out of the card carries the block as HTML, and every card has a "Copy card" button that copies the standalone HTML for pasting into other responses or files.
Header toggles: every card header has a
</>button that shows or hides the card's own HTML source in a code panel, and a chevron button beside it that collapses the card down to its header row and expands it again.Efficient prompt builder: every card's right-click menu has a built-in "Generate Efficient Verbose Prompt" item that opens a three-step flow: a 350-character gist, up to three rounds of multiple-choice refinement (each question with a free-text "Other"), and a finished prompt shown with its character and token count, editable in place, copyable, and sent only after a confirmation box. The model reads a bounded gist and bounded answers instead of a rambling thread, so the only long text in the exchange is the prompt the user wanted.
Copyable cards: every card's right-click menu has a built-in "Copy card" item that copies the standalone HTML, mirroring the header button. For visual placement,
get_insert_bookmarkletreturns a bookmarklet that shows a floating "Insert Card" item on right-click and injects the copied card at that spot (page-local preview; gone on reload).
Related MCP server: mcp-apps-generative-ui-showcase
When the model should call this server
The server advertises itself for conversations about research, education, professional skills, general hobbyist skills (woodworking, arts, and similar), professional topics, history, and news, plus related subjects, whenever a card communicates better than text.
Installation
git clone https://github.com/jhauga/mcp-chat-cards.git
cd mcp-chat-cards
npm install
npm run buildRequires Node.js 18.17 or newer.
Use with Claude Desktop
Add the server to claude_desktop_config.json (Settings > Developer > Edit Config),
adjusting the path to where you cloned the repository:
{
"mcpServers": {
"chat-cards": {
"command": "node",
"args": ["C:/path/to/mcp-chat-cards/dist/index.js"]
}
}
}Restart the desktop client after saving, or use Developer > Reload MCP Configuration (the Developer menu appears after Help > Troubleshooting > Enable Developer Mode). The same stdio command works in any MCP host; for hosts that support MCP UI resources, cards render as sandboxed iframes.
Where the desktop client keeps its logs depends on how it was installed: the Microsoft
Store build writes mcp-server-chat-cards.log under %LOCALAPPDATA%\Claude\Logs\, the
classic installer under %APPDATA%\Claude\logs\. The server's own stderr lines land in
that file, which is what Debugging cards in Claude Desktop
reads.
Host status (October 2026). Claude Desktop builds since September 2026 carry a local stdio server into Claude app chats through a device bridge that announces its tools without their
uibinding and passes the model onlystructuredContent. The host never classifies a card tool as an App, never reads the template, and shows the result as a JSON row, in new and old conversations alike; the upstream report is anthropics/claude-ai-mcp#1069. Since 1.0.0-alpha.1.0.0 the server works around it: while a host has not read the card template, each result also carries a ready-made widget for the chat's own inline renderer (the visualizer'sshow_widgettool), and the model paints the card with it. See Visualizer widget. Hosts that mount the template render cards as before, and Run as a custom connector remains an untested alternative.
Run as a custom connector (Streamable HTTP)
npm run start:http starts the same server over Streamable HTTP so a chat client can
reach it as a remote ("custom") connector. The client's cloud makes the connection, so the
process has to be reachable from the internet, normally through a tunnel on the machine
that runs it, and everything is gated by one bearer token.
Variable | Purpose |
| Required. The server refuses to start without it and rejects every request that does not carry |
| Port to listen on (default |
| Address to bind (default |
| Strongly recommended here. The local file tools read the filesystem of the machine running the server, so confine them to one folder before exposing it. |
The endpoint is /mcp; every other path answers 404. Each client session gets its own
server instance (the session id travels in the mcp-session-id header, as the transport
specifies), request bodies are capped at 4 MiB, and the SDK's DNS-rebinding check is off,
because behind a tunnel the Host header is the tunnel's name and the token is the gate.
A minimal setup, with set instead of export in a Windows command prompt:
export MCP_CHAT_CARDS_HTTP_TOKEN=<token>
export MCP_CHAT_CARDS_FS_ROOT=/path/to/an/empty/folder
npm run start:http
cloudflared tunnel --url http://127.0.0.1:3310Then add the tunnel's URL plus /mcp (for example https://example.com/mcp) in the
client's connector settings, with authentication set to "No sign in" and one request
header, Authorization: Bearer <token>. In Claude, custom connectors live under
Settings > Connectors and have to be enabled in each conversation's tools menu; the Free
plan allows one.
Status: experimental. The entry point is covered by test/http.test.ts, has been
exercised with the SDK's Streamable HTTP client and through a public tunnel, and is the
route reported upstream as rendering Apps on current desktop builds, but a card has not
yet been seen rendering in Claude through it from this repository. Nothing here is needed
for the stdio setup above.
Tools
Tool | Purpose |
| Tabbed views of one subject (text, HTML, or code per tab) |
| HTML table from rows or raw text with delimiter detection |
| SVG bar, line, pie, or donut chart with data table |
| Form whose submission becomes the next conversation prompt |
| HTML video player for a short clip (direct file URL, |
| Collapsible show/hide sections (text, HTML, or code per section) |
| Nested sequential outline (1., 1.1., 1.1.1.) |
| Render a markdown document (content or file path) as one card |
| Render a project (zip path or explicit files) as file tabs: highlighted source behind Raw/Code, |
| Step 1 of the efficient-prompt flow: collect a 350-character gist |
| Step 2: multiple-choice questions that close the gaps (max 3 rounds) |
| Step 3: the finished prompt, editable, copyable, sent on confirmation |
| Read a local text file for review or card building |
| List a local zip and return its text file contents |
| Fetch a public page and return structured extracted data |
| Rebuild a website form as an interactive card |
| Submit user-confirmed values to the real website form |
Example: create_table_card
{
"title": "JavaScript array methods",
"headers": ["Method", "Purpose"],
"rows": [
["map", "Transform each item"],
["filter", "Keep matching items"],
["reduce", "Fold items into one value"]
]
}Output: a text summary plus an embedded resource
(ui://mcp-chat-cards/<id>, text/html) containing the full card document.
Example: create_form_card
{
"title": "Study preferences",
"promptTemplate": "Teach {{topic}} with {{style}} examples.",
"fields": [
{ "name": "topic", "label": "Topic", "required": true },
{ "name": "style", "type": "select", "options": ["practical", "theoretical"] }
]
}When the user submits the card, the filled template is posted to the host as the next prompt. If the host does not consume the message, the card reveals the prompt text with a copy button as a fallback.
Example: the efficient-prompt flow
"Generate Efficient Verbose Prompt" in any card's right-click menu sends a message tagged
[efficient-prompt]. The model answers with create_prompt_gist_card, and the gist the
user submits carries the rules for the rest of the flow, so nothing has to be restated:
{
"round": 1,
"questions": [
{
"name": "depth",
"question": "How much detail?",
"options": ["Overview", "Step by step", "Line by line"]
},
{
"name": "output",
"question": "What should come back?",
"options": ["A table", "A checklist", "Prose"],
"multiple": true
}
]
}Each question also renders a free-text "Other" input under the group's own name, so a typed answer arrives joined with the checked ones. Anything left blank comes back empty, which the submitted prompt spells out as "no preference". The flow ends with:
{
"prompt": "Audit config/loader.py for unhandled error paths. Output: a table of file, line, failure mode, and fix, then one line on the riskiest one.",
"notes": "Assumes the current logging setup stays."
}The card shows that prompt with its character and token count and a Send this prompt button. Clicking it opens a confirmation box; only "Yes, send it" hands the prompt to the conversation. On hosts with no channel back to the chat, the copy button is the whole story: the prompt is copied and the user pastes it as their next message.
Example: plug-n-play with files the model generates
Suppose earlier in the conversation the model built a small project and delivered
project.zip plus a GUIDE.md walkthrough. Instead of the user unpacking and reading
them by hand, the model turns them into interactive cards in two calls:
{ "path": "C:/Users/jane/Downloads/GUIDE.md" }sent to create_markdown_card renders the whole guide as one card: the first H1 becomes
the title, each H2 section folds into a show/hide reveal, tables get card styling, and
every fenced code block gets a copy button.
{
"title": "Project source tour",
"archivePath": "C:/Users/jane/Downloads/project.zip",
"intro": "Read the guide card first, then follow these files in order."
}sent to create_code_tour_card unpacks the archive in memory and renders one tab per
text file, ordered README, manifest, then source, each language-tagged with a copy
button. Explicit files keep the order the caller gives them (README and manifests are
hoisted to the front), so a deliberate teaching order - data model, then errors, then
the entry point - renders as written instead of alphabetically. Build caches
(target/, node_modules/) and binary entries are skipped automatically. Use unpack_archive or read_local_file first when the model needs to
inspect contents before deciding which cards to build.
When a document or project exceeds the card size budget (default about 32,000 characters
of card markup, tunable via MCP_CHAT_CARDS_CARD_BUDGET), the tool splits it at natural
boundaries - H2 sections for documents, whole files for tours - and returns part 1 with
an instruction like "call create_code_tour_card again with part: 2". The model repeats
the call until every part has rendered as its own card, and oversized single files are
truncated with a visible notice.
The budget is measured against what a file costs after rendering, not its length on
disk: source is HTML-escaped into the tab panel, where a single < becomes four
characters, so a handful of markup-dense files can cost far more than their raw size
suggests. Every finished result is then measured once more against the host's ceiling
(about 40,000 characters of serialized result, tunable via
MCP_CHAT_CARDS_RESULT_LIMIT). A card that is still too large and cannot split itself -
a table with thousands of rows, say - returns an actionable error naming the overage
instead of an oversized result that the host would silently refuse to render.
Example: mirrored website form
mirror_web_formwith{ "url": "https://example.com/newsletter" }renders the page's signup form as a card.The user fills it in and submits; the card returns a structured payload to the chat.
The model reviews the values with the user, then calls
submit_web_formwith the payload to submit the real form and reports the HTTP result.
How cards render
The server supports three delivery paths, chosen automatically per connection:
Inline in the conversation (MCP Apps, SEP-1865). The server pre-declares one UI
template resource at ui://mcp-chat-cards/card.html with MIME type
text/html;profile=mcp-app, and every card tool links to it through
_meta.ui.resourceUri and declares an output schema (hosts drop structuredContent
from schema-less tools, leaving the card nothing to paint). Hosts that support the Apps
extension render the template inline in the chat as a sandboxed iframe, complete the
ui/initialize handshake, and deliver the tool result to it (Claude Desktop did so until
September 2026; see the host status note under
Use with Claude Desktop). The template is defensive about the parts that fail silently: it announces
ui/notifications/initialized on a timeout as well as on the handshake reply (the host
withholds the tool result until it sees the announcement), locates the card payload by
deep search rather than one fixed nesting, reports ui/notifications/size-changed after
every paint and on resize so the iframe takes its real height, and adopts the host's
theme (including a full dark palette). Card interactions travel back over JSON-RPC
postMessage: form submissions and context actions become ui/message requests (the next
conversation prompt), links go through ui/open-link, and telemetry uses logging
notifications.
Standalone document fallback. For clients that did not declare the Apps extension,
each result carries a link to ui://mcp-chat-cards/html/<card-id>. Reading that resource
returns the same card as a self-contained HTML document (inline CSS and JS, restrictive
Content-Security-Policy, no external scripts). Hosts without Apps support but with MCP-UI
style rendering show that document in a sandboxed panel; there the card posts MCP-UI
style messages (prompt, notify, link).
The document is deliberately not inlined in the tool result. Its theme and runtime are
byte-for-byte identical in every card, so inlining repeated about 16 KB of boilerplate per
call: it crowded out the caller's context and was the main reason an otherwise ordinary
card could exceed a host's result ceiling and render nothing at all. Set
MCP_CHAT_CARDS_EMBED_HTML=1 to restore the inline copy for a host that cannot follow a
resource link. The server keeps the last 24 rendered cards available for reading.
Visualizer widget (hosts that never mount the template). Some hosts negotiate the
Apps extension, call the card tools, and still never mount a view: Claude's device
bridge, which carries local stdio servers into Claude app chats, strips the ui binding
and hands the model only structuredContent. Those chats have an inline HTML renderer
of their own, the visualizer tool show_widget. Until the host reads the card template
on a connection (the one act that proves it mounts Apps views), every card result for an
Apps client also carries structuredContent.display:
{
"shown": false,
"action": "This host does not mount MCP Apps views for this server, so ... call show_widget ...",
"title": "rust_iterator_adapters_table_card",
"loading_messages": ["Laying out the table card"],
"widget_code": "<style id=\"mcc-critical\">...</style><h2 class=\"sr-only\">...</h2><article class=\"mcc-card\">...</article><script type=\"application/json\" id=\"mcc-config\">...</script><script src=\"https://cdn.jsdelivr.net/gh/jhauga/mcp-chat-cards@v<version>/widget/mcc-widget.js\"></script>"
}The model passes title, loading_messages, and widget_code to show_widget and the
card renders inline. widget_code is the card's own article plus a short critical style
that keeps it legible while it streams, and one script tag for
widget/mcc-widget.js: the full card theme mapped onto the
host's design tokens (light and dark), a bridge that turns form submissions and context
actions into sendPrompt() and links into openLink(), and the same card runtime the
Apps template runs. The bundle is generated by npm run build, committed, and served by
jsDelivr from the release tag (the visualizer only loads scripts from a few CDNs), so it
can never disagree with the server that emitted the markup. If it cannot load, the card
still reads correctly with the critical style; tabs, copy buttons, and menus need the
bundle.
Variable | Effect |
|
|
| Bundle URL override, for a fork or a local test server. |
Because a widget result carries the article twice (once for the template, once inside
widget_code), cards that split by size pack half as much per part while a widget ships.
Known limits of this path: the visualizer's sandbox loads nothing from origins outside
its CDN allowlist, so video and image cards show their captions and links but not the
media; the card's hover and ready notifications have no channel back to the model; and on
the first card after a host starts mounting Apps views again, the card can appear twice
(once in the Apps frame, once as a widget) until the template read switches the
connection to apps.
Consistent result shape
Every card tool returns the same three things, whatever the card kind:
Part | Contents |
| Text summary of the card, meaningful on its own |
| Resource link to the standalone HTML (omitted for Apps hosts) |
|
|
Rendering surface
Cards render inline in the Claude desktop app on builds that mount the template, and in Claude app chats that reach a local server through the device bridge by way of the visualizer widget (see the host status note under Use with Claude Desktop). Other surfaces (mobile and web) receive the text summary and the structured payload but do not paint the card, so each summary is written to stand alone and tools are instructed to state a card's conclusion in the conversation as well.
Text fields are plain text
Every text field a tool accepts - titles, labels, cell values, tutor tips - is plain text
and is escaped by the server exactly once. Callers must not pre-escape: pass
Predict, Spot & Fix, not Predict, Spot & Fix.
Input is never decoded first, in any field. A caller who does pass & gets a card
that displays the six characters &, because that is what a guide documenting HTML,
escaping, or templating means to show its reader. The rule is the same everywhere, so the
same string renders identically in a table cell, a tab, a markdown table, and a code
sample.
Raw HTML is only honoured in fields named html (create_tab_card and
create_reveal_card sections), where it is sanitized: scripts, event handlers, frames,
forms, and dangerous URLs are stripped while formatting such as <b> and <i> is kept.
Everywhere else - including HTML written inside a create_markdown_card document - tags
render as literal text, so use markdown syntax for formatting there. Escaped block-level
HTML is wrapped in the paragraph the markdown structure implies rather than dropped
between siblings as loose text, and HTML comments are dropped rather than shown, since a
<!-- markdownlint-disable --> directive is not prose.
Where paths resolve
create_markdown_card(path), create_code_tour_card(archivePath), read_local_file, and
unpack_archive all resolve paths on the filesystem of the machine running this server.
When the server is reached over a remote bridge, that is not the caller's sandbox: a file
the model generated on its own side does not exist here. Pass the content inline
(markdown, files) in that case. A path from the wrong operating system - say
/home/demo-user/project.zip sent to a server running on Windows - is rejected with an
error naming the mismatch rather than resolved onto a drive where it never existed; the
same goes for Windows paths sent to a POSIX server and for unexpanded ~/ paths. Set
MCP_CHAT_CARDS_FS_ROOT to confine local reads to one directory.
Interactivity notes and limits
Drag and drop reorders blocks inside one card. Dragging a block out of the card carries its HTML in the drag data; dropping into another response requires host support, which desktop chat clients generally do not expose yet.
"Copy card" copies the standalone HTML document so a card can be reproduced in another response, a file, or a browser tab.
Tutor tooltips appear after hovering a marked term for about 1.2 seconds; the card also notifies the host so the model can follow up while the user explores. Each term is marked once per card (longest term wins where two overlap), duplicates in the term list are ignored, and marking never happens inside code samples, native tooltips, or another term's tip. Matching is case-sensitive, so a tip written for
PATHdoes not attach itself to a filesystempath; setcaseInsensitive: trueon a term to match any casing. PasstutorTermsInCode: truetocreate_code_tour_cardto opt code in.Every card result carries
structuredContent.partsas{ current, total, hasMore }, so one completeness check works on every card type. WhilehasMoreis true, content has been withheld and the caller calls the same tool again withpart: current + 1. Onlycreate_markdown_cardandcreate_code_tour_cardcan split; every other card always reports{ current: 1, total: 1, hasMore: false }. The rendered title keeps its human-readable(part 1 of 2)suffix for the reader.The split threshold is measured on rendered characters, not on the input a caller writes. Escaping expands source unpredictably -
<,>,&, and quotes each become four to six characters - so a payload that looks well under the budget can cross it and a larger-looking one may not. Readparts.hasMorerather than predicting from input size. A markdown document with no H2 headings has no split boundary and always renders as one part.In a code tour, a source file whose language the highlighter knows gets a Raw | Code toggle. Code is the view on arrival: syntax-highlighted, with line numbers in an unselectable gutter, so a copy or a drag through the file picks up the file and not its numbering. Raw is the same text with the highlighting and gutter switched off, so the card carries one copy of the source rather than two. Languages covered: C, C++, C#, CSS, Go, Java, JavaScript, JSON, JSX, PHP, Python, Ruby, Rust, shell, SQL, TOML, TSX, TypeScript, and YAML, plus the usual aliases (
node,js,py,golang,yml, and so on). Anything else renders as the plain code block it always did.Highlighted files cost more card budget than plain ones (roughly two to three times, since every token carries a span), and the packer measures the rendered panel, so a large tour splits into more parts than it used to rather than overflowing a card.
In a code tour, a
.md,.markdown, or.mdxfile gets a Raw/Rendered toggle. Rendered is the view on arrival and shows the document as a page (headings, card-styled tables, links, fenced code with copy buttons, never folded into reveals); Raw is the ordinary code block, whitespace preserved, whose copy button returns the source byte for byte. Both views ship inside the card, so switching costs no round trip and the choice survives switching between file tabs. Every other extension is unchanged.Right-click context actions are defined by the model per card;
{{selection}}in an action prompt is replaced with the user's selected text. Two items are always present regardless of what the model defined: "Generate Efficient Verbose Prompt" and "Copy card".The finished prompt card never sends on a single click. The first click opens a confirmation box; the prompt goes to the conversation only when that box is accepted, and what is sent is whatever the textarea holds at that moment, edits included.
Form answers are gathered per field name, and empty values are dropped, so a choice group and a text input can share one name and arrive as a single comma-joined answer. Every named control still yields a key, so an unanswered group renders as an empty value rather than leaving a literal
{{name}}in the prompt.
Security
Local file tools (
read_local_file,unpack_archive, and the path/archive inputs of the document and code tour cards) read text only, cap sizes, refuse binaries, and cap archive extraction (entry count, per-file, and total bytes). SetMCP_CHAT_CARDS_FS_ROOTto confine all local reads to one directory.Outbound requests are limited to http(s) URLs resolving to public addresses. Localhost, RFC 1918, link-local, CGNAT, and equivalent IPv6 ranges are blocked, redirects are re-validated, bodies are size-capped, and requests time out. Set
MCP_CHAT_CARDS_ALLOW_PRIVATE=1only if you intentionally need intranet fetches.All model- and user-supplied text is HTML-escaped; fetched third-party HTML is sanitized (scripts, event handlers, frames, forms, and dangerous URLs are stripped).
Cards ship a restrictive CSP and load no external scripts, stylesheets, or fonts.
submit_web_formshould only be called with values the user entered in a mirrored form card or explicitly confirmed.
Debugging cards in Claude Desktop
A card that arrives as text, or mounts and stays empty, fails silently. Work down this list; each step separates the host from the server.
Did the host mount anything? Enable Developer Mode (Help > Troubleshooting > Enable Developer Mode), press
Ctrl+Shift+I(Cmd+Option+Ion macOS), and inspect the tool call. A rendered card is an iframe nested inside another iframe. No inner iframe means the host never treated the tool as an App: continue with step 2. An inner iframe that stays empty means the handshake or the payload failed: go to step 5.Did the host read the template? Open
mcp-server-chat-cards.log(locations under Use with Claude Desktop). The server writes one stderr line per host interaction, all prefixedmcp-chat-cards:mcp-chat-cards client <name> <version> connected (apps extension: declared) mcp-chat-cards card table card-abc123-1 rendered (1658 chars, apps client: yes) mcp-chat-cards template read by host (ui://mcp-chat-cards/card.html, 66232 chars)A
card ... renderedline with notemplate read by hostline near it is the signature of the host-side regression: the host negotiated Apps, called the tool, and never asked for the template. In the default render mode the next line then readscard <id> sent as a visualizer widget (render mode auto, template read by host: no), which means the result carriedstructuredContent.displayand the card appears only once the model callsshow_widgetwith it. A JSON row with no widget after it means the model skipped that call (ask it to show the card) or the chat has no visualizer. The host's ownresources/readentries in the same file are only a lower bound (it logs one of its connections and never logstools/call), so read the server's lines rather than the host's.Is the server side healthy? Run
npm run probe. It spawnsdist/index.jsover real stdio as a client that declares the Apps extension and checks the things a host needs: the server's extension capability, theuibinding on every card tool, output schemas, a visualizer widget on a result before any template read, the template's MIME type and content, a card result'sstructuredContentwith no widget once the template was read, and the absence of the standalone fallback for Apps clients. All passing means a text-only card is the host's doing.What does the model see? Ask, in the same conversation, which chat-cards tools advertise a
ui://resource. The model answers from the tool list the host gave it; "none" means the host dropped the binding before the model ever saw it.Inside a mounted iframe, filter its console for
[mcp-chat-cards]: every JSON-RPC message the card sends and receives is logged with its direction (tx/rx), so a missing handshake reply or an undelivered tool result is visible immediately. Runwindow.__mccDebug()there for a snapshot: template version, whetherinitializedwas announced, whether a card painted, the rendered card HTML, and the last 50 protocol messages. Paste its output when reporting a rendering issue.
Supplemental ports
The extension/ folder contains supplemental ports of the card tools for
other hosts. Both are self-contained - they do not import from src/ or dist/, and
the MCP server is unaffected by them.
extension/github/ - a GitHub Copilot canvas extension named
chat-cards. The agent drives the same card kinds (tabs, tables, charts, forms, show/hide, sequential lists, markdown documents, video) through canvas actions, and form submissions come back to the conversation as prompts. Its README covers the action list, the differences from the MCP tools, and how the folder maps onto the awesome-copilot contribution layout.extension/claude/ - a Claude artifact template: one self-contained HTML page whose card spec block Claude fills and publishes as an artifact. Forms and right-click actions produce prompts the user copies back into the conversation.
Development
npm run build # compile TypeScript to dist/ and regenerate widget/mcc-widget.js
npm test # run the vitest suite (unit + in-memory MCP integration)
npm run probe # check the built server over real stdio, as a host would
npm run coverage # run tests with V8 coverage
npm run dev # compile in watch modewidget/mcc-widget.js is committed because jsDelivr serves it from the tagged
repository; a test fails when it drifts from the sources. Cards point at
@v<package version>, so push the release tag along with the commit
(git push origin main v<version>), or widget-delivered cards fall back to their critical
style until it exists. Do not load the bundle URL before the tag is on GitHub: jsDelivr
caches the miss. If that happened, opening
https://purge.jsdelivr.net/gh/jhauga/mcp-chat-cards@v<version>/widget/mcc-widget.js
clears it.
The bundle runs inside the host's frame, so it must never feed back into the host: no
observers on :root style or class, no DOM writes on a host-triggered path, no
microtask loops. test/widget.test.ts mounts it beside a host that touches :root on
every DOM change and fails if the two keep triggering each other.
License
MIT. See LICENSE.
Available Tools
19 toolscreate_animation_cardCreate animation cardA
Render a short animated clip as a card when no direct video URL exists but motion would communicate better than static content - explanations, walkthroughs, and data stories. Scenes play sequentially in a 16:9 stage with play/pause, replay, and progress controls; everything is generated text, SVG shapes, and CSS animation (no external assets). Compose classic clip patterns and vary them per conversation: title reveal into bullet build (fade/slide), diagram walk-through with arrows tracing in (draw), a chart that zooms into the label range under discussion and back out (chart.zoom), and a closing takeaway scene (zoom). Mix scene kinds freely; per-scene transition and duration make endless variations from the same schema.
| Name | Required | Description | Default |
|---|---|---|---|
| loop | No | Restart from scene 1 after the last scene | |
| title | Yes | ||
| scenes | Yes | ||
| autoplay | No | Start playing on render (default true) | |
| subtitle | No | ||
| tutorTerms | No | Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so "PATH" does not attach its tip to a filesystem "path"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text. | |
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. | |
| sceneDurationMs | No | Default per-scene duration in ms (default 3500) |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does substantial work: 16:9 stage, play/pause/replay/progress controls, sequential scene playback, no external assets, and 'vary them per conversation' hinting at repetition control. It doesn't cover permissions, persistence, or error behavior, so it falls short of exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and routing condition are front-loaded in the first sentence, followed by rendering behavior and composition patterns. The dense last sentence earns its place by showing how the schema yields varied output, though it borders on repeating the scene-kind list.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-complexity nested-scene tool with an output schema (so returns need no explanation), the description covers purpose, rendering behavior, and composition patterns well. Minor gaps remain around lifecycle and error cases, but nothing an agent needs to author a valid card is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 63%, and the description adds real meaning on top: per-scene transition and duration, the chart.zoom camera behavior into a label range, and shapes as diagram elements with arrows tracing in. It is silent on tutorTerms and contextActions, but those carry rich schema descriptions of their own.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (render) and resource (short animated clip as a card) and pins the exact scope: 'when no direct video URL exists but motion would communicate better than static content'. This implicitly separates it from the sibling create_video_card without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear when-to-use conditions ('explanations, walkthroughs, and data stories') and a negative trigger (no direct video URL exists), which routes the agent away from the video sibling. It stops short of naming the alternative tool explicitly, but the selecting condition is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_chart_cardCreate chart cardB
Render a dynamically generated SVG chart card (bar, line, pie, or donut) with a legend and a collapsible data table. Use for useful graphics summarizing referenced data.
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | ||
| title | Yes | ||
| labels | No | X-axis labels (bar/line) | |
| series | No | Data series (bar/line) | |
| values | No | Slices (pie/donut) | |
| yLabel | No | ||
| subtitle | No | ||
| tutorTerms | No | Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so "PATH" does not attach its tip to a filesystem "path"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text. | |
| description | No | ||
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose output composition (SVG, legend, collapsible data table) and that the chart is 'dynamically generated,' which is useful. But it says nothing about rendering context, permissions, or side effects on the host.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the core capability front-loaded and no wasted words. Efficient for a complex tool, though the second sentence is too vague to fully earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need no explanation, and the schema richly covers the nested tutorTerms/contextActions params. However, for a 10-parameter tool with no annotations, the description is thin on usage routing and rendering behavior, leaving real gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% and the schema already documents that labels/series are for bar-line versus values for pie-donut, plus rich descriptions for tutorTerms and contextActions. The description's enumeration of chart types merely repeats the enum and adds no meaning beyond the schema, so baseline 3 fits.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Render a dynamically generated SVG chart card') and enumerates the supported chart types (bar, line, pie, donut) plus the legend and collapsible data table it produces. This distinguishes it from sibling card tools like create_table_card or create_markdown_card, though it never names them directly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only guidance is 'Use for useful graphics summarizing referenced data,' which is vague and offers no when-not-to-use or alternatives. Against a large sibling set of card creators, the description does nothing to route the agent to the right one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_code_tour_cardCreate code tour cardA
Render a project's source as an interactive card with one tab per file. Source files are syntax-highlighted for their detected language and line-numbered, with a Raw/Code toggle and a copy button, the way a repository browser shows a file; a language with no grammar renders as a plain code block. Markdown files (.md, .markdown, .mdx) render as a formatted page - headings, tables, links, copyable fenced code - with a Raw/Rendered toggle back to the source, so a README in a tour reads as documentation rather than as source. Explicit files keep the order they are given in, with README and manifests hoisted to the front; archive files are ordered README, manifest, then src. Pass the path of a zip archive generated earlier in the conversation for a one-call plug-n-play tour, or pass files explicitly. Files are packed into parts of about 32,000 rendered characters each regardless of how many there are, so a handful of medium files still splits. The result's structuredContent.parts {current,total,hasMore} reports the split: while hasMore is true some files were withheld, so call again with part: current + 1 and identical other arguments until every part has rendered.
| Name | Required | Description | Default |
|---|---|---|---|
| part | No | Part number for large projects (1-based). Big tours split automatically; while structuredContent.parts.hasMore is true, call again with the next part. | |
| files | No | Explicit files to show when not using archivePath | |
| intro | No | Guidance shown in a leading 'Start here' tab | |
| title | Yes | ||
| include | No | With archivePath: only include entries whose path contains one of these | |
| maxTabs | No | ||
| subtitle | No | ||
| tutorTerms | No | Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so "PATH" does not attach its tip to a filesystem "path"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text. | |
| archivePath | No | Path to a zip ON THE MACHINE RUNNING THIS SERVER, not in the caller's sandbox. Over a remote bridge those are different machines: if the archive exists only on your side, pass its text files as files instead. | |
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. | |
| tutorTermsInCode | No | Also highlight tutorTerms inside the code samples. Off by default, because marking up language keywords in source is noise rather than teaching. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden, and it delivers: ordering rules (explicit order with README/manifests hoisted; archive order README, manifest, src), the ~32,000-character part split and why small files still split, the exact resume loop against structuredContent.parts.hasMore, and the archivePath-on-server-vs-sandbox caveat. This is unusually rich behavioral disclosure for a mutation/render tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then rendering behavior, then input-mode selection, then pagination — a sensible order. A few clauses are UI minutiae ('copy button,' 'Raw/Code toggle') that don't aid invocation, keeping it just short of tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter, annotation-free tool this covers the risky paths — archive vs explicit files, part-splitting and resumption, ordering, tutor-term matching rules. Remaining gaps (maxTabs interaction with the split, subtitle/intro/contextActions purpose) are covered by the schema, so the omission is minor.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
At 73% schema coverage the baseline is elevated, and the description genuinely adds meaning for the high-stakes params: the part/resume protocol, files ordering and hoisting behavior, and the archivePath machine caveat. It is silent on maxTabs, subtitle, and intro, which are left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Render a project's source as an interactive card with one tab per file,' then elaborates with syntax highlighting, Raw/Code toggle, and markdown rendering. An agent can immediately tell this is the code-tour card, not the table, chart, or markdown card among its siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit selection criteria between the two input modes ('Pass the path of a zip archive generated earlier... or pass files explicitly') and a precise continuation protocol for pagination. It does not name sibling tools as alternatives, so it stops short of full when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_efficient_prompt_cardDeliver the efficient promptA
Step 3 of the efficient-prompt flow: hand back the finished prompt in an editable card with a character and token count, a copy button, and a send button gated behind a confirmation box. Write one prompt that is verbose only where verbosity buys a complete first-pass answer: no restated context, no filler, an explicit output shape. Do not act on the prompt here - wait for the user to send it back as a message.
| Name | Required | Description | Default |
|---|---|---|---|
| notes | No | One line on what the prompt assumes or leaves out, shown under it | |
| title | No | ||
| prompt | Yes | The finished prompt, as plain text | |
| subtitle | No | ||
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose real behavior: the card renders character/token counts, a copy button, and a send button gated behind a confirmation box, and critically that the tool does not itself act on the prompt. Permission, state, or edge-case behavior (e.g. what happens if prompt is blank beyond minLength) is not covered, keeping it out of 5 territory.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the flow position and artifact, then the authoring rule, then the do-not-act constraint. Every sentence contributes, though the first sentence is dense with UI feature enumeration that borders on over-specification.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the description covers flow position, authoring intent, and the non-action constraint. The only meaningful gap is undocumented title/subtitle parameters, which is a minor incompleteness rather than a blocker.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 60% with the main required 'prompt' param described in the schema, and the description adds genuinely useful authoring guidance for it (verbose only where verbosity buys a complete first-pass answer, explicit output shape). However, 'title' and 'subtitle' remain undocumented in both schema and description, and 'contextActions' semantics are largely carried by the schema itself, so this sits at the baseline-3 level.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and output artifact: hand back the finished prompt in an editable card with counts, copy and send controls. It also situates itself as step 3 of the efficient-prompt flow, which helps distinguish it from siblings, though it never names the adjacent prompt-card siblings (create_prompt_gist_card, create_prompt_refine_card) so an agent must infer the routing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'Step 3 of the efficient-prompt flow' framing plus the explicit prohibition 'Do not act on the prompt here - wait for the user to send it back as a message' gives clear when-to-use and when-not-to-act guidance. It does not, however, state when to choose this card over the other prompt-card siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_form_cardCreate form cardA
Render a form card the user fills in to give the conversation context and direction. Submitting sends the values back to the chat as the next prompt (optionally shaped by promptTemplate with {{fieldName}} tokens).
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | ||
| fields | Yes | ||
| subtitle | No | ||
| description | No | ||
| submitLabel | No | ||
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. | |
| promptTemplate | No | Prompt sent on submit; {{fieldName}} tokens are replaced with values |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose the critical side effect: submitting returns the values to the chat as the next prompt, optionally shaped by promptTemplate. That is the behavior an agent most needs to know for an interactive, non-read-only tool, though it says nothing about blocking, rendering timing, or cancellation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with no filler, front-loading the render action and follow-on submit behavior. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the submit-to-prompt flow is covered. Still, a 7-parameter interactive tool with no annotations and only 29% schema coverage leaves the non-promptTemplate parameters (fields, submitLabel, contextActions semantics) under-explained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 29% across 7 parameters, so the description must compensate. It explains promptTemplate and its {{fieldName}} substitution tokens, which is real added meaning, but title, fields, subtitle, description, submitLabel and contextActions receive no explanation in the description (contextActions is only covered inside the schema).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Render a form card') and adds the interaction model: the user fills it in to give the conversation context and direction. An agent can distinguish it from the other card creators by the 'form' noun, though the description never explicitly contrasts it with siblings like create_list_card or create_prompt_refine_card.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It implies the usage context ('to give the conversation context and direction'), which is a genuine hint about when to reach for a form rather than a static card. However, there is no explicit when-to-use/when-not statement and no named alternative among the many sibling card tools, so selection still requires inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_list_cardCreate sequential list cardB
Render a nested ordered list card with hierarchical numbering (1., 1.1., 1.1.1.). Good for procedures, outlines, and curricula.
| Name | Required | Description | Default |
|---|---|---|---|
| intro | No | ||
| items | Yes | ||
| title | Yes | ||
| subtitle | No | ||
| tutorTerms | No | Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so "PATH" does not attach its tip to a filesystem "path"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text. | |
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, yet it only describes what the card looks like. It says nothing about the creation/mutation semantics, the interactive tutorTerms and contextActions behavior, or any side effects — all of which matter for a tool that constructs a live card.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the core capability front-loaded and the numbering scheme given concretely. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the two complex params carry rich schema docs. However, with no annotations and no mention of the card's interactive features, the definition is only minimally complete for an agent deciding how to populate it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 33%, so the description must compensate. It does explain the nested/hierarchical nature that maps to items.children (which itself has no schema description), but it never mentions title, intro, subtitle, tutorTerms, or contextActions, leaving half the parameters to the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Render) and resource (nested ordered list card) plus the distinctive feature (hierarchical numbering 1., 1.1., 1.1.1.). It is clearly distinguishable from sibling card types like create_table_card or create_chart_card, though it never names them explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Good for procedures, outlines, and curricula" gives implied usage context, but there is no explicit when-not guidance and no routing to alternatives (e.g., a flat list or a markdown card). The agent must infer when this card beats its siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_markdown_cardCreate document card from markdownA
Render a markdown document as one interactive card: tables become card tables, fenced code gets copy buttons, and H2 sections fold into show/hide reveals. Pass either the markdown content or the path of a markdown file generated earlier in the conversation (for example a walkthrough or guide) to plug it into the chat in one call. Raw HTML in the markdown is NOT rendered as markup: it is shown as literal text, the same as in every other card's text fields, so use markdown syntax for formatting. Long documents split at H2 boundaries into parts of about 32,000 rendered characters each; the result's structuredContent.parts {current,total,hasMore} says whether more parts remain. A document with no H2 headings cannot be split and renders as one part.
| Name | Required | Description | Default |
|---|---|---|---|
| part | No | Part number for large documents (1-based). Long documents split automatically; while structuredContent.parts.hasMore is true, call again with the next part. | |
| path | No | Path to a markdown file ON THE MACHINE RUNNING THIS SERVER, not in the caller's sandbox. Over a remote bridge those are different machines: if the file exists only on your side, pass its text as markdown instead. | |
| title | No | Card title; defaults to the document's first H1 | |
| markdown | No | Markdown content to render | |
| subtitle | No | ||
| openFirst | No | Open the first section initially (default true) | |
| tutorTerms | No | Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so "PATH" does not attach its tip to a filesystem "path"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text. | |
| splitSections | No | Fold H2 sections into reveals (default true) | |
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does so well: it discloses that raw HTML renders as literal text, that long documents split at H2 boundaries into ~32,000-character parts, how to detect more parts via structuredContent.parts.hasMore, and that documents without H2 headings cannot be split. These are non-obvious behavioral traits an agent would otherwise discover only by trial and error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and rendering behavior are front-loaded, and each subsequent sentence covers a distinct concern (input choice, HTML handling, splitting, no-H2 edge case) with no filler. It is slightly long for a single paragraph but every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter tool with no required parameters and an output schema that handles return values, the description covers everything an agent needs: rendering semantics, input source caveats, pagination behavior, and the HTML limitation. Nothing material is left to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is high (89%), so the baseline is 3 and the description only needs to add marginal value. It does: it explains the interaction between the `part` parameter and the automatic splitting/hasMore flow, and ties H2 folding to splitSections, adding cross-parameter semantics the schema documents only in isolation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: 'Render a markdown document as one interactive card', then immediately enumerates the concrete rendering behaviors (tables, code copy buttons, H2 folding). This clearly separates it from siblings like create_table_card or create_code_tour_card, which would render those elements standalone rather than as parts of one markdown document.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It tells the agent which inputs are acceptable and where content should come from: 'Pass either the markdown content or the path of a markdown file generated earlier in the conversation (for example a walkthrough or guide)'. The schema further warns about the path-vs-sandbox distinction. However, there is no explicit when-to-use-this-vs-a-sibling guidance (e.g. when to prefer create_table_card over a markdown table), which would be needed for a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_prompt_gist_cardStart an efficient promptA
Open step 1 of the efficient-prompt flow: a card asking the user to describe, in no more than 350 characters, the gist of where they want to go. Call this when a message is tagged [efficient-prompt], or when the user asks for help writing a prompt. Submitting the card sends back the gist along with the rules for the rest of the flow, so answer with the card and wait rather than asking follow-up questions in chat.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | ||
| question | No | Replaces the default gist question when you already know what they are circling | |
| subtitle | No | ||
| placeholder | No | Placeholder text inside the gist textarea | |
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does disclose key behavior: submitting the card returns the gist plus the flow rules, and the agent should wait instead of asking follow-ups. It does not cover permissions or error conditions, but for a UI card launcher this is substantial behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences are used efficiently, front-loading the purpose and flow step before the trigger conditions and behavior. The 350-character detail is embedded usefully, though the sentence is dense with instructions.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not explain return values, and it focuses on when and how to call. It is largely complete for a card-launcher tool, though it could better distinguish itself from the similarly named create_efficient_prompt_card sibling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 60%, so the schema does most of the work for parameters like question and contextActions. The description adds the 350-character limit and the gist concept, but does not explain the title, subtitle, or placeholder parameters, leaving a moderate gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: opening step 1 of the efficient-prompt flow via a card that asks the user to describe their goal gist. It clarifies the tool's role but does not distinguish it from its close sibling create_efficient_prompt_card, which remains ambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit triggers (a message tagged [efficient-prompt], or a user asking for help writing a prompt) and even directs the agent to wait rather than follow up in chat. The when-to-use context is complete and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_prompt_refine_cardRefine an efficient promptA
Step 2 of the efficient-prompt flow: ask the fewest multiple-choice questions that close the gaps the gist left. Radios by default, checkboxes when several answers can be true at once; every question also gets a free-text "Other". At most 3 refine rounds - pass the round number so the card can say how many are left. Skip this step entirely when the gist is already clear enough to write the prompt.
| Name | Required | Description | Default |
|---|---|---|---|
| round | No | Which refine round this is, 1 to 3 (default 1) | |
| title | No | ||
| subtitle | No | ||
| questions | Yes | ||
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does add real behavioral context: default radio widgets, checkbox mode when several answers are true, an always-present free-text 'Other', and a hard cap of 3 refine rounds. It doesn't say what happens to submitted answers or what the card renders/returns, but it discloses enough UI and lifecycle behavior to be usable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the flow position, with no filler. The widget-behavior sentence is dense but each clause carries distinct information; slight trimming of the radios/checkboxes detail is conceivable, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the flow guidance is solid. However, for a 5-parameter tool with a nested `questions` array, several parameters (`title`, `subtitle`, `contextActions`) receive no semantic coverage anywhere, leaving the definition short of complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 40%, so the description must compensate. It explains the `round` semantics ('how many are left') and maps onto the `questions`/`multiple`/`options` structure via the radios-vs-checkboxes and Other rules, but leaves `title`, `subtitle`, and `contextActions` entirely unexplained in both places.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('ask the fewest multiple-choice questions that close the gaps the gist left') and explicitly positions itself as 'Step 2 of the efficient-prompt flow', which cleanly separates it from the sibling gist and efficient-prompt card tools. An agent can tell what this tool does and where it sits without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states clear usage context ('Step 2 of the efficient-prompt flow') and an explicit exclusion ('Skip this step entirely when the gist is already clear enough to write the prompt'), plus the round cap. It stops short of naming the concrete alternative tools (e.g. the gist card as step 1, the efficient-prompt card as step 3), so the routing is implied by flow position rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_reveal_cardCreate show/hide cardA
Render a card of collapsible show/hide sections with show-all/hide-all buttons. Good for step-by-step guides, FAQs, spoilers, and long reference material. Put source in a section's code field rather than inline in text, so it renders as a monospace block with a copy button instead of a paragraph.
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | ||
| sections | Yes | ||
| subtitle | No | ||
| tutorTerms | No | Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so "PATH" does not attach its tip to a filesystem "path"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text. | |
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose a real render behavior (source placed in a section's code field becomes a monospace block with a copy button rather than a paragraph), which is useful. However it says nothing about permissions, size/length limits, sanitization of html, or other operational traits an agent would need.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with what renders first, then use cases, then a practical placement tip. Nothing is wasted, though the final tip is narrow enough that it slightly dilutes the otherwise clean structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. The description covers the core capability plus one important param behavior, and the complex tutorTerms/contextActions params are richly documented in the schema. It is largely sufficient, with only sibling-routing detail missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is low (40%) so the description must compensate. It adds meaningful semantics for the code field (monospace rendering plus copy button) versus the text field, partially closing the gap. The remaining params (title, subtitle, and the 'open' behavior behind show-all/hide-all) get no explanation, and tutorTerms/contextActions rely entirely on their schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Render) and a precise resource (a card of collapsible show/hide sections with show-all/hide-all buttons), which is clearly distinguishable from sibling card types like animation, chart, table, or markdown cards. An agent can identify this tool without opening sibling schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use guidance ('step-by-step guides, FAQs, spoilers, and long reference material'), which helps selection. It stops short of naming which sibling card to prefer for adjacent scenarios or any exclusion conditions, so it lacks explicit alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_tab_cardCreate tab cardA
Render an interactive card with tabs, each showing a different context of the same subject (for example one tab per programming language, OS, or skill level). Tab content can be plain text, HTML, or code with a copy button.
| Name | Required | Description | Default |
|---|---|---|---|
| tabs | Yes | ||
| title | Yes | ||
| subtitle | No | ||
| tutorTerms | No | Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so "PATH" does not attach its tip to a filesystem "path"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text. | |
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It discloses useful rendering behavior (interactive tabs, copy button for code, plain text/HTML/code content), but says nothing about persistence, side effects, permissions, size limits, or how tutorTerms/contextActions behave at runtime beyond what the schema already documents.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, front-loaded with the what and immediately followed by the concrete example and content-type capabilities. No filler, no restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return format need not be explained, and the rich schema descriptions cover tutorTerms and contextActions. The description sufficiently explains the card's purpose and content model, though it leaves the role of subtitle and the educational/context-action features entirely to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Top-level schema coverage is only 40% (title and subtitle undocumented in schema), and the description partially compensates by describing tab content types (text/HTML/code-with-copy-button), which maps to the tab item properties. However, it adds nothing about title, subtitle, or how tutorTerms/contextActions interact with the rendered card beyond what the schema already says. Baseline 3 for low coverage with partial compensation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Render') and resource ('interactive card with tabs') and explains the organizing concept: one tab per context of the same subject. It is distinguishable in substance from card siblings like create_chart_card or create_markdown_card, though it never explicitly names or contrasts them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The example ('one tab per programming language, OS, or skill level') implies the use case and content-type fit, but there is no explicit when-to-use guidance, no conditions for choosing this over create_code_tour_card or create_markdown_card, and no prerequisites stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_table_cardCreate table cardA
Render an HTML table card from explicit rows, or convert loosely delimited text into a balanced table (delimiter auto-detected; newlines can mark cells). URL cells become links.
| Name | Required | Description | Default |
|---|---|---|---|
| rows | No | Explicit cell data, row-major | |
| text | No | Raw text to convert when rows are not given | |
| title | Yes | ||
| caption | No | ||
| columns | No | ||
| headers | No | Column titles; padded if fewer than columns | |
| subtitle | No | ||
| tutorTerms | No | Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so "PATH" does not attach its tip to a filesystem "path"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text. | |
| linkColumns | No | ||
| cellDelimiter | No | ||
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose real behavior: delimiter auto-detection, newlines as cell markers, and URL cells becoming links. However it is silent on the other high-impact behaviors that only the schema hints at (linkColumns, cellDelimiter override, tutorTerms underlining, contextActions, the 12-column cap), so coverage is partial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences, front-loaded with the primary action, no filler. Every clause carries information (input modes, delimiter detection, newline cells, URL linking).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be described, but for an 11-parameter tool with no annotations the description omits several non-obvious parameters (tutorTerms, contextActions, linkColumns) and never signals the non-destructive nature of the operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 45%, so the description must compensate; it clarifies rows, text, delimiter auto-detection, and newline handling, but leaves title, caption, subtitle, columns, headers, linkColumns, tutorTerms, and contextActions unaddressed in prose. Partial compensation over an incomplete schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Render') and resource ('HTML table card') and enumerates both input modes: explicit rows vs. converting loosely delimited text. The 'table card' resource is clearly distinguishable from sibling card tools like create_list_card and create_chart_card even though no sibling is named.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies which of the two main inputs to supply ('from explicit rows, or convert ... text'), which is useful conditional guidance, but it never states when to choose a table card over alternatives such as create_list_card or create_markdown_card, and gives no prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_video_cardCreate video cardA
Render a card with an HTML video player for a short clip. src must point straight at a video file (mp4/webm): a direct http(s) URL, a small data:video/* URI, or a blob: URL. Streaming platform page URLs (YouTube, Vimeo, Twitch, TikTok, and similar) are REJECTED, because a video element pointed at a player page renders a card that can never play. When no direct video source exists, use create_animation_card to generate an animated clip instead.
| Name | Required | Description | Default |
|---|---|---|---|
| src | Yes | Direct http(s) URL to a video file, a data:video/* URI, or a blob: URL | |
| loop | No | ||
| muted | No | ||
| title | Yes | ||
| poster | No | Still image shown before playback: http(s) URL or data:image/* URI | |
| autoplay | No | Start muted playback on render | |
| subtitle | No | ||
| description | No | ||
| contextActions | No | Right-click menu actions the model anticipates being useful. Choosing one sends its prompt to the conversation; use {{selection}} to include the user's selected text. |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden, and it does well: it discloses a hard validation rule (platform page URLs rejected), the accepted source forms, and the rationale (a video element on a player page can never play). It does not cover auth/permission needs or persistence, but the failure-mode disclosure is substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core purpose, then the constraint, then the fallback. No filler; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. The description covers the decisive routing constraint and the fallback path, leaving only secondary parameter behavior to the schema, which is acceptable for a card renderer.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 44% (<50%), so the description must compensate. It adds strong meaning for the critical 'src' parameter (accepted formats mp4/webm, http(s)/data:/blob:, rejected platforms) but says nothing about loop, muted, poster, autoplay, subtitle, or contextActions, leaving most parameters to the sparse schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Render a card') plus resource ('HTML video player for a short clip') and implicitly separates itself from the sibling create_animation_card. An agent can distinguish this from other card-creation tools immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it (direct video file sources), when NOT to use it (streaming platform page URLs are REJECTED), and names the alternative (create_animation_card) with the condition that selects it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_referenceFetch reference siteB
Fetch a public web page and return structured data: title, description, headings, readable text, tables, images, links, and form specifications. Feed the results into the card tools (tables into create_table_card, numbers into create_chart_card, and so on).
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| maxTextChars | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that the tool returns structured data fields (title, headings, tables, etc.), which gives some behavioral insight. It does not mention failure modes, rate limits, authentication needs, or what happens with inaccessible pages, and annotations are absent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured, with the action stated first and the output details and downstream usage mentioned efficiently. No redundant or verbose content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description gives a clear high-level purpose and output format, and it hints at downstream integration. However, it lacks details about constraints on input, error behavior, or the depth of the structured extraction, leaving some contextual gaps for an agent deciding whether to invoke the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides no per-parameter descriptions. The description mentions 'maxTextChars' indirectly through the structured data output, but it does not explain the meaning of the parameter, its unit, or the effect of the minimum/maximum constraints. The 'url' parameter is obvious from context but not formally described.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the specific action 'Fetch a public web page' and distinguishes the tool from siblings by explaining that results feed into card tools. It does not explicitly name sibling tools it differs from, but the downstream use case clarifies its role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool—when needing structured web content for card creation—but does not explicitly state when not to use it or how it compares to alternatives like read_local_file. The 'and so on' phrase is vague about the full range of downstream tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_insert_bookmarkletGet the Insert Card bookmarkletA
Return the Insert Card bookmarklet and usage instructions. Browsers do not let page script extend the native right-click menu, so this bookmarklet is how a copied card gets placed visually: after the user copies a card (right-click menu "Copy card" or the header button), running the bookmarklet on the host page shows an "Insert Card" item beside every right-click, which injects the copied card at that spot. The insertion is cosmetic and page-local (gone on reload, not part of the conversation history). Call this when the user asks how to place a card at an arbitrary spot on the page.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It thoroughly discloses the bookmarklet's behavior: insertion is cosmetic, page-local, gone on reload, and not part of conversation history. It also clarifies the prerequisite step (copying a card) and the mechanism (right-click menu). This is exemplary transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, dense sentence that front-loads the purpose, then explains the mechanism and context. Every clause earns its place, providing essential context without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has no output schema, but the description fully covers what the agent needs: what the tool returns, when to call it, why it's needed, and the behavior of the result. There are no gaps for a 0-parameter retrieval tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. The description adds context about the tool's invocation but not parameter semantics since there are none. This matches the rubric for a 0-parameter tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: to return the Insert Card bookmarklet and usage instructions. It explicitly names the verb 'Return' and the resource 'bookmarklet', and distinguishes it from sibling tools (which create cards or handle files) by explaining the specific scenario it addresses.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit usage guidance: 'Call this when the user asks how to place a card at an arbitrary spot on the page.' It also explains the underlying context (browser limitation) and why the bookmarklet is needed, leaving no ambiguity about when to invoke it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mirror_web_formMirror a website formA
Fetch a public web page, extract one of its forms, and render it as an interactive card in the conversation. When the user submits the card, the values return to the chat as a structured payload for the submit_web_form tool, so a model-created task can submit the actual website form.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| title | No | Card title override | |
| formIndex | No | Which form on the page, default 0 |
Output Schema
| Name | Required | Description |
|---|---|---|
| card | Yes | |
| parts | Yes | Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld. |
| display | No | Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does disclose a genuinely non-obvious trait: the card is interactive, and on submit the values return to the chat as a structured payload routed to submit_web_form. The word "public" implicitly flags that no authentication is available. It does not cover failure modes (JS-rendered forms, unreachable pages) or any rate limiting.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, with the core action stated first and the downstream handoff second. Every clause adds information the agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is rightly omitted, and the description supplies the workflow context an unannotated tool needs. Minor gaps remain around error behavior and whether non-public or login-gated pages are rejected, but nothing essential to a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67% with url fully specified as a URI, and title/formIndex already documented in the schema. The description adds only marginal semantics — "public web page" constrains url, and "one of its forms" loosely maps to formIndex, but it never mentions the title override. Roughly baseline for partially-covered params.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a precise verb chain — fetch a public page, extract one of its forms, render it as an interactive card — which is clearly distinct from sibling tools like create_form_card (builds a card from scratch) and fetch_reference (plain fetch). It even names submit_web_form as the downstream consumer, so the agent can place this tool in the workflow without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The use case is explicit: mirror a real website's form so a model-created task can submit it. The description explains the full round trip, ending with submit_web_form. It falls short of naming when *not* to use it (e.g., versus fetch_reference or create_form_card for non-web forms), which keeps it out of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_local_fileRead a local fileA
Read a text file from the filesystem OF THE MACHINE RUNNING THIS SERVER so its content can be reviewed and plugged into cards. Over a remote bridge that is not the caller's sandbox: a file you generated on your side is not visible here, so pass its text to the card tool directly. Size-capped; binary files are refused. Set MCP_CHAT_CARDS_FS_ROOT to confine reads to one directory.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| maxChars | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses size caps, binary refusal, and filesystem confinement, which are critical behavioral traits. It doesn't detail error handling or exact return format, but the key constraints are well covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, with each sentence adding value: purpose, remote bridge caveat, size/binary limits, and configuration. It's front-loaded with the core purpose and efficiently covers all key points without fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read tool with two parameters and no output schema, the description covers purpose, constraints, and configuration. It lacks explicit return format details, but given the tool's simplicity and the absence of an output schema, the description is largely sufficient for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It explains the 'path' parameter's context (server filesystem) and implies 'maxChars' via size caps, though it doesn't explicitly name maxChars. The description adds meaning beyond the bare schema, but could be more explicit about maxChars.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reads a text file from the server's filesystem for review and card integration. It distinguishes itself from siblings by focusing on local file access, which is unique among the listed card creation and web tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly warns about remote bridge scenarios, advising to pass text directly to the card tool instead. It also mentions size caps and binary refusal, and provides configuration guidance via MCP_CHAT_CARDS_FS_ROOT, giving clear when-to-use and when-not-to-use context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_web_formSubmit a website formA
Submit values to a real website form (form-encoded GET or POST). Only call this with data the user entered in a mirrored form card, or values the user explicitly confirmed. Returns the HTTP status and a snippet of the response.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | Form action URL | |
| fields | Yes | Field name to value map | |
| method | No | ||
| headers | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states the action (submit values), the encoding, and the return (HTTP status and snippet). However, it does not disclose potential side effects (e.g., submitting data could mutate server state) or mention authorization, rate limiting, or failure behavior. The clause 'real website form' hints at an actual external action, but more explicit disclosure would be safer for an agent. The constraint on when to call it is a good behavioral trait.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that front-loads the purpose and includes the usage constraint and return format. It is concise with no filler. The critical usage condition is placed early, making it easy for an agent to parse. Slightly more structure (e.g., separating the return statement) could improve readability, but as is, it is efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has four parameters, two of which are nested objects, and no output schema, so the description must cover operational context. It states what it does, when to call it, and what it returns. However, it lacks guidance on error handling, side effects, or details about the structure of 'fields' and 'headers' beyond schema descriptions. Given the absence of annotations, an agent would benefit from explicit notes about the potential mutating nature of submitting a form. It is adequate but not comprehensive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides descriptions for 'action' and 'fields' but not for 'method' or 'headers' (50% coverage). The description adds 'form-encoded GET or POST,' which clarifies the method parameter's purpose and its encoding format. However, it does not add meaning for 'headers' or provide additional detail on how 'fields' should be structured beyond the schema. Since the schema already documents half the parameters and the description clarifies method encoding, it meets the baseline but does not fully compensate for the undocumented parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Submit' and the resource 'a real website form,' and specifies the encoding ('form-encoded GET or POST'). It distinguishes itself from the sibling card-creation tools by emphasizing this is an actual submission, and the reference to 'mirrored form card' implicitly connects it to mirror_web_form. Specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear condition for use: 'Only call this with data the user entered in a mirrored form card, or values the user explicitly confirmed.' This provides a strong guardrail. It doesn't explicitly name alternatives or say when not to use it, but the constraint implies it should be used only after mirror_web_form and with user consent. Evidence: 'Only call this...'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unpack_archiveUnpack a zip archiveA
List a zip archive's entries and return the contents of its text files, so a project can be inspected and turned into cards (code tours, tables, walkthroughs). The path is resolved ON THE MACHINE RUNNING THIS SERVER, not in the caller's sandbox. Build caches and binary entries are skipped.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| include | No | Only include entries whose path contains one of these substrings | |
| maxFiles | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It does well: it explains that the path is resolved on the server machine, not in the caller's sandbox, and that build caches and binary entries are skipped. It does not mention permissions, rate limits, or whether anything is written to disk, but the core behaviors are covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, all carrying substantive information. The main behavior is stated first, followed by the important environment safety note and the skip policy. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is sufficiently complete for a moderately simple tool: it defines the operation, the environment constraint, and the filtering behavior. No output schema exists, but because the description says 'return the contents of its text files', the return concept is explained reasonably. It does not specify the output format or potential edge cases, but these are minor gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is low (33%), but the description adds critical semantics for the required 'path' parameter by emphasizing server-side resolution. The 'include' parameter already has a schema description; maxFiles only has numeric bounds, but the tool's purpose implies it limits the number of inspected files. The description partially compensates but does not fully document all parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'List a zip archive's entries and return the contents of its text files.' This is unambiguous and clearly distinguishes the tool from siblings like read_local_file by describing a zip-inspection workflow.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The described use case—'so a project can be inspected and turned into cards'—gives clear context for when to call this tool. It does not explicitly name alternative tools or state when not to use it, but the purpose is obvious enough for an agent to choose it appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
14 tool updates
v1.0.0-alpha.1.0.1- Changed
create_animation_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_chart_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_code_tour_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_efficient_prompt_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_form_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_list_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_markdown_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_prompt_gist_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_prompt_refine_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_reveal_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_tab_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_table_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
create_video_card1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
- Changed
mirror_web_form1 field changed- added
Output schema / properties / displayAdded value: +{ + "additionalProperties": false, + "description": "Present only when the host is not mounting this server's MCP Apps template (see MCP_CHAT_CARDS_RENDER): the card ships as a ready-made visualizer widget instead.", + "properties": { + "action": { + "description": "What the caller must do to put the card in front of the user", + "type": "string" + }, + "loading_messages": { + "description": "show_widget loading_messages", + "items": { + "type": "string" + }, + "type": "array" + }, + "shown": { + "description": "False: the user cannot see this card until action is taken", + "type": "boolean" + }, + "title": { + "description": "show_widget title (snake_case)", + "type": "string" + }, + "widget_code": { + "description": "show_widget widget_code, passed unchanged", + "type": "string" + } + }, + "required": [ + "shown", + "action", + "title", + "loading_messages", + "widget_code" + ], + "type": "object" +}
3 tool updates
v0.2.0-alpha- Added
create_efficient_prompt_card - Added
create_prompt_gist_card - Added
create_prompt_refine_card
16 tool updates
v0.1.3-alpha- Changed
create_animation_card6 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so \"PATH\" does not attach its tip to a filesystem \"path\"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text." - added
Input schema / properties / tutorTerms / items / properties / caseInsensitiveAdded value: +{ + "description": "Match the term regardless of letter case (default false)", + "type": "boolean" +} - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_chart_card6 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so \"PATH\" does not attach its tip to a filesystem \"path\"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text." - added
Input schema / properties / tutorTerms / items / properties / caseInsensitiveAdded value: +{ + "description": "Match the term regardless of letter case (default false)", + "type": "boolean" +} - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_code_tour_card7 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - changed
Input schema / properties / part / descriptionPrevious value: -"Part number for large projects (1-based). Big tours split automatically; when the result says more parts remain, call again with the next part."New value: +"Part number for large projects (1-based). Big tours split automatically; while structuredContent.parts.hasMore is true, call again with the next part." - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so \"PATH\" does not attach its tip to a filesystem \"path\"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text." - added
Input schema / properties / tutorTerms / items / properties / caseInsensitiveAdded value: +{ + "description": "Match the term regardless of letter case (default false)", + "type": "boolean" +} - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_form_card4 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_list_card6 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so \"PATH\" does not attach its tip to a filesystem \"path\"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text." - added
Input schema / properties / tutorTerms / items / properties / caseInsensitiveAdded value: +{ + "description": "Match the term regardless of letter case (default false)", + "type": "boolean" +} - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_markdown_card7 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - changed
Input schema / properties / part / descriptionPrevious value: -"Part number for large documents (1-based). Long documents split automatically; when the result says more parts remain, call again with the next part."New value: +"Part number for large documents (1-based). Long documents split automatically; while structuredContent.parts.hasMore is true, call again with the next part." - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so \"PATH\" does not attach its tip to a filesystem \"path\"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text." - added
Input schema / properties / tutorTerms / items / properties / caseInsensitiveAdded value: +{ + "description": "Match the term regardless of letter case (default false)", + "type": "boolean" +} - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_reveal_card10 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Input schema / properties / sections / items / properties / codeAdded value: +{ + "description": "Code sample shown with a copy button", + "type": "string" +} - added
Input schema / properties / sections / items / properties / html / descriptionAdded value: +"HTML content (sanitized)" - added
Input schema / properties / sections / items / properties / languageAdded value: +{ + "description": "Language for the code sample", + "type": "string" +} - added
Input schema / properties / sections / items / properties / text / descriptionAdded value: +"Plain text content; ``` fenced blocks become code blocks" - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so \"PATH\" does not attach its tip to a filesystem \"path\"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text." - added
Input schema / properties / tutorTerms / items / properties / caseInsensitiveAdded value: +{ + "description": "Match the term regardless of letter case (default false)", + "type": "boolean" +} - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_tab_card6 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so \"PATH\" does not attach its tip to a filesystem \"path\"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text." - added
Input schema / properties / tutorTerms / items / properties / caseInsensitiveAdded value: +{ + "description": "Match the term regardless of letter case (default false)", + "type": "boolean" +} - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_table_card6 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Matching is CASE-SENSITIVE, so \"PATH\" does not attach its tip to a filesystem \"path\"; set caseInsensitive on a term to match any casing. Term and tip are PLAIN text." - added
Input schema / properties / tutorTerms / items / properties / caseInsensitiveAdded value: +{ + "description": "Match the term regardless of letter case (default false)", + "type": "boolean" +} - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
create_video_card4 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
fetch_reference1 field changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
get_insert_bookmarklet1 field changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
mirror_web_form4 fields changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - removed
Output schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#" - added
Output schema / properties / partsAdded value: +{ + "additionalProperties": false, + "description": "Split state, present on EVERY card result so one completeness check works for all card types. Cards that cannot split always report {current:1,total:1,hasMore:false}; create_markdown_card and create_code_tour_card pack oversized content into parts and can report more. Read hasMore rather than the card title to decide whether content was withheld.", + "properties": { + "current": { + "description": "Part number this result rendered (1-based)", + "type": "number" + }, + "hasMore": { + "description": "True when content was withheld; call again with part: current + 1", + "type": "boolean" + }, + "total": { + "description": "How many parts the content splits into", + "type": "number" + } + }, + "required": [ + "current", + "total", + "hasMore" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "card" -]New value: +[ + "card", + "parts" +]
- Changed
read_local_file1 field changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
submit_web_form1 field changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
- Changed
unpack_archive1 field changed- removed
Input schema / $schemaRemoved value: -"http://json-schema.org/draft-07/schema#"
9 tool updates
v0.1.1-alpha- Changed
create_animation_card1 field changed- changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. Occurrences in the card are underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."
- Changed
create_chart_card1 field changed- changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. Occurrences in the card are underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."
- Changed
create_code_tour_card3 fields changed- changed
Input schema / properties / archivePath / descriptionPrevious value: -"Path to a local zip; its text files become tabs"New value: +"Path to a zip ON THE MACHINE RUNNING THIS SERVER, not in the caller's sandbox. Over a remote bridge those are different machines: if the archive exists only on your side, pass its text files as files instead." - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. Occurrences in the card are underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text." - added
Input schema / properties / tutorTermsInCodeAdded value: +{ + "description": "Also highlight tutorTerms inside the code samples. Off by default, because marking up language keywords in source is noise rather than teaching.", + "type": "boolean" +}
- Changed
create_list_card1 field changed- changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. Occurrences in the card are underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."
- Changed
create_markdown_card2 fields changed- changed
Input schema / properties / path / descriptionPrevious value: -"Path to a local markdown file to render instead"New value: +"Path to a markdown file ON THE MACHINE RUNNING THIS SERVER, not in the caller's sandbox. Over a remote bridge those are different machines: if the file exists only on your side, pass its text as markdown instead." - changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. Occurrences in the card are underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."
- Changed
create_reveal_card1 field changed- changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. Occurrences in the card are underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."
- Changed
create_tab_card1 field changed- changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. Occurrences in the card are underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."
- Changed
create_table_card1 field changed- changed
Input schema / properties / tutorTerms / descriptionPrevious value: -"Educational tutor terms. Occurrences in the card are underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up."New value: +"Educational tutor terms. The first occurrence of each term in the card's visible prose is underlined; hovering ~1.2s shows the tip and notifies the host so the model can follow up. Terms are matched once per card, longest first, and never inside code samples, tooltips, or another term's tip. Term and tip are PLAIN text."
- Changed
create_video_card7 fields changed- added
Input schema / properties / autoplayAdded value: +{ + "description": "Start muted playback on render", + "type": "boolean" +} - added
Input schema / properties / poster / descriptionAdded value: +"Still image shown before playback: http(s) URL or data:image/* URI" - removed
Input schema / properties / poster / formatRemoved value: -"uri" - added
Input schema / properties / poster / minLengthAdded value: +1 - added
Input schema / properties / src / descriptionAdded value: +"Direct http(s) URL to a video file, a data:video/* URI, or a blob: URL" - removed
Input schema / properties / src / formatRemoved value: -"uri" - added
Input schema / properties / src / minLengthAdded value: +1
2 tool updates
v0.1.0-alpha- Added
create_animation_card - Added
get_insert_bookmarklet
14 tool updates
v0.0.0-alpha- First observed
create_chart_card - First observed
create_code_tour_card - First observed
create_form_card - First observed
create_list_card - First observed
create_markdown_card - First observed
create_reveal_card - First observed
create_tab_card - First observed
create_table_card - First observed
create_video_card - First observed
fetch_reference - First observed
mirror_web_form - First observed
read_local_file - First observed
submit_web_form - First observed
unpack_archive
TDQS
Scored across 19 tools
Most card tools target distinct content types (table, chart, list, video, animation, form), and descriptions actively steer between close pairs like animation vs video and tab vs code-tour. Minor overlap remains: create_tab_card and create_code_tour_card both render tabbed content, and create_markdown_card folds H2s into reveals like create_reveal_card, so a few boundaries require reading the descriptions carefully.
The dominant create_*_card pattern (create_table_card, create_chart_card, etc.) is highly predictable, and the non-card tools follow verb_noun (fetch_reference, submit_web_form, unpack_archive). Minor deviations like create_efficient_prompt_card vs create_prompt_gist_card/create_prompt_refine_card break the pattern slightly but stay readable.
19 tools sits at the upper end but is justified by genuinely diverse needs: ~10 distinct card renderers plus input ingest (fetch/read/unpack), a 3-step prompt flow, and a 3-tool form flow. Each tool appears to earn its place, though the surface is on the heavier side.
The surface covers a wide card lifecycle (animation, tab, table, chart, video, reveal, list, markdown, code tour, form) plus data ingestion and form submission, with no obvious dead ends. Only marginal gaps remain, such as a dedicated image/plain-text card, which the animation and markdown tools partly absorb.
Maintenance
Related MCP Connectors
Publish, edit, share and track HTML docs and decks from chat, with view analytics.
Renders interactive Chart.js charts and dashboards inline in AI conversations.
Create, inspect, manage, and render charts and data visualizations as SVG/PNG or interactive embeds.
Publish static websites to a live URL from chat. Write HTML/CSS/JS, get a hosted site and edit link.
Related MCP Servers
- AlicenseAqualityAmaintenanceRenders 45+ interactive chart types, dashboards, and KPI widgets directly inside AI conversations. Supports drill-down, live API polling, 20 themes, and one-click export to PNG, PowerPoint, and A4 documents.40133 npm52Functional Source , Version 1.1, MIT Future
- AlicenseNot gradedqualityCmaintenanceEnables booking flights and hotels, creating investment portfolios, and managing kanban boards directly within a chat interface using generative UI components.3 npmApache 2.0
- AlicenseAqualityBmaintenanceMCP server that lets agents create, display, and export rich UI widgets (cards, dashboards, charts, forms) inline in conversations, with interactive iframe support in MCP Apps hosts and PNG image fallback for other clients.43MIT
- AlicenseNot gradedqualityBmaintenanceEnables agents to turn structured tabular data or CSV/XLSX files into interactive charts that render inline in conversations, with client-adaptive output modes and self-contained HTML.MIT
