MCP support
Your project includes a Model Context Protocol (MCP) server that allows AI clients like Claude Code and Claude Desktop to interact with your application data. Authentication uses OAuth2 via Better Auth.
How it works
- AI client connects to the MCP endpoint with OAuth2 authentication.
- Client calls
tools/listto discover available tools (CRUD operations for each entity). - Client calls
tools/callto execute tools — listing, creating, updating, or deleting records. - Tools respect user permissions — only tools the authenticated user has access to are available.
Endpoint
POST /api/mcp/:language/:organizationIdThe endpoint accepts JSON-RPC requests implementing the MCP specification (version 2024-11-05).
| Method | Description |
|---|---|
initialize | Returns server info and capabilities |
tools/list | Lists available tools with JSON schemas |
tools/call | Executes a tool by name with arguments |
notifications/initialized | Acknowledgment (returns 204) |
Connecting an AI client
The MCP docs page (/mcp) shows users how to connect their AI client. It displays the endpoint URL with the correct organization and language parameters, along with step-by-step instructions.
Claude Code
Add the MCP server to your Claude Code configuration:
{
"mcpServers": {
"your-app": {
"type": "url",
"url": "https://your-backend-url/api/mcp/en/your-org-id"
}
}
}Claude Code handles the OAuth2 flow automatically.
Authentication
The MCP server uses Better Auth's MCP plugin with OAuth2/OIDC:
- Auto-registered OAuth endpoints:
/.well-known/oauth-authorization-serverand/.well-known/oauth-protected-resource - Dynamic client registration is enabled
- Users authenticate via the sign-in page, then the OAuth flow grants access to the MCP server
Tool structure
Each feature defines tools in [feature]Mcp.ts files. Tools follow a standard pattern:
export const memberFindManyMcpTool = (dictionary: Dictionary): McpTool => ({
name: 'member_list',
description: dictionary.member.mcpDescription.list,
requiredPermissions: { member: ['read'] },
schema: toMcpJsonSchema(memberFindManyInputSchema),
handler: async (params, context) => {
return await memberFindManyController(params, context);
},
});Tools are aggregated in mcp.ts via getAllMcpTools(), which is also used by the chatbot feature.
Error mapping
HTTP errors are mapped to JSON-RPC codes:
| HTTP | JSON-RPC | Meaning |
|---|---|---|
| 400 | -32602 | Invalid params |
| 401 | -32001 | Unauthorized |
| 403 | -32002 | Forbidden |
| 404 | -32003 | Not found |
| Other | -32603 | Internal error |
Permissions
The MCP docs page requires the mcp:use permission. Both admin and member roles have this permission by default.
Key files
| File | Description |
|---|---|
backend/src/features/mcp/mcp.ts | Main router + tool aggregator |
backend/src/features/mcp/mcpTypes.ts | McpTool interface |
backend/src/features/mcp/mcpSchemaConverter.ts | Zod to JSON Schema converter |
backend/src/features/[entity]/[entity]Mcp.ts | Per-feature tool definitions |
frontend/src/features/mcp/pages/McpDocsPage.tsx | Connection docs page |