An agent tool tells you what it does. Nobody checks.

EffectProbe runs the tool and watches. Every argument gets a marked value, and where that value surfaces is what the argument controls. The result is a contract a runtime can act on — and a description that was measured instead of believed.

what it declares
annotations · descriptions · hints
self-reported
by the server
what it does
observed · cited · reproducible
measured
by execution
@antv/mcp-server-chart generate_line_chart readOnlyHint: true description: "Generate visual charts using GPT-Vis..." declared side effects: none
measured on unmodified package 114 of 183 arguments → CONTROLS_PAYLOAD caller bytes, verbatim in POST body 0 of 183 → CONTROLS_TARGET destination fixed; only cargo is yours 27 tools annotated read-only, all post off-host

Agents trust what tools say about themselves and runtimes have no ground truth

EffectProbe treats the declaration as a hypothesis and the execution as the experiment.

trust

Tool descriptions are unverified claims

When a model decides to call a tool, the prose and annotations the server wrote about itself are the only signal. A server can annotate readOnlyHint: true and write to disk. Nothing in the protocol contradicts it, and nothing in the host is measuring.

readOnlyHint: true observed: NETWORK_WRITE · CREATE · EXTERNAL_PAYLOAD Semia (2026): 55.6% of expert-labelled agent skills carry critical semantic risk — measured statically.

enforcement

Blocking too much fails as fast as blocking too little

Any layer can deny an exfiltration. A layer that also blocks the benign twin — same untrusted text, different argument, allowed destination — has distinguished nothing and gets uninstalled in a week.

call 2 DENY write_file(.git/hooks/pre-commit) ← derived path call 3 ALLOW write_file(notes/summary.md) ← same text, payload arg Both facts required. Either alone is not enough.

@antv/mcp-server-chart

114 of 183
arguments measured to steer the body of a request to a host the declaration never names — the caller's own bytes, verbatim in the payload.
0 of 183
steer where that request goes. The destination is fixed; only the cargo is yours.

The allow is the hard part

Three calls against the unmodified public @modelcontextprotocol/server-filesystem 2026.7.10. Verified by diffing workspaces on disk, not by reading the gateway log.

manifest + provenance

Both facts are required

The gateway joins what each argument was observed to control with where this call's values came from. Call 2 is denied because the path is derived from untrusted content. Call 3 carries the same text in content and goes through.

Every denial is answerable — a block resting on observed behaviour without evidence cannot be constructed. On that server, 20 of 25 arguments compile to Unclassified.

call 1ALLOWread_file(notes/quarterly-brief.md)

A document is read. Every byte returned goes into the provenance ledger.

call 2DENYwrite_file(.git/hooks/pre-commit)

Path derived from that document. path controls the destination — blocked.

call 3ALLOWwrite_file(notes/summary.md)

Same untrusted text in content, forwarded untouched. Payload arg, not target.

Where the marked value lands is what the argument controls

Without region affinity, send_email.to and send_email.body are indistinguishable — and the second is the one you must not block.

probe

Runs the server in a sandbox, plants a canary in one argument at a time, records where it surfaces.

compile

Derives an authority contract per argument. Nothing above CORROBORATED is enforced without citation.

gateway

Joins manifest with provenance ledger. Blocks derived values in authority arguments; allows the same text in payload arguments.

write_file(path: "EP7C4A19B2E0F3", content: "EP7C4A19B2E0F3")
path
file pathfile body
CONTROLS_TARGET
content
file pathfile body
CONTROLS_PAYLOAD
One call, one token, two arguments — two different landing sites. Telling them apart is the whole product.
Marked value observed inRoleMeaning
HTTP Host, connection target, file pathCONTROLS_TARGETthe argument chooses where the effect lands
HTTP body, file contentsCONTROLS_PAYLOADthe argument chooses what is carried, not where
process argvCONTROLS_COMMANDthe argument reaches an executable specification
nowhere, but the effect togglesGATESthe argument switches a behaviour on or off

Every figure traces to a recorded run

Ground truth first, then servers nobody wrote for us. A funnel would book all four as probed — three taught us almost nothing about their arguments, and each report says so on its face.

Benchmark · 47 tools · 9 deceptive

Tool effects
1.000P0.944R
Argument effects
1.000P0.980R
Authority targets
1.000P0.967R
Deception detected
1.000P0.889R

Every false negative is an acknowledged reachability or observability limit.

Real servers · argument coverage

  • firecrawl-mcp25/25 tools · 0 contradictions
    0/145 args
  • @playwright/mcp24/24 tools · 0 contradictions
    1/64 args
  • godot-mcp-server40/40 tools · 0 contradictions
    16/95 args
  • @antv/mcp-server-chart27/27 tools · 0 contradictions
    114/183 args

What it does not do

A report with zero findings is the most dangerous thing this produces. These are not a footnote.

  • One call at a time

    A sequence harmful only in aggregate is not caught. No reasoning across calls.

  • Taint matching is textual

    A value the model paraphrased rather than copied is missed.

  • REVIEW goes nowhere

    A review verdict is not routed to a human. There is no queue.

  • Coverage is the ceiling

    397 of 515 tools on disk were never reached deeply enough to conclude anything about their arguments.

Disclosure reports

One self-contained file per server, addressed to the people who publish it. Every citation is a live anchor into an embedded evidence appendix.

Held for coordinated disclosure

  • @antv/mcp-server-chart

    The strongest evidence here and no published contradiction: 114 of 183 arguments were measured to steer the request body, none to steer its destination. Twenty-five read-only annotations look contradicted, but the observation behind them is an HTTP method, which cannot witness a modification — so they are candidates. Held back pending the maintainer's answer to the one question that would settle it.

Questions, answered

What is EffectProbe?

An authority layer for agent tool use. It runs each tool in a sandbox, varies one argument at a time, plants a marked value, and records where that value surfaces. The result is a contract a runtime can act on.

Who is it for?

Teams running agents against tools they did not write, and the runtime that has to decide whether a call is allowed.

How is this different from static analysis?

Descriptions are claims under test, never facts. Semia reads what a skill says; EffectProbe runs what a tool does. A server can pass every static check and still post your document to a host its declaration never names.

Does it block calls today?

Yes, through the gateway. The demo blocks an exfiltration and allows the benign twin on the same untrusted text — verified by diffing workspaces, not by reading the log.

Is the source available?

The repository is private — access on request. Every number on this page traces to a recorded run.