* Add Security docs section, SEO improvements, and doc site enhancements - Add Authorization guide covering per-server and per-tool OAuth patterns - Add CSP & CORS guide extracted from Patterns doc - Group both under a new Security section in the documentation nav - Replace CSP & CORS section in Patterns with cross-reference to new guide - Rename doc site title from package name to 'MCP Apps' - Rename 'Modules' nav section to 'API Documentation' - Ensure Security section appears before API Documentation in TOC - Add SEO plugin with JSON-LD structured data (TechArticle/WebPage) - Add per-page meta descriptions from frontmatter - Add description frontmatter to all documentation pages - Add hostedBaseUrl for sitemap.xml generation and canonical URLs - Normalize document page slugs to lowercase hyphenated format - Update compressed navigation and search index data to match new slugs * Add favicons with light/dark mode support - Download favicons from modelcontextprotocol.io (light + dark variants) - Inject favicon link tags into every page with correct relative paths - Support prefers-color-scheme media queries for light/dark mode - Include apple-touch-icon for iOS - Copy favicon assets to output directory during doc build * Fix HTML sanitization in SEO plugin with proper parser Replace regex-based HTML tag stripping with htmlparser2 for extracting plain-text descriptions from rendered pages. * Add custom theme to align with modelcontextprotocol.io styling - Import Inter and JetBrains Mono fonts (matching MCP site) - Override light mode colors: pure white backgrounds, softer gray borders - Override dark mode colors: match MCP site dark background (#0f1117) - Taller header (3.5rem) with backdrop-blur frosted glass effect - Sidebar: adjusted spacing, font size, and hover/active states - Content: increased line-height (1.6), more heading breathing room - Code blocks: JetBrains Mono, subtle border, more padding - Fix CSS load order: custom.css now loads after theme stylesheets * Align sidebar nav styling with modelcontextprotocol.io - Active item: tinted blue background with blue text (matching MCP's primary-color tinted active state) - Non-active items: muted gray text, subtle hover background - Larger border-radius (0.75rem/rounded-xl) matching MCP sidebar - Group headers: semibold with slight letter spacing - Proper dark mode variants for all states * Fix sidebar active item: dark gray background with bold text * Make sidebar active item more prominent: bolder weight, stronger background * Highlight current page in sidebar nav, normalize code font size Inject a small script via the SEO plugin that marks the active sidebar link with a "current" class (TypeDoc doesn't do this natively for document pages). Uses a MutationObserver since the sidebar is populated asynchronously. Pathname comparison strips .html extensions to support clean-URL servers. Also bumps code/pre font-size from 0.85em to 1em so code snippets match the surrounding body text size. * Split styling into dedicated plugin, fix auth terminology, improve breadcrumbs Extract CSS cascade fix, breadcrumb labels, and sidebar nav highlighting from the SEO plugin into a new typedoc-plugin-mcpstyle.mjs to keep concerns separated. Fix authorization doc: use "authorization" consistently instead of mixing with "authentication", link to MCP spec and RFC 9728 for Protected Resource Metadata, remove redundant spec link paragraph. Rename "Documents" nav section to "Getting Started" and add explicit group frontmatter to all doc pages. Breadcrumbs now show the section name instead of duplicating the page title.
3 KiB
| title | group | description |
|---|---|---|
| CSP and CORS | Security | Configure Content Security Policy and CORS for MCP Apps that make network requests from sandboxed iframes, including connectDomains, resourceDomains, and stable origin setup. |
CSP & CORS
Unlike regular web apps, MCP Apps HTML is served as an MCP resource and runs in a sandboxed iframe with no same-origin server. Any app that makes network requests must configure Content Security Policy (CSP) and possibly CORS.
CSP controls what the browser allows. You must declare all origins in {@link types!McpUiResourceMeta.csp _meta.ui.csp} ({@link types!McpUiResourceCsp McpUiResourceCsp}) — including localhost during development. Declare connectDomains for fetch/XHR/WebSocket requests and resourceDomains for scripts, stylesheets, images, and fonts.
CORS controls what the API server allows. Public APIs that respond with Access-Control-Allow-Origin: * or use API key authentication work without CORS configuration. For APIs that allowlist specific origins, use {@link types!McpUiResourceMeta.domain _meta.ui.domain} to give the app a stable origin that the API server can allowlist. The format is host-specific, so check each host's documentation for its supported format.
// Computes a stable origin from an MCP server URL for hosting in Claude.
function computeAppDomainForClaude(mcpServerUrl: string): string {
const hash = crypto
.createHash("sha256")
.update(mcpServerUrl)
.digest("hex")
.slice(0, 32);
return `${hash}.claudemcpcontent.com`;
}
const APP_DOMAIN = computeAppDomainForClaude("https://example.com/mcp");
registerAppResource(
server,
"Company Dashboard",
"ui://dashboard/view.html",
{
description: "Internal dashboard with company data",
},
async () => ({
contents: [
{
uri: "ui://dashboard/view.html",
mimeType: RESOURCE_MIME_TYPE,
text: dashboardHtml,
_meta: {
ui: {
// CSP: tell browser the app is allowed to make requests
csp: {
connectDomains: ["https://api.example.com"],
},
// CORS: give app a stable origin for the API server to allowlist
//
// (Public APIs that use `Access-Control-Allow-Origin: *` or API
// key auth don't need this.)
domain: APP_DOMAIN,
},
},
},
],
}),
);
Note that _meta.ui.csp and _meta.ui.domain are set in the contents[] objects returned by the resource read callback, not in registerAppResource()'s config object.
Note
For full examples that configures CSP, see:
examples/sheet-music-server/(connectDomains) andexamples/map-server/(connectDomainsandresourceDomains).