Skip to content
Go back

Claude Skills vs MCP: What Each One Is For

By KingPin 13 min read
Claude Skills vs MCP: What Each One Is For
Contents

You want your AI agent to check whether last night’s backup ran. You search around, find two shiny extension systems, and now you are staring at a Skill and an MCP server wondering which one to build. Plenty of posts treat them as rivals. They are not.

Here is the short version. A Skill packages know-how: instructions, scripts, and reference files that load into the model’s context on demand. An MCP server packages access: a running process that exposes tools and resources over a protocol, so the agent can reach systems it cannot touch on its own. Most home-lab users should write a Skill first. Reach for MCP when you need a live connection, an auth boundary, or one tool shared across many clients.

Full example: Clone the working files at github.com/KingPin/sumguy-examples/llm/claude-skills-vs-mcp

A Skill is a folder with a README the model actually reads

An Agent Skill is a directory with a SKILL.md file in it. Anthropic created the format, then released it as an open standard at agentskills.io. The file needs YAML frontmatter with two required fields, name and description, followed by plain markdown instructions.

The open spec sets the limits. The name is 1 to 64 characters: lowercase letters, numbers, and hyphens, no leading, trailing, or consecutive hyphens, and it must match the directory name. The description is 1 to 1024 characters and should say both what the skill does and when to use it. Optional fields include license, compatibility, metadata, and an experimental allowed-tools. Claude Code adds more of its own, such as disable-model-invocation, and it truncates the combined description and when_to_use text at 1,536 characters in its skill listing.

Here is a trimmed version of the skill from the example repo:

SKILL.md
---
name: homelab-backup-check
description: Checks whether a backup directory (restic, borg, rsync, tar dumps) is fresh by looking at the newest file's modification time. Use when the user asks if backups are current, healthy, or have stopped running.
---
# Homelab backup freshness check
Run the bundled script against the backup directory. Never guess the path: ask the user if they did not give one.
python3 scripts/check_backups.py /srv/backups --max-age-hours 26
## Reading the result
- Exit code 0 and `FRESH`: report the age and stop.
- Exit code 1 and `STALE`: report the age, then check the scheduler
and the last job log before suggesting fixes.
- Exit code 2: the path is wrong. Ask the user.

That is all there is. No daemon, no port, no JSON-RPC. The folder can also hold a scripts/ directory, a references/ directory for long docs, and an assets/ directory for templates. The agent reads them when the instructions point at them.

In Claude Code, skills live in ~/.claude/skills/<name>/SKILL.md (personal), .claude/skills/<name>/SKILL.md (project), or inside a plugin’s skills/ directory. Installing one is a cp -r:

Terminal window
mkdir -p ~/.claude/skills
cp -r skill/homelab-backup-check ~/.claude/skills/

Skills also work on claude.ai (uploaded as a zip in Settings) and the Claude API (uploaded through the Skills API). Custom skills do not sync between those surfaces, so you manage each one separately. The agentskills.io site says a growing number of agent products have adopted the format, so a skill you write is not locked to one vendor. Check your tool’s own docs for its skills directory before assuming it behaves the same.

An MCP server is a separate process you plug in

The Model Context Protocol is a JSON-RPC 2.0 protocol between a host (the app running the model), a client inside that host, and a server. The latest spec revision is dated 2026-07-28. Servers offer three primitives: tools (functions the model can call), resources (data the model or user can read), and prompts (templated messages).

The spec defines two standard transports. Stdio runs the server as a subprocess of the client and talks over its standard streams. Streamable HTTP sends each message as an HTTP POST to a single endpoint. Stdio is the home-lab default for a local server. HTTP is what you use for something remote or shared.

Here is the same backup check as an MCP server, using the official mcp Python SDK:

server.py
import time
from pathlib import Path
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("homelab-backup-check")
@mcp.tool()
def check_backups(directory: str, max_age_hours: float = 26.0) -> str:
"""Report whether the newest file under `directory` is newer than max_age_hours."""
root = Path(directory)
if not root.is_dir():
return f"ERROR: {root} is not a directory"
newest = max(
(p for p in root.rglob("*") if p.is_file()),
key=lambda p: p.stat().st_mtime,
default=None,
)
if newest is None:
return f"STALE: {root} contains no files"
age = (time.time() - newest.stat().st_mtime) / 3600
state = "FRESH" if age <= max_age_hours else "STALE"
return f"{state}: newest file {newest.name} is {age:.1f}h old (limit {max_age_hours:g}h)"
if __name__ == "__main__":
mcp.run() # stdio by default

A version gotcha will bite you here. The mcp package reached 2.x, and the 2.x SDK renamed FastMCP to MCPServer. Every older tutorial that says from mcp.server.fastmcp import FastMCP fails on a fresh pip install mcp with a ModuleNotFoundError that points you at the migration guide. I tested this example on mcp 2.3.0. If you want the old import, pin mcp<2.

Registering it with Claude Code uses claude mcp add. Everything after the double-dash separator goes to the server unchanged:

Terminal window
python3 -m venv .venv
.venv/bin/pip install mcp==2.3.0
claude mcp add --transport stdio backup-check -- "$PWD/.venv/bin/python" "$PWD/mcp-server/server.py"
claude mcp list

For a remote server the shape is claude mcp add --transport http <name> <url>. Add --scope project to write it to a .mcp.json file you can commit, or --scope user to make it available in every project. The default scope is local to you and the current project.

The real difference: what is each one for?

Look at those two files again. The skill is words plus a script the agent runs through its normal shell tool. The server is a program that stays alive and answers calls.

Agent SkillMCP server
PackagesKnow-how: instructions, scripts, referencesAccess: tools, resources, prompts
Runs asFiles the agent reads, scripts it runs with its own shellSeparate process, stdio or HTTP
CredentialsWhatever the agent’s shell already hasIts own, held by the server
Client supportAny agent that reads the Agent Skills formatAny MCP client
Built withA text editorAn SDK and a process to keep running
Typical use“How we do restores here”“Query the live ticket system”

The test I use: can the agent already do this if it knew how? Your agent can run restic snapshots in a shell. It lacks the knowledge of your repo layout, your retention policy, and what a healthy result looks like. That is a Skill. Your agent cannot reach a SaaS API behind OAuth, or a database that only listens on a private network, no matter how good the instructions are. That needs access, so that is MCP.

Hiring an MCP server to deliver a checklist is the forklift-and-couch move. Technically it works, but you now run a process, version a package, and debug a transport, for a text file.

Context cost: what loads when

This is where the two designs differ most, and it explains a lot of the “my context is full” complaints.

Skills use progressive disclosure, in three levels. At startup, the agent loads only each skill’s name and description, roughly 100 tokens per skill. When a task matches, it reads the full SKILL.md body, which the spec recommends keeping under 5,000 tokens and 500 lines. Bundled files and scripts load only when needed. When a script runs, only its output enters context, not its source.

So twenty skills cost you a couple thousand tokens of descriptions until one fires. One cost remains: the body stays in the conversation once invoked. Claude Code’s docs say each line of an invoked skill is a recurring token cost across turns, so write lean bodies and push the long material into references/.

MCP historically worked the other way: every tool’s name, description, and JSON schema loaded up front, for every connected server. Ten servers with fifteen tools each meant 150 schemas in context before you typed a word. Claude Code now defers this. According to its docs, tool search is on by default, and with it “only tool names and server instructions load at session start” while the full definitions load on demand. The ENABLE_TOOL_SEARCH environment variable controls it: false loads everything up front, and auto loads tools up front until their definitions reach 10% of the context window. On models earlier than Claude Opus 4 and Sonnet 4, Claude Code loads all MCP tools upfront regardless. Other MCP clients may not defer anything, so check yours.

That makes the context gap smaller than it used to be inside Claude Code. It does not make it zero. A server with tool search still adds its tool names and instructions to every session.

They compose: a Skill that teaches an MCP server manners

The best pattern is both together. An MCP server gives the agent a capability. A Skill tells it when to use that capability and how to interpret the answer.

Say you run the backup MCP server from above. The tool returns STALE: newest file ... is 72.0h old. An agent with only the tool will report that and shrug. An agent with a Skill knows your house rules:

SKILL.md
---
name: backup-triage
description: Interprets backup freshness results from the backup-check MCP server and walks through triage. Use when a backup is reported stale or the user asks about backup health.
---
# Backup triage
Call the `check_backups` tool for each directory in references/paths.md.
- Daily jobs use the default limit. Weekly jobs use `max_age_hours` 180.
- On STALE, check `systemctl list-timers` before touching the backup tool.
- Never report "healthy" from freshness alone. Suggest a restore test.

The skill carries the judgment (your retention rules, your triage order). The server carries the connection. If you swap the MCP server for a different implementation next year, you edit one paragraph.

Security: both can ruin your afternoon

Neither is safe by default, and they fail differently.

A Skill’s scripts run with the agent’s own permissions. In Claude Code, per Anthropic’s docs, skills have the same network access as any other program on your computer. A hostile skill does not need an exploit. It just has to tell the agent to run curl with your SSH keys, and the agent can follow instructions. Anthropic’s guidance is to use skills only from sources you trust, audit every bundled file, and be wary of skills that fetch content from external URLs.

An MCP server is a separate process with its own credentials, which gives you a real boundary. A server holding a read-only database user cannot do more than that user can, whatever the model is talked into. The spec says tools “represent arbitrary code execution” and tool descriptions should be treated as untrusted unless they come from a trusted server. That boundary only helps if you scope the credentials. A server running with your admin token has no boundary at all, which is the case against one skeleton-key MCP server.

Both are supply-chain risks the moment you install one from a stranger. A skill is a text file plus scripts, so you can read all of it in five minutes. Do that. For an MCP server installed from a package registry, you are trusting the code you did not read plus its dependencies. Pin versions, as the example’s requirements.txt does.

So which one do you build?

Walk down this list and stop at the first yes:

  1. Is it a procedure, a checklist, or house knowledge? Write a Skill.
  2. Can a shell command or script do the job, and does the agent already have a shell? Write a Skill with a script in it.
  3. Does it need credentials the agent should not hold, or a network the agent cannot reach? Build an MCP server and keep the credentials in it.
  4. Do several different clients need the same tool? Build an MCP server. Skills are portable files, but a running server is one thing to maintain instead of N copies.
  5. Does it need a live, stateful connection (a browser session, a streaming feed, a long-lived DB connection)? MCP server.
  6. Both a connection and a procedure? An MCP server for the connection, a Skill for the procedure.

For a home lab, steps 1 and 2 catch most of it. Backup checks, restore runbooks, “how I name Docker volumes”, Compose conventions, your Proxmox cheat sheet: all Skills. The MCP-shaped jobs are the ones with an API and a token on the other end. Your 2 AM self will thank you for picking the one with fewer moving parts.

Common Questions

Do Claude Skills work without Claude Code?

Yes. Claude Skills also work on claude.ai (uploaded as a zip in Settings) and through the Claude API (uploaded via the Skills API). They do not sync between surfaces, so a skill you uploaded to claude.ai is not available on the API until you upload it there too.

What are the limits on a SKILL.md name and description?

The open Agent Skills spec limits name to 64 characters of lowercase letters, numbers, and hyphens, and description to 1024 characters. Claude Code’s skill listing also truncates the combined description and when_to_use text at 1,536 characters, so put the key use case first.

Can a Skill and an MCP server do the same job?

Often yes, which is why people confuse them. A Skill that runs a script and an MCP server exposing a tool can return identical output, as the example repo shows. The Skill is a folder of files with no running process. The MCP server is a separate process with its own credentials.

Do I need to change my old FastMCP code for mcp 2.x?

Yes, old FastMCP code needs a change. The mcp 2.x Python SDK renamed FastMCP to MCPServer, imported from mcp.server.mcpserver. The old mcp.server.fastmcp import raises ModuleNotFoundError on 2.x. Either update the import and check the migration guide, or pin mcp<2 to keep running 1.x code unchanged.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
Immich Backups That Outlive Immich
Next Post
Read-Only Docker Containers: What Breaks

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts