A REST Profile for the Model Context Protocol — Draft Proposal

Version: 0.1.0 | Status: Draft Proposal


Abstract

The Model Context Protocol (MCP) defines how AI models connect to external services. MCP currently supports two transports: stdio for local servers, and Streamable HTTP for remote servers using JSON-RPC over HTTP. This document proposes a third transport option: a REST profile that allows any service with an existing REST API to become MCP-compatible by publishing an OpenAPI specification at a well-known URL.

The REST profile does not replace the existing MCP transports. It is designed for the common case — remote services that authenticate with OAuth and expose request-response endpoints — where the full JSON-RPC transport is unnecessary overhead. Services that need bidirectional communication, server-initiated requests, or stateful sessions should continue to use the Streamable HTTP transport.


1. Motivation

MCP’s architecture is inherently modular. Capabilities are negotiated at initialization, and servers only implement what they need. But the transport layer currently requires every server to speak JSON-RPC, even when the server’s functionality maps directly to standard REST endpoints.

Hundreds of thousands of services already have REST APIs, OpenAPI specifications, and OAuth 2.0 support. For these services, the gap between “has an API” and “supports MCP” is a full JSON-RPC implementation, a new deployment, and a new codebase to maintain. A REST profile closes that gap: the same service becomes MCP-compatible by adding a single YAML file at a well-known URL.

This isn’t a theoretical problem. The MCP meme has spread far faster than MCP server implementations. Every AI platform supports MCP. Every developer knows the term. Yet the number of services that have actually shipped MCP servers remains small. A REST profile would unlock the long tail of services that will never build a dedicated JSON-RPC server but would happily expose their existing API.

2. Relationship to the MCP Specification

This profile maps MCP’s existing concepts onto REST and OpenAPI equivalents. The semantics are identical — only the wire format changes.

MCP ConceptREST Profile Equivalent
Transport (JSON-RPC over HTTP)Standard HTTP (REST calls)
tools/list discoveryOpenAPI spec at /.well-known/mcp.yaml
Tool name + inputSchemaoperationId + OpenAPI parameter/request schemas
Tool resultHTTP response body
OAuth 2.0 + PKCEIdentical — same auth model
Dynamic Client RegistrationIdentical — same RFC 7591 support
Capability negotiationImplicit in the OpenAPI document

Features that require bidirectional communication are outside the scope of this profile:

  • Sampling — Server-initiated LLM completion requests (requires server→client messages)
  • Prompts — User-controlled prompt templates (requires a discovery protocol beyond static files)
  • Resource subscriptions — Real-time change notifications (requires server push)

Services that need these features should use the Streamable HTTP transport. The REST profile covers the common case: AI clients discovering and invoking tools on remote services with user-scoped authentication.

3. 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 conforms to the MCP REST profile if it satisfies all requirements in Sections 4 through 7.

4. Discovery

4.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).

This follows the same well-known URI pattern that MCP already uses for OAuth discovery (/.well-known/oauth-authorization-server).

4.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.

4.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

5. Tool Definitions

5.1 Mapping to MCP Tools

In the standard MCP protocol, tools are defined as {name, description, inputSchema} objects and discovered via the tools/list JSON-RPC method. In the REST profile, tools map to OpenAPI path operations:

MCP Tool FieldOpenAPI Equivalent
nameoperationId
descriptiondescription field on the operation
inputSchemaCombined parameters + requestBody schema

Each path operation in the manifest represents one MCP tool. AI clients read the manifest to build their tool list, exactly as they would call tools/list in the standard protocol.

5.2 Required Fields

Every tool endpoint MUST include:

  • operationId — A unique, short, descriptive identifier (e.g., search-tasks, 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.

5.3 Writing Descriptions for AI Consumers

This is the key difference between a standard OpenAPI spec and an MCP-compatible one. Tool descriptions 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.

5.4 Parameter and Response 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.

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.

6. Authentication

6.1 OAuth 2.0

The REST profile uses the same authentication model as MCP’s Streamable HTTP transport: OAuth 2.0 with PKCE.

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

6.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.

This is identical to MCP’s existing security principle that servers must not gain ambient authority beyond what the user explicitly grants.

6.3 Token Handling

AI host applications are responsible for initiating the OAuth flow, obtaining user consent, storing and refreshing access tokens, and including the access token in the Authorization header of all requests:

Authorization: Bearer {access_token}

6.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. MCP already addresses this challenge.

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.
  • Dynamic Client Registration (RFC 7591) — The service’s authorization server accepts registration requests from unknown clients at runtime. This is already recommended by the MCP specification.
  • Pre-registered client IDs (fallback) — The service publishes documentation where AI platform developers can manually register and obtain a client_id.

7. HTTP Conventions

7.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.

7.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.

7.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.

7.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. This aligns with MCP’s existing use of SSE in the Streamable HTTP transport.

Streaming is OPTIONAL. Most tool endpoints will use standard request-response.

8. Example Manifest

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.

  /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.
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

9. Adoption Path

If your service already has a REST API with an OpenAPI specification and OAuth 2.0 support, conforming to this profile requires minimal additional work:

RequirementYou likely already haveWhat to add
REST APIYesNothing
OpenAPI specProbablyPublish at /.well-known/mcp.yaml
OAuth 2.0 + PKCEProbablyAdd PKCE if not already supported
AI-optimised descriptionsNoRewrite operationId, summary, and description fields for AI consumers

That’s the gap. MCP compatibility goes from "build a new JSON-RPC server" to "add a well-known URL and improve your descriptions."

10. What This Profile Does Not Cover

The following MCP features require bidirectional communication and are outside the scope of this profile. Services that need them should use the Streamable HTTP transport:

  • Sampling — Server-initiated LLM completion requests. The server asks the client’s LLM for help while processing a request. Requires server→client messaging.
  • Prompts — User-controlled prompt templates that servers expose as slash commands. Requires a dynamic discovery protocol.
  • Resource subscriptions — Clients subscribe to change notifications on specific resources. Requires server push.
  • Server-initiated notifications — The server pushes updates to the client without being asked. Requires a persistent connection.

The REST profile is deliberately limited in scope. It covers the overwhelmingly common case — AI clients discovering and calling tools on remote services with user-scoped authentication — and defers everything else to MCP’s existing transports. This is a feature, not a limitation: the simplicity is what makes it possible for hundreds of thousands of existing REST APIs to participate in the MCP ecosystem without building anything new.


References

  • Model Context Protocol Specification (2025-03-26)
  • 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
  • RFC 8615 — Well-Known URIs