One read of Claude Documentationclaude-docs-20260814T092040Z
213 pages moved out of 213 read.
What this read moved
101-125 of 213, page 5 of 9This capture is too large to show at once. Changes 101-125 of 213 are below, significant first; the rest are on the following screens.
connectors/building/mcp First recorded · 72 lines, first recorded
# Model Context Protocol (MCP) ## What is MCP? ## How MCP works ### Local vs remote servers ### Key components ## Security model ### User control ### Tool hints ## Building with MCP ### For developers ### Submitting to directory ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Model Context Protocol (MCP)
> Understanding the open standard powering Claude's connectors
The Model Context Protocol (MCP) is an open standard created by Anthropic for AI applications to connect with tools and data sources.
## What is MCP?
MCP provides a standardized way for AI assistants like Claude to:
* Connect to external tools and services
* Access data from various sources
* Perform actions on behalf of users
* Maintain security and user control
## How MCP works
### Local vs remote servers
| Type | Description | Use Case |
| -------------- | ---------------------- | --------------------------------- |
| **Local MCP** | Runs on your device | Desktop integrations, local tools |
| **Remote MCP** | Hosted on the internet | Web services, cloud applications |
### Key components
* **Tools**: Actions Claude can perform (search, create, modify)
* **Resources**: Data Claude can access (files, documents, records)
* **Prompts**: Predefined interactions for specific tasks
## Security model
### User control
* You authenticate each connector individually
* Permissions mirror your access on the external service
* You can disconnect at any time
### Tool hints
All MCP tools must declare:
* [`readOnlyHint`](https://modelcontextprotocol.io/specification/latest/schema#toolannotations-readonlyhint): Tool only reads data
* [`destructiveHint`](https://modelcontextprotocol.io/specification/latest/schema#toolannotations-destructivehint): Tool can modify or delete data
This helps Claude and users understand what actions are possible.
## Building with MCP
The [MCP documentation](https://modelcontextprotocol.io/docs) is the source of truth for building MCP servers.
### For developers
* Open specification at [modelcontextprotocol.io](https://modelcontextprotocol.io)
* [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) and [Python SDK](https://github.com/modelcontextprotocol/python-sdk) available
* Cloudflare hosting support with OAuth
### Submitting to directory
Organizations can [submit MCP servers](/docs/connectors/building/submission) to the Connectors Directory for broader availability.
## Related topics
<Columns cols={2}>
<Card title="MCP in Claude Code" icon="terminal" href="https://code.claude.com/docs/en/mcp">
Connect MCP servers to Claude Code from the command line.
</Card>
<Card title="Submit to Directory" icon="paper-plane" href="/docs/connectors/building/submission">
Review requirements and submit your connector.
</Card>
</Columns>
connectors/building/mcp-apps/cross-compatibility First recorded · 35 lines, first recorded
# Building cross-platform MCP Apps ## How it works ### Server side ### Client side ## Platform differences ### Domain handling
The first capture of this source. The page was already there, and this is what it said.
# Building cross-platform MCP Apps
> Build MCP Apps that work with both Claude and ChatGPT using a single codebase
MCP Apps can run in both Claude and ChatGPT from a single codebase. The SDK auto-detects the host environment and uses the appropriate transport, though some platform-specific behaviors require attention.
## How it works
### Server side
Use [`registerAppTool()`](https://modelcontextprotocol.github.io/ext-apps/api/functions/server-helpers.registerAppTool.html) and [`registerAppResource()`](https://modelcontextprotocol.github.io/ext-apps/api/functions/server-helpers.registerAppResource.html) to register your tools and resources. These helper functions automatically generate platform-specific metadata, so you write the registration once and it works on both platforms.
### Client side
Call [`App.connect()`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#connect) without an explicit transport parameter. The SDK detects whether it's running in Claude or ChatGPT and uses the appropriate transport automatically.
## Platform differences
While the SDK handles most cross-platform concerns automatically, some behaviors vary between hosts.
### Domain handling
The [`Resource._meta.ui.domain`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceMeta.html#domain) field format and validation rules are determined by each host platform. For example, hosts may use hash-based subdomains, URL-derived patterns, or other formats.
For Claude, compute the `Resource._meta.ui.domain` value by running this command, replacing `https://example.com/mcp` with your server URL:
```shell theme={null}
node -e 'const yourServerUrl = "https://example.com/mcp"; console.log(require("crypto").createHash("sha256").update(yourServerUrl).digest("hex").slice(0,32) + ".claudemcpcontent.com")'
```
Example output for `https://example.com/mcp`:
```
c3d80a4ed901ee05b21755a88273b4a4.claudemcpcontent.com
```
connectors/building/mcp-apps/design-guidelines First recorded · 411 lines, first recorded
# Design guidelines ## Overview ## What makes a good MCP App ## Display modes ### Inline card ### Inline carousel ### Full screen ## Mobile guidelines ### Host context for layout ### Display modes ### Content security policy ### Viewport and layout ### Touch targets ### Scrolling and gestures ### Transitions ### Dark mode ### Loading states ## Visual design ## Interaction patterns ### App vs. chat interactions ### Start simple ### Visible controls over hidden menus ## Accessibility ## Style variables ### Example usage
The first capture of this source. The page was already there, and this is what it said.
# Design guidelines
> Visual and interaction design guidelines for MCP Apps in Claude
## Overview
MCP Apps are interactive interfaces that appear within Claude's conversational flow. Think of them as natural extensions of the conversation, not separate apps that happen to appear alongside it. Your app inherits conversational context and helps users accomplish meaningful tasks without breaking flow.
**Core principles:**
* **Conversational.** Fit naturally into dialogue. Don't force users to learn new interaction patterns.
* **Contextual.** Use conversation history to inform what you display and when.
* **Integrated.** Inherit styling and conventions from the containing environment.
* **Adaptive.** Handle variable sizing, mobile viewports, and diverse accessibility needs gracefully.
<Tip>
See our [Figma UI kit](https://www.figma.com/community/file/1597641111449594397/mcp-apps-for-claude) for components and patterns to help you get started.
</Tip>
## What makes a good MCP App
**Good candidates:**
* Tasks that fit naturally into conversation like data analysis, document review, or project coordination
* Communication and collaboration context like message search results, conversation threads, or team member profiles
* Tasks with a clear start and end like booking, ordering or scheduling
* Information users can act on immediately
* Functionality that extends Claude's capabilities meaningfully
**Patterns to avoid:**
* Long-form or static content better suited for external viewing
* Complex multi-step workflows that exceed the display mode's scope
* Deep navigation (no drill-ins, breadcrumbs, or multiple views)
* Nested scrolling (inline cards should auto-fit content height)
* Menus and popovers (dropdowns, context menus, and popover panels can get clipped by container boundaries or create z-index conflicts with the host UI — prefer visible controls like segmented buttons, toggles, or inline options)
* Chat inputs or conversational UI (don't replicate Claude's features)
## Display modes
### Inline card
Compact components embedded directly in conversation. Good for summaries, confirmations, and quick actions. Keep them focused.
**When to use:**
* Status updates and confirmations
* Simple data displays or selections
* Brief summaries with optional expansion
* Quick actions that continue the conversation
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/inline-card-1.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=0c7825c89be73ad56d0a90e4c979401d" alt="Inline card example showing a compact component" width="1999" height="1423" data-path="images/mcp-apps/inline-card-1.png" />
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/inline-card-2.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=344f114b1012838b4805b48d496201c0" alt="Inline card example showing a data display" width="1999" height="1423" data-path="images/mcp-apps/inline-card-2.png" />
**Constraints:**
* Height: auto-fits to content (no nested scrolling)
* Max actions: 2, placed at the bottom of the card
* Max data points: 4-5
* No drill-ins, breadcrumbs, or multiple views
* No menus or popovers — use visible controls instead
**On mobile:** Inline cards render full-width within the conversation. Ensure all tap targets are at least 44pt. Content should adapt to narrower viewports without horizontal scrolling.
<img src="https://mintcdn.com/claude-ai/sLZLADaApRAVEV6C/images/mcp-apps/inline-card-mobile.png?fit=max&auto=format&n=sLZLADaApRAVEV6C&q=85&s=3d2afa48da4f1d31cce9c0bb91a18807" alt="Inline card mobile examples" width="1999" height="838" data-path="images/mcp-apps/inline-card-mobile.png" />
### Inline carousel
Side-by-side items for browsing options. Users swipe or scroll horizontally to explore.
**When to use:**
* Product listings or search results
* Location or venue options
* Media galleries
* Any set of comparable items
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/inline-carousel-1.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=ef6b5615726ad25708ebdedf586226ae" alt="Inline carousel example showing browsable items" width="1999" height="1423" data-path="images/mcp-apps/inline-carousel-1.png" />
**Constraints:**
* 3-8 items for scannability
* Each card: image + title + metadata (max 3 lines) + optional CTA
* 1 optional CTA per card
* Maintain consistent card dimensions within a carousel
* Cards should have consistent visual hierarchy
**On mobile:** Carousel cards are optimized for horizontal swipe. Design for thumb reach — keep primary actions in the lower portion of cards. Peek the next card to signal scrollability.
<img src="https://mintcdn.com/claude-ai/sLZLADaApRAVEV6C/images/mcp-apps/inline-carousel-mobile.png?fit=max&auto=format&n=sLZLADaApRAVEV6C&q=85&s=2bf64edd4fdefe8a37188ca4f2f32f4e" alt="Inline carousel mobile examples" width="1999" height="1022" data-path="images/mcp-apps/inline-carousel-mobile.png" />
### Full screen
Immersive interfaces for complex interactions. The conversation composer remains available so users can continue talking to your app through Claude. Apps provide their own fullscreen button. A close button appears in the native header bar when in fullscreen mode. In fullscreen mode, avoid the use of floating panels. Use collapsible sidebars, tabs or pagination to disclose details.
**When to use:**
* Data visualizations and dashboards
* Detailed analysis tools
* Document editing
* Content that benefits from focused attention
* Rich tasks requiring more space than inline allows
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/fullscreen-1.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=a4b491bb475bab8ed146c1bc953516ec" alt="Full screen mode example" width="1999" height="1423" data-path="images/mcp-apps/fullscreen-1.png" />
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/fullscreen-2.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=8523c5ae46ab7492586044ff5fabea32" alt="Full screen mode with data visualization" width="1999" height="1423" data-path="images/mcp-apps/fullscreen-2.png" />
**Constraints:**
* Your app provides its own fullscreen button; a close button appears in the native header bar
* The composer is always visible — design your UX to work with it
* No floating panels — use collapsible sidebars, tabs, or pagination to disclose details
* Chat sheet maintains conversational context
**On mobile:** Your app fills the entire screen with the chat input and navigation bar overlaid on top, so keep critical UI within the safe area. Use the full viewport width and support both portrait and landscape where it makes sense.
<img src="https://mintcdn.com/claude-ai/sLZLADaApRAVEV6C/images/mcp-apps/fullscreen-mobile.png?fit=max&auto=format&n=sLZLADaApRAVEV6C&q=85&s=d2802346090fd1a7af6a1bdc1d7c3263" alt="Full screen mobile examples" width="1999" height="716" data-path="images/mcp-apps/fullscreen-mobile.png" />
## Mobile guidelines
MCP apps on mobile share the same principles as web, but the constrained viewport and touch-based interaction require specific adaptations.
On mobile, Claude renders apps in a native WebView (WKWebView on iOS, WebView on Android) rather than a sandboxed iframe. Current mobile-only constraints: no camera/mic/location access, and connectors must be added via web or desktop before they appear on mobile.
### Host context for layout
The host passes layout hints via `hostContext`.
**Safe areas.** The interactive portion of your app should be rendered inside of the safe area to ensure it's not obscured by the mobile navigation bar or chat input and respects the chat screen's content margins. The user won't be able to interact with anything rendered outside the safe area (e.g. buttons obscured by a mobile navigation bar). Read `hostContext.safeAreaInsets.{top, right, bottom, left}` (in pixels) and apply them as padding on your root container, or as `scroll-padding` on scroll-snap containers so items come to rest inside the visible region. Safe areas are not mobile-specific: on web and desktop the composer can overlay the bottom of an inline app, so avoid placing interactive controls flush against any edge.
<img src="https://mintcdn.com/claude-ai/sLZLADaApRAVEV6C/images/mcp-apps/safe-area-fullscreen.png?fit=max&auto=format&n=sLZLADaApRAVEV6C&q=85&s=d789bcbba50a3bff53d677478421de30" alt="Safe area insets in full screen mode on web and mobile" width="1999" height="1153" data-path="images/mcp-apps/safe-area-fullscreen.png" />
**Borderless inline.** Set `_meta.ui.prefersBorder` to true or false to explicitly determine whether your content should render with a border. If no value is specified, content will be rendered borderless on web and bordered on mobile. In borderless mode your content runs edge-to-edge with no host padding, so honoring `safeAreaInsets` becomes essential; the bordered card's built-in padding otherwise absorbs most of them. Borderless works well for carousels and other horizontally-scrolling content that should bleed to the screen edges while in motion: apply `safeAreaInsets.left` and `.right` as `scroll-padding-inline` on the scroll container so items at rest sit clear of the device edges, but can scroll underneath them.
<img src="https://mintcdn.com/claude-ai/sLZLADaApRAVEV6C/images/mcp-apps/safe-area-borderless-mobile.png?fit=max&auto=format&n=sLZLADaApRAVEV6C&q=85&s=9936d8064beb2fc37e39b10ab1e727a9" alt="Safe area insets for borderless inline apps on mobile" width="1999" height="1857" data-path="images/mcp-apps/safe-area-borderless-mobile.png" />
Apps always fill the container width—there are no fixed breakpoints. Design responsively from 320px up to fullscreen using container queries and the hostContext CSS variables.
### Display modes
Declare which modes your app supports via `appCapabilities.availableDisplayModes` in `ui/initialize`. The host responds with the modes it supports, and your app can request a switch with `ui/request-display-mode`. Modes are `inline`, `fullscreen`, and `pip`.
### Content security policy
Declare external origins per `ui://` resource via `_meta.ui.csp`:
```json theme={null}
{
"_meta": {
"ui": {
"csp": {
"connectDomains": ["https://api.example.com"],
"resourceDomains": ["https://cdn.example.com"],
"baseUriDomains": []
}
}
}
}
```
By default, all external origins are blocked. `frameDomains` (embedding third-party iframes) is currently restricted in Claude pending security review.
### Viewport and layout
* Design for variable widths (320pt minimum, up to tablet)
* Respect safe areas on notched devices
* Full-width layouts — don't add side margins that waste mobile screen real estate
* Content should reflow gracefully; avoid fixed-width layouts
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/mobile-viewport-layout.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=d2244b6ff7e2d6c5e7b2c36fd2d901ed" alt="Viewport and layout do's and don'ts" width="1718" height="1238" data-path="images/mcp-apps/mobile-viewport-layout.png" />
### Touch targets
* Minimum tap target: 44 x 44pt (per Apple HIG / Material guidelines)
* Add sufficient spacing between interactive elements to prevent mis-taps
* Prefer larger, thumb-friendly buttons over small text links
* Place primary actions within natural thumb reach (lower portion of screen)
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/mobile-touch-targets.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=95bd5b4393d85a67b74e894331d5f4b0" alt="Touch target do's and don'ts" width="1718" height="1238" data-path="images/mcp-apps/mobile-touch-targets.png" />
### Scrolling and gestures
On mobile touch devices, the conversation view owns vertical scrolling. When your app is rendered inline, vertical pan gestures that start inside it are passed to the conversation scroll instead of to your content. This keeps a tall widget from trapping the user and is why inline apps should fit their content height rather than relying on an internal vertical scroll container—the host caps inline height and clips content that exceeds it.
Horizontal gestures (ex: carousels or panning a map) and taps work normally.
If your app genuinely needs its own vertically scrollable viewport, request fullscreen presentation with `ui/request-display-mode` instead of rendering inline (see [Full screen](#full-screen)).
### Transitions
* Inline cards expand to fullscreen with a smooth transition
* Provide a clear visual affordance for expansion (fullscreen button or tap-to-expand)
* Fullscreen close returns to the conversation at the same scroll position
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/mobile-transitions.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=343fe75a1428c1874568c10e02de9aa8" alt="Transition from inline card to full screen" width="1718" height="1222" data-path="images/mcp-apps/mobile-transitions.png" />
### Dark mode
All views must support both light and dark themes. Use the host's style tokens — they automatically adapt. Never hardcode colors. Test both modes.
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/mobile-dark-mode.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=79df1abf42e75b052ad7c28ac71c4413" alt="Dark mode examples on mobile" width="1999" height="1315" data-path="images/mcp-apps/mobile-dark-mode.png" />
### Loading states
Show skeleton screens while content loads. Match the layout structure of the final content so the transition feels seamless. Avoid spinners for inline content — skeletons feel more native.
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/mobile-loading-states.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=9e7df0fa2294bbcbcc24bf079cbc5ff6" alt="Loading state examples on mobile" width="1718" height="1130" data-path="images/mcp-apps/mobile-loading-states.png" />
## Visual design
MCP Apps should feel native to their environment while maintaining consistent visual hierarchy and accessibility standards. You can still express your brand through accent colors, custom controls and content.
**Design guidance**
**Color.** Use host tokens for all structural elements: backgrounds, text, borders, icons. You can use your own brand colors for accents and identity, but the core UI should use the provided palette.
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/color-tokens.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=173ce1948ae87b9e72b0854b5d27f4e1" alt="Color token examples for light and dark mode" width="1999" height="1863" data-path="images/mcp-apps/color-tokens.png" />
**Typography.** Stick to the three-level size scale (heading, body, caption) and two weights (regular, emphasized). This creates clear hierarchy without visual noise.
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/typography.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=51ce152aab3d975ae57c5e5792dc6097" alt="Typography scale examples" width="1999" height="936" data-path="images/mcp-apps/typography.png" />
<Note>
The Figma Community File uses Anthropic Sans and Anthropic Serif. When your app runs inside Claude, the host client provides Anthropic Sans at runtime through style variables. [Download and install the fonts from here](https://brand.anthropic.com/typography) for local development.
</Note>
**Borders.** Using a limited set of corner radii and thickness will keep your app feeling native to the surrounding UI.
<img src="https://mintcdn.com/claude-ai/IPtAfld1XUBVOx8m/images/mcp-apps/borders.png?fit=max&auto=format&n=IPtAfld1XUBVOx8m&q=85&s=1755cc995399c9d6bf25a1405ff139f4" alt="Border radius examples" width="1999" height="201" data-path="images/mcp-apps/borders.png" />
**Icons.** Use monochromatic, outlined icons that match the host's icon color tokens. Icons should support understanding, not be essential to it.
<img src="https://mintcdn.com/claude-ai/IXMfN0TT8kfXbN6T/images/mcp-apps/icons.png?fit=max&auto=format&n=IXMfN0TT8kfXbN6T&q=85&s=1454f1f3e5e13107cbe543e8d6d617df" alt="Icon style examples" width="1320" height="768" data-path="images/mcp-apps/icons.png" />
**Spacing.** Maintain generous padding and logical groupings. Balance information density with readability, adapting to viewport constraints.
## Interaction patterns
### App vs. chat interactions
Understanding the boundary between your app's interactions and Claude's conversational interface helps you build something that feels cohesive.
**Handle within your app:**
* Direct manipulation like sliders, toggles, and selections
* Filtering or sorting data you're already displaying
* Expanding and collapsing content sections
* Confirming or executing a prepared action ("Mark complete," "Send," "Save")
* Interacting with visualizations like hover states or clicking data points
Prefer controls with visible options (segmented buttons, toggle chips, inline tabs) over menus and dropdowns, which can conflict with the host container.
**Push to chat input:**
* Text entry and freeform input
* Follow-up questions or requests for clarification
* Requests to modify, refine, or redo something
* Navigation to different contexts or topics
* Anything that benefits from Claude's interpretation
If the interaction requires language understanding or generates a response from Claude, it goes through chat. If it's a direct UI action on content your app already controls, handle it in the app.
### Start simple
Reveal complexity only when users need it. The inline card might show a summary; fullscreen mode can offer the detailed view.
### Visible controls over hidden menus
Prefer controls with visible options (segmented buttons, toggle chips, inline tabs) over menus and dropdowns. Menus conflict with the host container and are harder to use on mobile.
## Accessibility
Maintain high contrast standards (WCAG AA minimum). Support keyboard navigation and provide text alternatives for visual content. Test with assistive technologies. Your app must be usable by everyone.
## Style variables
MCP Apps automatically receive style variables from the host client. Reference these CSS custom properties to create interfaces that feel native to Claude.
**Color tokens** cover backgrounds, text, and borders. Semantic accent colors signal status. All tokens automatically adapt to light and dark mode.
| | Light mode | Dark mode |
| :--------------------------- | :-------------- | :-------------- |
| **Background** | | |
| `color-background-primary` | `#FFFFFF` | `#30302E` |
| `color-background-secondary` | `#F5F4ED` | `#262624` |
| `color-background-tertiary` | `#FAF9F5` | `#141413` |
| `color-background-inverse` | `#141413` | `#FAF9F5` |
| `color-background-ghost` | `#FFFFFF (0%)` | `#30302E (0%)` |
| `color-background-info` | `#D6E4F6` | `#253E5F` |
| `color-background-danger` | `#F7ECEC` | `#602A28` |
| `color-background-success` | `#E9F1DC` | `#1B4614` |
| `color-background-warning` | `#F6EEDF` | `#483A0F` |
| `color-background-disabled` | `#FFFFFF (50%)` | `#30302E (50%)` |
| **Text** | | |
| `color-text-primary` | `#141413` | `#FAF9F5` |
| `color-text-secondary` | `#3D3D3A` | `#C2C0B6` |
| `color-text-tertiary` | `#73726C` | `#9C9A92` |
| `color-text-inverse` | `#FFFFFF` | `#141413` |
| `color-text-ghost` | `#73726C (50%)` | `#9C9A92 (50%)` |
Cut at 300 lines. The page has the rest.
connectors/building/mcp-apps/external-links First recorded · 70 lines, first recorded
# Opening external links from MCP Apps ## Default behavior ## Allowlisting link destinations ### Example ### Restrictions on custom schemes ## User-activation requirement ## Design for the modal
The first capture of this source. The page was already there, and this is what it said.
# Opening external links from MCP Apps
> How Claude handles ui/open-link requests, and how directory connectors can allowlist destinations to skip the confirmation modal
When your MCP App sends a `ui/open-link` request, Claude shows an "Open external link" confirmation modal before navigating. This protects users from being silently redirected by an embedded app.
Directory connectors can declare a set of trusted destinations that open immediately without the modal. Custom connectors and locally configured servers always show the modal.
## Default behavior
A `ui/open-link` request displays a confirmation modal showing the destination URL. The link opens in a new tab when the user confirms; the request resolves as cancelled if they dismiss the modal.
## Allowlisting link destinations
If your connector is published in the [Connectors Directory](/docs/connectors/directory), you can declare destinations that skip the modal. Provide them in the **Allowed link URIs** field when you [submit](/docs/connectors/building/submission) or update your directory listing.
Each entry must be one of two shapes:
| Entry shape | Example | Matches |
| ----------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HTTPS origin | `https://docs.example.com` | Any `https://` URL whose hostname is exactly `docs.example.com` (case-insensitive). Subdomains do not match implicitly; list each one you need. Port is not compared. |
| Custom URI scheme | `example-app` or `example-app:` | Any URL with the scheme `example-app:`, typically a deep link into your native mobile or desktop app. |
Entries that do not fit one of these shapes are ignored. This includes bare hostnames such as `example.com`, `http://` origins, and malformed values.
### Example
Given the following allowlist:
```text theme={null}
https://example.com
https://docs.example.com
example-app
```
These destinations open immediately:
* `https://example.com/pricing`
* `https://docs.example.com/getting-started?ref=claude`
* `example-app://open/project/123`
These destinations still show the confirmation modal:
* `https://blog.example.com` (subdomain not listed)
* `http://example.com` (not HTTPS)
* `https://example.com.attacker.net` (different hostname)
### Restrictions on custom schemes
A custom-scheme entry must name a scheme your application registers and owns. Entries that name a generic, browser-internal, or platform-reserved scheme are rejected. This includes `http`, `https`, `file`, `data`, `javascript`, `blob`, `mailto`, `tel`, `sms`, `intent`, `android-app`, browser-extension schemes, and Windows shell schemes such as `search-ms` and `shell`.
## User-activation requirement
The modal is bypassed only when the `ui/open-link` request follows a real user gesture in your app, such as a button click.
If your app sends `ui/open-link` without a preceding gesture (programmatically, on a timer, or after the browser's activation window has expired), the modal is shown so the user's confirmation click supplies the gesture the browser requires to open a new tab.
<Note>
A bypassed `ui/open-link` request resolves successfully once the open is attempted; it does not indicate whether the browser actually opened the tab. Do not treat the response as confirmation that the user reached the destination.
</Note>
## Design for the modal
Even with an allowlist configured, your app should remain usable when the modal appears:
* Custom and local connectors always show the modal. Your app may run outside the directory during development or in self-hosted deployments.
* Destinations not on your allowlist, or added since your last published directory update, show the modal.
* Requests without user activation show the modal.
Provide enough context in your UI that the destination URL shown in the modal is recognizable to the user.
connectors/building/mcp-apps/getting-started First recorded · 114 lines, first recorded
# Get started with MCP Apps ## Try an example MCP App ### Connect an example server ### See it in action ## Build your own MCP App ## Migrate from OpenAI Apps SDK
The first capture of this source. The page was already there, and this is what it said.
# Get started with MCP Apps
> Learn how to test MCP Apps in Claude
## Try an example MCP App
### Connect an example server
Make sure you have installed and logged into Claude Desktop. Navigate to the [developer settings page](https://claude.ai/desktop/settings/desktop/developer) (**Settings > Developer**) and click the "Edit Config" button.
Add one of the example servers to your `claude_desktop_config.json`:
| Example | Description |
| ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| [**Customer Segmentation**](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/customer-segmentation-server) | Data visualization with scatter charts and clustering analysis |
| [**Map**](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/map-server) | Interactive 3D globe viewer using CesiumJS |
| [**QR Code**](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/qr-server) | QR code generation with customizable colors and styling |
| [**ShaderToy**](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/shadertoy-server) | Real-time GLSL shader compilation and display |
| [**Sheet Music**](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/sheet-music-server) | ABC notation rendering with interactive audio playback |
| ⋮ | Explore [more examples](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples)—each with ready-to-use config snippets! |
<CodeGroup>
```json Customer Segmentation theme={null}
{
"mcpServers": {
"customer-segmentation": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/customer-segmentation-server", "--stdio"]
}
}
}
```
```json Map theme={null}
{
"mcpServers": {
"map": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/map-server", "--stdio"]
}
}
}
```
```json QR Code theme={null}
{
"mcpServers": {
"qr": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/qr-server", "--stdio"]
}
}
}
```
```json ShaderToy theme={null}
{
"mcpServers": {
"shadertoy": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/shadertoy-server", "--stdio"]
}
}
}
```
```json Sheet Music theme={null}
{
"mcpServers": {
"sheet-music": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/sheet-music-server", "--stdio"]
}
}
}
```
</CodeGroup>
Save and restart the desktop app to connect.
### See it in action
Once your local server is connected, prompt Claude to use it. For example, with the customer segmentation server, ask Claude to show you recent customer data.
Claude will prompt you for permission to display the App. Click "Always allow", and you'll see the MCP App render inline in the conversation.
## Build your own MCP App
Ready to add an MCP App to your own MCP server? Here are the key resources:
* [MCP Apps Quickstart](https://modelcontextprotocol.github.io/ext-apps/api/documents/Quickstart.html) - Step-by-step guide to building your first MCP App
* [SDK API Documentation](https://modelcontextprotocol.github.io/ext-apps/api/index.html) - Full API reference
* [Example implementations](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples) - Vanilla JS, React, Vue, Svelte, and more
If you are using an AI coding agent, [MCP Apps skills](https://github.com/modelcontextprotocol/ext-apps/tree/main/plugins/mcp-apps) provide guided development for agents that support the [Agent Skills](https://agentskills.io) standard, including Claude Code, Cursor, Gemini CLI, and others. In Claude Code, you can install the MCP Apps skills plugin with the following commands:
```
/plugin marketplace add modelcontextprotocol/ext-apps
/plugin install mcp-apps@modelcontextprotocol-ext-apps
```
Once installed, ask your agent to "Create an MCP App" or "Add a UI to my MCP tool".
<Tip>You can test remote MCP Apps locally via a proxy like [mcp-remote](https://www.npmjs.com/package/mcp-remote).</Tip>
## Migrate from OpenAI Apps SDK
If you are migrating an existing app from the OpenAI Apps SDK to the MCP Apps SDK, see the [migration reference](https://modelcontextprotocol.github.io/ext-apps/api/documents/Migrate_OpenAI_App.html).
You can also use the MCP Apps skills mentioned above to help migrate your apps. Ask your agent to "Migrate from OpenAI Apps SDK" or "Convert my OpenAI App to an MCP App".
***
We'd love to see what you build! Send feedback to [[email protected]](mailto:[email protected]) or open an issue on the [ext-apps repository](https://github.com/modelcontextprotocol/ext-apps/issues).
connectors/building/mcp-apps/instance-supersession First recorded · 241 lines, first recorded
# Supersede older widget instances ## How it works ## Mint the election key on the server ### Why not use client-side `Date.now()`? ## Run the election in the widget ### Read the key from the `toolresult` event ### Broadcast and compare on a shared channel ### Gate host-mutating calls on `!superseded` ### Reflect the state in the UI ## Special considerations ### Channel scope and `ui.domain` ### Fall back if the server key is delayed ### Fallback caveat: don't compare server and client timestamps ### Caching the key across remounts ### If you bypass the SDK `App` class ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Supersede older widget instances
> Keep only the newest copy of a widget active when its tool is called more than once in a conversation
Each time Claude calls a tool that renders an MCP App, a separate iframe is mounted in the conversation. There is no host API to unmount earlier instances when a newer one appears, so by default you end up with several live copies of the same widget, each independently pushing [model-context updates](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#updatemodelcontext) (data the widget feeds into Claude's context for the next turn) and [messages](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#sendmessage) to Claude.
If your widget represents a single piece of state, such as a shopping cart or a dashboard, only the most recent instance should remain interactive. You can use [`BroadcastChannel`](https://developer.mozilla.org/docs/Web/API/BroadcastChannel) to make earlier instances disable themselves.
The snippets on this page assume you have registered a UI resource and tool and created an `App` instance from `@modelcontextprotocol/ext-apps`. See the [SDK Quickstart](https://modelcontextprotocol.github.io/ext-apps/api/documents/Quickstart.html) if you haven't.
## How it works
All widget iframes from a single connector are served from the same sandbox origin on `*.claudemcpcontent.com` (the iframe sandbox includes [`allow-same-origin`](https://developer.mozilla.org/docs/Web/HTML/Element/iframe#sandbox)). That means a `BroadcastChannel` opened in one instance reaches every other instance from the same connector in the current conversation. See [Channel scope and `ui.domain`](#channel-scope-and-ui-domain) for how a fixed domain widens this.
The pattern has three parts:
1. **The server stamps each tool result with an election key.** It returns a `{createdAt, seq}` pair (server wall-clock time and a monotonic counter) in [`structuredContent`](https://modelcontextprotocol.io/specification/latest/server/tools#structured-content), the typed JSON payload slot of an MCP tool result. Tool results are stored in the conversation transcript, so every device and every remount of the widget sees the same key.
2. **Each widget announces its key on a shared channel.** Shortly after `connect()` resolves, the host delivers the tool result that mounted this widget (including its `structuredContent`) via the SDK's [`toolresult` event](https://modelcontextprotocol.github.io/ext-apps/api/types/app.AppEventMap.html). The widget reads its key from that event, opens a `BroadcastChannel`, and broadcasts the key.
3. **Any widget that sees a younger sibling marks itself superseded.** It greys out its UI, disables its buttons, and short-circuits all calls that mutate model context or inject messages.
## Mint the election key on the server
Use [`registerAppTool`](https://modelcontextprotocol.github.io/ext-apps/api/functions/server-helpers.registerAppTool.html) to register the tool, and return the key in `structuredContent` alongside your normal tool output. A per-process counter works for a demo; a production server should derive the key from something durable, such as a database row ID or a version number on the underlying record.
```ts theme={null}
import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
import { z } from "zod";
let callSeq = 0;
registerAppTool(
server,
"show_cart",
{
title: "Show cart",
description: "Render the user's shopping cart as an interactive widget.",
inputSchema: { items: z.array(z.string()).optional() },
_meta: { ui: { resourceUri: "ui://cart-demo/cart.html" } },
},
async ({ items }) => {
const list = items ?? [];
const seq = ++callSeq;
const createdAt = Date.now();
return {
content: [{ type: "text", text: `Cart rendered with ${list.length} item(s).` }],
// The election key travels with the tool result in the transcript,
// so rehydrated widgets on any device recover the same ordering.
structuredContent: { items: list, seq, createdAt },
};
},
);
```
### Why not use client-side `Date.now()`?
Client mount time does not reflect tool-call order. When a stored conversation is reopened, Claude lazy-mounts widget cells as they scroll into view, so an older widget can mount after a newer one and would win an election based on client timestamps. The server-minted key is written into the transcript at tool-call time and is identical everywhere.
## Run the election in the widget
The four snippets in this section form a single module; paste them in order into your widget entry file.
### Read the key from the `toolresult` event
Connect and read the values you need from the host: your instance ID from [`hostContext.toolInfo`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiHostContext.html#toolinfo), and the server-minted key from the `toolresult` event. The event's `structuredContent` is typed `Record<string, unknown>`, so cast it to the shape your server returns.
```ts theme={null}
import { App } from "@modelcontextprotocol/ext-apps";
type CartResult = { items?: string[]; createdAt?: number; seq?: number };
const app = new App({ name: "cart-demo", version: "1.0.0" });
let superseded = false;
let keyFinalized = false;
let orderKey: number | undefined;
let seq: number | undefined;
let items: string[] = [];
app.addEventListener("toolresult", (params) => {
const sc = params.structuredContent as CartResult | undefined;
if (sc?.items) items = sc.items;
if (sc && Number.isFinite(sc.createdAt)) {
orderKey = sc.createdAt;
seq = Number.isFinite(sc.seq) ? sc.seq : undefined;
keyFinalized = true;
announce(); // defined in "Broadcast and compare on a shared channel" below
}
});
await app.connect();
const hostContext = app.getHostContext();
const instanceId = hostContext?.toolInfo?.id ?? crypto.randomUUID();
```
### Broadcast and compare on a shared channel
Broadcast the key and compare against every sibling you hear from. The comparison is `createdAt`, tie-broken by `seq`, then by instance ID for determinism. Ignore inbound messages until your own key is finalized so you never reply with an undefined key.
```ts theme={null}
const channel = new BroadcastChannel("my-app-cart-supersede");
const peers = new Map<string, { orderKey: number; seq?: number; instanceId: string }>();
function isYounger(other: { orderKey: number; seq?: number; instanceId: string }) {
// keyFinalized guards every call site, so orderKey is set by the time this runs.
if (other.orderKey !== orderKey) return other.orderKey > orderKey!;
if (other.seq != null && seq != null && other.seq !== seq) return other.seq > seq;
return String(other.instanceId) > String(instanceId);
}
function recompute() {
superseded = [...peers.values()].some(isYounger);
render(); // defined in "Reflect the state in the UI" below
}
channel.onmessage = (ev) => {
const msg = ev.data;
if (!msg || msg.instanceId === instanceId) return;
if (!keyFinalized) return;
if (msg.type === "hello") {
channel.postMessage({ type: "born", instanceId, orderKey, seq });
}
peers.set(msg.instanceId, msg);
recompute();
};
function announce() {
channel.postMessage({ type: "hello", instanceId, orderKey, seq });
channel.postMessage({ type: "born", instanceId, orderKey, seq });
}
```
### Gate host-mutating calls on `!superseded`
The election only matters if superseded instances actually stop talking to Claude. Guard every call to [`updateModelContext`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#updatemodelcontext) or [`sendMessage`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#sendmessage):
```ts theme={null}
// addButton, card, badge: elements in your widget's DOM.
// pickRandomItem: your own helper that returns a string.
function updateModelContext() {
if (superseded) return;
app.updateModelContext({
content: [{ type: "text", text: `Cart has ${items.length} item(s): ${items.join(", ")}.` }],
});
}
addButton.onclick = () => {
if (superseded) return;
items.push(pickRandomItem());
render();
updateModelContext();
};
```
### Reflect the state in the UI
In your render function, disable buttons and show a banner that points the user to the newest instance:
```ts theme={null}
function render() {
card.classList.toggle("superseded", superseded);
badge.textContent = superseded ? "Superseded" : "Live";
addButton.disabled = superseded;
}
```
## Special considerations
The election above covers the common case. A production widget should also handle the following.
### Channel scope and `ui.domain`
`BroadcastChannel` is same-origin only. How far that origin extends depends on whether you set [`_meta.ui.domain`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceMeta.html#domain) on your resource:
* **Without `ui.domain`** (the default), Claude derives the iframe origin from the conversation and connector, so the broadcast is scoped to a single conversation.
* **With a fixed `ui.domain`**, the origin is shared across every conversation and tab for your connector. A fixed channel name would let a widget in one conversation supersede a widget in another. Neither `hostContext` nor the tool-call arguments include a Claude-provided conversation ID, so if you need both a fixed domain and per-conversation elections, generate your own scope key on the server (for example, a UUID minted once per client connection) and return it in `structuredContent` for the widget to append to the channel name.
### Fall back if the server key is delayed
The main snippet above waits for the `toolresult` event before announcing. If you want the widget to participate in the election even when that event is slow to arrive, replace that listener with one that resolves a promise, and race the promise against a short timeout after `connect()`:
```ts theme={null}
let resolveServerKey!: (k: { orderKey: number; seq?: number }) => void;
const serverKeyReady = new Promise<{ orderKey: number; seq?: number }>(
(r) => (resolveServerKey = r),
);
// Replaces the toolresult listener from the first widget snippet.
app.addEventListener("toolresult", (params) => {
const sc = params.structuredContent as CartResult | undefined;
if (sc?.items) items = sc.items;
if (sc && Number.isFinite(sc.createdAt)) {
resolveServerKey({ orderKey: sc.createdAt!, seq: sc.seq });
}
});
// Place after the announce() definition in the broadcast snippet,
// so channel is initialized before announce() runs.
const serverKey = await Promise.race([
serverKeyReady,
new Promise<null>((r) => setTimeout(() => r(null), 1000)),
]);
orderKey = serverKey?.orderKey ?? Date.now();
seq = serverKey?.seq;
keyFinalized = true;
announce();
```
If the server key arrives after the timeout, adopt it, recompute `superseded` against the peers you have already heard from, and re-announce so siblings update their view of you. The recomputed result may flip the instance back to live.
### Fallback caveat: don't compare server and client timestamps
This applies only if you implemented the fallback above. If you fall back to a client-side `Date.now()` while waiting for the server key, tag the key with its source and refuse to compare a client value against a server value. A server `createdAt` from a tool call made hours ago will always be smaller than a fresh client timestamp, which would wrongly hand "live" to whichever instance happened to fall back. Include `keySource` in the broadcast payload (`announce()` and the `born` reply) and in the `peers` Map value type so siblings can read it:
```ts theme={null}
type KeySource = "server" | "client";
let keySource: KeySource = "client";
function isYounger(other: { orderKey: number; seq?: number; instanceId: string; keySource: KeySource }) {
if ((other.keySource === "server") !== (keySource === "server")) return false;
// keyFinalized guards every call site, so orderKey is set by the time this runs.
if (other.orderKey !== orderKey) return other.orderKey > orderKey!;
if (other.seq != null && seq != null && other.seq !== seq) return other.seq > seq;
return String(other.instanceId) > String(instanceId);
}
```
### Caching the key across remounts
On Claude.ai web, [`hostContext.toolInfo.id`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiHostContext.html#toolinfo) is the stable tool-use ID, so you can persist the resolved server key to `localStorage` keyed by that ID and reuse it on the next mount without waiting for the `toolresult` event again.
Treat this as an optimization rather than a correctness guarantee. On Claude iOS, `toolInfo.id` is `undefined` when a stored conversation is rehydrated, so there is no stable per-instance cache key. Detect that case and skip the cache; the server key from the `toolresult` event is the only ordering source that works on every platform.
### If you bypass the SDK `App` class
The snippets on this page use the SDK's [`App`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html) class. If you instead hand-roll a minimal `postMessage` bridge, it will silently drop requests sent from the host to the widget, such as `ping` (a liveness check) and [`ui/resource-teardown`](https://apps.extensions.modelcontextprotocol.io/api/interfaces/app.McpUiResourceTeardownRequest.html) (the host asking the widget to clean up before unmount). Claude.ai web does not currently send either to widgets, and Claude iOS sends `ui/resource-teardown` only when the user navigates away from the conversation, so ignoring them is harmless today. The `App` class handles the full request surface and is recommended for production.
## Related topics
* [Cross-platform compatibility](/docs/connectors/building/mcp-apps/cross-compatibility#domain-handling) for how `_meta.ui.domain` is computed on Claude.
* [SDK API reference](https://modelcontextprotocol.github.io/ext-apps/api/index.html) for `registerAppTool`, `App`, and `McpUiResourceMeta`.
connectors/building/mcp-apps/transparent-theming First recorded · 154 lines, first recorded
# Blend your MCP App with Claude's theme ## Let the host background show through ### Don't paint a body background ### Declare `color-scheme` in your document head ### Request a borderless frame ## Apply the host's style variables ### Read `hostContext` and listen for changes ### Reference the variables in your CSS ### Allow the host font origin in your CSP ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Blend your MCP App with Claude's theme
> Make your widget background transparent and style it with Claude's style variables
Claude renders MCP Apps inside a sandboxed iframe, and every frame between your widget and the chat surface already has a transparent background, so the conversation can show through. When you leave your own background transparent and style text and borders with the host's [style variables](/docs/connectors/building/mcp-apps/design-guidelines#style-variables), your app looks like part of the conversation rather than an embedded box, and it follows the user's light or dark mode automatically.
The snippets on this page assume you have registered a UI resource and created an `App` instance from `@modelcontextprotocol/ext-apps`. See the [SDK Quickstart](https://modelcontextprotocol.github.io/ext-apps/api/documents/Quickstart.html) if you haven't.
## Let the host background show through
Three settings on your side keep the transparency intact.
### Don't paint a body background
Any opaque background on `<html>` or `<body>` hides the chat surface behind it. Explicitly set both to `transparent`:
```css theme={null}
html,
body {
margin: 0;
background: transparent;
}
```
### Declare `color-scheme` in your document head
Browsers give iframe documents an opaque canvas backdrop (white in light mode, near-black in dark mode) when the iframe's [`color-scheme`](https://developer.mozilla.org/docs/Web/CSS/color-scheme) differs from the embedding page. Declaring both schemes opts your document into whichever mode the host is in, so the browser drops the backdrop and makes the CSS [`light-dark()`](https://developer.mozilla.org/docs/Web/CSS/color_value/light-dark) values in Claude's tokens resolve correctly:
```html theme={null}
<meta name="color-scheme" content="light dark" />
```
### Request a borderless frame
Set [`prefersBorder: false`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceMeta.html#prefersborder) in your UI resource's [`_meta.ui`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceMeta.html) object so the host doesn't wrap your widget in its own bordered card. Claude web's default is already borderless, but other hosts differ, so being explicit keeps your app portable. Register the resource with [`registerAppResource`](https://modelcontextprotocol.github.io/ext-apps/api/functions/server-helpers.registerAppResource.html):
```ts theme={null}
import {
registerAppResource,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
registerAppResource(server, "My Widget", "ui://my-app/widget.html", {}, async () => ({
contents: [
{
uri: "ui://my-app/widget.html",
mimeType: RESOURCE_MIME_TYPE,
text: widgetHtml, // the bundled HTML string of your widget; see the SDK Quickstart
_meta: {
ui: {
prefersBorder: false,
// lets applyHostFonts load Anthropic Sans; see "Allow the host font origin in your CSP"
csp: { resourceDomains: ["https://assets.claude.ai"] },
},
},
},
],
}));
```
## Apply the host's style variables
Claude passes a [`hostContext`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiHostContext.html) object to your widget during the [`connect()`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#connect) handshake. The fields relevant to theming are:
| Field | Contents |
| :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `theme` | `"light"` or `"dark"` |
| `styles.variables` | CSS custom properties: `--color-background-*`, `--color-text-*`, `--color-border-*`, `--color-ring-*`, `--font-*`, `--border-radius-*`, `--border-width-*` |
| `styles.css.fonts` | `@font-face` rules for Anthropic Sans, served from `https://assets.claude.ai` |
The [Style variables](/docs/connectors/building/mcp-apps/design-guidelines#style-variables) section of the design guidelines lists every variable and its light- and dark-mode value.
### Read `hostContext` and listen for changes
The [`App`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html) class exposes the initial context via [`getHostContext()`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#gethostcontext) once `connect()` resolves, and delivers subsequent updates (such as the user toggling dark mode) through the [`hostcontextchanged`](https://modelcontextprotocol.github.io/ext-apps/api/types/app.AppEventMap.html) event. Register the listener before you connect so you don't miss an early update.
The SDK provides three helpers that do the DOM work for you, plus React hooks that wrap them:
* [`applyDocumentTheme(theme)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyDocumentTheme.html) sets `<html data-theme>` and the root `color-scheme`, so `[data-theme="dark"]` selectors and `light-dark()` values resolve correctly.
* [`applyHostStyleVariables(variables)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyHostStyleVariables.html) writes every entry in `styles.variables` onto `:root` as a CSS custom property.
* [`applyHostFonts(fontCss)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyHostFonts.html) injects the host's `@font-face` rules once.
* [`useApp(options)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/_modelcontextprotocol_ext-apps_react.useApp.html) creates and connects the `App` instance for you in React.
* [`useHostStyles(app, hostContext)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/_modelcontextprotocol_ext-apps_react.useHostStyles.html) applies all of the above and re-applies on `hostcontextchanged`.
Keep the `<meta name="color-scheme">` tag from the previous section even though `applyDocumentTheme` also sets `color-scheme` at runtime. The tag covers the first paint before your script runs and prevents an opaque-backdrop flash.
<CodeGroup>
```ts TypeScript theme={null}
import {
App,
applyDocumentTheme,
applyHostFonts,
applyHostStyleVariables,
type McpUiHostContext,
} from "@modelcontextprotocol/ext-apps";
function applyHostContext(ctx: Partial<McpUiHostContext>) {
if (ctx.theme) applyDocumentTheme(ctx.theme);
if (ctx.styles?.variables) applyHostStyleVariables(ctx.styles.variables);
if (ctx.styles?.css?.fonts) applyHostFonts(ctx.styles.css.fonts);
}
const app = new App({ name: "my-app", version: "1.0.0" });
// Updates carry only the fields that changed.
app.addEventListener("hostcontextchanged", (changed) => applyHostContext(changed));
await app.connect();
const initial = app.getHostContext();
if (initial) applyHostContext(initial);
```
```tsx React theme={null}
import { useApp, useHostStyles } from "@modelcontextprotocol/ext-apps/react";
function Widget() {
const { app } = useApp({
appInfo: { name: "my-app", version: "1.0.0" },
capabilities: {},
});
// Applies theme + CSS variables + fonts, and re-applies on host-context-changed.
useHostStyles(app, app?.getHostContext());
return <div className="card">…</div>;
}
```
</CodeGroup>
### Reference the variables in your CSS
Once the variables are on `:root`, reference them directly. Provide fallbacks so the widget is still readable when rendered outside a host:
```css theme={null}
body {
font-family: var(--font-sans, system-ui, sans-serif);
color: var(--color-text-primary, light-dark(#141413, #faf9f5));
}
.card {
border: var(--border-width-regular, 0.5px) solid var(--color-border-primary);
border-radius: var(--border-radius-md, 8px);
}
```
<Note>
Claude's token values use CSS `light-dark()`, so once `applyDocumentTheme` has set the root `color-scheme`, every `--color-*` variable resolves to the right variant without any `[data-theme]` selectors on your side.
</Note>
### Allow the host font origin in your CSP
For `applyHostFonts` to load the `@font-face` files, your resource's [`_meta.ui.csp`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceMeta.html#csp) allowlist must include `https://assets.claude.ai` in [`resourceDomains`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceCsp.html#resourcedomains) (shown in the [`registerAppResource` snippet above](#request-a-borderless-frame)). `resourceDomains` also adds the listed origins to `script-src` and `style-src`, so keep it to origins you trust to serve executable code; prefer bundling third-party fonts into your widget rather than allowlisting public CDNs.
## Related topics
* [Design guidelines: Style variables](/docs/connectors/building/mcp-apps/design-guidelines#style-variables) and [Visual design](/docs/connectors/building/mcp-apps/design-guidelines#visual-design) for the full variable palette and usage guidance.
* [SDK API reference](https://modelcontextprotocol.github.io/ext-apps/api/index.html) for `App`, `McpUiHostContext`, and `McpUiResourceMeta`.
connectors/building/mcp-apps/troubleshooting First recorded · 109 lines, first recorded
# Troubleshooting MCP Apps ## Using developer tools ### Desktop ### iOS ## Problem: Tool call appears but the app is invisible ### Missing `app.connect()` call ### Iframe has zero height ## Problem: App doesn't render when tool results are large ## Problem: Assets or API requests fail only on iOS ## Problem: ui.domain validation fails
The first capture of this source. The page was already there, and this is what it said.
# Troubleshooting MCP Apps
> Debug and resolve common issues with MCP Apps
## Using developer tools
### Desktop
Claude Desktop's Developer Tools can help you debug MCP Apps. To use them:
1. Open **Help > Troubleshooting** and click **Enable Developer Mode**. A new **Developer** menu appears in the menu bar.
2. Open Developer Tools by pressing `Cmd+Option+I` (Mac) or `Ctrl+Shift+I` (Windows)
3. Inspect the tool call element and look for an iframe nested inside another iframe. Your app will be loaded as the content of the inner iframe.
<Tip>From the **Developer** menu, select **Reload MCP Configuration** after editing your `claude_desktop_config.json` to apply changes without restarting.</Tip>
### iOS
On iOS, the Claude app renders your MCP app inside a `WKWebView`. You can inspect it from a connected Mac using Safari's Web Inspector—see Apple's guide to [inspecting iOS](https://developer.apple.com/documentation/safari-developer-tools/inspecting-ios) for setup. Once connected, the Claude web view appears under your device in Safari's **Develop** menu, and you can use the console, network panel, and element inspector just as you would on desktop.
## Problem: Tool call appears but the app is invisible
This is the most common issue when developing MCP Apps. Check these two causes:
### Missing `app.connect()` call
Your app must call [`app.connect()`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#connect) (Vanilla JS) or [`useApp()`](https://modelcontextprotocol.github.io/ext-apps/api/functions/_modelcontextprotocol_ext-apps_react.useApp.html) (React) to establish communication with Claude Desktop.
<CodeGroup>
```javascript Vanilla JS theme={null}
import { App } from "@modelcontextprotocol/ext-apps";
const app = new App({ name: "My App", version: "1.0.0" });
// Register handlers before connecting
app.ontoolresult = (result) => {
// Handle tool results
};
await app.connect();
```
```javascript React theme={null}
import { useApp } from "@modelcontextprotocol/ext-apps/react";
function MyComponent() {
// The useApp hook handles connection automatically
const { app } = useApp({
appInfo: { name: "My App", version: "1.0.0" },
capabilities: {},
onAppCreated: (app) => {
app.ontoolresult = (result) => {
// Handle tool results
};
}
});
}
```
</CodeGroup>
<Warning>Event handlers like `app.ontoolinput` and `app.ontoolresult` won't be invoked until the app is connected.</Warning>
### Iframe has zero height
Your app needs a non-zero height to be visible. A zero height can occur if:
* Your app's container has no content yet
* You called `sendSizeChanged({ width, height: 0 })`
Check that your root element has explicit dimensions or content that gives it height.
## Problem: App doesn't render when tool results are large
When a tool result exceeds approximately 150,000 characters and Claude's code execution sandbox is active, the result is written to the sandbox filesystem instead of being passed inline to the conversation. Your app receives a pointer to the stored file rather than the structured content it needs, so it never hydrates.
<Note>This \~150,000-character threshold is specific to Claude.ai and Claude Desktop. Claude Code uses a separate 25,000-token default limit configurable via `MAX_MCP_OUTPUT_TOKENS`.</Note>
To avoid this, keep initial tool result payloads lean:
* **Paginate large results.** Return a summary or the first page of data, and let the user request more through follow-up interactions.
* **Fetch details on demand.** Use app-initiated tool calls to load additional data from within your widget as the user explores, rather than returning everything upfront.
* **Defer heavy content.** If your data includes large blobs—full document text, base64-encoded images, extensive logs—return identifiers or previews in the initial result and provide a separate tool to retrieve the full content when needed.
## Problem: Assets or API requests fail only on iOS
If your app loads on desktop and web but fails to fetch scripts, images, or API data on iOS, check whether your server, CDN, or WAF is gating access on the `Referer` header.
WebKit on iOS—both Safari and in the Claude iOS app—omits the `Referer` header on cross-origin subresource requests as part of its tracking prevention (WebKit bugs [206521](https://bugs.webkit.org/show_bug.cgi?id=206521) and [179053](https://bugs.webkit.org/show_bug.cgi?id=179053#c8)). A server that requires a `Referer` to allow the request will reject iOS traffic even though the same app works elsewhere.
**Fix:** Allowlist on the `Origin` header instead, which WebKit does send. Requests from your app carry an `Origin` of `{hash}.claudemcpcontent.com`—see [Domain handling](/docs/connectors/building/mcp-apps/cross-compatibility#domain-handling) to compute the hash for your server URL. Configure your infrastructure to allow requests whose `Origin` matches `*.claudemcpcontent.com` and return a corresponding `Access-Control-Allow-Origin` header.
<Note>This applies to requests your app makes directly from the user's device—loading bundles, images, or calling your own API from client-side code. MCP tool calls are proxied through Claude's backend and egress from Anthropic's published IP ranges, not the user's device.</Note>
## Problem: ui.domain validation fails
Setting [`_meta.ui.domain`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceMeta.html#domain) on your resource opts your app into a stable sandbox origin, which you need if your app runs its own OAuth flow. Claude validates the value against your connector URL and shows an `Invalid ui.domain format` or `ui.domain mismatch` error instead of rendering the app when validation fails.
The value must be exactly `{hash}.claudemcpcontent.com`, where `{hash}` is the first 32 hexadecimal characters of the SHA-256 digest of your full connector URL. Compute it by running this command with your own URL:
```shell theme={null}
node -e 'const yourServerUrl = "https://example.com/mcp"; console.log(require("crypto").createHash("sha256").update(yourServerUrl).digest("hex").slice(0,32) + ".claudemcpcontent.com")'
```
Common causes of a mismatch:
* **The URL you hashed differs from the URL Claude connects to.** The hash covers the full URL string including scheme, path, and any trailing slash, so `https://example.com/mcp` and `https://example.com/mcp/` produce different values. Hash the exact URL configured in **Customize > Connectors**.
* **The connector is local (stdio).** Local connectors have no URL to hash, so `ui.domain` is not available for them. Remove the field, or deploy the server as a remote connector to use a stable origin.
See [Domain handling](/docs/connectors/building/mcp-apps/cross-compatibility#domain-handling) for how the origin is used across platforms.
connectors/building/mcpb First recorded · 173 lines, first recorded
# Build a desktop extension with MCPB ## What is an MCPB? ## Local (MCPB) vs remote: which to build ## Choose a language ## Platform support ## Quickstart ## manifest.json ## Add an icon ## User configuration ## How users install your MCPB ## Resources ## Get help ## Ready for distribution
The first capture of this source. The page was already there, and this is what it said.
# Build a desktop extension with MCPB
> Package a local MCP server as a single-click .mcpb install for Claude Desktop
<Note>
MCPB is the secondary distribution path. Remote MCP servers are recommended for directory listing—see [what to build](/docs/connectors/building/what-to-build).
</Note>
This guide covers building an MCP Bundle (`.mcpb`) for internal use, private distribution, or as a foundation for [submission to the Connectors Directory](/docs/connectors/building/submission).
## What is an MCPB?
An `.mcpb` file is a zip archive containing a local MCP server and a `manifest.json`. It enables single-click installation in Claude Desktop, similar to a browser extension.
Key characteristics:
* Runs locally on the user's machine
* Communicates via stdio transport
* Bundles all dependencies
* Works offline
* No OAuth required
See the [MCPB repository](https://github.com/modelcontextprotocol/mcpb) for the complete specification and the [Desktop Extensions blog post](https://www.anthropic.com/engineering/desktop-extensions) for an architecture overview.
## Local (MCPB) vs remote: which to build
| Choose MCPB when you need | Choose a remote connector when you need |
| -------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| Access to systems behind your firewall (JIRA, Confluence, internal wikis, private databases) | Cloud services and public APIs with centralized infrastructure |
| Authentication via existing SSO and browser sessions, no token management | OAuth flows with server-side token management |
| Zero-trust compliance inside corporate network boundaries | Distribution across Claude on web, mobile, and desktop |
| Direct filesystem access for code editing and Git operations | Centralized updates pushed to all users |
| Integration with locally installed tools (Docker, IDEs, databases) | Public-facing integrations used by multiple organizations |
| Hardware integration and desktop application control | |
| Privacy-sensitive operations that should not leave the user's machine | |
| One-click install with bundled Node.js runtime, no dependencies to manage | |
| No cloud infrastructure, VPN configuration, or firewall rules | |
| Organization-level admin controls (custom uploads, allowlists) | |
| Full control over authentication, authorization, and audit logs | |
**Key difference:** MCPBs run on the user's machine via stdio with access to local and internal resources. Remote connectors run on your servers via HTTPS and are accessed through Anthropic's infrastructure.
Organizations commonly build MCPBs as secure proxies to internal MCP servers, for internal documentation access, and to connect development tools while preserving their security architecture.
For remote connector guidance, see [building custom connectors](/docs/connectors/building/index).
## Choose a language
Node.js is strongly recommended:
* Ships with Claude Desktop on macOS and Windows, so users need no separate runtime
* Best compatibility and reliability with Claude Desktop
* Extensive MCP SDK support
## Platform support
Claude Desktop runs on macOS (`darwin`) and Windows (`win32`). Specify supported platforms in the `compatibility` section of your `manifest.json`. Test on both platforms even if you primarily develop on one.
See the [manifest spec compatibility section](https://github.com/modelcontextprotocol/mcpb/blob/main/MANIFEST.md#compatibility) for platform and runtime requirement details.
## Quickstart
<Steps>
<Step title="Install the MCPB CLI">
```bash theme={null}
npm install -g @anthropic-ai/mcpb
```
</Step>
<Step title="Create your MCP server">
Build a stdio MCP server using the [MCP SDK](https://www.npmjs.com/package/@modelcontextprotocol/sdk).
</Step>
<Step title="Generate the manifest">
```bash theme={null}
mcpb init
```
</Step>
<Step title="Bundle">
```bash theme={null}
mcpb pack
```
</Step>
<Step title="Install and test in Claude Desktop">
Double-click the generated `.mcpb` file.
</Step>
</Steps>
For detailed implementation guidance, see the [MCPB repository](https://github.com/modelcontextprotocol/mcpb), the [examples directory](https://github.com/modelcontextprotocol/mcpb/tree/main/examples) including a Hello World, and the [README "For Bundle Developers" section](https://github.com/modelcontextprotocol/mcpb/blob/main/README.md).
<Warning>
Before distributing your MCPB, review the testing and best-practices guidance in the MCPB README to ensure quality.
</Warning>
## manifest.json
The `manifest.json` file is required metadata describing what your MCPB does, how to run it, which tools it provides, and what configuration it needs.
| Reference | |
| ---------------------------------------------------------------------------------------- | --------------------------- |
| [MCPB Manifest Spec](https://github.com/modelcontextprotocol/mcpb/blob/main/MANIFEST.md) | Full schema with all fields |
| [Example manifests](https://github.com/modelcontextprotocol/mcpb/tree/main/examples) | Real-world implementations |
| [CLI documentation](https://github.com/modelcontextprotocol/mcpb/blob/main/CLI.md) | Command reference |
## Add an icon
Icons are optional but recommended. Place `icon.png` in your bundle root and reference it in `manifest.json`.
| Requirement | Value |
| ----------- | ----------------------------------------- |
| File name | `icon.png` (or a custom path) |
| Size | 512×512px recommended (minimum 256×256px) |
| Format | PNG with transparency |
| Location | Bundle root or specified path |
You can also provide multiple icon variants for different sizes and themes (light/dark mode). See the [manifest spec icons section](https://github.com/modelcontextprotocol/mcpb/blob/main/MANIFEST.md#icons) for variant syntax and best practices.
## User configuration
Define a `user_config` section in `manifest.json` and Claude Desktop automatically generates a settings UI for your extension. The [manifest spec user configuration section](https://github.com/modelcontextprotocol/mcpb/blob/main/MANIFEST.md#user-configuration) covers the full schema, configuration types, validation constraints, sensitive-data handling, and multi-select patterns.
## How users install your MCPB
Users can install three ways:
1. **Double-click** the `.mcpb` file
2. **Drag and drop** the `.mcpb` file into the Claude Desktop window
3. **Settings**: Settings → Extensions → Advanced settings → Install Extension… → select the `.mcpb` file
All three open an installation UI where the user reviews extension details and permissions, configures required settings, grants permissions, and completes installation. Installation is per-user; each user installs separately on their own system.
For the end-user installation experience and Team/Enterprise admin controls (organization management, allowlists, policy configuration), see [Getting Started with Local MCP Servers on Claude Desktop](https://support.claude.com/en/articles/10949351-getting-started-with-local-mcp-servers-on-claude-desktop).
## Resources
**MCPB framework**
* [MCPB repository](https://github.com/modelcontextprotocol/mcpb): complete specification and tools
* [MCPB Manifest Spec](https://github.com/modelcontextprotocol/mcpb/blob/main/MANIFEST.md): full manifest schema
* [MCPB CLI documentation](https://github.com/modelcontextprotocol/mcpb/blob/main/CLI.md): command reference
* [MCPB examples](https://github.com/modelcontextprotocol/mcpb/tree/main/examples): reference implementations
**MCP protocol**
* [MCP specification](https://modelcontextprotocol.io/docs/getting-started/intro): protocol documentation
* [MCP quickstart](https://modelcontextprotocol.io/docs/develop/build-server): getting-started guide
* [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk): Node.js implementation
* [Python SDK](https://github.com/modelcontextprotocol/python-sdk): Python implementation
**Claude Desktop**
* [Release notes](https://support.claude.com/en/articles/12138966-release-notes): version updates
* [Desktop Extensions blog](https://www.anthropic.com/engineering/desktop-extensions): architecture overview
## Get help
* [MCPB GitHub issues](https://github.com/modelcontextprotocol/mcpb/issues): bug reports and feature requests
* [MCP specification repo](https://github.com/modelcontextprotocol/modelcontextprotocol): protocol questions
* [Claude support](https://support.claude.com/en/articles/9015913-how-to-get-support): general Claude Desktop support
Check repository discussions for community Q\&A, follow release notes for updates, and review the examples for implementation patterns.
## Ready for distribution
If you have a working MCPB and want broader distribution and discoverability, submit it to the Connectors Directory. See [submitting to the directory](/docs/connectors/building/submission) for requirements including:
* Mandatory tool annotations for all tools
* Privacy policy requirements
* Working examples that exercise each tool
* Test credentials where applicable
* The complete submission process and review timeline
connectors/building/review-criteria First recorded · 74 lines, first recorded
# Pre-submission checklist ## Tool design ### Separate read and write tools ### Reference API docs in custom query tools ### Provide tool annotations ### Keep tool names short ### Write narrow, accurate descriptions ## Avoid prompt-injection patterns ## Functional quality ## API ownership ## Unsupported use cases ## Submission requirements ## Before you submit
The first capture of this source. The page was already there, and this is what it said.
# Pre-submission checklist
> What Anthropic reviewers test, so you can pass on the first try
When you submit a server, it is automatically scanned for policy compliance and, by default, listed in the directory as a [community connector](/docs/connectors/verification). Anthropic may then escalate listings flagged as highly useful to Claude users to verified review, which is higher touch and slower; reviewers run a functional test of each tool. This escalation is assessed automatically, and you do not need to take any action. Every server in the directory must meet the criteria on this page, whichever label it carries. The label is a quality signal shown to users; it does not change how your connector runs once connected. This page surfaces the most common rejection reasons so you can self-correct before submitting. For the full legal text, see the [Software Directory Policy](https://support.claude.com/en/articles/13145358-anthropic-software-directory-policy).
## Tool design
### Separate read and write tools
A single tool that accepts both safe HTTP methods (GET, HEAD, OPTIONS) and unsafe methods (POST, PUT, PATCH, DELETE) is rejected. Do not ship a catch-all `api_request` tool with a `method` parameter.
Split into a read-only tool and one or more write tools. Ideally, split write operations further by action type (create, update, delete). Documenting safe versus unsafe operations within one tool's description does not satisfy this requirement—the operations must be in separate tools.
### Reference API docs in custom query tools
If a tool accepts freeform endpoint paths, query strings, or request bodies that the caller constructs, its description must include a link to or explicit name of the target API. For example: "Queries the Slack Web API—see [https://api.slack.com/methods](https://api.slack.com/methods)". A description like "Makes a request to the API" with no further context fails.
This applies only to custom query tools. Purpose-built tools that call a fixed endpoint internally do not need an API docs reference.
### Provide tool annotations
Every tool must include a `title` and the applicable hint—`readOnlyHint: true` for read-only tools, `destructiveHint: true` for tools that modify or delete data. These determine auto-permissions in Claude: read-only tools can run without per-call confirmation; destructive tools always prompt.
### Keep tool names short
Tool names must be 64 characters or fewer.
### Write narrow, accurate descriptions
Each tool description should state precisely what the tool does and when to invoke it. The description must match the tool's actual behavior.
## Avoid prompt-injection patterns
Tool descriptions are rejected if they:
* Instruct Claude to call external software or tools the user didn't request
* Interfere with Claude calling other tools
* Direct Claude to pull behavioral instructions from external sources
* Contain hidden, obfuscated, or encoded instructions
* Tell Claude to behave in ways unrelated to the tool's function, attempt to override system instructions, or promote products and services
Describe what the tool does. Do not tell Claude how to behave.
## Functional quality
* Every tool must return a successful response when called with valid parameters. Generic errors ("Internal Server Error", "Bad Request" with no detail) fail review.
* Validate inputs and return actionable error messages rather than silently accepting invalid data.
* Keep responses reasonably sized for the task. Do not return a full database dump when a summary was requested.
* Do not collect conversation data beyond what the tool needs for its function.
* Do not query Claude's memory, chat history, conversation summaries, or user files.
## API ownership
Your server must call your own first-party APIs, or APIs you legitimately proxy. The MCP server domain should match your service.
## Unsupported use cases
Connectors that do the following are not accepted:
* Transfer money, cryptocurrency, or other financial assets
* Generate images, video, or audio via AI models (design tools that produce diagrams, charts, or UI mockups are allowed)
## Submission requirements
* **Test credentials** are required and must be a fully populated account.
* **Allowed link URIs** are recommended if your server calls `ui/open-link`. Declared HTTPS origins and custom URI schemes open without a confirmation prompt; anything else still prompts the user. See [Allowed link URIs](/docs/connectors/building/submission#allowed-link-uris).
* **Public documentation** is required by your publish date—a blog post or help-center article is sufficient. You can share docs privately with Anthropic during review.
* **Plugins** must link a public GitHub repo; closed-source is not accepted.
* **MCPB** open-source and "spec will evolve" clauses in the [Software Directory Terms](https://support.claude.com/en/articles/13145338-anthropic-software-directory-terms) are required and not waivable.
## Before you submit
Run `claude plugin validate` on plugins. For MCP servers, exercise every tool through the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) and as a [custom connector in Claude](/docs/connectors/building/testing).
connectors/building/submission First recorded · 172 lines, first recorded
# Submitting to the Connectors Directory ## What you can submit ## Before you start ## Directory terms & conditions ## Submission requirements ## Privacy policy requirements ## Allowed link URIs ## Asset specifications ### Carousel screenshots (MCP Apps) ### Detail card description ## Review process ## Submit your connector ### What to expect in the portal
The first capture of this source. The page was already there, and this is what it said.
# Submitting to the Connectors Directory > Submit your MCP connector to the Connectors Directory The [Connectors Directory](/docs/connectors/directory) aims to be a collection of high-quality, vetted, and reviewed MCP servers that are helpful and harmless to users. Anyone is welcome to build MCP servers, but only servers meeting the review standards outlined on this page will be included in the directory. ## What you can submit Developers can submit: * **Remote MCP servers** — internet-hosted servers that provide tools and data to Claude * **Desktop extensions** — local MCP servers packaged as [MCP Bundles (MCPB)](https://github.com/modelcontextprotocol/mcpb) for Claude Desktop * **[MCP Apps](/docs/connectors/building/mcp-apps/getting-started)** — MCP servers that surface interactive UI elements. These have the additional requirement of including screenshots for submission and listing in the directory. ## Before you start Remote MCP server submissions happen inside Claude.ai, in the [submission portal](https://claude.ai/admin-settings/directory/submissions/new). The portal is part of your organization's admin settings, so you need: * **A Team or Enterprise organization.** Admin settings aren't available on individual plans. * **Directory management access.** By default, only organization Owners and Primary owners can submit and manage directory listings. On Enterprise, an Owner can delegate this to other members by creating a custom role in **Organization settings > Roles** with either the **Directory** permission (directory submissions only) or the **Libraries** permission (broader: it also covers managing the organization's plugins, connectors, and skills), and assigning that role. Team plans don't have custom roles, so on Team this stays with Owners. Desktop extensions (MCPB) use a separate [submission form](https://clau.de/desktop-extention-submission) and don't require the portal. ## Directory terms & conditions All servers in the directory must comply with: * [Anthropic Software Directory Terms](https://support.claude.com/en/articles/13145338-anthropic-software-directory-terms) * [Anthropic Software Directory Policy](https://support.claude.com/en/articles/13145358-anthropic-software-directory-policy) By submitting a connector, you also agree to: * Maintain your connector's security and functionality * Respond to security issues promptly * Provide accurate descriptions and documentation ## Submission requirements All MCP connectors submitted to the directory must meet: 1. **Security**: Meet Anthropic's security standards 2. **Tool annotations**: All tools must include a `title` and the applicable `readOnlyHint` or `destructiveHint` 3. **Authentication**: Use OAuth 2.0 for authenticated services 4. **Privacy Policy**: Local connectors must include privacy policies 5. **Documentation**: Provide clear setup and usage instructions If your connector opens external links, also provide your [allowed link URIs](#allowed-link-uris) so users aren't prompted to confirm each one. ## Privacy policy requirements Local connectors must include: 1. "Privacy Policy" section in README.md 2. `privacy_policies` array in manifest.json (manifest\_version 0.2+) 3. HTTPS URLs to privacy policies The privacy policy must cover: * Data collection practices * Usage and storage * Third-party sharing * Data retention * Contact information <Warning> Missing or incomplete privacy policies result in immediate rejection. </Warning> ## Allowed link URIs If your connector uses the `ui/open-link` capability to open URLs in the user's browser or native apps, provide the list of link targets your server will request. Claude uses this list to suppress the "Open external link" confirmation prompt for destinations you've declared. Links to any other destination still work—users are simply asked to confirm before the link opens. Provide each entry in one of two forms: * **HTTPS origin** — `https://example.com`. Only the scheme and hostname are matched; paths, ports, and query strings are ignored. Subdomains are not implied—list each one (`https://app.example.com`, `https://docs.example.com`). * **Custom URI scheme** — `myapp:` for deep links into a native app you own (for example, `spotify:` or `notion:`). Only the scheme is matched. Every origin and scheme you list **must be owned by you** (the submitting organization). You may not list third-party domains or URI schemes registered to apps you don't publish. Entries you don't own will be removed during review. <Note> This field is optional. If omitted, your connector functions normally, but users are shown a confirmation prompt each time it opens a link. </Note> ## Asset specifications ### Carousel screenshots (MCP Apps) * **Format:** PNG * **Width:** at least 1000px * **Count:** 3–5 images * **Crop:** to the app response only—**do not include the prompt** in the image * **Aspect ratio:** any * **Paired prompts:** provide the prompt text separately for each screenshot * **Mobile:** no separate mobile assets are required—one batch covers all surfaces * **Video/GIF:** not accepted A carousel template is available in the [Anthropic MCP Apps Figma community file](https://www.figma.com/community/file/1597641111449594397/mcp-apps-for-claude). ### Detail card description You write the detail card description in the submission portal. It is not editable by Anthropic. The disclaimer text shown on connector cards is general and not customizable per partner. ## Review process Review times vary with queue volume. The submission portal is always open. After you submit, track your submission's status and read reviewer feedback in the [submissions dashboard](https://claude.ai/admin-settings/directory/submissions). See [Managing your listing](/docs/connectors/building/managing-your-listing) for what's available there, including server health and usage metrics after publication. Email `[email protected]` for escalations. Run the [pre-submission checklist](/docs/connectors/building/review-criteria) and, for plugins, `claude plugin validate` before you submit. ## Submit your connector Ready to submit? Use the path that matches your connector type: * **Remote MCP servers (including MCP Apps)**: submit through the [submission portal](https://claude.ai/admin-settings/directory/submissions/new) in Claude.ai admin settings. See [Before you start](#before-you-start) for access requirements. * **Desktop extensions (MCPB)**: use the [desktop extension submission form](https://clau.de/desktop-extention-submission). Skills are not a standalone submission type—bundle them in a [plugin](/docs/plugins/submit). ### What to expect in the portal Before you start, have your documentation URL, privacy policy URL, icon, and test account credentials ready, plus carousel screenshots if you're submitting an MCP App (see [asset specifications](#asset-specifications) above). The portal walks you through the following steps. Your progress saves automatically in your browser as you move between steps, so within a browser session you can jump back to earlier steps without losing work. <Steps> <Step title="Introduction"> Explains what a directory listing does and doesn't do: inclusion makes your connector discoverable but doesn't change the tools it exposes. The portal accepts remote MCP servers only. Local servers are distributed as [desktop extensions](https://clau.de/desktop-extention-submission) or [plugins](/docs/plugins/submit) instead. </Step> <Step title="Connection"> Connect the server you're submitting. You confirm the server URL (must be `https://`), the transport (streamable HTTP or SSE), and whether every user connects to the same URL or different users connect to different URLs. </Step> <Step title="Tools"> Your server's tools, prompts, and resources sync automatically from the connected server, grouped by whether their annotations declare them read-only or write (tools without annotations are grouped separately). If any tools are flagged for missing titles or annotations, fix them on your server before submitting. </Step> <Step title="Listing"> The public-facing listing: server name (100 characters max), tagline (55 characters max), description (2,000 characters max), one to five categories, documentation URL, privacy policy URL, support contact, icon, and the URL slug for your listing page. The slug is permanent once published. </Step> <Step title="Use cases"> Describe the primary use cases, what users need before they can connect (accounts, plans, or other setup), and whether the connector reads data, writes data, or both. </Step> <Step title="Company"> Company name and website, plus a primary contact for review updates. The contact name and email are pre-filled from your account. </Step> <Step title="Authentication"> How users authenticate: OAuth (with dynamic client registration, client ID metadata documents, or a static client ID held by Anthropic), a custom connection where users supply their own URL or credentials at connection time, or no authentication. See [authentication](/docs/connectors/building/authentication) for which modes are supported out of the box and which need coordination with the review team. If your server starts without authentication and individual tools prompt for it on demand, you can flag that here. </Step> <Step title="Data handling"> Whether the underlying API is your own, proxied from a partner with permission, or a third party's you don't control, and whether the connector handles personal health data or sponsored content. </Step> <Step title="Test & launch"> Test-account setup and access instructions detailed enough for a reviewer to access your server end to end: every link, credential, and step, including credentials for a fully populated account where relevant. You also confirm you've run every tool yourself, either via MCP Inspector or as a custom connector in Claude. </Step> <Step title="Compliance"> Seven policy acknowledgments covering the directory guidelines, first-party API usage, financial transactions, AI media generation, prompt injection, conversation data collection, and public documentation. All seven are required. </Step> <Step title="Review"> A final read-through of everything you've entered. Any quality warnings (for example, very short answers) are shown here and shared with the review team alongside your submission. Submit when you're ready. </Step> </Steps> After you submit, your submission's status and any reviewer feedback appear in the [submissions dashboard](https://claude.ai/admin-settings/directory/submissions). See [Managing your listing](/docs/connectors/building/managing-your-listing).
connectors/building/testing First recorded · 43 lines, first recorded
# Testing your connector ## Test as a custom connector ## Test a local server ## Validate with MCP Inspector ## Detect Claude as the client ## Prepare test credentials for review ## Debugging
The first capture of this source. The page was already there, and this is what it said.
# Testing your connector
> Test your MCP server against Claude before submitting to the directory
Test your server against the real Claude client before submitting. There is no separate staging environment—you test in production using a custom connector.
## Test as a custom connector
Any Claude account (Free, Pro, Max, Team, or Enterprise) can add a custom connector. Go to **Customize > Connectors**, select **Add custom connector**, and enter your server's URL. Custom connectors use the exact same runtime as directory connectors, so what works here will work after publication.
## Test a local server
To test a server running on your machine, expose it as a public URL with a tunnel such as [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) or `ngrok`, then add the tunnel URL as a custom connector. This is the recommended pattern for iterating on MCP Apps as well.
<Warning>
A tunnel exposes your local server to the public internet. Keep authentication enabled on your server while tunneling, and shut the tunnel down when you're done testing.
</Warning>
## Validate with MCP Inspector
Use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) to verify protocol compliance, exercise your auth flow, and inspect tool schemas before connecting to Claude.
## Detect Claude as the client
Claude identifies itself in the MCP `initialize` handshake via `clientInfo`, but the exact value depends on the surface and the request path. You may see `"name": "claude-ai"`, `"name": "Anthropic"` (sometimes with a service suffix), or `"name": "claude-code"`:
```json theme={null}
{ "clientInfo": { "name": "Anthropic", "version": "1.0.0" } }
```
Don't gate behavior on an exact `name` or `version` string — both vary across surfaces, request paths, and releases. Use `clientInfo` for telemetry and coarse feature detection only, and remember it's unauthenticated: any client can claim any name, so it must never feed an authorization decision.
## Prepare test credentials for review
Directory submission requires test credentials. Provide a **fully populated account**—not an empty shell—so reviewers can exercise real functionality (list real records, search real data, exercise write tools on real resources). Include step-by-step setup instructions for someone unfamiliar with your service.
## Debugging
Partner-visible error logs are in development. In the meantime, use server-side logging on your end and the MCP Inspector to diagnose connection failures. Common causes of `initialize` timeouts include slow OAuth endpoints (keep discovery, registration, and token responses under ten seconds; see [endpoint latency](/docs/connectors/building/authentication#endpoint-latency)), overly strict `Origin`-header validation rejecting Anthropic's requests, and firewalls dropping Anthropic's egress traffic.
If your infrastructure logs show `403 Forbidden` responses your application didn't generate, your CDN or WAF is likely blocking Anthropic's traffic. See [firewall or WAF blocks Anthropic's traffic](/docs/connectors/building/troubleshooting#2-firewall-or-waf-blocks-anthropic%E2%80%99s-traffic) for the fix.
For a structured walkthrough of "Couldn't reach the MCP server" and "Authorization failed" errors, including DNS resolution checks, OAuth discovery diagnostics, and how to find the `ofid_` reference ID to include in a support request, see [troubleshooting connectors](/docs/connectors/building/troubleshooting).
connectors/building/troubleshooting First recorded · 162 lines, first recorded
# Troubleshooting connectors ## Find your reference ID ## "Couldn't reach the MCP server" ### 1. Hostname resolves to a private IP ### 2. Firewall or WAF blocks Anthropic's traffic ### 3. Your server URL redirects to a different host ### 4. OAuth discovery fails ## "Authorization with the MCP server failed" ### Microsoft Entra ID rejects the resource value ## Diagnostic checklist ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Troubleshooting connectors
> Diagnose and resolve common connection failures for custom and directory MCP connectors
This page covers the most common reasons a connector fails to connect or authenticate, and how to diagnose each one. The errors Claude shows in the UI ("Couldn't reach the MCP server" and "Authorization with the MCP server failed") cover more than one root cause, so the first step is figuring out which one you're hitting.
## Find your reference ID
When a connection fails, the error toast and the page URL include a reference ID that starts with `ofid_`. For example:
```text theme={null}
.../customize/connectors?step=start_error&flow_id=ofid_d32594c73257a651
```
Copy that ID and include it in any GitHub issue or support request. It lets Anthropic trace the exact failure on the server side. Reference IDs are time-limited, so report them soon after the failure.
<Tip>
If you're filing on the [`anthropics/claude-ai-mcp` issue tracker](https://github.com/anthropics/claude-ai-mcp/issues), include the `ofid_` value, your server URL, and what your server-side access logs show during the Connect attempt.
</Tip>
## "Couldn't reach the MCP server"
This error appears when Claude can't complete the connection handshake. Despite the wording, it isn't always a network failure. Work through these causes in order.
### 1. Hostname resolves to a private IP
claude.ai connectors run on Anthropic's infrastructure and reach your server over the public internet. Before making any request, Claude resolves your server's hostname and validates the result. If **any** resolved address is not globally routable, Claude rejects the connection before any HTTP request leaves Anthropic's network. Your server's access logs see nothing, and Claude reports "Couldn't reach."
Claude rejects the connection when the hostname:
* resolves to a private address (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`)
* resolves to a carrier-grade NAT address (`100.64.0.0/10`)
* resolves to a loopback or link-local address
* resolves to a mix of public and non-public addresses — every returned address must be globally routable
* has no `A` record from public DNS — connectors are IPv4-only, so a hostname that only publishes `AAAA` records can't be reached
**Common gotchas:**
* **Works in Claude Code or `curl` but not claude.ai.** The CLI and `curl` connect from your machine, while claude.ai connects from Anthropic's servers. If your hostname resolves differently inside and outside your network (split-horizon DNS), claude.ai may be getting a private IP.
* **Dynamic DNS providers.** Dynamic DNS hostnames often resolve to a home network behind NAT or carrier-grade NAT.
* **Internal corporate DNS.** A hostname that resolves on your VPN won't resolve to a routable address from the public internet.
**How to check:** Run `dig +short your-server.example.com` from a machine outside your network, or use a public DNS lookup service. Every returned address must be globally routable.
**How to fix:** Expose your server through a publicly-routable endpoint, such as a cloud host with a public IP, a public reverse proxy, or a tunnel. See [test a local server](/docs/connectors/building/testing#test-a-local-server) for the recommended tunnel setup.
### 2. Firewall or WAF blocks Anthropic's traffic
If your hostname resolves correctly but a CDN, WAF, bot-management rule, or rate limiter in front of your server blocks the request, the connection fails before your application sees it.
**How to check:** Look for `403` or `429` responses in your edge or CDN logs that your application didn't generate, especially during a Connect attempt.
**How to fix:** Allowlist Anthropic's published outbound IP range in your WAF or CDN configuration, or exempt your MCP and OAuth paths from the blocking rule. The current range is on the [IP address reference](https://platform.claude.com/docs/en/api/ip-addresses) page.
### 3. Your server URL redirects to a different host
If your registered MCP URL returns a `301`/`302`/`307`/`308` redirect to a different host (apex to `www.`, region routing, vanity domain to CDN), the `Authorization` header is dropped on the redirect per standard HTTP client security behavior. The redirect target receives an unauthenticated request and returns `401`, and the connection fails with "Authorization with the MCP server failed."
This also explains the common report "works in MCP Inspector or Claude Code CLI but not claude.ai." Local clients fail fast on a redirect, so the misconfiguration is visible immediately. claude.ai follows the redirect, drops the credential, and the failure surfaces later as an authorization error.
**How to check:** Run `curl -sI https://your-server.example.com/your-mcp-path` and look at the response status and `Location` header. If you see a `3xx` status pointing at a different host, that target is the URL you should register.
**How to fix:** Register the URL your server actually listens on, not a URL that redirects to it. Common culprits are apex-to-`www.` canonicalization, geographic or region routing, and vanity-domain-to-CDN redirects.
### 4. OAuth discovery fails
If your server requires authentication, Claude performs OAuth discovery before it can connect. A discovery failure surfaces as "Couldn't reach" even though your MCP endpoint itself is reachable. The most common causes:
* **Discovery metadata returns 404.** If your `401` response doesn't include a `WWW-Authenticate` header with a `resource_metadata` pointer, Claude looks for [RFC 9728](https://www.rfc-editor.org/rfc/rfc9728) protected resource metadata and authorization server metadata at the standard `/.well-known/` paths on your MCP server's origin. If those paths return `404` and you haven't pointed Claude elsewhere, Claude has no way to start the OAuth flow.
* **No way to register a client.** Claude needs one of: [RFC 7591 dynamic client registration](https://www.rfc-editor.org/rfc/rfc7591) (a `registration_endpoint` in your authorization server metadata), [Client ID Metadata Documents](/docs/connectors/building/authentication#dcr-and-cimd-details) (`"client_id_metadata_document_supported": true`), or a pre-registered client. Without any of these, Claude can't obtain a client identity. See [supported authentication types](/docs/connectors/building/authentication#supported-authentication-types).
* **Authorization server is on a different host than the MCP server.** Claude discovers protected resource metadata from your MCP server, then makes a *second* round of discovery requests against the authorization server host listed in `authorization_servers`. If that host lives behind a different CDN or WAF, it must also be reachable from Anthropic's egress range. See [cross-host authorization servers](/docs/connectors/building/authentication#cross-host-authorization-servers).
**How to check:** From a public network, run:
```bash theme={null}
curl -i https://your-server.example.com/.well-known/oauth-protected-resource
curl -i https://your-server.example.com/.well-known/oauth-authorization-server
curl -i https://your-server.example.com/.well-known/openid-configuration
```
If your MCP endpoint includes a path component (such as `https://your-server.example.com/mcp`), append it to the well-known path: `/.well-known/oauth-protected-resource/mcp`.
The protected resource metadata should return `200` with valid JSON. For authorization server metadata, your server only needs to answer **one** of the two discovery endpoints — Claude tries `/.well-known/oauth-authorization-server` ([RFC 8414](https://www.rfc-editor.org/rfc/rfc8414)) first, then falls back to `/.well-known/openid-configuration` ([OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html)). A `404` on one is expected if the other returns `200`. Most hosted identity providers (Auth0, Okta, Microsoft Entra, Keycloak, Supabase Auth) only serve `/.well-known/openid-configuration`.
Whichever metadata document resolves should advertise a `registration_endpoint` (DCR), `"client_id_metadata_document_supported": true` (CIMD), or you should be using pre-registered credentials. In a cross-host setup, run the protected-resource curl against your MCP server and the two authorization-server curls against your authorization server's issuer host.
## "Authorization with the MCP server failed"
This error appears after the OAuth flow has started. The most common causes:
* **Issuer mismatch.** The `issuer` value in your authorization server metadata must match the issuer that signs your tokens. If your tokens come from a third-party identity provider such as Supabase Auth or Auth0 but your metadata advertises a different issuer URL, validation can fail.
* **Audience mismatch.** The [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#token-handling) requires your server to verify each access token was issued for it. Claude sends the [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707) `resource` parameter on authorization and token requests, set to the canonical form of your MCP server URL — lowercase scheme and host, no trailing slash, no fragment, no default port — including any path component. Your authorization server should issue tokens with that audience, and your MCP server should accept the canonical value when checking `aud` rather than doing a strict byte-for-byte comparison against what the user typed. Or use whatever audience-binding mechanism your token format supports, as long as it confirms the token was minted for your server and not another service.
* **PKCE not supported.** Claude includes a PKCE `code_challenge` with `code_challenge_method=S256` in every authorization request. If your authorization server doesn't implement S256 PKCE, the flow fails at the token endpoint. The [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#authorization-code-protection) also requires authorization servers to advertise `"code_challenge_methods_supported": ["S256"]` so spec-compliant clients can verify support before starting the flow.
* **Refresh failures.** Use RFC 6749-compliant error codes when a refresh token expires. See [token refresh](/docs/connectors/building/authentication#token-refresh).
* **Slow token endpoint.** Claude waits up to 10 seconds for your `/token` response; if no response bytes arrive in that window, the flow fails here even if your server eventually issues the token. Check the end-to-end latency of your token handler and any proxy or gateway in front of it. See [endpoint latency](/docs/connectors/building/authentication#endpoint-latency).
### Microsoft Entra ID rejects the resource value
If your authorization server is Microsoft Entra ID and the token request fails with `AADSTS9010010` (sometimes surfaced as `invalid_target`), Entra is rejecting the `resource` value Claude sends because it does not match any Application ID URI registered on your app. Claude sets `resource` to your MCP server URL, including the path, and Entra issues a token when that value is listed under **Expose an API** → **Application ID URI** (`identifierUris` in the manifest) on the app registration that represents your protected API. The default `api://{client-id}` URI alone is not sufficient here, because Claude sends the full MCP server URL as the resource value.
**How to fix:**
1. In the [Microsoft Entra admin center](https://entra.microsoft.com), open the app registration that represents your protected API. If you have separate registrations for the OAuth client and the API, this is the API registration, not the client.
2. Under **Expose an API**, add your MCP server URL as an additional [Application ID URI](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-configure-app-expose-web-apis). The value must match exactly, including the path, without a trailing slash.
3. If your server validates the token audience (for example, through Azure App Service Authentication), add the API app's Application (client) ID and its `api://` URI to the allowed token audiences so your server accepts tokens issued for the API. This is the **Allowed token audiences** setting, not **Allowed client applications**, which is a different list.
4. If the OAuth client and the API are separate app registrations, confirm the client has an admin-consented API permission for the scope your API exposes.
If the OAuth flow completes successfully on your server (you see the token issued in your logs) but the connection still fails, file a [GitHub issue](https://github.com/anthropics/claude-ai-mcp/issues) with the `ofid_` reference ID and the timestamps from your server's OAuth logs.
## Diagnostic checklist
Run through these in order before filing an issue:
<Steps>
<Step title="Public DNS resolution">
From a network outside your own, confirm `dig +short your-server.example.com` returns a globally-routable address.
</Step>
<Step title="Public reachability">
From a public network, confirm `curl -i https://your-server.example.com/your-mcp-path` returns a response (a `401` or `405` is fine; a timeout or connection refused is not).
</Step>
<Step title="No redirect">
Run `curl -sI https://your-server.example.com/your-mcp-path` and confirm the response is not a `3xx` redirect to a different host. If it is, register the redirect target instead.
</Step>
<Step title="No WAF block">
Check your edge logs for `403` or `429` responses. Allowlist Anthropic's published egress range if needed. See the [IP address reference](https://platform.claude.com/docs/en/api/ip-addresses).
</Step>
<Step title="Discovery metadata">
Confirm `/.well-known/oauth-protected-resource` returns `200` with valid JSON, and that one of `/.well-known/oauth-authorization-server` or `/.well-known/openid-configuration` does the same — only one is needed. The authorization server metadata should include a `registration_endpoint` (DCR) or advertise `"client_id_metadata_document_supported": true` (CIMD), or you should be using pre-registered credentials, and it should advertise `"code_challenge_methods_supported": ["S256"]`.
</Step>
<Step title="Cross-host hint">
If your authorization server is on a different host than your MCP server, confirm your protected resource metadata's `authorization_servers` field points at it, and that the authorization server's host is reachable from Anthropic's egress range and answers `/.well-known/openid-configuration` (or `/.well-known/oauth-authorization-server`). See [cross-host authorization servers](/docs/connectors/building/authentication#cross-host-authorization-servers).
</Step>
<Step title="Collect the reference ID">
Reproduce the failure and copy the `ofid_` value from the error URL. Include it, your server URL, and your server-side logs in your report.
</Step>
</Steps>
## Related topics
<Columns cols={2}>
<Card title="Authentication" icon="lock" href="/docs/connectors/building/authentication">
OAuth requirements and supported auth types.
</Card>
<Card title="Testing" icon="flask" href="/docs/connectors/building/testing">
How to test your server before publishing.
</Card>
<Card title="Lazy authentication" icon="hourglass" href="/docs/connectors/building/lazy-authentication">
The 401 + WWW-Authenticate discovery handshake.
</Card>
<Card title="IP address reference" icon="network-wired" href="https://platform.claude.com/docs/en/api/ip-addresses">
Anthropic's published IP ranges for allowlisting.
</Card>
</Columns>
connectors/building/what-to-build First recorded · 59 lines, first recorded
# What should I build: MCP, plugin, or both? ## The recommendation ## When to build only one ## What a plugin can bundle ## How they coexist ## Skills are not a standalone directory type ## Build it with Claude ## Next steps
The first capture of this source. The page was already there, and this is what it said.
# What should I build: MCP, plugin, or both?
> Decide between an MCP server, a plugin, or both for your Claude integration
Most partners ship two things: a remote MCP server and a plugin that wraps it. They serve different purposes, and together they give users the best experience.
## The recommendation
Build a **remote MCP server with OAuth** first to provide connectivity and core functionality. Then create a **plugin with skills** that helps users get the most out of that MCP server.
| | MCP server | Plugin |
| ---------------- | ------------------------------------------------ | ------------------------------------------------ |
| **What it is** | A live tool surface Claude calls over HTTP | An installable bundle of skills and connectors |
| **Mental model** | "Claude can call your API" | "Claude knows how to *use* your product" |
| **Contains** | Tools, prompts, resources, optionally MCP App UI | Skills, MCP connector references, slash commands |
| **Works in** | Claude.ai, Desktop, mobile, Cowork, Claude Code | Claude Code, Cowork |
## When to build only one
**MCP server only** is fine when your integration is simple and doesn't need skills—a few well-named tools that Claude can use without additional guidance.
**Plugin only** is fine when you already have a public API or CLI that doesn't need an MCP wrapper. A plugin can ship skills that teach Claude to use that API or CLI directly.
## What a plugin can bundle
A plugin can contain any combination of:
* Skills only
* A single MCP connector reference
* Skills plus one or more MCP connectors
* Multiple MCP connectors
Plugins can reference both remote and local MCP servers. A remote MCP works on every Claude surface (web, mobile, Cowork, Desktop, Claude Code); a local MCP works only in Claude Desktop and Claude Code. Most MCP servers are remote.
## How they coexist
A plugin references a remote MCP server by **URL**. If a user has both your directory connector and your plugin installed, Claude sees one set of tools—the plugin and the connector point at the same server. If a plugin references an MCP URL that isn't in the directory, the connector appears as **Custom** in the user's settings.
Both MCP servers and plugins can update without Anthropic involvement. When you add tools to your MCP server, plugins that reference it pick them up automatically. Plugin updates are pushed via GitHub and pass through automated screening.
## Skills are not a standalone directory type
Skills are user-shared micro-workflows. **Plugins are the distribution mechanism for skills**—you can't submit a skill to the directory on its own. If you have skills to ship, bundle them in a plugin.
## Build it with Claude
The fastest way to scaffold an MCP server is with Claude itself. Install the official [`mcp-server-dev` plugin](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/mcp-server-dev) in Claude Code and run `/mcp-server-dev:build-mcp-server`—it interviews you about your use case, picks the right deployment model, and generates a working server.
## Next steps
<Columns cols={2}>
<Card title="Build an MCP server" icon="server" href="/docs/connectors/building/index">
Start with the MCP building guide.
</Card>
<Card title="Build a plugin" icon="puzzle-piece" href="/docs/plugins/overview">
Bundle skills and connectors together.
</Card>
</Columns>
connectors/custom/desktop-extensions First recorded · 82 lines, first recorded
# Desktop extensions ## What are desktop extensions? ## MCPB (MCP Bundles) ### Key features ## When to use desktop vs remote ## Enterprise deployment ## Security considerations ## Getting started ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Desktop extensions
> Deploy enterprise-grade MCP servers with MCPB
Desktop extensions allow you to deploy local MCP servers for Claude Desktop with enterprise-grade features using MCPB (MCP Bundles).
<Note>
Available for Team and Enterprise plans with Claude Desktop.
</Note>
## What are desktop extensions?
Desktop extensions are local MCP servers that run on user devices, providing:
* Local tool access without internet dependency
* Enhanced security for sensitive operations
* Custom integrations for internal tools
* Enterprise deployment capabilities
## MCPB (MCP Bundles)
MCPB is Anthropic's utility for building and deploying desktop extensions:
* Package MCP servers for distribution
* Handle cross-platform compatibility
* Manage dependencies
* Support enterprise deployment
### Key features
* **Bundling**: Package your MCP server with all dependencies
* **Distribution**: Deploy to users via your organization's channels
* **Updates**: Manage version updates centrally
* **Security**: Sign and verify extensions
## When to use desktop vs remote
| Use Case | Recommended |
| --------------------------- | ----------------- |
| Access to local files/tools | Desktop Extension |
| Internet-hosted services | Remote MCP |
| Sensitive enterprise data | Desktop Extension |
| Public APIs | Remote MCP |
| Offline capability needed | Desktop Extension |
## Enterprise deployment
For Team and Enterprise plans, admins can:
1. Build custom desktop extensions
2. Package with MCPB
3. Deploy through enterprise software management
4. Control which extensions are available to users
## Security considerations
Desktop extensions run locally with user permissions:
* Access only what the user can access
* No data transmitted unless explicitly designed
* Full audit capability for enterprise
* Revocable by administrators
## Getting started
1. Review the [MCPB documentation](https://github.com/modelcontextprotocol/mcpb)
2. Build your MCP server
3. Bundle with MCPB
4. Test locally
5. Deploy to your organization
## Related topics
<Columns cols={2}>
<Card title="Building Connectors" icon="hammer" href="/docs/connectors/building/">
Learn to build MCP servers.
</Card>
<Card title="Remote MCP" icon="globe" href="/docs/connectors/custom/remote-mcp">
Using cloud-hosted connectors.
</Card>
</Columns>
connectors/custom/remote-mcp First recorded · 148 lines, first recorded
# Third party connectors with remote MCP ## What are third party connectors? ### Finding connectors ## Adding custom connectors ### For Team and Enterprise plans ### For Free, Pro, and Max plans ### Enabling connectors in chat ## Authenticating with request headers ### Adding a request header ### Enter the full header value ## Managing connectors ## Security and privacy ### Best practices ### Tool actions ## Reporting issues ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Third party connectors with remote MCP
> Connect Claude to your tools using the Model Context Protocol
Custom connectors enable you to link Claude directly to your essential tools and data sources using the Model Context Protocol (MCP).
## What are third party connectors?
Custom connectors allow Claude to operate within your preferred software and leverage comprehensive context from your external tools.
You can:
* Connect Claude to existing remote MCP servers
* Build your own remote MCP servers for any tool
### Finding connectors
Browse the [Connectors Directory](/docs/connectors/directory) to discover third-party MCP servers that are ready to use across all Claude products. Some are verified by Anthropic and others are community connectors; see [connector verification](/docs/connectors/verification).
## Adding custom connectors
You can manually add any third-party connector to Claude as long as you have the URL of that remote MCP server.
<Warning>
**Security Notice**: Custom connectors allow connections to unverified services. Claude can access and perform actions within these services, so review security considerations carefully.
</Warning>
### For Team and Enterprise plans
**Owners must:**
1. Navigate to **Organization settings > Connectors**
2. Select **Add**, then **Custom**. If Claude asks for the connector type, choose **Web**.
3. Enter the remote MCP server URL
4. Optionally configure OAuth Client ID/Secret in Advanced settings
5. Click "Add"
**Members then:**
1. Go to **Customize > Connectors**
2. Find the connector with "Custom" label
3. Click "Connect" to authenticate
### For Free, Pro, and Max plans
1. Navigate to **Customize > Connectors**
2. Click "Add custom connector"
3. Enter the remote MCP server URL
4. Optionally configure OAuth credentials
5. Click "Add"
### Enabling connectors in chat
Use the "+" button in your chat interface to access "Connectors," where you can enable/disable connectors per conversation.
## Authenticating with request headers
<Note>
Request header authentication is in beta. This feature is being slowly rolled out to customers; contact Anthropic for early access.
</Note>
If your MCP server authenticates with an API key, bearer token, or other fixed credential instead of OAuth, you can configure it in the **Request headers** section of the Add custom connector dialog. Claude stores each header value securely, does not show it again after you save, and sends it on every request to your server.
Request headers suit services where everyone in your organization shares one credential, such as an internal tool or a service account. If each person needs to sign in with their own account, use OAuth instead.
You can also use request headers in addition to OAuth, including OAuth with your own pre-registered client credentials. Headers configured on an OAuth connection are sent on every request alongside the OAuth bearer token. This is useful for verifying where a request came from, passing additional client metadata, or working with tunnels and gateways that need their own routing header. The one exception is `Authorization`: OAuth owns that header, so it cannot be configured as a request header on an OAuth connection.
### Adding a request header
1. In the Add custom connector dialog, open **Request headers**.
2. Select a header name from the list, or enter one manually. Claude accepts a fixed set of standard authentication and routing header names such as `authorization`, `x-api-key`, and `x-auth-token`. Header names are restricted to this allowlist for security reasons: each name is reviewed before Claude will send it to a third-party server, which prevents connector configuration from being used to send arbitrary header names. To request an addition to the allowlist, contact your Anthropic representative.
3. Enter the header value exactly as your server expects to receive it.
4. Choose whether the header is **Required**. When a required header has no stored value at connection time, the connection fails. When an optional header has no value, Claude simply omits it from the request.
5. Repeat for any additional headers your server needs (you can add up to four), then click **Add**.
### Enter the full header value
Claude sends the value exactly as you enter it. It does not add an authentication scheme or any other prefix.
For an `Authorization` header, include the scheme in the value:
| You enter | Claude sends |
| ------------------- | ---------------------------------- |
| `Bearer your-token` | `Authorization: Bearer your-token` |
| `your-token` | `Authorization: your-token` |
Most servers that use bearer tokens reject the second form. If your server's documentation shows `Authorization: Bearer YOUR_TOKEN`, enter `Bearer ` followed by your token, including the space. The same applies to Basic authentication: enter `Basic ` followed by the base64-encoded credentials.
## Managing connectors
To remove or edit connectors:
1. Go to **Customize > Connectors**
2. Click "Remove" or select the three-dot menu
3. Follow prompts to edit or remove
## Security and privacy
### Best practices
* Only connect to servers from trusted organizations
* Carefully review requested permission scopes during authentication
* Be aware of prompt injection risks; Claude has built-in protections
* Monitor for unexpected changes in tool behavior
### Tool actions
Remote MCP servers enable Claude to invoke tools that can:
* Read data from applications
* Create, modify, or delete data
* Take actions on your behalf
**Usage guidelines:**
* Monitor Claude's actions for unintended effects
* Review tool approval requests carefully
* Only click "Always allow" for trusted servers
* Turn off connectors you aren't using with the toggles in the chat "+" menu's **Connectors** item
* Block individual tools you don't need under **Customize > Connectors** by selecting the connector and setting the tool's permission to **Blocked**
## Reporting issues
Report malicious MCP servers to [Anthropic's Bug Bounty Program](https://www.anthropic.com/responsible-disclosure-policy).
## Related topics
<Columns cols={2}>
<Card title="Building Connectors" icon="hammer" href="/docs/connectors/building/">
Learn to build your own MCP servers.
</Card>
<Card title="Connectors Directory" icon="book" href="/docs/connectors/directory">
Browse pre-built connectors.
</Card>
<Card title="MCP Overview" icon="plug" href="/docs/connectors/building/mcp">
Understand the Model Context Protocol.
</Card>
<Card title="Desktop Extensions" icon="desktop" href="/docs/connectors/custom/desktop-extensions">
Deploy enterprise-grade MCP servers.
</Card>
<Card title="MCP in Claude Code" icon="terminal" href="https://code.claude.com/docs/en/mcp-quickstart">
Add the same server to Claude Code from the command line.
</Card>
</Columns>
connectors/directory First recorded · 65 lines, first recorded
# Connectors directory ## How the directory works ## Browsing the directory ## Requesting a connector on a Team plan ## When a connector's endpoint changes ## Submitting to the directory ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Connectors directory > Browse verified and community MCP integrations for Claude The Connectors Directory is a catalog of [MCP](/docs/connectors/building/mcp) servers that work across all Claude products — Claude.ai, Claude Desktop, Claude Mobile, Claude Code, and Cowork. The directory contains both verified connectors and community connectors. Verified connectors are reviewed by Anthropic for security, reliability, and compatibility. Community connectors pass Anthropic's automated checks but are not reviewed in depth by Anthropic. The label reflects how much review a connector has had, not how it works: verified and community connectors work the same way once connected. See [connector verification](/docs/connectors/verification) to learn what each label means. <Note> All connectors in the directory are subject to the [Anthropic Software Directory Policy](https://support.claude.com/en/articles/13145358-anthropic-software-directory-policy) and the [Anthropic Software Directory Terms](https://support.claude.com/en/articles/13145338-anthropic-software-directory-terms). </Note> ## How the directory works * The same catalog serves Claude.ai, Cowork, Desktop, mobile, and Claude Code. * Directory connectors are eligible for **Suggested Connectors**—in-chat recommendations when relevant to the user's task. Every directory entry is included automatically. * Ranking is usage-based, similar to other app stores. * No domain-ownership proof (DNS or `.well-known`) is required—that requirement applies only to the open MCP Registry, not the Anthropic Directory. * The help-docs link shown in the in-product connector setup flow is not partner-customizable. Directory connectors and custom connectors run on the same infrastructure—see [directory vs custom](/docs/connectors/building/directory-vs-custom). ## Browsing the directory Access the Connectors Directory through: * **[Customize > Connectors](https://claude.ai/customize/connectors)** in claude.ai * **[Organization settings > Connectors](https://claude.ai/admin-settings/connectors)** for Team/Enterprise admins ## Requesting a connector on a Team plan On Claude Team plans, members who do not have permission to enable connectors see a **Request** button on each directory connector instead of a connect action. Selecting **Request** sends the connector to your organization's admins for review. The button changes to **Requested** while the request is pending. If you are a Team admin with permission to manage connectors, member requests appear in two places: * **[Organization settings > Connectors](https://claude.ai/admin-settings/connectors)** shows a **Requested by your team** section above the connector list. * **[Organization settings > Notifications](https://claude.ai/admin-settings/notifications)** lists each requested connector on the **Requests** tab, and the **Notifications** item in the admin sidebar shows a count badge while requests are pending. From either location you can enable the connector for your organization or dismiss the request. Claude shows the requesting member the outcome the next time they open the connectors directory. ## When a connector's endpoint changes Occasionally a provider updates the endpoint URL behind its directory listing, for example moving a server from `https://mcp.example.com/sse` to `https://mcp.example.com/mcp`. This is a routine change on the provider's side. Here is what you may notice in Claude: * **Your existing connection keeps working.** Connectors you added before the change keep using the endpoint they were installed with, and your authentication is unaffected. * **It appears as a custom connector.** Because your connector no longer matches the updated directory listing, it shows under "Custom" in [Customize > Connectors](https://claude.ai/customize/connectors) instead of as a named directory connector. * **The directory listing shows as not installed.** Adding the connector from the directory again without removing the original gives you two connections: your original one and a new one on the updated endpoint. To move to the new endpoint, remove the connector and re-add it from the directory. Claude prompts you to authenticate with the service again. ## Submitting to the directory Organizations can submit their MCP servers for review and inclusion in the directory: 1. Review the [submission guidelines](/docs/connectors/building/submission) 2. Ensure your server meets security and compatibility standards 3. Submit through the [submission portal](https://claude.ai/admin-settings/directory/submissions/new) in Claude.ai admin settings Submitting requires a Team or Enterprise organization and directory management access (organization Owners by default); see [Before you start](/docs/connectors/building/submission#before-you-start). After publication, the same dashboard shows your server's health and usage; see [Managing your listing](/docs/connectors/building/managing-your-listing). ## Related topics <Card title="Build a connector" icon="code" href="/docs/connectors/building/index"> Create your own MCP server. </Card>
connectors/getting-started First recorded · 130 lines, first recorded
# Get started with connectors ## What you'll learn ## Prerequisites ## Setting up your first connector ### Step 1: Access connector settings ### Step 2: Choose a connector ### Step 3: Authenticate ## Using connectors in conversations ### In chat ### In projects ## Connector-specific tips ### Google Drive ### Gmail & Calendar ### GitHub ### Slack ### Microsoft 365 ## Best practices ## Troubleshooting ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Get started with connectors
> Learn to connect Claude to your tools and data
This tutorial walks you through setting up and using Claude's connector integrations to enhance your workflow.
## What you'll learn
* Setting up your first connector
* Using connectors in conversations
* Best practices for each integration
* Troubleshooting common issues
## Prerequisites
* A Claude account (Pro, Max, Team, or Enterprise for most connectors)
* Accounts on the services you want to connect
## Setting up your first connector
### Step 1: Access connector settings
1. Go to [claude.ai](https://claude.ai)
2. Select **Customize** in the sidebar
3. Select **Connectors**
### Step 2: Choose a connector
Available connectors include:
* Google Drive, Gmail, Calendar
* GitHub
* Slack
* Microsoft 365
### Step 3: Authenticate
1. Click "Connect" next to your chosen service
2. Log in to your account on that service
3. Grant Claude the requested permissions
4. Return to Claude
## Using connectors in conversations
### In chat
1. Start a new conversation
2. Click the "+" button
3. Select "Add from \[Service]"
4. Choose the content you want to include
5. Ask your question
### In projects
1. Open your project
2. Click "Add Content"
3. Select the connector
4. Add documents to your project knowledge
## Connector-specific tips
### Google Drive
* Best for: Document analysis, research
* Add multiple Google Docs for comprehensive context
* Documents sync automatically with updates
### Gmail & Calendar
* Best for: Finding information, scheduling context
* Ask questions like "What did Sarah say about the budget?"
* Claude can search your emails but can't send them
### GitHub
* Best for: Code understanding, documentation
* Add entire repositories or specific files
* Use with Projects for persistent codebase context
### Slack
* Best for: Finding discussions, team context
* Search channels and direct messages
* Requires installing the earlier Claude in Slack app first
### Microsoft 365
* Best for: Enterprise document search
* Access SharePoint, OneDrive, Outlook, Teams
* Requires a work or school Microsoft account
## Best practices
1. **Connect what you need**: Only connect services with relevant data
2. **Review permissions**: Understand what Claude can access
3. **Keep context focused**: Don't overload with too much data
## Troubleshooting
<AccordionGroup>
<Accordion title="Connector won't authenticate">
* Clear browser cookies and try again
* Check that you have the right account permissions
* Try a different browser
</Accordion>
<Accordion title="Data not showing up">
* Verify you have access to the data in the source service
* Wait a moment for sync to complete
* Try disconnecting and reconnecting
</Accordion>
<Accordion title="Connection expired">
* Go to Customize > Connectors
* Click "Reconnect" or "Refresh"
* Re-authenticate with the service
</Accordion>
</AccordionGroup>
## Related topics
<Columns cols={2}>
<Card title="Connectors Overview" icon="plug" href="/docs/connectors/overview">
See all available connectors.
</Card>
<Card title="Custom Connectors" icon="code" href="/docs/connectors/custom/remote-mcp">
Build your own integrations with MCP.
</Card>
</Columns>
connectors/github/index First recorded · 77 lines, first recorded
# GitHub integration ## Adding GitHub repositories ### In chats ### In projects ## Connecting to private repositories ## Best practices ## What information is retrieved ## Frequently asked questions
The first capture of this source. The page was already there, and this is what it said.
# GitHub integration
> Connect your code repositories to Claude
Connect GitHub repositories directly to Claude to provide comprehensive context for software development tasks. Claude can understand your codebase and assist with development questions.
<Note>
Available on all plans including Free.
</Note>
## Adding GitHub repositories
### In chats
1. Click the "+" button in the lower left corner of the chat interface
2. Select "Add from GitHub" from the dropdown menu
3. Use the file browser to select specific files and folders
4. When sending your message, Claude accesses and processes the selected content
### In projects
1. Click the "+" button in your project knowledge section
2. Select "GitHub" from the dropdown
3. Search accessible repositories or paste a repository URL
4. Use the file browser to select specific files and folders
5. Your selected content is added to project knowledge
**Keeping content current:**
* Use the "Sync" icon to ensure you're working with the latest codebase
* Use the "Configure files" icon to modify which files Claude analyzes
<Note>
If you're not authenticated with GitHub, you'll be redirected to authenticate before using the integration.
</Note>
## Connecting to private repositories
If you see a warning after entering a valid URL, you're likely attempting to connect to a private repository.
Follow the link to the GitHub App where you can:
* **Grant access yourself**: Choose between allowing Claude access to all repos or specific ones
* **Request access**: GitHub organization administrators receive an email notification. Once approved, you can sync and access the repository
## Best practices
1. **Start small**: Begin with a small codebase subset to understand how Claude interprets your code
2. **Iterate and refine**: Ask follow-up questions if initial responses need clarification
3. **Combine with human expertise**: Use Claude's insights as a starting point for team discussion
4. **Thoughtful file selection**: Include key files central to your task while staying within token limits
5. **Regular updates**: Refresh GitHub sync periodically, especially before new analysis or major repo changes
## What information is retrieved
| Retrieved | Not Retrieved |
| -------------- | ------------------- |
| File names | Commit history |
| File contents | Pull requests |
| Branch content | Issues |
| | Repository metadata |
## Frequently asked questions
<AccordionGroup>
<Accordion title="What if my repository updates after adding it?">
Click "Sync now" to fetch the latest changes from your repository.
</Accordion>
<Accordion title="Can I add multiple repositories?">
Yes, add multiple repositories to provide comprehensive context, provided they fit within Claude's context window.
</Accordion>
<Accordion title="What happens if I lose repository access?">
You won't be able to view its contents in projects where it was previously added. The repository preview is removed, but conversation history remains.
</Accordion>
</AccordionGroup>
connectors/google/calendar First recorded · 79 lines, first recorded
# Google Calendar integration ## Connect Google Calendar ## How to use Calendar integration ### 1. Ask about your schedule ### 2. Review Claude's response ### 3. Follow up ## Privacy and data handling ### Authentication ### Data access ## Limitations ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Google Calendar integration
> Access your calendar and meeting information with Claude
The Google Calendar integration enables Claude to understand your calendar commitments, helping you manage your schedule more effectively.
<Note>
Available on Pro, Max, Team, and Enterprise plans.
</Note>
## Connect Google Calendar
1. In claude.ai, go to **Customize > Connectors**.
2. Find Google Calendar and click **Connect**.
3. Sign in to your Google account and grant the requested permissions.
On Team and Enterprise plans, an Owner or Primary Owner must enable the integration for your organization before it appears in your connector list. For the full walkthrough, including troubleshooting, see [Get started with connectors](/docs/connectors/getting-started).
## How to use Calendar integration
### 1. Ask about your schedule
Simply ask Claude questions about your calendar. Claude automatically detects when calendar data is needed.
**Example questions:**
* "What meetings do I have tomorrow?"
* "When is my next meeting with the product team?"
* "Do I have any conflicts next week?"
* "Who's attending the budget review meeting?"
### 2. Review Claude's response
Claude provides answers that include:
* Clear answers to your questions
* Citations indicating which calendar events were used
* Links to original events when applicable
### 3. Follow up
You can ask for more details about:
* Meeting attendees
* Event timing and duration
* Related meetings and patterns
## Privacy and data handling
### Authentication
You must authenticate directly to your Google account. For Claude for Work (Team/Enterprise) plans, an Owner or Primary Owner must enable integrations at the account level.
### Data access
* Claude accesses only data from your connected Google account
* Access occurs only when you explicitly request it
* Minimum information is retrieved to answer your question
* Your existing calendar permissions are mirrored
## Limitations
<Warning>
* Claude cannot create, modify, or delete calendar events
* Claude cannot send calendar invitations
* Only calendars you have access to can be searched
</Warning>
## Related topics
<Columns cols={2}>
<Card title="Gmail" icon="envelope" href="/docs/connectors/google/gmail">
Search and analyze your emails.
</Card>
<Card title="Google Drive" icon="google-drive" href="/docs/connectors/google/drive">
Connect your documents.
</Card>
</Columns>
connectors/google/drive First recorded · 89 lines, first recorded
# Google Drive integration ## How to add Google Docs ### In chats ### In projects ## Supported file types ## Key features ## Frequently asked questions ## Troubleshooting ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Google Drive integration
> Connect Google Docs directly to Claude
The Google Drive integration lets you connect Google Docs directly to Claude on paid Claude.ai plans. You can add documents by pasting URLs or selecting recent files to provide context for your conversations.
<Note>
Available on Pro, Max, Team, and Enterprise plans.
</Note>
## How to add Google Docs
### In chats
1. Click the plus sign (+) in the chat interface
2. Select "Add from Google Drive"
3. Authenticate with Google on first use
4. Search recent documents or paste a document URL
5. Claude accesses and processes the document when you send your message
### In projects
The integration works only in private projects:
1. Click "Add Content" in project knowledge
2. Select "Google Drive"
3. Authenticate on first use
4. Search or paste a document URL
5. The document becomes available to Claude within that project
## Supported file types
| Type | Supported | Notes |
| -------------------- | --------- | -------------------------------- |
| Google Docs | ✅ | Up to 10MB, text extraction only |
| Google Sheets | ❌ | Not currently supported |
| Google Slides | ❌ | Not currently supported |
| Images in docs | ❌ | Not extracted |
| Comments/Suggestions | ❌ | Not extracted |
<Tip>
Convert .docx files by opening in Google Docs, clicking "File," then "Save as Google Docs."
</Tip>
## Key features
* **Live sync**: Documents continue syncing with the latest Google Drive version
* **Multiple documents**: Add multiple docs if they fit the context window
* **Permission-based**: You can only sync documents you have permission to view
## Frequently asked questions
<AccordionGroup>
<Accordion title="Do documents update after I add them?">
Yes, documents continue syncing with the latest Google Drive version.
</Accordion>
<Accordion title="Can I add multiple documents?">
Yes, you can add multiple docs as long as they fit within the context window.
</Accordion>
<Accordion title="What happens if I lose access to a document?">
You'll lose document preview access but your conversation history remains.
</Accordion>
</AccordionGroup>
## Troubleshooting
For reconnection errors:
1. Navigate to **Customize > Connectors**
2. Find Google Drive
3. Click the menu button (...)
4. Select "Disconnect"
5. Authenticate again when prompted
For persistent issues, disconnect from Google account connections at [myaccount.google.com](https://myaccount.google.com), search "Claude for Google Drive," and delete all connections.
## Related topics
<Columns cols={2}>
<Card title="Gmail" icon="envelope" href="/docs/connectors/google/gmail">
Search and analyze your emails.
</Card>
<Card title="Google Calendar" icon="calendar" href="/docs/connectors/google/calendar">
Access your calendar information.
</Card>
</Columns>
connectors/google/gmail First recorded · 82 lines, first recorded
# Gmail integration ## Connect Gmail ## How to use Gmail integration ### 1. Ask a question ### 2. Review Claude's response ### 3. Follow up ## Understanding citations ## Privacy and data handling ### Authentication ### Data access ## Limitations ## Related topics
The first capture of this source. The page was already there, and this is what it said.
# Gmail integration
> Search and analyze emails with Claude
The Gmail integration enables Claude to search your emails and provide answers based on your email content, reducing time spent retrieving information.
<Note>
Available on Pro, Max, Team, and Enterprise plans.
</Note>
## Connect Gmail
1. In claude.ai, go to **Customize > Connectors**.
2. Find Gmail and click **Connect**.
3. Sign in to your Google account and grant the requested permissions.
On Team and Enterprise plans, an Owner or Primary Owner must enable the integration for your organization before it appears in your connector list. For the full walkthrough, including troubleshooting, see [Get started with connectors](/docs/connectors/getting-started).
## How to use Gmail integration
### 1. Ask a question
Simply ask Claude a question that needs email information. Claude automatically detects when email data is needed.
**Example questions:**
* "What did Sarah say about the project deadline?"
* "Find emails about the Q4 budget review"
* "Summarize my conversation with the sales team last week"
### 2. Review Claude's response
Claude provides answers that include:
* Clear answers to your questions
* Citations indicating which emails were used
* Links to original sources when applicable
### 3. Follow up
You can ask for more details, such as:
* Requesting additional email information
* Finding related threads
* Summarizing longer conversations
## Understanding citations
Citations show which specific emails Claude used to answer your question. You can follow links back to original sources for verification and additional context.
## Privacy and data handling
### Authentication
You must authenticate directly to your Google account. For Claude for Work (Team/Enterprise) plans, an Owner or Primary Owner must enable integrations at the account level.
### Data access
* Claude accesses only data from your connected Google account
* Access occurs only when you explicitly request it
* Minimum information is retrieved to answer your question
* Your existing Gmail permissions are mirrored
## Limitations
<Warning>
* Claude cannot create, send, or modify emails
* Embedded images in emails are not visible to Claude
* Only emails you have access to can be searched
</Warning>
## Related topics
<Columns cols={2}>
<Card title="Google Calendar" icon="calendar" href="/docs/connectors/google/calendar">
Access your calendar information.
</Card>
<Card title="Google Drive" icon="google-drive" href="/docs/connectors/google/drive">
Connect your documents.
</Card>
</Columns>
connectors/microsoft/365 First recorded · 118 lines, first recorded
# Microsoft 365 connector ## Capabilities ## Setup requirements ### Prerequisites ### Phase 1: Administrator setup ### Phase 2: User enablement ## Usage ### Example queries ## What you can access ## Write actions ## Permissions ## Troubleshooting
The first capture of this source. The page was already there, and this is what it said.
# Microsoft 365 connector
> Connect SharePoint, OneDrive, Outlook, and Teams to Claude
The Microsoft 365 connector enables Claude to search, analyze, and act on information across SharePoint, OneDrive, Outlook, and Teams.
<Note>
Available on all Claude plans: Free, Pro, Max, Team, and Enterprise. On Team and Enterprise plans, an organization Owner must enable the connector before members can connect.
</Note>
## Capabilities
With this connector, Claude can:
* **Search and analyze documents** across SharePoint sites and OneDrive libraries
* **Access email threads** and analyze Outlook communications
* **Review meeting information** from Teams Calendar
* **Pull insights** from Teams Chat discussions
* **Send and manage email**, including drafts, labels, mail filters, and automatic replies
* **Manage calendar events** and find meeting times
* **Create and update files** in SharePoint
## Setup requirements
On Free, Pro, and Max plans, no organization-level setup is needed. Connect from **Customize > Connectors** in claude.ai. A Microsoft Entra Global Administrator still needs to grant one-time tenant consent for your Microsoft organization.
### Prerequisites
* A work or school Microsoft account on a Microsoft Entra tenant (personal accounts such as outlook.com, hotmail.com, or live.com aren't supported)
* Claude user with Owner or Primary Owner role (Team and Enterprise plans)
* Global Administrator access to Microsoft Entra tenant
* Active Microsoft 365 accounts for all users (Team and Enterprise plans)
### Phase 1: Administrator setup
**Automatic Setup (Recommended):**
1. Navigate to **Organization settings > Connectors**
2. Select **Add**, then **All available**
3. Find Microsoft 365 and select "Add to your team"
4. Connect individually and grant organization-wide permissions
5. (Optional) Restrict user access or revoke specific permission scopes
### Phase 2: User enablement
Once enabled by administrators, team members:
1. Navigate to **Customize > Connectors**
2. Find Microsoft 365 and click "Connect"
3. Authenticate with credentials
## Usage
Ask Claude questions requiring Microsoft 365 data, or ask Claude to take an action such as sending an email or updating a file. Claude automatically detects and uses the necessary tools.
### Example queries
* "Find the Q4 strategic planning document in SharePoint"
* "Summarize email conversations about the product launch"
* "What discussions happened in Teams about the marketing campaign?"
* "Review meeting notes from last week's leadership sync"
* "Draft a reply to the latest email about the vendor contract"
* "Schedule a 30-minute sync with the design team next week"
## What you can access
| Service | Capabilities |
| ----------------------- | ---------------------------------------------------------------------------------------------------------- |
| **SharePoint/OneDrive** | Search and analyze documents; create and update files in SharePoint |
| **Outlook** | Search email threads and archived emails; send and manage mail; create, update, and delete calendar events |
| **Teams Calendar** | Review meeting summaries and attendance |
| **Teams Chat** | Access channel and chat discussions |
## Write actions
Claude can take actions in Outlook and SharePoint: send mail and manage drafts; organize mail with labels, filters, and trash; set automatic replies; create, update, and delete calendar events; and create and update files in SharePoint. Read and search tools work the same whether or not write actions are enabled.
Write actions are controlled by your organization's administrators in two places:
1. **Approve the write permissions.** If your tenant's consent for the connector covers only read permissions, a Microsoft Entra Global Administrator or Application Administrator approves the updated permission set (mail, calendar, mailbox settings, and file writes) under **Enterprise applications** in the Entra admin center. This is a one-time action per tenant.
2. **Turn on write actions.** If write actions are off for your organization, administrators turn them on for all users in the Microsoft 365 connector configuration, or enable them for specific users with role-based access control (beta).
Claude cannot attach files to the drafts it creates and cannot send Teams messages.
For setup steps, see [Connect to Microsoft 365](https://support.claude.com/en/articles/15183774-connect-to-microsoft-365) and [Set up the Microsoft 365 connector](https://support.claude.com/en/articles/12542951-set-up-the-microsoft-365-connector) in the help center. The [Microsoft 365 connector security guide](https://support.claude.com/en/articles/12684923-microsoft-365-connector-security-guide) covers the permission model.
## Permissions
<Note>
All permissions are delegated: Claude acts on behalf of users and can only access and change content that you already have permission to access and change in Microsoft 365. Write actions are available when your administrators enable them (see [Write actions](#write-actions)).
</Note>
## Troubleshooting
<AccordionGroup>
<Accordion title="Authentication failures">
* Verify correct Microsoft 365 credentials
* Check active license status
* Review organizational third-party app policies
* Try a different browser
* Clear cookies and cache
</Accordion>
<Accordion title="Documents not found">
* Verify direct access to the document in Microsoft 365
* Ensure document is in SharePoint/OneDrive (not local)
* Recently uploaded documents may need time to index
* Use specific SharePoint site names
* Search by exact filename
</Accordion>
<Accordion title="Incomplete search results">
* Be more specific about requirements
* Specify locations and date ranges
* Use exact phrases
* Break complex queries into simpler questions
</Accordion>
</AccordionGroup>
connectors/overview First recorded · 92 lines, first recorded
# Connectors overview ## How connectors work ## Types of connectors ### Prebuilt integrations ### Remote MCP servers ### MCP Apps ### MCP Bundles ### Self-serve local MCP ## Ways to connect ### Connectors directory ### Third-party connectors ## Related concepts ### Plugins ## Platform availability ## Next steps
The first capture of this source. The page was already there, and this is what it said.
# Connectors overview
> Connect Claude to external tools, data, and UI through MCP
Connectors extend Claude's capabilities by connecting it to external tools and data sources. They are powered by the [Model Context Protocol (MCP)](/docs/connectors/building/mcp), an open standard created by Anthropic that provides a unified way for AI applications to interact with the outside world.
## How connectors work
Connectors can do two things:
* **Provide tools and information** — Give Claude access to external data and the ability to take actions (search files, read emails, create issues, etc.)
* **Surface UI components** — Render interactive visual elements directly in the conversation through [MCP Apps](/docs/connectors/building/mcp-apps/getting-started)
<Note>
**Building for Claude?** Most partners ship both a remote MCP server and a plugin that wraps it with skills. See [what to build](/docs/connectors/building/what-to-build) for the decision guide.
</Note>
## Types of connectors
### Prebuilt integrations
Anthropic provides first-party integrations with popular services like Google Drive, Gmail, Google Calendar, GitHub, Slack, and Microsoft 365. These are ready to use with no setup beyond authentication. See [Getting started](/docs/connectors/getting-started) for setup instructions.
### Remote MCP servers
[Remote MCP servers](/docs/connectors/custom/remote-mcp) communicate with Claude over the internet, giving it access to cloud-hosted tools and data. You can connect to existing remote MCP servers or build your own for any tool or service.
### MCP Apps
[MCP Apps](/docs/connectors/building/mcp-apps/getting-started) allow MCP servers to display interactive UI elements in conversational MCP clients. Rather than only returning text, an MCP App can render charts, maps, forms, and other visual components directly in the chat. See the [design guidelines](/docs/connectors/building/mcp-apps/design-guidelines) and [cross-platform compatibility](/docs/connectors/building/mcp-apps/cross-compatibility) docs for building MCP Apps.
### MCP Bundles
[MCP Bundles (MCPB)](/docs/connectors/custom/desktop-extensions) package MCP servers with their dependencies for distribution as desktop extensions. MCPB handles cross-platform compatibility, dependency management, code signing, and centralized version updates — making it suitable for enterprise deployment of local MCP servers to Claude Desktop.
### Self-serve local MCP
Local MCP servers distributed through third-party package registries like npm or PyPI cannot be listed directly in the Connectors Directory. To distribute a local server, package it as an [MCPB](/docs/connectors/building/mcpb) for the Desktop Extensions gallery, or bundle it in a [plugin](/docs/plugins/overview) using `.mcp.json` and submit it to the [plugin directory](/docs/plugins/submit).
## Ways to connect
### Connectors directory
The [Connectors Directory](/docs/connectors/directory) is an open catalog of MCP servers from Anthropic and third-party developers, available across all Claude products. It includes both connectors that Anthropic has verified and community connectors; see [connector verification](/docs/connectors/verification) to learn what each label means.
### Third-party connectors
You can build and connect your own MCP servers for proprietary tools or workflows. See [Third-party Connectors](/docs/connectors/custom/remote-mcp) for remote MCP and [Desktop Extensions](/docs/connectors/custom/desktop-extensions) for local integrations.
## Related concepts
### Plugins
[Plugins](/docs/plugins/overview) combine MCP connectors, [Skills](/docs/skills/overview), slash commands, and sub-agents into shareable capability packages. They are available in Claude Code and Cowork. You can also [submit your plugin](/docs/plugins/submit) to the plugin directory.
## Platform availability
Prebuilt integrations and directory connectors work across all Claude products:
* **Claude.ai** — Full remote MCP support & MCP Apps
* **Claude Desktop** — Full MCP support and local desktop extensions
* **Claude Mobile** — Remote MCP access
* **Claude Code** — Remote MCP access and plugins
* **Claude Cowork** — Full MCP and plugin support
## Next steps
<Columns cols={2}>
<Card title="Getting started" icon="rocket" href="/docs/connectors/getting-started">
Set up your first connector.
</Card>
<Card title="Connectors directory" icon="grid-2" href="/docs/connectors/directory">
Browse verified and community integrations.
</Card>
<Card title="Build a connector" icon="code" href="/docs/connectors/building/index">
Create your own MCP server.
</Card>
<Card title="MCP Apps" icon="window" href="/docs/connectors/building/mcp-apps/getting-started">
Build UI components for Claude.
</Card>
<Card title="MCP in Claude Code" icon="terminal" href="https://code.claude.com/docs/en/mcp-quickstart">
Add an MCP server to Claude Code from the command line.
</Card>
<Card title="Claude Code documentation" icon="terminal" href="https://code.claude.com/docs">
Install, configure, and use the Claude Code CLI.
</Card>
</Columns>
connectors/slack/index First recorded · 96 lines, first recorded
# Slack integration ## Claude in Slack (earlier app) ### Ways to interact with Claude ## Installation ### For Slack admins ### For individual users ## Slack connector ### Enabling the connector ## Managing connections ### Viewing connection status ### Disconnecting ## Privacy & data ## Troubleshooting
The first capture of this source. The page was already there, and this is what it said.
# Slack integration > Use Claude directly in Slack and connect your workspace Integrate Claude and Slack in two ways: add Claude directly to your Slack workspace, or enable the Slack connector for your Claude apps. <Note> This page covers the earlier per-user Claude in Slack app. The current product is [Claude Tag](/docs/claude-tag/overview), which gives your team one Claude identity set up by an admin. If your organization used the earlier app, see [Migrate from the earlier Claude in Slack](/docs/claude-tag/admins/migrate-from-earlier). </Note> ## Claude in Slack (earlier app) Claude is available to paid Slack plan users. Slack admins must approve the app before individual users can access it. ### Ways to interact with Claude 1. **Direct messaging**: Start private conversations with @Claude 2. **AI assistant panel**: Click Claude's icon in Slack's AI assistant header 3. **Thread participation**: Mention @Claude in any thread for assistance All surfaces support the same Claude capabilities you've enabled, including web search and tool integrations. <Note> Team and Enterprise plan users with Claude Code access can route coding tasks directly to Claude Code by mentioning @Claude. </Note> ## Installation ### For Slack admins 1. Navigate to the Claude app in Slack's App Marketplace 2. Click "Add to Slack" 3. Review and approve for your organization 4. Deploy org-wide or to specific workspaces **For multi-workspace deployment:** * Access your Slack management workspace * Navigate to **Integrations → Installed apps → Add to more workspaces** * Toggle through relevant workspaces ### For individual users 1. Find Claude in your apps list or the Slack App Marketplace 2. Click "Connect Account" 3. Select your organization 4. Click "Authorize" to grant access 5. Return to Slack and click "+ New Chat" or @mention Claude **Tip**: Add Claude to your Slack header by clicking the three dots and selecting "Add this app to header." ## Slack connector Available for Team and Enterprise plans, the Slack connector allows Claude to search your workspace's channels, direct messages, and files for relevant context. <Warning> You must install Claude in Slack before enabling and using the Slack connector. </Warning> ### Enabling the connector **For Owners**: Navigate to **Organization settings > Connectors** and enable the Slack connector. **For Individual Users**: Go to **Customize > Connectors**, find Slack, and click "Connect." ## Managing connections ### Viewing connection status 1. Click Claude in your Slack sidebar 2. Go to the "Home" tab 3. View your connection details ### Disconnecting **Claude app**: Go to Claude's Home tab and click the red "Disconnect" button. **Slack connector**: Go to [claude.ai/customize/connectors](https://claude.ai/customize/connectors), find Slack, and select "Disconnect." <Note> Disconnecting removes your account connection and deletes past conversations within 30 days. </Note> ## Privacy & data * Slack conversations remain separate from your Claude web history * Conversations initiated in Slack don't appear in your Claude chat history * Each platform maintains separate conversation histories * Conversations auto-delete within 30 days if you disconnect * Slack retention policies apply to your workspace messages ## Troubleshooting <Accordion title="Can't install Claude in Slack"> If your company Slack requires admin approval and you lack admin access, you'll see a "Request to install" prompt. Contact your Slack Admin to approve the app. </Accordion>