流形
Manifold 是a。NET基础,用于定义一次操作并通过CLI和MCP表面公开它。
模型很简单:
- 手写一个操作
- 让源代码生成器发出描述符和调用者
- 将这些生成的工件连接到CLI和/或MCP主机中
Manifold 不拥有您的传输、托管模式或特定于产品的运行时。它侧重于操作定义、绑定、元数据和快速调度。
如果你想要一个可运行的起点,存储库包括以下示例主机 samples/.
包含内容
| 包装 | 用途 |
|---|---|
Manifold | 核心契约、描述符、属性和绑定原语 |
Manifold.Cli | CLI运行时帮助程序和生成的调用 |
Manifold.Generators | 发出描述符和调用者的源代码生成器 |
Manifold.Mcp | MCP元数据和调用帮助程序 |
核心概念
手术是唯一的真理来源。
根据该定义, Manifold.Generators 发射:
GeneratedOperationRegistryGeneratedCliInvokerGeneratedMcpCatalogGeneratedMcpInvoker
您可以将这些生成的类型组合到自己的应用程序中。
Manifold 支持两种创作风格:
- 静态方法操作
- 基于类的操作实现
IOperation
安装
大多数消费者不应该安装所有四个软件包。
从核心包和生成器开始,然后只添加实际使用的曲面。
典型组合:
| 场景 | 包 |
|---|---|
| 仅定义操作 | Manifold, Manifold.Generators |
| CLI应用程序 | Manifold, Manifold.Generators, Manifold.Cli |
| MCP主机 | Manifold, Manifold.Generators, Manifold.Mcp |
| CLI和MCP | Manifold, Manifold.Generators, Manifold.Cli, Manifold.Mcp |
CLI主机:
MCP主机:
如果需要两个曲面,请将这两个示例结合起来。
创作操作
静态方法示例
当你想要尽可能简单的定义时,静态方法操作效果很好。
using Manifold;
public static class MathOperations
{
[Operation("math.add", Summary = "Adds two integers.")]
[CliCommand("math", "add")]
[McpTool("math_add")]
public static int Add(
[Argument(0, Name = "x")] int x,
[Argument(1, Name = "y")] int y)
{
return x + y;
}
}基于类的示例
当您需要专用的请求类型、更丰富的建模或DI管理的构造时,基于类的操作非常有用。
using Manifold;
[Operation("math.add", Summary = "Adds two integers.")]
[CliCommand("math", "add")]
[McpTool("math_add")]
public sealed class AddOperation : IOperation
{
public ValueTask ExecuteAsync(Request request, OperationContext context)
=> ValueTask.FromResult(request.X + request.Y);
public sealed class Request
{
[Argument(0, Name = "x")]
[McpName("x")]
public int X { get; init; }
[Argument(1, Name = "y")]
[McpName("y")]
public int Y { get; init; }
}
}对于基于类的操作,在使用生成的调用者之前,在DI中注册操作类型。
using Microsoft.Extensions.DependencyInjection;
ServiceCollection services = new();
services.AddTransient();
ServiceProvider serviceProvider = services.BuildServiceProvider();静态方法操作不需要DI注册,除非它们显式请求服务。
属性模型
主要属性包括:
| 属性 | 适用于 | 目的 |
|---|---|---|
[Operation("operation.id")] | 方法、类 | 声明规范操作id。支持 Summary, Description,以及 Hidden. |
[CliCommand("group", "verb")] | 方法,类 | 声明CLI命令路径,例如 math add. |
[McpTool("tool_name")] | 方法,类 | 声明MCP工具名称,例如 math_add. |
[CliOnly] | 方法,类 | 仅在CLI界面上显示操作。 |
[McpOnly] | 方法,类 | 仅在MCP表面上显示操作。 |
[ResultFormatter(typeof(...))] | 方法,类 | 使用自定义格式化程序覆盖默认CLI文本呈现。 |
[Argument(position)] | 参数,请求属性 | 绑定位置CLI参数。支持 Name, Description,以及 Required. |
[Option("name")] | 参数,请求属性 | 绑定一个命名的CLI选项。支持 Description 和 Required. |
[Alias(...)] | 方法、类、参数、请求属性 | 为命令、选项、参数或名称添加别名。 |
[CliName("...")] | 方法、类、参数、请求属性 | 仅覆盖面向CLI的名称。 |
[McpName("...")] | 方法、类、参数、请求属性 | 仅覆盖面向MCP的名称。 |
[FromServices] | 参数 | 从DI而不是用户输入中解析值。 |
常见模式:
- 使用
[Operation]以及至少一个表面属性,例如[CliCommand]或[McpTool] - 使用
[Argument]用于有序的CLI输入和[Option]用于命名CLI输入 - 使用
[CliName]和[McpName]当同一概念字段应在每个曲面上以不同名称出现时 - 使用
[CliOnly]或[McpOnly]当一个操作不应该在两个表面上共享时 - 使用
[FromServices]用于运行时服务,如时钟、存储库或应用程序状态
示例:
- 仅使用重命名CLI选项
[CliName("person")] - 将MCP参数重命名为
[McpName("targetName")] - 在生成的曲面中隐藏内部操作
[Operation("internal.sync", Hidden = true)] - 仅暴露于一个表面
[CliOnly]或[McpOnly]
命令行用法
在运行时,将生成的注册表和调用者组合成 CliApplication.
using Manifold.Cli;
using Manifold.Generated;
using Microsoft.Extensions.DependencyInjection;
ServiceCollection services = new();
services.AddTransient();
ServiceProvider serviceProvider = services.BuildServiceProvider();
CliApplication cli = new(
GeneratedOperationRegistry.Operations,
new GeneratedCliInvoker(),
serviceProvider);
StringWriter output = new();
StringWriter error = new();
int exitCode = await cli.ExecuteAsync(
["math", "add", "2", "3"],
output,
error,
CancellationToken.None);笔记:
CliApplication处理使用文本和命令调度GeneratedCliInvoker是生成的绑定层- 快速同步和异步路径在可用时会自动选择
MCP使用
Manifold 不运送MCP传输主机。相反,它提供:
- 通过以下方式生成工具元数据
GeneratedMcpCatalog - 通过以下方式生成执行
GeneratedMcpInvoker - 中的MCP参数解析和辅助API
Manifold.Mcp
最小本地调用如下:
using System.Text.Json;
using Manifold.Generated;
using Manifold.Mcp;
using Microsoft.Extensions.DependencyInjection;
ServiceCollection services = new();
services.AddTransient();
ServiceProvider serviceProvider = services.BuildServiceProvider();
JsonElement args = JsonSerializer.Deserialize(
"{\"x\":2,\"y\":3}");
GeneratedMcpInvoker invoker = new();
if (invoker.TryInvokeFast(
"math_add",
args,
serviceProvider,
CancellationToken.None,
out ValueTask invocation))
{
FastMcpInvocationResult result = await invocation;
Console.WriteLine(result.Number);
}元数据发现:
using Manifold.Generated;
foreach (var tool in GeneratedMcpCatalog.Tools)
{
Console.WriteLine($"{tool.Name}: {tool.Description}");
}MCP运输和样品
主要的MCP传输方式包括:
stdioStreamable HTTP
Manifold 故意与传输无关,因此存储库包含示例主机,而不是将传输主机烘焙到核心包中。
这样运行它们:
dotnet run --project .\samples\Manifold.Samples.McpStdioHost\Manifold.Samples.McpStdioHost.csproj
dotnet run --project .\samples\Manifold.Samples.McpHttpHost\Manifold.Samples.McpHttpHost.csprojHTTP示例侦听 http://127.0.0.1:38474/mcp.
注意:HTTP示例使用 ModelContextProtocol.AspNetCore,目前是一个预览包。稳定的核心MCP包是 ModelContextProtocol.
CLI示例主机
还有一个最小的可运行CLI主机:
dotnet run --project .\samples\Manifold.Samples.CliHost\Manifold.Samples.CliHost.csproj -- math add 2 3
dotnet run --project .\samples\Manifold.Samples.CliHost\Manifold.Samples.CliHost.csproj -- weather preview --city Tokyo --days 3依赖注入和服务
有两种服务访问模式。
基于方法的操作
使用 [FromServices] 在一个参数上。
[Operation("clock.now")]
[CliCommand("clock", "now")]
public static DateTimeOffset Now(
[FromServices] IClock clock)
{
return clock.UtcNow;
}基于类的操作
使用构造函数注入,或通过以下方式请求服务 OperationContext.
public sealed class GreetingOperation(IGreetingService greetings)
: IOperation
{
public ValueTask ExecuteAsync(Request request, OperationContext context)
=> ValueTask.FromResult(greetings.Format(request.Name));
public sealed class Request
{
[Option("name")]
public string Name { get; init; } = string.Empty;
}
}结果格式
要提供自定义CLI文本输出,同时保持JSON或MCP的结构化结果,请实现 IResultFormatter.
using Manifold;
public sealed class WeatherFormatter : IResultFormatter
{
public string? FormatText(WeatherResult result, OperationContext context)
=> $"{result.City}:{result.TemperatureC}";
}然后附上:
[ResultFormatter(typeof(WeatherFormatter))]生成的类型
发电机在以下情况下发出这些公共入口点 Manifold.Generated:
GeneratedOperationRegistryGeneratedCliInvokerGeneratedMcpCatalogGeneratedMcpInvoker
这些是消费者的标准集成界面。
演出
Manifold 包括专用的BenchmarkDotNet套件 benchmarks/.
基准说明和比较表见 benchmarks/README.md.
比较集:
- 命令行界面
- Manifold.Cli - ConsoleAppFramework - System.CommandLine
- 主控程序
- Manifold.Mcp - 官方的 ModelContextProtocol - McpToolkit - mcpdotnet
当前快照:
CLI:
| 场景 | 歧管 | 控制台AppFramework | 系统。命令行 |
|---|---|---|---|
| 阵地指挥 | 22.61 ns / 0 B | 26.57 ns / 0 B | 1730.82 ns / 4688 B |
| 选项繁重的命令 | 28.89 ns / 0 B | 24.76 ns / 0 B | 2110.84 ns / 5632 B |
MCP(往返形状):
| 场景 | 流形 | 模型上下文协议 | McpToolkit | McpDotNet |
|---|---|---|---|---|
tools/list 回应 | 756.3 ns / 0 B | 754.6 ns / 0 B | 635.4 ns / 0 B | 816.2 ns / 0 B |
tools/call 回应 | 47.16 ns / 0 B | 68.56 ns / 0 B | 146.34 ns / 96 B | 93.20 ns / 256 B |
笔记:
- CLI编号测量解析器+分派热路径
- 上面的MCP数字反映了内存响应结构,而不是传输基准
- 生的
ModelContextProtocol调用微基准测试即将到来ZeroMeasurement往返形状的桌子是更有意义的比较
有关方法和完整报告,请参阅 benchmarks/README.md.
构建
从存储库根目录:
./build/restore.ps1
./build/build.ps1 -NoRestore
./build/test.ps1 -NoBuild
./build/quality.ps1
./build/pack.ps1./build/pack.ps1 写 .nupkg 和 .snupkg 文件到 .artifacts/packages/.
存储库状态
- Windows第一脚本和CI
- 麻省理工学院许可
- CI验证构建、测试、格式化、架构检查和包创建
OSS客房服务
- 许可证:
LICENSE - 贡献说明:
CONTRIBUTING.md - 第三方通知:
THIRD_PARTY_NOTICES.md
仓库布局
src/
Manifold
Manifold.Cli
Manifold.Generators
Manifold.Mcp
tests/
Manifold.Tests
Manifold.Cli.Tests
Manifold.Generators.Tests
Manifold.Mcp.Tests
benchmarks/
Manifold.Benchmarks
Manifold.Mcp.Benchmarks
samples/
Manifold.Samples.Operations
Manifold.Samples.CliHost
Manifold.Samples.McpStdioHost
Manifold.Samples.McpHttpHost