MCP Apps¶
The server ships four browser-based views that MCP clients supporting the MCP Apps protocol can render inline or in fullscreen. They are delivered as a single HTML resource at ui://vault/app.html and use visibility="app" so they appear only in supporting clients.
Views¶
Context Card¶
Displays a note dossier for the note currently in focus. Includes:
- Backlinks: other notes that link to this note
- Outlinks: notes this document links to, with existence check
- Similar notes: semantically similar documents (requires embeddings)
- Tags: frontmatter tag values
- Folder peers: other notes in the same folder
- Modification time: last modified timestamp
Click any linked note to open its context card.
Graph Explorer¶
Interactive force-directed link graph of the vault, powered by vis-network. Two modes:
- Neighborhood: shows a note and its direct connections (configurable depth, soft-capped at
max_nodes=200by default; the response carriestruncated=truewhen the BFS hit the cap so the SPA can warn the user) - Hubs: shows the most-linked notes in the vault and their connections
Click a node to view that note's context card. Toggle semantic similarity edges when embeddings are available (semantic edges render as dashed accent-colored lines, distinct from the solid wikilink edges).
Node labels follow a level-of-detail rule. The focus note, its direct neighbors, and hub notes keep their labels; other farther-out notes render as unlabelled dots (their names appear on hover, or once you zoom in past a threshold). A separate hover text with the note's title and backlink count is always available, regardless of zoom level. A count chip in the top-right corner of the canvas reports how many notes are currently visible, next to zoom-in and zoom-out buttons. A legend below the canvas explains the edge and node styles; on a narrow panel it collapses behind an "ⓘ legend" chip to save space.
Vault Browser¶
Searchable, filterable file tree for browsing the vault without issuing tool calls. Features:
- Expandable folder tree
- Real-time search filtering
- Click a note to preview it in the Note tab
Note Preview¶
Full-width markdown preview with:
- Rendered markdown (via marked.js, sanitized with DOMPurify), with the leading frontmatter block stripped so it renders only once
- A Contents popover: an on-this-page table of contents built from the note's headings
- Collapsible frontmatter properties (first few shown, the rest behind a toggle) and collapsible tags
- Copy markdown (the full note, frontmatter included) and Copy vault link (the note's path) buttons
- Send to Claude button: sends the note content to the LLM conversation
- Navigation to Context Card or Graph Explorer for the same note
Tools¶
Two primary tools are exposed to MCP clients:
| Tool | Description |
|---|---|
browse_vault |
Opens the vault explorer SPA; optionally focuses a specific note and view. Returns a text summary for non-Apps clients. |
show_context |
Opens the Context Card for a given note path. |
browse_vault accepts an optional path parameter to focus on a specific note, and a view parameter (context, graph, browse, or note). show_context requires a path parameter.
Six additional app-only tools (prefixed with _vault_) handle data fetching for the SPA views. These are hidden from the LLM and only callable from within the app itself.
Configuration¶
| Variable | Default | Description |
|---|---|---|
MARKDOWN_VAULT_MCP_BASE_URL |
(none) | Public base URL of the server. Required for auto-computing the app domain. |
MARKDOWN_VAULT_MCP_APP_DOMAIN |
(auto) | Override the Claude app domain used for iframe sandboxing. Auto-computed from BASE_URL when not set. |
Domain auto-computation¶
When APP_DOMAIN is not set, the server computes it from BASE_URL and HTTP_PATH:
- Concatenate:
mcp_url = f"{BASE_URL}{HTTP_PATH}" - SHA-256 hash the URL and take the first 32 hex characters
- Result:
{hash_prefix}.claudemcpcontent.com
Override APP_DOMAIN if your deployment is behind a proxy that changes the apparent hostname.
Architecture¶
The SPA is a self-contained HTML file with its JavaScript dependencies vendored at build time (no runtime CDN requests for libraries; web fonts are the one exception, see Visual identity):
| Library | Purpose |
|---|---|
| vis-network | Force-directed graph rendering |
| marked.js | Markdown to HTML rendering |
| DOMPurify | XSS sanitization |
| @modelcontextprotocol/ext-apps | MCP Apps lifecycle, messaging, and theming |
The app integrates with the host client via the ext-apps SDK:
app.callServerTool(): calls app-only tools to fetch dataapp.sendMessage(): sends note content to the LLM conversationapp.updateModelContext(): keeps the LLM aware of which note the user is viewingapp.requestDisplayMode(): requests fullscreen or inline display (auto-expands to fullscreen on first load on desktop and web, but stays inline on mobile)- Adaptive sizing: honors the host's reported container dimensions and safe-area insets. It fills a fixed-height frame with internal scrolling, or, when the host reports a flexible or unbounded frame (as mobile inline hosts and sidebars typically do), grows to its content and reports its height so the host can size the view
- Theme sync: automatically adapts to the host's light/dark theme and CSS variables
Visual identity ("Paper")¶
The views use a warm, editorial "Paper" theme (serif headings, a single warm
accent, light and dark). The Paper palette is expressed as CSS custom properties
that map onto the host's --color-* variables: a host that pushes its own theme
overrides Paper, otherwise the Paper values show. Three font families load from
Google Fonts and are exposed as --font-head / --font-body / --font-mono:
Newsreader styles headings, Public Sans the body and UI, and IBM Plex Mono the
code, property keys, and tags. (As each view is restyled, these families also
reach the remaining mono metadata such as paths and scores.) The fonts are the
one runtime network dependency the app keeps (the vendored libraries are embedded);
if they fail to load, the app falls back to system fonts with no loss of
function.
Source layout and build¶
The SPA source is authored as small partials under
src/markdown_vault_mcp/static/spa/:
| File | Contents |
|---|---|
shell.html |
The HTML document: head, tab bar, view panels, toast |
styles.css |
All styles |
core.js |
App setup, theming, tab navigation, cross-view routing, shared helpers |
views/context.js, views/graph.js, views/browser.js, views/note.js |
One file per view |
Two build steps turn the partials into the served resource:
spa/* -> build_spa.py -> app.src.html -> vendor_spa.py -> app.html
python scripts/build_spa.pyassembles the partials intostatic/app.src.html. Assembly is a recursive/*@@FILE:path@@*/include, a valid comment in both CSS and JavaScript, so each partial stays independently readable.python scripts/vendor_spa.pyembeds the vendored libraries into the self-containedstatic/app.htmlthat the server serves.
app.src.html and app.html are both generated, committed artifacts: edit the
files under static/spa/, then run both scripts. Never hand-edit the generated
files. build_spa.py --check and vendor_spa.py --check fail the build if
either artifact is stale; both run in CI and as pre-commit hooks.
Client support¶
MCP Apps views require a client that supports the MCP Apps protocol. Currently supported by Claude on claude.ai. Clients without Apps support receive a text-only fallback from browse_vault and show_context.
To hide browse_vault and show_context from the tool listing entirely (for clients that never render Apps panels), set MARKDOWN_VAULT_MCP_DISABLE_APPS_UI=true. See Configuration.
Firing prompts from Claude.ai's + menu¶
MCP Apps surface interactive views, but this server also ships MCP prompts (summarize, research, propose-links, and the workflow prompts from the PARA and Zettelkasten packs). On Claude.ai, every prompt appears in the compose area's + menu once the server is added as a connector. Click +, select connectors, pick the server, pick a prompt, and Claude opens with the invocation scaffolded. See How to invoke prompts.