A C# source generator that automatically transforms your ASP.NET Core API endpoints into Model Context Protocol (MCP) tools.
Api.ToMcp analyzes your existing ASP.NET Core controllers at compile time and generates MCP-compatible tool classes. This allows AI assistants (like Claude) to interact with your REST API through the MCP protocol without writing any integration code manually.
- Automatic Tool Generation - Scans controllers and generates MCP tools at compile time
- Attribute Control - Use
[McpExpose]and[McpIgnore]to fine-tune which endpoints are exposed - Flexible Selection - Choose between allowlist (
SelectedOnly) or blocklist (AllExceptExcluded) modes - Customizable Naming - Configure tool naming format via
generator.json - Loop Prevention - Built-in middleware prevents infinite recursion when MCP tools call back to the API
- Auth Forwarding - Authentication headers from MCP requests are forwarded to API calls
dotnet add package Kebechet.Api.ToMcpCreate Mcp/generator.json in your project:
{
"schemaVersion": 1,
"mode": "SelectedOnly",
"include": [
"ProductsController.GetAll",
"ProductsController.GetById"
],
"exclude": [],
"naming": {
"toolNameFormat": "{Controller}_{Action}",
"removeControllerSuffix": true
}
}Add it to your .csproj:
<ItemGroup>
<AdditionalFiles Include="Mcp\generator.json" />
</ItemGroup>using System.Reflection;
using Api.ToMcp.Runtime;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddMcpTools(Assembly.GetExecutingAssembly());
var app = builder.Build();
app.UseMcpLoopPrevention();
app.MapControllers();
app.MapMcpEndpoint("mcp");
app.Run();[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public Task<IEnumerable<Product>> GetAll([FromQuery] string? category = null)
{
// ...
}
[HttpGet("{id:guid}")]
public Task<ActionResult<Product>> GetById(Guid id)
{
// ...
}
[HttpDelete("{id:guid}")]
[McpIgnore] // Exclude dangerous operations
public Task<ActionResult> Delete(Guid id)
{
// ...
}
}| Mode | Description |
|---|---|
SelectedOnly |
Only endpoints in the include list are exposed (allowlist) |
AllExceptExcluded |
All endpoints except those in exclude are exposed (blocklist) |
| Option | Description |
|---|---|
toolNameFormat |
Format string for tool names. Supports {Controller} and {Action} placeholders |
removeControllerSuffix |
When true, strips "Controller" from the controller name |
"ProductsController"- Include/exclude entire controller"ProductsController.GetById"- Include/exclude specific action
Forces an endpoint to be exposed as an MCP tool, regardless of configuration mode.
[McpExpose(Name = "GetProduct", Description = "Retrieves a product by ID")]
public Task<Product> GetById(Guid id) { ... }Forces an endpoint to be excluded from MCP exposure.
[McpIgnore]
public Task<ActionResult> Delete(Guid id) { ... }Api.ToMcp supports optional scope-based access control for MCP tools. Scopes are mapped from HTTP methods:
| Scope | HTTP Methods |
|---|---|
| Read | GET, HEAD, OPTIONS |
| Write | POST, PUT, PATCH |
| Delete | DELETE |
By default, no scope checking is performed - all generated tools are accessible.
To enable scope validation, configure a claim-to-scope mapper:
using Api.ToMcp.Abstractions.Scopes;
builder.Services.AddMcpTools(Assembly.GetExecutingAssembly(), options =>
{
options.ClaimName = "permissions"; // JWT claim name
options.ClaimToScopeMapper = claimValue =>
{
var scope = McpScope.None;
if (claimValue.Contains("read")) scope |= McpScope.Read;
if (claimValue.Contains("write")) scope |= McpScope.Write;
if (claimValue.Contains("delete")) scope |= McpScope.Delete;
return scope;
};
});- MCP request arrives with JWT containing claims
- The configured
ClaimNameis read from the user's claims ClaimToScopeMapperconverts the claim value toMcpScope- If the tool's required scope (based on HTTP method) isn't granted, an error is returned
{ "permissions": "mcp:read mcp:write" }This grants Read and Write scopes but not Delete.
- Compile Time: The source generator scans your controllers for HTTP actions
- Code Generation: For each selected endpoint, a tool class is generated with
[McpServerToolType]attribute - Runtime: When an MCP client calls a tool, it invokes your API via HTTP internally
- Loop Prevention: The
X-MCP-Internal-Callheader prevents MCP endpoints from being called recursively
For ProductsController.GetById(Guid id), the generator creates:
[McpServerToolType]
public static class ProductsController_GetByIdTool
{
[McpServerTool(Name = "Products_GetById")]
[Description("Invokes ProductsController.GetById")]
public static async Task<string> InvokeAsync(
IMcpHttpInvoker invoker,
[Description("Parameter: id")] Guid id)
{
var route = $"/api/products/{Uri.EscapeDataString(id.ToString())}";
return await invoker.GetAsync(route);
}
}- .NET 8.0 or later
- ASP.NET Core
This project is licensed under the MIT License - see the LICENSE file for details.
