.NET SDK for developing mcpd middleware plugins.
This SDK provides .NET types and gRPC interfaces for building middleware plugins that integrate with mcpd.
Plugins can process HTTP requests and responses, implementing capabilities like authentication, rate limiting,
content transformation, and observability.
Add the package reference to your project:
dotnet add package MozillaAI.Mcpd.Plugins.SdkOr add it directly to your .csproj file:
<ItemGroup>
<PackageReference Include="MozillaAI.Mcpd.Plugins.Sdk" Version="0.0.3" />
</ItemGroup>The SDK provides the PluginServer helper and BasePlugin class to minimize boilerplate.
using Google.Protobuf.WellKnownTypes;
using MozillaAI.Mcpd.Plugins.V1;
public class MyPlugin : BasePlugin
{
public override Task<Metadata> GetMetadata(Empty request, Grpc.Core.ServerCallContext context)
{
return Task.FromResult(new Metadata
{
Name = "my-plugin",
Version = "1.0.0",
Description = "Example plugin that does something useful"
});
}
public override Task<Capabilities> GetCapabilities(Empty request, Grpc.Core.ServerCallContext context)
{
return Task.FromResult(new Capabilities
{
Flows = { FlowConstants.FlowRequest }
});
}
public override Task<HTTPResponse> HandleRequest(HTTPRequest request, Grpc.Core.ServerCallContext context)
{
var response = new HTTPResponse
{
Continue = true,
StatusCode = 0,
Body = request.Body
};
foreach (var header in request.Headers)
{
response.Headers.Add(header.Key, header.Value);
}
return Task.FromResult(response);
}
}
public class Program
{
public static async Task<int> Main(string[] args)
{
return await PluginServer.Serve<MyPlugin>(args);
}
}The BasePlugin class provides default implementations for all plugin methods. Override only the methods you need:
| Method/Property | Default Behavior |
|---|---|
CheckHealth() |
Returns OK |
CheckReady() |
Returns OK |
Configure() |
No-op |
Stop() |
No-op |
HandleRequest() |
Pass through unchanged |
HandleResponse() |
Pass through unchanged |
GetMetadata() |
Returns empty (should be overridden) |
GetCapabilities() |
Returns empty (should be overridden) |
Logger |
Automatically provided ILogger instance for structured logging |
Plugins can modify incoming HTTP requests by setting the ModifiedRequest field in the returned HTTPResponse. This allows plugins to transform requests before they reach downstream handlers:
public override Task<HTTPResponse> HandleRequest(HTTPRequest request, Grpc.Core.ServerCallContext context)
{
// Create a modified version of the request.
var modifiedRequest = new HTTPRequest
{
Method = request.Method,
Url = request.Url,
Path = request.Path,
Body = request.Body,
RemoteAddr = request.RemoteAddr,
RequestUri = request.RequestUri
};
// Copy and modify headers.
foreach (var header in request.Headers)
{
modifiedRequest.Headers.Add(header.Key, header.Value);
}
modifiedRequest.Headers["X-Custom-Header"] = "added-by-plugin";
// Return response with modified request.
return Task.FromResult(new HTTPResponse
{
Continue = true,
StatusCode = 0,
ModifiedRequest = modifiedRequest
});
}Plugins that extend BasePlugin have access to an ILogger instance via the Logger property. This allows plugins to emit structured logs that appear in the host application's output.
using Microsoft.Extensions.Logging;
using MozillaAI.Mcpd.Plugins.V1;
public class MyPlugin : BasePlugin
{
public override Task<Empty> Configure(PluginConfig request, Grpc.Core.ServerCallContext context)
{
Logger?.LogInformation("Plugin configured with {Count} settings", request.Settings.Count);
return Task.FromResult(new Empty());
}
public override Task<HTTPResponse> HandleRequest(HTTPRequest request, Grpc.Core.ServerCallContext context)
{
Logger?.LogInformation("Processing request: {Method} {Path}", request.Method, request.Path);
// Your plugin logic here.
return Task.FromResult(new HTTPResponse { Continue = true });
}
}The SDK automatically suppresses ASP.NET Core framework logs at the Info level to reduce noise. Plugin logs at Info level and above will appear normally in the host application's output.
Build and run your plugin:
dotnet build
dotnet run -- --address /tmp/my-plugin.sock --network unixOr for TCP:
dotnet run -- --address localhost:50051 --network tcpThe SDK automatically downloads proto definitions from mcpd-proto at build time.
Current proto version: v0.0.3
| Version Type | Description |
|---|---|
| API Version | plugins/v1/ (in proto repo) maps to MozillaAI.Mcpd.Plugins.V1 namespace (in SDK) |
| Release Version | Proto repo tags like v0.0.1, v0.0.2, etc. |
| SDK Version | This repo's tags track SDK releases and may differ from proto versions |
To update the proto version, modify the <ProtoVersion> property in the SDK .csproj file.
mcpd-plugins-sdk-dotnet/
├── README.md # This file.
├── LICENSE # Apache 2.0 license.
├── mcpd-plugins-sdk-dotnet.sln # Solution file.
├── .gitignore # Ignores proto/ and bin/obj directories.
├── src/
│ └── MozillaAI.Mcpd.Plugins.Sdk/
│ ├── MozillaAI.Mcpd.Plugins.Sdk.csproj # SDK project file.
│ ├── BasePlugin.cs # BasePlugin helper class.
│ ├── PluginServer.cs # PluginServer helper class.
│ ├── FlowConstants.cs # Flow enum constants.
│ └── proto/ # Downloaded protos (auto-generated, gitignored).
└── examples/
└── MyPlugin/
├── MyPlugin.csproj # Example plugin project.
├── MyPlugin.cs # Plugin implementation.
└── Program.cs # Entry point.
- .NET 9.0 SDK or later
- Protocol Buffer Compiler (protoc) - automatically installed via
Grpc.ToolsNuGet package
dotnet buildThe proto files are automatically downloaded during the build process via the FetchProto target defined in the .csproj file.
cd examples/MyPlugin
dotnet run -- --address /tmp/my-plugin.sock --network unix- Edit the
<ProtoVersion>property insrc/MozillaAI.Mcpd.Plugins.Sdk/MozillaAI.Mcpd.Plugins.Sdk.csproj - Run
dotnet cleananddotnet build - Commit the updated project file
The SDK follows gRPC Health Checking Protocol conventions:
rpc CheckHealth(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc CheckReady(google.protobuf.Empty) returns (google.protobuf.Empty);Apache 2.0 - See LICENSE file for details.
This is an early PoC. Contribution guidelines coming soon.