skills-mcp-server
Serves SKILL.md-based skills as MCP resources and tools over streamable HTTP, enabling remote discovery and retrieval of skill files with full YAML frontmatter parsing.
README
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) 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.
-
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.
Configuration
All configuration is via environment variables (see .env.example):
| Variable | Default | Meaning |
|---|---|---|
SKILLS_DIR |
/skills |
Root directory to scan for skill folders |
MCP_HOST |
0.0.0.0 |
Host/interface the HTTP transport binds to |
MCP_PORT |
8010 |
Port the HTTP transport binds to |
SKILLS_RELOAD |
true |
If true, re-scan the skills directory on every request. Default on since an external process (e.g. a cron job re-cloning a skills repo into the mounted volume) may mutate content behind the server's back. Set false for a static skills directory to skip re-scan overhead. |
SKILLS_SUPPORTING_FILES |
resources |
resources (list every file upfront) or template (lazy URI template) |
LOG_LEVEL |
INFO |
Standard Python logging level |
A GET /health route is also registered for container/orchestrator liveness checks.
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.)
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", "skills_dir": "./example-skills"}
Docker quickstart
docker compose up --build
This 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:ro
Compose 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:local
Connecting 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
└── src/skills_mcp_server/
├── __init__.py
├── config.py # env-driven Settings
├── discovery.py # full YAML frontmatter parsing for list_skills/get_skill
├── tools.py # list_skills / get_skill MCP tool definitions
└── server.py # FastMCP app wiring, provider, health route, entrypoint
License
Apache License 2.0 — see LICENSE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.