effectfence
The EffectFence server is a causal concurrency fence for multi-agent tool calls that guarantees exactly-once execution of side-effecting operations (e.g., charging a card, sending a payout, provisioning a resource). It prevents double-execution from races, retries, or duplicate dispatches and issues verifiable certificates for completed effects.
What you can do with it:
Prepare an effect (
fence_prepare): Request permission to run a side-effecting tool call, supplying a stableintent,domain,tool, andagent. The server returns a fresh ticket if you win the race, replays an existing certificate if the effect already ran, or rejects with an error if:Another attempt is in-flight (
IntentInFlight)A previous attempt failed and needs reconciliation
Your causal dependencies are stale (
ReadSetStale)You lost a same-instant race (
DomainRace)
Commit a successful effect (
fence_commit): After executing an effect granted byfence_prepare, report the outcome. This mints a content-addressedEffectCertand ensures future attempts with the same intent replay the recorded result instead of re-running.Abort a failed or unknown effect (
fence_abort): Report that an effect failed or its outcome is unknown. The intent remains fenced, preventing automatic re-execution until an operator manually reconciles and clears it.
Key guarantees:
Exactly-once execution – Same-instant races are resolved via atomic compare-exchange; only one caller wins per domain sequence.
Duplicate/retry safety – Late duplicates receive the stored certificate, not a new execution.
Causal tracking – Vector clocks and read-set validation ensure decisions are never based on stale information.
Failure fencing – Failed attempts lock the intent until reconciliation, avoiding blind retries.
No configuration required – Runs as a stdio MCP server with all state held in memory; no accounts, environment variables, or external dependencies.
EffectFence
Public register: the Retry-Safety Index lists which agent-payment implementations pay once when the answer is lost — verified safe, found & fixed (with time-to-fix), and how to get verified. Every row links to its proof.
Your swarm doesn't need more memory. It needs a causal fence around tool side effects.
Free: submit any client, facilitator, SDK or toolkit that moves money — yours or someone else's — and we read it and publish a verdict on the Retry-Safety Index at no cost. Findings come back with the mechanism, the file and line, and a failing test. You are counted, never named, until you ship a fix. Submit for grading →
⚡ effectfence — THE STORM
1,000 attempts to charge order #777 ($49.00): concurrent racers + late retries…
ACTUAL EXECUTIONS : 1 ← the whole point
served sealed receipt : 995
told to stand down : 4
elapsed : 22.33ms
💰 double-charges prevented this run: $48,951.00
✅ ONE execution. Every other attempt was fenced, replayed, or refused.Run the attack yourself:
cargo run --release --example stormThe multi-agent turf war
The storm above is one action, many racers. The harder case is different agents making contradictory decisions on the same production resource — the coordination failure now reported across production multi-agent systems (~a third of 2026 multi-agent incidents). Three autonomous SRE agents react to one latency spike:
cargo run --example turf_warAgent A (autoscaler): scale node pool UP
ADMITTED. Fence leased cluster:prod-us-east-1 — executing kubectl scale up.
DONE. EffectCert minted — verify() -> true
Agent B (cost-optimizer): scale the same pool DOWN
REFUSED before kubectl ran:
read-set for `metrics:prod-us-east-1` is stale: B decided on seq 0, world is at seq 1.
Agent C (deploy-bot): roll the deployment BACK
C's causal view is concurrent with A's: true
-> escalated to a human instead of corrupting the cluster.
Actions proposed: 3 executed: 1 cluster: intended, not corrupted.Each agent was individually correct for the state it read. Run concurrently
without coordination, all three kubectl calls fire and the cluster ends in a
state none of them intended — the $100M outage. The fence lets exactly one act,
refuses the other two before their side effect runs, and tells each one why.
Nothing above is mocked — every call is the real crate API.
EffectFence is a causal concurrency fence for multi-agent tool calls. When more than one agent (or retry, or re-dispatch) can end up trying to run the same side-effecting operation — charge a card, send a payout, provision a resource — EffectFence guarantees exactly one attempt ever executes it: same-instant races are decided by an atomic compare-exchange reservation, and late duplicates get the recorded outcome replayed instead of running again. Every effect that does run gets a content-addressed certificate chained to whatever it was causally built on.
It ships as a Rust library (effectfence::fence) and as a stdio MCP server exposing three tools — fence_prepare, fence_commit, fence_abort — so agents can route side-effecting tool calls through the fence instead of racing each other directly.
Related MCP server: io.github.GSterlingPress/once
The problem
In a multi-agent gateway, more than one caller can end up trying to run the same effect:
Two agents independently decide "charge the customer for order #123" needs to happen — at the same instant.
A supervisor times out waiting for a tool call and re-dispatches it while the original is still in flight.
A retried or duplicated event triggers the same decision again, minutes after the first attempt already succeeded.
Naively, any of these double-runs the effect. Naively rejecting every duplicate with no memory of outcome is also wrong: if the first attempt crashed, the effect never runs at all, and a duplicate that arrives after success gets an error instead of the result it needs. EffectFence closes all of it with optimistic concurrency control (OCC) plus an intent ledger: attempts don't block each other, exactly one executes, and every other attempt learns what actually happened.
Architecture
Four pieces compose into the fencing protocol:
The intent ledger is what stops duplicates, not just races. Every effect carries an intent — a stable id for the logical action (e.g. "charge:order-123"). Attempts sharing an intent are the same action: the first is admitted and holds a lease; concurrent duplicates are told an attempt is in flight; duplicates arriving after success get the recorded certificate replayed verbatim; duplicates after a failure are fenced (the side effect may or may not have fired — that must be reconciled, not blindly retried) until explicitly cleared. Crashed holders lose their lease after a TTL so the action isn't stuck forever.
Vector clocks (VectorClock) track causal "happened-before" relationships across agents — one logical counter per agent, joined via elementwise-max merge, compared via a le partial order, with a concurrent check for genuinely unordered events and a stable SHA-256 digest for inclusion in certificates.
OCC read-sets (ReadSetEntry) record the causal dependencies a decision was based on: "when I decided to act, domain D was at sequence S." Both prepare_effect_fence and commit_effect_cert validate every entry against live state — if anything moved, the attempt is rejected as stale rather than allowed to act on outdated information.
CAS domain fencing is where same-instant races are decided. Each domain (a named contention scope, e.g. "order:123") has an AtomicU64 sequence counter. The decision is a single atomic compare_exchange — exactly one concurrent caller can win for any given expected sequence. (Precision note: the counter lookup sits behind a short mutex; only the race decision itself is lock-free. Ideas for a fully lock-free path are welcome.)
┌ intent gate ──────── already done? → Replay(recorded cert) [do NOT run]
│ in flight / failed? → rejected [do NOT run]
EffectRequest┤
├ read-set check ───── dependency moved? → ReadSetStale [do NOT run]
│
└ domain CAS ────────── lost the race? → DomainRace [do NOT run]
│
└ Fresh(ticket) → run the effect → commit_effect_cert → EffectCert
↘ abort_effect (failed; fenced until reconciled)Every committed effect becomes an EffectCert: a SHA-256 content hash over {intent, parent, domain, seq, tool, args, result, vector_clock, read_set, agent}, chained to a parent cert hash for causal lineage. Two certs with the same hash are, by definition, records of the same effect — EffectCert::verify() recomputes the hash and confirms it hasn't been tampered with or hand-built incorrectly.
Scope
This is an in-memory, single-process fence — state lives behind an Arc and is lost on restart. That's enough to close races and duplicates between concurrent threads/tasks in one gateway process. Two things it deliberately does not do (yet):
Cross-process/cross-restart fencing. A horizontally scaled gateway needs the same intent/domain/read-set model backed by a shared store (e.g.
SETNX+CAS in Redis, or an optimistic version column in Postgres) — the types here are meant to carry over directly to that backend.Enforcement. The fence protects agents that route their effects through it; it cannot stop an agent that bypasses it entirely. Deploy it at the one choke point your agents share (the gateway process that owns the tools).
Memory is bounded: finished outcomes expire after a configurable TTL (FenceConfig::result_ttl, swept by EffectFence::sweep), queries never create tracking state, and domain counters are tiny and manually evictable (evict_domain).
Quickstart: library
use effectfence::fence::{
prepare_effect_fence, commit_effect_cert, Admission, EffectFence, EffectRequest, VectorClock,
};
let fence = EffectFence::new();
let req = EffectRequest {
intent: "charge:order-123".into(), // same action -> same intent, always
parent: None, // hash of the cert this follows, if any
domain: "order:123".into(), // contention scope
tool: "charge_card".into(),
args: serde_json::json!({"amount_cents": 1999}),
read_set: vec![], // other domains this decision cross-checked
agent: "agent-a".into(),
known_clock: VectorClock::new(),
};
match prepare_effect_fence(&fence, req)? {
Admission::Fresh(prepared) => {
// This attempt won. Actually run the charge...
let cert = commit_effect_cert(
&fence,
prepared,
serde_json::json!({"charge_id": "ch_123"}),
)?;
assert!(cert.verify());
// (on failure: abort_effect(&fence, prepared, "why") instead)
}
Admission::Replay(cert) => {
// This exact action already ran -- use cert.result, charge nothing.
}
}A concurrent duplicate of the same intent gets Err(FenceError::IntentInFlight); a same-instant race on the domain gets Err(FenceError::DomainRace); either way it must not run the effect.
Try it in 10 seconds (nothing installs, nothing real fires)
cargo install effectfence # or: npx -y effectfence demo
effectfence demoTwelve agents reach for one $49 charge at the same instant. You'll see it hit a built-in server raw — 12 duplicate charges — then the same twelve calls behind the fence: exactly 1. This binary is talking to itself, so no real call fires and you need no server of your own to see the point.
── Act 1: the raw server, no fence ──
DISTINCT effects : 12 PROVEN DOUBLE-FIRE
── Act 2: the SAME twelve calls, behind the fence ──
DISTINCT effects : 1 12 callers, 12 clean answers, one executionFirst: does YOUR stack actually double-fire? (probe it)
Before you install a fence, prove you need one — on your own server, not our demo.
probe is a bare MCP client. Point it at any MCP server, and it fires N
byte-identical calls at one tool concurrently — the twin-caller race that
happens the instant two agents reach for the same action — then reports how many
distinct effects actually landed:
effectfence probe --tool charge_card --args '{"amount":4900}' --calls 12 -- npx -y @your-org/your-mcp-serverEffectFence probe — twin-caller race report
--------------------------------------------
identical calls : 12
DISTINCT effects : 12
PROVEN DOUBLE-FIRE. 12 byte-identical calls produced 12 DIFFERENT
results. Each distinct result is a separate real execution of one
intended action — the duplicate side effect you cannot take back.It fires only the one tool you name, with the exact arguments you supply — it never enumerates and hammers a server blindly. And it is honest about what it can see: distinct results are undeniable proof of double-execution; identical results are reported as inconclusive from the response, never as a zero it can't prove.
Then re-run the same probe through the fence and watch DISTINCT effects drop
to 1:
effectfence probe --tool charge_card --args '{"amount":4900}' --calls 12 -- effectfence wrap -- npx -y @your-org/your-mcp-serverThat is the whole pitch in two commands: the footprints, then the lock.
Quickstart: wrap an existing MCP server (start here)
The fastest way to use EffectFence is to put it in front of a tool server you already run. Agents don't have to remember to call anything — every tool call is fenced automatically:
agent/client ──MCP──> effectfence wrap ──MCP──> your real tool servercargo install effectfenceThen wrap whatever server owns your dangerous tools:
effectfence wrap -- npx -y @your-org/your-mcp-serverThe tool list is mirrored 1:1 from the child (same names, schemas, docs), so nothing in your agent changes. What changes: identical duplicate calls — same tool, same arguments — execute the child once; later duplicates get the recorded result replayed, and concurrent identical calls are refused rather than double-firing.
One-paste recipe: fence a cluster-mutating server
The case this exists for — several agents with kubectl on the same cluster.
Claude Code:
claude mcp add k8s-fenced -- effectfence wrap -- npx -y kubernetes-mcp-serverCursor (~/.cursor/mcp.json) or Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"k8s-fenced": {
"command": "effectfence",
"args": ["wrap", "--", "npx", "-y", "kubernetes-mcp-server"]
}
}
}Swap kubernetes-mcp-server for whichever server holds your write-bearing tools —
cloud APIs, deploy tooling, a payments server. Point every agent at the fenced name
and remove their access to the raw one; the fence is only a fence if it is the only
door.
Watch it work with fence_stats (see below) — replayed and refused are the
duplicate executions that did not happen.
Honest scope of wrap
Tools only for now (no resource/prompt passthrough). Intent is derived from
hash(tool + canonical args), so byte-identical arguments are treated as the same
action — an agent that varies a timestamp in its arguments defeats dedup, and that
direction fails safe: the call runs, nothing is corrupted. State is in-memory per
wrap process; run one fenced gateway per set of production-mutating tools.
Quickstart: MCP server (explicit fencing)
Use this when you want agents to fence deliberately — richer control (read_set,
parent, known_clock) than wrap derives automatically.
Listed in the official MCP Registry as
mcp-name: io.github.aurumflux20/effectfence
Install
With a Rust toolchain (rustup.rs):
cargo install effectfenceOr build from a clone of this repo:
cargo build --release # binary at ./target/release/effectfenceAdd it to Claude
Claude Code (one command):
claude mcp add effectfence -- effectfence(If you built from source instead of cargo install, use the full path: claude mcp add effectfence -- /path/to/target/release/effectfence.)
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"effectfence": {
"command": "effectfence"
}
}
}Any project (team-shared) — commit a .mcp.json at the project root:
{
"mcpServers": {
"effectfence": {
"command": "effectfence"
}
}
}That's it — no configuration, no environment variables, no accounts. The server holds its fence state in memory for the life of the process.
The tools
It exposes:
fence_prepare—{ intent, domain, tool, args, agent, read_set?, parent?, known_clock? }→{status: "fresh", prepared}when this attempt wins (run the tool, then report back), or{status: "already_done", cert}when this exact action already ran (use the recorded result — do NOT run the tool). Errors mean do not run.fence_commit—{ prepared, result }→{status: "committed", cert}. Later duplicates of the intent now replay this cert.fence_abort—{ prepared, reason }→{status: "aborted"}. The intent stays fenced until reconciled and cleared.fence_stats— no arguments → live counters since the process started:admitted(effects that ran),replayed(duplicates handed a recorded result),refusedbroken out by cause (stale_read_set,domain_race,in_flight,prior_failure), plustotal_attemptsandprevented.preventedis the number that matters: every attempt that did not run the effect.effectfence since boot: admitted=1 replayed=995 refused(stale=0 race=4 in-flight=0 failed=0) total=1000 prevented=999
Tool input schemas are generated automatically from the Rust types (via schemars), so any MCP client can introspect them with tools/list.
Testing
cargo test # unit tests + chaos tests
cargo clippy --all-targetstests/chaos_test.rs uses real OS threads to prove the two guarantees separately: a forced same-instant domain race (synchronization deliberately constructed so the collision is guaranteed, not hoped for) admits exactly one winner every time, and 16 concurrent duplicates of one intent admit exactly one execution — with late duplicates replaying the committed cert. A 32-thread stress test additionally asserts sequence numbers are never double-allocated.
Scan your own MCP server
tools/fencescan.py finds tools in an MCP server that could fire the same effect
twice. No install, no dependencies, no network:
python3 tools/fencescan.py /path/to/your-mcp-serverIt reports candidates with evidence and deliberately renders no verdict, because an outsider reading a repository usually cannot prove a double-fire — the guard often lives in a service the repo calls, or in a sibling SDK, and a tool whose name sounds like a write may only return a payload for someone else to sign. Output includes an explicit list of what it cannot see.
It was rewritten after hand-verification killed 4 of its first 7 "confirmations". Each failure is now a fixed behaviour rather than a caveat:
It got this wrong | Why | Now |
Flagged read-only tools | A flat window after a tool name ran into the next tool, so reads inherited writes' vocabulary | Brace-matched to the tool's own block; a read verb in the name vetoes |
Said a repo had no idempotency when it had a whole module |
| Anchors removed; the same blindness hid |
Found no writes anywhere | Writes live in shared helpers, not in the tool declaration | Collected per repo as corroboration, never claimed as "this tool writes" |
Missed | String literals were stripped before matching, deleting the HTTP verb itself | Matched on the raw line |
Printed "AT RISK" | That is an accusation, and it was wrong 4 times in 7 | No verdict field exists |
If it flags something in your server and you want a second pair of eyes, open an issue — a wrong accusation costs more than a missed one, so a false positive here is worth reporting too.
Sibling project — once (Python)
Same problem, other runtime. once (pip install once-kernel) is the Python idempotency kernel built on the same idea: a side effect runs exactly once under retries, webhook redelivery, and concurrent workers. It goes further on durability — a Postgres store, heartbeat leases with fence tokens so a stale worker can't resurrect after its lease is reclaimed, and RFC 8785 canonical payload fingerprints.
Use EffectFence when your fence lives in Rust or in front of an MCP server; use once when the side effect is Python and you want a durable store. effectfence wrap has been proven fencing once's own MCP server.
Commercial support
The libraries are free and stay free.
Retry Safety Review — $1,200, refunded in full if we find nothing. We read one money path in your codebase and hunt the defect that survives good engineering: not "is there an idempotency key" (most competent teams have one), but what happens when a payment fails ambiguously — the request that timed out after it settled, the retry that mints a fresh nonce, the reservation released on a failure that wasn't one. Five working days, written report tied to your own file and line numbers, no calls.
It's the class of defect we hunt in public: hpp-io/x402-mcp-bridge shipped two
fixes from our findings, mcp-server-kibana merged two PRs. Details in
SUPPORT.md. To start: book it and reply to the
receipt with the repository and which money path matters most — or email
hello@aurumflux.co first if you'd rather talk it through.
If it isn't a fit we'll say so — and if we don't think we can find anything, we say that instead of billing you for a clean bill of health.
License
MIT — see LICENSE.
Available Tools
3 toolsfence_abortA
Report that a prepared effect failed or its outcome is unknown. The intent stays fenced -- later fence_prepare calls with the same intent are rejected instead of silently re-running an action whose side effect may have fired -- until an operator reconciles with the downstream system and clears it.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | Why the effect failed (or why its outcome is unknown). | |
| prepared | Yes | The prepared-effect ticket returned by a prior `fence_prepare` call, passed back verbatim. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden. It discloses the key behavioral trait: the intent remains fenced and subsequent fence_prepare calls for the same intent are rejected, preventing silent re-execution after a possible side effect. This adds crucial context beyond the schema's data definitions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the primary purpose and followed by the critical consequence. No filler or repetition; every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the purpose and the significant blocking behavior, making it clear when to call and what will happen. It doesn't mention return values or explicit preconditions like a prior fence_prepare call, though those are implied by the 'prepared' parameter and the fencing behavior. Slightly more detail on the expected response or error cases would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both parameters, and the description adds no additional parameter semantics beyond what the schema already provides. The baseline for high coverage is 3, and the description does not compensate with extra param-level detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states it 'Report[s] that a prepared effect failed or its outcome is unknown,' naming a specific action and resource. This clearly distinguishes the tool from siblings by contrasting with commit/prepare semantics.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly defines when to use: when 'a prepared effect failed or its outcome is unknown.' The description also explains the consequence of using it (intent stays fenced, later fence_prepare calls rejected), but it does not explicitly name fence_commit as the success-path alternative, leaving the contrast implicit rather than fully explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fence_commitA
Report that a prepared effect finished, and mint its content-addressed EffectCert. Re-validates the read set one more time; if a dependency moved while the effect was running, the commit is rejected AND the intent is fenced as failed (the effect did run -- reconcile before retrying). On success, later fence_prepare calls with the same intent replay this cert instead of re-running the action.
| Name | Required | Description | Default |
|---|---|---|---|
| result | No | The actual result of running the tool/effect. | |
| prepared | Yes | The prepared-effect ticket returned by a prior `fence_prepare` call, passed back verbatim. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does well. It discloses the re-validation of the read set, the rejection and fencing of the intent on conflict, and the replay behavior on success, which are critical side effects for an agent to know.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no waste. Each sentence conveys distinct information: the purpose and the two behavioral outcomes (rejection/fencing on conflict, replay on success).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's purpose, failure condition, side effect on the intent, and success behavior, making it complete for a two-parameter tool with a rich schema and workflow context. No output schema exists, but return values aren't necessary to describe given the description's depth.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description doesn't add detail beyond the schema's property descriptions for 'prepared' and 'result', but the schema already explains that prepared is the ticket from a prior call and result is the actual tool output.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Report that a prepared effect finished, and mint its content-addressed EffectCert.' This distinguishes it from siblings fence_prepare and fence_abort by covering the commit/terminal success step in the workflow.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description says to use this after a prepared effect has finished, and clarifies that if a dependency moved, the commit is rejected and the intent is fenced as failed. It also explains that successful commits cause later fence_prepare calls to replay the cert, which gives clear usage context, though it doesn't explicitly mention alternatives like fence_abort.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fence_prepareA
Ask permission to run a side-effecting tool call. intent is a stable id for the logical action (e.g. charge:order-123) -- attempts sharing an intent are the SAME action and only one will ever execute. Returns {status:'fresh', prepared} when this attempt wins (run the tool, then call fence_commit or fence_abort with the ticket), or {status:'already_done', cert} when this exact action already ran (use the recorded result; do NOT run the tool). Errors mean do not run: another attempt is in flight, a previous attempt failed (reconcile first), a dependency changed (ReadSetStale), or a same-instant race was lost (DomainRace).
| Name | Required | Description | Default |
|---|---|---|---|
| args | No | Arbitrary JSON arguments for the tool call being fenced. | |
| tool | Yes | Name of the tool/effect being fenced, e.g. `"charge_card"`. | |
| agent | Yes | Identifier of the calling agent. | |
| domain | Yes | The contention scope this effect will act on, e.g. `"order:123"`. | |
| intent | Yes | Stable identifier for the logical action, e.g. `"charge:order-123"`. Attempts sharing an intent are the SAME action: only one ever executes; later attempts get the recorded outcome replayed. Mint a new intent only for a genuinely new action. | |
| parent | No | Hex SHA-256 hash of the effect certificate this one causally follows. Omit for a genesis effect with no prior cause. | |
| read_set | No | Other domains this decision cross-checked, and the sequence observed for each. Do not include `domain` itself here — its own sequence is about to be advanced by the reservation, so an entry for it would go stale the instant that happens. Same-domain lineage belongs in `parent`. | |
| known_clock | No | The calling agent's current view of causal history. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses idempotency semantics, single-execution guarantees, replay behavior, and four distinct failure modes. This is exactly the behavioral context needed for a fencing primitive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three focused sentences covering purpose, return states, and error handling. No filler; every clause serves a decision the agent must make.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the description fully captures usage protocol, including consequences for each outcome and required follow-up actions (fence_commit/fence_abort). Output schema absent, but return values are described in prose.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers all 8 parameters with descriptions (100% coverage), so baseline 3 applies. Description reinforces intent's stable-id semantics but doesn't add new parameter-specific detail beyond schema; the protocol context (fresh/already_done) supplies useful surrounding semantics but not per-parameter meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description uses a specific verb ('Ask permission') and identifies the resource (side-effecting tool call execution). It clearly differentiates from sibling tools fence_commit/fence_abort by framing this as the preparation/reservation step.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Description explicitly specifies action based on return: on fresh, run then call fence_commit/fence_abort; on already_done, do NOT run; on errors, do not run and reconcile. It names error types for further guidance, making it superior for an agent to decide when to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
3 tool updates
v0.1.4- Changed
fence_abort2 fields changed- changed
Input schema / $defs / PreparedEffect / properties / argsPrevious value: -trueNew value: +{ + "additionalProperties": true, + "type": [ + "object", + "null" + ] +} - changed
Input schema / $defs / PreparedEffect / requiredPrevious value: -[ - "intent", - "domain", - "seq", - "tool", - "args", - "vector_clock", - "read_set", - "agent" -]New value: +[ + "intent", + "domain", + "seq", + "tool", + "vector_clock", + "read_set", + "agent" +]
- Changed
fence_commit3 fields changed- changed
Input schema / $defs / PreparedEffect / properties / argsPrevious value: -trueNew value: +{ + "additionalProperties": true, + "type": [ + "object", + "null" + ] +} - changed
Input schema / $defs / PreparedEffect / requiredPrevious value: -[ - "intent", - "domain", - "seq", - "tool", - "args", - "vector_clock", - "read_set", - "agent" -]New value: +[ + "intent", + "domain", + "seq", + "tool", + "vector_clock", + "read_set", + "agent" +] - added
Input schema / properties / result / typeAdded value: +[ + "object", + "array", + "string", + "number", + "boolean", + "null" +]
- Changed
fence_prepare2 fields changed- added
Input schema / properties / args / additionalPropertiesAdded value: +true - added
Input schema / properties / args / typeAdded value: +[ + "object", + "null" +]
3 tool updates
v0.1.3- First observed
fence_abort - First observed
fence_commit - First observed
fence_prepare
TDQS
Each tool has a distinct role in the effect lifecycle: prepare initiates, commit reports success, abort reports failure. There is no overlap or ambiguity among them.
All tool names follow the consistent pattern 'fence_' + verb (prepare, commit, abort). This is uniform and predictable.
Three tools is precisely right for the narrow, well-defined domain of effect fencing. Each tool is necessary and none is superfluous.
The set covers the full lifecycle: prepare to request permission, commit for success, abort for failure. There are no obvious gaps for the stated purpose.
Maintenance
Related MCP Connectors
Prevent duplicate AI-agent side effects with idempotency, verification, and durable receipts.
Payment-rail-independent intent-to-effect integrity for consequential agent actions.
An effect gate for AI agents: at-most-once side effects, spend limits, and signed receipts.
- llm-busOAuthcom.llm-bus
Coordinate multiple AI agents over MCP: atomic claims, leases, shared ledger, handoffs, tasks.
Related MCP Servers
- AlicenseAqualityAmaintenancePost-quantum, tamper-evident receipts for consequential agent actions. Provides tools for auditing, gating decisions, and egress classification with quantum-hardened security.7Apache 2.0
- FlicenseNot gradedqualityBmaintenanceMCP server that prevents duplicate side effects in AI agents by using idempotency keys and durable receipts, ensuring actions like refunds, emails, or orders execute exactly once even across retries.-
- AlicenseNot gradedqualityAmaintenanceProvides AI agents with a transparent proxy and journal for every tool action, including pre-state snapshots and approval gates for risky operations. Enables per-action undo, rewind to a point in time, and a kill switch that agents cannot override.15Business Source 1.1
- AlicenseNot gradedqualityCmaintenanceProvides permission gates and tamper-evident audit logging for AI agent tool executions, with declarative policies, consent ladders, and hash-chained verification.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/aurumflux20/effectfence'
If you have feedback or need assistance with the MCP directory API, please join our Discord server