Skills vs MCP: procedural knowledge or live tool access
A skill is knowledge the agent didn't have; an MCP server is reach the harness didn't have. Three questions that settle which one your job needs.
The question everyone lands on
Usually there's a certain thing you keep doing by hand and would like the agent to do instead, and then there's two offerings on the market: either you can create a skill or run an MCP server. These are both being marketed as extending the agent's capabilities, but really, one of them does it, the other — not so much
A skill is a file, a server is a process
In terms of the differences, what's key is that they're completely different things under the hood. A skill is essentially a directory with a SKILL.md file inside (it's an industry standard established by Anthropic and then opened up). That directory can contain a couple of more things like scripts, reference docs etc but crucially, it contains a markdown file with instructions, which includes metadata like name and description, and that's what the skill is. An MCP server on the other hand is a live process, while the Model Context Protocol is generally client-server, so the host harness spins up a new client for every connected server, with its own connection to it.
There are three primitive types of things an MCP server can expose:
tools — which are basically functions that AI apps call in order to perform actions
resources — which are data sources providing context
prompts — which are templates for structuring conversations with LLM-s
The most important thing is that a skill is knowledge the agent didn't have, while an MCP server is reach the harness didn't have. The former tells you how to do sth, the latter allows you to contact sth. So if you reckon that a competent developer at your terminal could get the job done using what's already installed on it, and the only thing missing is that the agent doesn't know the procedure — that's a skill; if there's nothing that could touch the target — that's a server
What the model actually sees
We could now get into a long discussion about context, but let's just do some math.
When you define a skill at startup, only its name and description are being loaded into the context, which is enough for the agent to understand it's relevant. When it then faces a task it might be relevant for, the entire SKILL.md file gets pulled in; during the task's execution, any additional files included in the skill are being loaded as needed.
Codex has a codex debug prompt-input command that renders the model-visible prompt input as JSON without calling a model at all. Run in a scratch directory with eleven skills, the skills block weighs 6,356 characters — names, descriptions and file paths, no bodies — but if we now list all the SKILL.md files, they actually add up to 122,636 characters. So it's roughly 5% being paid upfront, the rest — on demand. It's also important to note that OpenAI restricts this list to 2% of the context, 8,000 characters.
But when it comes to tools, what's interesting is that it works the other way round: the client asks every connected server for its tools and merges them all into a single registry the LLM can access. So every tool comes with its name, title, description, and an inputSchema — the complete JSON Schema describing the shape of its inputs — all visible to the model before the user types anything in; which is why Anthropic writes:
In cases where agents are connected to thousands of tools, they'll need to process hundreds of thousands of tokens before reading a request.
And their own way out of it is to stop calling the tools directly — generate the code that calls them instead, so the agent only pulls in what it needs. In their worked example that's the difference between 150,000 and 2,000 tokens. But there are a few caveats here:
it's an extreme scenario — using thousands of tools is not something you do with three modest servers
it's about the client, not the protocol; the spec leaves room for the client to implement federating multiple servers to discover tools progressively, rather than pulling them all in upfront, so if yours doesn't, that's a harness problem
Another thing that we often see being omitted by advocates of MCP is that skills also rent their space. In Claude Code docs it's clearly stated that once loaded, the skill's content remains in the context turn after turn — so every line of it is a recurring token cost. A 400-lines-long skill pulled in at turn two will still be there on turn forty
The three questions that settle it
So whenever you consider an MCP server, ask yourself three questions:
Does this require a connection that can't be established from the machine's shell? — like credentials the agent shouldn't have access to, or an unreachable network, or a SaaS product with no CLI client; in such case it's a server and there's no skill that could replace it
Does it need to return a handle so you can revisit it later? — like long-running jobs, or a list of capabilities that change during the session; the protocol covers both scenarios, via Tasks extension (which introduces a durable handle for the LLM to return so the client can poll for the result later), and notifications (for notifying the client about changes in the tool list); whereas a markdown file doesn't do any of these
Could a competent developer sitting at your terminal with what's installed on it do this job? — if yes, that's a skill; even if there were to be a server for the same thing, it'd be a skill, which costs its description until it runs, and a server, which costs its schemas in every session it's connected to, regardless of being used or not
The wrapper server
The most common misconception we come across is the "wrapper server", an MCP server whose every tool calls the CLI the agent already has. A server for git, a server for kubectl, a server for a REST API that ships with its own CLI on your machine already. It's appealing because it feels like a more serious engineering decision, so people keep doing it.
But think about it:
you need to set up and maintain a process
every tool comes with a schema in the window of every session that connects with it
you need to create a config entry on every developer's machine
you need to align another thing with what's beneath it
While a skill pointing at gh with what to run and what to verify first costs only its description until it runs. So before you consider setting up an MCP server, ask yourself if there's already an authenticated CLI client for the system in question on your machine, and if yes — write the skill
We're not saying that MCP is overhyped (that'd be a stretch), we're saying that when it comes to this particular use case of encapsulating a CLI that's already there on the machine within the protocol, it adds nothing the skill doesn't have and charges rent
Where a skill genuinely cannot go
There are four things a skill can't do that the protocol can:
credentials — project skills are git files; if you were to instruct the agent to call an API with a token in a skill, you'd end up with the token in git, but if you were to use a server for it instead, it'd stay on the server side and the client would just authenticate against the HTTP transport using a bearer token, API key, or OAuth (which the spec recommends)
nothing installed locally — if there's an API with an authentication flow and no CLI client anywhere near your machine, you can't create a skill because the skill is just a file telling the agent what to run
statefulness — the protocol is stateless as of 2026-07-28 (each request comes with its own version and capabilities), but an MCP server can have its state and return a handle for you to revisit a job later; skills are just files
machine-readable contract — tools come with
inputSchema, the JSON Schema describing the shape of their inputs, a type that travels with them; skill instructions are prose the LLM might or might not follow
They compose, and that is the normal case
It's not a "versus" thing, that's composition — this is the normal configuration; the "versus" narrative is mostly a misconception. In every setup we run there's both, splitting one thing — the server for reach, the skill for reasoning
Here's an example:
we have an MCP server exposing a tool to create an issue
but it doesn't tell the agent anything about our team's conventions
That we:
should include the reproduction steps in the body, not the title
use a specific label for anything connected with billing
check if there's no duplicate before creating the issue
This is skills territory. We'd write a skill referring to the server's tool, so both the connection and the procedure end up in the context at once. Which also means that:
our rules are cheaper as skills — a line in a tool description sits in the window of every session that connects with the server, while the same line in a skill body costs nothing in every session that doesn't trigger it
In Claude Code
The location of the skill files is ~/.claude/skills/<name>/SKILL.md (per-user) and .claude/skills/<name>/SKILL.md (per-project). Claude Code also finds skills in .claude/skills directories nested under the working directory, but only after Claude reads or modifies a file in this subdirectory. That's so packages in monorepos can ship their own skills. Now both slash commands and skills are unified in terms of the implementation to the extent that .claude/commands/deploy.md and .claude/skills/deploy/SKILL.md will both define a /deploy command with exactly the same behaviour.
If you were wondering how to set up MCP, here's an example:
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
claude mcp listclaude mcp add --transport http sentry https://mcp.sentry.dev/mcp— adding a Sentry server (via HTTP transport)claude mcp list— listing the servers, verifying they workGenerally, servers defined in a committed
.mcp.jsonare not connected until approved, so listing them will display a "pending" status instead of displaying them as active
The last thing — the Claude CLI is the only one of the six whose docs never mention .agents/skills/, so just keep in mind that if you put your skill there, it might not be loaded here; check before you rely on it. Also, it's good to know a few limitations before writing an essay:
The
descriptionandwhen_to_usefields are truncated after 1,536 characters in the listingAfter compaction, only the first 5,000 tokens of every invoked skill are being re-attached
There's a general limit of 25,000 tokens for all the skills that are being re-attached
In Codex CLI
There are skills under .agents/skills/ (or any parent dir, or the root of the repo), or under ~/.agents/skills/ if it's a user-level skill. You can call them with $skill, or they get automatically picked by Codex from the description field. MCP servers are added with the codex mcp subcommand.
codex mcp add my-tool -- my-command --flag
codex mcp listAmong the six tools, Codex is the best one for observing this trade-off.
codex debug prompt-inputFor example, if you type codex debug prompt-input, it prints the prompt as it's seen by LLM as JSON. So you can see it has skills, but only their names and descriptions, and file paths — their bodies aren't there until they get activated. That's the measurement in this lesson; you can even try it yourself on your repo in a second.
Gotcha: Just keep in mind that Codex looks at .agents/skills, not .claude/skills, so that's why nothing appears if you've come over from Claude Code. The same codex debug prompt-input command also shows whether a skill got picked up, so you don't need to guess based on behaviour.
In GitHub Copilot CLI
The most open of the six tools when it comes to skills location, it accepts skills defined in these paths:
.github/skills/,.agents/skills/,.claude/skills/on a project level~/.copilot/skills/,~/.agents/skills/on user level
If you define a skill in two of the aforementioned paths, it will appear only once in the list.
Listing skills and adding one from file, URL or a directory:
copilot skill list
copilot skill add <file-or-url-or-directory>The tool automatically reads MCP configuration from these sources:
~/.copilot/mcp-config.json(personal).mcp.jsonor.github/mcp.json(workspace)any plugin that ships with its own server
You can list them using this command copilot mcp list and it will list all of them. It's worth noticing that the CLI comes with github-mcp-server built in, so there's a server without you doing anything about it. It comes with only a part of the toolset enabled by default — which is reasonable; we wouldn't change it. If you want the whole thing, --add-github-mcp-toolset all is the flag, and it's the fastest way to find out what a crowded tool list feels like. --disable-builtin-mcps goes the other way and turns the built-ins off entirely.
In Cursor
Locations in which you can define skills:
per project —
.agents/skills/and.cursor/skills/per user —
~/.agents/skills/and~/.cursor/skills/
Cursor also reads the older .claude/skills/ and .codex/skills/ paths, so it works with most of the projects created using other agent tools.
Skills are defined via frontmatter with name and description properties required, optional paths globs and disable-model-invocation (so it will work only when you use it).
You can define MCP servers in .cursor/mcp.json file per project or ~/.cursor/mcp.json globally, and if there's none the CLI will tell you about these locations. Then you can run the following commands:
agent mcp list
agent mcp list-tools <identifier>agent mcp list— lists all the configured serversagent mcp list-tools <identifier>— lists tools of a specific server
If you were to ask us which one is more valuable, we'd say the latter one — for a particular server it shows what tools are exposed and what arguments they have. It's the closest thing these CLIs can offer in terms of showing what a server costs.
But there's a catch — these paths belong to the editor, so if you run agent mcp list command with no servers configured it points to .cursor/mcp.json or ~/.cursor/mcp.json which are also used by the editor so you might end up having a project with tools that somebody else created for some other purpose.
In Gemini CLI
There are four levels where you can place skills:
Installed with the CLI
From an extension
Per-user:
~/.gemini/skills/(or~/.agents/skills/)Per-workspace:
.gemini/skills/(or.agents/skills/)
For a single level, if you have both .gemini and .agents folders, .agents is prioritised.
To list all the skills and to install one from a git URL or local path:
gemini skills list --all
gemini skills install <git-url-or-path>Once the session starts, you'll see a list of available skills and their descriptions, and when the LLM finds a match it calls the activate_skill tool which prompts the user to proceed with the SKILL.md contents. So basically, it's a staged disclosure process, with the user being asked for permission halfway through.
For MCP-s: gemini mcp add, gemini mcp list, and enable / disable per server. The enable/disable are useful if you want to have a server configured but don't need it during a session.
Also, there's a thing called "workspace trust" that might be confusing. If the directory is not trusted, listing skills it says "Skipping project agents due to untrusted folder" and only shows the personal and built-in ones. It's just the project skill being skipped in this case. This message is displayed at the very beginning of the list so might be easily missed — make sure you don't miss it before assuming there's a problem with a file.
In Kimi Code CLI
The skills are resolved from four sources (with the highest precedence first):
Project directories,
.kimi-code/skills/and.agents/skills/, being located in the current directory and all its parent dirs up to the git rootPer-user directories,
~/.kimi-code/skills/and~/.agents/skills/Extra skill directories, if configured under
extra_skill_dirsinconfig.tomlThe shipped defaults
You can use them like this: /skill:<name> [arguments]… if the skill has been defined with any.
For example: running it with a flag pointing to some temporary directory with skills so they can be used during that run without being resolved automatically. This way you can test a skill before incorporating it in some of the permanent scopes.
kimi --skills-dir ./scratch-skillsWhat's more, there are more frontmatter properties than just name and description in the skills.
whenToUse- to define the triggerdisableModelInvocation- set it to true if you don't want the model picking this skill up on its owntype- prompt or flow (for the latter only manual calls are possible)
The MCP setup is configured in mcp.json files, per-user ones at ~/.kimi-code/mcp.json and project-specific ones at .kimi-code/mcp.json. If there's a collision between the server names defined in both of these files, the project one has higher priority. There's no mcp subcommand in the Kimi Code CLI so to add or edit servers you can run /mcp-config during a session and to see their status you can use /mcp.
Once found, skills are being put into the system prompt, grouped by their scope (so the model can understand that some of them come from the project and some from your personal setup), which is good but means that it's better to keep their descriptions concise as they'll appear there in every turn after incorporating them to some of the scopes. And kimi doctor validates the config files, so run it first when some scope isn't being picked up.
What to check before you install anything
Before you add an MCP server, spend a minute to inventory what's already installed and authenticated on your machine; for most of the clients we work with, it turns out most so-called "integration problems" are git, gh, psql or kubectl. Which means that once somebody gives the agent the procedure, it can operate them via the existing shell tool
After you set up a server, spend another minute to explore what it actually did; every harness here can list the configured servers from the CLI or within the session, some of them even list the tools they expose. Because this number is not trivia — it's the per-session rent you're paying now and the basis to decide if the server was worth its place
.agents/skills/gh-issues/SKILL.md---
name: gh-issues
description: Read, triage and comment on GitHub issues and pull requests with the gh CLI. Use when asked about an issue or PR by number or URL, to triage the issue backlog, to find who last touched something, or to leave a comment on GitHub.
---
# GitHub through `gh`
`gh` is already authenticated on this machine. Use it instead of guessing from the repo,
and instead of asking for a GitHub token.
## Read before you write
- One issue: `gh issue view <number> --comments`
- Open issues, newest first: `gh issue list --state open --limit 30`
- Anything matching a phrase: `gh search issues "<phrase>" --repo <owner>/<name>`
- A pull request and its review state: `gh pr view <number> --comments`
- Arbitrary reads the subcommands don't cover: `gh api repos/<owner>/<name>/issues/<n>/events`
## Triage
Read the issue and the linked code before proposing a label. State which file the report
lands in and quote the line. If the report is not reproducible from what is in the repo,
say that instead of guessing a cause.
## Writing
Ask first. Every write is public and attributed to the account `gh` is logged in as.
- Comment: `gh issue comment <number> --body-file <path>`
- Label: `gh issue edit <number> --add-label <label>`
- Close: `gh issue close <number> --comment "<why>"`
Write the body to a file and show it before running the command. Never open, close or
comment on an issue in a repository the current task did not name.