skills-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@skills-mcp-serverlist all available skills"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
skills-mcp-server
An MCP server, built with FastMCP, that serves a directory of
SKILL.md-based "skills" over the network — as both MCP resources and MCP tools.
How it works
Resources come from FastMCP's built-in
fastmcp.server.providers.skills.SkillsDirectoryProvider. It scans a root directory, and treats every subdirectory containing aSKILL.mdfile as one skill, exposing:skill://{name}/SKILL.md— the skill's main fileskill://{name}/_manifest— a synthetic JSON file listing (path/size/hash) for the skillskill://{name}/{relative/path}— every other file in the skill folder (e.g.references/*.md)
This server configures the provider with
supporting_files="resources", so every supporting file is individually listed bylist_resources()up front (not hidden behind a lazy URI template) — good for upfront discoverability by clients that just calllist_resources()once.Tools (
list_skills,get_skill,get_skill_reference) are hand-written on top of the same skills directory, since the provider only exposes resources, not tools. They parse full YAML frontmatter (interface:blocks, nested lists, etc.) rather than relying on the provider's internal simplified line-based frontmatter parser, so nested metadata (e.g.risk_level,confirmation_points) comes through correctly.list_skills()→ name, description, argument hint, risk level, and path for every skill.get_skill(name)→ full parsed frontmatter, the markdown body, and a list of that skill's supporting reference files.get_skill_reference(skill_name, path)→ the text content and MIME type of one reference file within a skill (e.g.references/infoblox/procedure.md), for clients that want a specific reference file's content without walkinglist_resources().pathmust be one of the paths in that skill'sreference_fileslist; anything else (including path traversal attempts) is rejected.
Transport: streamable-HTTP (
mcp.run(transport="http", ...)), since this is meant to run in a container and be reached by remote MCP clients rather than over stdio.Skills directory is never baked into the image. The Dockerfile only ships the server code; the actual skills live on the host and are mounted as a read-only volume at container runtime (
docker-compose.ymlmounts them to/skills). Swap in a different skills directory by changing the compose volume mount or theSKILLS_DIRenv var — no rebuild needed.
Related MCP server: skills-mcp-server
Configuration
All configuration is via environment variables (see .env.example):
Variable | Default | Meaning |
| (unset) | Multiple named skill sources — see Multiple skills directories below. Takes precedence over |
|
| Legacy single-directory config. Root directory to scan for skill folders. Still fully supported for backward compatibility when |
|
| Host/interface the HTTP transport binds to |
|
| Port the HTTP transport binds to |
|
| If |
|
|
|
|
| Standard Python logging level |
A GET /health route is also registered for container/orchestrator liveness checks. It reports
every configured skill source by name.
Multiple skills directories
This server can merge more than one skills collection behind a single MCP endpoint. Configure
SKILLS_DIRS as a comma-separated list of name=path pairs, one per source:
SKILLS_DIRS=agent-skills=/skills/agent-skills,automation-skills=/skills/automation-skillsEach source is identified by an explicit, stable name — this is what drives collision
resolution (below), not the order the sources are listed in.
Collision policy: agent-skills always wins. If the same skill directory name exists under
more than one configured source, the source literally named agent-skills always wins,
regardless of where it appears in SKILLS_DIRS. This is enforced by an explicit name check
(source.name == "agent-skills") in discovery._resolve_skill_dirs, not by "whichever directory
happens to be scanned first" — reordering SKILLS_DIRS in your .env file later will not
silently flip precedence. If neither colliding source is named agent-skills, the
first-configured source wins (list order only matters as a tiebreaker in that case).
Every time a collision is resolved, the server logs a WARNING naming the skill, every source
that defines it, the winning source, and the shadowed source(s) — so shadowing is never silent.
This applies identically to both the tool layer (list_skills/get_skill/get_skill_reference)
and the resource layer (skill://... URIs): a shadowed source's own files are never served under
the winning skill's name, even if you ask for one of its supporting files by path directly.
SKILLS_DIR (singular) keeps working unchanged if you only need one source — it's treated as one
source named "default". If both SKILLS_DIRS and SKILLS_DIR are set, SKILLS_DIRS wins and
SKILLS_DIR is ignored.
Local development quickstart
Requires Python 3.11+ and uv.
uv venv .venv
source .venv/bin/activate
uv pip install -e .
# Point at any skills directory you like — this repo bundles a minimal
# example under ./example-skills:
export SKILLS_DIR=./example-skills
skills-mcp-server
# -> Starting MCP server 'Skills MCP Server' with transport 'http' on http://0.0.0.0:8010/mcp(pip install -e . in a plain venv works too, if you'd rather not use uv.)
To run locally against a real, richer skills set instead of the bundled example (e.g. for manual
testing), just point SKILLS_DIR elsewhere — nothing else needs to change:
export SKILLS_DIR=/path/to/agent-skills/skills
skills-mcp-serverThis only affects your local shell session — it does not touch docker-compose.yml, the
project's .env.example default, or the test suite (which always uses its own fixtures under
tests/fixtures/, independent of both example-skills/ and whatever SKILLS_DIR you export).
Quick smoke test with the FastMCP client
import asyncio
from fastmcp import Client
async def main():
async with Client("http://127.0.0.1:8010/mcp") as client:
tools = await client.list_tools()
print([t.name for t in tools])
resources = await client.list_resources()
print([str(r.uri) for r in resources])
result = await client.call_tool("list_skills", {})
print(result.data)
asyncio.run(main())Or with curl against the health route:
curl http://127.0.0.1:8010/health
# {"status": "ok", "skill_sources": {"default": "./example-skills"}}Docker quickstart
docker compose up --buildThis builds the image (server code only — no skills baked in), mounts the bundled
./example-skills directory from the repo to /skills inside the container read-only, and
serves on http://localhost:8010/mcp. No configuration is required for this to work on a fresh
clone.
Pointing at a different skills directory
Copy docker-compose.override.yml.example to docker-compose.override.yml (untracked — see
.gitignore) and edit the path:
services:
skills-mcp-server:
volumes:
- /path/to/your/skills:/skills:roCompose automatically merges docker-compose.override.yml over docker-compose.yml, so your
own skills directory is used without editing the tracked file.
Or, if running the container directly instead of via compose:
docker run --rm -p 8010:8010 \
-v /path/to/your/skills:/skills:ro \
-e SKILLS_DIR=/skills \
skills-mcp-server:localConnecting an MCP client
Any MCP client that supports streamable-HTTP transport can connect directly to
http://<host>:8010/mcp. Example generic client config:
{
"mcpServers": {
"skills": {
"url": "http://localhost:8010/mcp",
"transport": "http"
}
}
}Project layout
skills-mcp-server/
├── pyproject.toml
├── Dockerfile
├── docker-compose.yml
├── docker-compose.override.yml.example # template for pointing at your own skills dir
├── .env.example
├── .gitignore
├── LICENSE
├── README.md
├── example-skills/ # bundled fixture so the server works out of the box
│ └── hello-world/
│ ├── SKILL.md
│ └── references/
│ └── greeting-styles.md
├── tests/ # pytest suite — uses its own fixtures/, never example-skills/
│ ├── conftest.py
│ ├── fixtures/skills/
│ ├── fixtures/multi/ # two-source fixtures for collision-policy tests
│ ├── test_config.py
│ ├── test_discovery.py
│ ├── test_server.py
│ └── test_tools.py
└── src/skills_mcp_server/
├── __init__.py
├── config.py # env-driven Settings; SKILLS_DIRS / SKILLS_DIR parsing, SkillSource
├── discovery.py # full YAML frontmatter parsing, multi-source merge + collision policy
├── tools.py # list_skills / get_skill / get_skill_reference MCP tool definitions
└── server.py # FastMCP app wiring, multi-provider root ordering, health route, entrypointRunning tests
uv pip install -e ".[dev]" --python .venv/bin/python
.venv/bin/python -m pytestLicense
Apache License 2.0 — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP server exposing SMI Aware tools, resources, and skills over Streamable HTTP.
- UnifAPIOAuthcom.unifapi
Hosted MCP server for live public-data APIs and Skills for AI agents.
Host your MCP tool over streamable HTTP in one command.
MCP server for skill documentation, generated by doc2mcp.
Related MCP Servers
- AlicenseAqualityCmaintenanceConverts AI Skills (following Claude Skills format) into MCP server resources, enabling LLM applications to discover, access, and utilize self-contained skill directories through the Model Context Protocol. Provides tools to list available skills, retrieve skill details and content, and read supporting files with security protections.328Apache 2.0
- AlicenseAqualityDmaintenanceExposes Cursor-style skill packs (SKILL.md trees) via MCP resources, tools, and prompts, enabling any MCP client to list, get, search skills, and retrieve skill context.313 npmISC
- AlicenseNot gradedqualityDmaintenanceA minimal MCP server that resolves skill names to filesystem paths + metadata, enabling on-demand skill retrieval without loading full content into context.MIT
- AlicenseAqualityCmaintenanceMCP server that serves agent skills (SKILL.md bundles) to any MCP client, exposing them via tools and resources for tool-oriented and resource-aware clients.313 npmISC