{"slug": "mcp-subagents-and-hooks-in-claude-code-the-guide-i-wish-i-d-had", "title": "MCP, Subagents, and Hooks in Claude Code: The Guide I Wish I'd Had", "summary": "A developer's guide to extending Claude Code with MCP servers, subagents, and hooks details how to connect external services, manage scopes, and create custom subagents. The guide covers adding MCP servers via CLI or .mcp.json, authentication flows, and using built-in subagents like Explore and Plan, with practical examples for tools like Playwright and Sentry.", "body_md": "*Originally published on El Rack — Spanish tech reviews from a sysadmin/homelab perspective.*\n\nClaude Code is capable right out of the box, but it starts to feel thin the moment your project needs to touch external systems: a ticket tracker, a database, your own VPS. This guide covers the four pieces that turn it into a real production tool:\n\n`/mcp`\n\n): connecting external services as toolsYou'll need Claude Code installed and authenticated, and a terminal open in any project folder.\n\nMCP (Model Context Protocol) lets Claude Code use tools it doesn't ship with by default. Those tools live in MCP servers: local processes or hosted services reachable over a URL. You add them with `claude mcp add`\n\n, no hand-editing JSON required. Start with the official docs server — it needs no account and no config:\n\n```\nclaude mcp add --transport http claude-code-docs https://code.claude.com/docs/mcp\n```\n\nConfirm it connected:\n\n```\nclaude mcp list\n```\n\nYou should see `✔ Connected`\n\n. From inside a session, manage servers any time with `/mcp`\n\n.\n\nA stdio server is a program Claude Code launches as a subprocess — useful when it needs access to your filesystem or a browser. Example with Playwright, which requires no account:\n\n```\nclaude mcp add playwright -- npx -y @playwright/mcp@latest\n```\n\nThe `--`\n\nseparates Claude Code's own flags from the command that starts the server. For services that require sign-in (Sentry, Linear, Notion, GitHub), you add them the same way and authenticate from inside the session:\n\n```\nclaude mcp add --transport http sentry https://mcp.sentry.dev/mcp\n```\n\nAfter adding, you'll see `! Needs authentication`\n\n. Start a session, run `/mcp`\n\n, select the server, and choose \"Authenticate\" — your browser opens for sign-in.\n\nIf the service uses a static token instead of OAuth (common with self-hosted instances), pass it directly:\n\n```\nclaude mcp add --transport http my-server http://my-host:3001/api/mcp --header \"Authorization: Bearer YOUR_TOKEN\"\n```\n\nBy default, every server is registered at \"local\" scope: private to you, active only in the current project. Two alternatives depending on how widely you want to share it:\n\n```\n# Available in all your projects, still private\nclaude mcp add --scope user --transport http claude-code-docs https://code.claude.com/docs/mcp\n\n# Shared with the team via the repo (writes .mcp.json)\nclaude mcp add --scope project --transport http claude-code-docs https://code.claude.com/docs/mcp\n```\n\n| Scope | File | Available to |\n|---|---|---|\n| local |\n`~/.claude.json` (project entry) |\nOnly you, only this project |\n| project |\n`.mcp.json` at the repo root |\nEveryone who clones the repo |\n| user |\n`~/.claude.json` (top-level `mcpServers` ) |\nOnly you, all your projects |\n\nIf you'd rather write `.mcp.json`\n\nby hand to keep it version-controlled with the team:\n\n```\n{\n  \"mcpServers\": {\n    \"claude-code-docs\": {\n      \"type\": \"http\",\n      \"url\": \"https://code.claude.com/docs/mcp\"\n    },\n    \"playwright\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@playwright/mcp@latest\"]\n    }\n  }\n}\n```\n\nA subagent is an instance with its own context, its own system prompt, and its own tools, working in isolation and returning only a summary. It's the fix for two problems: flooding your main conversation with logs or results you won't reuse, and re-spawning the same kind of worker with the same instructions over and over.\n\nClaude Code ships with three built-in subagents: Explore (read-only code search), Plan (research during plan mode), and general-purpose (complex tasks with access to everything). For a custom one, just ask Claude to write it:\n\n```\nCreate a personal subagent in ~/.claude/agents/ called \"code-reviewer\" that\nreviews code for quality, security, and best practices. Make it read-only\nand have it use Sonnet.\n```\n\nClaude writes the file with YAML frontmatter plus the system prompt:\n\n```\n---\nname: code-reviewer\ndescription: Reviews code for quality, security, and best practices. Use after writing or modifying code.\ntools: Read, Grep, Glob\nmodel: sonnet\n---\n\nYou are a senior code reviewer. For each issue you find, explain the\nproblem, show the current code, and provide an improved version.\n```\n\nThe most useful frontmatter fields: `tools`\n\n(allowlist), `disallowedTools`\n\n(denylist), `model`\n\n(sonnet/opus/haiku/inherit), and `mcpServers`\n\n(gives an MCP server to that subagent alone, without loading its context into the main conversation).\n\nSave it in `.claude/agents/`\n\nto scope it to this project, or `~/.claude/agents/`\n\nto make it available everywhere.\n\nThere are three ways to use a subagent, from least to most explicit:\n\n```\n# Natural language: Claude decides whether to delegate\nUse the code-reviewer subagent to review my recent changes\n\n# @-mention: forces that specific subagent to run\n@\"code-reviewer (agent)\" review the authentication logic\n\n# Run the whole session as that subagent (its system prompt and tools)\nclaude --agent code-reviewer\n```\n\nFor independent investigations, you can request several subagents in parallel:\n\n```\nResearch the authentication, database, and API modules in parallel using\nseparate subagents\n```\n\nEach one explores its own area in isolation; you only get the synthesized summary back in your main conversation.\n\nIf you type the same instruction over and over, turn it into a command. Classic commands (`.claude/commands/*.md`\n\n) still work, but the recommended approach now is Skills (`.claude/skills/<name>/SKILL.md`\n\n) — if a command and a skill share a name, the skill wins.\n\nClassic command, saved as `.claude/commands/audit-disk.md`\n\n:\n\n```\n---\ndescription: Disk space audit with a configurable threshold\nallowed-tools: Read, Bash, Grep\nargument-hint: [threshold-percentage]\n---\n\nAudit disk space across the servers. Alert threshold: $ARGUMENTS%.\n```\n\nInvoke it with `/audit-disk 85`\n\n. `$ARGUMENTS`\n\ncaptures everything typed after the command; `!` command``\n\ninjects live shell output (e.g. `!` git diff --cached``\n\n).\n\nSame idea as a skill, at `.claude/skills/audit-disk/SKILL.md`\n\n:\n\n```\n---\nname: audit-disk\ndescription: Disk space audit with a configurable threshold. Use when the user asks to check disk space on the servers.\nallowed-tools: Read, Bash, Grep\n---\n\nAudit disk space across the servers...\n```\n\nThe advantage of skills: they can bundle several reference files in the same folder, and Claude can invoke them on its own, without you typing the slash.\n\nIf you run in an autonomous mode (`--dangerously-skip-permissions`\n\n), hooks are how you block dangerous operations without relying on the AI remembering a rule. They fire every time, at the exact lifecycle point you define.\n\nThe two most-used events: `PreToolUse`\n\n(before a tool runs — good for blocking) and `PostToolUse`\n\n(after — good for formatting, linting, or logging). Configure them in `settings.json`\n\n:\n\n```\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Bash\",\n        \"hooks\": [\n          { \"type\": \"command\", \"command\": \"./scripts/validate-command.sh\" }\n        ]\n      }\n    ]\n  }\n}\n```\n\nThe script receives the command as JSON via stdin, and exit code 2 blocks the operation. Example that stops an overly broad `pkill`\n\non a server where multiple processes share the same name:\n\n``` bash\n#!/bin/bash\nINPUT=$(cat)\nCOMMAND=$(echo \"$INPUT\" | jq -r '.tool_input.command // empty')\n\nif echo \"$COMMAND\" | grep -qE 'pkill.*node|rm -rf /'; then\n  echo \"Blocked: command too broad or destructive. Use an exact PID.\" >&2\n  exit 2\nfi\n\nexit 0\n```\n\nMake it executable:\n\n```\nchmod +x ./scripts/validate-command.sh\n```\n\nAnother common one: auto-format every file Claude touches, without having to ask:\n\n```\n{\n  \"hooks\": {\n    \"PostToolUse\": [\n      {\n        \"matcher\": \"Write|Edit\",\n        \"hooks\": [\n          { \"type\": \"command\", \"command\": \"npx prettier --write \\\"$CLAUDE_TOOL_INPUT_FILE_PATH\\\"\" }\n        ]\n      }\n    ]\n  }\n}\n```\n\nPut these four pieces together and Claude Code stops being a terminal assistant and becomes a real automation layer: it connects to whatever it needs (MCP), delegates whatever would clutter its context (subagents), packages whatever repeats (skills), and respects hard limits that don't depend on its memory (hooks). Suggested adoption order: start with one low-risk MCP server, add one read-only subagent, migrate your commands to skills whenever you have time, and — the highest-leverage one if you run in autonomous mode — add at least one hook that blocks the operation you're most afraid of running by accident.\n\n*Tutorial by Álvaro Fraguas Bravo for El Rack.*", "url": "https://wpnews.pro/news/mcp-subagents-and-hooks-in-claude-code-the-guide-i-wish-i-d-had", "canonical_source": "https://dev.to/alvarito1983/mcp-subagents-and-hooks-in-claude-code-the-guide-i-wish-id-had-4gg", "published_at": "2026-08-19 08:36:15+00:00", "updated_at": "2026-08-19 08:41:38.624363+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "artificial-intelligence"], "entities": ["Claude Code", "MCP", "Playwright", "Sentry", "Linear", "Notion", "GitHub", "Anthropic"], "alternates": {"html": "https://wpnews.pro/news/mcp-subagents-and-hooks-in-claude-code-the-guide-i-wish-i-d-had", "markdown": "https://wpnews.pro/news/mcp-subagents-and-hooks-in-claude-code-the-guide-i-wish-i-d-had.md", "text": "https://wpnews.pro/news/mcp-subagents-and-hooks-in-claude-code-the-guide-i-wish-i-d-had.txt", "jsonld": "https://wpnews.pro/news/mcp-subagents-and-hooks-in-claude-code-the-guide-i-wish-i-d-had.jsonld"}}