>_

Claude Code Skills vs Plugins vs MCP vs Subagents [2026]

Robin||10 min
claude-codeskillspluginsmcpsubagents
Claude Code skills vs plugins vs MCP servers vs subagents comparison - SKILL.md, plugin.json manifest, .mcp.json, agents directory, model-invoked skills, isolated context window, marketplace install, claude plugin init, Evolving Lite, primeline-ai/evolving-lite

Claude Code skills, plugins, MCP servers and subagents are all described as ways to extend Claude Code, which is why the same question turns up on Reddit three times a month in three different wordings. The names do not tell you which one you need. Worse, three of the four can produce results that look identical from the outside, so picking wrong does not fail loudly. It just costs you a weekend.

The confusion has one cause, and naming it fixes most of the problem: these are not four options on one list. Three of them are things Claude uses, and the fourth is the box you put the others in.

3 + 1capabilities, plus one packaging format
13default locations a plugin can use
0hits for pluginDirectories in the 2.1.233 binary
1of the four that gets its own context window

Why these four get mixed up

They get mixed up because two of them are markdown files with YAML frontmatter that tell Claude how to do something, and from the outside a skill and a subagent both look like "a file that does a task". The real difference is invisible in the file: it is where the work happens and what comes back.

Here is the map I wish someone had handed me.

Three capabilities and one wrapper
PluginThe box. Ships any of the above to someone else, versioned and installable
MCP serverReach. Gives Claude tools for systems outside your codebase
SubagentA worker. Gets its own context window, returns only a summary
SkillInstructions. Loaded on demand into the conversation you are already in

If you remember one sentence from this post, make it this one: a skill spends your context, a subagent protects it, an MCP server extends what Claude can touch, and a plugin is how any of it reaches another machine.

What is a Claude Code skill?

A skill is a SKILL.md file with instructions in it. Claude loads it when it is relevant, or you invoke it directly with /skill-name. Its body costs nothing until it is used, which is what makes it the right home for a long procedure that would otherwise bloat your claude(.)md.

Anthropic's skills documentation is blunt about when to write one: create a skill when you keep pasting the same instructions into chat, or when a section of claude(.)md has grown into a procedure rather than a fact.

The 2026 change most people missed

Custom commands have been merged into skills. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and behave the same way. Existing commands/ files keep working, and the plugin structure table now says outright to use skills/ for new plugins.

So "should this be a slash command or a skill?" is no longer a real question. It is a skill either way. What the skill layout adds is a directory for supporting files, and frontmatter that controls who is allowed to invoke it:

yaml
---
description: Deploy the current branch to staging
disable-model-invocation: true
allowed-tools: Bash(git push *) Bash(gh workflow run *)
---

disable-model-invocation: true means only you can fire it. That is the setting you want on anything with side effects, because you do not want Claude deciding your code looks ready to deploy.

The part that surprises people

When a skill is invoked, its rendered content enters the conversation as a message and stays there. Claude does not re-read the file on later turns, so write standing instructions rather than one-time steps, and remember that a very long skill is context you are now carrying.

It does not persist unconditionally, though, and this is the part I had wrong until I read the lifecycle section properly. Auto-compaction re-attaches only the most recent invocation of each skill, keeps only its first 5,000 tokens, and gives all re-attached skills a combined 25,000-token budget filled newest-first. Invoke enough skills in one session and the early ones are dropped entirely. If a skill seems to stop working after a compaction, re-invoke it.

How is a subagent different from a skill?

A subagent gets its own context window. That is the whole distinction, and everything else follows from it.

A subagent is also a markdown file with frontmatter, living in .claude/agents/ or ~/.claude/agents/. But when Claude delegates to it, the subagent starts fresh: it does not see your conversation history, the files already read, or the skills already invoked. It does its work, and returns only a summary to your conversation. The search results, the logs and the file dumps stay in its context and never reach yours.

Skill
  • -Runs in your current conversation
  • -Its full text stays in your context
  • -Everything it produces lands in front of you
  • -Right when the work needs the conversation
Subagent (non-fork)
  • +Runs in a fresh, isolated context window
  • +Sees no history, unless it is a fork - see below
  • +Returns a summary, keeps the noise
  • +Right when the work would flood your context

There is one exception you should know before you rely on the isolation: a fork. A forked subagent inherits the entire conversation instead of starting fresh. So "sees no history" describes the ordinary subagent, not every subagent.

Read the next part carefully, because the exception is not only something you opt into. Fork mode is on by default in interactive sessions from v2.1.232, and while it is on, Claude can spawn a fork itself by requesting the fork subagent type. You force one deliberately with /subtask, which needs v2.1.212 or later and agent view enabled; with agent view off the command is /fork instead. Either way you are not the only one who can start one. In -p and in the Agent SDK it is off by default, so the same setup behaves differently depending on how the session was launched.

Claude only gets a fork when it explicitly asks for that type. Anything spawned from a definition, an Explore or a custom agent of your own, is still an ordinary isolated subagent. But if your reason for reaching for a subagent was context isolation specifically, that default is worth knowing rather than discovering. Two controls:

bash
CLAUDE_CODE_FORK_SUBAGENT=0    # fork mode off in every session
json
{ "permissions": { "deny": ["Agent(fork)"] } }

The first switches fork mode off entirely. The second leaves it on but stops Claude spawning forks, which is usually the one you actually want. One side effect to expect either way: while fork mode is on, Claude Code runs spawned subagents in the background, forks and ordinary subagents alike.

The practical test is one question: do I want to read everything this produces? If yes, skill. If the useful output is one paragraph sitting on top of two thousand lines of grep results, subagent. That is also the rule behind my scored delegation setup, which decides automatically rather than leaving it to a judgement call every time.

A subagent's frontmatter can restrict its tools, pin its model, cap its turns, and preload specific skills into it. Do not skip the description field: it is what Claude reads to decide whether to delegate at all.

This lives in primeline-ai/evolving-lite - the self-evolving Claude Code plugin. Free, MIT, no build step.

What does an MCP server actually add?

An MCP server adds reach. Skills and subagents change how Claude works with what it already has. An MCP server gives Claude access to something it otherwise could not touch: an issue tracker, a database, a monitoring dashboard, a design file.

The Model Context Protocol is an open standard, so this is not a Claude-specific plugin format. Connect a server when you notice yourself copying data into chat from another tool. Adding one is a single command:

bash
# an HTTP server
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp

# a local stdio server, with an environment variable
claude mcp add my-server -e API_KEY=xxx -- npx my-mcp-server

The thing to keep straight is that an MCP server is not instructions. It does not tell Claude what to do or when. It hands Claude a set of tools and lets Claude decide. If the problem is "Claude does not know your deployment procedure", an MCP server is the wrong answer and a skill is the right one. If the problem is "Claude cannot see your Jira tickets", it is the other way round.

There is a context cost, and it is smaller than it used to be. Tool search is on by default now: Claude Code loads each server's tool names and instructions at session start and defers the parameter schemas until a task actually needs one. I am writing this in a session that works exactly that way, with schemas fetched on demand rather than loaded up front. So the baseline still grows with every server you connect, just far more slowly than when full schemas loaded for everything. Tiering servers is now about keeping your own setup legible rather than heading off an emergency, which is what my post on organising MCP servers by tier covers.

A plugin is a box, not a capability

A plugin does nothing on its own. It is a directory that bundles the other things into one installable, versioned, shareable unit.

Note what is not required: the .claude-plugin/plugin.json manifest is optional. Leave it out and Claude Code auto-discovers components in their default locations and takes the plugin name from the directory. Add one when you need metadata or custom paths. I had this wrong for a while and it matters, because "no manifest" is a perfectly valid plugin rather than a broken one.

One exception, and it is the case most people meet first: a directory under ~/.claude/skills/ needs the manifest to be adopted as a plugin. Without it the directory still loads as a plain skill, it just cannot carry commands, agents or hooks, and it will not appear in claude plugin list.

The plugins reference lists thirteen default locations, and knowing the range is most of what you need to judge whether something should be a plugin at all:

LocationWhat it holds
.claude-plugin/plugin.jsonManifest with metadata and custom paths. Optional
skills/Skills as name/SKILL.md directories
commands/Skills as flat markdown files. The docs say to use skills/ for new plugins
agents/Subagent definitions
workflows/Workflow script files
output-styles/Output style definitions
themes/Colour theme definitions
hooks/hooks.jsonEvent handlers
.mcp.jsonMCP server definitions
.lsp.jsonLanguage server configurations
monitors/monitors.jsonBackground monitors that watch logs or files
bin/Executables added to the Bash tool's PATH while enabled
settings.jsonDefault settings applied when enabled, agent and subagentStatusLine only

One warning worth repeating because it is the most common structural mistake: only plugin.json goes inside .claude-plugin/. Every other directory sits at the plugin root. And the plugin root is the plugin's own directory, never ~/.claude/.

Plugin skills are namespaced, so a hello skill in a plugin called my-tool is /my-tool:hello, and installing a plugin cannot silently shadow a skill you already had. The bare name is registered too, unless something already uses it. One wrinkle: a plugin skill's frontmatter name overrides the directory name, so the command is not always what the folder is called.

If you want the full build walkthrough rather than the decision, I wrote how to build a Claude Code plugin as a step-by-step. The plugin I ship, primeline-ai/evolving-lite, is a working example of the bundle: skills, agents and hooks in one directory.

Which one do I need?

Start from the problem, not the feature. Every row here is a real thing I have wanted at some point.

What you actually wantReach forWhy not the others
Claude to follow a procedure you keep re-explainingSkillA plugin is overkill for one file; an MCP server carries no instructions
A long reference doc available but not always loadedSkillPutting it in claude(.)md pays the cost on every turn
A noisy investigation kept out of your conversationSubagentA skill would dump all of it in front of you
A specialist with restricted tools and its own modelSubagentSkills inherit your tools and your context
Claude to read your issue tracker or databaseMCP serverNo amount of instruction gives Claude access it does not have
To hand your whole setup to a teammatePluginThe others are files on your machine until something packages them
The same setup across several of your own projectsPluginCopying .claude/ between repos is the drift you are trying to avoid
Long work running while you do something elseBackground sessionNot on this list at all, and covered in parallel Claude Code sessions
The decision in four questions
Does Claude need access to a system it cannot reach? -> MCP server
v
Would the output flood your conversation? -> Subagent
v
Is it instructions you keep repeating? -> Skill
v
Does someone else need it too? -> Wrap the above in a plugin

Note that the last question is a different kind of question. You never choose a plugin instead of a skill. You choose a skill, then decide whether it travels.

Where they overlap on purpose

The four are not sealed off from each other, and the deliberate overlaps are where the remaining confusion lives.

A skill can run in a subagent. Setting context: fork in a skill's frontmatter runs it in its own subagent context. So "skill or subagent" is sometimes "a skill, executed the subagent way".

A subagent can preload skills. The skills field in a subagent's frontmatter loads specific skills into it at startup. A skill with disable-model-invocation: true is excluded from that preloading, which is easy to trip over.

A plugin can ship an MCP server. Put .mcp.json at the plugin root and installing the plugin configures the server. This is how a team ships a working integration rather than a README telling everyone to run claude mcp add.

Hooks are the fifth thing, and they are not on this list. A hook fires on an event rather than being invoked, which puts it in a different category from all four. It ships inside a plugin like the rest.

Four traps that cost me time

All four were measured against Claude Code v2.1.233, not read off a blog post.

claude plugin add does not exist

It is the command everyone types, including a page on this site until recently. The real subcommand list is details, disable, enable, eval, help, init, install, list, marketplace, prune, tag, uninstall, update and validate.

I nearly published a second error on top of this one. I had a note claiming the list grew by four entries between v2.1.232 and v2.1.233, so I checked instead of repeating it. Both versions were still on disk, and both return the same fourteen subcommands:

bash
~/.local/share/claude/versions/2.1.232 plugin --help   # 14 subcommands
claude plugin --help                                   # the same 14

The earlier note had simply recorded an incomplete reading and I had turned that into a version delta. Run claude plugin --help on your own install rather than trusting any published list, this one included.

pluginDirectories in settings.json does nothing

This one is worth checking on your own machine, because it fails in silence. Unknown settings keys are ignored, so you get no plugin and no error.

bash
strings ~/.local/share/claude/versions/2.1.233 | grep -ic pluginDirectories   # 0
strings ~/.local/share/claude/versions/2.1.233 | grep -ic skills-dir          # 37
strings ~/.local/share/claude/versions/2.1.233 | grep -ic enabledPlugins      # 35

Zero hits for a key alongside dozens for its working siblings is strong evidence nothing reads it. A live test agreed: a settings entry produced No plugins installed.

Presence in a config file is not evidence that the config is read

This is the general version and it generalises well past plugins. Verifying that a key is present in your settings verifies an action. Whether the loader honours it is the outcome, and only the second one matters. Checking the first and reporting the second is how a wrong instruction survives in a README for months.

marketplace add fails on a plain plugin repository

claude plugin marketplace add owner/repo is the canonical flow, and it is structurally inapplicable to a repository that ships only a plugin. It needs .claude-plugin/marketplace.json, and a bare plugin repo has .claude-plugin/plugin.json instead. The error arrives at your terminal, not in any documentation you would have read first.

What actually works

Three paths, all of which I have run end to end:

bash
# persistent: clone or symlink into your skills directory
git clone https://github.com/primeline-ai/evolving-lite.git ~/.claude/skills/evolving-lite

# session only, ideal while developing
claude --plugin-dir ./my-plugin

# scaffold a new one that auto-loads next session
claude plugin init my-tool

claude plugin init creates ~/.claude/skills/my-tool/ with a manifest and a starter SKILL.md, and it loads as my-tool@skills-dir with no marketplace step. Anything in that directory with a .claude-plugin/plugin.json is picked up the same way. A directory holding only a SKILL.md and no manifest is not adopted as a plugin, which is a distinction I got wrong before someone made me test the negative case.

Honest scope

Everything above was checked against the current documentation and, where a command was involved, run on Claude Code v2.1.233 on macOS on 2026-08-15. I have not exercised fork mode myself; the defaults and the two controls above come from the subagents documentation. The strings counts are from that exact binary and will differ on your version.

I have not used the workflows, output-styles, themes, LSP or monitors locations at all. They are in the table because the plugins reference lists them, and I am saying so rather than implying coverage I do not have. What I have built and run is the skills, agents, hooks and MCP combination.

Four claims in an earlier draft were wrong and an external model review caught all four: I described the manifest as required when it is optional, called the plugin commands/ row "legacy" when the documentation only says to prefer skills/, stated that skill content persists for a whole session without the compaction limits, and presented subagent isolation without the fork exception. A fifth, a claimed version delta in the plugin subcommands, I killed myself by running both binaries. All are corrected above. Re-read claude plugin --help and the skills page before building on any specific claim here.

FAQ

What is the difference between a skill and a plugin in Claude Code?+
A skill is one SKILL.md file of instructions that Claude loads when relevant. A plugin is a directory that packages skills, subagents, hooks and MCP servers into one installable versioned unit. You never pick a plugin instead of a skill. You write the skill, then decide whether it needs to travel.
What is the difference between a Claude Code skill and a subagent?+
Context. A skill runs in your current conversation and its full text stays there. An ordinary subagent gets a fresh isolated context window, sees none of your history, and returns only a summary. The exception is a fork, which inherits the whole conversation, and fork mode is on by default in interactive sessions from v2.1.232.
Are slash commands and skills the same thing now?+
Effectively yes. Custom commands have been merged into skills. A file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy. Existing commands files keep working, but skills is the layout to use for anything new.
When should I use an MCP server instead of a skill?+
When the problem is access rather than instruction. An MCP server gives Claude tools for systems it cannot otherwise reach, like a database or an issue tracker. If Claude can already reach the thing and just does not know your procedure, write a skill.
Why does claude plugin add not work?+
Because it is not a subcommand. On v2.1.233 the list is details, disable, enable, eval, help, init, install, list, marketplace, prune, tag, uninstall, update and validate. Run claude plugin --help on your own install rather than trusting a published list, since this area changes faster than most.
Why is my plugin not loading from pluginDirectories in settings.json?+
Because nothing reads that key. It has zero occurrences in the v2.1.233 binary while enabledPlugins and skills-dir have dozens, and a live test returns No plugins installed. Unknown settings keys are ignored, so it fails silently. Clone into ~/.claude/skills/ or use claude --plugin-dir instead.
Can a plugin contain an MCP server?+
Yes. Put a .mcp.json at the plugin root and installing the plugin configures the server. That is how you ship a working integration to a team instead of a README telling everyone to run claude mcp add themselves.
Do I need a plugin to share a skill with my team?+
Not strictly. A skill checked into .claude/skills/ in the repository works for anyone who clones it. A plugin is what you want when the same setup should follow you across several repositories, or when you want versioned releases and marketplace installation.

>_ Get the free Claude Code guide

>_ No spam. Unsubscribe anytime.

>_ Related