Tools are ordinary Yii3 services
Public methods annotated with the SDK's own
MCP server integration for Yii3 over the official mcp/sdk — core + audit log, RBAC, and telemetry bridges.
AI agent (Claude Code, Claude Desktop, …)
│ JSON-RPC over Streamable HTTP or stdio
▼
SharedSecretMiddleware ── fail-closed shared-secret guard
▼
McpAction / McpServeCommand
▼
Mcp\Server ── built by McpServerFactory
│
├─ your tool classes (#[McpTool] methods, DI-resolved)
├─ OpenAPI-bridged operations (OpenApiServerConfigurator)
├─ Markdown-file prompts (MarkdownPromptsConfigurator)
└─ interceptor chain
budget → [tracing → audit → RBAC] → cache → size limitThe bracketed interceptors are the three bridges — nothing about them is special-cased in the core; each is an ordinary Interceptor\ToolCallInterceptorInterface.
use Mcp\Capability\Attribute\McpTool;
final readonly class OrderTools
{
public function __construct(private OrderRepository $orders) {}
#[McpTool(name: 'order.status')]
public function status(string $orderId): string
{
return $this->orders->get($orderId)->status->value;
}
}use Rasuvaeff\Yii3McpRbacBridge\RequiredPermission;
#[McpTool(name: 'order.status')]
#[RequiredPermission('orders.view')]
public function status(string $orderId): string { /* … */ }'rasuvaeff/yii3-mcp' => [
'interceptors' => [AuditTrailInterceptor::class],
],
// every tools/call now writes an audit event: actor, tool, arguments,
// outcome, duration — masked, rethrown on failure'rasuvaeff/yii3-mcp' => [
'interceptors' => [
TracingToolCallInterceptor::class,
MetricsToolCallInterceptor::class,
],
],
// mcp.tool <name> span + mcp_tool_calls_total / mcp_tool_call_duration_secondsSee Bridges: overview for how they combine, and Getting started to wire the core on its own.