Exposing ABP application services as MCP tools for AI agents
By turning your ABP application services into MCP tools, AI agents such as Claude Code, GitHub Copilot or Cursor can list orders and approve invoices in plain language. The article lays out a roughly 150-line pattern that keeps permission checks, multi-tenant data filters and audit logging exactly where they already are: a thin tool class, a /mcp endpoint and agents acting on behalf of a user via OpenIddict bearer tokens.
Key points
- Every [McpServerTool] method calls an existing ABP application service, so permissions, tenant filters and auditing stay in that layer.
- Inject the service interface (IBookAppService): the proxy makes the authorization, unit of work and auditing interceptors run.
- The entity must implement IMultiTenant so the repository filters by CurrentTenant automatically.
- The endpoint is added with MapMcp("/mcp") via AbpEndpointRouterOptions; stateless mode keeps the normal middleware pipeline and works behind a load balancer.
- Bearer tokens make the agent act as a user; the OpenIddict validation scheme returns 401 to anonymous clients.
- Catch AbpAuthorizationException and return a clear denial the model can explain; ReadOnly/Destructive annotations are hints, not security.
Built with ABP 11.0.0-rc.1, .NET 11 RC3 and Microsoft's official MCP C# SDK (ModelContextProtocol.AspNetCore 2.3.1), the pattern routes agents through your existing application services instead of a separate "AI API" that talks to the database. Every [McpServerTool] method calls an app service, so [Authorize] checks, unit of work, multi-tenant data filters and audit logging are applied by ABP's interceptors. The key details are injecting the interface such as IBookAppService rather than the class, and making the entity implement IMultiTenant.
The endpoint is registered with MapMcp("/mcp") through AbpEndpointRouterOptions, without editing the template's module code, and runs in stateless mode so each request flows through the normal middleware pipeline and scales behind a load balancer without session affinity. Requests are authenticated with bearer tokens, so anonymous agents get a 401. The tool class catches AbpAuthorizationException and returns a "DENIED, nothing was changed" message the model can reason about, while annotations like ReadOnly and Destructive are only hints to the client, not security.
Real-world use
- An e-commerce backend where a support agent tells Claude Code to list the last ten orders and approve a refund.
- A multi-tenant SaaS accounting app where each tenant's agent can only see and approve that tenant's invoices.
- An internal logistics admin app where operations staff update shipment status through tools wired into VS Code or Cursor.
- A regulated finance or healthcare system where every agent call is traceable in AbpAuditLogs by user, tool and time.
Why it matters
A separate "AI API" creates a back door around permissions and tenant boundaries; this pattern gives agents capabilities strictly through your existing security model, so there is no second authorization layer to maintain.