feat: MCP Server plugin (Task 5.16) - expose LeoCRM tools to external AI clients

- New plugin app/plugins/builtins/mcp_server/ with 9 MCP tools
- Tools: search_contacts, get_contact, create_contact, list_calendar_entries,
  create_calendar_entry, list_emails, send_email, list_files, upload_file
- Routes: GET /api/v1/mcp/tools, POST /api/v1/mcp/tools/{name}/execute, GET /api/v1/mcp/config
- API-token auth via session + RBAC (mcp:read, mcp:write)
- Frontend: mcp.ts API client with React Query hooks
- Frontend: SettingsMcp.tsx settings page with tool listing and execution
- i18n: de.json and en.json updated with MCP entries
- Tests: 7 tests covering tool listing, config, execution, auth, schema validation
This commit is contained in:
Agent Zero
2026-07-23 23:01:59 +02:00
parent f4beb78f91
commit 9d4f701a25
14 changed files with 1313 additions and 6 deletions
@@ -0,0 +1,54 @@
"""Pydantic schemas for MCP Server plugin."""
from __future__ import annotations
from typing import Any
from pydantic import BaseModel, Field
class McpToolParameter(BaseModel):
"""Single parameter in an MCP tool definition."""
name: str
type: str
description: str
required: bool = False
default: Any | None = None
class McpToolDefinition(BaseModel):
"""MCP tool definition returned by GET /api/v1/mcp/tools."""
name: str
description: str
category: str
parameters: list[McpToolParameter]
required_permission: str | None = None
class McpToolExecuteRequest(BaseModel):
"""Request body for POST /api/v1/mcp/tools/{tool_name}/execute."""
arguments: dict[str, Any] = Field(default_factory=dict)
class McpToolExecuteResponse(BaseModel):
"""Response from executing an MCP tool."""
tool: str
success: bool
result: Any | None = None
error: str | None = None
class McpServerConfig(BaseModel):
"""MCP server configuration for external clients."""
server_name: str = "LeoCRM"
server_version: str = "1.0.0"
protocol_version: str = "2024-11-05"
base_url: str = "/api/v1/mcp"
auth_method: str = "api-token"
available_tools: list[str] = Field(default_factory=list)
class McpToolListResponse(BaseModel):
"""Response listing all MCP tools."""
tools: list[McpToolDefinition]
count: int