I build LastPing, a monitoring service for cron jobs, CI pipelines and AI agents. It has a remote MCP server with 50 tools, so an agent can create monitors, read failed runs and write notes on incidents.
This week it was listed in Claude's Connectors Directory. Getting there meant rewriting every tool description we had. If you run an MCP server, the lesson applies to you whether or not you ever submit it anywhere.
Tool descriptions are the main thing a model sees about your tool, so over months of watching agents misuse ours, we kept adding instructions to them. When we audited before submitting, 34 of our 50 tools contained text aimed at the model's behaviour rather than at the tool.
Some real examples:
CALL get_monitor FIRST and read its routes field
PROPOSE, THEN ASK. Show the user what you found and get their agreement BEFORE calling this.
SEND A NOTE WHETHER OR NOT YOU COULD FIX THE PROBLEM.
If you ARE Claude Code specifically, hook_install is available as an OPTIONAL SHORTCUT...
Every one of these was added for a good reason, usually after an agent did something wrong. Together they turned the tool list into a second system prompt that nobody had approved.
Anthropic's directory policy boils down to this for tool descriptions:
The submission form even asks you to attest that your descriptions "contain no instructions about model behavior, other tools, or external instruction sources".
Reading that, our first worry was: if we delete the instructions, do agents get worse?
It turned out almost every instruction was hiding a fact that the model needed. The fix was to state the fact and let the model decide what to do with it.
Before:
THIS REPLACES THE WHOLE SET for that event type β every destination you leave out stops receiving that event. CALL get_monitor FIRST and read its routes field.
After:
Replaces the whole destination set for that event type: destinations not listed stop receiving it, including ones someone else configured. get_monitor's routes field holds the current set, so adding a destination means sending the existing ids plus the new one.
Same safety property. The model still learns that a partial list deletes routing, and where the current list lives. It's just no longer being ordered around.
PROPOSE, THEN ASK. Show the user what you found and get their agreement BEFORE calling this β it CREATES monitors.
Creates one monitor per source not already monitored; never deletes, s or edits existing monitors, so a scheduled re-run is safe drift detection.
The tool is also annotated as a write tool. Whether to confirm with the user first is up to the client and the user's permission settings, not the tool description. The description only has to be honest about what gets created.
Before (for an API key tool): a paragraph about storing the key safely.
Creates an API key. The plaintext key appears only in this result and cannot be retrieved again.
A fact the model can act on, in one sentence.
Our rules of thumb, which we wrote down and applied to every tool and every parameter:
Some guidance genuinely matters. It moved to places where it applies at the right moment:
The difference: a description is read on every request whether the user asked for anything or not. A result or a skill is read when the user asked for it.
One tool, the one that returns setup instructions, produced 65,283 characters per call. Most of it was installation details for coding agents the caller wasn't using.
Now it returns the client-specific install only when the caller names its client (a tool parameter). The default response dropped to about 24,000 characters, roughly a third. Nothing was removed; it's just not sent to clients that can't use it.
Descriptions drift. Someone fixes a bug, adds "IMPORTANT: always..." and you're back where you started.
So we added a test that runs in CI over every registered tool and every parameter description. It fails on:
We checked the test by putting one of the old phrases back into a real tool and confirming CI went red. Plus a positive companion test, so an empty description list can't pass by accident.
This was the real fear. We ran the same tasks through Claude with the old descriptions and the new ones, using MCP tools only, and compared what it did: creating monitors from a description, wiring alerts, reading a failed run and writing a note back.
Behaviour was the same. The tasks that worked before still worked, including the ones the old instructions were added to protect. In hindsight that makes sense: the model needed the facts, not the shouting.
We submitted, and the automated review approved LastPing as a Community connector the same day. It's now at claude.ai/directory/lastping.
Even if you never submit to a directory:
I build LastPing. It watches cron jobs, CI pipelines and AI agents and tells you when they fail, stall or go quiet, and it's free for individuals. If you use Claude: Settings β Connectors β Discover β "LastPing". Other clients: lastping.dev/mcp.