Back to all articles
Model Context Protocol

Best Practices for Mapping REST APIs to MCP Tools

February 26, 2026

The Model Context Protocol (MCP) gives AI agents a standardized way to discover and call your APIs as tools. Instead of crafting custom integrations for every LLM, you define your API once and MCP handles the rest -- agents can browse available operations, understand their parameters, and invoke them with structured inputs and outputs.

But REST APIs and MCP tools come from different paradigms. REST is resource-oriented with URLs, HTTP methods, headers, and status codes. MCP tools are function-oriented with names, descriptions, and parameter schemas. Getting the mapping right determines whether an AI agent can use your API effectively or stumbles through confusing tool names and ambiguous parameters.

This guide covers the practical patterns for turning REST endpoints into well-structured MCP tools that AI agents can actually work with.

How MCP Tools Map to REST Endpoints

Each MCP tool corresponds to a single API operation. When you generate MCP tools from an OpenAPI spec, the mapping works like this:

OpenAPI FieldMCP Tool Field
operationIdTool name
summary / descriptionTool description
Path, query, and body paramsTool inputSchema (JSON Schema)
Response schemaTool output

Here is an OpenAPI operation and its corresponding MCP tool definition side-by-side.

OpenAPI operation:

YAMLyaml
paths:
  /users/{userId}:
    get:
      operationId: getUserById
      summary: Get a user by their unique ID
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
          description: The unique identifier of the user
      responses:
        "200":
          description: The user object

Resulting MCP tool:

JSONjson
{
  "name": "getUserById",
  "description": "Get a user by their unique ID",
  "inputSchema": {
    "type": "object",
    "properties": {
      "userId": {
        "type": "string",
        "description": "The unique identifier of the user"
      }
    },
    "required": ["userId"]
  }
}

The mapping is direct. The quality of your MCP tools is a direct reflection of the quality of your OpenAPI spec.

Naming Conventions

AI agents use tool names to decide which tool to call. When an agent sees a list of 20 tools, it reads the names and descriptions to pick the right one. Clarity matters more than brevity.

Use action-oriented operationIds that describe exactly what the tool does:

  • listUsers -- not getUsers or users
  • createOrder -- not postOrder or newOrder
  • getInvoiceById -- not invoice or fetchInvoice
  • searchProducts -- not findProducts or queryProducts
  • deleteComment -- not removeComment or destroyComment

Follow a consistent verb pattern:

ActionVerbExample
List alllistlistOrders
Get onegetgetOrderById
CreatecreatecreateOrder
UpdateupdateupdateOrder
DeletedeletedeleteOrder
SearchsearchsearchOrders

Avoid generic names like handleRequest or processData. If an agent cannot determine what a tool does from its name alone, the name is too vague.

Parameter Mapping Best Practices

Parameters are where the mapping gets nuanced. REST APIs spread parameters across path segments, query strings, headers, and request bodies. MCP tools flatten everything into a single inputSchema object.

Path parameters become required tool parameters. A path like /orders/{orderId} produces a required orderId parameter. This is straightforward.

Query parameters become optional tool parameters. Filters, sorting, and pagination controls map to optional fields:

YAMLyaml
parameters:
  - name: status
    in: query
    required: false
    schema:
      type: string
      enum: [pending, shipped, delivered, cancelled]
    description: Filter orders by status

Notice the enum values. This is critical for MCP tools. When an AI agent sees enum: [pending, shipped, delivered, cancelled], it knows exactly which values are valid. Without the enum, the agent has to guess -- and it often guesses wrong.

Request body fields become tool parameters. For simple request bodies, flatten the fields into the tool's input schema:

YAMLyaml
requestBody:
  content:
    application/json:
      schema:
        type: object
        required: [name, email]
        properties:
          name:
            type: string
            description: The full name of the user
          email:
            type: string
            format: email
            description: The user's email address
          role:
            type: string
            enum: [admin, editor, viewer]
            description: The user's role in the organization

Each property -- name, email, role -- becomes a top-level parameter in the MCP tool's input schema. The required array carries over directly.

Write descriptions for AI agents, not just humans. Every parameter should have a description that explains what it does and what values are acceptable. Compare:

  • Bad: description: "The ID"
  • Good: description: "The unique identifier of the order, e.g. ord_12345"

Including examples in descriptions helps agents construct valid requests.

Handling Pagination

Pagination is one of the trickiest parts of the REST-to-MCP mapping. AI agents are not browsers -- they cannot easily navigate through pages of results, keep track of cursors, or know when to stop fetching.

There are three practical approaches:

1. Return all results for small datasets. If the collection is small (under a few hundred items), skip pagination entirely. A listTags endpoint that returns 50 tags does not need pagination. Simpler is better for AI agents.

2. Provide a limit parameter with a sensible default. For larger collections, let the agent control how many results it gets back:

YAMLyaml
parameters:
  - name: limit
    in: query
    schema:
      type: integer
      default: 20
      maximum: 100
    description: Maximum number of results to return (default 20, max 100)

A default of 20 keeps responses manageable. The agent can request more if needed.

3. Expose separate list and search tools. Instead of making the agent paginate through all orders to find one, give it a dedicated search tool:

  • listOrders -- returns recent orders with a limit parameter
  • searchOrders -- takes a query string and returns matching orders

This pattern works well because agents are good at describing what they are looking for but bad at iterating through pages.

Error Responses

When something goes wrong, the AI agent needs to understand what happened so it can retry, adjust parameters, or ask the user for help. Vague error messages like "Something went wrong" are useless to an agent.

Use the RFC 7807 Problem Details format for structured error responses:

JSONjson
{
  "type": "https://api.example.com/errors/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "The 'email' field must be a valid email address. Received: 'not-an-email'",
  "instance": "/users",
  "errors": [
    {
      "field": "email",
      "message": "Must be a valid email address",
      "received": "not-an-email"
    }
  ]
}

Key principles for agent-friendly errors:

  • Include the field name that caused the error
  • Show the invalid value the agent sent, so it can correct it
  • Explain what is expected -- format, range, or valid options
  • Use consistent error structure across all endpoints

When an agent receives a clear error like "The 'status' field must be one of: pending, shipped, delivered", it can fix the request and retry automatically.

What to Expose (and What Not To)

Not every REST endpoint should become an MCP tool. More tools means more confusion for the agent. Be deliberate about what you expose.

Good candidates for MCP tools:

  • CRUD operations on core resources (createUser, getUser, updateUser)
  • Search and filtering (searchOrders, listProductsByCategory)
  • Key business actions (submitInvoice, approveRequest)
  • Status checks (getOrderStatus, getSystemHealth)

Skip these:

  • Admin and internal endpoints -- agents should not manage users or configure system settings
  • Bulk operations -- endpoints that accept arrays of hundreds of items are hard for agents to construct correctly
  • File uploads -- binary data does not map to MCP tool parameters
  • Webhook management -- registering and managing webhooks is infrastructure, not something an agent needs
  • Deprecated endpoints -- do not expose tools that will stop working

A focused set of 10-15 well-designed tools is far more useful than 100 tools where the agent cannot figure out which one to call.

OpenAPI Best Practices for MCP

Your OpenAPI spec is the source of truth for your MCP tool definitions. Every gap in the spec becomes a gap in the tool. Here is a checklist:

Every operation needs an operationId. Without it, the tool has no name. Do not rely on auto-generated IDs -- they produce names like get_users_userId that agents struggle with.

Write descriptions for both humans and agents. The summary should be a short one-liner. The description can include details about behavior, edge cases, and relationships to other endpoints:

YAMLyaml
summary: Search for products
description: >
  Search the product catalog by keyword. Returns up to 50 results sorted by
  relevance. Use the 'category' parameter to narrow results to a specific
  product category. For browsing all products, use the listProducts operation
  instead.

Use examples in your schemas. Examples help agents understand what valid data looks like:

YAMLyaml
properties:
  email:
    type: string
    format: email
    example: "jane@example.com"
  amount:
    type: number
    minimum: 0
    example: 29.99

Mark required versus optional clearly. Agents need to know which parameters must be provided and which ones can be skipped. Always define the required array at the schema level.

Example: Mapping a Todo API

Here is a complete example showing an OpenAPI spec for a todo API and the resulting MCP tools.

OpenAPI spec:

JSONjson
{
  "openapi": "3.1.0",
  "info": {
    "title": "Todo API",
    "version": "1.0.0"
  },
  "paths": {
    "/todos": {
      "get": {
        "operationId": "listTodos",
        "summary": "List all todos",
        "description": "Returns all todo items, optionally filtered by completion status.",
        "parameters": [
          {
            "name": "completed",
            "in": "query",
            "schema": { "type": "boolean" },
            "description": "Filter by completion status. True for completed, false for incomplete."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": { "type": "integer", "default": 20, "maximum": 100 },
            "description": "Maximum number of todos to return (default 20, max 100)"
          }
        ]
      },
      "post": {
        "operationId": "createTodo",
        "summary": "Create a new todo",
        "description": "Creates a new todo item. The title is required.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["title"],
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "The title of the todo item",
                    "example": "Buy groceries"
                  },
                  "priority": {
                    "type": "string",
                    "enum": ["low", "medium", "high"],
                    "description": "Priority level of the todo"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/todos/{todoId}": {
      "get": {
        "operationId": "getTodoById",
        "summary": "Get a todo by ID",
        "parameters": [
          {
            "name": "todoId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "The unique identifier of the todo"
          }
        ]
      },
      "patch": {
        "operationId": "updateTodo",
        "summary": "Update a todo",
        "description": "Updates an existing todo item. Only include fields you want to change.",
        "parameters": [
          {
            "name": "todoId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "The unique identifier of the todo"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": { "type": "string" },
                  "completed": { "type": "boolean" },
                  "priority": {
                    "type": "string",
                    "enum": ["low", "medium", "high"]
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteTodo",
        "summary": "Delete a todo",
        "parameters": [
          {
            "name": "todoId",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "description": "The unique identifier of the todo to delete"
          }
        ]
      }
    }
  }
}

Resulting MCP tools:

Tool NameDescriptionRequired ParamsOptional Params
listTodosList all todos--completed, limit
createTodoCreate a new todotitlepriority
getTodoByIdGet a todo by IDtodoId--
updateTodoUpdate a todotodoIdtitle, completed, priority
deleteTodoDelete a todotodoId--

Five clean tools with clear names, descriptive parameters, and obvious required versus optional fields. An AI agent can look at this list and immediately understand what each tool does and how to call it.

Turn Your OpenAPI Spec into MCP Tools

You do not need to build the mapping layer yourself. If you have an OpenAPI spec, Zuplo can turn it into a fully functional MCP server in minutes -- complete with authentication, rate limiting, and analytics. Your OpenAPI descriptions become tool descriptions. Your parameter schemas become input schemas. Your API is instantly ready for AI agent consumption.

Start with a well-structured OpenAPI spec, follow the patterns in this guide, and the resulting MCP tools will be ones that AI agents can actually use.

Tags:#Model Context Protocol#API Best Practices

Related Articles

Continue learning from the Zuplo Learning Center.

API Gateway

API Gateway Patterns: BFF, Composition, Offloading, and Gateway Routing

Learn the most important API gateway architecture patterns — BFF, API composition, gateway offloading, routing, transformation, and more — with practical examples.

Edge Computing

Edge-Native API Gateway Architecture: Benefits, Patterns, and Use Cases

Learn what edge-native API gateways are, how they differ from cloud-region gateways, and why they deliver lower latency, better security, and global scale.

On this page

How MCP Tools Map to REST EndpointsNaming ConventionsParameter Mapping Best PracticesHandling PaginationError ResponsesWhat to Expose (and What Not To)OpenAPI Best Practices for MCPExample: Mapping a Todo APITurn Your OpenAPI Spec into MCP Tools

Scale your APIs with
confidence.

Start for free or book a demo with our team.
Book a demoStart for Free
SOC 2 TYPE 2High Performer Spring 2025Momentum Leader Spring 2025Best Estimated ROI Spring 2025Easiest To Use Spring 2025Fastest Implementation Spring 2025

Get Updates From Zuplo

Zuplo logo
© 2026 zuplo. All rights reserved.
Products & Features
API ManagementAI GatewayMCP ServersMCP GatewayDeveloper PortalRate LimitingOpenAPI NativeGitOpsProgrammableAPI Key ManagementMulti-cloudAPI GovernanceMonetizationSelf-Serve DevX
Developers
DocumentationBlogLearning CenterCommunityChangelogIntegrations
Product
PricingSupportSign InCustomer Stories
Company
About UsMedia KitCareersStatusTrust & Compliance
Privacy PolicySecurity PoliciesTerms of ServiceTrust & Compliance
Docs
Pricing
Sign Up
Login
ContactBook a demoFAQ
Zuplo logo
DocsPricingSign Up
Login