Skip to main content
Glama

skill-router-mcp

npm version license

Skill routing for SKILL.md libraries, served over MCP to any agent.

Point it at a directory of Agent Skills (SKILL.md files with YAML frontmatter) and any MCP client — Claude Code, Cursor, Windsurf, Codex, or your own agent — can discover skills, match a task to the best one, and load instructions on demand without blowing its context window.

skill-router-mcp demo

match_skill("create a word document")
  → [{ name: "docx", score: 0.85, requires: ["filesystem", "python"] }, ...]
get_skill("docx")
  → full SKILL.md instructions (token-capped, section-aware)

Why this exists (honest version)

Claude Code and Codex now load Agent Skills natively, and several MCP skill servers already exist (skillz, mcp-skill-hub, skillserver, Skills Over MCP). What none of them do is rank skills against a task query — they rely on the host LLM picking from descriptions, which degrades as skill libraries grow. This project's focus is the routing layer: a scored match_skill backed by local embeddings (Ollama + nomic-embed-text, with automatic keyword fallback), plus strict path security and context-window discipline.

Measured on a 48-query labeled benchmark over 16 skills (queries written before measuring, not tuned):

Engine

Top-1

Top-3

MRR

ms/query

keyword

77.1%

85.4%

0.813

~1

semantic (nomic-embed-text)

93.8%

97.9%

0.958

~69

Both engines score 100% on queries that share words with the skill description — the gap is entirely on paraphrased (62.5% → 93.8%) and indirect (68.8% → 87.5%) queries like "combine several invoices into a single file for printing"pdf. Reproduce with npm run benchmark.

Every match_skill response reports which engine produced the ranking (semantic or keyword), so fallback is never silent.

Quick start

Run it straight from npm — no clone, no build:

SKILLS_ROOT=/path/to/skills npx skill-router-mcp

Wire it into Claude Code (.mcp.json in your project):

{
  "mcpServers": {
    "skill-router": {
      "command": "npx",
      "args": ["skill-router-mcp"],
      "env": { "SKILLS_ROOT": "/absolute/path/to/your/skills" }
    }
  }
}

Semantic matching is optional — install Ollama and ollama pull nomic-embed-text to enable it; otherwise it falls back to keyword matching automatically.

From source

git clone https://github.com/anujkumar8076/skill-router-mcp
cd skill-router-mcp
npm install && npm run build
SKILLS_ROOT=/path/to/skills node dist/index.js

Tools

Tool

Purpose

list_skills()

All skills — name + description only (cheap, call first)

match_skill(query, top_k?)

Top-k skills for a task, with 0–1 scores and requires

get_skill(name)

Full SKILL.md, capped at MAX_TOKENS (default 8000); returns truncated + sections

get_skill_section(name, section)

One H2 section — for skills too big for one fetch

rescan_skills()

Force re-index (a chokidar watcher also auto-reindexes)

SEP-2640 resources

Skills are also served through the MCP Resources primitive per the Skills Over MCP Working Group draft (SEP-2640), so any spec-aware host can consume them without knowing this server's tools:

  • skill://index.json — enumerable discovery index (Agent Skills discovery schema 0.2.0)

  • skill://<name>/SKILL.md — each skill as a text/markdown resource, with requires/works_in frontmatter exposed under the io.modelcontextprotocol.skills/ _meta prefix

  • The io.modelcontextprotocol/skills extension capability is declared at initialization

Resource reads pass through the same allowlist validation as the tools.

Skill format

Standard Agent Skills format, with two optional routing fields:

---
name: docx
description: "Use when the user wants to create or edit Word documents."
requires: [filesystem, python]   # tools the agent needs to execute this skill
works_in: [claude_code]          # environments the skill is known to work in
---
# Instructions...

Agents should check requires against their own toolset before loading a skill — this server delivers instructions; your agent supplies execution.

Configuration

Env var

Default

Meaning

SKILLS_ROOT

./skills

Directory scanned (recursively) for SKILL.md files

MAX_TOKENS

8000

Token cap on get_skill responses

WATCH_SKILLS

true

Set false to disable the file watcher (network drives, Docker volumes — use rescan_skills instead)

EMBEDDINGS

auto

auto = semantic if Ollama is reachable, else keyword; on / off to force

OLLAMA_URL

http://127.0.0.1:11434

Ollama endpoint for embeddings

EMBEDDING_MODEL

nomic-embed-text

Embedding model (ollama pull nomic-embed-text first)

Skill vectors are cached by content hash in ~/.cache/skill-router-mcp/embeddings.json, so restarts and re-indexes only embed skills whose text changed. If Ollama goes down mid-session, matching degrades to keyword automatically — routing never hard-fails.

Security model

  • Allowlist, not paths. Skill names are sanitized to [a-z0-9_-], looked up in an index built at startup, and the resolved file is canonicalized and verified to live inside SKILLS_ROOT. User input never constructs a path.

  • Rejected lookups are logged to stderr.

  • Trust boundary: skill content is injected into your agent's context. Only point SKILLS_ROOT at skills you trust — a 2026 study of 31k marketplace skills found ~26% contained prompt-injection or exfiltration patterns.

  • Index-time content lint. Every skill is scanned for suspicious patterns: prompt injection ("ignore previous instructions"), concealment ("don't tell the user"), exfiltration (send-to-URL, known exfil endpoints), credential access (~/.ssh, .env, API-key harvesting), pipe-to-shell, decode-and-execute, destructive commands, and opaque base64 blobs. Findings are logged at index time, shown as lint_warnings in list_skills, and attached to get_skill responses before the content so a reviewing agent sees the warning first. The lint flags — it never blocks — and rules favor precision over recall.

Roadmap

  • Embedding-based match_skill (local, Ollama nomic-embed-text) behind the Matcher interface, with content-hash caching + keyword fallback

  • Routing benchmark: keyword vs. embeddings on a 48-query labeled set — see benchmark/RESULTS.md

  • Index-time content lint for suspicious skill patterns (10 rules, surfaced in list_skills and get_skill)

  • SEP-2640 alignment: skill:// resources, skill://index.json discovery index, and the skills extension capability

Development

npm test               # vitest: security, indexer, matchers, content
npm run build          # tsc → dist/
node scripts/smoke.mjs # drive the built server over stdio with real queries
npm run benchmark      # keyword vs semantic routing accuracy (needs Ollama)

MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/anujkumar8076/skill-router-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server