Documentation

A condensed reference. For the complete guide, see the README on GitHub.

Skills on disk

Skills live under DATA_DIR/skills/ in either of two shapes. Both use YAML frontmatter (name, description) followed by the markdown body.

Flat file

A single <name>.md โ€” the simplest skill:

---
name: commit-messages
description: Write clear, conventional git commit messages.
---

# Writing good commit messages

...the skill body...

Directory (Claude Code convention)

A <name>/SKILL.md plus any supporting files โ€” reference docs, scripts, templates:

skills/pdf-forms/
โ”œโ”€โ”€ SKILL.md           # frontmatter + body
โ”œโ”€โ”€ reference.md       # supporting file
โ””โ”€โ”€ scripts/fill.py    # nested supporting file

Supporting files are listed on the skill and referenced in the rendered tool output, so the agent knows they exist. Manage them from the web UI's file tree โ€” create, upload, rename, delete, or export the whole skill as a .zip โ€” or edit them directly on disk.

Frontmatter

The name must be a slug: lowercase letters, digits, ., _, - (max 64 chars). It doubles as the MCP tool name (dots sanitized to _) and the resource URI (skill://<name>). description is surfaced as the MCP tool/resource description. An optional tags key (a comma-separated string or a YAML list) organises skills and feeds the search_skills filter. Unknown frontmatter keys are preserved across round-trips.

Workspaces

A workspace is a named subset of skills served at its own /mcp/w/<slug> endpoint. It is a JSON file at DATA_DIR/config/workspaces/<slug>.json:

{
  "name": "Backend",
  "slug": "backend",
  "enabled": true,               // false = the /mcp/w/<slug> endpoint 404s
  "description": "Skills for backend work.",
  "skills": ["commit-messages", "pdf-forms"]
}

Served at /mcp/w/backend over HTTP and via --workspace backend over stdio. The slug is derived from the name and doubles as the filename. Manage workspaces from the Workspaces page in the web UI, or edit the files directly โ€” changes are picked up automatically.

Configuration

Everything lives under DATA_DIR (default ./data locally, /data in Docker). Config files are written atomically with mode 0600. Edits on disk are watched (debounced) and hot-reloaded; you can also force a re-read:

curl -X POST -H "Authorization: Bearer $MCP_SKILLS_TOKEN" \
  http://localhost:3000/api/reload
data/
โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ settings.json          # port, auth token, auth/authoring toggles, tool mode, httpLiveUpdates
โ”‚   โ””โ”€โ”€ workspaces/
โ”‚       โ””โ”€โ”€ <slug>.json        # one file per workspace
โ””โ”€โ”€ skills/
    โ”œโ”€โ”€ <name>.md              # flat-file skill
    โ””โ”€โ”€ <name>/                # directory-format skill
        โ”œโ”€โ”€ SKILL.md
        โ””โ”€โ”€ <supporting files>

Environment variables

VariableDefaultDescription
DATA_DIR./dataRoot directory for skills and config
PORT3000HTTP listen port (or settings.json)
MCP_SKILLS_TOKENโ€”Bearer token; overrides settings.json
SECURE_LOCAL_NETfalsetrue disables auth entirely (trusted networks only)

If no token is configured and SECURE_LOCAL_NET is not set, a random token is generated into settings.json on first run and logged once.

REST API

Management API under /api, bearer auth, JSON in/out. Errors are non-2xx with { "error": "...", "detail": "..." }.

Method & pathPurpose
GET /api/statusVersion, uptime, skill/workspace counts, auth mode, port
GET /api/settingsRead auth/authoring toggles, tool mode, live updates
PATCH /api/settingsUpdate authoringEnabled / skillToolMode / httpLiveUpdates
GET /api/skillsList skills (summaries)
POST /api/skillsCreate a skill
POST /api/skills/importImport an uploaded .md / directory / zip
GET /api/skills/:nameGet a skill (with body)
PATCH /api/skills/:nameUpdate body/description, or rename
DELETE /api/skills/:nameDelete a skill
GET /api/skills/:name/exportDownload the skill as a .zip
GET /api/skills/:name/files/content?path=Read one supporting file
PUT /api/skills/:name/filesAdd/overwrite a supporting file (promotes to a dir)
POST /api/skills/:name/foldersCreate an empty sub-folder
POST /api/skills/:name/files/moveRename / move a file or folder
DELETE /api/skills/:name/files?path=Delete a file or folder
GET/POST /api/workspacesList / create workspaces
GET/PATCH/DELETE /api/workspaces/:slugGet / update / delete a workspace
POST /api/reloadRe-read all config from disk

MCP endpoints

EndpointPurpose
ALL /mcpEvery skill โ€” each as a tool and a skill:// resource
ALL /mcp/w/<slug>A workspace's skills only
mcp-skills-stdiostdio transport; --data-dir, optional --workspace <slug>

The HTTP endpoints speak streamable HTTP and require the bearer token (unless authEnabled is false). Disabled workspaces return 404; auth failures return 401 before any MCP handling.

Discovering skills

Every endpoint exposes two discovery meta-tools. list_skills returns a JSON catalogue of the available skills โ€” name, description, format, tags, supporting files, updatedAt, and the tool name to call to load each โ€” without any skill bodies. search_skills returns the same shape, filtered by a free-text query (matched against name, description, tags, and body) and/or a tags filter. An agent discovers what's on offer first, then calls the named tool (or reads the matching skill://<name> resource) to pull the full contents.

Tool modes

How skills are advertised as tools is set globally (and overridable per workspace) via skillToolMode:

  • per-skill (default) โ€” one no-arg tool per skill; calling it returns that skill's body.
  • loader โ€” a single load_skill(name) tool, so the advertised tool count stays fixed no matter how many skills the endpoint serves.

Resources

Every skill is also an MCP resource at skill://<name>, and each bundled supporting file at skill://<name>/<path> (path segments percent-encoded so names with spaces or % round-trip). The endpoint advertises RFC 6570 resource templates (skill://{name} and skill://{name}/{+path}) with argument completion over skill names and file paths, and resources/list is paginated with opaque cursors.

Clients that subscribe receive live updates (notifications/resources/list_changed and resources/updated) when skills change on disk. This is always on over stdio. Over HTTP it needs stateful sessions โ€” enable httpLiveUpdates in settings and the server keeps a session per client (via Mcp-Session-Id) and pushes over SSE; otherwise HTTP stays stateless and clients re-poll resources/list.

Authoring over MCP

When authoring is enabled (the default), every endpoint also exposes tools for agents to write and refine their own skills โ€” create_skill, update_skill, rename_skill, delete_skill, and supporting-file tools (write_skill_file, read_skill_file, create_skill_folder, move_skill_file, delete_skill_file). A skill authored through a workspace endpoint is scoped to that workspace by default; skills authored at the root /mcp are global. Toggle the whole feature with authoringEnabled in settings.

Security notes

  • The auth token is plaintext in settings.json. Files are mode 0600, but anyone with read access to DATA_DIR can read it. Protect the directory.
  • One bearer token guards everything. Treat it like a password. Set it via MCP_SKILLS_TOKEN.
  • Don't expose the server directly to the internet โ€” it speaks plain HTTP. Put it behind a TLS-terminating reverse proxy, or bind to localhost / a private network.
  • Skills are content, not code โ€” the server serves markdown; it doesn't execute supporting scripts. But agents may act on what a skill tells them, so treat skill content as trusted instructions.

Read the full README โ†—