| The agent sees | The agent never sees |
|---|
| Tool name | Your source code |
| Description | Your intentions |
| Input schema | Your internal docs |
Spine of the lesson: to the model, the description is the tool.
| Part | States | Example cue |
|---|
| Purpose | The job, one plain sentence | ”Return the stock count for one product” |
| Inputs | Meaning and format of each parameter | ”exact SKU, for example RACK-CT-114” |
| Output | Shape of the result, incl. empty case | ”count, shelf location, last delivery” |
| Boundaries | What it will not do | ”read-only, never changes stock” |
| Siblings | When to use it vs named neighbors | ”for keywords, use inventory_search_catalog” |
Imagined reader: a new hire who can ask no follow-up questions.
| Smell | Fix |
|---|
| One tool, action parameter, many modes | Split along jobs, one strict contract each |
| Agent always chains the same 3 calls | Merge them into one job-shaped tool |
| One tool per backend endpoint | The unit is the agent’s job, not your API’s history |
| Rule | Why |
|---|
Shared prefix per server (inventory_) | Clusters tools; no cross-server confusion |
| Sibling names non-interchangeable | Names narrow selection before descriptions |
| Cover test: names alone, colleague picks right | If they hesitate, rename |
| Case | Retry helps? | The error must say |
|---|
| Transient (timeout, upstream down) | Yes, likely | Retry shortly; what is unaffected |
| Business-rule refusal | Never | Which rule; what would work instead |
| Permission problem | Never | Needs different caller or human sign-off |
| Empty result | Not an error | Query succeeded; zero matches is the answer |
Never confuse: “the query failed” with “the query succeeded and found nothing.”
| Principle | Effect |
|---|
| Only the tools the role needs | Better selection, smaller blast radius |
| Too many or overlapping tools | Degraded strategies, harder choices |
| Tool never granted | A guarantee (instruction is only a request) |
| Primitive | Is | Use for |
|---|
| Tool | Function the model calls (user approval) | Acting on the world |
| Resource | File-like data clients read | Read-only material, e.g. a price list |
| Prompt | Pre-written template | Recurring user tasks |
Python SDK: decorated typed function; the docstring becomes the tool definition the model reads.
| Scope | Who gets it | Where it lives | In version control |
|---|
| Local (default) | You, this project | Home config | No |
| Project | Whole team | .mcp.json in project root | Yes, by design |
| User | You, all projects | Home config | No |
Secrets: committed config references variables, plain (${VAR}) or with a default (${VAR:-default}), in command, args, env, url, and headers. Missing variable with no default fails the load loudly. Project-scoped servers need per-person approval before first use.
| Line | Meaning |
|---|
| The description is the tool | Selection runs on your prose, not your code |
| An error is part of the interface | The agent’s next move is decided by your error text |
| Found nothing is not failed | Empty results are true answers about the world |
| A tool never granted is a guarantee | Least privilege beats instructions |