Skills or MCP servers: when you need a server

The argument I keep hearing is that skills have made MCP servers redundant. A skill can drive any CLI, so point the agent at aws or psql and it can do anything a server can. For one person working on their own machine, that’s mostly true.

Calling a CLI doesn’t make a skill a good way to authenticate or retrieve governed data. The skill uses whatever credentials happen to be on your laptop, which means the caller is whoever you last logged in as. It can do anything those credentials allow. There is no central place deciding which tools finance can see or recording who touched a customer’s data. The skill may also give the agent more access than the task needs.

For personal work, that can be fine. A skill gives the local chat agent a procedure and any local glue code it needs. The client loads it and the work runs as you, with nothing else to deploy or authenticate. If the job is “teach the agent how to do this” or “wire these two commands together”, a server is overhead.

Once several people work with the data behind a skill, something other than a laptop has to check access. My rule is to use skills for instructions and local glue on my own machine. When a policy governs access to the data, I put a server in front of it. That gives me one place to enforce who sees what and keep the audit log. It also gives me a useful answer when a security reviewer asks where access is checked; “the user’s laptop” isn’t going to get me through that review.

flowchart LR
    subgraph machine["your machine: enforcement is your laptop"]
        skill["skill: prompt + glue scripts,<br/>running with your creds"] --> own[("your data")]
    end
    subgraph governed["governed: enforcement is the server"]
        server["mcp server: governed access<br/>with an audit log"] --> shared[("shared data")]
    end
    machine ==>|"the data becomes shared"| governed

Skills and servers work well together too. For file delivery, a secured MCP server can put the file in S3 and return a short-lived signed link. A small skill tells the agent to show the link and mention when it expires, while the file itself stays out of context.

Skills usually live in a user’s agent config or a project repo, though organisations can install them centrally. FastMCP 3 can publish skills as MCP resources, which lets the server keep instructions beside the tools and control who can read them. The client follows the skill as usual.

Skills and MCP tools both consume context if the client loads their full definitions up front. Just-in-time loading keeps a small catalogue in the starting context and pulls in the detail when the task needs it.

Claude Code does this for both. Skill descriptions load at startup and the full SKILL.md arrives when the skill is used. MCP Tool Search starts with tool names and defers the full schemas until use. For skills I only invoke manually, disable-model-invocation: true removes even the description from startup context.

I changed acme-mcp to work this way for file delivery. The handle-downloads skill is available at skill://handle-downloads/SKILL.md, and its reports tag limits it to callers who can use reports. The server doesn’t have to stuff the instructions into every tool result.

Models have got better at following skills. I can give an agent a short procedure and a couple of scripts, and it calls the right tool for each step without a hand-wired workflow. I start with a skill for a lot of what I build. Designing the tools it calls is a separate problem, especially once datasets need different schemas.

I wrote up the production setup in Building and securing MCP servers with FastMCP, including authentication and the audit trail.

I use skills for instructions and local glue when the work runs on my machine with my credentials. Once the data is shared, I put a server in the middle. It can distribute the skill too, but the access check stays on the server.

Discussion