Sample Operations Reference - Garume/Manifold GitHub Wiki
The Manifold.Samples.Operations project and the Manifold.Generators.Tests.Samples namespace contain shared operation definitions that demonstrate the full range of Manifold's authoring patterns. These samples serve as a practical pattern catalog for both the static-method and class-based operation styles, illustrating parameter binding (positional arguments, named options, service injection, cancellation tokens), surface visibility control ([CliOnly], [McpOnly]), surface-specific naming, aliases, and hidden operations.
This page covers all sample operation files across the repository and cross-references the attribute definitions documented in Attributes and Operation Definition, the binding pipeline described in Parameter Binding and Type Conversion, and the result handling covered in Result Types and Formatting. The sample operations are consumed by the host applications documented in Sample — CLI Host and Samples — MCP Hosts (Stdio and HTTP).
Manifold supports two distinct operation authoring styles. Both styles produce identical OperationDescriptor records via the source generator and are dispatched through the same CLI and MCP pipelines.
flowchart TD
A[Operation Definition] --> B{Authoring Style}
B -->|Static Method| C[Static class with<br/>attributed method]
B -->|Class-Based| D[Class implementing<br/>IOperation<TRequest, TResult>]
C --> E[Parameters on<br/>method signature]
D --> F[Parameters on<br/>Request class properties]
E --> G[Source Generator]
F --> G
G --> H[OperationDescriptor]
H --> I[CLI Surface]
H --> J[MCP Surface]
In the static-method style, an operation is a static method decorated with [Operation], [CliCommand], and/or [McpTool] attributes. Parameters are declared directly on the method signature and annotated with [Argument], [Option], [FromServices], or left as CancellationToken.
[Operation("math.add", Description = "Add two integers.", Summary = "Returns the sum of x and y.")]
[CliCommand("math", "add")]
[McpTool("math_add")]
public static int Add(
[Argument(0, Name = "x", Description = "Left operand")] int x,
[Argument(1, Name = "y", Description = "Right operand")] int y)
{
return x + y;
}Sources: samples/Manifold.Samples.Operations/SampleOperations.cs:5–13
Key characteristics of the static-method style:
- Method return type can be
T,Task<T>, orValueTask<T> - Parameters are bound directly from method parameters
- The containing class must be
staticandpartial(for source generation) - Supports
[FromServices]for dependency injection andCancellationTokenfor cancellation
In the class-based style, an operation is a class that implements IOperation<TRequest, TResult>. The [Operation], [CliCommand], and [McpTool] attributes are placed on the class itself. Parameters are defined as properties on a nested Request class.
[Operation("weather.preview", Description = "Return a pretend weather summary.")]
[CliCommand("weather", "preview")]
[McpTool("weather_preview")]
public sealed class WeatherPreviewOperation : IOperation<WeatherPreviewOperation.Request, string>
{
public ValueTask<string> ExecuteAsync(Request request, OperationContext context)
{
int days = request.Days <= 0 ? 1 : request.Days;
string city = string.IsNullOrWhiteSpace(request.City) ? "unknown" : request.City.Trim();
string summary = $"Forecast for {city}: mild for the next {days} day(s). Surface={context.Surface}.";
return ValueTask.FromResult(summary);
}
public sealed class Request
{
[Option("city", Description = "Target city")]
public string City { get; init; } = string.Empty;
[Option("days", Description = "Number of forecast days")]
public int Days { get; init; } = 3;
}
}Sources: samples/Manifold.Samples.Operations/SampleOperations.cs:16–40
Key characteristics of the class-based style:
- Always returns
ValueTask<TResult>via theExecuteAsyncmethod - Receives
OperationContextdirectly, providing access toSurface,Services, andCancellationToken - Parameters are defined as
{ get; init; }properties on the nestedRequestclass - The
Requestproperties use the same[Option],[Argument],[Alias],[CliName], and[McpName]attributes
The following table summarizes every sample operation defined across the repository.
| Operation ID | Style | Declaring Type | Return Type | Visibility | CLI Command | MCP Tool Name | Hidden |
|---|---|---|---|---|---|---|---|
math.add (samples) |
Static method | SampleOperations |
int |
Both | math add |
math_add |
No |
weather.preview |
Class-based | WeatherPreviewOperation |
string |
Both | weather preview |
weather_preview |
No |
sample.hello |
Static method |
SampleOperations (tests) |
string |
Both | sample hello |
sample_hello |
Yes |
math.add (tests) |
Static method |
SampleOperations (tests) |
int |
CliOnly | math add |
— | No |
weather.get |
Static method |
SampleOperations (tests) |
string |
McpOnly | — | weather_fetch |
No |
sample.class-hello |
Class-based | SampleClassHelloOperation |
string |
Both | sample class-hello |
sample_class_hello |
No |
Sources: samples/Manifold.Samples.Operations/SampleOperations.cs:1–41, tests/Manifold.Generators.Tests/Samples/SampleOperations.cs:1–40, tests/Manifold.Generators.Tests/Samples/SampleClassOperations.cs:1–24
The sample operations collectively demonstrate all four ParameterSource types defined in the ParameterSource enum: Option, Argument, Service, and CancellationToken.
flowchart TD
A[Parameter Sources] --> B[Argument]
A --> C[Option]
A --> D[Service]
A --> E[CancellationToken]
B --> B1["[Argument(position)]<br/>Positional, CLI only"]
C --> C1["[Option(name)]<br/>Named, both surfaces"]
D --> D1["[FromServices]<br/>DI-injected"]
E --> E1["CancellationToken<br/>Auto-detected by type"]
Sources: src/Manifold/DescriptorModels.cs:18–24
Positional arguments are bound using [Argument(position)] and are primarily used on the CLI surface.
[Argument(0, Name = "x", Description = "Left operand")] int x,
[Argument(1, Name = "y", Description = "Right operand")] int yThe generated ParameterDescriptor captures the position, name, description, and required status:
| Property | Value (for x) |
Value (for y) |
|---|---|---|
Name |
"x" |
"y" |
ParameterType |
typeof(int) |
typeof(int) |
Source |
ParameterSource.Argument |
ParameterSource.Argument |
Required |
true |
true |
Position |
0 |
1 |
Description |
"Left operand" |
"Right operand" |
Sources: src/Manifold/ParameterAttributes.cs:15–27, tests/Manifold.Generators.Tests/GeneratedOperationRegistryTests.cs:53–70
Named options use [Option(name)] and are supported on both CLI and MCP surfaces.
[Option("city", Description = "Target city")]
public string City { get; init; } = string.Empty;
[Option("days", Description = "Number of forecast days")]
public int Days { get; init; } = 3;Options can be marked as optional with Required = false:
[Option("city", Description = "Target city", Required = false)] string? city = nullSources: src/Manifold/ParameterAttributes.cs:3–13, tests/Manifold.Generators.Tests/Samples/SampleOperations.cs:36
The [FromServices] attribute marks a parameter for dependency injection. The parameter is resolved from the IServiceProvider at invocation time and is never exposed to end users.
[FromServices] IServiceProvider servicesThe resulting ParameterDescriptor has Source = ParameterSource.Service and Required = false.
Sources: src/Manifold/ParameterAttributes.cs:91–92, tests/Manifold.Generators.Tests/GeneratedOperationRegistryTests.cs:72–78
Parameters of type CancellationToken are automatically detected by the source generator without any attribute. They are populated from the OperationContext.CancellationToken at runtime.
CancellationToken cancellationToken = defaultThe resulting ParameterDescriptor has Source = ParameterSource.CancellationToken and Required = false.
Sources: tests/Manifold.Generators.Tests/GeneratedOperationRegistryTests.cs:79–86
Operations can be restricted to a single surface using [CliOnly] or [McpOnly], or exposed on both surfaces (the default).
flowchart TD
A[Operation Visibility] --> B{Attribute Present?}
B -->|"[CliOnly]"| C["OperationVisibility.CliOnly<br/>CLI surface only"]
B -->|"[McpOnly]"| D["OperationVisibility.McpOnly<br/>MCP surface only"]
B -->|Neither| E["OperationVisibility.Both<br/>Both surfaces"]
C --> F["CliCommandPath set<br/>McpToolName = null"]
D --> G["CliCommandPath = null<br/>McpToolName set"]
E --> H["Both paths set"]
The test math.add operation is annotated with [CliOnly], restricting it to the CLI surface:
[Operation("math.add", Description = "Add two integers.")]
[CliOnly]
[CliCommand("math", "add")]
[Alias("sum", "calc plus")]
public static Task<int> AddAsync(...)The generated descriptor has Visibility = OperationVisibility.CliOnly and no McpToolName. The [Alias] attribute on this operation generates two alternative CLI command paths: ["math", "sum"] and ["calc", "plus"].
Sources: tests/Manifold.Generators.Tests/Samples/SampleOperations.cs:19–29, tests/Manifold.Generators.Tests/GeneratedOperationRegistryTests.cs:44–50
The weather.get operation is annotated with [McpOnly] and uses [McpName] to override the tool name:
[Operation("weather.get")]
[McpOnly]
[McpName("weather_fetch")]
public static ValueTask<string> FetchAsync(
[Option("city", Description = "Target city", Required = false)] string? city = null)The generated descriptor has Visibility = OperationVisibility.McpOnly, McpToolName = "weather_fetch", and CliCommandPath = null.
Sources: tests/Manifold.Generators.Tests/Samples/SampleOperations.cs:32–39, tests/Manifold.Generators.Tests/GeneratedOperationRegistryTests.cs:125–128
Parameters can have different names on the CLI and MCP surfaces, and can define multiple aliases for CLI discovery. This pattern is demonstrated in both the static-method and class-based styles.
flowchart TD
A["Parameter 'name'"] --> B["[Option('name')]<br/>Canonical name"]
A --> C["[CliName('person')]<br/>CLI display name"]
A --> D["[McpName('targetName')]<br/>MCP JSON key"]
A --> E["[Alias('n', 'username')]<br/>CLI aliases"]
[Operation("sample.hello", Description = "Say hello.", Hidden = true)]
[CliCommand("sample", "hello")]
[McpTool("sample_hello")]
public static string Hello(
[Option("name", Description = "User name")]
[CliName("person")]
[McpName("targetName")]
[Alias("n", "username")]
string name,
CancellationToken cancellationToken = default)Sources: tests/Manifold.Generators.Tests/Samples/SampleOperations.cs:5–17
internal sealed class Request
{
[Option("name", Description = "User name")]
[CliName("person")]
[McpName("targetName")]
[Alias("n", "username")]
public string Name { get; init; } = string.Empty;
}Sources: tests/Manifold.Generators.Tests/Samples/SampleClassOperations.cs:16–23
Both styles produce identical ParameterDescriptor values, as verified by the registry tests:
| Descriptor Field | Value |
|---|---|
Name |
"name" |
CliName |
"person" |
McpName |
"targetName" |
Aliases |
["n", "username"] |
ParameterType |
typeof(string) |
Source |
ParameterSource.Option |
Sources: tests/Manifold.Generators.Tests/GeneratedOperationRegistryTests.cs:109–123
Hidden Operations
The Hidden property on [Operation] controls whether the operation appears in help text and tool listings while remaining fully invocable.
[Operation("sample.hello", Description = "Say hello.", Summary = "Returns a greeting.", Hidden = true)]The generated OperationDescriptor has Hidden = true, which the CLI help generator and MCP tool catalog can use to suppress the operation from discovery listings.
Sources: src/Manifold/OperationAttribute.cs:14, tests/Manifold.Generators.Tests/GeneratedOperationRegistryTests.cs:32
Class-based operations receive an OperationContext instance directly in the ExecuteAsync method. This provides access to the current invocation surface, service provider, and cancellation token.
public ValueTask<string> ExecuteAsync(Request request, OperationContext context)
{
string summary = $"Forecast for {city}: mild for the next {days} day(s). Surface={context.Surface}.";
return ValueTask.FromResult(summary);
}The OperationContext class provides:
| Member | Type | Description |
|---|---|---|
OperationId |
string? |
The operation identifier |
Surface |
InvocationSurface |
Current surface (Cli, Mcp, Protocol, Unknown) |
Services |
IServiceProvider? |
Dependency injection container |
CancellationToken |
CancellationToken |
Cancellation signal |
GetService<T>() |
T? |
Typed service resolution |
GetRequiredService<T>() |
T |
Required typed service resolution (throws on missing) |
Sources: src/Manifold/OperationContext.cs:3–84, samples/Manifold.Samples.Operations/SampleOperations.cs:21–29
The Manifold.Samples.Operations project is a shared library referenced by all three host samples. It depends on Manifold (core contracts), Manifold.Cli, Manifold.Mcp, and Manifold.Generators (as a source generator).
flowchart TD
A[Manifold.Samples.Operations] -->|ProjectReference| B[Manifold]
A -->|ProjectReference| C[Manifold.Cli]
A -->|ProjectReference| D[Manifold.Mcp]
A -->|Analyzer| E[Manifold.Generators]
F[Manifold.Samples.CliHost] -->|References| A
G[Manifold.Samples.McpStdioHost] -->|References| A
H[Manifold.Samples.McpHttpHost] -->|References| A
E -->|Generates at compile time| I[GeneratedOperationRegistry<br/>GeneratedCliInvoker<br/>GeneratedMcpCatalog<br/>GeneratedMcpInvoker]
The generator reference uses OutputItemType="Analyzer" and ReferenceOutputAssembly="false", meaning it runs at compile time without becoming a runtime dependency.
Sources: samples/Manifold.Samples.Operations/Manifold.Samples.Operations.csproj:1–14
The following diagram shows the complete decision tree for defining an operation using the patterns demonstrated in the samples.
flowchart TD
Start[Define Operation] --> Style{Choose style}
Style -->|Simple, stateless| SM[Static Method]
Style -->|Stateful, needs context| CB["Class : IOperation"]
SM --> SMAttr["Add [Operation],<br/>[CliCommand], [McpTool]"]
CB --> CBAttr["Add attributes to class"]
SMAttr --> Params{Define parameters}
CBAttr --> ReqClass[Define Request class<br/>with properties]
Params --> Arg["[Argument(n)]<br/>positional"]
Params --> Opt["[Option(name)]<br/>named"]
Params --> Svc["[FromServices]<br/>injected"]
Params --> CT["CancellationToken<br/>auto-detected"]
ReqClass --> PropAttr["Annotate properties<br/>with [Option]/[Argument]"]
Arg --> Naming
Opt --> Naming
PropAttr --> Naming
Naming{Surface-specific naming?}
Naming -->|Yes| Names["[CliName], [McpName],<br/>[Alias]"]
Naming -->|No| Vis
Names --> Vis{Restrict visibility?}
Vis -->|CLI only| CliO["[CliOnly]"]
Vis -->|MCP only| McpO["[McpOnly]"]
Vis -->|Both| Done[Done]
CliO --> Done
McpO --> Done
- Attributes and Operation Definition — Comprehensive reference for all operation attributes
- Parameter Binding and Type Conversion — Detailed binding pipeline for both surfaces
-
Core Contracts — Manifold Package —
IOperation,OperationContext,OperationDescriptor, and enums - Source Generator — Manifold.Generators — How operations are analyzed and code-generated
- Sample — CLI Host — CLI host consuming these sample operations
- Samples — MCP Hosts (Stdio and HTTP) — MCP hosts consuming these sample operations
-
Result Types and Formatting — Result handling and the
IResultFormatterinterface -
Dependency Injection and Service Resolution —
[FromServices]and service resolution patterns - Diagnostics and Compile-Time Validation — Compile-time validation rules for operation definitions