MCP Telemetry sample
This page is part of the documentation for Orleans.Lattice 9.9.0 (release line 9.9), built 2026-10-04. It is also published as markdown, with every table and list, at README.md, and llms.txt lists every page.A single-process demonstration of the optional
Orleans.Lattice.Api.Mcp.Telemetry add-on. It co-hosts a single-silo Orleans
cluster with the Model Context Protocol (MCP) server, exports the cluster's
orleans.lattice metrics over Prometheus, and drives the telemetry tools with a
real MCP client - proxying a real Prometheus instance running in Docker.
The round-trip is genuine: the Docker Prometheus scrapes this process's
/metrics endpoint, and this process's lattice_telemetry_* tools then query
that same Prometheus over its PromQL HTTP API.
[ this process ] [ docker compose ]
Orleans silo + Lattice prometheus:9090
| emits orleans.lattice metrics ^ |
| /metrics (OTel Prometheus exporter) --/ | PromQL HTTP API
| v
MCP server + AddTelemetryTools -----------> queries Prometheus
^
| streamable HTTP + in-process MCP client
AI agent journey
It proves the headline properties of the telemetry surface:
- Capability-gated discovery. An agent granted the cluster-wide
LatticeOperation.Telemetrycapability discovers the four read-onlylattice_telemetry_*tools and runs a live PromQL query end-to-end over MCP. - Permission-scoping. The same agent, granted only telemetry, does not see the state tools the server also registers - and an unauthenticated caller is offered nothing at all.
- The dual-credential boundary. The tools authenticate to Prometheus with a
backend credential the host configures (here
None, because the sample's Prometheus is unauthenticated), never the caller's Lattice identity.
Known issue: the sample registers no
ILatticeApiMcpAuthorizer.AddLatticeMcptherefore falls back to the defaultDenyAllMcpAuthorizer, which the discovery core consults for every group tool - the telemetry tools included - when it builds the tool list and again when a tool is called;RequireAuthorization = falsedoes not lift that gate. As written, the agent is offered only thelattice_capabilitiesmeta-tool, so the four telemetry tools never appear and the run cannot complete property 1 or the live queries below: after waiting for the telemetry tools, its firstlattice_telemetry_querycall names a tool the session does not offer, which the MCP server answers with a protocol error, so the client throws and the run ends there, before the anonymous-caller act. The anonymous caller would still be offered nothing. RegisteringAllowAllMcpAuthorizer(or your ownILatticeApiMcpAuthorizer) is the missing step for the agent journey.
Run it
The sample needs a Prometheus to talk to, so start it first with Docker, then run the sample:
docker compose -f samples/McpTelemetry/docker-compose.yml up -d
dotnet run --project samples/McpTelemetry/McpTelemetry.csproj
The sample seeds an agent subject with a cluster-wide telemetry grant, drives a
burst of writes and reads to populate the orleans.lattice metrics, then is
written to (as written it stops short - see the known issue above):
- prints the four telemetry tools the agent discovered (and confirms it sees zero state tools),
- waits for Prometheus to scrape the silo, then runs
lattice_telemetry_queryfor the silo's scrape-health (up), - lists the Lattice metric names Prometheus discovered and queries one (in
Prometheus form,
orleans_lattice_*: the OpenTelemetry exporter turns the dots into underscores and appends unit words such as_millisecondsand_bytes, and_totalto counters), - shows the anonymous caller being offered zero tools,
and exits. Tear Prometheus down afterwards with:
docker compose -f samples/McpTelemetry/docker-compose.yml down
Prometheus scrapes the host process at host.docker.internal:5290; on Docker
Desktop this resolves automatically, and the compose file adds a host-gateway
mapping so it also works on Linux. If the sample reports that Prometheus did not
report the silo as up, confirm docker compose up -d is running and that port
5290 is reachable from the container.
Authorization on the MCP endpoint is disabled purely to keep the sample
one-command runnable with no identity provider: a demo credential bridge maps a
request carrying a marker header onto a fixed agent credential. A real
deployment leaves RequireAuthorization at its secure default, registers an
ILatticeApiMcpAuthorizer, and lifts an authenticated ASP.NET Core principal
onto the ambient credential instead, and
points the telemetry proxy at an authenticated Prometheus with a Bearer,
Basic, or MutualTls backend credential, or a rotating DynamicBearer token.
What to look at
Program.cs- the silo + MCP host wiring (AddOpenTelemetry().WithMetrics(...),AddLatticeMcp/AddStateTools/AddTelemetryTools/MapLatticeMcp/MapPrometheusScrapingEndpoint, with the MCP endpoint mounted at/mcpso it coexists with/metrics), the cluster-wide telemetry grant seeding, and the MCP client journey.docker-compose.ymlandprometheus.yml- the real Prometheus that scrapes the silo and answers the telemetry tools' PromQL queries.DemoCredentialBridge.cs/DemoAuthenticator.cs- the fail-closed demo identity plumbing (shared shape with theMcpServersample).- The package docs under
docs/lattice.api.mcp.telemetry/cover the tool catalogue, the dual-credential trust boundary, and the metric-access allow-list in depth.