skillsdotnet
C# implementation of agent skills (agentskills.io) with MCP integration and convenience.
SkillsDotNet
Agent skills (agentskills.io) for the C# MCP SDK.
Experimental: This package is under active development and its API is subject to change.
Skills provide "context-as-progressive-disclosure" via SKILL.md files. This library uses a skill:// URI convention to distribute skills as MCP resources -- clients can load frontmatter for discovery (~50-100 tokens), full SKILL.md on demand, and supporting files as needed.
Installation
dotnet add package SkillsDotNet.Mcp
Requires the official C# MCP SDK (ModelContextProtocol package).
If you only need the core skill types (parsing, validation, scanning) without the MCP transport layer:
dotnet add package SkillsDotNet
Server-Side Usage
Register a single skill directory
builder.Services
.AddMcpServer()
.WithSkill("/path/to/my-skill");
Register all skills from a directory
Each subdirectory containing a SKILL.md is registered as a skill:
builder.Services
.AddMcpServer()
.WithSkillsDirectory("/path/to/skills");
Vendor shortcuts
Register skills from well-known agent directories:
builder.Services
.AddMcpServer()
.WithClaudeSkills() // ~/.claude/skills/
.WithCursorSkills() // ~/.cursor/skills/
.WithCopilotSkills() // ~/.copilot/skills/
.WithCodexSkills() // /etc/codex/skills/ + ~/.codex/skills/
.WithGeminiSkills() // ~/.gemini/skills/
.WithGooseSkills() // ~/.config/agents/skills/
.WithOpenCodeSkills(); // ~/.config/opencode/skills/
Options
builder.Services
.AddMcpServer()
.WithSkillsDirectory("/path/to/skills", new SkillOptions
{
// List every file as a separate resource (default: Template)
SupportingFiles = SkillFileMode.Resources,
// Custom main file name (default: "SKILL.md")
MainFileName = "SKILL.md"
});
Client-Side Usage
Discover skills on a server
var skills = await client.ListSkillsAsync();
foreach (var skill in skills)
{
Console.WriteLine($"{skill.Name}: {skill.Description}");
}
Read a skill's manifest
var manifest = await client.GetSkillManifestAsync("code-review");
foreach (var file in manifest.Files)
{
Console.WriteLine($" {file.Path} ({file.Size} bytes, {file.Hash})");
}
Download a skill locally
var path = await client.DownloadSkillAsync("code-review", targetDirectory: "./skills");
Sync all skills from a server
var paths = await client.SyncSkillsAsync(targetDirectory: "./skills");
Using skills with IChatClient
SkillCatalog discovers skills from one or more MCP servers and provides two things for use with Microsoft.Extensions.AI: context blocks (frontmatter summaries for the system prompt) and a load_skill tool the model can call to load a skill's full content on demand.
// Build a catalog from one or more MCP servers
var catalog = new SkillCatalog();
await catalog.AddClientAsync(mcpClient1);
await catalog.AddClientAsync(mcpClient2);
// Get frontmatter context blocks β add to the system message so the
// model knows what skills are available (~50-100 tokens each)
var contexts = catalog.GetSkillContexts(); // IReadOnlyList<TextContent>
var messages = new List<ChatMessage>
{
new(ChatRole.System, [
new TextContent("You are a helpful assistant. The following skills are available:"),
.. contexts
]),
new(ChatRole.User, "Help me review this pull request"),
};
// Get the load_skill tool β add to ChatOptions.Tools so the model
// can load a skill's full SKILL.md content when it decides to use one
var options = new ChatOptions
{
Tools = [catalog.LoadSkillTool],
};
var response = await chatClient.GetResponseAsync(messages, options);
If a server disconnects, remove its skills from the catalog:
catalog.RemoveClient(mcpClient1);
Handling skill dependencies
Skills can declare MCP server dependencies in their frontmatter:
---
name: explore-everything
description: Explores an MCP server
dependencies: [everything-server]
---
When a skill with dependencies is loaded via the load_skill tool, the OnDependenciesRequired callback fires so the client host can connect to the required servers on demand:
catalog.OnDependenciesRequired = async (request, cancellationToken) =>
{
Console.WriteLine($"Skill '{request.SkillName}' requires: {string.Join(", ", request.ServerNames)}");
foreach (var serverName in request.ServerNames)
{
// Look up and connect to the server using your own configuration
var client = await ConnectToServerAsync(serverName, cancellationToken);
if (client is null)
return false; // Signal failure β LoadSkillAsync will throw
}
return true; // All dependencies satisfied
};
The callback receives a SkillDependencyRequest with the skill name and the list of required server names. Return true when all servers are connected, or false to abort (which causes LoadSkillAsync to throw InvalidOperationException). If the callback is not set, skills with dependencies load silently without notification.
See the DynamicMcpServers sample for a complete example.
URI Convention
Each skill exposes three resources following the FastMCP convention:
| URI | Type | Content |
|---|---|---|
skill://{name}/SKILL.md |
Resource (listed) | Full SKILL.md content |
skill://{name}/_manifest |
Resource (listed) | JSON manifest with file listing |
skill://{name}/{+path} |
ResourceTemplate | Supporting files on demand |
Manifest format
{
"skill": "code-review",
"files": [
{ "path": "SKILL.md", "size": 512, "hash": "sha256:abc123..." },
{ "path": "references/checklist.md", "size": 256, "hash": "sha256:def456..." }
]
}
Writing a Skill
A skill is a directory containing a SKILL.md file with YAML frontmatter:
my-skill/
SKILL.md
references/
example.md
---
name: my-skill
description: What this skill does
license: MIT
compatibility: claude, cursor
metadata:
author: your-name
version: "1.0"
---
# My Skill
Instructions for the agent go here.
Frontmatter fields
| Field | Required | Description |
|---|---|---|
name |
Yes | 1-64 chars, lowercase alphanumeric + hyphens, must match directory name |
description |
Yes | 1-1024 chars |
license |
No | License identifier |
compatibility |
No | Comma-separated list of compatible agents (max 500 chars) |
dependencies |
No | List of required MCP server names (connected on demand via OnDependenciesRequired) |
allowed-tools |
No | Experimental tool restrictions |
metadata |
No | Arbitrary key-value pairs for client-specific data |
Name rules
Per the agentskills.io spec:
- Lowercase letters, digits, and hyphens only
- No leading, trailing, or consecutive hyphens
- NFKC normalized, max 64 characters
- Must match the directory name
Packages
| Package | Description |
|---|---|
SkillsDotNet |
Core library: FrontmatterParser, SkillValidator, SkillDirectoryScanner, SkillInfo, SkillFileInfo, SkillContextExtensions. Depends on Microsoft.Extensions.AI.Abstractions. |
SkillsDotNet.Mcp |
MCP transport layer: SkillResourceFactory, SkillCatalog, builder extensions, client extensions. Depends on SkillsDotNet and ModelContextProtocol. |
Target Frameworks
- .NET 10
- .NET 9
- .NET 8
Acknowledgements
Many conventions and especially the server-side resource implementations in this library are inspired by FastMCP 3.0. We've tried to align with FastMCP whenever possible.
License
MIT