SkillsDotNet
 
代理技能(agentskills.io 网站)对于C#MCP SDK。
实验性: 此软件包正在积极开发中,其API可能会更改。
技能通过以下方式提供“渐进式披露的背景” SKILL.md 文件夹。这个图书馆使用 skill:// 将技能作为MCP资源分发的URI约定——客户端可以加载frontmatter进行发现(约50-100个令牌),按需加载完整的SKILL.md,并根据需要加载支持文件。
安装
dotnet add package SkillsDotNet.Mcp需要官方 C#mcpsdk (ModelContextProtocol 包装)。
如果你只需要核心技能类型(解析、验证、扫描)而不需要MCP传输层:
dotnet add package SkillsDotNet服务器端使用情况
注册单个技能目录
builder.Services
.AddMcpServer()
.WithSkill("/path/to/my-skill");从目录中注册所有技能
每个子目录包含一个 SKILL.md 已注册为技能:
builder.Services
.AddMcpServer()
.WithSkillsDirectory("/path/to/skills");供应商快捷方式
从知名代理商目录中注册技能:
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/选项
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"
});客户端使用情况
在服务器上发现技能
var skills = await client.ListSkillsAsync();
foreach (var skill in skills)
{
Console.WriteLine($"{skill.Name}: {skill.Description}");
}阅读技能清单
var manifest = await client.GetSkillManifestAsync("code-review");
foreach (var file in manifest.Files)
{
Console.WriteLine($" {file.Path} ({file.Size} bytes, {file.Hash})");
}在本地下载技能
var path = await client.DownloadSkillAsync("code-review", targetDirectory: "./skills");从服务器同步所有技能
var paths = await client.SyncSkillsAsync(targetDirectory: "./skills");使用技能 IChatClient
SkillCatalog 从一个或多个MCP服务器中发现技能,并提供两件事供使用 Microsoft.Extensions.AI:上下文块(系统提示的前端摘要)和a load_skill 模型可以调用工具按需加载技能的全部内容。
// 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
var messages = new List
{
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"),
};
// Add catalog.Tools to ChatOptions.Tools — this is load_skill plus, once any skill
// has been loaded, unload_skill (so the model can free context when finished).
var options = new ChatOptions
{
Tools = [.. catalog.Tools],
};
var response = await chatClient.GetResponseAsync(messages, options);如果服务器断开连接,请从目录中删除其技能:
catalog.RemoveClient(mcpClient1);处理技能依赖性
技能可以在其frontmatter中声明MCP服务器依赖关系:
---
name: explore-everything
description: Explores an MCP server
dependencies: [everything-server]
---当通过加载具有依赖关系的技能时 load_skill 工具 OnDependenciesRequired 回调触发,以便客户端主机可以按需连接到所需的服务器:
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
};回调收到 SkillDependencyRequest 带有技能名称和所需服务器名称列表。返回 true 当所有服务器都连接时,或 false 中止(这会导致 LoadSkillAsync 扔 InvalidOperationException).如果未设置回调,则具有依赖关系的技能将在没有通知的情况下静默加载。
看 DynamicMcpServers示例 举一个完整的例子。
卸货技能
渐进式披露不应该变成渐进式积累。一旦加载了至少一项技能, SkillCatalog.UnloadSkillTool 同时可用 load_skill --通过附加在每个模型后面的简短附言来告知模型 load_skill 响应,完成后可以调用它来释放技能的上下文。这 unload_skill AIFunction及其附带指南仅在当前加载至少一项技能时显示。
这 OnSkillUnloaded 每次卸载技能时,回调都会触发。主机将其连接起来以执行两件事:
- 断开所有已释放的MCP服务器。 目录只传递任何其他仍然加载的技能不再需要的服务器,因此不需要进行引用计数。
- 擦洗前面
load_skill聊天记录中的通话/结果对 --这就是SKILL.md内容实际存在的地方。图书馆不会碰你的消息列表;主人负责。
更改聊天历史记录 FunctionInvokingChatClient 迭代是不安全的,因此队列清理工作在回调期间进行,并在回调后进行处理 GetStreamingResponseAsync 返回:
var pendingScrubs = new List();
catalog.OnSkillUnloaded = async (result, ct) =>
{
foreach (var serverName in result.ReleasedServers)
await DisconnectAsync(serverName, ct);
pendingScrubs.Add(result.SkillName);
};
// ... after each streaming turn:
foreach (var skillName in pendingScrubs)
ScrubLoadCallsForSkill(messages, skillName);
pendingScrubs.Clear();scrub本身是消息列表上的一个简单谓词——match FunctionCallContent 谁的 Name == "load_skill" 和 Arguments["skillName"] 等于卸载技能,然后放弃这些呼叫和匹配 FunctionResultContent。参见 DynamicMcpServers/Program.cs 为了全面实施。
URI约定
每种技能都会暴露出以下三种资源 FastMCP 惯例:
| URI | 类型 | 内容 |
|---|---|---|
skill://{name}/SKILL.md | 资源(列出) | 完整SKILL.md内容 |
skill://{name}/_manifest | 资源(已列出) | 带文件列表的JSON清单 |
skill://{name}/{+path} | 资源模板 | 按需支持文件 |
清单格式
{
"skill": "code-review",
"files": [
{ "path": "SKILL.md", "size": 512, "hash": "sha256:abc123..." },
{ "path": "references/checklist.md", "size": 256, "hash": "sha256:def456..." }
]
}写作技巧
技能是一个目录,其中包含 SKILL.md 带有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.前线阵地
| 字段 | 必填 | 描述 |
|---|---|---|
name | 是 | 1-64个字符,小写字母数字+连字符,必须与目录名匹配 |
description | 是 | 1-1024个字符 |
license | 否 | 许可证标识符 |
compatibility | 否 | 逗号分隔的兼容代理列表(最多500个字符) |
dependencies | 否 | 所需MCP服务器名称列表(通过按需连接 OnDependenciesRequired) |
allowed-tools | 否 | 实验工具限制 |
metadata | 否 | 客户端特定数据的任意键值对 |
名称规则
根据 agentskills.io规范:
- 仅限小写字母、数字和连字符
- 无前导、尾随或连续连字符
- NFKC标准化,最多64个字符
- 必须与目录名匹配
包裹
| 包装 | 描述 |
|---|---|
SkillsDotNet | 核心库: FrontmatterParser, SkillValidator, SkillDirectoryScanner, SkillInfo, SkillFileInfo, SkillContextExtensions取决于 Microsoft.Extensions.AI.Abstractions. |
SkillsDotNet.Mcp | MCP传输层: SkillResourceFactory, SkillCatalog,构建器扩展,客户端扩展。取决于 SkillsDotNet 和 ModelContextProtocol. |
目标框架
- .NET 10
- .NET 9
- .NET 8
致谢
许多约定,特别是该库中的服务器端资源实现,都受到了以下方面的启发 FastMCP 3.0。我们尽可能地与FastMCP保持一致。
许可证
麻省理工学院
