MCP Integration — Expose Granit Modules to AI Agents
Granit wraps the official MCP C# SDK to let any Granit-based application expose its capabilities to AI agents via the Model Context Protocol (MCP). An agent connects to your app, discovers available tools, and invokes them — with full Granit authorization, multi-tenancy, and GDPR sanitization applied automatically.
What you can do with Granit.Mcp
Section titled “What you can do with Granit.Mcp”| Capability | Package | What it does |
|---|---|---|
| Expose tools | Granit.Mcp | Auto-discover [McpServerTool] methods from module assemblies |
| HTTP transport | Granit.Mcp.Server | Streamable HTTP endpoint with [Authorize] + RBAC permissions |
| GDPR sanitization | Granit.Mcp | Omit PII from tool responses, truncate large payloads, strip stack traces |
| Multi-tenancy | Granit.Mcp.Server | Per-tenant tool visibility, module scoping, opt-in discovery |
| Consume external servers | Granit.Mcp.Client | Named factory for HTTP + stdio connections with credential forwarding |
| AI workspace bridge | Granit.AI.Mcp | Inject MCP tools into IChatClient pipelines, cost-controlled sampling |
Package structure
Section titled “Package structure”DirectoryGranit.Mcp/ Core abstractions, auto-discovery, sanitization pipeline, diagnostics
DirectoryGranit.Mcp.Server/ ASP.NET Core Streamable HTTP transport, auth, permissions, visibility filters
- …
DirectoryGranit.Mcp.Client/ Named factory for external MCP server connections (HTTP + stdio)
- …
DirectoryGranit.AI.Mcp/ Bridge MCP tools into Granit.AI workspaces, sampling guard
- …
Architecture
Section titled “Architecture”flowchart LR
subgraph "Your Granit App"
direction TB
M1["[McpServerTool]<br/>BlobStorage tools"] --> MCP["Granit.Mcp<br/>Auto-discovery + Filters"]
M2["[McpServerTool]<br/>Workflow tools"] --> MCP
MCP --> SRV["Granit.Mcp.Server<br/>HTTP transport + Auth"]
end
AI["AI Agent<br/>(Claude, Copilot, Cursor)"] -- "Streamable HTTP<br/>/mcp" --> SRV
subgraph "External"
ERP["ERP MCP Server"]
end
CLI["Granit.Mcp.Client"] -- "HTTP / stdio" --> ERP
CLI --> AIM["Granit.AI.Mcp<br/>→ IChatClient tools"]
Design principles
Section titled “Design principles”SDK-native, not wrapper-heavy
Section titled “SDK-native, not wrapper-heavy”Granit delegates to the MCP C# SDK wherever possible. Cross-cutting concerns
(sanitization, visibility, audit) are wired into the SDK’s onion-model filter
pipeline (AddCallToolFilter, AddListToolsFilter) — not a parallel abstraction.
Standard ASP.NET Core authorization
Section titled “Standard ASP.NET Core authorization”No custom auth attributes. Tool authorization uses [Authorize(Policy = "...")]
via the SDK’s .AddAuthorizationFilters(). Granit’s DynamicPermissionPolicyProvider
maps policy names to RBAC permissions automatically.
Opt-in by default
Section titled “Opt-in by default”In production (McpToolDiscoveryMode.Explicit), tool classes need [McpExposed]
alongside [McpServerToolType]. An accidental [McpServerTool] on an internal
service stays hidden until explicitly opted in.
GDPR-compliant output
Section titled “GDPR-compliant output”Tool responses pass through a sanitization pipeline before reaching the AI agent. PII is omitted (not masked — masked values waste LLM tokens and trigger hallucinations), large payloads are truncated, and error messages are stripped of stack traces.
Quick start
Section titled “Quick start”Three lines to expose your first MCP tool:
// 1. Registerbuilder.AddGranitMcpServer();
// 2. Mapapp.MapGranitMcpServer();
// 3. Create a tool (in any module assembly)[McpServerToolType, McpExposed]public sealed class InvoiceMcpTools(IInvoiceReader reader){ [McpServerTool, Description("Search invoices by status and date range.")] [Authorize(Policy = "Invoicing.Invoices.Read")] [McpToolOptions(ReadOnly = true)] public async Task<string> SearchInvoicesAsync( [Description("Invoice status filter")] string status, [Description("Start date (ISO 8601)")] DateOnly from, ICurrentTenant tenant, CancellationToken ct) { var invoices = await reader.SearchAsync(status, from, ct); return JsonSerializer.Serialize(invoices); }}Connect Claude Desktop, Cursor, or any MCP client to https://your-app/mcp — your
tools appear automatically.
Observability
Section titled “Observability”Meter: Granit.Mcp — all metrics follow Granit conventions.
| Metric | Type | Tags |
|---|---|---|
granit.mcp.tools.invoked | Counter | tenant_id, tool_name, status |
granit.mcp.resources.read | Counter | tenant_id, resource_uri |
granit.mcp.sessions.active | UpDownCounter | tenant_id, transport |
granit.mcp.request.duration | Histogram (s) | tenant_id, method |
Activity source: Granit.Mcp — registered via GranitActivitySourceRegistry.