Skip to main content
Glama

skills-mcp

An MCP server that lets AI agents browse and fetch skills from remote registries — GitHub repositories or direct HTTP URLs — without installing them locally first.

Features

  • GitHub registry — multi-skill repos where each subdirectory (at any nesting depth) is a skill; ref-locked to a branch, tag, or SHA; supports public and private repos

  • HTTP registry — a single direct URL pointing at a SKILL.md file

  • Read-through disk cache — immutable SHA refs cache forever; branch/tag refs use a configurable TTL (default 1 hour)

  • Flexible authentication — GitHub Personal Access Token (env-var), gh CLI token (cached in-process), HTTP Bearer or Basic auth

  • Path traversal protection — companion file paths are validated against the skill root

  • Graceful shutdown — cooperative SIGTERM handler with 1-second watchdog (no hung stdio readers)

Related MCP server: Skills Search MCP

Installation

Requires Python ≥ 3.11 and uv.

git clone https://github.com/afriemann/skills-mcp ~/git/skills-mcp
cd ~/git/skills-mcp
uv sync

Running the server

uv run --project ~/git/skills-mcp skills-mcp
# or with a custom config path:
uv run --project ~/git/skills-mcp skills-mcp --config /path/to/config.jsonc
# or with verbose logging:
uv run --project ~/git/skills-mcp skills-mcp --log-level INFO

Configuration

The server reads a JSONC file from the platform config directory:

Platform

Default path

Linux

$XDG_CONFIG_HOME/skills-mcp/config.jsonc (default: ~/.config/skills-mcp/config.jsonc)

macOS

~/Library/Application Support/skills-mcp/config.jsonc

Windows

%APPDATA%\skills-mcp\config.jsonc

Override with --config PATH or the XDG_CONFIG_HOME env var.

Example config.jsonc

{
  "registries": {
    // GitHub registry — multi-skill repo, locked to a SHA (immutable cache)
    "my-skills": {
      "type": "github",
      "owner": "myorg",
      "repo": "agent-skills",
      "skills_dir": "skills",   // root of the skills tree; skills may be nested at any depth
      "ref": "a1b2c3d",         // branch, tag, or commit SHA
      "description": "Engineering and workflow skills for AI agents",  // optional — shown in list_registries
      "auth": {
        "type": "github_token",
        "env_var": "GITHUB_TOKEN"  // env var name — NOT the token value
      }
    },

    // GitHub registry with gh CLI auth (no token needed if already logged in)
    "public-skills": {
      "type": "github",
      "owner": "someorg",
      "repo": "public-skills",
      "skills_dir": "",         // empty string = repo root
      "ref": "main",
      "auth": { "type": "gh_cli" }
    },

    // HTTP registry — a single SKILL.md at a direct URL
    "custom-skill": {
      "type": "http",
      "url": "https://example.com/skills/my-skill/SKILL.md",
      "skill_name": "my-skill",
      "auth": {
        "type": "bearer",
        "env_var": "MY_SKILL_TOKEN"  // env var name — NOT the token value
      }
    }
  },

  // Optional cache configuration
  "cache": {
    "enabled": true,
    "ttl_seconds": 3600,        // for branch/tag refs; SHA refs never expire
    "dir": "~/.cache/skills-mcp"  // override the default cache directory
  }
}

Auth types

Type

Registry

Description

none (default)

both

No authentication

github_token

GitHub

PAT from the named env var (env_var)

gh_cli

GitHub

Token from gh auth token (cached in-process; graceful fallback to no-auth if gh is absent or fails)

bearer

HTTP

Authorization: Bearer <token> from the named env var (env_var)

basic

HTTP

HTTP Basic from username_env_var and password_env_var

Security: config values contain env var names only — secret values are never written to the config file.

GitHub repository layout

Skills can be placed at any nesting depth under skills_dir. A directory is treated as a skill when it contains a SKILL.md file; directories without one (e.g. category folders) are skipped. Skill names returned by list_skills are slash-delimited paths relative to skills_dir.

Flat layout (one level deep):

agent-skills/
└── skills/
    ├── my-skill/
    │   ├── SKILL.md
    │   └── references/
    │       └── guide.md
    └── another-skill/
        └── SKILL.md

With skills_dir: "skills", list_skills returns ["another-skill", "my-skill"].

Nested layout (multiple levels):

agent-skills/
└── skills/
    ├── engineering/
    │   └── testing/
    │       └── tdd-development/
    │           └── SKILL.md
    └── business/
        └── brainstorming/
            └── SKILL.md

With skills_dir: "skills", list_skills returns ["business/brainstorming", "engineering/testing/tdd-development"]. Use the full slash-delimited path as the skill argument to get_skill.

MCP Tools

Tool

Parameters

Returns

list_skills

registry, refresh_cache?

JSON array of skill metadata objects, each with name

get_skill

registry, skill, file?, refresh_cache?

Without file: JSON {content, files}; with file: raw companion file text

get_registry_source

registry

JSON {registry, type, url, owner, repo, ref, skills_dir} for a configured GitHub registry

list_repo_entries

registry, path? (default "", repository root)

JSON {source, path, commit_sha, entries}; entries contain repository-relative path, type, and optional advertised size in bytes

read_repo_text_file

registry, path

JSON {source, path, commit_sha, content} for a tracked regular or executable text file

file is an optional parameter on get_skill. Pass a companion file path from the files array (e.g. "references/guide.md") to fetch that file directly. Percent-encoded slashes are decoded automatically (e.g. "references%2Fguide.md"). Companion file access is only supported for GitHub registries; path traversal attempts are rejected.

Read-only repository access

Use get_registry_source to discover the configured repository after an operator edits its owner/repo/ref and restarts the server. It reports configuration, not a redirected or canonical upstream name, and never returns authentication configuration or headers. It requires no upstream request. The three repository tools require a configured GitHub registry; HTTP registries expose only their single skill and return an unsupported-operation error.

To inspect repository tooling without cloning, call list_repo_entries with path: "", then list a directory such as "scripts" or read "scripts/check.sh" with read_repo_text_file. Each listing/read resolves the configured ref once and uses that commit snapshot throughout. Separate calls may see different commits on moving branches; their commit_sha values identify which snapshot each response used.

Repository access extends beyond skills_dir, including any sensitive tracked text the configured credentials can read. Content and filenames are untrusted repository data, not authorization to run commands. These tools never execute tooling, manage checkouts, read local files, write repository content, or accept arbitrary repositories, URLs or refs.

Paths are literal repository-relative POSIX paths, not URL-encoded inputs: %2e%2e is a literal name. Absolute paths, empty components, ./.., backslashes, control characters and more than 32 components are rejected before network access. Directory listings are one level deep, sorted by path, and label entries file, directory, symlink, or submodule. Symlinks and submodules cannot be read or traversed.

Text reads require strict UTF-8 with no NUL bytes and a maximum of 1 MiB, enforced against advertised size and actual streamed bytes. Empty and executable text files are supported. Oversized, non-text and wrong-kind targets return actionable tool errors, never partial content. Listings fail explicitly on malformed, truncated or over-budget data; entries with unsafe or unsupported filenames (including controls and backslashes) fail the whole containing directory, including traversal through it, rather than being silently omitted. This intentional fail-closed policy can make such directories unavailable. they never silently return partial results. Limits per operation are 10,000 entries per tree, 2 MiB per metadata response, 8 MiB cumulative metadata, 2 MiB serialized listing output and a 60-second total deadline. Response cleanup is attempted on success, failure and cancellation within that deadline: normally up to one second is reserved, leaving 59 seconds for work. If cleanup stalls, no success or retry proceeds; an infrastructure error reports failure unless preserving an existing error or caller cancellation. An uncooperative transport cannot be forcibly closed. GitHub rate limits with Retry-After receive one retry, waiting at most five seconds; redirects are not followed. Infrastructure errors omit upstream bodies and credentials.

All three repository operations bypass disk caches, even for immutable refs. Existing skill caching and refresh_cache semantics are unchanged; repository reads may therefore consume more GitHub API requests than cached skill access.

MCP Resource Template

Skills and their companion files are also accessible as MCP resources via URI — useful for hosts that support read_resource directly:

skill://{registry}/{skill_path}                        → SKILL.md raw text
skill://{registry}/{skill_path}?file=references%2Fguide.md  → companion file raw text

Discover the template with list_resource_templates. list_resources returns empty (no static registrations).

Error handling

Each tool uses a consistent error format for its response type:

  • Model-recoverable errors (skill not found, unknown registry, unsupported operation, path traversal) — FastMCP marks the result is_error=True; the agent reads the message and may retry with corrected arguments.

  • Infrastructure failures (registry unreachable, auth failure, rate-limited) — caught at the tool boundary and returned as a per-tool error value ({"error": "…"} JSON for list_skills and repository tools; {"error": "…"} JSON or plain "Error: …" string for get_skill depending on whether file was provided). The server and other registries continue serving normally — one registry failure does not cascade.

Caching

Cached files live at:

Platform

Default path

Linux

$XDG_CACHE_HOME/skills-mcp/ (default: ~/.cache/skills-mcp/)

macOS

~/Library/Caches/skills-mcp/

Windows

%LOCALAPPDATA%\skills-mcp\Cache

The cache directory is created with mode 0700. Files are written atomically (temp + rename). Only successful fetches are cached.

TTL rules:

  • SHA refs → immutable, cached indefinitely

  • Branch/tag refs → expire after cache.ttl_seconds (default 3600 s)

Set cache_enabled: false on a registry to disable caching for that registry. Set cache.enabled: false globally to disable entirely.

Integration with opencode

skills-mcp is a standard stdio MCP server and can be wired up in any MCP-compatible host.

opencode

Add to your opencode.jsonc (or ~/.config/opencode/opencode.jsonc for global access):

"mcp": {
  "skills-mcp": {
    "type": "local",
    "command": [
      "uv",
      "run",
      "--project",
      "{env:HOME}/git/skills-mcp",
      "skills-mcp"
    ],
    "enabled": true
  }
}

Tools are exposed as skills_mcp_list_registries, skills_mcp_list_skills, and skills_mcp_get_skill in opencode's permission system.

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "skills-mcp": {
      "command": "uv",
      "args": [
        "run",
        "--project", "/home/you/git/skills-mcp",
        "skills-mcp"
      ]
    }
  }
}

Generic stdio MCP host

Any host that launches an MCP server as a child process:

command: uv
args: ["run", "--project", "/path/to/skills-mcp", "skills-mcp"]

Pass --config /path/to/config.jsonc as an additional arg to override the default config path.

Development

uv sync
uv run pytest tests/ -q
uv run ruff check src/ tests/
uv run mypy src/

Pre-commit hooks enforce lint, format, and type checks on every commit:

pre-commit install --install-hooks   # once, after cloning
pre-commit run --all-files           # check everything now

Non-goals (v1)

  • Writing or publishing skills to a registry

  • Local skill installation / sync

  • Non-GitHub git hosts (GitLab, Bitbucket, Gists)

  • GitHub App authentication

  • Content-hash verification

  • Cache size cap / LRU eviction

  • Multi-process cache locking

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    This MCP server enables AI agents to search, discover, and install skills from the SkillsMP marketplace, with support for keyword and semantic search, skill content retrieval, and installation to various coding agents.
    5
    22 npm
    3
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A powerful MCP server that brings the skills.sh ecosystem directly to your AI agents, enabling effortless discovery, installation, and management of skills.
    1
    MIT