Curate the tools an upstream exposes (in code)
Choose how to curate tools
Curate the same way in the Portal or in code. Both write the same mcp-capability-filter-inbound policy, so you can switch approaches at any time.
In code
Configure the mcp-capability-filter-inbound policy directly in your project files with the Zuplo CLI.
When an upstream MCP server exposes more capabilities than belong in front of an
AI client, attach the mcp-capability-filter-inbound policy to the route to
allow-list the subset that should pass through, override descriptions or
annotations, and block direct calls to anything outside the list.
For the conceptual model behind capability filtering, including what the policy filters, the omit-versus-empty-array rule, and how projections are merged, see Capability filtering.
Prefer the Portal? The Portal version reaches the same result from the MCP Gateway Virtual Server UI.
Add the capability filter policy
-
Declare the policy in
config/policies.json. List the upstream identifiers you want to expose for each capability type (namefor tools and prompts,urifor resources,uriTemplatefor resource templates):config/policies.json -
Attach the policy to the route in
config/routes.oas.json, aftermcp-token-exchange-inboundso the filter operates on the final upstream response:config/routes.oas.json
Because prompts, resources, and resourceTemplates are omitted from the
options, the upstream's prompts and resources flow through unmodified. Only the
tool list is restricted.
Override a tool description
To rewrite the description or annotations a client sees while keeping the upstream identifier as the match key, replace the string entry with a projection object:
Code
The string entries ("list_issues", "get_issue") pass through with the
upstream's own descriptions. The projection object overrides create_issue's
description while keeping the upstream's input schema, output schema, and name
untouched.
Override tool annotations
Tool annotations
are deep-merged with the upstream's annotations, so fields you specify win and
fields you don't specify pass through. The same applies to _meta:
Code
Project a resource
Resources use uri as the match key. A resource projection can rewrite the
downstream-facing name, description, or mimeType:
Code
Block everything from a capability type
Provide an empty array to expose nothing of that type. The list response becomes
empty and every direct call returns MethodNotFound:
Code
To turn a route into a temporary kill switch, with all capability types disabled
without removing the route from configuration, set every type to []:
Code
Omitting an option behaves like a pass-through; an empty array ("tools": [])
hides every capability of that type. Confusing the two is the most common source
of "why can the client still see that tool?" reports.
Example: read-only Linear
Suppose the corp Linear upstream exposes more than two dozen tools and only the read-only subset belongs in front of the team's AI assistant. Allow-list the read tools, override descriptions for clarity, and hide all prompts and resources:
config/policies.json
Attach the policy to a dedicated route in config/routes.oas.json:
config/routes.oas.json
The same upstream Linear MCP server is now reachable at two routes, the
full-featured /mcp/linear-v1 and the curated /mcp/linear-readonly, each with
its own surface area.
Verify the filter
After deploying (or restarting zuplo dev), confirm the filter is active:
- Connect a test client (the MCP Inspector is the fastest option) to the filtered route.
- Call
tools/list. Only the allow-listed tools should appear. - Call
tools/callwith a tool name that isn't on the list. The gateway returns a JSON-RPCMethodNotFounderror before the request reaches the upstream.
If a tool you expected to see doesn't appear, check the upstream's tools/list
response directly. The match is case-sensitive and exact, so a typo or
capitalization difference makes the entry not match.
Related
- Curate tools in the Portal: do the same from the Virtual Server UI.
- Capability filtering: the conceptual model behind the policy.
McpProxyHandlerreference: the route handler the filter runs in front of.- Connect a gateway to an upstream OAuth provider: pair the filter with per-user upstream OAuth.