One read of Model Context Protocolmcp-20260814T095811Z
144 pages moved out of 144 read.
What this read moved
51-75 of 144, page 3 of 6This capture is too large to show at once. Changes 51-75 of 144 are below, significant first; the rest are on the following screens.
docs/2026-07-28/tutorials/security/security_best_practices First recorded · 983 lines, first recorded
# Security Best Practices ## Introduction ### Purpose and Scope ## Attacks and Mitigations ### Confused Deputy Problem #### Terminology #### Vulnerable Conditions #### Architecture and Attack Flows ##### Normal OAuth proxy usage (preserves user consent) ##### Malicious OAuth proxy usage (skips user consent) #### Attack Description #### Mitigation ##### Consent Flow Implementation ##### Required Protections ### Token Passthrough #### Risks #### Mitigation ### Server-Side Request Forgery (SSRF) #### Attack Description #### Risks #### Mitigation #### SSRF Against Authorization Servers #### Resources and Tools ### State Handle Hijacking #### Attack Description #### Mitigation ### Local MCP Server Compromise #### Attack Description #### Risks #### Mitigation ### OAuth Authorization URL Validation #### Attack Description #### Risks #### Mitigation ### stdio Transport Security in Proxy Scenarios #### Attack Description #### Risks #### Mitigation ### Mix-Up Attacks #### Attack Description #### Mitigation ### Localhost Redirect URI Impersonation #### Attack Description #### Mitigation ### CIMD Trust Policies ### Scope Minimization #### Attack Description #### Risks #### Mitigation #### Common Mistakes
The first capture of this source. The page was already there, and this is what it said.
# Security Best Practices
> Security considerations, attack vectors, and best practices for MCP implementations
## Introduction
### Purpose and Scope
This document provides security considerations for the Model Context
Protocol (MCP), complementing the
[MCP Authorization](/specification/latest/basic/authorization)
specification. This document identifies security risks, attack vectors,
and best practices specific to MCP implementations.
The primary audience for this document includes developers implementing
MCP authorization flows, MCP server operators, and security
professionals evaluating MCP-based systems. This document should be read
alongside the MCP Authorization specification and
[OAuth 2.0 security best practices](https://datatracker.ietf.org/doc/html/rfc9700).
## Attacks and Mitigations
This section gives a detailed description of attacks on MCP
implementations, along with potential countermeasures.
### Confused Deputy Problem
Attackers can exploit MCP proxy servers that connect to third-party
APIs, creating
"[confused deputy](https://en.wikipedia.org/wiki/Confused_deputy_problem)"
vulnerabilities. This attack allows malicious clients to obtain
authorization codes without proper user consent by exploiting the
combination of static client IDs, dynamic client registration, and
consent cookies.
#### Terminology
**MCP Proxy Server**
: An MCP server that connects MCP clients to third-party APIs, offering
MCP features while delegating operations and acting as a single OAuth
client to the third-party API server.
**Third-Party Authorization Server**
: Authorization server that protects the third-party API. It may lack
dynamic client registration support, requiring the MCP proxy to use a
static client ID for all requests.
**Third-Party API**
: The protected resource server that provides the actual API
functionality. Access to this API requires tokens issued by the
third-party authorization server.
**Static Client ID**
: A fixed OAuth 2.0 client identifier used by the MCP proxy server when
communicating with the third-party authorization server. This Client ID
refers to the MCP server acting as a client to the Third-Party API. It
is the same value for all MCP server to Third-Party API interactions
regardless of which MCP client initiated the request.
#### Vulnerable Conditions
This attack becomes possible when all of the following conditions are
present:
* MCP proxy server uses a **static client ID** with a third-party
authorization server
* MCP proxy server allows MCP clients to **dynamically register** (each
getting their own client\_id)
* The third-party authorization server sets a **consent cookie** after
the first authorization
* MCP proxy server does not implement proper per-client consent before
forwarding to third-party authorization
#### Architecture and Attack Flows
##### Normal OAuth proxy usage (preserves user consent)
```mermaid theme={null}
sequenceDiagram
participant UA as User-Agent (Browser)
participant MC as MCP Client
participant M as MCP Proxy Server
participant TAS as Third-Party Authorization Server
Note over UA,M: Initial Auth flow completed
Note over UA,TAS: Step 1: Legitimate user consent for Third Party Server
M->>UA: Redirect to third party authorization server
UA->>TAS: Authorization request (client_id: mcp-proxy)
TAS->>UA: Authorization consent screen
Note over UA: Review consent screen
UA->>TAS: Approve
TAS->>UA: Set consent cookie for client ID: mcp-proxy
TAS->>UA: 3P Authorization code + redirect to mcp-proxy-server.com
UA->>M: 3P Authorization code
Note over M,TAS: Exchange 3P code for 3P token
Note over M: Generate MCP authorization code
M->>UA: Redirect to MCP Client with MCP authorization code
Note over M,UA: Exchange code for token, etc.
```
##### Malicious OAuth proxy usage (skips user consent)
```mermaid theme={null}
sequenceDiagram
participant UA as User-Agent (Browser)
participant M as MCP Proxy Server
participant TAS as Third-Party Authorization Server
participant A as Attacker
Note over UA,A: Step 2: Attack (leveraging existing cookie, skipping consent)
A->>M: Dynamically register malicious client, redirect_uri: attacker.com
A->>UA: Sends malicious link
UA->>TAS: Authorization request (client_id: mcp-proxy) + consent cookie
rect rgba(255, 17, 0, 0.67)
TAS->>TAS: Cookie present, consent skipped
end
TAS->>UA: 3P Authorization code + redirect to mcp-proxy-server.com
UA->>M: 3P Authorization code
Note over M,TAS: Exchange 3P code for 3P token
Note over M: Generate MCP authorization code
M->>UA: Redirect to attacker.com with MCP Authorization code
UA->>A: MCP Authorization code delivered to attacker.com
Note over M,A: Attacker exchanges MCP code for MCP token
A->>M: Attacker impersonates user to MCP server
```
#### Attack Description
When an MCP proxy server uses a static client ID to authenticate with
a third-party authorization server, the following attack becomes
possible:
1. A user authenticates normally through the MCP proxy server to access
the third-party API
2. During this flow, the third-party authorization server sets a cookie
on the user agent indicating consent for the static client ID
3. An attacker later sends the user a malicious link containing a
crafted authorization request which contains a malicious redirect URI
along with a new dynamically registered client ID
4. When the user clicks the link, their browser still has the consent
cookie from the previous legitimate request
5. The third-party authorization server detects the cookie and skips the
consent screen
6. The MCP authorization code is redirected to the attacker's server
(specified in the malicious `redirect_uri` parameter during
[dynamic client registration](/specification/latest/basic/authorization#dynamic-client-registration))
7. The attacker exchanges the stolen authorization code for access
tokens for the MCP server without the user's explicit approval
8. The attacker now has access to the third-party API as the compromised
user
#### Mitigation
To prevent confused deputy attacks, MCP proxy servers **MUST** implement
per-client consent and proper security controls as detailed below.
##### Consent Flow Implementation
The following diagram shows how to properly implement per-client consent
that runs **before** the third-party authorization flow:
```mermaid theme={null}
sequenceDiagram
participant Client as MCP Client
participant Browser as User's Browser
participant MCP as MCP Server
participant ThirdParty as Third-Party AuthZ Server
Note over Client,ThirdParty: 1. Client Registration (Dynamic)
Client->>MCP: Register with redirect_uri
MCP-->>Client: client_id
Note over Client,ThirdParty: 2. Authorization Request
Client->>Browser: Open MCP server authorization URL
Browser->>MCP: GET /authorize?client_id=...&redirect_uri=...
alt Check MCP Server Consent
MCP->>MCP: Check consent for this client_id
Note over MCP: Not previously approved
end
MCP->>Browser: Show MCP server-owned consent page
Note over Browser: "Allow [Client Name] to access [Third-Party API]?"
Browser->>MCP: POST /consent (approve)
MCP->>MCP: Store consent decision for client_id
Note over Client,ThirdParty: 3. Forward to Third-Party
MCP->>Browser: Redirect to third-party /authorize
Note over MCP: Use static client_id for third-party
Browser->>ThirdParty: Authorization request (static client_id)
ThirdParty->>Browser: User authenticates & consents
ThirdParty->>Browser: Redirect with auth code
Browser->>MCP: Callback with third-party code
MCP->>ThirdParty: Exchange code for token (using static client_id)
MCP->>Browser: Redirect to client's registered redirect_uri
```
##### Required Protections
**Per-Client Consent Storage**
MCP proxy servers **MUST**:
* Maintain a registry of approved `client_id` values per user
* Check this registry **before** initiating the third-party
authorization flow
* Store consent decisions securely (server-side database, or server
specific cookies)
**Consent UI Requirements**
The MCP-level consent page **MUST**:
* Clearly identify the requesting MCP client by name
* Display the specific third-party API scopes being requested
* Show the registered `redirect_uri` where tokens will be sent
* Implement CSRF protection (e.g., state parameter, CSRF tokens)
* Prevent iframing via `frame-ancestors` CSP directive or
`X-Frame-Options: DENY` to prevent clickjacking
**Consent Cookie Security**
If using cookies to track consent decisions, they **MUST**:
* Use `__Host-` prefix for cookie names
* Set `Secure`, `HttpOnly`, and `SameSite=Lax` attributes
* Be cryptographically signed or use server-side sessions
* Bind to the specific `client_id` (not just "user has consented")
**Redirect URI Validation**
The MCP proxy server **MUST**:
* Validate that the `redirect_uri` in authorization requests exactly
matches the registered URI
* Reject requests if the `redirect_uri` has changed without
re-registration
* Use exact string matching (not pattern matching or wildcards)
**OAuth State Parameter Validation**
The OAuth `state` parameter is critical to prevent authorization code
interception and CSRF attacks. Proper state validation ensures that
consent approval at the authorization endpoint is enforced at the
callback endpoint.
MCP proxy servers implementing OAuth flows **MUST**:
* Generate a cryptographically secure random `state` value for each
authorization request
* Store the `state` value server-side (in a secure session store or
encrypted cookie) **only after** consent has been explicitly approved
* Set the `state` tracking cookie/session **immediately before**
redirecting to the third-party identity provider (not before consent
approval)
* Validate at the callback endpoint that the `state` query parameter
exactly matches the stored value in the callback request's cookies or
in the request's cookie-based session
* Reject any callback requests where the `state` parameter is missing
or does not match
* Ensure `state` values are single-use (delete after validation) and
have a short expiration time (e.g., 10 minutes)
The consent cookie or session containing the `state` value **MUST NOT**
be set until **after** the user has approved the consent screen at the
MCP server's authorization endpoint. Setting this cookie before consent
approval renders the consent screen ineffective, as an attacker could
bypass it by crafting a malicious authorization request.
### Token Passthrough
"Token passthrough" is an anti-pattern where an MCP server accepts
tokens from an MCP client without validating that the tokens were
properly issued *to the MCP server* and passes them through to the
downstream API.
An attacker can gain unauthorized access or otherwise compromise an
MCP server if the server accepts tokens issued for other resources.
This vulnerability has two critical dimensions:
1. **Audience validation failures.** When an MCP server doesn't verify
that tokens were specifically intended for it (for example, via the
audience claim, as mentioned in
[RFC9068](https://www.rfc-editor.org/rfc/rfc9068.html)), it may
accept tokens originally issued for other services. This breaks a
fundamental OAuth security boundary, allowing attackers to reuse
legitimate tokens across different services than intended.
2. **Token passthrough.** If the MCP server not only accepts tokens
with incorrect audiences but also forwards these unmodified tokens
to downstream services, it can potentially cause the
["confused deputy" problem](#confused-deputy-problem), where the
downstream API may incorrectly trust the token as if it came from
the MCP server or assume the token was validated by the upstream
Cut at 300 lines. The page has the rest.
examples First recorded · 90 lines, first recorded
# Example Servers ## Reference implementations ### Current reference servers ### Additional example servers (archived) ## Official integrations ## Community implementations ## Getting started ### Using reference servers ### Configuring with Claude ## Additional resources
The first capture of this source. The page was already there, and this is what it said.
# Example Servers
> A list of example servers and implementations
This page showcases various Model Context Protocol (MCP) servers that demonstrate the protocol's capabilities and versatility. These servers enable Large Language Models (LLMs) to securely access tools and data sources.
## Reference implementations
These official reference servers demonstrate core MCP features and SDK usage:
### Current reference servers
* **[Everything](https://github.com/modelcontextprotocol/servers/tree/main/src/everything)** - Reference / test server with prompts, resources, and tools
* **[Fetch](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch)** - Web content fetching and conversion for efficient LLM usage
* **[Filesystem](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem)** - Secure file operations with configurable access controls
* **[Git](https://github.com/modelcontextprotocol/servers/tree/main/src/git)** - Tools to read, search, and manipulate Git repositories
* **[Memory](https://github.com/modelcontextprotocol/servers/tree/main/src/memory)** - Knowledge graph-based persistent memory system
* **[Sequential Thinking](https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking)** - Dynamic and reflective problem-solving through thought sequences
* **[Time](https://github.com/modelcontextprotocol/servers/tree/main/src/time)** - Time and timezone conversion capabilities
### Additional example servers (archived)
Visit the [servers-archived repository](https://github.com/modelcontextprotocol/servers-archived) to get access to archived example servers that are no longer actively maintained.
They are provided for historical reference only.
## Official integrations
Visit the [MCP Servers Repository (Official Integrations section)](https://github.com/modelcontextprotocol/servers?tab=readme-ov-file#%EF%B8%8F-official-integrations) for a list of MCP servers maintained by companies for their platforms.
## Community implementations
Visit the [MCP Servers Repository (Community section)](https://github.com/modelcontextprotocol/servers?tab=readme-ov-file#-community-servers) for a list of MCP servers maintained by community members.
## Getting started
### Using reference servers
TypeScript-based servers can be used directly with `npx`:
```bash theme={null}
npx -y @modelcontextprotocol/server-memory
```
Python-based servers can be used with `uvx` (recommended) or `pip`:
```bash theme={null}
# Using uvx
uvx mcp-server-git
# Using pip
pip install mcp-server-git
python -m mcp_server_git
```
### Configuring with Claude
To use an MCP server with Claude, add it to your configuration:
```json theme={null}
{
"mcpServers": {
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
},
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/path/to/allowed/files"
]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
}
}
}
}
```
## Additional resources
Visit the [MCP Servers Repository (Resources section)](https://github.com/modelcontextprotocol/servers?tab=readme-ov-file#-resources) for a collection of other resources and projects related to MCP.
Visit our [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions) to engage with the MCP community.
extensions/apps/build First recorded · 515 lines, first recorded
# Build an MCP App ## Prerequisites ## Getting started ### Using an AI coding agent ### Manual setup ## Building an MCP App ### Server implementation ### UI implementation ## Testing your app ### Testing with Claude ### Testing with the basic-host ## Learn more ## Feedback
The first capture of this source. The page was already there, and this is what it said.
# Build an MCP App
> Getting started guide for building interactive UI applications with MCP Apps
## Prerequisites
You'll need [Node.js](https://nodejs.org/en/download) 18 or higher. Familiarity
with [MCP tools](/specification/latest/server/tools) and
[resources](/specification/latest/server/resources) is recommended since MCP
Apps combine both primitives. Experience with the
[MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
will help you better understand the server-side patterns.
## Getting started
The fastest way to create an MCP App is using an AI coding agent with the MCP
Apps skill. If you prefer to set up a project manually, skip to
[Manual setup](#manual-setup).
### Using an AI coding agent
AI coding agents with Skills support can scaffold a complete MCP App project for
you. Skills are folders of instructions and resources that your agent loads when
relevant. They teach the AI how to perform specialized tasks like creating MCP
Apps.
The `create-mcp-app` skill includes architecture guidance, best practices, and
working examples that the agent uses to generate your project.
<Steps>
<Step title="Install the skill">
If you are using Claude Code, you can install the skill directly with:
```
/plugin marketplace add modelcontextprotocol/ext-apps
/plugin install mcp-apps@modelcontextprotocol-ext-apps
```
You can also use the [Vercel Skills CLI](https://skills.sh/) to install skills across different AI coding agents:
```bash theme={null}
npx skills add modelcontextprotocol/ext-apps
```
Alternatively, you can install the skill manually by cloning the ext-apps repository:
```bash theme={null}
git clone https://github.com/modelcontextprotocol/ext-apps.git
```
And then copying the skill to the appropriate location for your agent:
| Agent | Skills directory (macOS/Linux) | Skills directory (Windows) |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------------- |
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code/skills) | `~/.claude/skills/` | `%USERPROFILE%\.claude\skills\` |
| [VS Code](https://code.visualstudio.com/docs/copilot/customization/agent-skills) and [GitHub Copilot](https://docs.github.com/en/copilot/concepts/agents/about-agent-skills) | `~/.copilot/skills/` | `%USERPROFILE%\.copilot\skills\` |
| [Gemini CLI](https://geminicli.com/docs/cli/skills/) | `~/.gemini/skills/` | `%USERPROFILE%\.gemini\skills\` |
| [Cline](https://cline.bot/blog/cline-3-48-0-skills-and-websearch-make-cline-smarter) | `~/.cline/skills/` | `%USERPROFILE%\.cline\skills\` |
| [Goose](https://goose-docs.ai/docs/guides/context-engineering/using-skills/) | `~/.config/goose/skills/` | `%USERPROFILE%\.config\goose\skills\` |
| [Codex](https://developers.openai.com/codex/skills/) | `~/.codex/skills/` | `%USERPROFILE%\.codex\skills\` |
| [Cursor](https://cursor.com/docs/context/skills) | `~/.cursor/skills/` | `%USERPROFILE%\.cursor\skills\` |
<Note>
This list is not comprehensive. Other agents may support skills in different locations; check your agent's documentation.
</Note>
For example, with Claude Code you can install the skill globally (available in all projects):
<CodeGroup>
```bash macOS/Linux theme={null}
cp -r ext-apps/plugins/mcp-apps/skills/create-mcp-app ~/.claude/skills/create-mcp-app
```
```powershell Windows theme={null}
Copy-Item -Recurse ext-apps\plugins\mcp-apps\skills\create-mcp-app $env:USERPROFILE\.claude\skills\create-mcp-app
```
</CodeGroup>
Or install it for a single project only by copying to `.claude/skills/` in your project directory:
<CodeGroup>
```bash macOS/Linux theme={null}
mkdir -p .claude/skills && cp -r ext-apps/plugins/mcp-apps/skills/create-mcp-app .claude/skills/create-mcp-app
```
```powershell Windows theme={null}
New-Item -ItemType Directory -Force -Path .claude\skills | Out-Null; Copy-Item -Recurse ext-apps\plugins\mcp-apps\skills\create-mcp-app .claude\skills\create-mcp-app
```
</CodeGroup>
To verify the skill is installed, ask your agent "What skills do you have access to?" — you should see `create-mcp-app` as one of the available skills.
</Step>
<Step title="Create your app">
Ask your AI coding agent to build it:
```
Create an MCP App that displays a color picker
```
The agent will recognize the `create-mcp-app` skill is relevant, load its instructions, then scaffold a complete project with server, UI, and configuration files.
<Frame caption="Creating a new MCP App with Claude Code">
<img src="https://mintcdn.com/mcp/GU_E-622SLWFdCrP/images/quickstart-apps/create-mcp-app-skill.gif?s=6c3a3b8a7590b5e97b5c3d8480a9ab12" alt="Creating a new MCP App with Claude Code" width="800" height="563" data-path="images/quickstart-apps/create-mcp-app-skill.gif" />
</Frame>
</Step>
<Step title="Run your app">
<CodeGroup>
```bash macOS/Linux theme={null}
npm install && npm run build && npm run serve
```
```powershell Windows theme={null}
npm install; npm run build; npm run serve
```
</CodeGroup>
<Tip>
You might need to make sure that you are first in the **app folder** before running the commands above.
</Tip>
</Step>
<Step title="Test your app">
Follow the instructions in [Testing your app](#testing-your-app) below. For the color picker example, start a new chat and ask Claude to provide you a color picker.
<Frame caption="Testing the color picker in Claude">
<img src="https://mintcdn.com/mcp/GU_E-622SLWFdCrP/images/quickstart-apps/test-color-picker.gif?s=09413b99bc31d7edc7f9aa22df4faa6a" alt="Testing the color picker in Claude" width="800" height="544" data-path="images/quickstart-apps/test-color-picker.gif" />
</Frame>
</Step>
</Steps>
### Manual setup
If you're not using an AI coding agent, or prefer to understand the setup
process, follow these steps.
<Steps>
<Step title="Create the project structure">
A typical MCP App project separates the server code from the UI code:
<Tree>
<Tree.Folder name="my-mcp-app" defaultOpen>
<Tree.File name="package.json" />
<Tree.File name="tsconfig.json" />
<Tree.File name="vite.config.ts" />
<Tree.File name="server.ts" comment="MCP server with tool + resource" />
<Tree.File name="mcp-app.html" comment="UI entry point" />
<Tree.Folder name="src" defaultOpen>
<Tree.File name="mcp-app.ts" comment="UI logic" />
</Tree.Folder>
</Tree.Folder>
</Tree>
The server registers the tool and serves the UI resource. The UI resource will eventually be rendered in a secure iframe with deny-by-default CSP configuration. If your app has CSS and JS assets, you will need to [configure CSP](https://apps.extensions.modelcontextprotocol.io/api/documents/Patterns.html#configuring-csp-and-cors), or you can bundle your assets into the HTML with a tool like `vite-plugin-singlefile`, which is what we will do in this tutorial.
</Step>
<Step title="Install dependencies">
```bash theme={null}
npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk
npm install -D typescript vite vite-plugin-singlefile express cors @types/express @types/cors tsx
```
The `ext-apps` package provides helpers for both the server side (registering tools and resources) and the client side (the `App` class for UI-to-host communication). Vite with the `vite-plugin-singlefile` plugin is used here to bundle your UI and assets into a single HTML file for convenience, but this is optional — you can use any bundler or serve unbundled files if you [configure CSP](https://apps.extensions.modelcontextprotocol.io/api/documents/Patterns.html#configuring-csp-and-cors).
</Step>
<Step title="Configure the project">
<Tabs>
<Tab title="package.json">
The `"type": "module"` setting enables ES module syntax. The `build` script uses the `INPUT` environment variable to tell Vite which HTML file to bundle. The `serve` script runs your server using `tsx` for TypeScript execution.
```json theme={null}
{
"type": "module",
"scripts": {
"build": "INPUT=mcp-app.html vite build",
"serve": "npx tsx server.ts"
}
}
```
</Tab>
<Tab title="tsconfig.json">
The TypeScript configuration targets modern JavaScript (`ES2022`) and uses ESNext modules with bundler resolution, which works well with Vite. The `include` array covers both the server code in the root and UI code in `src/`.
```json theme={null}
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "dist"
},
"include": ["*.ts", "src/**/*.ts"]
}
```
</Tab>
<Tab title="vite.config.ts">
```typescript theme={null}
import { defineConfig } from "vite";
import { viteSingleFile } from "vite-plugin-singlefile";
export default defineConfig({
plugins: [viteSingleFile()],
build: {
outDir: "dist",
rollupOptions: {
input: process.env.INPUT,
},
},
});
```
</Tab>
</Tabs>
</Step>
<Step title="Build the project">
With the project structure and configuration in place, continue to [Building an MCP App](#building-an-mcp-app) below to implement the server and UI.
</Step>
</Steps>
## Building an MCP App
Let's build a simple app that displays the current server time. This example
demonstrates the full pattern: registering a tool with UI metadata, serving the
bundled HTML as a resource, and building a UI that communicates with the server.
### Server implementation
The server needs to do two things: register a tool that includes the
`_meta.ui.resourceUri` field, and register a resource handler that serves the
bundled HTML. Here's the complete server file:
```typescript theme={null}
// server.ts
console.log("Starting MCP App server...");
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import {
registerAppTool,
registerAppResource,
RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";
import cors from "cors";
import express from "express";
import fs from "node:fs/promises";
import path from "node:path";
const server = new McpServer({
name: "My MCP App Server",
version: "1.0.0",
});
// The ui:// scheme tells hosts this is an MCP App resource.
// The path structure is arbitrary; organize it however makes sense for your app.
const resourceUri = "ui://get-time/mcp-app.html";
// Register the tool that returns the current time
registerAppTool(
server,
"get-time",
{
title: "Get Time",
description: "Returns the current server time.",
inputSchema: {},
_meta: { ui: { resourceUri } },
},
async () => {
const time = new Date().toISOString();
return {
content: [{ type: "text", text: time }],
};
},
);
// Register the resource that serves the bundled HTML
registerAppResource(
server,
resourceUri,
resourceUri,
{ mimeType: RESOURCE_MIME_TYPE },
async () => {
const html = await fs.readFile(
path.join(import.meta.dirname, "dist", "mcp-app.html"),
"utf-8",
);
return {
contents: [
{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html },
],
Cut at 300 lines. The page has the rest.
extensions/apps/overview First recorded · 228 lines, first recorded
# MCP Apps ## Why not just build a web app? ## How MCP Apps work ## When to use MCP Apps ## Security model ## Framework support ## Client support ## Examples
The first capture of this source. The page was already there, and this is what it said.
# MCP Apps
> Interactive UI applications that render inside MCP hosts like Claude Desktop
<Tip>
For comprehensive API documentation, advanced patterns, and the full specification, visit the [official MCP Apps documentation](https://apps.extensions.modelcontextprotocol.io).
</Tip>
Text responses can only go so far. Sometimes users need to interact with data, not
just read about it. MCP Apps let servers return interactive HTML interfaces (data
visualizations, forms, dashboards) that render directly in the chat.
## Why not just build a web app?
You could build a standalone web app and send users a link. However, MCP Apps
offer these key advantages that a separate page can't match:
* **Context preservation.** The app lives inside the conversation. Users don't
switch tabs, lose their place, or wonder which chat thread had that dashboard.
The UI is right there, alongside the discussion that led to it.
* **Bidirectional data flow.** Your app can call any tool on the MCP server, and
the host can push fresh results to your app. A standalone web app would need its
own API, authentication, and state management. MCP Apps get this via existing
MCP patterns.
* **Integration with the host's capabilities**. The app can delegate actions to the host, which can then invoke the capabilities and tools the user has already connected (subject to user consent). Instead of every app implementing and maintaining direct integrations (e.g., email providers), the app can request an outcome (like "schedule this meeting"), and the host routes it through the user's existing connected capabilities.
* **Security guarantees.** MCP Apps run in a sandboxed iframe controlled by the
host. They can't access the parent page, steal cookies, or escape their
container. This means hosts can safely render third-party apps without trusting
the server author completely.
If your use case doesn't benefit from these properties, a regular web app might
be simpler. But if you want tight integration with the LLM-based conversation,
MCP Apps are a much better tool.
## How MCP Apps work
Traditional MCP tools return text, images, resources or structured data that the host displays as
part of the conversation. MCP Apps extend this pattern by allowing tools to
declare a reference to an interactive UI in their tool description that the host
renders in place.
The core pattern combines two MCP primitives: a tool that declares a UI resource
in its description, plus a UI resource that renders data as an interactive HTML
interface.
When a large language model (LLM) decides to call a tool that supports MCP Apps,
here's what happens:
1. **UI preloading**: The tool description includes a `_meta.ui.resourceUri`
field pointing to a `ui://` resource. The host can preload this resource before
the tool is even called, enabling features like streaming tool inputs to the
app.
2. **Resource fetch**: The host fetches the UI resource from the server. This
resource contains an HTML page, often bundled with its JavaScript and CSS for
simplicity. Apps can also load external scripts and resources from origins
specified in `_meta.ui.csp`.
3. **Sandboxed rendering**: Web hosts typically render the HTML inside a
sandboxed [iframe](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe)
within the conversation. The sandbox restricts the app's access to the parent
page, ensuring security. The resource's `_meta.ui` object can include
`permissions` to request additional capabilities (e.g., microphone, camera)
and `csp` to control what external origins the app can load resources from.
4. **Bidirectional communication**: The app and host communicate through a
JSON-RPC protocol that forms its own dialect of MCP. Some requests and
notifications are shared with the core MCP protocol (e.g., `tools/call`), some
are similar (e.g., `ui/initialize`), and most are new with a `ui/` method name
prefix. The app can request tool calls, send messages, update the model's
context, and receive data from the host.
```mermaid theme={null}
sequenceDiagram
participant User
participant Agent
participant App as MCP App iframe
participant Server as MCP Server
User->>Agent: "show me analytics"
Note over User,App: Interactive app rendered in chat
Agent->>Server: tools/call
Server-->>Agent: tool input/result
Agent-->>App: tool result pushed to app
User->>App: user interacts
App->>Agent: tools/call request
Agent->>Server: tools/call (forwarded)
Server-->>Agent: fresh data
Agent-->>App: fresh data
Note over User,App: App updates with new data
App-->>Agent: context update
```
The app stays isolated from the host but can still call MCP tools through the
secure postMessage channel.
## When to use MCP Apps
MCP Apps are a good fit when your use case involves:
**Exploring complex data.** A user asks "show me sales by region." A text
response might list numbers, but an MCP App can render an interactive map where
users click regions to drill down, hover for details, and toggle between
metrics, all without additional prompts.
**Configuring with many options.** Setting up a deployment involves dozens of
interdependent choices. Rather than a back-and-forth conversation ("Which
region?" "What instance size?" "Enable autoscaling?"), an MCP App presents a
form where users see all options at once, with validation and defaults.
**Viewing rich media.** When a user asks to review a PDF, see a 3D model, or
preview generated images, text descriptions fall short. An MCP App embeds the
actual viewer (pan, zoom, rotate) directly in the conversation.
**Real-time monitoring.** A dashboard showing live metrics, logs, or system
status needs continuous updates. An MCP App maintains a persistent connection,
updating the display as data changes without requiring the user to ask "what's
the status now?"
**Multi-step workflows.** Approving expense reports, reviewing code changes, or
triaging issues involves examining items one by one. An MCP App provides
navigation controls, action buttons, and state that persists across
interactions.
## Security model
MCP Apps run in a sandboxed
[iframe](https://developer.mozilla.org/docs/Web/HTML/Element/iframe), which
provides strong isolation from the host application. The sandbox prevents your
app from accessing the parent window's
[DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model), reading
the host's cookies or local storage, navigating the parent page, or executing
scripts in the parent context.
All communication between your app and the host goes through the
[postMessage API](https://developer.mozilla.org/docs/Web/API/Window/postMessage).
The host controls which capabilities your app can access. For example, a host
might restrict which tools an app can call or disable the `sendOpenLink` capability.
The sandbox is designed to prevent apps from escaping to access the host or user data.
## Framework support
MCP Apps use their own dialect of MCP, built on JSON-RPC like the core protocol.
Some messages are shared with regular MCP (e.g., `tools/call`), while others are
specific to apps (e.g., `ui/initialize`). The transport is
[postMessage](https://developer.mozilla.org/docs/Web/API/Window/postMessage)
instead of stdio or HTTP. Since it's all standard web primitives, you can use any
framework or none at all.
The `App` class from `@modelcontextprotocol/ext-apps` is a convenience wrapper,
not a requirement. You can implement the
[postMessage protocol](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx)
directly if you prefer to avoid dependencies or need tighter control.
The [examples directory](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples)
includes starter templates for React, Vue, Svelte, Preact, Solid, and vanilla
JavaScript. These demonstrate recommended patterns for each framework's system,
but they're examples rather than requirements. You can choose whatever works
best for your use case.
## Client support
<Note>
MCP Apps is an extension to the [core MCP specification](/specification/latest). Host support varies by client.
</Note>
MCP Apps are currently supported by [Claude](https://claude.ai),
[Claude Desktop](https://claude.ai/download),
[VS Code GitHub Copilot](https://code.visualstudio.com/), [Microsoft 365 Copilot](https://www.microsoft.com/microsoft-365-copilot), [Goose](https://block.github.io/goose/), [Postman](https://postman.com), [MCPJam](https://www.mcpjam.com/), and [Archestra.AI](https://www.archestra.ai/). See the
[client matrix](/extensions/client-matrix) for the full list of extension support across clients.
If you're building an MCP client and want to support MCP Apps, you have two options:
1. **Use a framework**: The [`@mcp-ui/client`](https://github.com/MCP-UI-Org/mcp-ui)
package provides React components for rendering and interacting with MCP Apps
views in your host application. See the
[MCP-UI documentation](https://mcpui.dev/) for usage details.
2. **Build on AppBridge**: The SDK includes an
[**App Bridge**](https://apps.extensions.modelcontextprotocol.io/api/modules/app-bridge.html)
module that handles rendering apps in sandboxed iframes, message passing, tool
call proxying, and security policy enforcement. The
[basic-host example](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host)
shows how to integrate it.
See the [API documentation](https://apps.extensions.modelcontextprotocol.io/api/)
for implementation details.
## Examples
The [ext-apps repository](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples)
includes ready-to-run examples demonstrating different use cases:
* **3D and visualization**:
[map-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/map-server)
(CesiumJS globe),
[threejs-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/threejs-server)
(Three.js scenes),
[shadertoy-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/shadertoy-server)
(shader effects)
* **Data exploration**:
[cohort-heatmap-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/cohort-heatmap-server),
[customer-segmentation-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/customer-segmentation-server),
[wiki-explorer-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/wiki-explorer-server)
* **Business applications**:
[scenario-modeler-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/scenario-modeler-server),
[budget-allocator-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/budget-allocator-server)
* **Media**:
[pdf-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/pdf-server),
[video-resource-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/video-resource-server),
[sheet-music-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/sheet-music-server),
[say-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/say-server)
(text-to-speech)
* **Utilities**:
[qr-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/qr-server),
[system-monitor-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/system-monitor-server),
[transcript-server](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/transcript-server)
(speech-to-text)
* **Starter templates**:
[React](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-react),
[Vue](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-vue),
[Svelte](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-svelte),
[Preact](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-preact),
[Solid](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-solid),
[vanilla JavaScript](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-server-vanillajs)
To start building your own MCP App, see the [build guide](/extensions/apps/build).
extensions/auth/enterprise-managed-authorization First recorded · 158 lines, first recorded
# Enterprise-Managed Authorization ## What it is ## When to use it ## How it works ## Implementation guide ### For MCP clients ### For MCP servers ### For MCP Authorization Servers ## Client support ## Related resources
The first capture of this source. The page was already there, and this is what it said.
# Enterprise-Managed Authorization
> Centralized access control for MCP in enterprise environments via identity providers
The Enterprise-Managed Authorization extension (`io.modelcontextprotocol/enterprise-managed-authorization`) enables organizations to control MCP server access centrally through their existing identity provider (IdP). Instead of each employee authorizing each MCP server individually, the organization's IT or security team manages access policies in one place.
<Card title="Specification" icon="file-lines" href="https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/stable/enterprise-managed-authorization.mdx">
Full technical specification for the Enterprise-Managed Authorization
extension.
</Card>
## What it is
In a standard MCP deployment, each user independently authorizes an MCP client to access each MCP server. For consumer applications, this user-driven model is ideal — it gives individuals control over what accesses their data.
In enterprise environments, this model creates friction and security gaps:
* Employees shouldn't need to understand the authorization details of every MCP server their organization uses
* Security teams can't enforce consistent access policies if each user authorizes independently
* Onboarding new employees requires them to manually authorize dozens of services
* Offboarding requires revoking access across every service individually
Enterprise-Managed Authorization solves this by introducing the organization's IdP as the authoritative decision-maker. The IdP (such as Okta, Azure AD, or a corporate SSO system) controls which MCP servers employees can access, and under what conditions. Employees authenticate with their corporate identity — the same credentials they use for email, Slack, and other work tools — and the IdP grants or denies MCP server access based on organizational policy.
## When to use it
Use Enterprise-Managed Authorization when:
* **Deploying MCP in a corporate environment** where IT manages access to all business applications
* **Enforcing organizational access policies** — you need to ensure only authorized employees access specific MCP servers
* **Centralizing access control** — you want to add or revoke access to MCP servers from a single admin console
* **Meeting compliance requirements** — your organization needs an auditable authorization trail for all MCP server access
* **Simplifying employee experience** — employees should access MCP tools with their existing corporate SSO credentials, without per-service authorization flows
## How it works
The extension establishes a delegated authorization flow where the enterprise IdP acts as an intermediary between the MCP client and the MCP server. The MCP Client requests a special type of token from the enterprise IdP called an Identity Assertion JWT Authorization Grant, or ID-JAG. The MCP Client then exchanges the ID-JAG for an access token from the MCP server's Authorization Server:
```mermaid theme={null}
sequenceDiagram
participant UA as Browser
participant C as MCP Client
participant IdP as Enterprise IdP
participant MAS as MCP Authorization Server
participant MRS as MCP Resource Server
C-->>UA: Redirect to IdP
UA->>IdP: Redirect to IdP
Note over IdP: User Logs In
IdP-->>UA: IdP Authorization Code
UA->>C: IdP Authorization Code
C->>IdP: Token Request with IdP Authorization Code
IdP-->>C: ID Token
note over C: User is logged<br/>in to MCP Client.<br/>Client stores ID Token.
C->>IdP: Exchange ID Token for ID-JAG
note over IdP: Evaluate Policy
IdP-->>C: Responds with ID-JAG
C->>MAS: Token Request with ID-JAG
note over MAS: Validate ID-JAG
MAS-->>C: MCP Access Token
loop
C->>MRS: Call MCP API with Access Token
MRS-->>C: MCP Response with Data
end
```
Key aspects of the flow:
1. **Centralized policy**: The enterprise IdP maintains a registry of approved MCP servers and the access policies for each. Administrators configure these in their existing identity management tools.
2. **Single sign-on**: Employees authenticate with their corporate credentials once. The IdP issues tokens that grant access to approved MCP servers without additional per-server authorization prompts.
3. **Policy enforcement**: The IdP evaluates access policies (group membership, role assignments, conditional access rules) before issuing tokens. Employees who lack authorization receive an appropriate error — the MCP client never receives a token for unauthorized servers.
4. **Centralized revocation**: Revoking an employee's access to MCP servers happens at the IdP level, taking effect immediately across all MCP clients. No per-client, per-server revocation needed.
## Implementation guide
### For MCP clients
To support Enterprise-Managed Authorization, your client must:
1. **Declare support** in its per-request capabilities:
```jsonc theme={null}
{
"jsonrpc": "2.0",
"id": 1,
"method": "...",
"params": {
// Other fields...
"_meta": {
// Other fields...
"io.modelcontextprotocol/clientCapabilities": {
"extensions": {
"io.modelcontextprotocol/enterprise-managed-authorization": {},
},
},
},
},
}
```
2. **Support SSO** — users should authenticate to the MCP Client using the enterprise IdP. Save the Identity Assertion (either an OpenID ID Token or SAML assertion) issued during login for later use.
3. **Handle ID-JAGs** — when the server indicates that enterprise-managed auth is required, request an ID-JAG token from the enterprise IdP's authorization endpoint using the previously obtained Identity Assertion. Exchange this ID-JAG for an access token from the MCP Authorization Server. Do not redirect the user to the MCP Authorization Server's authorization endpoint.
4. **Support organization configuration** — allow administrators to configure the enterprise IdP's endpoints, typically via organization-level settings rather than per-user settings.
5. **Respect token scopes** — tokens issued by enterprise IdPs may have scope restrictions that differ from standard MCP authorization. Handle scope errors gracefully.
### For MCP servers
To require enterprise-managed authorization:
1. **Declare the extension** in your server's authorization metadata, indicating that clients must use the enterprise-managed flow.
2. **Integrate with IdP admin APIs** (optional) — publish your server's resource descriptor so enterprise administrators can configure access policies in their IdP admin console.
### For MCP Authorization Servers
1. **Validate ID-JAGs** issued by the enterprise IdP. This typically means validating JWT signatures against the IdP's JWKS endpoint and checking the token's audience, issuer, and expiration.
2. **Map IdP claims to permissions** — ID-JAG tokens carry claims (scope and resource information) that your server uses to determine who the employee is and what the employee can access. Define your authorization logic based on these claims.
3. **Handle Account Linking** - ID-JAG tokens will always contain a subject claim and may additionally contain an email claim that can be used to link the enterprise identity to an existing account in your system. Use the subject claim as the primary stable identifier for the user, and fall back to the email claim for matching against pre-existing accounts that were created before enterprise-managed authorization was configured.
## Client support
<Note>
Support for this extension varies by client. Extensions are opt-in and never active by default.
</Note>
Check the [client matrix](/extensions/client-matrix) for current implementation status across MCP clients. Enterprise-Managed Authorization typically requires client-level support from the organization's IT team in addition to the MCP client application.
## Related resources
<CardGroup cols={2}>
<Card title="ext-auth repository" icon="github" href="https://github.com/modelcontextprotocol/ext-auth">
Source code and reference implementations
</Card>
<Card title="Full specification" icon="file-lines" href="https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/stable/enterprise-managed-authorization.mdx">
Technical specification with normative requirements
</Card>
<Card title="SEP-990" icon="file-lines" href="/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o">
Original proposal: Enable Enterprise IdP Policy Controls
</Card>
<Card title="MCP Authorization" icon="lock" href="/specification/latest/basic/authorization">
Core MCP authorization specification
</Card>
</CardGroup>
extensions/auth/oauth-client-credentials First recorded · 419 lines, first recorded
# OAuth Client Credentials ## What it is ## When to use it ## How it works ### JWT Bearer Assertions (recommended) ### Client Secrets ## Implementation guide ### For MCP clients ### For MCP servers ## SDK examples ## Client support ## Related resources
The first capture of this source. The page was already there, and this is what it said.
# OAuth Client Credentials
> Machine-to-machine authentication for MCP using the OAuth 2.0 client credentials flow
The OAuth Client Credentials extension (`io.modelcontextprotocol/oauth-client-credentials`) adds support for the [OAuth 2.0 client credentials flow](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4) to MCP. This enables automated systems to connect to MCP servers without interactive user authorization.
<Card title="Specification" icon="file-lines" href="https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/draft/oauth-client-credentials.mdx">
Full technical specification for the OAuth Client Credentials extension.
</Card>
## What it is
The standard MCP authorization flow requires a user to interactively approve access — a browser opens, the user logs in, and grants permission. That works well for humans, but breaks down when there's no user present.
The OAuth Client Credentials extension solves this by letting a client authenticate using application-level credentials (a client ID and secret, or a signed JWT assertion) rather than delegated user credentials. The client proves its identity directly to the authorization server, which issues an access token without requiring a browser redirect or user interaction.
## When to use it
Use OAuth Client Credentials when:
* **Background services** need to call MCP tools on a schedule or in response to events, without a user present
* **CI/CD pipelines** invoke MCP servers as part of automated build, test, or deployment workflows
* **Server-to-server integrations** connect two backend systems where there's no end user involved
* **Daemon processes** or long-running workers need persistent access to MCP resources
If your integration has a human user who should explicitly authorize access, use the standard MCP authorization flow instead.
## How it works
The extension supports two credential formats:
### JWT Bearer Assertions (recommended)
Defined in [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523), JWT Bearer Assertions let the client sign a token with its private key and present it as proof of identity. The authorization server validates the signature using the client's registered public key.
```mermaid theme={null}
sequenceDiagram
participant Client
participant AS as Authorization Server
participant MCP as MCP Server
Client->>AS: POST /token<br/>grant_type=urn:ietf:params:<br/>oauth:grant-type:jwt-bearer<br/>assertion=<signed JWT>
AS-->>Client: access_token
Client->>MCP: MCP request (Bearer token)
```
The JWT assertion typically includes:
* `iss`: Client ID (the issuer)
* `sub`: Client ID (subject being authenticated)
* `aud`: Authorization server token endpoint URL
* `exp`: Expiration time
* `iat`: Issued-at time
### Client Secrets
For simpler deployments, the extension also supports the standard client credentials flow using a `client_id` and `client_secret`. The client sends its credentials directly to the authorization server's token endpoint and receives an access token in return.
```mermaid theme={null}
sequenceDiagram
participant Client
participant AS as Authorization Server
participant MCP as MCP Server
Client->>AS: POST /token<br/>grant_type=client_credentials<br/>client_id + client_secret
AS-->>Client: access_token
Client->>MCP: MCP request (Bearer token)
```
<Warning>
Client secrets are **long-lived credentials** that grant access without user interaction. If a secret is leaked, an attacker can silently authenticate as your application until the secret is rotated. To reduce risk:
* Store secrets in a secrets manager, never in source code or environment files checked into version control.
* Rotate secrets on a regular schedule and immediately after any suspected compromise.
* Scope credentials to the minimum permissions required.
* Prefer JWT assertions when possible — they are short-lived and do not require transmitting the signing key.
</Warning>
## Implementation guide
### For MCP clients
To use the OAuth Client Credentials extension, your client must:
<Steps>
<Step title="Declare support">
Include the extension in its per-request capabilities:
```jsonc theme={null}
{
"jsonrpc": "2.0",
"id": 1,
"method": "...",
"params": {
// Other fields...
"_meta": {
// Other fields...
"io.modelcontextprotocol/clientCapabilities": {
"extensions": {
"io.modelcontextprotocol/oauth-client-credentials": {},
},
},
},
},
}
```
</Step>
<Step title="Obtain an access token">
Request a token from the authorization server using the client credentials grant before connecting to the MCP server.
</Step>
<Step title="Include the token">
Pass the token in the `Authorization` header of HTTP requests to the MCP server:
```
Authorization: Bearer <access_token>
```
</Step>
<Step title="Handle token refresh">
Client credentials tokens typically have shorter lifetimes than user-delegated tokens. Implement token refresh logic to obtain a new token before expiry.
</Step>
</Steps>
### For MCP servers
To accept client credentials tokens, your server must:
<Steps>
<Step title="Validate the token">
On each request, verify the JWT signature and claims against your authorization server's public keys (usually via a JWKS endpoint).
</Step>
<Step title="Check scopes">
Ensure the token includes the required scopes for the requested operation.
</Step>
<Step title="Advertise support">
Optionally (but recommended for discoverability), include the extension in the `server/discover` response:
```jsonc theme={null}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
// Other fields...
"capabilities": {
"extensions": {
"io.modelcontextprotocol/oauth-client-credentials": {},
},
},
},
}
```
</Step>
</Steps>
## SDK examples
The official MCP SDKs provide built-in support for client credentials authentication. Both handle token acquisition and refresh automatically.
<Steps>
<Step title="Install the SDK">
<Tabs>
<Tab title="TypeScript">
```bash theme={null}
npm install @modelcontextprotocol/client
```
</Tab>
<Tab title="Python">
```bash theme={null}
pip install mcp
```
</Tab>
</Tabs>
</Step>
<Step title="Create a provider and connect">
Choose the credential format that matches your setup:
#### Using a client secret
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import {
Client,
ClientCredentialsProvider,
StreamableHTTPClientTransport,
} from "@modelcontextprotocol/client";
const provider = new ClientCredentialsProvider({
clientId: "my-service",
clientSecret: "s3cr3t",
});
const client = new Client(
{ name: "my-service", version: "1.0.0" },
{ capabilities: {} },
);
const transport = new StreamableHTTPClientTransport(
new URL("https://mcp.example.com/mcp"),
{ authProvider: provider },
);
await client.connect(transport);
// Use the client
const tools = await client.listTools();
console.log(
"Available tools:",
tools.tools.map((t) => t.name),
);
await transport.close();
```
</Tab>
<Tab title="Python">
```python theme={null}
import asyncio
import httpx2
from mcp import Client
from mcp.client.auth.extensions.client_credentials import (
ClientCredentialsOAuthProvider,
)
from mcp.client.streamable_http import streamable_http_client
from mcp.shared.auth import OAuthClientInformationFull, OAuthToken
class InMemoryTokenStorage:
def __init__(self) -> None:
self.tokens: OAuthToken | None = None
self.client_info: OAuthClientInformationFull | None = None
async def get_tokens(self) -> OAuthToken | None:
return self.tokens
async def set_tokens(self, tokens: OAuthToken) -> None:
self.tokens = tokens
async def get_client_info(self) -> OAuthClientInformationFull | None:
return self.client_info
async def set_client_info(self, client_info: OAuthClientInformationFull) -> None:
self.client_info = client_info
provider = ClientCredentialsOAuthProvider(
server_url="https://mcp.example.com/mcp",
storage=InMemoryTokenStorage(),
client_id="my-service",
client_secret="s3cr3t",
scopes="read write",
)
async def main() -> None:
async with httpx2.AsyncClient(auth=provider) as http_client:
transport = streamable_http_client(
"https://mcp.example.com/mcp",
http_client=http_client,
)
async with Client(transport) as client:
# Use the client
tools = await client.list_tools()
print("Available tools:", [t.name for t in tools.tools])
if __name__ == "__main__":
asyncio.run(main())
```
</Tab>
</Tabs>
#### Using a JWT private key
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import {
Client,
PrivateKeyJwtProvider,
StreamableHTTPClientTransport,
} from "@modelcontextprotocol/client";
const provider = new PrivateKeyJwtProvider({
clientId: "my-service",
privateKey: process.env.CLIENT_PRIVATE_KEY_PEM,
algorithm: "RS256",
});
const client = new Client(
{ name: "my-service", version: "1.0.0" },
{ capabilities: {} },
Cut at 300 lines. The page has the rest.
extensions/auth/overview First recorded · 54 lines, first recorded
# Authorization Extensions ## Why authorization extensions? ## Available extensions ## Choosing the right extension ## Client support ## Specification
The first capture of this source. The page was already there, and this is what it said.
# Authorization Extensions
> Supplementary authorization mechanisms for the Model Context Protocol
The [ext-auth repository](https://github.com/modelcontextprotocol/ext-auth) contains official MCP extensions that add authorization capabilities beyond the core MCP specification. These extensions address specific real-world scenarios where the standard OAuth 2.0 authorization code flow isn't the right fit.
<Card title="modelcontextprotocol/ext-auth" icon="github" href="https://github.com/modelcontextprotocol/ext-auth">
Source code, specifications, and reference implementations for MCP
authorization extensions.
</Card>
## Why authorization extensions?
The core MCP specification includes a robust [authorization framework](/specification/latest/basic/authorization) built on OAuth 2.0. That framework handles the common case well: a user interactively grants an MCP client permission to access a server on their behalf.
But not every MCP deployment fits this pattern:
* **Machine-to-machine integrations** don't have a human in the loop. Background services, CI pipelines, and automated workflows need to authenticate without interactive user consent flows.
* **Enterprise environments** often have centralized identity providers (IdPs) that enforce policy across all applications. Requiring employees to authorize each MCP server individually creates friction and bypasses existing security controls.
The ext-auth extensions address these gaps.
## Available extensions
<CardGroup cols={2}>
<Card title="OAuth Client Credentials" icon="robot" href="/extensions/auth/oauth-client-credentials">
Machine-to-machine authentication using the OAuth 2.0 client credentials
flow. No user interaction required.
</Card>
<Card title="Enterprise-Managed Authorization" icon="building" href="/extensions/auth/enterprise-managed-authorization">
Centralized access control via enterprise identity providers. Employees
access MCP servers through their organization's IdP.
</Card>
</CardGroup>
## Choosing the right extension
| Scenario | Recommended extension |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Background service or daemon accessing an MCP server | [OAuth Client Credentials](/extensions/auth/oauth-client-credentials) |
| CI/CD pipeline calling MCP tools | [OAuth Client Credentials](/extensions/auth/oauth-client-credentials) |
| Server-to-server API integration | [OAuth Client Credentials](/extensions/auth/oauth-client-credentials) |
| Enterprise employees accessing MCP servers at work | [Enterprise-Managed Authorization](/extensions/auth/enterprise-managed-authorization) |
| Organization-wide MCP access policy enforcement | [Enterprise-Managed Authorization](/extensions/auth/enterprise-managed-authorization) |
| Standard interactive user authorization | Core MCP spec (no extension needed) |
## Client support
Authorization extension support varies by client. See the [client matrix](/extensions/client-matrix) for a full breakdown. Both extensions require explicit support from the MCP client — they are never active by default.
## Specification
Both extensions are specified in the [ext-auth repository](https://github.com/modelcontextprotocol/ext-auth/tree/main/specification/draft). They use the standard MCP [extension negotiation](/extensions/overview#negotiation) mechanism: clients declare support in the `extensions` field of the `io.modelcontextprotocol/clientCapabilities` they send in each request's `_meta`, and servers advertise theirs in the capabilities returned by [`server/discover`](/specification/draft/server/discover).
extensions/client-matrix First recorded · 52 lines, first recorded
# Extension Support Matrix ## Extension overview ## Support matrix ## Adding extension support to your client
The first capture of this source. The page was already there, and this is what it said.
# Extension Support Matrix
> Which MCP clients implement which official extensions
export const CHECK = () => <span className="flex justify-center">
<Icon icon="check" iconType="solid" size={18} className="text-green-500" />
</span>;
This matrix shows which MCP clients support each [official extension](/extensions/overview). Extensions are always opt-in: a client only uses an extension if both client and server declare support in the `extensions` field of their [capabilities](/extensions/overview#negotiation).
<Note>
This list is maintained by the community. If you notice any inaccuracies or would like to add or update information, please [submit a pull request](https://github.com/modelcontextprotocol/modelcontextprotocol/pulls).
</Note>
## Extension overview
| Extension | Identifier | Description |
| ------------------------------------------------------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------- |
| [MCP Apps](/extensions/apps/overview) | `io.modelcontextprotocol/ui` | Interactive HTML interfaces rendered inline in the conversation |
| [OAuth Client Credentials](/extensions/auth/oauth-client-credentials) | `io.modelcontextprotocol/oauth-client-credentials` | Machine-to-machine auth without interactive user login |
| [Enterprise-Managed Authorization](/extensions/auth/enterprise-managed-authorization) | `io.modelcontextprotocol/enterprise-managed-authorization` | Centralized access control via enterprise IdP |
## Support matrix
| Client | [MCP Apps](/extensions/apps/overview) | [OAuth Client Credentials](/extensions/auth/oauth-client-credentials) | [Enterprise Auth](/extensions/auth/enterprise-managed-authorization) |
| ------------------------------------------------------------------------ | :-----------------------------------: | :-------------------------------------------------------------------: | :------------------------------------------------------------------: |
| [Claude (web)](https://claude.ai) | <CHECK /> | | |
| [Claude Desktop](https://claude.ai/download) | <CHECK /> | | |
| [VS Code GitHub Copilot](https://code.visualstudio.com/) | <CHECK /> | | |
| [Microsoft 365 Copilot](https://www.microsoft.com/microsoft-365-copilot) | <CHECK /> | | |
| [Goose](https://block.github.io/goose/) | <CHECK /> | | |
| [Postman](https://postman.com) | <CHECK /> | | |
| [MCPJam](https://www.mcpjam.com/) | <CHECK /> | | |
| [ChatGPT](https://chatgpt.com/) | <CHECK /> | | |
| [Cursor](https://cursor.com/) | <CHECK /> | | |
| [Archestra.AI](https://www.archestra.ai/) | <CHECK /> | | <CHECK /> |
| [PostHog Code](https://posthog.com/code/) | <CHECK /> | | |
<Note>
Auth extension support (OAuth Client Credentials and Enterprise-Managed Authorization) is tracked separately from the core MCP authorization features (DCR, CIMD). Check each extension's specification and the [ext-auth repository](https://github.com/modelcontextprotocol/ext-auth) for the latest implementation status.
</Note>
## Adding extension support to your client
If you're building an MCP client and want to implement extension support:
1. Review the extension specification (e.g., in the [ext-auth](https://github.com/modelcontextprotocol/ext-auth) or [ext-apps](https://github.com/modelcontextprotocol/ext-apps) repository)
2. Declare support in the `extensions` field of the `io.modelcontextprotocol/clientCapabilities` your client sends in each request's `_meta`, and read the server's `extensions` from its [`server/discover`](/specification/draft/server/discover) response
3. Implement the extension's protocol requirements
4. Submit a pull request to update this matrix
See [Extensions Overview](/extensions/overview#negotiation) for details on the capability negotiation mechanism.
extensions/overview First recorded · 172 lines, first recorded
# Extensions Overview # MCP Extensions ## Official Extension Repositories ### MCP Authorization Extensions ### MCP Apps ### MCP Tasks ## Experimental Extensions ### Ground Rules ### Graduation to Official Status ## Creating Extensions ### Requirements ### SDK Implementation ### Evolution ## Negotiation ### Client Capabilities ### Server Capabilities ### Graceful Degradation
The first capture of this source. The page was already there, and this is what it said.
# Extensions Overview
> Optional extensions to the Model Context Protocol
# MCP Extensions
MCP extensions are optional additions to the specification that define capabilities beyond the core protocol. Extensions enable functionality that may be modular (e.g., distinct features like authentication), specialized (e.g., industry-specific logic), or experimental (e.g., features being incubated for potential core inclusion).
Extensions are identified using a unique *extension identifier* with the format: `{vendor-prefix}/{extension-name}`, e.g. `io.modelcontextprotocol/oauth-client-credentials`. Identifiers follow the same rules as [`_meta` keys](/specification/draft/basic/index#meta), with a mandatory prefix. Official extensions use the `io.modelcontextprotocol` vendor prefix.
<Tip>
If you're building a third-party extension, use a reversed domain name you own as the vendor prefix to avoid collisions (similar to Java package naming). For example, a company owning `example.com` would use `com.example/` as their prefix (e.g., `com.example/my-extension`).
</Tip>
## Official Extension Repositories
Official extensions live inside the [Model Context Protocol GitHub organization](https://github.com/modelcontextprotocol/) in repositories with the `ext-` prefix.
### MCP Authorization Extensions
<Card title="modelcontextprotocol/ext-auth" icon="github" href="https://github.com/modelcontextprotocol/ext-auth">
Extensions for supplementary authorization mechanisms beyond the core
specification.
</Card>
| Extension | Description |
| ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| [OAuth Client Credentials](/extensions/auth/oauth-client-credentials) | OAuth 2.0 client credentials flow for machine-to-machine authentication. |
| [Enterprise-Managed Authorization](/extensions/auth/enterprise-managed-authorization) | Framework for enterprise environments requiring centralized access control. |
### MCP Apps
<Card title="modelcontextprotocol/ext-apps" icon="github" href="https://github.com/modelcontextprotocol/ext-apps">
Extensions for interactive UI elements in conversational MCP clients.
</Card>
| Extension | Description |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| [MCP Apps](/extensions/apps/overview) | Allows MCP Servers to display interactive UI elements (charts, forms, video players) inline within conversations |
To get started building MCP Apps, see the [quickstart guide](/extensions/apps/build#getting-started) or read the full [MCP Apps documentation](https://apps.extensions.modelcontextprotocol.io/api/documents/Quickstart.html).
### MCP Tasks
| Extension | Description |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| [MCP Tasks](/extensions/tasks/overview) | Asynchronous task execution for long-running operations, with polling, mid-flight input, and durable handles. |
## Experimental Extensions
Experimental extensions provide an incubation pathway for [Working Groups and Interest Groups](/community/working-interest-groups) to prototype ideas and collaborate on extension concepts before formal SEP submission.
Experimental extension repositories live within the MCP GitHub organization with the `experimental-ext-` prefix (e.g., `experimental-ext-interceptors`).
### Ground Rules
* Every experimental extension needs to be associated with a Working Group or Interest Group
* Repositories and published packages need to clearly indicate their experimental status (e.g., in the README and package name)
* [Core Maintainers](/community/contributor-ladder#core-maintainer) retain oversight of experimental extension repositories, including the ability to archive or remove them
### Graduation to Official Status
To promote an experimental extension to official status, it goes through the standard SEP process (Extensions Track). Feel free to reference the experimental repository and any reference implementations you built during incubation to demonstrate the extension's practicality.
## Creating Extensions
The lifecycle for official extensions follows a SEP-based process. For full details, see [SEP-2133: Extensions](/seps/2133-extensions).
1. **Propose**: Create a SEP in the main MCP repository using the [standard SEP guidelines](/community/sep-guidelines) with type **Extensions Track**.
2. **Implement**: Build at least one reference implementation in an official SDK — this is required before the SEP can be reviewed.
3. **Review**: [Core Maintainers](/community/contributor-ladder#core-maintainer) review the SEP and have final authority over inclusion.
4. **Publish**: Once approved, open a PR to add the extension to the extension repository.
5. **Adopt**: After that, other clients, servers, and SDKs can implement the extension too.
### Requirements
* Extension specifications need to use RFC 2119 language (MUST, SHOULD, MAY)
* Extensions must have an associated working group or interest group
### SDK Implementation
SDKs can choose to implement extensions, but it's not required for protocol conformance. SDK maintainers have full autonomy over which extensions they support. Where an SDK does support extensions, SDK documentation should list which extensions are supported.
<Note>
Extensions are always disabled by default and require explicit opt-in from the developer.
</Note>
### Evolution
Extensions evolve independently of the core protocol. Updates are managed by the extension repository maintainers and don't require core maintainer review.
That said, backwards compatibility matters. When you need to change an extension, prefer using capability flags or versioning within the extension settings object rather than creating a new extension identifier. If a breaking change is unavoidable, use a new identifier (e.g., `io.modelcontextprotocol/my-extension-v2`).
A **breaking change** is any modification that would cause existing implementations to fail or behave incorrectly, including:
* Removing or renaming fields
* Changing field types
* Altering the semantics of existing behavior
* Adding new required fields
## Negotiation
Clients and servers advertise their support for extensions in the `extensions` field within their respective capability declarations.
### Client Capabilities
Clients advertise extension support in `_meta["io.modelcontextprotocol/clientCapabilities"]` within each request:
```json theme={null}
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "New York"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {
"extensions": {
"io.modelcontextprotocol/ui": {
"mimeTypes": ["text/html;profile=mcp-app"]
}
}
},
"io.modelcontextprotocol/clientInfo": {
"name": "ExampleClient",
"version": "1.0.0"
}
}
}
}
```
### Server Capabilities
Servers advertise extension support in the `server/discover` response:
```json theme={null}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28"],
"capabilities": {
"tools": {},
"extensions": {
"io.modelcontextprotocol/ui": {}
}
},
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "ExampleServer",
"version": "1.0.0"
}
},
"ttlMs": 3600000,
"cacheScope": "public"
}
}
```
Each extension specifies the schema of its settings object; an empty object indicates no settings.
### Graceful Degradation
If one side supports an extension but the other doesn't, the supporting side needs to either fall back to core protocol behavior or reject the request with an appropriate error if the extension is mandatory.
It's a good practice to document expected fallback behavior in your extension. For example, a server offering UI-enhanced tools should still return meaningful text content for clients that don't support the UI extension. On the other hand, a server that requires a specific authentication extension can reject connections from clients that don't support it.
extensions/tasks/overview First recorded · 257 lines, first recorded
# Tasks ## Why not just block? ## How Tasks work ## When to use Tasks ## Task lifecycle ## Notifications ## Implementation guide ### For MCP clients ### For MCP servers ## Client support ## Specification
The first capture of this source. The page was already there, and this is what it said.
# Tasks
> Asynchronous task execution for long-running MCP operations
The [ext-tasks repository](https://github.com/modelcontextprotocol/ext-tasks) contains the full specification and documentation for MCP Tasks.
<Card title="modelcontextprotocol/ext-tasks" icon="github" href="https://github.com/modelcontextprotocol/ext-tasks">
Full specification and documentation for MCP Tasks.
</Card>
Not every tool call returns instantly. Some operations — CI pipelines, batch
processing, human approvals — take seconds, minutes, or longer. MCP Tasks let
servers return a durable handle instead of blocking, so clients can poll for
progress, provide input when needed, and retrieve the final result after
reconnecting.
## Why not just block?
You could hold the connection open until the work finishes. Tasks solve
problems that blocking cannot:
* **No long-lived connections.** Blocking ties up a connection for the duration
of the operation. Many clients and transport intermediaries impose timeouts
that make this impractical beyond a few seconds.
* **Crash resilience.** A task ID is a durable handle. If the client
disconnects or restarts, it can resume polling with the same ID.
* **Progress visibility.** Tasks carry status metadata (`working`,
`input_required`, `completed`, `failed`, `cancelled`) and optional status
messages, giving clients visibility into progress.
* **Mid-flight interaction.** When a task needs input (e.g., an elicitation for
user confirmation), it moves to `input_required` and surfaces the request.
The client responds via `tasks/update` — no second connection or unsolicited
server-to-client messages required.
* **Server-directed.** The server decides per-request whether to create a task.
Clients opt in once via the extension capability and handle whichever result
shape arrives. No per-tool warmup or per-request flag.
## How Tasks work
Tasks extend the standard request flow. When a server decides a request will be
long-running, it returns a task handle instead of the final result. The client
polls for completion.
1. **Capability negotiation.** The client includes
`io.modelcontextprotocol/tasks` in its per-request capabilities. The server
advertises the same extension in its own `server/discover` capabilities.
2. **Task creation.** In response to a supported request, the server returns a
`CreateTaskResult` (identified by `resultType: "task"`) containing a `taskId`,
initial status, TTL, and suggested polling interval. The task is durably
created before the response is sent.
3. **Polling.** The client calls `tasks/get` with the `taskId`. The response
carries the current status and, for terminal states, the final result or
error.
4. **Mid-flight input.** If the task moves to `input_required`, the `tasks/get`
response includes an `inputRequests` map with elicitations or other server
requests. The client fulfills these via `tasks/update`.
5. **Completion.** When the status reaches `completed`, the `result` field
contains what the original request would have returned synchronously. If the
status is `failed`, the `error` field contains the JSON-RPC error.
6. **Cancellation.** The client can send `tasks/cancel` at any time.
Cancellation is cooperative — the server acknowledges the intent but is not
obligated to stop the work.
```mermaid theme={null}
sequenceDiagram
participant Client
participant Server
Client->>Server: tools/call (with tasks capability)
Server-->>Client: CreateTaskResult (taskId, status: working)
loop Poll until terminal
Client->>Server: tasks/get (taskId)
Server-->>Client: Task (status: working)
end
Note over Client,Server: Server needs user input
Client->>Server: tasks/get (taskId)
Server-->>Client: Task (status: input_required, inputRequests)
Client->>Server: tasks/update (taskId, inputResponses)
Server-->>Client: ack
loop Poll until terminal
Client->>Server: tasks/get (taskId)
Server-->>Client: Task (status: working)
end
Client->>Server: tasks/get (taskId)
Server-->>Client: Task (status: completed, result)
```
## When to use Tasks
Tasks are a good fit when your use case involves:
**Long-running operations.** CI pipelines, batch data processing, or model
training jobs that take minutes or hours.
**Human-in-the-loop workflows.** Approval gates, review steps, or any operation
that pauses for user confirmation. The task moves to `input_required` and the
client presents the request.
**External job systems.** If your server wraps an API that already uses job IDs
(cloud deployments, async APIs, queued work), return a task when you create the
job and resolve it when the job completes.
**Unreliable connections.** Mobile clients, intermittent networks, or
environments where connections drop. Task IDs survive disconnects.
**Batch processing.** Operations that process many items (bulk imports, mass
updates) where partial progress is meaningful. Status messages report progress.
## Task lifecycle
| Status | Meaning |
| ---------------- | -------------------------------------------------------------------------- |
| `working` | The operation is in progress. |
| `input_required` | The server needs client input before continuing. See `inputRequests`. |
| `completed` | The operation finished. The `result` field contains the final output. |
| `failed` | A JSON-RPC error occurred during execution. The `error` field has details. |
| `cancelled` | The operation was cancelled (not always honored). |
`completed`, `failed`, and `cancelled` are terminal — once reached, the task's
state does not change.
## Notifications
Servers can push status updates via `notifications/tasks`. Clients opt
into these through the `subscriptions/listen` mechanism. Each notification
carries the full task state, eliminating the need for an extra `tasks/get`
round-trip.
Polling is the default. If a server supports notifications, clients can rely on
them instead of polling.
## Implementation guide
### For MCP clients
To consume task-augmented responses, your client must:
<Steps>
<Step title="Declare support">
Include the extension in its per-request capabilities:
```jsonc theme={null}
{
"jsonrpc": "2.0",
"id": 1,
"method": "...",
"params": {
// Other fields...
"_meta": {
// Other fields...
"io.modelcontextprotocol/clientCapabilities": {
"extensions": {
"io.modelcontextprotocol/tasks": {},
},
},
},
},
}
```
</Step>
<Step title="Handle polymorphic results">
When issuing a supported request (e.g., `tools/call`), be prepared to receive
either the standard result or a `CreateTaskResult` with `resultType: "task"`.
</Step>
<Step title="Poll for completion">
Call `tasks/get` with the returned `taskId`, respecting the `pollIntervalMs`
value. Continue polling until the task reaches a terminal status (`completed`,
`failed`, or `cancelled`).
</Step>
<Step title="Handle input requests">
If the task status is `input_required`, read the `inputRequests` map, present
the requests to the user or model, and submit responses via `tasks/update`.
</Step>
<Step title="Persist task IDs">
Store task IDs durably so polling can resume after a client crash or restart.
</Step>
</Steps>
### For MCP servers
To return tasks from your server:
<Steps>
<Step title="Advertise support">
Include the extension in your `server/discover` capabilities:
```jsonc theme={null}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
// Other fields...
"capabilities": {
"extensions": {
"io.modelcontextprotocol/tasks": {},
},
},
},
}
```
</Step>
<Step title="Check client capabilities">
Before returning a `CreateTaskResult`, verify that the client included the
extension in its per-request capabilities. Never return a task to a client that
did not declare support.
</Step>
<Step title="Return CreateTaskResult">
When a request will be long-running, respond with `resultType: "task"` and a
`Task` object containing a unique `taskId`, initial status, `ttlMs`, and
`pollIntervalMs`. The task must be durably created before sending the response.
</Step>
<Step title="Serve tasks/get">
Return the current task state on each poll. For terminal states, include the
`result` (on `completed`) or `error` (on `failed`) field.
</Step>
<Step title="Handle tasks/update">
Accept `inputResponses` keyed to outstanding `inputRequests`. Acknowledge with
an empty result. Ignore responses for unknown or already-satisfied keys.
</Step>
<Step title="Handle tasks/cancel">
Acknowledge cancellation requests with an empty result. Honor them when
possible, but cancellation is cooperative — the task may still reach a
non-`cancelled` terminal status.
</Step>
</Steps>
## Client support
<Note>
MCP Tasks is an extension to the [core MCP specification](/specification/latest). Host
support varies by client.
</Note>
See the [client matrix](/extensions/client-matrix) for extension support across
clients. Task support requires explicit opt-in from both client and server.
## Specification
The Tasks extension is specified in the [ext-tasks repository](https://github.com/modelcontextprotocol/ext-tasks). It uses the standard MCP [extension negotiation](/extensions/overview#negotiation) mechanism: clients declare support in the `extensions` field of the `io.modelcontextprotocol/clientCapabilities` they send in each request's `_meta`, and servers advertise theirs in the capabilities returned by [`server/discover`](/specification/draft/server/discover).
registry/about First recorded · 90 lines, first recorded
# The MCP Registry ## The MCP Registry Ecosystem ### Relationship with Package Registries ### Relationship with Server Developers ### Relationship with Downstream Aggregators ### Relationship with Other MCP Registries ### Relationship with MCP Host Applications ## Trust and Security ### Verifying Server Authenticity ### Security Scanning ### Spam Prevention
The first capture of this source. The page was already there, and this is what it said.
# The MCP Registry <Note> The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues). </Note> The MCP Registry is the official centralized metadata repository for publicly accessible MCP servers, backed by major trusted contributors to the MCP ecosystem such as Anthropic, GitHub, PulseMCP, and Microsoft. The MCP Registry provides: * A single place for server creators to publish metadata about their servers * Namespace management through DNS verification * A REST API for MCP clients and aggregators to discover available servers * Standardized installation and configuration information Server metadata is stored in a standardized [`server.json` format](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/draft/server.schema.json), which contains: * The server's unique name (e.g., `io.github.user/server-name`) * Where to locate the server (e.g., npm package name, remote server URL) * Execution instructions (e.g., command-line args, env vars) * Other discovery data (e.g., description, server capabilities) ## The MCP Registry Ecosystem The MCP Registry is part of an ecosystem that looks something like: <img src="https://mintcdn.com/mcp/jWyXLg8iLYJ-g6Lo/registry/ecosystem-diagram.excalidraw.svg?fit=max&auto=format&n=jWyXLg8iLYJ-g6Lo&q=85&s=06fcebbf5a33d3ef1fed72279f01f321" alt="The MCP Registry ecosystem" width="2787" height="1811" data-path="registry/ecosystem-diagram.excalidraw.svg" /> ### Relationship with Package Registries Package registries — such as npm, PyPI, and Docker Hub — host packages with code and binaries. The MCP Registry hosts metadata that points to those packages. For example, a `weather-mcp` package could be hosted on npm, and metadata in the MCP Registry could map the "weather v1.2.0" server to `npm:weather-mcp`. The [Package Types guide](./package-types) lists the supported package types and registries. More package registries may be supported in the future based on community demand. If you are interested in building support for a package registry, please [open an issue](https://github.com/modelcontextprotocol/registry). ### Relationship with Server Developers The MCP Registry supports both open-source and closed-source servers. Server developers can publish their server's metadata to the registry as long as the server's installation method is publicly available (e.g., an npm package or a Docker image on a public registry) *or* the server itself is publicly accessible (e.g., a remote server that is not restricted to private networks). The MCP Registry **does not** support private servers. Private servers are those that are only accessible to a narrow set of users. For example, servers published on a private network (like `mcp.acme-corp.internal`) or on private package registries (e.g. `npx -y @acme/mcp --registry https://artifactory.acme-corp.internal/npm`). If you want to publish private servers, we recommend that you host your own private MCP registry and add them there. ### Relationship with Downstream Aggregators The MCP Registry is intended to be consumed primarily by downstream aggregators, such as MCP server marketplaces. The metadata hosted by the MCP Registry is deliberately unopinionated. Downstream aggregators can provide curation or additional metadata such as community ratings. We expect that downstream aggregators will use the MCP Registry API to pull new metadata on a regular but infrequent basis (for example, once per hour). See the [MCP Registry Aggregators guide](./registry-aggregators) for more information. ### Relationship with Other MCP Registries In addition to a public REST API, the MCP Registry defines an [OpenAPI spec](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/api/openapi.yaml) that other MCP registries can implement in order to provide a standardized interface for MCP host applications. We expect that many downstream aggregators will implement this interface. Private MCP registries can implement it as well to benefit from existing host application support. Note that the official MCP Registry codebase is **not** designed for self-hosting, and the registry maintainers cannot provide support for this use case. If you choose to fork it, you would need to maintain and operate it independently. ### Relationship with MCP Host Applications The MCP Registry is not intended to be directly consumed by host applications. Instead, host applications should consume other MCP registries, such as downstream marketplaces, via a REST API conforming to the official MCP Registry's OpenAPI spec. ## Trust and Security ### Verifying Server Authenticity The MCP Registry uses namespace authentication to ensure that servers come from their claimed sources. Server names follow a reverse DNS format (like `io.github.username/server` or `com.example/server`) that ties them to verified GitHub accounts or domains. This namespace system ensures that only the legitimate owner of a GitHub account or domain can publish servers under that namespace, providing trust and accountability in the ecosystem. For details on authentication methods, see the [Authentication guide](./authentication). ### Security Scanning The MCP Registry delegates security scanning to: * **Underlying package registries** — npm, PyPI, Docker Hub, and other package registries perform their own security scanning and vulnerability detection. * **Downstream aggregators** — MCP Registry aggregators and marketplaces can implement additional security checks, ratings, or curation. The MCP Registry focuses on namespace authentication and metadata hosting, while relying on the broader ecosystem for security scanning of actual server code. ### Spam Prevention The MCP Registry uses multiple mechanisms to prevent spam: * **Namespace authentication requirements** — Publishers must verify ownership of their namespace through GitHub, DNS, or HTTP challenges, preventing arbitrary spam submissions. * **Character limits and validation** — Free-form fields have strict character limits and regex validation to prevent abuse. * **Manual takedown** — The registry maintainers can manually remove spam or malicious servers. See the [Moderation Policy](./moderation-policy) for details on what content is removed. Future spam prevention measures under consideration include stricter rate limiting, AI-based spam detection, and community reporting capabilities.
registry/authentication First recorded · 283 lines, first recorded
# How to Authenticate When Publishing to the Official MCP Registry ## GitHub Authentication ## DNS Authentication ## HTTP Authentication
The first capture of this source. The page was already there, and this is what it said.
# How to Authenticate When Publishing to the Official MCP Registry
<Note>
The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues).
</Note>
You must authenticate before publishing to the official MCP Registry. The MCP Registry supports different authentication methods. Which authentication method you choose determines the namespace of your server's name.
If you choose GitHub-based authentication, your server's name in `server.json` **MUST** be of the form `io.github.username/*` (or `io.github.orgname/*`). For example, `io.github.alice/weather-server`.
If you choose domain-based authentication, your server's name in `server.json` **MUST** be of the form `com.example.*/*`, where `com.example` is the reverse-DNS form of your domain name. For example, `io.modelcontextprotocol/everything`.
| Authentication | Name Format | Example Name |
| -------------- | ----------------------------------------------- | ------------------------------------ |
| GitHub-based | `io.github.username/*` or `io.github.orgname/*` | `io.github.alice/weather-server` |
| domain-based | `com.example.*/*` | `io.modelcontextprotocol/everything` |
## GitHub Authentication
GitHub authentication uses an OAuth flow initiated by the `mcp-publisher` CLI tool.
To perform GitHub authentication, navigate to your server project directory and run:
```bash theme={null}
mcp-publisher login github
```
You should see output like:
```text Output theme={null}
Logging in with github...
To authenticate, please:
1. Go to: https://github.com/login/device
2. Enter code: ABCD-1234
3. Authorize this application
Waiting for authorization...
```
Visit the link, follow the prompts, and enter the authorization code that was printed in the terminal (e.g., `ABCD-1234` in the above output). Once complete, go back to the terminal, and you should see output like:
```text Output theme={null}
Successfully authenticated!
✓ Successfully logged in
```
## DNS Authentication
DNS authentication is a domain-based authentication method that relies on a DNS TXT record.
To perform DNS authentication using the `mcp-publisher` CLI tool, run the following commands in your server project directory to generate a TXT record based on a public/private key pair:
<CodeGroup>
```bash Ed25519 theme={null}
MY_DOMAIN="example.com"
# Generate public/private key pair using Ed25519
openssl genpkey -algorithm Ed25519 -out key.pem
# Generate TXT record
PUBLIC_KEY="$(openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64)"
echo "${MY_DOMAIN}. IN TXT \"v=MCPv1; k=ed25519; p=${PUBLIC_KEY}\""
```
```bash ECDSA P-384 theme={null}
MY_DOMAIN="example.com"
# Generate public/private key pair using ECDSA P-384
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -out key.pem
# Generate TXT record
PUBLIC_KEY="$(openssl ec -in key.pem -text -noout -conv_form compressed | grep -A4 "pub:" | tail -n +2 | tr -d ' :\n' | xxd -r -p | base64)"
echo "${MY_DOMAIN}. IN TXT \"v=MCPv1; k=ecdsap384; p=${PUBLIC_KEY}\""
```
```bash Google KMS theme={null}
MY_DOMAIN="example.com"
MY_PROJECT="myproject"
MY_KEYRING="mykeyring"
MY_KEY_NAME="mykey"
# Log in using gcloud CLI (https://cloud.google.com/sdk/docs/install)
gcloud auth login
# Set default project
gcloud config set project "${MY_PROJECT}"
# Create a keyring in your project
gcloud kms keyrings create "${MY_KEYRING}" --location global
# Create an Ed25519 signing key
gcloud kms keys create "${MY_KEY_NAME}" --default-algorithm=ec-sign-ed25519 --purpose=asymmetric-signing --keyring="${MY_KEYRING}" --location=global
# Enable Application Default Credentials (ADC) so the publisher tool can sign
gcloud auth application-default login
# Attempt login to show the public key
mcp-publisher login dns google-kms --domain="${MY_DOMAIN}" --resource="projects/${MY_PROJECT}/locations/global/keyRings/${MY_KEYRING}/cryptoKeys/${MY_KEY_NAME}/cryptoKeyVersions/1"
# Copy the "Expected proof record":
# ${MY_DOMAIN}. IN TXT "v=MCPv1; k=ed25519; p=${PUBLIC_KEY}"
```
```bash Azure Key Vault theme={null}
MY_DOMAIN="example.com"
MY_SUBSCRIPTION="subscription name or ID"
MY_RESOURCE_GROUP="MyResourceGroup"
MY_KEY_VAULT="MyKeyVault"
MY_KEY_NAME="MyKey"
# Log in using Azure CLI (https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
az login
# Set default subscription
az account set --subscription "${MY_SUBSCRIPTION}"
# Create a resource group
az group create --location westus --resource-group "${MY_RESOURCE_GROUP}"
# Create a key vault
az keyvault create --name "${MY_KEY_VAULT}" --location westus --resource-group "${MY_RESOURCE_GROUP}"
# Create an ECDSA P-384 signing key
az keyvault key create --name "${MY_KEY_NAME}" --vault-name "${MY_KEY_VAULT}" --curve P-384
# Attempt login to show the public key
mcp-publisher login dns azure-key-vault --domain="${MY_DOMAIN}" --vault "${MY_KEY_VAULT}" --key "${MY_KEY_NAME}"
# Copy the "Expected proof record":
# ${MY_DOMAIN}. IN TXT "v=MCPv1; k=ecdsap384; p=${PUBLIC_KEY}"
```
</CodeGroup>
Then add the TXT record using your DNS provider's control panel. It may take several minutes for the TXT record to propagate. After the TXT record has propagated, log in using the `mcp-publisher login` command:
<CodeGroup>
```bash Ed25519 theme={null}
MY_DOMAIN="example.com"
PRIVATE_KEY="$(openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n')"
mcp-publisher login dns --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"
```
```bash ECDSA P-384 theme={null}
MY_DOMAIN="example.com"
PRIVATE_KEY="$(openssl ec -in key.pem -noout -text | grep -A4 "priv:" | tail -n +2 | tr -d ' :\n')"
mcp-publisher login dns --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"
```
```bash Google KMS theme={null}
MY_DOMAIN="example.com"
MY_PROJECT="myproject"
MY_KEYRING="mykeyring"
MY_KEY_NAME="mykey"
mcp-publisher login dns google-kms --domain="${MY_DOMAIN}" --resource="projects/${MY_PROJECT}/locations/global/keyRings/${MY_KEYRING}/cryptoKeys/${MY_KEY_NAME}/cryptoKeyVersions/1"
```
```bash Azure Key Vault theme={null}
MY_DOMAIN="example.com"
MY_KEY_VAULT="MyKeyVault"
MY_KEY_NAME="MyKey"
mcp-publisher login dns azure-key-vault --domain="${MY_DOMAIN}" --vault "${MY_KEY_VAULT}" --key "${MY_KEY_NAME}"
```
</CodeGroup>
## HTTP Authentication
HTTP authentication is a domain-based authentication method that relies on a `/.well-known/mcp-registry-auth` file hosted on your domain. For example, `https://example.com/.well-known/mcp-registry-auth`.
To perform HTTP authentication using the `mcp-publisher` CLI tool, run the following commands in your server project directory to generate an `mcp-registry-auth` file based on a public/private key pair:
<CodeGroup>
```bash Ed25519 theme={null}
# Generate public/private key pair using Ed25519
openssl genpkey -algorithm Ed25519 -out key.pem
# Generate mcp-registry-auth file
PUBLIC_KEY="$(openssl pkey -in key.pem -pubout -outform DER | tail -c 32 | base64)"
echo "v=MCPv1; k=ed25519; p=${PUBLIC_KEY}" > mcp-registry-auth
```
```bash ECDSA P-384 theme={null}
# Generate public/private key pair using ECDSA P-384
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -out key.pem
# Generate mcp-registry-auth file
PUBLIC_KEY="$(openssl ec -in key.pem -text -noout -conv_form compressed | grep -A4 "pub:" | tail -n +2 | tr -d ' :\n' | xxd -r -p | base64)"
echo "v=MCPv1; k=ecdsap384; p=${PUBLIC_KEY}" > mcp-registry-auth
```
```bash Google KMS theme={null}
MY_DOMAIN="example.com"
MY_PROJECT="myproject"
MY_KEYRING="mykeyring"
MY_KEY_NAME="mykey"
# Log in using gcloud CLI (https://cloud.google.com/sdk/docs/install)
gcloud auth login
# Set default project
gcloud config set project "${MY_PROJECT}"
# Create a keyring in your project
gcloud kms keyrings create "${MY_KEYRING}" --location global
# Create an Ed25519 signing key
gcloud kms keys create "${MY_KEY_NAME}" --default-algorithm=ec-sign-ed25519 --purpose=asymmetric-signing --keyring="${MY_KEYRING}" --location=global
# Enable Application Default Credentials (ADC) so the publisher tool can sign
gcloud auth application-default login
# Attempt login to show the public key
mcp-publisher login http google-kms --domain="${MY_DOMAIN}" --resource="projects/${MY_PROJECT}/locations/global/keyRings/${MY_KEYRING}/cryptoKeys/${MY_KEY_NAME}/cryptoKeyVersions/1"
# Copy the "Expected proof record" to `./mcp-registry-auth`:
# v=MCPv1; k=ed25519; p=${PUBLIC_KEY}
```
```bash Azure Key Vault theme={null}
MY_DOMAIN="example.com"
MY_SUBSCRIPTION="subscription name or ID"
MY_RESOURCE_GROUP="MyResourceGroup"
MY_KEY_VAULT="MyKeyVault"
MY_KEY_NAME="MyKey"
# Log in using Azure CLI (https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
az login
# Set default subscription
az account set --subscription "${MY_SUBSCRIPTION}"
# Create a resource group
az group create --location westus --resource-group "${MY_RESOURCE_GROUP}"
# Create a key vault
az keyvault create --name "${MY_KEY_VAULT}" --location westus --resource-group "${MY_RESOURCE_GROUP}"
# Create an ECDSA P-384 signing key
az keyvault key create --name "${MY_KEY_NAME}" --vault-name "${MY_KEY_VAULT}" --curve P-384
# Attempt login to show the public key
mcp-publisher login http azure-key-vault --domain="${MY_DOMAIN}" --vault "${MY_KEY_VAULT}" --key "${MY_KEY_NAME}"
# Copy the "Expected proof record" to `./mcp-registry-auth`:
# v=MCPv1; k=ecdsap384; p=${PUBLIC_KEY}
```
</CodeGroup>
Then host the `mcp-registry-auth` file at `/.well-known/mcp-registry-auth` on your domain. After the file is hosted, log in using the `mcp-publisher login` command:
<CodeGroup>
```bash Ed25519 theme={null}
MY_DOMAIN="example.com"
PRIVATE_KEY="$(openssl pkey -in key.pem -noout -text | grep -A3 "priv:" | tail -n +2 | tr -d ' :\n')"
mcp-publisher login http --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"
```
```bash ECDSA P-384 theme={null}
MY_DOMAIN="example.com"
PRIVATE_KEY="$(openssl ec -in key.pem -noout -text | grep -A4 "priv:" | tail -n +2 | tr -d ' :\n')"
mcp-publisher login http --domain "${MY_DOMAIN}" --private-key "${PRIVATE_KEY}"
```
```bash Google KMS theme={null}
MY_DOMAIN="example.com"
MY_PROJECT="myproject"
MY_KEYRING="mykeyring"
MY_KEY_NAME="mykey"
mcp-publisher login http google-kms --domain="${MY_DOMAIN}" --resource="projects/${MY_PROJECT}/locations/global/keyRings/${MY_KEYRING}/cryptoKeys/${MY_KEY_NAME}/cryptoKeyVersions/1"
```
```bash Azure Key Vault theme={null}
MY_DOMAIN="example.com"
MY_KEY_VAULT="MyKeyVault"
MY_KEY_NAME="MyKey"
mcp-publisher login http azure-key-vault --domain="${MY_DOMAIN}" --vault "${MY_KEY_VAULT}" --key "${MY_KEY_NAME}"
```
</CodeGroup>
registry/faq First recorded · 41 lines, first recorded
# Frequently Asked Questions ## General ### What is the difference between "Official MCP Registry", "MCP Registry", "MCP registry", "MCP Registry API", etc? ### Can I delete/unpublish my server? ### How do I update my server metadata? ### Can I add custom metadata when publishing? ## Reporting Issues ### What if I need to report a spam or malicious server? ### What if I need to report a security vulnerability in the registry itself?
The first capture of this source. The page was already there, and this is what it said.
# Frequently Asked Questions <Note> The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues). </Note> ## General ### What is the difference between "Official MCP Registry", "MCP Registry", "MCP registry", "MCP Registry API", etc? * "MCP Registry API" — An API that implements the [OpenAPI spec](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/api/openapi.yaml) defined by the MCP Registry. * "Official MCP Registry API" — The REST API served at `https://registry.modelcontextprotocol.io`, which is a superset of the MCP Registry API. Its OpenAPI spec can be downloaded from [https://registry.modelcontextprotocol.io/openapi.yaml](https://registry.modelcontextprotocol.io/openapi.yaml). * "MCP registry" — A third-party service that provides an MCP Registry API. * "Official MCP Registry" (or "The MCP Registry") — The service that lives at `https://registry.modelcontextprotocol.io`. ### Can I delete/unpublish my server? Currently, no. At the time of writing, there is [open discussion](https://github.com/modelcontextprotocol/registry/issues/104). ### How do I update my server metadata? Submit a new `server.json` with a unique version string. Once published, version metadata is immutable (similar to npm). ### Can I add custom metadata when publishing? Yes, custom metadata under `_meta.io.modelcontextprotocol.registry/publisher-provided` is preserved when publishing to the registry. This allows you to include custom metadata specific to your publishing process. <Warning> There is a 4KB size limit (4096 bytes of JSON). Publishing will fail if this limit is exceeded. </Warning> ## Reporting Issues ### What if I need to report a spam or malicious server? 1. Report it as abuse to the underlying package registry (e.g. NPM, PyPI, DockerHub, etc.); and 2. Raise a GitHub issue on the registry repo with a title beginning `Abuse report: ` ### What if I need to report a security vulnerability in the registry itself? Follow [the MCP community SECURITY.md](https://github.com/modelcontextprotocol/.github/blob/main/SECURITY.md).
registry/github-actions First recorded · 216 lines, first recorded
# How to Automate Publishing with GitHub Actions ## Step 1: Create a Workflow File ## Step 2: Add Secrets ## Step 3: Tag and Release ## Troubleshooting
The first capture of this source. The page was already there, and this is what it said.
# How to Automate Publishing with GitHub Actions
<Note>
The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues).
</Note>
## Step 1: Create a Workflow File
In your server project directory, create a `.github/workflows/publish-mcp.yml` file. Here is an example for npm-based local server, but the MCP Registry publishing steps are the same for all package types:
<CodeGroup>
```yaml OIDC authentication (recommended) theme={null}
name: Publish to MCP Registry
on:
push:
tags: ["v*"] # Triggers on version tags like v1.0.0
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC authentication
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
### Publish underlying npm package:
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "lts/*"
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test --if-present
- name: Build package
run: npm run build --if-present
- name: Publish package to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
### Publish MCP server:
- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
- name: Authenticate to MCP Registry
run: ./mcp-publisher login github-oidc
# Optional:
# - name: Set version in server.json
# run: |
# VERSION=${GITHUB_REF#refs/tags/v}
# jq --arg v "$VERSION" '.version = $v' server.json > server.tmp && mv server.tmp server.json
- name: Publish server to MCP Registry
run: ./mcp-publisher publish
```
```yaml PAT authentication theme={null}
name: Publish to MCP Registry
on:
push:
tags: ["v*"] # Triggers on version tags like v1.0.0
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
### Publish underlying npm package:
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "lts/*"
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test --if-present
- name: Build package
run: npm run build --if-present
- name: Publish package to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
### Publish MCP server:
- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
- name: Authenticate to MCP Registry
run: ./mcp-publisher login github --token ${{ secrets.MCP_GITHUB_TOKEN }}
# Optional:
# - name: Set version in server.json
# run: |
# VERSION=${GITHUB_REF#refs/tags/v}
# jq --arg v "$VERSION" '.version = $v' server.json > server.tmp && mv server.tmp server.json
- name: Publish server to MCP Registry
run: ./mcp-publisher publish
```
```yaml DNS authentication theme={null}
name: Publish to MCP Registry
on:
push:
tags: ["v*"] # Triggers on version tags like v1.0.0
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v5
### Publish underlying npm package:
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "lts/*"
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test --if-present
- name: Build package
run: npm run build --if-present
- name: Publish package to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
### Publish MCP server:
- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# TODO: Replace `example.com` with your domain name
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- name: Authenticate to MCP Registry
run: ./mcp-publisher login dns --domain example.com --private-key ${{ secrets.MCP_PRIVATE_KEY }}
# Optional:
# - name: Set version in server.json
# run: |
# VERSION=${GITHUB_REF#refs/tags/v}
# jq --arg v "$VERSION" '.version = $v' server.json > server.tmp && mv server.tmp server.json
- name: Publish server to MCP Registry
run: ./mcp-publisher publish
```
</CodeGroup>
## Step 2: Add Secrets
You may need to add a secret to the repository depending on which authentication method you choose:
* **GitHub OIDC Authentication**: No dedicated secret necessary.
* **GitHub PAT Authentication**: Add a `MCP_GITHUB_TOKEN` secret with a GitHub Personal Access Token (PAT) that has `read:org` and `read:user` scopes.
* **DNS Authentication**: Add a `MCP_PRIVATE_KEY` secret with your Ed25519 private key.
You may also need to add secrets for your package registry. For example, the workflow above needs an `NPM_TOKEN` secret with your npm token.
For information about how to add secrets to a repository, see [Using secrets in GitHub Actions](https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets).
## Step 3: Tag and Release
Create and push a version tag to trigger the workflow:
```bash theme={null}
git tag v1.0.0
git push origin v1.0.0
```
The workflow will run tests, build the package, publish the package to npm, and publish the server to the MCP Registry.
## Troubleshooting
| Error Message | Action |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "Authentication failed" | Ensure `id-token: write` permission is set for OIDC, or check secrets. |
| "Package validation failed" | Verify your package successfully published to the package registry (e.g., npm, PyPI), and that your package has the [necessary verification information](./package-types). |
registry/moderation-policy First recorded · 59 lines, first recorded
# The MCP Registry Moderation Policy ## Scope ## Disclaimer ## What We Remove ## What We Don't Remove ## How Removal Works ## Appeals ## Changes to This Policy
The first capture of this source. The page was already there, and this is what it said.
# The MCP Registry Moderation Policy <Note> The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues). </Note> **TL;DR**: The MCP Registry is quite permissive! We only remove illegal content, malware, spam, and completely broken servers. ## Scope This policy applies to the official MCP Registry at `registry.modelcontextprotocol.io`. Subregistries may have their own moderation policies. If you have questions about content on a specific subregistry, please contact them directly. ## Disclaimer The MCP Registry **does not** make guarantees about moderation, and consumers should assume minimal-to-no moderation. The MCP Registry is a community supported project, and we have limited active moderation capabilities. We largely rely on upstream package registries (like NPM, PyPI, and Docker) or downstream subregistries (like the GitHub MCP Registry) to do more in-depth moderation. This means there may be content in the MCP Registry that should be removed under this policy, but which we haven't yet removed. Consumers should treat scraped data accordingly. ## What We Remove We will remove servers that contain: * Illegal content, which includes obscene content, copyright violations, and hacking tools * Malware, regardless of intentions * Spam, especially mass-created servers that disrupt the registry. Examples: * The same server being submitted multiple times under different names * A server that doesn't do anything but provide a fixed response with some marketing copy * A server with a description stuffed with marketing copy and an unrelated implementation * Non-functioning servers ## What We Don't Remove Generally, we believe in keeping the registry open and pushing moderation to subregistries. We therefore **won't** remove: * Low-quality or buggy servers * Servers with security vulnerabilities * Servers that do the same thing as other servers * Servers that provide or contain adult content ## How Removal Works When we remove a server, we set the server's `status` to `"deleted"`, but the server's metadata remains accessible via the MCP Registry API. Aggregators may then remove the server from their indexes. In extreme cases, we may overwrite or erase the server's metadata. For example, if the metadata itself is unlawful. ## Appeals Think we made a mistake? Open an issue on our [GitHub repository](https://github.com/modelcontextprotocol/registry) with: * The name of the server * Why you believe the server doesn't meet the above criteria for removal ## Changes to This Policy We're still learning how best to run the MCP Registry! As such, we might end up changing this policy in the future.
registry/package-types First recorded · 202 lines, first recorded
# MCP Registry Supported Package Types # Package Types ## npm Packages ### Ownership Verification ## PyPI Packages ### Ownership Verification ## NuGet Packages ### Ownership Verification ## Docker/OCI Images ### Ownership Verification ## MCPB Packages ### Verification
The first capture of this source. The page was already there, and this is what it said.
# MCP Registry Supported Package Types
<Note>
The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues).
</Note>
# Package Types
The MCP Registry supports several different package types, and each package type has its own verification method.
## npm Packages
For npm packages, the MCP Registry currently supports the npm public registry (`https://registry.npmjs.org`) only.
npm packages use `"registryType": "npm"` in `server.json`. For example:
```json server.json highlight={9} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.username/email-integration-mcp",
"title": "Email Integration",
"description": "Send emails and manage email accounts",
"version": "1.0.0",
"packages": [
{
"registryType": "npm",
"identifier": "@username/email-integration-mcp",
"version": "1.0.0",
"transport": {
"type": "stdio"
}
}
]
}
```
### Ownership Verification
The MCP Registry verifies ownership of npm packages by checking `mcpName` in `package.json`. The `mcpName` property **MUST** match the server name from `server.json`. For example:
```json package.json theme={null}
{
"name": "@username/email-integration-mcp",
"version": "1.0.0",
"mcpName": "io.github.username/email-integration-mcp"
}
```
## PyPI Packages
For PyPI packages, the MCP Registry currently supports the official PyPI registry (`https://pypi.org`) only.
PyPI packages use `"registryType": "pypi"` in `server.json`. For example:
```json server.json highlight={9} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.username/database-query-mcp",
"title": "Database Query",
"description": "Execute SQL queries and manage database connections",
"version": "1.0.0",
"packages": [
{
"registryType": "pypi",
"identifier": "database-query-mcp",
"version": "1.0.0",
"transport": {
"type": "stdio"
}
}
]
}
```
### Ownership Verification
The MCP Registry verifies ownership of PyPI packages by checking for the existence of an `mcp-name: $SERVER_NAME` string in the package README (which becomes the package description on PyPI). The string may be hidden in a comment, but the `$SERVER_NAME` portion **MUST** match the server name from `server.json`. For example:
```markdown README.md highlight={5} theme={null}
# Database Query MCP Server
This MCP server executes SQL queries and manages database connections.
<!-- mcp-name: io.github.username/database-query-mcp -->
```
## NuGet Packages
For NuGet packages, the MCP Registry currently supports the official NuGet registry (`https://api.nuget.org/v3/index.json`) only.
NuGet packages use `"registryType": "nuget"` in `server.json`. For example:
```json server.json highlight={9} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.username/azure-devops-mcp",
"title": "Azure DevOps",
"description": "Manage Azure DevOps work items and pipelines",
"version": "1.0.0",
"packages": [
{
"registryType": "nuget",
"identifier": "Username.AzureDevOpsMcp",
"version": "1.0.0",
"transport": {
"type": "stdio"
}
}
]
}
```
### Ownership Verification
The MCP Registry verifies ownership of NuGet packages by checking for the existence of an `mcp-name: $SERVER_NAME` string in the package README. The string may be hidden in a comment, but the `$SERVER_NAME` portion **MUST** match the server name from `server.json`. For example:
```markdown README.md highlight={5} theme={null}
# Azure DevOps MCP Server
This MCP server manages Azure DevOps work items and pipelines.
<!-- mcp-name: io.github.username/azure-devops-mcp -->
```
## Docker/OCI Images
For Docker/OCI images, the MCP Registry currently supports:
* Docker Hub (`docker.io`)
* GitHub Container Registry (`ghcr.io`)
* Google Artifact Registry (any `*.pkg.dev` domain)
* Azure Container Registry (`*.azurecr.io`)
* Microsoft Container Registry (`mcr.microsoft.com`)
Docker/OCI images use `"registryType": "oci"` in `server.json`. For example:
```json server.json highlight={9} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.username/kubernetes-manager-mcp",
"title": "Kubernetes Manager",
"description": "Deploy and manage Kubernetes resources",
"version": "1.0.0",
"packages": [
{
"registryType": "oci",
"identifier": "docker.io/yourusername/kubernetes-manager-mcp:1.0.0",
"transport": {
"type": "stdio"
}
}
]
}
```
The format of `identifier` is `registry/namespace/repository:tag`. For example, `docker.io/user/app:1.0.0` or `ghcr.io/user/app:1.0.0`. The tag can also be specified as a digest.
### Ownership Verification
The MCP Registry verifies ownership of Docker/OCI images by checking for an `io.modelcontextprotocol.server.name` annotation. The value of the `io.modelcontextprotocol.server.name` annotation **MUST** match the server name from `server.json`. For example:
```dockerfile Dockerfile theme={null}
LABEL io.modelcontextprotocol.server.name="io.github.username/kubernetes-manager-mcp"
```
## MCPB Packages
For MCPB packages, the MCP Registry currently supports MCPB artifacts hosted via GitHub or GitLab releases.
MCPB packages use `"registryType": "mcpb"` in `server.json`. For example:
```json server.json highlight={9} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.username/image-processor-mcp",
"title": "Image Processor",
"description": "Process and transform images with various filters",
"version": "1.0.0",
"packages": [
{
"registryType": "mcpb",
"identifier": "https://github.com/username/image-processor-mcp/releases/download/v1.0.0/image-processor.mcpb",
"fileSha256": "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce",
"transport": {
"type": "stdio"
}
}
]
}
```
### Verification
The MCPB package URL (`identifier` in `server.json`) **MUST** contain the string "mcp". That can be as part of the `.mcpb` file extension or in the name of the repository.
The package metadata in `server.json` **MUST** include a `fileSha256` property with a SHA-256 hash of the MCPB artifact, which can be computed using the `openssl` command:
```bash theme={null}
openssl dgst -sha256 image-processor.mcpb
```
The MCP Registry does not validate this hash; however, MCP clients **do** validate the hash before installation to ensure file integrity. Downstream registries may also implement their own validation.
registry/quickstart First recorded · 284 lines, first recorded
# Quickstart: Publish an MCP Server to the MCP Registry ## Prerequisites ## Step 1: Add verification information to the package ## Step 2: Publish the package ## Step 3: Install `mcp-publisher` ## Step 4: Create `server.json` ## Step 5: Authenticate with the MCP Registry ## Step 6: Publish to the MCP Registry ## Troubleshooting ## Next Steps
The first capture of this source. The page was already there, and this is what it said.
# Quickstart: Publish an MCP Server to the MCP Registry
<Note>
The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues).
</Note>
This tutorial will show you how to publish an MCP server written in TypeScript to the MCP Registry using the official `mcp-publisher` CLI tool.
## Prerequisites
* **Node.js** — This tutorial assumes the MCP server is written in TypeScript.
* **npm account** — The MCP Registry only hosts metadata, not artifacts. Before publishing to the MCP Registry, we will publish the MCP server's package to npm, so you will need an [npm](https://www.npmjs.com) account.
* **GitHub account** — The MCP Registry supports [multiple authentication methods](./authentication). For simplicity, this tutorial will use GitHub-based authentication, so you will need a [GitHub](https://github.com/) account.
If you do not have an MCP server written in TypeScript, you can copy the `weather-server-typescript` server from the [`modelcontextprotocol/quickstart-resources` repository](https://github.com/modelcontextprotocol/quickstart-resources) to follow along with this tutorial:
```bash theme={null}
git clone --depth 1 [email protected]:modelcontextprotocol/quickstart-resources.git
cp -r quickstart-resources/weather-server-typescript .
rm -rf quickstart-resources
cd weather-server-typescript
```
And edit `package.json` to reflect your information:
```diff package.json theme={null}
{
- "name": "mcp-quickstart-ts",
- "version": "1.0.0",
+ "name": "@my-username/mcp-weather-server",
+ "version": "1.0.1",
"main": "index.js",
```
```diff package.json theme={null}
"license": "ISC",
- "description": "",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/my-username/mcp-weather-server.git"
+ },
+ "description": "An MCP server for weather information.",
"devDependencies": {
```
## Step 1: Add verification information to the package
The MCP Registry verifies that a server's underlying package matches its metadata. For npm packages, this requires adding an `mcpName` property to `package.json`:
```diff package.json theme={null}
{
"name": "@my-username/mcp-weather-server",
"version": "1.0.1",
+ "mcpName": "io.github.my-username/weather",
"main": "index.js",
```
The value of `mcpName` will be your server's name in the MCP Registry.
Because we will be using GitHub-based authentication, `mcpName` **must** start with `io.github.my-username/`.
## Step 2: Publish the package
The MCP Registry only hosts metadata, not artifacts, so we must publish the package to npm before publishing the server to the MCP Registry.
Ensure the distribution files are built:
```bash theme={null}
# Navigate to project directory
cd weather-server-typescript
# Install dependencies
npm install
# Build the distribution files
npm run build
```
Then follow npm's [publishing guide](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages). In particular, you will probably need to run the following commands:
```bash theme={null}
# If necessary, authenticate to npm
npm adduser
# Publish the package
npm publish --access public
```
You can verify your package is published by visiting its npm URL, such as [https://www.npmjs.com/package/@my-username/mcp-weather-server](https://www.npmjs.com/package/@my-username/mcp-weather-server).
## Step 3: Install `mcp-publisher`
Install the `mcp-publisher` CLI tool using a pre-built binary or [Homebrew](https://brew.sh):
<CodeGroup>
```bash macOS/Linux theme={null}
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher && sudo mv mcp-publisher /usr/local/bin/
```
```powershell Windows theme={null}
$arch = if ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture -eq "Arm64") { "arm64" } else { "amd64" }; Invoke-WebRequest -Uri "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_windows_$arch.tar.gz" -OutFile "mcp-publisher.tar.gz"; tar xf mcp-publisher.tar.gz mcp-publisher.exe; rm mcp-publisher.tar.gz
# Move mcp-publisher.exe to a directory in your PATH
```
```bash theme={null}
brew install mcp-publisher
```
</CodeGroup>
Verify that `mcp-publisher` is correctly installed by running:
```bash theme={null}
mcp-publisher --help
```
You should see output like:
```text Output theme={null}
MCP Registry Publisher Tool
Usage:
mcp-publisher <command> [arguments]
Commands:
init Create a server.json file template
login Authenticate with the registry
logout Clear saved authentication
publish Publish server.json to the registry
```
## Step 4: Create `server.json`
The `mcp-publisher init` command can generate a `server.json` template file with some information derived from your project.
In your server project directory, run `mcp-publisher init`:
```bash theme={null}
mcp-publisher init
```
Open the generated `server.json` file, and you should see contents like:
```json server.json theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.my-username/weather",
"description": "An MCP server for weather information.",
"repository": {
"url": "https://github.com/my-username/mcp-weather-server",
"source": "github"
},
"version": "1.0.0",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/mcp-weather-server",
"version": "1.0.0",
"transport": {
"type": "stdio"
},
"environmentVariables": [
{
"description": "Your API key for the service",
"isRequired": true,
"format": "string",
"isSecret": true,
"name": "YOUR_API_KEY"
}
]
}
]
}
```
Edit the contents as necessary:
```diff server.json theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.my-username/weather",
"description": "An MCP server for weather information.",
"repository": {
"url": "https://github.com/my-username/mcp-weather-server",
"source": "github"
},
- "version": "1.0.0",
+ "version": "1.0.1",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/mcp-weather-server",
- "version": "1.0.0",
+ "version": "1.0.1",
"transport": {
"type": "stdio"
- },
- "environmentVariables": [
- {
- "description": "Your API key for the service",
- "isRequired": true,
- "format": "string",
- "isSecret": true,
- "name": "YOUR_API_KEY"
- }
- ]
+ }
}
]
}
```
The `name` property in `server.json` **must** match the `mcpName` property in `package.json`.
## Step 5: Authenticate with the MCP Registry
For this tutorial, we will authenticate with the MCP Registry using GitHub-based authentication.
Run the `mcp-publisher login` command to initiate authentication:
```bash theme={null}
mcp-publisher login github
```
You should see output like:
```text Output theme={null}
Logging in with github...
To authenticate, please:
1. Go to: https://github.com/login/device
2. Enter code: ABCD-1234
3. Authorize this application
Waiting for authorization...
```
Visit the link, follow the prompts, and enter the authorization code that was printed in the terminal (e.g., `ABCD-1234` in the above output). Once complete, go back to the terminal, and you should see output like:
```text Output theme={null}
Successfully authenticated!
✓ Successfully logged in
```
## Step 6: Publish to the MCP Registry
Finally, publish your server to the MCP Registry using the `mcp-publisher publish` command:
```bash theme={null}
mcp-publisher publish
```
You should see output like:
```text Output theme={null}
Publishing to https://registry.modelcontextprotocol.io...
✓ Successfully published
✓ Server io.github.my-username/weather version 1.0.1
```
You can verify that your server is published by searching for it using the MCP Registry API:
```bash theme={null}
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.my-username/weather"
```
You should see your server's metadata in the search results JSON:
```text Output theme={null}
{"servers":[{ ... "name":"io.github.my-username/weather" ... }]}
```
## Troubleshooting
| Error Message | Action |
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "Registry validation failed for package" | Ensure your package includes the required validation information (e.g, `mcpName` property in `package.json`). |
| "Invalid or expired Registry JWT token" | Re-authenticate by running `mcp-publisher login github`. |
| "You do not have permission to publish this server" | Your authentication method doesn't match your server's namespace format. With GitHub auth, your server name must start with `io.github.your-username/`. |
## Next Steps
* Learn about [support for other package types](./package-types).
* Learn about [support for remote servers](./remote-servers).
* Learn how to [use other authentication methods](./authentication), such as [DNS authentication](./authentication#dns-authentication) which enables custom domains for server name prefixes.
* Learn how to [automate publishing with GitHub Actions](./github-actions).
registry/registry-aggregators First recorded · 105 lines, first recorded
# MCP Registry Aggregators ## Consuming the MCP Registry REST API ### Pagination ### Filtering Since ## Server Status ## Acting as a Subregistry
The first capture of this source. The page was already there, and this is what it said.
# MCP Registry Aggregators
<Note>
The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues).
</Note>
Aggregators are downstream consumers of the MCP Registry that provide additional value. For example, a server marketplace that provides user ratings and security scanning.
The MCP Registry provides an unauthenticated read-only REST API that aggregators can use to populate their data stores. Aggregators are expected to scrape data on a regular but infrequent basis (e.g., once per hour), and persist the data in their own data store. The MCP Registry **does not provide uptime or data durability guarantees**.
## Consuming the MCP Registry REST API
The base URL for the MCP Registry REST API is `https://registry.modelcontextprotocol.io`. It supports the following endpoints:
* [`GET /v0.1/servers`](https://registry.modelcontextprotocol.io/docs#/operations/list-servers-v0.1) — List all servers.
* [`GET /v0.1/servers/{serverName}/versions`](https://registry.modelcontextprotocol.io/docs#/operations/get-server-versions-v0.1) — List all versions of a server.
* [`GET /v0.1/servers/{serverName}/versions/{version}`](https://registry.modelcontextprotocol.io/docs#/operations/get-server-version-v0.1) — Get a specific version of a server. Use the special version `latest` to get the latest version of the server.
<Warning>
URL path parameters such as `serverName` and `version` **must** be URL-encoded. For example, `io.modelcontextprotocol/everything` must be encoded as `io.modelcontextprotocol%2Feverything`.
</Warning>
Aggregators will most likely scrape the `GET /v0.1/servers` endpoint.
### Pagination
The `GET /v0.1/servers` endpoint supports cursor-based pagination.
For example, the first page can be fetched using a `limit` query parameter:
```bash theme={null}
curl "https://registry.modelcontextprotocol.io/v0.1/servers?limit=100"
```
```jsonc Output highlight={5} theme={null}
{
"servers": [
/* ... */
],
"metadata": {
"count": 100,
"nextCursor": "com.example/my-server:1.0.0",
},
}
```
Then subsequent pages can be fetched by passing the `nextCursor` value as the `cursor` query parameter:
```bash theme={null}
curl "https://registry.modelcontextprotocol.io/v0.1/servers?limit=100&cursor=com.example/my-server:1.0.0"
```
### Filtering Since
The `GET /v0.1/servers` endpoint supports filtering servers that have been updated since a given timestamp.
For example, servers that have been updated since 2025-10-23 can be fetched using an `updated_since` query parameter in [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) date-time format:
```bash theme={null}
curl "https://registry.modelcontextprotocol.io/v0.1/servers?updated_since=2025-10-23T00:00:00.000Z"
```
## Server Status
Server metadata is generally immutable, except for the `status` field which may be updated to, e.g., `"deprecated"` or `"deleted"`. We recommend that aggregators keep their copy of each server's `status` up to date.
The `"deleted"` status typically indicates that a server has violated our permissive [moderation policy](./moderation-policy), suggesting the server might be spam, malware, or illegal. Aggregators may prefer to remove these servers from their index.
## Acting as a Subregistry
A subregistry is an aggregator that also implements the [OpenAPI spec](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/api/openapi.yaml) defined by the MCP Registry. This allows clients, such as MCP host applications, to consume server metadata via a standardized interface.
The subregistry OpenAPI spec allows subregistries to inject custom metadata via the `_meta` field. For example, a subregistry could inject user ratings, download counts, and security scan results:
```json server.json highlight={17-26} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.username/email-integration-mcp",
"title": "Email Integration",
"description": "Send emails and manage email accounts",
"version": "1.0.0",
"packages": [
{
"registryType": "npm",
"identifier": "@username/email-integration-mcp",
"version": "1.0.0",
"transport": {
"type": "stdio"
}
}
],
"_meta": {
"com.example.subregistry/custom": {
"user_rating": 4.5,
"download_count": 12345,
"security_scan": {
"last_scanned": "2025-10-23T12:00:00Z",
"vulnerabilities_found": 0
}
}
}
}
```
We recommend that custom metadata be put under a key that reflects the subregistry (e.g., `"com.example.subregistry/custom"` in the above example).
registry/remote-servers First recorded · 167 lines, first recorded
# Publishing Remote Servers ## Transport Type ## URL Template Variables ## HTTP Headers ## Supporting Remote and Non-remote Installation
The first capture of this source. The page was already there, and this is what it said.
# Publishing Remote Servers
<Note>
The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues).
</Note>
The MCP Registry supports remote MCP servers via the `remotes` property in `server.json`:
```json server.json highlight={7-12} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.example/acme-analytics",
"title": "ACME Analytics",
"description": "Real-time business intelligence and reporting platform",
"version": "2.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://analytics.example.com/mcp"
}
]
}
```
A remote server **MUST** be publicly accessible at its specified URL.
## Transport Type
Remote servers should use the Streamable HTTP transport. The SSE transport is [deprecated](/specification/draft/deprecated), so publish an `"sse"` remote only to support existing clients. Remote servers can also support both transports simultaneously at different URLs.
Specify the transport by setting the `type` property of the `remotes` entry to either `"streamable-http"` or `"sse"`:
```json server.json highlight={9,13} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.example/acme-analytics",
"title": "ACME Analytics",
"description": "Real-time business intelligence and reporting platform",
"version": "2.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://analytics.example.com/mcp"
},
{
"type": "sse",
"url": "https://analytics.example.com/sse"
}
]
}
```
## URL Template Variables
Remote servers can define URL template variables using `{curly_braces}` notation. This enables multi-tenant deployments where a single server definition can support multiple endpoints with configurable values:
```json server.json highlight={10-17} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.example/acme-analytics",
"title": "ACME Analytics",
"description": "Real-time business intelligence and reporting platform",
"version": "2.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://{tenant_id}.analytics.example.com/mcp",
"variables": {
"tenant_id": {
"description": "Your tenant identifier (e.g., 'us-cell1', 'emea-cell1')",
"isRequired": true
}
}
}
]
}
```
When configuring this server, users provide their `tenant_id` value, and the URL template gets resolved to the appropriate endpoint (e.g., `https://us-cell1.analytics.example.com/mcp`).
Variables support additional properties like `default`, `choices`, and `isSecret`:
```json server.json highlight={12-22} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.example/multi-region-mcp",
"title": "Multi-Region MCP",
"description": "MCP server with regional endpoints",
"version": "1.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://api.example.com/{region}/mcp",
"variables": {
"region": {
"description": "Deployment region",
"isRequired": true,
"choices": [
"us-east-1",
"eu-west-1",
"ap-southeast-1"
],
"default": "us-east-1"
}
}
}
]
}
```
## HTTP Headers
MCP clients can be instructed to send specific HTTP headers by adding the `headers` property to the `remotes` entry:
```json server.json highlight={11-18} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.example/acme-analytics",
"title": "ACME Analytics",
"description": "Real-time business intelligence and reporting platform",
"version": "2.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://analytics.example.com/mcp",
"headers": [
{
"name": "X-API-Key",
"description": "API key for authentication",
"isRequired": true,
"isSecret": true
}
]
}
]
}
```
## Supporting Remote and Non-remote Installation
The `remotes` property can coexist with the `packages` property in `server.json` in order to allow MCP host applications to choose the preferred method of installation.
```json server.json highlight={7-22} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.username/email-integration-mcp",
"title": "Email Integration",
"description": "Send emails and manage email accounts",
"version": "1.0.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://email.example.com/mcp"
}
],
"packages": [
{
"registryType": "npm",
"identifier": "@example/email-integration-mcp",
"version": "1.0.0",
"transport": {
"type": "stdio"
}
}
]
}
```
registry/terms-of-service First recorded · 49 lines, first recorded
# Official MCP Registry Terms of Service ## Overview ## For All Users ## For MCP Developers
The first capture of this source. The page was already there, and this is what it said.
# Official MCP Registry Terms of Service <Note> The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues). </Note> **Effective date: 2025-09-02** ## Overview These terms (“Terms”) govern your access to and use of the official MCP Registry (the service hosted at [https://registry.modelcontextprotocol.io/](https://registry.modelcontextprotocol.io/) or a successor location) (“Registry”), including submissions or publications of MCP servers, references to MCP servers or to data about such servers and/or their developers (“Registry Data”), and related conduct. The Registry is intended to be a centralized repository of MCP servers developed by community members to facilitate easy access by AI applications. These terms are governed by the laws of the State of California. ## For All Users 1. No Warranties. The Registry is provided “as is” with no warranties of any kind. That means we don't guarantee the accuracy, completeness, safety, durability, or availability of the Registry, servers included in the registry, or Registry Data. In short, we’re also not responsible for any MCP servers or Registry Data, and we highly recommend that you evaluate each MCP server and its suitability for your intended use case(s) before deciding whether to use it. 2. Access and Use Requirements. To access or use the Registry, you must: 1. Be at least 18 years old. 2. Use the Registry, MCP servers in the Registry, and Registry Data only in ways that are legal under the applicable laws of the United States or other countries including the country in which you are a resident or from which you access and use the Registry, and not be barred from accessing or using the Registry under such laws. You will comply with all applicable law, regulation, and third party rights (including, without limitation, laws regarding the import or export of data or software, privacy, intellectual property, and local laws). You will not use the Registry, MCP servers, or Registry Data to encourage or promote illegal activity or the violation of third party rights or terms of service. 3. Log in via method(s) approved by the Registry maintainers, which may involve using applications or other software owned by third parties. 3. Entity Use. If you are accessing or using the Registry on behalf of an entity, you represent and warrant that you have authority to bind that entity to these Terms. By accepting these Terms, you are doing so on behalf of that entity (and all references to “you” in these Terms refer to that entity). 4. Account Information. In order to access or use the Registry, you may be required to provide certain information (such as identification or contact details) as part of a registration process or in connection with your access or use of the Registry or MCP servers therein. Any information you give must be accurate and up-to-date, and you agree to inform us promptly of any updates. You understand that your use of the Registry may be monitored to ensure quality and verify your compliance with these Terms. 5. Feedback. You are under no obligation to provide feedback or suggestions. If you provide feedback or suggestions about the Registry or the Model Context Protocol, then we (and those we allow) may use such information without obligation to you. 6. Branding. Only use the term “Official MCP Registry” where it is clear it refers to the Registry, and does not imply affiliation, endorsement, or sponsorship. For example, you can permissibly say “Acme Inc. keeps its data up to date by automatically pulling data from the Official MCP Registry” or “This data comes from the Official MCP Registry,” but cannot say “This is the website for the Official MCP Registry,” “We’re the premier destination to view Official MCP Registry data,” or “We’ve partnered with the Official MCP Registry to provide this data.” 7. Modification. We may modify the Terms or any portion to, for example, reflect changes to the law or changes to the Model Context Protocol. We’ll post notice of modifications to the Terms to this website or a successor location. If you do not agree to the modified Terms, you should discontinue your access to and/or use of the Registry. Your continued access to and/or use of the Registry constitutes your acceptance of any modified Terms. 8. Additional Terms. Depending on your intended use case(s), you must also abide by applicable terms below. ## For MCP Developers 9. Prohibitions. By accessing and using the Registry, including by submitting MCP servers and/or Registry Data, you agree not to: 1. Share malicious or harmful content, such as malware, even in good faith or for research purposes, or perform any action with the intent of introducing any viruses, worms, defects, Trojan horses, malware, or any items of a destructive nature; 2. Defame, abuse, harass, stalk, or threaten others; 3. Interfere with or disrupt the Registry or any associated servers or networks; 4. Submit data with the intent of confusing or misleading others, including but not limited to via spam, posting off-topic marketing content, posting MCP servers in a way that falsely implies affiliation with or endorsement by a third party, or repeatedly posting the same or similar MCP servers under different names; 5. Promote or facilitate unlawful online gambling or disruptive commercial messages or advertisements; 6. Use the Registry for any activities where the use or failure of the Registry could lead to death, personal injury, or environmental damage; 7. Use the Registry to process or store any data that is subject to the International Traffic in Arms Regulations maintained by the U.S. Department of State. 10. License. You agree that metadata about MCP servers you submit (e.g., schema name and description, URLs, identifiers) and other Registry Data is intended to be public, and will be dedicated to the public domain under [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/). By submitting such data, you agree that you have the legal right to make this dedication (i.e., you own the copyright to these submissions or have permission from the copyright owner(s) to do so) and intend to do so. You understand that this dedication is perpetual, irrevocable, and worldwide, and you waive any moral rights you may have in your contributions to the fullest extent permitted by law. This dedication applies only to Registry Data and not to packages in third party registries that you might point to. 11. Privacy and Publicity. You understand that any MCP server metadata you publish may be made public. This includes personal data such as your GitHub username, domain name, or details from your server description. Moreover, you understand that others may process personal information included in your MCP server metadata. For example, subregistries might enrich this data by adding how many stars your GitHub repository has, or perform automated security scanning on your code. By publishing a server, you agree that others may engage in this sort of processing, and you waive rights you might have in some jurisdictions to access, rectify, erase, restrict, or object to such processing.
registry/versioning First recorded · 164 lines, first recorded
# Versioning Published MCP Servers ## Version Format ## Best Practices ### Use Semantic Versioning ### Align Server Version with Package Version ### Align Server Version with Remote API Version ### Use Prerelease Versions for Registry-only Updates ## Aggregator Recommendations
The first capture of this source. The page was already there, and this is what it said.
# Versioning Published MCP Servers
<Note>
The MCP Registry is currently in preview. Breaking changes or data resets may occur before general availability. If you encounter any issues, please report them on [GitHub](https://github.com/modelcontextprotocol/registry/issues).
</Note>
MCP servers **MUST** define a version string in `server.json`. For example:
```json server.json highlight={6} theme={null}
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.username/email-integration-mcp",
"title": "Email Integration",
"description": "Send emails and manage email accounts",
"version": "1.0.0",
"packages": [
{
"registryType": "npm",
"identifier": "@username/email-integration-mcp",
"version": "1.0.0",
"transport": {
"type": "stdio"
}
}
]
}
```
The version string **MUST** be unique for each publication of the server. Once published, the version string (and other metadata) cannot be changed.
## Version Format
The MCP Registry recommends [semantic versioning](https://semver.org/), but supports any version string format. When a server is published, the MCP Registry will attempt to parse its version as a semantic version string for sorting purposes, and will mark the version as "latest" if appropriate. If parsing fails, the version will always be marked as "latest".
<Warning>
If a server uses semantic version strings but publishes a new version that does *not* conform to semantic versioning, the new version will be marked as "latest" even if it would otherwise be sorted before the semantic version strings.
</Warning>
As an error prevention mechanism, the MCP Registry prohibits version strings that appear to refer to ranges of versions.
| Example | Type | Guidance |
| -------------- | ------------------- | ------------------------------ |
| `1.0.0` | semantic version | **Recommended** |
| `2.1.3-alpha` | semantic prerelease | **Recommended** |
| `1.0.0-beta.1` | semantic prerelease | **Recommended** |
| `3.0.0-rc.2` | semantic prerelease | **Recommended** |
| `2025.11.25` | semantic date | Recommended |
| `2025.6.18` | semantic date | Recommended **(⚠️Caution!⚠️)** |
| `2025.06.18` | non-semantic date | Allowed **(⚠️Caution!⚠️)** |
| `2025-06-18` | non-semantic date | Allowed |
| `v1.0` | prefixed version | Allowed |
| `^1.2.3` | version range | Prohibited |
| `~1.2.3` | version range | Prohibited |
| `>=1.2.3` | version range | Prohibited |
| `<=1.2.3` | version range | Prohibited |
| `>1.2.3` | version range | Prohibited |
| `<1.2.3` | version range | Prohibited |
| `1.x` | version range | Prohibited |
| `1.2.*` | version range | Prohibited |
| `1 - 2` | version range | Prohibited |
| `1.2 \|\| 1.3` | version range | Prohibited |
## Best Practices
### Use Semantic Versioning
Use [semantic versioning](https://semver.org/) for version strings.
### Align Server Version with Package Version
For local servers, align the server version with the underlying package version in order to prevent confusion:
```json server.json highlight={2,7} theme={null}
{
"version": "1.2.3",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/my-server",
"version": "1.2.3",
"transport": {
"type": "stdio"
}
}
]
}
```
If there are multiple underlying packages, use the server version to indicate the overall release version:
```json server.json highlight={2,7,15} theme={null}
{
"version": "1.3.0",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/my-server",
"version": "1.3.0",
"transport": {
"type": "stdio"
}
},
{
"registryType": "nuget",
"identifier": "MyUsername.MyServer",
"version": "1.0.0",
"transport": {
"type": "stdio"
}
}
]
}
```
### Align Server Version with Remote API Version
For remote servers with an API version, the server version should align with the API version:
```json server.json highlight={2,6} theme={null}
{
"version": "2.1.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://api.myservice.com/mcp/v2.1"
}
]
}
```
### Use Prerelease Versions for Registry-only Updates
If you anticipate publishing a server multiple times *without* changing the underlying package or remote URL — for example, to update other parts of the metadata — use semantic prerelease versions:
```json server.json highlight={2} theme={null}
{
"version": "1.2.3-1",
"packages": [
{
"registryType": "npm",
"identifier": "@my-username/my-server",
"version": "1.2.3",
"transport": {
"type": "stdio"
}
}
]
}
```
<Warning>
According to semantic versioning, prerelease versions such as `1.2.3-1` are sorted before regular semantic versions such as `1.2.3`. Therefore, if you publish a prerelease version *after* its corresponding regular version, the prerelease version will **not** be marked as "latest".
</Warning>
## Aggregator Recommendations
MCP Registry aggregators **SHOULD**:
1. Attempt to interpret versions as semantic versions when possible
2. Use the following version comparison rules:
* If one version is marked as "latest", treat it as later
* If both versions are valid semantic versions, use semantic versioning comparison rules
* If neither versions are valid semantic versions, compare published timestamp
* If one version is a valid semantic version and the other is not, treat the semantic version as later
seps/1024-mcp-client-security-requirements-for-local-server- First recorded · 132 lines, first recorded
# SEP-1024: MCP Client Security Requirements for Local Server Installation ## Abstract ## Motivation ## Specification ### Client Security Requirements #### Pre-Configuration Consent ## Rationale ### Design Decisions ## Backward Compatibility ## Reference Implementation ## Security Implications ### Security Benefits ### Residual Risks ### Risk Mitigation
The first capture of this source. The page was already there, and this is what it said.
# SEP-1024: MCP Client Security Requirements for Local Server Installation
> MCP Client Security Requirements for Local Server Installation
<div className="flex items-center gap-2 mb-4">
<Badge color="green" shape="pill">
Final
</Badge>
<Badge color="gray" shape="pill">
Standards Track
</Badge>
</div>
<Note>
This SEP has reached Final status and is preserved as a historical record of
the design as accepted. Changes made to the protocol after finalization are
not reflected here. Refer to the [current
specification](/specification/latest) and its changelog for authoritative
requirements.
</Note>
| Field | Value |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP** | 1024 |
| **Title** | MCP Client Security Requirements for Local Server Installation |
| **Status** | Final |
| **Type** | Standards Track |
| **Created** | 2025-07-22 |
| **Author(s)** | Den Delimarsky |
| **Sponsor** | None |
| **PR** | [#1024](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1024) |
***
## Abstract
This SEP addresses critical security vulnerabilities in MCP client implementations that support one-click installation of local MCP servers. The current MCP specification lacks explicit security requirements for client-side installation flows, allowing malicious actors to execute arbitrary commands on user systems through crafted MCP server configurations distributed via links or social engineering.
This proposal establishes a best practice for MCP clients, requiring explicit user consent before executing any local server installation commands and complete command transparency.
## Motivation
The existing MCP specification does not address client-side security concerns related to streamlined ("one-click") local server configuration. Current MCP clients that implement these configuration experiences create significant attack vectors:
1. **Silent Command Execution**: MCP clients can automatically execute embedded commands without user review or consent when installing local servers via one-click flows.
2. **Lack of Visibility**: Users have no insight into what commands are being executed on their systems, creating opportunities for data exfiltration, system compromise, and privilege escalation.
3. **Social Engineering Vulnerabilities**: Users become comfortable executing commands labeled as "MCP servers" without proper scrutiny, making them susceptible to malicious configurations.
4. **Arbitrary Code Execution**: Attackers can embed harmful commands in MCP server configurations and distribute them through legitimate channels (repositories, documentation, social media).
Visual Studio Code [addressed this](https://den.dev/blog/vs-code-mcp-install-consent/) by implementing consent dialogs. Similarly, Cursor also supports a consent dialog for one-click local MCP server installation.
Without explicit security requirements in the specification, MCP client implementers may unknowingly create vulnerable installation flows, putting end users at risk of system compromise.
## Specification
### Client Security Requirements
MCP clients that support one-click local MCP server configuration **MUST** implement the following security controls:
#### Pre-Configuration Consent
Before executing any command to install or configure a local MCP server, the MCP client **MUST**:
1. Display a clear consent dialog that shows:
* The exact command that will be executed, without truncation
* All arguments and parameters
* A clear warning that this operation may be potentially dangerous
2. Require explicit user approval through an affirmative action (button click, checkbox, etc.)
3. Provide an option for users to cancel the installation
4. Not proceed with installation if consent is denied or not provided
## Rationale
### Design Decisions
**Mandatory Consent Dialogs**: The requirement for explicit consent dialogs balances security with usability. While this adds friction to the MCP server configuration process, it prevents potential breaches from silent command execution.
## Backward Compatibility
This SEP introduces new **requirements** for MCP client implementations but does not change the core MCP protocol or wire format.
**Impact Assessment:**
* **Low Impact**: Existing MCP servers and the core protocol remain unchanged
* **Client Implementation Required**: MCP clients must update their local server installation flows to comply with new security requirements
* **User Experience Changes**: Users will see consent dialogs where none existed before
**Migration Path:**
1. MCP clients can implement these changes in new versions without breaking existing functionality
2. Existing installed MCP servers continue to work normally
3. Only new installation flows require the consent mechanisms
No protocol-level backward compatibility issues exist, as this SEP addresses client behavior rather than the MCP wire protocol.
## Reference Implementation
N/A
## Security Implications
### Security Benefits
This SEP directly addresses:
* **Arbitrary Code Execution**: Prevents silent execution of malicious commands
* **Social Engineering**: Forces users to consciously review commands before execution
* **Supply Chain Attacks**: Creates visibility into MCP server installation commands
* **Privilege Escalation**: Users can identify and reject commands requesting elevated privileges
### Residual Risks
Even with these controls, risks remain:
* **User Override**: Users may approve malicious commands despite warnings
* **Sophisticated Obfuscation**: Advanced attackers may craft commands that appear legitimate
* **Implementation Gaps**: Clients may implement controls incorrectly
### Risk Mitigation
These residual risks are addressed through:
* Clear warning language in consent dialogs
* Recommendation for additional security layers (sandboxing, signatures)
* Ongoing security research and community awareness
seps/1034--support-default-values-for-all-primitive-types-in First recorded · 170 lines, first recorded
# SEP-1034: Support default values for all primitive types in elicitation schemas ## Abstract ## Motivation ### Real-World Example ### Implementation ## Specification ### Schema Changes ### Behavior ## Rationale ### Alternatives Considered ## Backwards Compatibility ## Security Implications
The first capture of this source. The page was already there, and this is what it said.
# SEP-1034: Support default values for all primitive types in elicitation schemas
> Support default values for all primitive types in elicitation schemas
<div className="flex items-center gap-2 mb-4">
<Badge color="green" shape="pill">
Final
</Badge>
<Badge color="gray" shape="pill">
Standards Track
</Badge>
</div>
<Note>
This SEP has reached Final status and is preserved as a historical record of
the design as accepted. Changes made to the protocol after finalization are
not reflected here. Refer to the [current
specification](/specification/latest) and its changelog for authoritative
requirements.
</Note>
| Field | Value |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP** | 1034 |
| **Title** | Support default values for all primitive types in elicitation schemas |
| **Status** | Final |
| **Type** | Standards Track |
| **Created** | 2025-07-22 |
| **Author(s)** | Tapan Chugh (chugh.tapan[@gmail](https://github.com/gmail).com) |
| **Sponsor** | None |
| **PR** | [#1034](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1034) |
***
## Abstract
This SEP recommends adding support for default values to all primitive types in the MCP elicitation schema (StringSchema, NumberSchema, and EnumSchema), extending the existing support that only covers BooleanSchema.
## Motivation
Elicitations in MCP offer a way to mitigate complex API designs: tools can request information on-demand rather than resorting to convoluted parameter handling. The challenge however is that users must manually enter obvious information that could be pre-populated for more natural interactions. Currently, only `BooleanSchema` supports default values in elicitation requests. This limitation prevents servers from providing sensible defaults for text inputs, numbers, and enum selections leading to more user overhead.
### Real-World Example
Consider implementing an email reply function. Without elicitation, the tool becomes unwieldy:
```python theme={null}
def reply_to_email_thread(
thread_id: str,
content: str,
recipient_list: List[str] = [],
cc_list: List[str] = []
) -> None:
# Ambiguity: Does empty list mean "no recipients" or "use defaults"?
# Complex logic needed to handle different combinations
```
With elicitation, the tool signature itself can be much simpler
```python theme={null}
def reply_to_email_thread(
thread_id: str,
content: Optional[str] = ""
) -> None:
# Code can lookup the participants from the original thread
# and prepare an elicitation request with the defaults setup
```
```typescript theme={null}
const response = await client.request("elicitation/create", {
message: "Configure email reply",
requestedSchema: {
type: "object",
properties: {
recipients: {
type: "string",
title: "Recipients",
default: "[email protected], [email protected]" // Pre-filled
},
cc: {
type: "string",
title: "CC",
default: "[email protected]" // Pre-filled
},
content: {
type: "string",
title: "Message"
default: "" // If provided in the tool above
}
}
}
});
```
### Implementation
A working implementation demonstrating clients require minimal changes to display defaults (\~10 lines of code):
* Implementation PR: [https://github.com/chughtapan/fast-agent/pull/2](https://github.com/chughtapan/fast-agent/pull/2)
* A demo with the above email reply workflow: [https://asciinema.org/a/X7aQZjT2B5jVwn9dJ9sqQVkOM](https://asciinema.org/a/X7aQZjT2B5jVwn9dJ9sqQVkOM)
## Specification
### Schema Changes
Extend the elicitation primitive schemas to include optional default values:
```typescript theme={null}
export interface StringSchema {
type: "string";
title?: string;
description?: string;
minLength?: number;
maxLength?: number;
format?: "email" | "uri" | "date" | "date-time";
default?: string; // NEW
}
export interface NumberSchema {
type: "number" | "integer";
title?: string;
description?: string;
minimum?: number;
maximum?: number;
default?: number; // NEW
}
export interface EnumSchema {
type: "string";
title?: string;
description?: string;
enum: string[];
enumNames?: string[];
default?: string; // NEW - must be one of enum values
}
// BooleanSchema already has default?: boolean
```
### Behavior
1. The `default` field is optional, maintaining full backward compatibility
2. Default values must match the schema type
3. For EnumSchema, the default must be one of the valid enum values
4. Clients that support defaults SHOULD pre-populate form fields. Clients that don't support defaults MAY ignore the field entirely.
## Rationale
1. The high-level rationale is to follow the precedent set by BooleanSchema rather than creating new mechanisms.
2. Making defaults optional ensures backward compatibility.
3. This maintains the high-level intuition of keeping the client implementation simple.
### Alternatives Considered
1. **Server-side Templates**: Servers could maintain templates separately, but this adds complexity
2. **New Request Type**: A separate request type for forms with defaults would fragment the API
3. **Required Defaults**: Making defaults required would break existing implementations
## Backwards Compatibility
This change is fully backward compatible with no breaking changes. Clients that don't understand defaults will ignore them, and existing elicitation requests continue to work unchanged. Clients can adopt default support at their own pace
## Security Implications
No new security concerns:
1. **No Sensitive Data**: The existing guidance against requesting sensitive information still applies
2. **Client Control**: Clients retain full control over what data is sent to servers
3. **User Visibility**: Default values are visible to users who can modify them before submission
seps/1036-url-mode-elicitation-for-secure-out-of-band-intera First recorded · 331 lines, first recorded
# SEP-1036: URL Mode Elicitation for secure out-of-band interactions ## Abstract ## Motivation ## Specification ### Overview ### Capabilities ### Form Elicitation Requests ### URL Elicitation Requests #### Example: OAuth Authorization Flow #### Response Actions #### Completion Notifications #### URL Elicitation Required Error ## Rationale ### Design Decisions ### Alternative Approaches Considered ### Community Feedback ## Backward Compatibility ### Migration Path # Reference Implementation ## Security Implications ### URL Security Requirements ### Trust Boundaries ### Identity Verification ### Implementation Requirements ### Relationship to Existing Security Measures
The first capture of this source. The page was already there, and this is what it said.
# SEP-1036: URL Mode Elicitation for secure out-of-band interactions
> URL Mode Elicitation for secure out-of-band interactions
<div className="flex items-center gap-2 mb-4">
<Badge color="green" shape="pill">
Final
</Badge>
<Badge color="gray" shape="pill">
Standards Track
</Badge>
</div>
<Note>
This SEP has reached Final status and is preserved as a historical record of
the design as accepted. Changes made to the protocol after finalization are
not reflected here. Refer to the [current
specification](/specification/latest) and its changelog for authoritative
requirements.
</Note>
| Field | Value |
| ------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **SEP** | 1036 |
| **Title** | URL Mode Elicitation for secure out-of-band interactions |
| **Status** | Final |
| **Type** | Standards Track |
| **Created** | 2025-07-22 |
| **Author(s)** | Nate Barbettini ([@nbarbettini](https://github.com/nbarbettini)) and Wils Dawson ([@wdawson](https://github.com/wdawson)) |
| **Sponsor** | None |
| **PR** | [#1036](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1036) |
***
## Abstract
This SEP introduces a new `url` mode for the existing elicitation client capability, enabling secure out-of-band interactions that bypass the MCP client. URL mode elicitation addresses sensitive use cases that form mode elicitation cannot, such as gathering sensitive credentials, performing OAuth flows for external (3rd-party) authorization, and handling payments, *without* exposing sensitive data to the MCP client. By directing users to trusted URLs in their browser, this mode maintains security boundaries while enabling rich integrations with third-party services.
## Motivation
The current MCP specification (2025-06-18) provides an elicitation mechanism for gathering non-sensitive information from users through structured, in-band requests (most commonly imagined as the MCP client rendering a form to collect data from the end-user). However, several critical use cases require interactions that must not pass through the MCP client:
1. Sensitive data collection: API keys, passwords, and other credentials must never transit through intermediary systems.
2. External authorization: MCP servers often need to access third-party APIs on behalf of users. The MCP authorization specification only covers client-to-server authorization, not server-to-third-party authorization. The [Security Best Practices](https://modelcontextprotocol.io/specification/2025-06-18/basic/security_best_practices) document explicitly forbids token passthrough, requiring a secure mechanism for external (3rd-party) OAuth flows. This was a particularly important motivating factor emerging from discussions in #234 and #284.
3. Payment and Subscription Flows: Financial transactions require PCI compliance and secure payment processing that cannot be achieved through in-band data collection.
Without a standardized mechanism for these interactions, MCP servers must resort to non-standard workarounds or insecure practices like requesting API keys through in-band, form-style elicitation. This SEP addresses these gaps by introducing a URL elicitation mode that leverages established web security patterns to handle sensitive interactions securely.
URL elicitation is fundamentally different from [MCP authorization](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization). URL elicitation is not for authorizing the MCP client's access to the MCP server (that's handled directly by MCP authorization). Instead, it's used when the MCP server needs to obtain sensitive information or third-party authorization on behalf of the user. The MCP client's bearer token remains unchanged, and the client's only responsibility is to provide the user with context about the elicitation URL the server wants them to open.
## Specification
### Overview
Elicitation is updated to support two modes:
* **Form mode** (in-band): Servers can request structured data from users with optional JSON schemas to validate responses (no change here, other than adding a name to the existing capability)
* **URL mode** (out-of-band): Servers can direct users to external URLs for sensitive interactions that must not pass through the MCP client
### Capabilities
Clients that support elicitation **MUST** declare the `elicitation` capability during initialization:
```json theme={null}
{
"capabilities": {
"elicitation": {
"form": {},
"url": {}
}
}
}
```
For backwards compatibility, an empty capabilities object is equivalent to declaring support for `form` mode only:
```jsonc theme={null}
{
"capabilities": {
"elicitation": {},
},
}
```
Clients declaring the `elicitation` capability **MUST** support at least one mode (`form` or `url`).
### Form Elicitation Requests
The only change from the existing specification is the addition of a `mode` field in the `elicitation/create` request:
```json theme={null}
{
"jsonrpc": "2.0",
"id": 1,
"method": "elicitation/create",
"params": {
"mode": "form", // New field
"message": "Please provide your GitHub username",
"requestedSchema": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
},
"required": ["name"]
}
}
}
```
### URL Elicitation Requests
URL elicitation requests **MUST** specify `mode: "url"` and include these parameters:
| Name | Type | Description |
| --------------- | ------ | ------------------------------------------------------------------ |
| `url` | string | The URL that the user should navigate to. |
| `elicitationId` | string | A unique identifier for the elicitation. |
| `message` | string | A human-readable message explaining why the interaction is needed. |
#### Example: OAuth Authorization Flow
```json theme={null}
{
"jsonrpc": "2.0",
"id": 3,
"method": "elicitation/create",
"params": {
"mode": "url",
"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://github.com/login/oauth/authorize?client_id=abc123&state=xyz789&scope=repo",
"message": "Please authorize access to your GitHub repositories to continue."
}
}
```
#### Response Actions
URL elicitation responses use the same three-action model as form elicitation:
```json theme={null}
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"action": "accept" // or "decline" or "cancel"
}
}
```
The response with `action: "accept"` indicates that the user has consented to the interaction. The interaction occurs out of band and the client is not aware of the outcome unless the server sends a completion notification.
#### Completion Notifications
Servers **SHOULD** send a `notifications/elicitation/complete` notification when an
out-of-band interaction started by URL mode elicitation is completed. This allows clients to react programmatically if appropriate.
* The notification **MUST** only be sent to the client that initiated the elicitation request.
* The notification **MUST** include the `elicitationId` established in the original `elicitation/create` request.
* Clients **MUST** ignore notifications referencing unknown or already-completed IDs.
* If a completion notification never arrives, clients **SHOULD** provide a manual way for the user to continue the interaction.
Clients **MAY** use the notification to automatically retry requests that received a URL elicitation required error, update the user interface, or otherwise continue an interaction. However, because delivery of the notification is not guaranteed, clients must not wait indefinitely for a notification from the server.
```json theme={null}
{
"jsonrpc": "2.0",
"method": "notifications/elicitation/complete",
"params": {
"elicitationId": "550e8400-e29b-41d4-a716-446655440000"
}
}
```
#### URL Elicitation Required Error
When a request cannot be processed until an elicitation is completed, the server **MAY** return a `URLElicitationRequiredError` (code `-32042`) to indicate that a URL mode elicitation is required. The server **MUST NOT** return this error except when URL mode elicitation is required by the user interaction.
```json theme={null}
{
"jsonrpc": "2.0",
"id": 2,
"error": {
"code": -32042,
"message": "This request requires more information.",
"data": {
"elicitations": [
{
"mode": "url",
"elicitationId": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...",
"message": "Authorization is required to access your Example Co files."
}
]
}
}
}
```
Any elicitations returned in the error **MUST** be URL mode elicitations and include an `elicitationId`.
Returning a `URLElicitationRequiredError` is equivalent to sending an `elicitation/create` request. The server may return an error (instead of sending a separate `elicitation/create` request) as an affordance to the client to make it clear that a particular elicitation is directly related to a failed client request.
The client must treat `URLElicitationRequiredError` responses as equivalent to `elicitation/create` requests. Clients may automatically retry the failed request after the elicitation is completed successfully, for example after receiving a completion notification.
## Rationale
### Design Decisions
**Why extend elicitation instead of creating a new mechanism?**
Initially, we considered creating a separate mechanism for out-of-band interactions (discussed in #475). However, after discussions with the MCP maintainers, we decided to extend the existing elicitation specification because:
1. Both mechanisms serve the same fundamental purpose: gathering information from users
2. Having two similar-but-separate mechanisms for the same purpose is confusing and error-prone
3. The `mode` parameter cleanly separates the two interaction patterns
**Why can't the client perform the interaction itself?**
It is tempting to suggest that the MCP client should perform the interaction itself, e.g. act as an OAuth client to a third-party authorization server. However, there are several reasons why this is not a good idea:
* If the MCP client obtains user tokens from a third-party authorization server, the MCP server becomes a [token passthrough](https://modelcontextprotocol.io/specification/2025-06-18/basic/security_best_practices#token-passthrough) server, which is explicitly forbidden.
* Similarly, for payment-type flows, the MCP client would need to perform PCI-compliant payment processing, which is not a desired requirement for MCP clients.
**Why doesn't the server block (wait) on the elicitation to complete?**
URL mode elicitation requests are asynchronous or "disconnected" flows by design, because the kinds of interactions they enable are inherently asynchronous. Payment flows, external authorization, etc. can take minutes or more to complete, and in some cases never complete at all (if abandoned by the end-user).
**Why disallow URLs in form mode?**
Being very explicit about when URLs can (and cannot) be sent in an elicitation request improves the client's security posture. By clearly stating in the spec that URLs are *only* allowed in the `url` field of a URL mode elicitation request, client implementers can implement UX patterns that are consistent with the security model. For example, a client could refuse to render a URL as a clickable hyperlink in a form mode elicitation request, reducing the likelihood of a user clicking on a malicious URL sent by a malicious server.
### Alternative Approaches Considered
1. **Token Passthrough**: Simply passing the MCP client's token to external services was rejected due to security concerns documented in the Security Best Practices. Having the MCP client obtain additional tokens and passing those to the MCP server was rejected for the same reason.
2. **OAuth-specific Capability**: Creating a capability specific to external (3rd-party) authorization with OAuth was considered, but rejected in favor of the more general URL mode elicitation approach that supports multiple use cases.
### Community Feedback
This proposal incorporates extensive community feedback from discussions in #475, #234, and #284, as well as the #auth-wg working group on Discord. The community identified the need for:
* Secure credential collection without client exposure
* External authorization patterns separate from MCP authorization
* Payment and subscription flow support
* Clear security boundaries and trust models
## Backward Compatibility
This SEP introduces the following breaking changes:
1. **Capability Declaration**: Clients must now specify which elicitation modes they support:
```json theme={null}
{
"capabilities": {
"elicitation": {
"form": {},
"url": {}
}
}
}
```
Previously, clients only declared `"elicitation": {}` without mode specification.
2. **Mode Parameter**: All `elicitation/create` requests must now include a `mode` parameter (`"form"` or `"url"`).
### Migration Path
To ease migration:
* Servers SHOULD check client capabilities before sending mode-specific requests
* Clients MAY initially support only form mode to maintain compatibility
* Existing form elicitation implementations continue to work with the addition of the mode parameter
# Reference Implementation
Client/server implementation in TypeScript: [feat/url-elicitation](https://github.com/modelcontextprotocol/typescript-sdk/compare/main...ArcadeAI:mcp-typescript-sdk:feat/url-elicitation)
Explainer video: [https://drive.google.com/file/d/1llCFS9wmkK\_RUgi5B-zHfUUgy-CNb0n0/view?usp=sharing](https://drive.google.com/file/d/1llCFS9wmkK_RUgi5B-zHfUUgy-CNb0n0/view?usp=sharing)
## Security Implications
This SEP introduces several security considerations:
### URL Security Requirements
1. **SSRF Prevention**: Clients must validate URLs to prevent Server-Side Request Forgery attacks
2. **Protocol Restrictions**: Only HTTPS URLs are allowed for URL elicitation
3. **Domain Validation**: Clients must clearly display target domains to users
### Trust Boundaries
URL elicitation explicitly creates clear trust boundaries:
* The MCP client never sees sensitive data obtained by the MCP server via URL elicitation
* The MCP server must independently verify user identity
Cut at 300 lines. The page has the rest.
seps/1046-support-oauth-client-credentials-flow-in-authoriza First recorded · 67 lines, first recorded
# SEP-1046: Support OAuth client credentials flow in authorization ## Abstract ### Motivation ### Specification ### Rationale ### Backward Compatibility ### Security Implications
The first capture of this source. The page was already there, and this is what it said.
# SEP-1046: Support OAuth client credentials flow in authorization
> Support OAuth client credentials flow in authorization
<div className="flex items-center gap-2 mb-4">
<Badge color="green" shape="pill">
Final
</Badge>
<Badge color="gray" shape="pill">
Standards Track
</Badge>
</div>
<Note>
This SEP has reached Final status and is preserved as a historical record of
the design as accepted. Changes made to the protocol after finalization are
not reflected here. Refer to the [current
specification](/specification/latest) and its changelog for authoritative
requirements.
</Note>
| Field | Value |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP** | 1046 |
| **Title** | Support OAuth client credentials flow in authorization |
| **Status** | Final |
| **Type** | Standards Track |
| **Created** | 2025-07-23 |
| **Author(s)** | Darin McAdams ([@D-McAdams](https://github.com/D-McAdams) ) |
| **Sponsor** | None |
| **PR** | [#1046](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1046) |
***
## Abstract
Recommends adding the OAuth client credentials flow to the authorization spec to enable machine-to-machine scenarios.
### Motivation
The original authorization spec mentioned the client credentials flow, but it was dropped in subsequent revisions. Therefore, the spec is currently silent on how to solve machine-to-machine scenarios where an end-user is unavailable for interactive authorization.
### Specification
The authorization spec would be amended to list the OAuth client credentials flow as being allowed. Adhering to the patterns established by OAuth 2.1, the specification would RECOMMEND the use of asymmetric methods defined in RFC 753 (JWT Assertions), but also allow client secrets.
As guidance to implementors, the spec overview would also be updated to describe the different flows and when each is applicable. In addition, to address a common question, the spec would be updated to indicate that implementors may implement other authorization scenarios beyond what's defined; emphasizing that the specification defines the baseline requirements.
### Rationale
To maximize interoperability (and minimize SDK complexity), this change would intentionally constrain the client credentials flow to two options:
1. JWT Assertions as per RFC 7523 (RECOMMENDED)
2. Client Secrets via HTTP Basic authentication (Allowed for maximum compatibility with existing systems)
Other options, such as mTLS, are not included.
While the spec encourages the use of RFC 7523 (JWT Assertions), it does not yet specify how to populate the JWT contents nor how to discover the client's JWKS URI to validate the JWT. In future iterations of the spec, it will be beneficial to do so. However, this was currently left unspecified pending maturity of other RFCs that can define these profiles. The other RFCs include [WIMSE Headless JWT Authentication](https://www.ietf.org/archive/id/draft-levy-wimse-headless-jwt-authentication-01.html) (for specifying JWT contents) and [Client ID Metadata](https://datatracker.ietf.org/doc/draft-parecki-oauth-client-id-metadata-document/) (for specifying the JWKS URI). This revision intentionally leaves extensibility for these future profiles. As a practical matter, this means implementers needing to ship solutions ASAP will most likely use client secrets which are widely supported today, whereas the JWT Assertion pattern represents the longer-term direction.
### Backward Compatibility
This change is fully backward compatible. It introduces a new authorization flow, but does not alter the existing flows.
### Security Implications
The specification refers to the existing OAuth security guidance.