Table of Contents

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:

  1. Capability-gated discovery. An agent granted the cluster-wide LatticeOperation.Telemetry capability discovers the four read-only lattice_telemetry_* tools and runs a live PromQL query end-to-end over MCP.
  2. 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.
  3. 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. AddLatticeMcp therefore falls back to the default DenyAllMcpAuthorizer, 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 = false does not lift that gate. As written, the agent is offered only the lattice_capabilities meta-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 first lattice_telemetry_query call 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. Registering AllowAllMcpAuthorizer (or your own ILatticeApiMcpAuthorizer) 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_query for 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 _milliseconds and _bytes, and _total to 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 /mcp so it coexists with /metrics), the cluster-wide telemetry grant seeding, and the MCP client journey.
  • docker-compose.yml and prometheus.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 the McpServer sample).
  • 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.