mcp
17 posts.
-
Never declare a side-effect flag in your tool's inputSchema
A declared boolean `open` flag got auto-filled to true and opened browser tabs all day. Side-effect flags belong in the handler, never in the LLM-visible schema.
-
Your agent's safety gate guards an adapter, not the token
A safety gate inside one tool adapter only binds callers of that adapter. Any route holding the same token skips it. Here's how to find the ungated routes in yours.
-
Your load test measured the watchdog, not the server
A bash wait-plus-backgrounded-curl harness reported 85s and two hangs for a server whose real 4-concurrent latency was 6.5s. Per-request timeouts found it.
-
A parked human-in-the-loop prompt needs a clock, or a restart is your only exit
A workflow menu waited three days for a digit until a gateway restart freed it. Parked asks need a lazy TTL, a mismatch counter, and control words everywhere.
-
Your MCP audit table probably has no producer
The audit table existed since migration 046 and held zero rows for its whole life. What I found instrumenting both MCP client stacks, and three checks for yours.
-
The runs panel said 'No runs recorded yet'. The ledger had every run.
A scheduler wrote a run ledger nobody served, a skill prompt dropped the user's words, and a spawnSync stalled the gateway 9.6 s. Three checks for your own stack.
-
Your message table is storing your UI, not your transcript
Four producers wrote into one turn and two baked HTML into storage. What it took to make the turn receipt a real event, and the SQL to check your own store.
-
A skill that finishes into a tab nobody has open did not finish
Console-mode skills completed into a workbench nobody was looking at. How results got routed to the surface the user is on, and the sibling-tree trap that cost two days.
-
The renderer existed. Nothing on that surface ever called it.
A side panel drew agent plans perfectly and could not run one. Four presses found four bugs a green suite could not see, plus the delivery check that catches them.
-
Prompt injection defense that survives to turn 40
Page text an agent reads can outlive the turn as a stored memory and come back as trusted context. Two invariants: separate fields, and a turn-scoped approval gate.
-
Your agent's tool manifest is a comment until something reads it
A scheduled agent declared six MCP tools, called none of them, and reported ok. Enforcing that declaration at fire time cut selection from 1-of-942 to 1-of-6.
-
Your MCP allowlist controls tool names, not what they return
A read-only MCP profile still returned my cwd and MEMORY.md, because the disclosure was in the result envelope, not the tool list. How to check yours.
-
Every stdio MCP server you spawn inherits your whole .env
A host that loads .env into its own process hands every credential to every stdio tool server it spawns. Per-server env config was a no-op. How to check yours in five minutes.
-
Two tables both called 'skill', and nothing knew which was which
Vodou had 160 file skills and 15 console skills sharing one word. Every feature picked a table and called it the truth. Here is the seam and how to find yours.
-
Your agent's approval gate is probably just a warning label
We shipped plan cards, real parallel tool calls and an approval gate for an MCP agent. The gate was decoration for two days, and the fan was never parallel.
-
Every copy of the rule agreed. That was the bug.
Four surfaces minted the same token four different ways, and all four agreed. How we found the drift, why the tests couldn't see it, and the guard that now can.
-
Node execFile was 2.7x slower: the spawn cost nothing
Two implementations of the same memory lookup, one over a Unix socket and one shelling out to a CLI. I blamed the subprocess. The timing block said otherwise.