Documentation · Operating
Setting up metrics and Grafana
This page is an outline. What is here is accurate, but it is
not yet the whole story — each section ends with a note on what is still to be
written. For anything it does not answer, DEPLOYMENT.md and
USING-MCP.md in the repository are the complete references.
There are TWO endpoints, and they are easy to confuse
If your dashboard is empty, this is almost certainly why.
| Container health | Per-tool MCP metrics | |
|---|---|---|
| Where | The console, :8080/metrics | Each generated server, MCP_METRICS_PORT (e.g. :9464) |
| How many | One per container | One per running config |
| Switch | Always on — nothing to enable | PROMETHEUS_SERVER=YES and a port |
| Series | mcpdbwizard_container_* | mcpdbwizard_mcp_* |
A scrape config aimed only at 9464 collects no mcpdbwizard_container_* at all, and Grafana shows
an empty panel with no error anywhere.
scrape_configs:
- job_name: mcpdbwizard-container # CPU / memory / disk, one per container
static_configs:
- targets: ['mcpdbwizard-web:8080']
- job_name: mcpdbwizard-mcp # per-tool call metrics, one per generated server
static_configs:
- targets: ['mcpdbwizard-web:9464']
Turning on the per-tool metrics
Two switches, and you need both. PROMETHEUS_SERVER=YES in the config emits the collection and
the endpoint at generation time; MCP_METRICS_PORT at run time is what actually binds a socket.
There is deliberately no default port — the console runs up to twenty generated servers at once,
and a default would give one a socket and the rest a bind failure. Either set
mcpdbwizard.runtime.metrics-port-range (e.g. 9464-9483) and let the deployment allocate one per
server, or name a port per config on the Service Options tab for a scrape target that stays valid
across restarts.
What you get
Labelled by server, tool, db_object and object_type:
| Metric | Type | What it answers |
|---|---|---|
mcpdbwizard_mcp_calls_total | counter | call count, also split by outcome |
mcpdbwizard_mcp_call_duration_seconds{quantile} | summary | p50, p75, p90 over the last 2048 calls to that tool |
mcpdbwizard_mcp_call_duration_seconds_max | gauge | the worst call since start-up |
mcpdbwizard_mcp_request_bytes_total / _response_bytes_total | counter | inbound and outbound JSON volume |
mcpdbwizard_mcp_pool_* | gauge/counter | the POOL-STATS numbers, without parsing a log |
db_object is the label that matters, and it is why this needs a generation-time flag at all. A
tool name is a flattened Oracle name and one object yields several tools, so nothing at run time
could map one back to PAYROLL.JS_ADMIN.GREET. The generator writes the mapping into the server, so
sum by (db_object) needs no join.
Alert on absence, not only on errors
A call rejected by input-schema validation is not counted — the SDK checks the schema before the handler the metrics live in. A client sending malformed arguments therefore shows up as no traffic, not as failures.
The endpoint is unauthenticated and binds loopback
Exposing it with MCP_METRICS_HOST=0.0.0.0 logs a warning but is not refused: it is read-only and
carries no data from the database. It does publish your schema’s object names and your traffic shape,
so put a network policy in front of it.
To write. A ready-to-import Grafana dashboard JSON; example PromQL for the panels worth having; recommended alerts; the memory-limit caveat that decides whether the container gauge is about your container or the whole host.