> ## Documentation Index
> Fetch the complete documentation index at: https://tyk.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Gateway Policies

> Configure Tyk security policies for MCP proxies: per-tool access and rate limits, JSON-RPC method restrictions, and how Tyk merges multiple policies.

A Tyk security policy defines the access rules and usage limits for a consumer. For MCP proxies, policies go beyond the standard rate limit and quota controls available for REST APIs. They let you control access and apply rate limits at the level of individual tools, resources, and prompts, and restrict which JSON-RPC protocol methods a consumer can use at all.

***

## What Policies Are For

A policy is a reusable template applied to one or more API keys. Rather than configuring limits and access rights on each key individually, you define them once in a policy and issue keys that inherit those rules automatically. When you update the policy, every key bound to it picks up the change.

For MCP proxies, policies serve three purposes:

**Controlling access**: a policy determines which MCP proxies a consumer key can reach. Without an entry in the policy's access rights, the consumer receives `403 Forbidden` regardless of what key they present.

**Governing MCP capabilities**: beyond proxy-level access, policies let you restrict which JSON-RPC methods a consumer can use and which specific tools, resources, and prompts they can invoke. This lets you give different consumers different views of the same MCP proxy without creating separate proxy definitions.

**Enforcing usage limits**: policies apply rate limits at several levels: across the whole policy, per MCP proxy, per JSON-RPC method, and per named primitive. Each consumer key tracks its own independent counters.

***

## What MCP Policies Control

### Access Control

Tyk evaluates access control at three levels, in order:

**Proxy access**: the policy's access rights list determines which MCP proxies the key can reach. A key can only call a proxy listed in its access rights.

**JSON-RPC method access** (`json_rpc_methods_access_rights`): controls which protocol-level operations the consumer may use. For example, you can allow `tools/call` and `tools/list` while blocking `sampling/createMessage`. Use an `allowed` list to restrict to specific methods, or a `blocked` list to exclude specific methods while permitting all others.

Method rules match the methods that clients actually send, and those depend on the protocol version. Clients using `2026-07-28` don't send session methods such as `initialize` and `ping`, so a method rule or rate limit keyed on one of them never matches that traffic. See [Session Methods and Headers](https://tyk.io/docs/ai-management/mcp-gateway/protocol-versions.md#session-methods-and-headers).

**Primitive access** (`mcp_access_rights`): controls which specific tools, resources, and prompts the consumer can invoke. Each primitive type (tools, resources, prompts) has its own `allowed` and `blocked` list. Values are Go regular expressions, so `"internal_.*"` matches any tool whose name starts with `internal_`. A non-empty `allowed` list acts as an explicit allowlist; `blocked` entries are excluded from whatever is otherwise permitted.

Policy rules apply in addition to the proxy's own `allow` and `block` middleware. A policy cannot give a key access to a primitive that the proxy blocks.

### How Access Rules Shape Discovery

Access rules also control what a consumer can discover. Tyk removes the tools, resources and prompts that a consumer cannot call from list results. See [Discovery](https://tyk.io/docs/ai-management/mcp-gateway/core-concepts.md#discovery).

Tyk also removes a capability from the `server/discover` result when method rules deny any method that capability needs. If your clients use `2025-11-25`, the same applies to the `initialize` result. For example, a method allowlist that doesn't include `resources/templates/list` removes the whole `resources` capability. The following table shows the methods each capability needs.

| Capability | Methods the capability needs |
| - | - |
| `tools` | `tools/list`, `tools/call` |
| `resources` | `resources/list`, `resources/templates/list`, `resources/read` |
| `prompts` | `prompts/list`, `prompts/get` |

A filtered result is specific to the consumer's key, so Tyk marks it with `"cacheScope": "private"` and `"ttlMs": 0`. See [Cache Hints on Filtered Results](https://tyk.io/docs/ai-management/mcp-gateway/protocol-versions.md#cache-hints-on-filtered-results).

### Rate Limiting

Rate limits can be applied at four levels within a policy entry for an MCP proxy:

**Policy global**: the top-level `rate` and `per` fields on the policy apply across all APIs the key accesses.

**Per MCP proxy**: the `limit` field inside an access rights entry applies a rate limit specific to calls to that proxy, independent of the consumer's overall policy rate.

**Per JSON-RPC method** (`json_rpc_methods`): sets a rate limit for calls using a specific method name, such as `tools/call`. The counter applies across all tools invoked via that method.

**Per primitive** (`mcp_primitives`): sets a rate limit scoped to a specific named tool, resource, or prompt. A consumer who exhausts their limit on `generate_report` is blocked from calling that tool while remaining free to call others.

All applicable limits are checked independently on every call. Whichever is exhausted first blocks the request. For example, a call to `get_report` counts against both the `tools/call` method limit and the `get_report` primitive limit, if both are set.

Method and primitive limits (`json_rpc_methods` and `mcp_primitives`) are rate limits only. They do not support quotas or throttling.

The proxy's own middleware rate limit also applies. It is shared by all consumers. See [Policies versus middleware](https://tyk.io/docs/ai-management/mcp-gateway/core-concepts.md#policies-versus-middleware).

### Quotas

A quota sets a maximum total number of calls over a renewal period (daily, weekly, or monthly). A consumer who exhausts their quota receives `429 Too Many Requests` until the period resets. Quotas are configured at the policy level using `quota_max` and `quota_renewal_rate`. See [Quotas](https://tyk.io/docs/api-management/request-quotas.md) for details.

***

## Configuring MCP Policies

### Using the Tyk Dashboard

1. In the Tyk Dashboard sidebar, click **Policies** then **Add Policy**.

   ![MCP policy list](https://mintcdn.com/tyk/13-ZUbDBHZHQEh3H/img/ai-management/mcp-policy-list.png?fit=max\&auto=format\&n=13-ZUbDBHZHQEh3H\&q=85\&s=7b60aca5c4302bbbbb6bf19548f0c894)

2. On the **Access Rights** tab, find your MCP proxy in the list and click it to add it to the policy.

3. Expand the proxy's access rights block. You will see sections for primitive rate limits and access control.

4. To configure **primitive rate limits**, click **Add Rate Limit**. Set the **Rate** and **Per** (in seconds) values, then click **Add Primitive** to associate a named tool, resource, or prompt with that limit. Add multiple primitives to the same group if they share a limit; create separate groups for different limits.

5. To configure **access control** for tools, resources, and prompts, use the **Primitive based access** section within the access rights block. Add a name, select the type, and set it to **Allowed** or **Blocked**.

6. On the **Configurations** tab, set the policy name, key expiry, and global rate limit.

7. Click **Create Policy**.

### Using the Dashboard API

Create or update a policy via `POST /api/portal/policies` (create) or `PUT /api/portal/policies/{policy-id}` (update). The MCP-specific fields sit inside the `access_rights` entry for each MCP proxy.

The following example creates a policy that grants access to a weather MCP proxy, restricts which JSON-RPC methods the consumer can use, limits them to specific tools, and applies per-primitive rate limits:

```json expandable theme={null}
{
  "name": "Weather Agent Standard Tier",
  "state": "active",
  "rate": 1000,
  "per": 60,
  "quota_max": 50000,
  "quota_renewal_rate": 86400,
  "access_rights": {
    "{mcp-proxy-api-id}": {
      "api_id": "{mcp-proxy-api-id}",
      "api_name": "Weather MCP Proxy",
      "versions": ["Default"],
      "limit": {
        "rate": 200,
        "per": 60
      },
      "json_rpc_methods_access_rights": {
        "allowed": [
          "server/discover",
          "initialize",
          "notifications/initialized",
          "notifications/cancelled",
          "tools/list",
          "tools/call",
          "resources/list",
          "resources/templates/list",
          "resources/read"
        ]
      },
      "mcp_access_rights": {
        "tools": {
          "allowed": ["get_forecast", "search_weather"]
        },
        "resources": {
          "blocked": ["internal://.*"]
        },
        "prompts": {}
      },
      "json_rpc_methods": [
        {
          "name": "tools/call",
          "limit": { "rate": 100, "per": 60 }
        }
      ],
      "mcp_primitives": [
        {
          "type": "tool",
          "name": "get_forecast",
          "limit": { "rate": 20, "per": 60 }
        },
        {
          "type": "resource",
          "name": "weather://current",
          "limit": { "rate": 10, "per": 60 }
        }
      ]
    }
  }
}
```

> [!NOTE]
>
> An allowlist denies every method it doesn't name. Include the methods clients need to connect: `server/discover` for `2026-07-28` clients, and `initialize` and `notifications/initialized` for `2025-11-25` clients. `2025-11-25` clients also need `notifications/cancelled` to cancel calls in progress. Also include every method that a capability needs, or Tyk removes that capability from the discovery result.

See [Policies](https://tyk.io/docs/api-management/policies.md) for more details.

***

## Policy Schema for MCP

The MCP-specific fields appear inside each entry in the `access_rights` object, alongside the standard `limit` and `versions` fields.

### Access Rights Entry

| Field | Type | Description |
| - | - | - |
| `api_id` | string | The ID of the MCP proxy this entry applies to. |
| `api_name` | string | Display name of the proxy. |
| `versions` | array | Always `["Default"]` for MCP proxies. |
| `limit` | object | Per-proxy rate limit for this consumer. Contains `rate` (integer) and `per` (seconds). |
| `mcp_access_rights` | object | Primitive-level allow/block lists. See below. |
| `json_rpc_methods_access_rights` | object | Method-level allow/block list. Contains `allowed` (array of strings) and `blocked` (array of strings). |
| `mcp_primitives` | array | Per-primitive rate limits. Each entry targets one named tool, resource, or prompt. See below. |
| `json_rpc_methods` | array | Per-method rate limits. Each entry targets one JSON-RPC method name. See below. |

### `mcp_access_rights` Object

Controls which primitives the consumer can invoke. Each of the three sub-objects follows the same structure.

| Field | Type | Description |
| - | - | - |
| `tools.allowed` | array of strings | Explicit allowlist of tool names. If non-empty, only listed tools are accessible. Supports Go regular expressions. |
| `tools.blocked` | array of strings | Tools to block. A blocked entry always wins, even if it also matches `allowed`. Supports Go regular expressions. |
| `resources.allowed` | array of strings | Explicit allowlist of resource URIs. |
| `resources.blocked` | array of strings | Resource URIs to block. |
| `prompts.allowed` | array of strings | Explicit allowlist of prompt names. |
| `prompts.blocked` | array of strings | Prompt names to block. |

Patterns must match the whole name. For example, `get_.*` matches `get_forecast` but not `forecast_get_all`.

Leave a sub-object empty (`{}`) to apply no restrictions for that primitive type.

### `mcp_primitives` Array

Each entry defines a rate limit for one named primitive.

| Field | Type | Required | Description |
| - | - | - | - |
| `type` | string | Yes | Primitive type. Accepted values: `tool`, `resource`, `prompt`. |
| `name` | string | Yes | Name of the primitive as exposed by the MCP server. Case-sensitive. |
| `limit.rate` | integer | Yes | Maximum calls allowed per time window. Set to `0` for unlimited. |
| `limit.per` | integer | Yes | Time window in seconds. Set to `0` for unlimited. |

Entries are matched by `type` and `name` together. A tool named `weather` and a resource named `weather` are independent entries with independent counters.

### `json_rpc_methods` Array

Each entry defines a rate limit for one JSON-RPC method.

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | The JSON-RPC method name, for example `tools/call` or `resources/read`. |
| `limit.rate` | integer | Yes | Maximum calls using this method per time window. |
| `limit.per` | integer | Yes | Time window in seconds. |

### Top-Level Policy Fields

| Field | Type | Description |
| - | - | - |
| `rate` | integer | Global rate limit across all APIs in the policy. |
| `per` | integer | Time window for the global rate limit, in seconds. |
| `quota_max` | integer | Maximum total calls in the quota period. Set to `-1` for unlimited. |
| `quota_renewal_rate` | integer | Quota renewal period in seconds. Common values: `86400` (daily), `604800` (weekly). |
| `key_expires_in` | integer | Key lifetime in seconds from creation. Set to `0` for no expiry. |

***

## When Multiple Policies Apply

A consumer key can have multiple policies applied to it. Tyk merges MCP-specific fields as follows:

* **Rate limits**: the highest effective request rate wins. If two policies define a limit for the same primitive, Tyk compares `rate` divided by `per` and applies the limit that allows more requests. See [Combining Multiple Policies Configuring Rate Limits](https://tyk.io/docs/api-management/rate-limit.md#combining-multiple-policies-configuring-rate-limits).
* **`mcp_access_rights` and `json_rpc_methods_access_rights`**: `allowed` lists are merged by union (the consumer gains access to the combined set). `blocked` lists are also unioned, so a primitive blocked in any policy remains blocked. A policy that sets no rules for a field is ignored when merging, so it does not widen an allowlist that another policy sets. For example, if one policy allows only `tools/list` and `tools/call` and a second policy sets no method rules, the consumer can call only those two methods.
* **Proxy access**: the consumer gains access to the union of all proxies listed across all their policies.

A policy with no MCP access rules does not widen access. For example, if policy A allows four tools and policy B has no `mcp_access_rights`, the key can call only those four tools. A primitive that any policy blocks stays blocked, even if another policy allows it.

***

## Applying a Policy to a Consumer

A policy takes effect when it is applied to an access key. In the Tyk Dashboard, go to **Keys**, click **Add Key**, select the policy from the **Apply Policy** dropdown, and generate the key. Issue the key to the consumer; they include it in the `Authorization` header of every MCP request.

See [Policies](https://tyk.io/docs/api-management/policies.md) for full details.
