# MCP Capability Filter Inbound Policy

Filter the tools, prompts, resources, and resource templates exposed by an
upstream MCP server.

## Configuration

The configuration shows how to configure the policy in the 'policies.json' document.

```json title="config/policies.json"
{
  "name": "my-mcp-capability-filter-inbound-policy",
  "policyType": "mcp-capability-filter-inbound",
  "handler": {
    "export": "McpCapabilityFilterInboundPolicy",
    "module": "$import(@zuplo/runtime/mcp-gateway)",
    "options": {
      "tools": [
        {
          "name": "create_invoice",
          "description": "Create an invoice for accounting users.",
          "annotations": {
            "destructiveHint": false
          }
        }
      ],
      "prompts": ["summarize_customer"]
    }
  }
}
```

### Policy Configuration

- `name` <code className="text-green-600">&lt;string&gt;</code> - The name of your policy instance. This is used as a reference in your routes.
- `policyType` <code className="text-green-600">&lt;string&gt;</code> - The identifier of the policy. This is used by the Zuplo UI. Value should be `mcp-capability-filter-inbound`.
- `handler.export` <code className="text-green-600">&lt;string&gt;</code> - The name of the exported type. Value should be `McpCapabilityFilterInboundPolicy`.
- `handler.module` <code className="text-green-600">&lt;string&gt;</code> - The module containing the policy. Value should be `$import(@zuplo/runtime/mcp-gateway)`.
- `handler.options` <code className="text-green-600">&lt;object&gt;</code> - The options for this policy. [See Policy Options](#policy-options) below.

### Policy Options

The options for this policy are specified below. All properties are optional unless specifically marked as required.

- `tools` <code className="text-green-600">&lt;undefined[]&gt;</code> - Tools to expose. Use a string for name-only filtering, or an object to expose and project tool description, annotations, and \_meta. Omit to pass through all upstream tools; use an empty array to expose no tools.
- `prompts` <code className="text-green-600">&lt;undefined[]&gt;</code> - Prompts to expose. Use a string for name-only filtering, or an object to expose and project prompt description and \_meta. Omit to pass through all upstream prompts; use an empty array to expose no prompts.
- `resources` <code className="text-green-600">&lt;undefined[]&gt;</code> - Resources to expose. Use a string for URI-only filtering, or an object to expose and project resource name, description, MIME type, and \_meta. Omit to pass through all upstream resources; use an empty array to expose no resources.
- `resourceTemplates` <code className="text-green-600">&lt;undefined[]&gt;</code> - Resource templates to expose. Use a string for URI-template-only filtering, or an object to expose and project template name, description, MIME type, and \_meta. Omit to pass through all upstream resource templates; use an empty array to expose no resource templates.

## Using the Policy

## Overview

The `mcp-capability-filter-inbound` policy curates the MCP capabilities exposed
by a proxied upstream server. It filters successful JSON-RPC list responses and
blocks direct JSON-RPC access to hidden tools, prompts, and resources before the
request is forwarded upstream.

Omit a capability option to pass that capability type through unchanged. Set an
option to an empty array to expose none of that capability type. Matching is
case-sensitive and exact.

Each entry can be either a string identifier or a projection object. Projection
objects still use the name/URI as the stable upstream identity, but can override
the downstream-facing `description`, merge `annotations` for tools, and merge
`_meta` for future metadata such as role hints. Keep input and output schemas
out of this policy config; schemas are supplied by the upstream list response.

## Configuration

```json
{
  "name": "mcp-filter-stripe",
  "policyType": "mcp-capability-filter-inbound",
  "handler": {
    "module": "$import(@zuplo/runtime/mcp-gateway)",
    "export": "McpCapabilityFilterInboundPolicy",
    "options": {
      "tools": [
        {
          "name": "create_invoice",
          "description": "Create an invoice for accounting users.",
          "annotations": {
            "destructiveHint": false
          },
          "_meta": {
            "roles": ["accounting"]
          }
        }
      ],
      "prompts": ["summarize_customer"],
      "resources": ["stripe://customers"],
      "resourceTemplates": ["stripe://customers/{id}"]
    }
  }
}
```

Place this policy after `mcp-token-exchange-inbound` when the route uses
gateway-managed upstream OAuth credentials. That order lets the token exchange
policy retry or replace a 401 response first; this policy then filters the final
upstream JSON-RPC response.

## Batch Requests

For JSON-RPC batch requests, list responses are filtered per response item when
the item id can be matched to the original list request. If any batch item
directly calls a hidden tool, prompt, or resource, the policy blocks the whole
batch with a not-found JSON-RPC error response.

Read more about [how policies work](/articles/policies)
