@vurb/skills
v3.19.6
Published
Agent Skills distribution via MCP. Progressive disclosure (search → load → read) for teaching AI agents domain-specific procedures through the SKILL.md standard.
Maintainers
Readme
MCP Agent Skills for Vurb.ts, the Model Context Protocol framework for building production MCP servers. Parse, validate, search, and serve SKILL.md files via MCP — context-efficient three-layer progressive disclosure keeps agent context windows lean.
What Are Agent Skills?
A skill is a directory containing a SKILL.md file with YAML frontmatter and markdown instructions.
Skills teach AI agents how to perform domain-specific tasks — from deploying infrastructure to generating reports.
skills/
├── pdf-processing/
│ ├── SKILL.md # Frontmatter + instructions
│ ├── scripts/extract.py # Auxiliary files
│ └── assets/template.docx
├── deploy-k8s/
│ └── SKILL.md
└── data-migration/
├── SKILL.md
└── references/schema.sqlSKILL.md Format
---
name: pdf-processing
description: Extract text, tables, and images from PDF documents
version: 1.0.0
license: MIT
compatibility:
- Claude
- GPT-4
metadata:
category: document-processing
tags:
- pdf
- extraction
---
# PDF Processing
Step-by-step instructions for the agent...Progressive Disclosure
Instead of flooding the agent's context with every skill, @vurb/skills serves information in three layers:
Layer 1 — Search → Lightweight metadata (id, name, description)
Layer 2 — Load → Full instructions + file list
Layer 3 — Read File → Auxiliary file content on demandThis mirrors how developers browse documentation: search → read overview → dive into details.
Quick Start
import { initVurb } from '@vurb/core';
import {
SkillRegistry,
autoDiscoverSkills,
createSkillTools,
} from '@vurb/skills';
// 1. Initialize
const f = initVurb<AppContext>();
const skills = new SkillRegistry();
// 2. Discover skills from a directory
await autoDiscoverSkills(skills, './skills');
// 3. Create MCP tools (search, load, read_file)
const [search, load, readFile] = createSkillTools(f, skills);
// 4. Register with your server
const registry = f.registry();
registry.registerAll(search, load, readFile);Three tools are now available to any connected agent:
| Tool | Purpose |
|------|---------|
| skills.search | Find skills by natural-language query |
| skills.load | Load full instructions for a skill |
| skills.read_file | Read auxiliary files (scripts, assets) |
Features
Parsing
Parse SKILL.md files with YAML frontmatter extraction:
import { parseSkillMd } from '@vurb/skills';
const skill = parseSkillMd(markdownContent, '/path/to/skill', ['scripts/run.sh']);
// → { id, name, description, instructions, frontmatter, files }For lower-level control:
import { extractFrontmatter, toSkillFrontmatter } from '@vurb/skills';
const { frontmatter, body } = extractFrontmatter(rawContent);
const typed = toSkillFrontmatter(frontmatter);Validation
Validate skills against the agentskills.io specification:
import { validateSkill, formatValidationIssues } from '@vurb/skills';
const result = validateSkill(skill.frontmatter);
if (!result.valid) {
console.error(formatValidationIssues(result.issues));
}Validation checks include:
- Required fields (
name,description) - Name format (kebab-case, length limits)
- Description quality (minimum length)
- Compatibility entries
- Metadata structure
Full-Text Search
MiniSearch-powered search engine with prefix matching, fuzzy search, and field boosting:
import { FullTextSearchEngine } from '@vurb/skills';
const engine = new FullTextSearchEngine();
engine.rebuild([
{ id: 'pdf-processing', name: 'PDF Processing', description: '...' },
{ id: 'deploy-k8s', name: 'K8s Deploy', description: '...' },
]);
const results = engine.search('extract pdf', 5);
// → [{ id: 'pdf-processing', name: '...', description: '...', score: 12.5 }]Registry
Central hub for skill management with built-in validation and search:
import { SkillRegistry } from '@vurb/skills';
const registry = new SkillRegistry({
validateOnRegister: true, // enforce spec compliance
strictValidation: false, // warnings don't block registration
});
// Register individually
registry.register(skill, 'pdf-processing');
// Register in batch (atomic — all or nothing)
registry.registerAll([skillA, skillB], ['skill-a', 'skill-b']);
// Search (Layer 1)
const { skills, total } = registry.search('extract pdf', 10);
// Load full instructions (Layer 2)
const loaded = registry.load('pdf-processing');
// Read auxiliary file (Layer 3)
const file = await registry.readFile('pdf-processing', 'scripts/extract.py');Auto-Discovery
Recursively scan directories for SKILL.md files:
import { SkillRegistry, autoDiscoverSkills } from '@vurb/skills';
const skills = new SkillRegistry();
const ids = await autoDiscoverSkills(skills, './skills', {
recursive: true, // scan subdirectories (default: true)
strict: false, // skip invalid skills instead of throwing
onError: (path, err) => console.warn(`Skipping ${path}`, err),
});
console.log(`Discovered ${ids.length} skills`);Supports two directory layouts:
skills/skill-name/SKILL.md # Directory per skill
skills/SKILL.md # Single skill at rootMCP Tool Factory
Generate ready-to-use MCP tools with a single call:
import { createSkillTools } from '@vurb/skills';
const tools = createSkillTools(f, registry, {
prefix: 'skills', // tool name prefix (default: 'skills')
searchLimit: 10, // max results per search (default: 10)
});The factory uses duck-typed interfaces — it works with any object that implements the query() fluent builder pattern, avoiding hard coupling to Vurb.ts internals.
Security
- Path traversal protection —
readFileblocks.., absolute paths, andSKILL.mdaccess - Case-insensitive guards — filenames like
skill.mdandSKILL.MDare also blocked - File size limits — OOM protection with a configurable maximum file size (default: 1 MB)
- Error sanitization — absolute server paths are stripped from error messages
- Binary-safe — text files return UTF-8, binary files return Base64 with the correct MIME type
Types
Key types exported from the package:
interface SkillFrontmatter {
name: string;
description: string;
version?: string;
license?: string;
compatibility?: string;
metadata?: Record<string, unknown>;
allowedTools?: string[];
}
interface Skill {
id: string;
name: string;
description: string;
instructions: string;
filePath: string;
frontmatter: SkillFrontmatter;
files: string[];
}
interface SkillMetadata {
id: string;
name: string;
description: string;
}
interface SkillSearchResult {
id: string;
name: string;
description: string;
score: number;
}
interface SkillFileContent {
content: string;
path: string;
size: number;
encoding: 'utf-8' | 'base64';
mimeType: string;
}Installation
npm install @vurb/skillsPeer Dependencies
| Package | Version |
|---------|---------|
| vurb | ^3.0.0 |
| zod | ^3.25.1 \|\| ^4.0.0 |
Requirements
- Node.js ≥ 18.0.0
- Vurb.ts ≥ 3.0.0 (peer dependency)
