Skip to main content
Home/Blog/Claude Code: MCP, Subagents, Skills & Hooks — When to Use Which
Developer Tools

Claude Code: MCP, Subagents, Skills & Hooks — When to Use Which

MCP, subagents, skills, and hooks all extend Claude Code, but they solve different problems. Here's a practical decision guide for picking the right mechanism — and combining them.

By Sean

If you've spent any real time in Claude Code, you've hit the moment where you want it to do more: reach a database it can't see, stop polluting your conversation with 40 file reads, remember a workflow you keep retyping, or guarantee it never runs rm -rf on the wrong directory. There are four mechanisms for that — MCP servers, subagents, skills, and hooks — and they're easy to confuse because the docs introduce them all at once.

The confusion is costly. Reach for an MCP server when you needed a skill and you've bolted on an external dependency for something that was just knowledge. Put a safety rule in CLAUDE.md when you needed a hook and your "rule" is a suggestion the model can ignore. So before we get into each one, here's the mental model that actually disambiguates them:

A skill changes behavior, a subagent protects context, and an MCP server adds capability — and a hook guarantees an action runs deterministically on an event, regardless of what the model decides to do.

These four are a subset of a larger taxonomy. Claude Code's "Extend Claude Code" docs frame seven layers that plug into different parts of the agentic loop: CLAUDE.md (persistent context), skills, code intelligence/LSP, MCP, subagents, agent teams, and hooks — with plugins as the packaging layer on top. We're focused on the four in the title, but I'll touch CLAUDE.md, agent teams, and plugins where they matter, because picking the right tool often means knowing what it isn't.

MCP servers — when Claude needs external capability

MCP (Model Context Protocol) connects Claude to external services and tools it can't reach on its own: querying a database, posting to Slack, controlling a browser, hitting a third-party API, or touching a filesystem over SSH. If the thing you want lives behind a connection or an auth boundary, that's MCP.

The key distinction from a skill: MCP gives Claude purpose-built tools for an external system, with connection and authentication handled by the server. It is capability, not knowledge.

People worry MCP bloats the context window. It used to be a real concern — third-party guides report a typical multi-server setup consuming tens of thousands of tokens before you type anything (one cites roughly 55,000 for a 5-server, ~58-tool setup, though treat that as illustrative). But the default behavior now is friendlier: at session start only tool names load, full JSON schemas stay deferred until a specific tool is needed, and tool search is on by default so idle MCP tools cost minimal context. Run /mcp to see connection status and per-server token cost. Scope precedence is local > project > user.

Reach for MCP when: you're copying something from a browser tab Claude can't see, or you need live data or actions from an external system.

Subagents — when a side task would flood your context

A subagent is a specialized assistant that runs its own agentic loop in an isolated context window, with a custom system prompt, specific tool access, and independent permissions. It does its work separately and returns only a summary to the main conversation.

The job a subagent does best is context protection. When a side task would dump output you'll never reference again — reading dozens of files, running extensive searches, an exhaustive code review — route it to a subagent so your main window stays clean. Beyond that, subagents let you enforce constraints (limit which tools they can touch), specialize behavior with a focused prompt, reuse configurations across projects, and control cost by routing to a faster, cheaper model like Haiku.

Subagents are Markdown files with YAML frontmatter (or created via /agents). A minimal one:

---
name: code-reviewer
description: Reviews diffs for correctness and style issues
tools: Read, Glob, Grep
model: sonnet
---

You are a focused code reviewer. Read the diff, flag real bugs
and convention violations, and return a concise summary.

Frontmatter supports a lot more — disallowedTools, permissionMode, mcpServers, hooks, skills, maxTurns, memory, model, and others. Files resolve by precedence on name conflict: managed (highest) > CLI flag > project (.claude/agents/) > user (~/.claude/agents/) > plugin (lowest). Identity comes only from the name field. One security note: plugin subagents do not support hooks, mcpServers, or permissionMode — those fields are ignored.

Reach for a subagent when: a side task floods the conversation, you want a worker locked to a small tool set, or you want to run something on a cheaper model.

Skills — packaged, reusable expertise

A skill is a SKILL.md file (YAML frontmatter plus a Markdown body) that adds reusable knowledge, workflows, or instructions to Claude's toolkit. Claude loads it automatically when the task matches its description, or you invoke it directly with /skill-name. The body loads only when used, so long reference material costs almost nothing until needed.

There are two flavors:

  • Reference skills — knowledge Claude uses throughout a session, like an API style guide or your schema docs.
  • Action skills — tell Claude to do something specific, like /deploy running a deployment workflow.

If you've used custom slash commands, note they've been merged into skills: .claude/commands/*.md and skills both create a /name command and work the same way. Skills follow the open Agent Skills standard (agentskills.io) that works across multiple AI tools, and Claude Code extends it with a few useful knobs:

  • disable-model-invocation: true makes a skill user-only — zero context cost until you invoke it.
  • context: fork runs the skill in an isolated context (subagent-style execution).

Locations and precedence: personal (~/.claude/skills/<name>/SKILL.md), project (.claude/skills/<name>/SKILL.md), and plugin (<plugin>/skills/<name>/SKILL.md). On a name conflict, enterprise/managed wins over personal, which wins over project. Plugin skills are namespaced plugin-name:skill-name, so they can't collide. The directory name becomes the command; frontmatter requires name and description.

Reach for a skill when: you keep pasting the same playbook, you have reference material Claude should consult, or you've retyped the same prompt enough times to make it a command.

Hooks — deterministic lifecycle automation

Hooks are the odd one out, and the most important to understand. They're user-defined handlers that fire automatically on lifecycle events. The critical property: Claude has no awareness of hooks. The system fires them because an event occurred, not because the model decided to. That's what makes them deterministic — a hook always fires on its event; the trigger is guaranteed. A skill, by contrast, depends on Claude interpreting instructions, and the outcome can vary.

This is why the official guidance is blunt: put guardrails in hooks. An instruction like "never edit .env" in CLAUDE.md or a skill is a request, not a guarantee. A PreToolUse hook that blocks the edit is enforcement. If a rule must hold every time, make it a hook.

Hooks aren't only shell scripts. Handler types include: command (shell), http (call an endpoint), mcp_tool (invoke an MCP tool), prompt (a single-turn LLM evaluation like "is this command safe?"), and agent (a subagent for verification; experimental). So yes — a hook can run an LLM prompt or a subagent, not just a script.

Events span session, per-turn, agentic-loop, agent/task, and environment phases. The ones you'll touch most: PreToolUse (can block a call), PostToolUse, UserPromptSubmit, Stop, SubagentStop, SessionStart, SessionEnd. There are many more (PermissionRequest, PreCompact/PostCompact, FileChanged, Notification, and others). Reported total counts vary by source — you'll see "12," "18," "30" depending on whether it's CLI-only or shared with the Agent SDK, so don't anchor on a single number.

Config is JSON with three nesting levels — event, matcher, handlers:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "./scripts/block-rm-rf.sh" }
        ]
      }
    ]
  }
}

Matchers can be a tool name (Bash), an alternation (Edit|Write), *, or a regex (mcp__memory__.*). Config lives in ~/.claude/settings.json (all projects), .claude/settings.json (project, shareable), .claude/settings.local.json (gitignored), plugin hooks/hooks.json, skill/agent frontmatter, or managed policy. Exit codes matter: 0 = success, 2 = blocking error (stderr is shown to Claude), any other non-zero = non-blocking.

Reach for a hook when: you want something to happen on every matching event without asking — linting after edits, blocking unsafe commands, logging, notifications, format-on-save — or you need to enforce a hard rule.

The decision guide

The fastest way to choose is to match the trigger you're feeling to the mechanism. The official "build your setup over time" framing maps cleanly:

You notice...Reach for
A convention Claude gets wrong twiceCLAUDE.md rule
Retyping the same promptA user-invocable skill
Pasting the same playbook a third timeA skill
Copying from a browser tab Claude can't seeAn MCP server
A side task flooding the conversationA subagent
Wanting something to happen every time, no askingA hook
A second repo needing the same setupA plugin

And the context-cost cheat sheet, since that drives a lot of real decisions:

MechanismContext cost
CLAUDE.mdFull content, every request
SkillDescription at start; body when used (low)
MCPTool names at start; schemas on demand (low until used)
SubagentIsolated — never touches main window
HookZero unless it returns output

Combine, don't choose

The most common mistake is treating these as either/or. They're complementary. The combinations worth knowing:

  • MCP + skill — MCP connects Claude to your database; a skill documents the schema and your common query patterns. Capability plus the knowledge to use it well.
  • Subagent + skill — an isolated worker that preloads your conventions via its skills: field, optionally on a cheaper model with a scoped MCP server for live data.
  • Skill in a fork — a skill with context: fork runs subagent-style, getting isolation without a separate agent file.

When parallel subagents stop being enough — you hit context limits or they need to talk to each other — that's the signal to graduate to agent teams (independent sessions that self-coordinate; experimental, off by default). And when you want to ship any combination of these across repos or to your team, that's what plugins are for: one installable unit bundling skills, hooks, subagents, and MCP servers, distributed via marketplaces.

Bottom line

Don't overthink which "category" a need falls into — name the trigger. Need external data or actions? MCP. Drowning your context in throwaway output? Subagent. Repeating knowledge or a workflow? Skill. Need a rule enforced every single time, no matter what the model thinks? Hook — because in CLAUDE.md it's a polite request, and in a PreToolUse hook it's a guarantee.

A sane starting setup looks like one short CLAUDE.md, a scoped MCP config with only the servers you actually use, one safety hook, one reusable skill for repeated work, and subagents only when research or review would pollute your main session. Build from there as the triggers show up — and resist the giant plugin pile.

Frequently Asked Questions

Find answers to common questions

A skill is reusable content (knowledge or a workflow) that loads into your current context and adds to your main window. A subagent is an isolated worker that runs in its own context window and only returns a summary. Use a skill when you want Claude to know something or run a repeatable task in the main session; use a subagent when a side task would flood the conversation with output you won't reference again. They combine: a subagent can preload skills, and a skill can run in an isolated fork.

MCP gives Claude purpose-built tools for an external system, with connection and auth handled by the server — use it when Claude needs external data or actions it can't reach on its own. A skill gives Claude knowledge about how to use those tools effectively plus invocable workflows. The canonical pattern is both together: MCP connects Claude to your database, and a skill documents your schema and common query patterns.

Use a hook when a rule must hold every time, deterministically. An instruction like 'never edit .env' in CLAUDE.md or a skill is a request, not a guarantee — Claude interprets it and the outcome can vary. A PreToolUse hook that blocks the edit is enforcement. If a rule must always fire, make it a hook.

Hooks fire automatically. Claude has no awareness that hooks exist — the system fires them because a lifecycle event occurred, not because Claude reasoned about it. That is exactly what makes hooks deterministic: the trigger is guaranteed, unlike a prompt instruction the model might skip.

Per the official comparison: CLAUDE.md loads its full content every request. Skills load only their descriptions at session start, and the body loads when used (low cost). MCP loads tool names at start with schemas deferred until a tool is needed (low until used). Subagents run in isolated context, so their work never touches your main window. Hooks load nothing and cost zero unless they return output. Run /mcp to see per-server token cost.

Yes — they are complementary, not mutually exclusive. The recommended patterns: MCP plus a skill (tools plus knowledge of how to use them), and a subagent plus a skill (an isolated worker that preloads your conventions). A common composition is a subagent on a cheaper model with a preloaded skill for conventions and a scoped MCP server for live data.

They are the same thing now. Custom slash commands (.claude/commands/*.md) have been merged into skills. Both create a /name command and work identically. A skill can be auto-invoked when its description matches the task, invoked directly as /skill-name, or made user-only with disable-model-invocation so it costs zero context until you call it.

Subagents run inside your session and report only to the main agent, with lower token cost and summarized results. Agent teams are independent sessions whose members message each other and self-coordinate via a shared task list, at higher cost. Move from parallel subagents to agent teams when you hit context limits or when subagents need to talk to each other. Agent teams are experimental and disabled by default.

Building Something Great?

Our development team builds secure, scalable applications. From APIs to full platforms, we turn your ideas into production-ready software.