Agent Skills over MCP
Serve Agent Skills (folders with a SKILL.md) to every client of the gateway through the MCP Skills extension — skills/list, skills/get, skill:// resources and directory reads — from config alone, under the same access rules and audit as every other resource.
An Agent Skill is a folder of
instructions for an agent: a SKILL.md with a short YAML header (name,
description) and a body that says how to do one kind of task, plus any
references, templates or scripts it points to. Hosts show the model each
skill's name and description, and load the full text only when a task needs
it.
The Skills extension (SEP-2640, io.modelcontextprotocol/skills) lets an
MCP server ship skills next to the tools they describe. MCPG implements the
server side: point mcp.skills at a folder and every client of the gateway
can find, verify and read those skills. No plugin and no code.
Serve a folder of skills
mcp:
skills:
sources:
- path: skills # relative to this config file
prefix: macos # optional: served under skill://macos/…
governance:
minimum_trust: header_asserted
instructions: |
Load skill://macos/computer-use/SKILL.md before you use these tools.
skills/
├── computer-use/
│ ├── SKILL.md
│ └── references/
│ └── tool-map.md
└── screen-coordinates/
└── SKILL.md
Each folder that holds a SKILL.md is one skill. The folder name must equal
the name in its frontmatter. With the config above the gateway serves:
| Resource | URI |
|---|---|
| Skill | skill://macos/computer-use/SKILL.md |
| Supporting file | skill://macos/computer-use/references/tool-map.md |
| Skill folder | skill://macos/computer-use (a directory resource) |
SKILL.md
---
name: computer-use
description: Operate the user's Mac through this server's tools. Load this first.
license: Apache-2.0
metadata:
version: "1.0"
---
# Computer use on macOS
Work in a loop: observe, act, observe again. …
See `references/tool-map.md` for every tool.
name is 1 to 64 lowercase letters, digits and single hyphens. description
is 1 to 1024 characters. Every other frontmatter field is passed to clients
unchanged.
What clients get
When mcp.skills has a source, the gateway declares the extension in
initialize (2025-11-25) and server/discover (2026-07-28):
{ "capabilities": {
"resources": { "listChanged": true },
"extensions": { "io.modelcontextprotocol/skills": { "directoryRead": true } } } }
| Method | Answer |
|---|---|
skills/list | Every skill the caller may see: its SKILL.md URI, its frontmatter verbatim, and every file with a sha256: digest and its size. Paginated with cursor / nextCursor. |
skills/get | One entry by its SKILL.md URI. An unknown skill, or one the caller may not see, is -32602. |
resources/read | A skill file's bytes: text for UTF-8 files, blob (base64) for others. cacheToken is the file's digest. |
resources/directory/read | The direct children of a skill folder or of a prefix folder: files with their mimeType and size, folders as inode/directory. |
resources/list | Also lists each SKILL.md, for clients that do not speak the extension. |
On the 2026-07-28 wire, results carry resultType: "complete"; skills/list
also carries ttlMs and cacheScope: "private".
A client that knows only resources still works: it sees each SKILL.md in
resources/list and reads it — and the files it names — with
resources/read. Point the model at the skills from mcp.instructions.
Integrity
The gateway reads every source once, when it starts and when it reloads its
config, and serves the files from memory. The bytes resources/read returns
are therefore always the bytes the listed digest describes. To publish a
change, edit the files and reload (mcpg reloads on SIGHUP, or through the
admin API). A host that holds an older entry sees a digest mismatch, calls
skills/get and gets the new one.
The limits of the extension are enforced when the source loads: a skill holds at most 512 files and 16 MiB. Loading also refuses:
- a
SKILL.mdwithout frontmatter, anamethat breaks the naming rules or differs from its folder name, or nodescription; - a broken symbolic link, or a folder link that loops back (other links are followed, so a Kubernetes ConfigMap or Secret volume works as a source);
- a
SKILL.mdat the root of a source (skills live in its subfolders); - two sources that serve the same URI.
Names that start with . (.git, .DS_Store) are not served. A file that is
in no skill folder (a README.md next to the skill folders) is not served
either.
A failure stops the gateway from starting, or keeps the old config on a reload, and names the file and the reason.
Access and audit
Skill files are resources. skills/list, skills/get and
resources/directory/read show a caller only the URIs that its
resources/read would allow, and every read runs the same pre-dispatch gate
and policy chain as any other resource.
mcp.skills.governance is the block every binding takes (minimum_trust,
allow_if, required_scopes) and applies to every skill file and folder.
Unset minimum_trust takes governance.policy.tool_access.default_minimum_trust,
which refuses anonymous callers — so a local stdio server whose client is
anonymous sets minimum_trust: unauthenticated. A
governance.policy.tool_access rule filed under one URI tightens that URI
further; CEL sees the URI as tool_name.
Every read writes an mcpg.resource.read.success (or .denied) audit record,
and every skills/list writes mcpg.skill.list.
Digests prove that a file is the one the listing named; they do not prove the content is safe. Serve only skills you reviewed, and remember that a host treats MCP-served skills as untrusted input.
Reference
| Key | Default | Meaning |
|---|---|---|
mcp.skills.sources[].path | — | A folder of skills. A relative path starts at the last config file's folder. A config with no file (base64:, data:, a URL, a control-plane push) must give an absolute path; the gateway refuses a relative one at boot. The log line skills source loaded names the absolute folder. |
mcp.skills.sources[].prefix | unset | Served under skill://<prefix>/…. Segments of letters, digits, -, ., _, ~. |
mcp.skills.directory_read | true | Serve resources/directory/read and declare directoryRead: true. |
mcp.skills.list_as_resources | true | Also list each SKILL.md in resources/list. |
mcp.skills.governance | unset | minimum_trust, allow_if, required_scopes for every skill file and folder. |
The examples/25-macos-computer-use config serves six computer-use skills
this way.