Download the PHP package rasuvaeff/yii3-mcp-telemetry-bridge without Composer
On this page you can find all versions of the php package rasuvaeff/yii3-mcp-telemetry-bridge. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download rasuvaeff/yii3-mcp-telemetry-bridge
More information about rasuvaeff/yii3-mcp-telemetry-bridge
Files in rasuvaeff/yii3-mcp-telemetry-bridge
Package yii3-mcp-telemetry-bridge
Short Description Tracing and metrics for MCP servers: spans and RED-style metrics for every yii3-mcp tools/call via rasuvaeff/yii3-telemetry and rasuvaeff/yii3-metrics
License BSD-3-Clause
Homepage https://github.com/rasuvaeff/yii3-mcp-telemetry-bridge
Informations about the package yii3-mcp-telemetry-bridge
rasuvaeff/yii3-mcp-telemetry-bridge
Observability for MCP servers: a trace span and RED-style metrics for every
rasuvaeff/yii3-mcp tools/call, via
rasuvaeff/yii3-telemetry and
rasuvaeff/yii3-metrics.
Using an AI coding assistant? llms.txt contains a compact API reference you can share with the model. Contributors: see AGENTS.md.
Requirements
| Requirement | Version |
|---|---|
| PHP | 8.3 – 8.5 |
rasuvaeff/yii3-mcp |
^1.6 \|\| ^2.0 |
rasuvaeff/yii3-telemetry |
^1.0 |
rasuvaeff/yii3-metrics |
^1.0 |
Both observability cores are vendor-neutral; wire a backend
(yii3-telemetry-otel, yii3-metrics-prometheus) or the Null* providers.
Installation
Usage
One params line — the interceptors are resolved through the DI container (the telemetry/metrics facades must be wired, which their configs do):
Use either interceptor alone if you only run one of the two stacks.
Tracing: TracingToolCallInterceptor
Every tools/call — attribute tools, OpenAPI-bridged operations,
configurator-registered handlers — becomes one span:
| Span field | Value |
|---|---|
| name | mcp.tool <tool name> (e.g. mcp.tool order.status) |
mcp.tool |
tool name |
mcp.tool.argument.<name> |
one scalar attribute per argument: masked (***), stringified (arrays as JSON), truncated at 200 bytes |
mcp.outcome |
success / rejected / error (yii3-mcp's shared CallOutcome) |
mcp.client.id |
identity from the endpoint secret (multi-secret setups); absent on stdio |
mcp.client.name / mcp.client.version |
client from the initialize handshake |
mcp.session.id |
MCP session UUID |
mcp.session.calls_used |
tools/call count in this session (when the session budget is on) |
mcp.session.budget_remaining |
remaining budget (when sessionBudget is configured, see below) |
| status | Error + recorded exception on failure; Unset on success |
A tool exception is recorded on the span and rethrown — the MCP error envelope the agent sees is unchanged.
Arguments are flattened to per-argument scalar attributes on purpose: the OTel attribute model accepts only primitives and homogeneous lists, so a single nested-array attribute would be silently dropped by an OTel backend.
Manual wiring:
sessionBudget only feeds the mcp.session.budget_remaining attribute — the
budget itself is enforced by yii3-mcp's SessionBudgetInterceptor. Since an
int cannot be autowired, mirror your session.budget param in a DI factory:
null and the core default 0 both mean unlimited and omit
mcp.session.budget_remaining; every positive value publishes it. Negative
values are rejected.
OpenTelemetry and SDK Fibers
mcp/sdk runs request handlers in Fibers. The supported concurrent deployment
uses OTel automatic Fiber propagation: NTS PHP, ext-ffi,
OTEL_PHP_FIBERS_ENABLED=true, and (where FPM loads the observer too late)
preloaded vendor/autoload.php. The Integration suite verifies one HTTP parent,
one child mcp.tool ... span and isolation across alternating Fibers:
For strictly sequential php-fpm only, a limited fallback is
Context::setStorage(new ContextStorage()) before tracing starts. It shares a
single current context and is unsafe for event loops or any Fiber that can
suspend/resume concurrently. Do not add fork()/switch() only around
TracingToolCallInterceptor::$next: the SDK Fiber already exists and the
interceptor cannot observe every lifecycle transition.
Metrics: MetricsToolCallInterceptor
| Metric | Type | Labels |
|---|---|---|
mcp_tool_calls_total |
counter | tool, outcome (success/rejected/error) |
mcp_tool_call_duration_seconds |
histogram | tool |
Duration is the wall time of the wrapped chain (hrtime()), observed on both
success and failure. The histogram carries no outcome label to keep
cardinality low — errors are counted in the counter.
Manual wiring:
Interceptor order
Put tracing outermost so the span covers the whole chain (rate limits, RBAC, audit) and other interceptors' failures land on the span:
What the telemetry does NOT see
- Budget rejections are invisible. yii3-mcp auto-adds its
SessionBudgetInterceptoroutermost — outside any interceptor you list. A call rejected by the session budget produces no span and no metric, so an exhausted budget looks like traffic dropping to zero. Watch themcp.session.budget_remainingattribute on the calls that do go through. - Session-ownership rejections are invisible (yii3-mcp
^2.0). The core binds every session to the MCP client that created it and rejects a call against a foreign or ownerless session (the SDK-shaped 404 fromMcpAction,SessionOwnershipExceptionfromInterceptingReferenceHandler) before the interceptor chain runs. An ownership-rejected call produces no span and nomcp_tool_calls_totalincrement — hijack attempts show up only in the application/web-server logs, not in the telemetry. - Rejections are
rejected, noterror. AToolCallExceptionthrown by an inner interceptor (RBAC denial, rate limit, session budget) or the tool itself is classified via yii3-mcp'sCallOutcome: counteroutcome="rejected", span attributemcp.outcome=rejected(the span status still becomesErrorwith the recorded exception — the tracing contract is unchanged). Alert onoutcome="error"for crashes only.
stdio mode (mcp:serve)
The stdio worker is long-running: make sure your tracing backend exports
spans per call rather than only on process shutdown (for
yii3-telemetry-otel, use a batch processor with a scheduled delay or a
simple processor), otherwise spans buffer until the agent disconnects.
Security
- Arguments land on the span masked by field name (case-insensitive, at
every nesting level) via yii3-mcp's
ArgumentMasker— the same semantics as the audit bridge, so the two never disagree. Extend the key list via the constructor if your tools take other sensitive fields. - Span attributes leave the process through your tracing backend — treat trace storage with the same care as the data the tools access, or mask more aggressively.
- The interceptors add no failure mode to tool execution: tool exceptions are rethrown unchanged.
Examples
See examples/ — runs offline.
| Script | Shows | Needs server? |
|---|---|---|
tool-call-observability.php |
A tool call producing a span (logged via LogTracer) and metrics (in-memory snapshot), with a masked password argument |
no |
Dependency analysers
This leaf package is selected by the root application through config-plugin and may legitimately have no class reference in an autoloaded source directory. Keep the direct dependency: the application, not a core package, selects the backend or bridge. Scope the Composer Dependency Analyser exception to this package:
composer-require-checker detects used but undeclared symbols, not unused
packages, so this config-only dependency needs no require-checker suppression.
Development
No PHP/Composer on the host — run in Docker via the composer:2 image:
Or with Make: make build, make cs-fix, make psalm, make test.
License
BSD-3-Clause. See LICENSE.md.
All versions of yii3-mcp-telemetry-bridge with dependencies
rasuvaeff/yii3-mcp Version ^1.6 || ^2.0
rasuvaeff/yii3-metrics Version ^1.0
rasuvaeff/yii3-telemetry Version ^1.0