Skip to content

MCP Server Setup — ASP.NET Core HTTP Transport

This guide walks through installing Granit.Mcp and Granit.Mcp.Server to expose your application’s capabilities to AI agents via the Model Context Protocol.

  • .NET 10 application using the Granit module system
  • Granit.Authorization configured (for RBAC permission checks)
  • At least one JWT authentication scheme (Bearer, Keycloak, EntraID, etc.)
  1. Add packages

    Terminal window
    dotnet add package Granit.Mcp
    dotnet add package Granit.Mcp.Server
  2. Register modules in Program.cs

    builder.AddGranit(granit =>
    {
    granit.AddModule<GranitMcpServerModule>();
    // GranitMcpModule is pulled in automatically via [DependsOn]
    });
    builder.AddGranitMcpServer();
  3. Map the MCP endpoint

    app.MapGranitMcpServer();
  4. Create your first tool (see Creating tools)

    [McpServerToolType, McpExposed]
    public sealed class AppointmentMcpTools(IAppointmentReader reader)
    {
    [McpServerTool, Description("Lists upcoming appointments for the current tenant.")]
    [Authorize(Policy = "Scheduling.Appointments.Read")]
    [McpToolOptions(ReadOnly = true)]
    public async Task<string> ListUpcomingAsync(
    [Description("Max number of results")] int limit,
    CancellationToken ct)
    {
    var items = await reader.GetUpcomingAsync(limit, ct);
    return JsonSerializer.Serialize(items);
    }
    }

The MCP endpoint is now live at /mcp. Connect any MCP client (Claude Desktop, Cursor, VS Code) to https://your-app/mcp.

Behind the scenes, a single call registers:

ComponentSDK / GranitPurpose
AddMcpServer()SDKCore MCP server with Implementation { Name = "Granit" }
WithHttpTransport()SDKStreamable HTTP + legacy SSE on one endpoint
AddAuthorizationFilters()SDKEnables [Authorize] / [AllowAnonymous] on tools
WithToolsFromAssembly()SDKScans module assemblies for [McpServerToolType] classes
WithPromptsFromAssembly()SDKScans module assemblies for [McpServerPromptType] classes
AddListToolsFilterGranitTool visibility (tenant, module scope, explicit)
AddCallToolFilterGranitOutput sanitization + audit metrics
3 visibility filtersGranitExplicitDiscoveryFilter, TenantAwareVisibilityFilter, ModuleScopeVisibilityFilter
ErrorSanitizerGranitStrips stack traces and connection strings from errors
McpPermissionsGranit5 RBAC permissions auto-registered in GranitAuthorizationModule
// Default: /mcp with auth required
app.MapGranitMcpServer();
// Custom route prefix, no admin endpoints:
app.MapGranitMcpServer(options =>
{
options.RoutePrefix = "/api/mcp";
options.MapAdminEndpoints = false;
});
RouteProtocolAuthPurpose
{prefix}Streamable HTTP + SSEMcp.Server.AccessMCP protocol endpoint

All options are bindable from appsettings.json:

{
"Mcp": {
"ServerName": "MyApp",
"ServerVersion": "2.1.0",
"ToolDiscovery": "Explicit",
"EnableTenantFiltering": true,
"MaxResponseSizeBytes": 51200,
"Server": {
"RoutePrefix": "/mcp",
"RequireAuthentication": true,
"MapAdminEndpoints": true,
"AdminTagName": "MCP Admin",
"EnabledModules": []
}
}
}

McpPermissionDefinitionProvider auto-registers these permissions in Granit’s authorization system:

ConstantValuePurpose
McpPermissions.Server.AccessMcp.Server.AccessAccess the MCP endpoint
McpPermissions.Tools.ReadMcp.Tools.ReadList tools (admin API)
McpPermissions.Tools.ExecuteMcp.Tools.ExecuteExecute MCP tools
McpPermissions.Resources.ReadMcp.Resources.ReadRead MCP resources
McpPermissions.Prompts.ReadMcp.Prompts.ReadRead MCP prompts

Assign these permissions to roles via the Granit Authorization module, then use them in [Authorize(Policy = "...")] on tool classes and methods.

Add to claude_desktop_config.json:

{
"mcpServers": {
"my-app": {
"type": "url",
"url": "https://localhost:5001/mcp",
"headers": {
"Authorization": "Bearer <your-jwt-token>"
}
}
}
}