|Security

How to Make a REST API Read-Only for AI Agents

Make a REST API read-only for AI agents with method filtering, endpoint visibility, least-privilege credentials, rate limits, approvals, and audit logs.

Andrei
Founder of datamcp

The short answer

To make a REST API read-only for AI agents, do not rely on a prompt that says “never modify data.” Enforce the restriction at several independent layers:

  1. allow only operations with genuinely safe semantics
  2. remove or hide every endpoint the agent does not need
  3. use a dedicated upstream credential with the smallest possible permissions
  4. enforce object-level and function-level authorization inside the API
  5. add rate limits, response limits, approvals, activity logs, and revocation

HTTP method filtering is the first gate, not the complete security model. A GET request can still expose sensitive data, trigger expensive work, or even mutate state when an API is designed incorrectly.

datamcp Read Only links permit GET and HEAD operations and block POST, PUT, PATCH, and DELETE. Endpoint visibility can narrow the exposed OpenAPI operations further. Those controls reduce the callable surface, but the API owner must still make every allowed operation safe and authorize every returned object.

What “read-only REST API” actually means

The HTTP specification distinguishes safe methods from idempotent methods. According to RFC 9110, a safe method has read-only semantics: the client does not request a state change. GET and HEAD are safe. PUT and DELETE can be idempotent, but they are not safe because they request a change.

That definition describes the intended semantics, not a guarantee about an API implementation. A server can still attach logging, billing, caching, or other incidental effects to a safe request. More importantly, a poorly designed API might put a real business action behind GET.

Consider these operations:

GET /reports/quarterly
GET /users/42
GET /users/42/activate
GET /exports/customers?send_to=email

The first two look like reads. The third changes account state despite using GET. The fourth might start an export, send email, expose personal data, or create significant compute cost.

A method allowlist would permit all four. A genuinely read-only design would replace the mutating action with an unsafe method, such as:

POST /users/42/activation

Then it would hide that operation from the read-only agent and deny it at the API authorization layer.

Why method filtering is necessary but insufficient

Control layerWhat it reducesWhat it cannot guarantee alone
HTTP method gateCommon create, update, and delete operationsThat every allowed GET is side-effect-free
Endpoint visibilityUnneeded operations discoverable through MCPAuthorization for objects returned by visible operations
Upstream credentialFunctions unavailable to the service identityThat an allowed function returns only appropriate data
API authorizationObject and function accessThat an agent makes a sensible request
Approval and client policyAccidental or low-confidence executionProtection from an overprivileged backend credential
Rate limits and audit logsBlast radius and investigation timePrevention of every first harmful request

The most important lesson is that read-only is both an action policy and a data policy.

Blocking writes prevents the agent from changing records through common REST methods. It does not stop the agent from reading an entire customer directory, retrieving an administrator-only report, enumerating object IDs, or repeatedly calling an expensive analytics endpoint.

OWASP recommends denying access by default and granting explicit permissions at the function and object levels. The OWASP API Security project also treats unrestricted access to sensitive business flows and resource consumption as separate risks. A method filter cannot replace those controls.

Step 1: Inventory every operation the agent can reach

Start from the effective OpenAPI document, not from a list in a product brief. For each operation, record:

  • HTTP method and path
  • operation purpose
  • authentication requirement
  • data classification of the response
  • possible direct and indirect side effects
  • expected request rate and maximum result size
  • whether the agent truly needs it

Treat operation names such as preview, validate, search, export, sync, refresh, and test carefully. They may use GET while starting jobs, contacting third parties, consuming credits, or revealing data beyond the user’s request.

Do not expose an operation merely because it exists in the specification. Begin with an empty allowlist and add the smallest set required for the workflow.

Step 2: Fix unsafe GET endpoints

An AI gateway cannot make a mutating GET safe. Correct the API itself:

  • move state-changing actions to POST, PUT, PATCH, or DELETE
  • keep GET and HEAD free of requested business-state changes
  • avoid action verbs in read URLs such as /activate, /send, /run, or /approve
  • separate “calculate a preview” from “commit the result”
  • document incidental cost and data exposure for expensive reads

If you cannot change a legacy endpoint immediately, remove it from the agent-facing OpenAPI document, hide it from MCP discovery, and deny it to the agent’s upstream credential. Do not depend on the model to remember that one particular GET is dangerous.

Step 3: Publish a reduced OpenAPI surface

The agent-facing specification should contain only the operations required for the intended job. A reduced contract improves both security and tool selection:

  • fewer operations can be discovered or called
  • descriptions can explain the intended read workflow precisely
  • sensitive internal paths do not become prompt context
  • testing can cover the complete exposed surface

For datamcp, the connected OpenAPI source is converted into four schema-aware MCP tools:

  1. list_api_endpoints
  2. get_endpoint_details
  3. get_api_schema
  4. call_endpoint

datamcp does not create a separate MCP tool for every REST endpoint. The discovery tools reveal visible operations, and call_endpoint executes an operation only when it is defined in the connected specification and visible for MCP.

Use endpoint visibility to turn off individual methods and paths the agent should not discover. You can also hide all operations first and enable the approved set one by one.

Step 4: Create a least-privilege upstream credential

The gateway’s method policy and the REST API’s credential policy should fail independently.

Create a dedicated API key, service account, or pre-issued Bearer token for the agent workflow. Grant only the scopes and resources required by the visible read operations. Avoid owner, administrator, wildcard, or environment-wide credentials.

Examples of useful restrictions include:

  • customers:read without customers:write
  • access to one tenant rather than every tenant
  • access to sanitized reporting views rather than source records
  • permission to list orders without permission to retrieve payment details
  • production read access without deployment or configuration scopes

Do not put the upstream secret in the AI client. datamcp stores the supported API key, Bearer token, Basic credential, or fixed custom headers on the OpenAPI connection and injects them server-side. The client authenticates separately to the MCP endpoint with a datamcp API key or a supported OAuth 2.0 with PKCE flow.

See the OpenAPI authentication guide for the exact boundary and currently supported credential types.

For this workflow, explicitly select Read Only when creating the OpenAPI MCP link. Do not leave Full Access selected.

The Read Only policy permits GET and HEAD operations. datamcp blocks POST, PUT, PATCH, and DELETE through that link. Full Access is appropriate only when the agent genuinely needs write operations and you have designed separate approval and authorization controls for them.

The MCP policy does not expand the upstream credential. A Full Access link cannot perform an operation the REST API denies. Conversely, a Read Only link is still too broad if its upstream credential can read sensitive objects or one of the allowed GET endpoints causes a business action.

Step 6: Enforce authorization inside the REST API

Keep authorization at the resource server even when a gateway already authenticates the MCP client.

For every request, verify:

  • the service identity may call this function
  • the identity may access this specific object
  • tenant boundaries are enforced server-side
  • sensitive fields are filtered before serialization
  • pagination and query filters cannot bypass policy
  • identifiers cannot be enumerated across users or organizations

This protects against broken function-level authorization and broken object-level authorization. A valid GET /accounts/42 must not return account 42 merely because the caller guessed the ID.

Step 7: Bound data volume, cost, and execution time

Read-only traffic can still cause an operational incident. Apply limits at the API or gateway edge:

  • request rate per client and per upstream credential
  • maximum page size and maximum number of pages
  • query complexity or date-range limits
  • response size caps
  • request timeouts
  • concurrency limits for expensive reports
  • daily cost or quota alerts

Prefer bounded endpoints such as GET /events?from=...&to=...&limit=100 over unbounded exports. Return stable pagination metadata and reject requests that exceed documented limits.

datamcp applies an execution timeout and caps returned response content, but those gateway protections do not replace API-side quotas. The original API still owns database load, third-party billing, and business-flow limits.

Step 8: Require intent for sensitive reads

Some reads deserve user confirmation even though they do not modify state. Examples include payroll reports, customer exports, security events, legal documents, and cross-tenant analytics.

At the client or workflow layer:

  • disable automatic execution for sensitive tools when the client supports it
  • require the user to confirm the resource, scope, and date range
  • show the exact operation before approval
  • separate routine lookup from bulk export
  • never treat “read-only” as “low-risk” by default

Human approval is a useful control for intent. It is not a substitute for backend authorization because users can approve an operation without understanding its full data scope.

Step 9: Log successful and denied requests

An audit trail should answer:

  • which MCP client or user initiated the call
  • which link and upstream connection were used
  • which method and path were requested
  • when the request occurred
  • whether it succeeded, failed, or was denied
  • the response status and bounded result metadata

datamcp records MCP activity, including denied operations, so administrators can review calls made through a link. Avoid writing raw secrets or unrestricted response bodies into application logs. Retention and export requirements should match the sensitivity of the connected API.

Step 10: Test denial and revocation paths

Do not stop after one successful GET. A production test should prove that the unwanted paths fail.

Run at least these checks:

  1. an approved GET succeeds
  2. an approved HEAD behaves as expected
  3. POST, PUT, PATCH, and DELETE are denied through the Read Only link
  4. a hidden endpoint is absent from discovery and cannot be called
  5. an unauthorized object ID returns a denial, not another tenant’s data
  6. oversized, expensive, and high-rate reads are limited
  7. a revoked MCP link stops an already configured client
  8. a rotated upstream credential invalidates the previous secret

Review the activity record after each negative test. A denial that is invisible to operators is harder to investigate and tune.

A practical read-only architecture

AI client
  └─ client authentication
      └─ Read Only MCP link: GET / HEAD
          └─ endpoint visibility allowlist
              └─ dedicated upstream read credential
                  └─ REST API function + object authorization
                      └─ rate limits, bounded responses, audit logs

Each layer should reduce authority rather than assume the layer before it is perfect. If one control is misconfigured, another should still prevent or limit the request.

Production checklist

  • every allowed GET has been reviewed for side effects
  • unsafe actions use an unsafe HTTP method
  • the agent-facing OpenAPI surface contains only required operations
  • unnecessary endpoints are hidden from MCP discovery
  • the MCP link is explicitly set to Read Only
  • the upstream credential is dedicated and least-privilege
  • function-level and object-level authorization run inside the API
  • sensitive fields and tenant boundaries are enforced server-side
  • pagination, rate, cost, response, and timeout limits are defined
  • sensitive reads require visible user intent where appropriate
  • successful and denied operations are logged
  • link revocation and credential rotation have been tested

Next steps

Use the OpenAPI to MCP product page to review the hosted connection model, then follow the Swagger to MCP tutorial to connect a public OpenAPI 3.x or supported Swagger documentation URL. Keep the OpenAPI connection documentation open while configuring the connection and link.

For the wider control plane, read what an MCP gateway controls. Authentication, endpoint visibility, credential isolation, method policy, upstream execution logging, and revocation work best as separate layers rather than one broad permission.

REST APIOpenAPIAI agentsMCPAPI security

Already have an OpenAPI contract?

Connect the specification and publish a hosted MCP endpoint without maintaining custom server code.

Create OpenAPI MCP link

Explore OpenAPI to MCP · Questions? Read the docs or view pricing.