Restrict the tools an MCP server exposes
Cloudinary's remote MCP servers accept a cloudinary-tools header holding a comma-separated allowlist, so one connection advertises three tools instead of the server's full set. Enforcement is server-side, unlike a client-side toggle. Fewer tool definitions load into context, the model chooses between four plausible tools rather than forty, and an unadvertised delete tool cannot be called.
Before you start
Three things have to be true before an allowlist is available to you.
- The connection is to a remote endpoint. The header travels on the HTTP request that opens the session, so it is a property of a hosted connection. A server you run locally reads its configuration from disk and has no request to carry one. If that decision is still open, settle remote against local servers before configuring anything.
- Your client can set arbitrary headers per server entry. Nearly all can; only the config key differs. If the connection already carries credentials in headers — MediaFlows authenticates that way — you are adding one line to a block that already exists.
- You know what this connection is for. An allowlist is an answer to “what does this job need”. Without the job, there is nothing to filter against.
Steps
-
Scope the connection to one job. Write it down in a sentence: “look up assets and read their metadata for the docs pipeline”, not “Cloudinary”. A connection scoped to everything cannot be narrowed, because every tool is in scope by definition. Two narrow connections cost no more to run than one wide one, and each gets its own allowlist.
-
Read what the server currently advertises. Ask your client to list the connection’s tools; the server answers
tools/listwith a name, a description and a JSON Schema of the inputs for every tool it offers. Count them. Each of those definitions is loaded into the model’s context on connection, so an unrestricted server spends tokens describing capabilities the task will never call — on every turn, before the model has done anything. The same arithmetic across several connections at once is worked through in the context cost of leaving several MCP servers connected. -
Pick the smallest set that completes the job. Read the descriptions rather than guessing from names, and keep the tools the job calls directly plus anything they depend on. The reason to be strict here is not the token count: targeting improves before cost does. A model choosing between four plausible tools misfires far less often than one choosing between forty, and that shows up as fewer wrong calls long before it shows up on a usage graph. When you are unsure about a tool, leave it out — a missing tool produces a loud failure, an unnecessary one produces a quiet misfire.
-
Add the
cloudinary-toolsheader. Cloudinary’s remote servers accept a comma-separated allowlist in it, so one connection can expose three tools out of the server’s full set (Cloudinary’s MCP and LLM tooling docs).{ "mcpServers": { "cloudinary-assets": { "type": "http", "url": "https://asset-management.mcp.cloudinary.com/mcp", "headers": { "cloudinary-tools": "tool-a,tool-b,tool-c" } } } }Replace the placeholders with the exact names from step 2; the header matches names, not descriptions. This is the same block that holds whatever the connection uses to authenticate — if that is unsettled, see OAuth against API key headers.
-
Leave destructive tools out of every connection that does not need one. This is the cheapest blast-radius control available, because a connection that never advertises a delete tool cannot be talked into calling one — not by a confused plan, not by instructions sitting in an asset’s metadata or a page the agent read on the way. OWASP’s Top 10 for LLM applications treats excessive agency as its own failure class, and the remedy it describes is this one: constrain the tools reachable in a session rather than trusting the model’s intentions inside it. It is not a substitute for scoped credentials. The header narrows what this session can reach; the credential decides what the key can do at all. Do both.
-
Reconnect and count the tools again. The list should be exactly your allowlist. A name misspelled in the header fails silently — it simply never matches — so if the count is short by one, check the spelling against the list you read in step 2. Verify from the connection, not from your client’s settings screen: the header is enforced server-side, unlike disabling a tool in a client’s own settings, which only hides it from the model on that one machine. A tool switched off locally is still advertised, and a teammate who copies the URL without the header gets the full set.
What done looks like
The connection advertises only the tools named in the header, and the model’s context carries that many definitions instead of the server’s full inventory. The model’s tool choice is made among a handful of candidates that are all plausible for the job. Anything outside the list is unreachable through this connection regardless of what the model is asked or told, on every machine that uses it, because the filtering happens on the server before the tool list is ever sent. Adding a capability back is one more name in the header and a reconnect.
Sources
- for every tool it offers modelcontextprotocol.io
- Cloudinary's MCP and LLM tooling docs cloudinary.com
- Top 10 for LLM applications owasp.org
See also
-
A skill is instruction text; an MCP server executes against a live account. How Cloudinary's four-skill pack and its MCP servers differ, and when to use each.
-
A vendor CLI against an MCP server for bulk asset operations: setup, determinism, per-item token cost, and the cases where each one is the right tool.
-
Every connected MCP server loads its tool schemas into the context window before the first message, and a larger tool surface degrades selection accuracy.
-
Header-authenticated MCP client configs store a plaintext API secret on disk. How that file gets committed or logged, how to check, and what to rotate.