Observable AI Agents
The Observable AI Agents use case describes automatic, zero-instrumentation metrics for every MCP call. This tutorial runs a small gateway, makes a few tool calls, and watches the counters move.
Prerequisites
docker-compose.yaml
services:
gateway:
image: ghcr.io/aklivity/zilla:latest
pull_policy: always
depends_on:
- payments-api
ports:
- 7114:7114
- 7190:7190
volumes:
- ./zilla.yaml:/etc/zilla/zilla.yaml
command: start -v -e
payments-api:
image: kennethreitz/httpbin
ports:
- 8000:80zilla.yaml
name: observable-ai-agents
catalogs:
payments_catalog:
type: inline
options:
subjects:
get_payment_status_params:
schema: |
{
"type": "object",
"properties": {
"paymentId": {
"type": "string"
}
},
"required": [
"paymentId"
]
}
stores:
cache:
type: memory
bindings:
north_tcp_server:
type: tcp
kind: server
options:
host: 0.0.0.0
port: 7114
routes:
- when:
- port: 7114
exit: north_http_server
north_http_server:
type: http
kind: server
options:
access-control:
policy: cross-origin
routes:
- when:
- headers:
":path": /mcp
exit: north_mcp_server
#region telemetry_attributes
north_mcp_server:
type: mcp
kind: server
exit: north_mcp_proxy
telemetry:
metrics:
- mcp.*
attributes:
method: ${mcp.method}
tool: ${mcp.tool}
outcome: ${mcp.outcome}
#endregion telemetry_attributes
north_mcp_proxy:
type: mcp
kind: proxy
options:
cache:
store: cache
ttl: PT5M
routes:
- exit: payments_http_proxy
when:
- toolkit: payments
payments_http_proxy:
type: mcp-http
kind: proxy
options:
tools:
get_payment_status:
description: Look up the status of a payment by identifier.
summary: "Routed to ${result.url}"
schemas:
input:
model: json
catalog:
payments_catalog:
- subject: get_payment_status_params
version: latest
routes:
- when:
- tool: get_payment_status
exit: sys:http_client
with:
headers:
":method": GET
":scheme": http
":authority": payments-api:80
":path": /anything/payments/${args.paymentId}
#region telemetry_exporters
telemetry:
metrics:
- mcp.initialize
- mcp.initialize.duration
- mcp.tools.list
- mcp.tools.list.duration
- mcp.tools.call
- mcp.tools.call.duration
exporters:
prometheus_exporter:
type: prometheus
options:
endpoints:
- scheme: http
port: 7190
path: /metrics
#endregion telemetry_exportersnorth_mcp_server's telemetry.attributes dimension every metric by method, tool, and outcome, populated by the gateway itself:
north_mcp_server:
type: mcp
kind: server
exit: north_mcp_proxy
telemetry:
metrics:
- mcp.*
attributes:
method: ${mcp.method}
tool: ${mcp.tool}
outcome: ${mcp.outcome}Start the Stack
docker compose up -dMake a Few Tool Calls
Point an MCP client at http://localhost:7114/mcp and call payments__get_payment_status a couple of times with different paymentId values.
Watch the Counters
curl http://localhost:7190/metrics | grep mcp_tools_callmcp_tools_call_total{namespace="observable-ai-agents",binding="north_mcp_server",method="tools.call",outcome="ok",tool="payments__get_payment_status"} 2The counter reflects exactly how many calls were made, dimensioned by tool and outcome, without a single line of instrumentation in an agent or in payments-api.
Stop the Stack
docker compose downNext Steps
- See Monitoring and Observability for the full metrics table, attribute reference, and exporter options (OTLP, AWS CloudWatch, Syslog).

