Argument-level policy vs allowlists

The obvious way to govern an agent is an allowlist of tools: name the tools it may call, deny the rest. That works right up until the tools stop being fine-grained — and MCP servers are actively making them coarse.

The coarse-tool problem

To keep their tool catalogs small, servers are collapsing whole APIs into one or two generic tools. Stripe’s hosted MCP server is the canonical case: the entire API is exposed as stripe_api_read and stripe_api_write, and which operation actually runs is decided by an argumentstripe_api_operation_id: "PostProducts". That argument is a bare string in the tool’s schema, with no enumerated set of legal values; the real vocabulary lives in Stripe’s docs.

Now ask the question a security team always asks: “let this agent create products, but never delete anything.” A tool-identity allowlist cannot express it. Allowing stripe_api_write allows every write there is — creating a product and deleting a customer are the same tool. Denying it blocks the useful case with the dangerous one. The discriminator you care about is one level below the tool name, and an allowlist cannot see it.

Matching the argument, not just the tool

Meandr policies decide allow, deny, or approve on each call, and their conditions reach into the call’s own arguments. You address a value with a small, deliberate subset of JSONPath — $.amount, $.user.email, $.items[*].qty, or just amount — and test it with an operator: eq, neq, gt, lt, gte, lte, matches, contains, exists, or in. Within a single list of patterns the matches are OR’d; across different keys they are AND’d. Because the proxy reads a structured payload, amount > 10000 matches the genuine parameter — which is strictly better than an HTTP WAF trying to regex a request body it cannot parse.

So the Stripe question becomes three ordered rules:

allow   stripe_api_write  where  $.stripe_api_operation_id in [PostProducts, PostPrices]
deny    stripe_api_write  where  $.stripe_api_operation_id matches ^Delete
approve stripe_api_write  (everything else — a human decides)

“Create products and prices, never delete, and let a person look at anything unusual” — expressed against a single generic write tool that an allowlist could only wave through or block whole.

Order, first match, and a default that is always on

Rules carry a priority and evaluate in order; the first match wins. Put your specific exceptions above the broad rules, and let a project-level default policy — which is always in force — catch anything that falls through. That fallback is what makes deny-by-default expressible: nothing runs unless a rule, or the default, permitted it.

Two design choices keep this honest. Argument wildcards like [*] mean any element matches, which is the intuitive reading for a deny (“deny if any item exceeds the limit”) but the wrong shape for an allow — so write allows against a specific index, or deny the unsafe shape instead. And a policy whose pattern will not compile is excluded and reported, not allowed to take down all traffic; one typo in one field never becomes a fleet-wide outage.

Beyond arguments

The same engine matches on the agent (directly or by tag), the server, the tool name, the caller’s IP, request headers, and the tool’s own declared annotation hints (readOnlyHint, destructiveHint, and the rest). Those hints are matched exactly as the server declared them — an undeclared hint matches nothing, and Meandr invents no defaults about tools it did not write. Separately, the proxy can validate a call’s arguments against the tool’s own input schema and reject a non-conforming call before it reaches the upstream.

Today the argument evaluation runs on the proxy; the schema-driven builder that suggests keys and values from a tool’s input schema is still being rolled out, so you author argument conditions directly for now. The capability that matters — deciding on the value, not just the tool — is live.

Ready to write one? Start with your first policy, see the wider picture in MCP governance, or read how a matched approve becomes a human decision.