MCP When and How
Handbook: Add tools without turning agents into confused deputies
Repo anchors:content/mcps/README.md·content/mcps/version-control/github.mcp.md·pre-tool-call.hook.sh
Version: 1.0 | Updated: 2026-07-16
Purpose
Decide when an MCP server belongs in an agent’s tool belt, how to scope auth and effects, and how to keep tool definitions agent-optimized. This chapter is a decision playbook — not a dump of every integration under content/mcps/.
Why
MCP solves the M×N integration problem (models × tools → models + servers). Teams then recreate the failure mode MCP was meant to avoid:
| Mistake | Consequence |
|---|---|
| Register every API as a tool | Context bloat; worse routing |
| Broad PAT “for convenience” | Prompt injection → exfiltration / write abuse |
| Thin REST wrappers | Human API docs, not agent affordances |
| No audit of tool I/O | Irreproducible incidents |
| MCP before workflow clarity | Agents thrash tools instead of reading the plan |
OAIES principles (content/mcps/README.md): design for the agent, least privilege, avoid context bloat, validate untrusted inputs, audit every call.
Decision model — when to add MCP
Add MCP when the agent repeatedly needs structured, live access (issues, PRs, incidents, metrics) and copy-paste context is slower or wronger than a tool call.
Do not add MCP when the data is already in the context package, the effect is one-off for humans (click the UI), or you cannot fund auth, audit, and rate limits.
How
1. Start with one high-value, read-mostly server
Canonical deep example: github.mcp.md.
Minimum scopes (read path): repo:read, issues:read.
Write scopes only when the workflow requires them: issues:write, pull_requests:write, contents:write.
Prefer GitHub App installation tokens (short-lived, repo-scoped) over long-lived PATs. Threat model from the spec:
| Threat | Mitigation |
|---|---|
| Token exfiltration via prompt injection | Short-lived App tokens; minimal scopes |
| Unauthorized repo access | Restrict installation to named repos |
| SSRF via URLs | Allowlist destinations before fetch |
2. Design tools for agent reasoning, not API docs
From the MCP README:
| Bad (API-shaped) | Good (agent-shaped) |
|---|---|
POST /api/v2/issues |
create_issue — when to use, required fields |
| Dump 40 endpoints | Cap ~10–15 tools per server |
GitHub tools that earn their seat: search_issues, get_issue, get_pull_request, search_code, and only then create_issue if write is approved.
3. Bind high effects to hooks
MCP expands the blast radius of every prompt-injection success. Pair tool execution with pre-tool-call.hook.sh and post-tool-call.hook.sh:
- Low effect (read issue): may proceed under session policy.
- High effect (
deployment,workspace-write,contents:write): require approval evidence matching effect and target.
4. Progressive disclosure of the catalog
The library lists many integrations (GitHub, GitLab, Azure DevOps, Playwright, Jira, Linear, Slack, Datadog, Postgres, …). Do not load them all. Org adoption order that usually works:
| Phase | MCP class | Why first |
|---|---|---|
| 1 | Version control (GitHub) | Story/PR context is the daily loop |
| 2 | Browser testing (Playwright) when UI-heavy | Replaces flaky “describe the bug” |
| 3 | Observability (Sentry/Datadog) for on-call agents | Needs stricter auth |
| 4 | Project management / chat | High noise; easy to spam |
| 5 | Infrastructure data (Postgres/K8s) | Highest blast radius — read-only default |
Full inventory and security checklist: content/mcps/README.md. Spec format for any new server lives there — copy it; do not invent a parallel template.
5. Auth and operational controls (every production MCP)
Before production:
- OAuth 2.1 or rotating API key / App tokens
- Tool execution restricted by user/session permissions
- Input validation (type, length, patterns)
- Output filtering for secrets/PII
- Rate limits per user/session
- Audit log of tool calls
- Least privilege on the server identity
- SSRF protection on outbound fetches
6. Auth risk register (teach these, not “use OAuth”)
| Risk | How it shows up | Control |
|---|---|---|
| Long-lived PAT in agent env | Issue comment injection → create_issue / contents:write |
GitHub App install tokens; revoke on suspicion |
| Over-scoped token | Agent can push to repos the user cannot | Mirror human ACL; repo allowlist |
| Tool result poisoning | Malicious issue body becomes “instructions” | Treat tool output as data; never concatenate into system policy |
| Confused deputy | MCP server acts with server identity, not user | Per-user OAuth; deny server-wide write for multi-tenant agents |
| Shadow MCP | Engineer installs unlisted community server | Catalog admission (operating-model.md) |
| Rate-limit thrash | Agent loops search_code |
Cap tools; backoff; prefer filesystem read for known paths (github.mcp.md anti-pattern) |
7. Profile matrix — same MCP, different blast radius
| Agent profile | GitHub tools enabled | Auth | Hook gate |
|---|---|---|---|
| Planner | get_issue, search_issues, search_code (sparingly) |
Read-only App token | Optional for reads |
| Coding assist | + filesystem; no contents:write via MCP |
Read-only | Workspace writes via local tools + pre-code |
| Release bot | get_pull_request + approved write set |
Write scopes + short TTL | pre-tool-call mandatory |
| On-call | Usually not GitHub write; observability MCP instead | Separate identity | High-effect only with approval |
One server binary can power all four profiles; tool allowlists differ. That is how you avoid “we installed GitHub MCP” becoming “every agent can push main.”
8. When MCP is the wrong tool
| Need | Prefer instead |
|---|---|
| Known file contents | Context package / filesystem read |
| Stable architecture rules | Versioned skill (content/03-skill-engineering/) |
| One-time human click | Human does it; agent drafts the checklist |
| Bulk analytics over tickets | Offline export + eval dataset, not live tool spam |
| Secrets or prod DB mutation | Break-glass human runbook — not agent MCP |
Worked example — GitHub MCP for issue → plan (no write)
Situation. Engineer: “Look at issue #456 and draft an implementation plan.” Agent should not create branches or commits yet.
Config.
- Enable GitHub MCP with read-only scopes.
- Disable
create_issue/ write tools in this profile, or gate them behind approval. - Context package still includes repo paths and DoR (
definition-of-ready.md).
Agent sequence (from github.mcp.md):
get_issue(repository, 456)— full body + comments.search_code(...)— only if pattern location unknown; respect code-search rate limits.search_issues(...)— related/duplicate check.- Produce plan via
implementation-plan.prompt.md— no further MCP writes. - Human approves plan; coding proceeds under hooks, not under
contents:writeMCP.
Failure you avoid. Agent with contents:write “helpfully” opens a PR from a half-baked plan after a poisoned issue comment. Read-only profile + plan HITL stops that.
Worked example B — enabling write the hard way
Only after plan approval:
- Switch session profile to “release” or open a new session with write tools — do not silently escalate mid-chat.
- Create approval evidence:
effectmatching the MCP write class,target=owner/repo#pr-or-path. - Run
pre-tool-call.hook.sh; on exit70, stop. - Invoke the write tool; log I/O; run post-tool evidence.
- Add an adversarial eval case if the write path is novel (
eval/datasets/v1/adversarial.jsonl).
If the team cannot do steps 2–4, they are not ready for write MCP.
Tradeoffs
| Choice | Gain | Cost |
|---|---|---|
| MCP vs bespoke plugins | Portable tool surface | Another auth + audit surface |
| Few tools vs full API mirror | Better agent routing | Less one-shot coverage |
| App tokens vs PAT | Shorter blast radius | Setup overhead |
| Read-only default | Safer under injection | Extra step to enable writes |
| Loading all catalog servers | “Complete” IDE | Context collapse; confused tool choice |
Anti-patterns
| Anti-pattern | Why it fails |
|---|---|
| Dumping all ~24 MCP specs into every agent | Tool-selection failure; token waste |
Using search_code as a file browser |
Hits strict rate limits; wrong abstraction |
Putting secrets/PII in create_issue bodies |
Permanent leak in GitHub |
Broad repo PAT in developer laptops for agents |
Prompt injection becomes breach |
MCP write tools without pre-tool-call |
Side effects without evidence |
| Treating MCP as a substitute for a context package | Tools ≠ curated requirements/architecture |
| Thin wrappers with human-oriented descriptions | Model misroutes or over-calls |
Enterprise considerations
- Confused deputy. The MCP server identity must not exceed the human user’s authorization. Map session user → downstream scopes.
- Data residency. Tool responses may leave region; route through approved processors.
- Provider catalog. Admit MCP servers like models: qualification, owner, expiry (
operating-model.md). - Incident response. On suspected injection, revoke App installation / rotate tokens, preserve audit logs, add adversarial eval cases (
eval/datasets/v1/adversarial.jsonl). - Procurement. Prefer servers with clear threat models (as in
github.mcp.md) over anonymous community binaries for production.
Checklist
- Workflow is clear before MCP is added
- Decision tree answered: need live state/effects → approved path → ≤15 tools → auth ready
- Production server has agent-optimized descriptions
- Least privilege documented (read vs write scopes)
- High-effect tools gated by hooks + human approval
- Audit logging and rate limits enabled
- Adversarial input tests (injection, path traversal, SSRF)
- Catalog admission owner and review date named
- Engineers know when not to call MCP (local file already known)
- GitHub (or VCS) profile starts read-only for planning agents
Repo map
| Concern | Path |
|---|---|
| MCP library + principles | content/mcps/README.md |
| GitHub reference spec | content/mcps/version-control/github.mcp.md |
| Tool call gates | content/04-agent-engineering/hooks/pre-tool-call.hook.sh |
| Post tool evidence | content/04-agent-engineering/hooks/post-tool-call.hook.sh |
| Org operating model | content/10-ai-org-playbook/governance/operating-model.md |
| Adversarial eval partition | eval/datasets/v1/adversarial.jsonl |
Changelog
- 2026-07-16: Initial handbook chapter — when/how to add MCP, auth risks, GitHub worked example.