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 Authorization header 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:

  1. 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.
  2. 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).
  3. 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) and limit (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:

RequirementWhat to doTypical effort
Well-known manifestServe your OpenAPI spec (or a curated subset) at /.well-known/mcp.yamlA single route returning a static file
AI-oriented descriptionsReview and rewrite operationId, summary, and description fields so an AI model can understand when and how to use each endpointEditing existing documentation
PKCE supportEnsure your OAuth 2.0 Authorization Code flow supports the PKCE extensionMinor if using a standard OAuth library; many already support it
Plain-language error messagesEnsure error responses include a message field readable by an AI modelLikely 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