npx -y @modelcontextprotocol/inspector@0.22.0 --cli \
http://localhost:8000/petstore \
--transport http --method tools/call \
--tool-name get-pet-by-id \
--tool-arg path_petId=4 | jq -r '.content[0].text' | jq -c '.'Monitor MCP traffic with OpenTelemetry
To monitor MCP tool traffic, attach an OpenTelemetry Policy to an AI MCP Server entity. AI Gateway automatically sends metrics like tool call counts, response sizes, and request durations to your observability backend, with no code changes required.
This tutorial shows you how to attach the Policy using kongctl, generate some MCP traffic, and see the resulting metrics in a local OpenTelemetry Collector.
Prerequisites
Series Prerequisites
This page is part of the Map a RESTful API to MCP tools and observe MCP traffic series.
Complete the previous page, Map a RESTful API to MCP tools before completing this page.
kongctl v1.13.0+
This tutorial uses kongctl to manage Konnect resources programmatically. We recommend keeping kongctl up to date with the latest version (1.13.0).
- Install kongctl from developer.konghq.com/kongctl.
-
Verify the installation:
kongctl version
OpenTelemetry Collector
Launch a local OpenTelemetry Collector in the background, listening on port 4318:
docker run -d \
--name otel-collector \
-p 127.0.0.1:4318:4318 \
otel/opentelemetry-collector:0.141.0Attach an OpenTelemetry Policy to the MCP Server entity
By default, an AI Policy applies to every resource on your AI Gateway. Setting global to false changes that: the otel-mcp Policy only takes effect on entities that explicitly list it, instead of applying to all entities.
The petstore-mcp entity does this by referencing otel-mcp in its policies list. As a result, every request that goes through petstore-mcp is measured and exported as metrics to the collector you started earlier. The service.name value under resource_attributes is a label attached to that exported data, so if you’re running multiple AI Gateways or services into the same collector, you can tell which one a given metric came from.
kongctl apply -f - --auto-approve --pat "$KONNECT_TOKEN" << 'EOF'
ai_gateway_policies:
- ref: otel-mcp
ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
name: otel-mcp
display_name: "otel-mcp"
type: opentelemetry
enabled: true
global: false
config:
traces_endpoint: http://host.docker.internal:4318/v1/traces
metrics:
endpoint: http://host.docker.internal:4318/v1/metrics
enable_ai_metrics: true
resource_attributes:
service.name: kong-mcp
ai_gateway_mcp_servers:
- ref: petstore-mcp
ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
name: petstore-mcp
display_name: "Petstore API"
type: conversion-listener
enabled: true
policies:
- !ref otel-mcp#name
access:
acl_attribute_type: consumer
acls:
allow: []
default_tool_acls:
deny: []
config:
url: http://host.docker.internal:8080/api/v3
route:
paths:
- /petstore
logging:
payloads: false
server:
timeout: 60000
tools:
- name: get-pets-by-status
description: Find pets by status
method: GET
path: /petstore/pet/findByStatus
parameters:
- name: status
in: query
required: true
schema:
type: string
enum:
- available
- pending
- sold
description: Status value to filter pets by
- name: get-pet-by-id
description: Get a pet by ID
method: GET
path: /petstore/pet/{petId}
parameters:
- description: ID of the pet to retrieve
in: path
name: petId
required: true
schema:
type: integer
EOFGenerate MCP traffic
Now, we can check the details of Dog 1 (id:4) by calling the get-pet-by-id tool:
You should see the following response:
{"id":4,"category":{"id":1,"name":"Dogs"},"name":"Dog 1","photoUrls":["url1","url2"],"tags":[{"id":1,"name":"tag1"},{"id":2,"name":"tag2"}],"status":"available"}Validate metrics
Check the collector’s logs for kong.gen_ai.mcp to find the emitted metrics:
Allow a few seconds for the collector to export metrics after traffic generation.
docker logs otel-collector 2>&1 | grep -A 15 kong.gen_ai.mcpYou should see data like the following:
Metric #8
Descriptor:
-> Name: kong.gen_ai.mcp.response.size
-> Description: Size of AI MCP response body
-> Unit: By
-> DataType: Histogram
-> AggregationTemporality: Cumulative
HistogramDataPoints #0
Data point attributes:
-> kong.workspace.name: Str(default)
-> kong.route.name: Str(petstore-mcp-route)
-> mcp.method.name: Str(tools/call)
-> gen_ai.tool.name: Str(get-pet-by-id)
-> kong.service.name: Str(petstore-mcp)
Count: 1
Sum: 2175.000000
Metric #10
Descriptor:
-> Name: mcp.server.operation.duration
-> Description: MCP request/notification duration as observed on the receiver
-> Unit: s
-> DataType: Histogram
-> AggregationTemporality: Cumulative
HistogramDataPoints #3
Data point attributes:
-> gen_ai.operation.name: Str(execute_tool)
-> kong.workspace.name: Str(default)
-> kong.route.name: Str(petstore-mcp-route)
-> mcp.method.name: Str(tools/call)
-> gen_ai.tool.name: Str(get-pet-by-id)
-> kong.service.name: Str(petstore-mcp)
Count: 1
Sum: 0.037000kong.route.name carries a -route suffix because AI Gateway auto-generates a Route for the MCP Server entity.
See MCP metrics for the full metric reference.
MCP Metrics in Konnect
You can also view MCP traffic metrics without setting up a collector, using Konnect Analytics:
- Go to Observability > Dashboards.
- Click Create dashboard > Create from template.
- Select the Agentic analytics dashboard. This dashboard highlights which tools are called most frequently, breaks down tool usage by consumer, and tracks average latency per tool over time, helping teams operating MCP-enabled services understand usage patterns and identify performance bottlenecks.
- Click Use template to see MCP tool usage, total MCP requests, total MCP errors, and other statistics.
Cleanup
Stop the OpenTelemetry Collector
docker rm -f otel-collectorStop Petstore API
docker rm -f swagger-petstoreClean up AI Gateway resources
To clean up all AI Gateway resources created in this guide, run:
curl -Ls https://get.konghq.com/ai | bash -s -- -d