Model Context Protocol (REST Edition) — Draft Spec
Version: 0.1.0
Status: Draft
Abstract
The Model Context Protocol (MCP*) defines a standard way for AI models to discover, authenticate with, and invoke actions on third-party services. It is built entirely on existing web standards: REST, OpenAPI 3.x, OAuth 2.0, and HTTP.
Any service with a REST API can become MCP*-compatible by publishing an OpenAPI specification at a well-known URL and supporting OAuth 2.0 for user-scoped authentication.
1. Overview
MCP enables AI applications to:
- Discover what a service can do by reading a standard OpenAPI specification.
- Authenticate as a specific user via OAuth 2.0, inheriting that user's permissions.
- Invoke actions by calling the service's existing REST endpoints.
MCP* does not introduce a new transport, serialisation format, or session model. It is a set of conventions for exposing REST APIs to AI model consumers.
2. Conformance
The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in RFC 2119.
A service is MCP*-conformant if it satisfies all requirements in Sections 3 through 6.
3. Discovery
3.1 Manifest Location
A conformant service MUST publish an OpenAPI 3.x specification at the following well-known URI:
GET /.well-known/mcp.yaml
The response MUST have a Content-Type of application/yaml or application/json (if the service prefers to publish as mcp.json).
3.2 Manifest Content
The manifest MUST be a valid OpenAPI 3.1.0 (or later) document.
The manifest MAY be the service's complete OpenAPI specification, or it MAY be a curated subset containing only the endpoints intended for AI model consumption.
3.3 Metadata
The info object MUST include:
title— The human-readable name of the service.version— The version of the API.description— A plain-language description of the service and its capabilities. This description SHOULD be written with AI model consumers in mind.
The info object MAY include an x-mcp extension containing additional metadata:
info:
title: Notion
version: 1.0.0
description: Access and manage pages, databases, and content in Notion workspaces.
x-mcp:
logo: https://notion.so/logo.png
categories:
- productivity
- knowledge-management
4. Tool Definitions
4.1 Endpoints as Tools
Each path operation in the manifest represents a tool available to the AI model. The operationId field serves as the tool's identifier.
Every tool endpoint MUST include:
operationId— A unique, short, descriptive identifier (e.g.,search,create-page).summary— A one-line description of what the tool does.description— A detailed explanation of the tool's behaviour, including when to use it, what it returns, and any important constraints.
4.2 Writing Descriptions for AI Consumers
Tool descriptions serve a different purpose in MCP* than in traditional API documentation. They are the primary mechanism by which an AI model decides whether and how to use a tool.
Descriptions SHOULD:
- State what the tool does in concrete terms.
- Specify what the tool returns.
- Clarify when to use this tool versus other available tools.
- Note any side effects (e.g., "This will send an email to the specified recipient.").
Descriptions SHOULD NOT:
- Reference UI elements or user-facing features the AI cannot interact with.
- Assume familiarity with the service's internal concepts without explanation.
4.3 Parameter Schemas
Request parameters and bodies MUST be described using JSON Schema as defined by OpenAPI 3.1.0. Each property SHOULD include a description field.
4.4 Response Schemas
Response bodies SHOULD be described with JSON Schema. This allows AI models to understand the shape of returned data and use it in subsequent reasoning or tool calls.
5. Authentication
5.1 OAuth 2.0
A conformant service MUST support OAuth 2.0 Authorization Code flow with PKCE (Proof Key for Code Exchange).
OAuth configuration MUST be declared in the securitySchemes section of the OpenAPI manifest:
components:
securitySchemes:
oauth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://api.example.com/oauth/authorize
tokenUrl: https://api.example.com/oauth/token
scopes:
read: Read access to user content
write: Create and modify content
A global security requirement MUST be declared at the top level of the manifest:
security:
- oauth2:
- read
5.2 User-Scoped Access
All API calls made by an AI model on behalf of a user MUST use that user's OAuth access token. The service MUST enforce its existing permission model against the authenticated user. An AI model MUST NOT have access to any data or actions beyond what the authenticated user is authorised to access.
5.3 Token Handling
AI host applications are responsible for:
- Initiating the OAuth flow and obtaining user consent.
- Storing and refreshing access tokens.
- Including the access token in the
Authorizationheader of all requests:
Authorization: Bearer {access_token}
5.4 Client Registration
Traditional OAuth assumes a developer manually registers their application with a service and obtains a client_id in advance. AI clients connecting to arbitrary services cannot do this — they may encounter a service for the first time at runtime.
A conformant service MUST support at least one of the following client registration mechanisms:
- Client Metadata Documents (preferred) — The AI platform publishes a stable document at a well-known URL (e.g.,
https://anthropic.com/.well-known/oauth-client.json) describing its client identity, redirect URIs, and capabilities. The service fetches this document and uses it as the client record. This avoids per-session registration overhead and gives services a stable identity to associate with the AI client. - Dynamic Client Registration (RFC 7591) — The service's authorization server accepts registration requests from unknown clients at runtime. This is more flexible but creates operational complexity (many ephemeral client records).
- Pre-registered client IDs (fallback) — The service publishes documentation where AI platform developers can manually register and obtain a
client_id. This works but does not scale to the long tail of services.
Services SHOULD prefer Client Metadata Documents or Dynamic Client Registration to minimise friction for AI clients connecting for the first time.
6. HTTP Conventions
6.1 Error Responses
Error responses MUST use appropriate HTTP status codes and SHOULD return a JSON body with a human-readable message field:
{
"error": "not_found",
"message": "No page found with the given ID. It may have been deleted or you may not have access."
}
The message field SHOULD be written in plain language suitable for interpretation by an AI model.
6.2 Pagination
Endpoints that return collections SHOULD support cursor-based pagination using the following convention:
- Request parameter:
cursor(string, optional) andlimit(integer, optional). - Response field:
next_cursor(string or null). A null value indicates no further results.
6.3 Rate Limiting
Services SHOULD return 429 Too Many Requests with a Retry-After header when rate limits are exceeded. AI host applications MUST respect the Retry-After value before retrying.
6.4 Streaming (Optional)
Endpoints that return long-running or incremental results MAY use Server-Sent Events (SSE). This is indicated by the response content type text/event-stream in the OpenAPI manifest.
Streaming is OPTIONAL. Most tool endpoints will use standard request-response.
7. Example: Task Management Service
A complete manifest for a hypothetical task management service:
openapi: 3.1.0
info:
title: Acme Tasks
version: 2.0.0
description: |
Manage tasks and projects in Acme Tasks.
Supports creating, searching, updating, and completing tasks
within the authenticated user's workspace.
x-mcp:
logo: https://acmetasks.com/logo.png
categories:
- project-management
servers:
- url: https://api.acmetasks.com
paths:
/v1/tasks/search:
post:
operationId: search-tasks
summary: Search for tasks in the user's workspace.
description: |
Returns tasks matching the query string. Searches task titles,
descriptions, and comments. Results are ordered by relevance.
Only returns tasks visible to the authenticated user.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
query:
type: string
description: Free-text search query.
status:
type: string
enum: [open, in_progress, done]
description: Filter by task status. Omit to include all statuses.
limit:
type: integer
default: 20
description: Maximum number of results.
cursor:
type: string
description: Pagination cursor from a previous response.
required:
- query
responses:
'200':
description: A list of matching tasks.
content:
application/json:
schema:
type: object
properties:
results:
type: array
items:
$ref: '#/components/schemas/Task'
next_cursor:
type: string
nullable: true
/v1/tasks:
post:
operationId: create-task
summary: Create a new task.
description: |
Creates a task in the specified project. The task will be
assigned to the authenticated user by default unless an
assignee_id is provided.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
project_id:
type: string
description: The project to create the task in.
title:
type: string
description: The task title.
description:
type: string
description: Detailed task description. Supports Markdown.
assignee_id:
type: string
description: User ID to assign the task to. Defaults to the authenticated user.
due_date:
type: string
format: date
description: Due date in YYYY-MM-DD format.
required:
- project_id
- title
responses:
'201':
description: The created task.
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
/v1/tasks/{task_id}/complete:
post:
operationId: complete-task
summary: Mark a task as done.
description: |
Sets the task's status to done and records the completion
timestamp. This action cannot be undone via this endpoint;
use update-task to reopen a task if needed.
parameters:
- name: task_id
in: path
required: true
schema:
type: string
responses:
'200':
description: The completed task.
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
components:
schemas:
Task:
type: object
properties:
id:
type: string
title:
type: string
description:
type: string
status:
type: string
enum: [open, in_progress, done]
assignee_id:
type: string
project_id:
type: string
due_date:
type: string
format: date
nullable: true
completed_at:
type: string
format: date-time
nullable: true
created_at:
type: string
format: date-time
securitySchemes:
oauth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://acmetasks.com/oauth/authorize
tokenUrl: https://acmetasks.com/oauth/token
scopes:
read: Read tasks and projects
write: Create and modify tasks
security:
- oauth2:
- read
- write
8. Adopting MCP* with an Existing REST API
If your service already has a REST API with an OpenAPI specification and OAuth 2.0 support, the following table summarises what is required for MCP* conformance beyond your current implementation:
| Requirement | What to do | Typical effort |
|---|---|---|
| Well-known manifest | Serve your OpenAPI spec (or a curated subset) at /.well-known/mcp.yaml | A single route returning a static file |
| AI-oriented descriptions | Review and rewrite operationId, summary, and description fields so an AI model can understand when and how to use each endpoint | Editing existing documentation |
| PKCE support | Ensure your OAuth 2.0 Authorization Code flow supports the PKCE extension | Minor if using a standard OAuth library; many already support it |
| Plain-language error messages | Ensure error responses include a message field readable by an AI model | Likely already the case for most APIs |
If your service does not yet have OAuth 2.0 or an OpenAPI specification, those are the prerequisites to address first. Both are widely documented standards with mature tooling in every major language and framework.
References
- OpenAPI Specification 3.1.0
- RFC 6749 — The OAuth 2.0 Authorization Framework
- RFC 7636 — Proof Key for Code Exchange (PKCE)
- RFC 7591 — OAuth 2.0 Dynamic Client Registration Protocol
- RFC 2119 — Key Words for Use in RFCs
- Server-Sent Events — HTML Living Standard
- Well-Known URIs — RFC 8615