last9-mcp-server
Last9 MCP Server
Documentation
Last9 MCP Server

Your AI agent doesn't know what's broken in production. This fixes that.
Last9 MCP Server connects Claude, Cursor, Windsurf, and any other MCP-capable AI assistant directly to your production observability data — logs, metrics, traces, exceptions, database queries, alerts, and deployments. The agent stops guessing and starts reading the actual signal.
Start in 30 seconds (Hosted)
No binary to install. No tokens to manage. One URL, OAuth in your browser, done.
Find your org slug in your Last9 URL: `app.last9.io//...`
Claude Code
claude mcp add --transport http last9 https://app.last9.io/api/v4/organizations//mcpType `/mcp`, select last9, authenticate. That's it.
Cursor
Settings > MCP > Add New MCP Server:
{
"mcpServers": {
"last9": {
"type": "http",
"url": "https://app.last9.io/api/v4/organizations//mcp"
}
}
}Click Connect, complete OAuth.
VS Code
Requires v1.99+. Open Command Palette → MCP: Add Server, paste the URL, authenticate.
Or directly in `settings.json`:
{
"mcp": {
"servers": {
"last9": {
"type": "http",
"url": "https://app.last9.io/api/v4/organizations//mcp"
}
}
}
}Windsurf
Settings > Cascade > Open MCP Marketplace > gear icon (`mcp_config.json`):
{
"mcpServers": {
"last9": {
"serverUrl": "https://app.last9.io/api/v4/organizations//mcp"
}
}
}Claude Web/Desktop
Settings > Connectors > Add custom connector. Name it `last9`, paste the URL, authenticate.
> Requires admin access to your Claude organization.
Self-Hosted (STDIO)
Use this when your MCP client doesn't support HTTP transport, or when you need the server running locally.
Install
Homebrew:
brew install last9/tap/last9-mcpNPM:
npm install -g @last9/mcp-server@latest
# or directly:
npx -y @last9/mcp-server@latestBinary releases (Windows / manual):
Download from GitHub Releases:
| Platform | Archive |
|---|---|
| Windows (x64) | `last9-mcp-server_Windows_x86_64.zip` |
| Windows (ARM64) | `last9-mcp-server_Windows_arm64.zip` |
| Linux (x64) | `last9-mcp-server_Linux_x86_64.tar.gz` |
| Linux (ARM64) | `last9-mcp-server_Linux_arm64.tar.gz` |
| macOS (x64) | `last9-mcp-server_Darwin_x86_64.tar.gz` |
| macOS (ARM64) | `last9-mcp-server_Darwin_arm64.tar.gz` |
Get a Refresh Token
Only admins can create tokens.
1. Go to API Access
2. Click Generate Token with Write permissions
3. Copy it
Client Configuration
Homebrew:
{
"mcpServers": {
"last9": {
"command": "/opt/homebrew/bin/last9-mcp",
"env": {
"LAST9_REFRESH_TOKEN": ""
}
}
}
}NPM:
{
"mcpServers": {
"last9": {
"command": "npx",
"args": ["-y", "@last9/mcp-server@latest"],
"env": {
"LAST9_REFRESH_TOKEN": ""
}
}
}
}Where to paste this:
| Client | Location |
|---|---|
| Claude Web/Desktop | Settings > Developer > Edit Config (`claude_desktop_config.json`) |
| Cursor | Settings > Cursor Settings > MCP > Add New Global MCP Server |
| Windsurf | Settings > Cascade > MCP Marketplace > gear icon (`mcp_config.json`) |
| VS Code | Wrap in `{ "mcp": { "servers": { ... } } }` in `settings.json` — details |
VS Code STDIO config
{
"mcp": {
"servers": {
"last9": {
"type": "stdio",
"command": "/opt/homebrew/bin/last9-mcp",
"env": {
"LAST9_REFRESH_TOKEN": ""
}
}
}
}
}For NPM: use `"command": "npx"` and add `"args": ["-y", "@last9/mcp-server@latest"]`.
Windows
After downloading from GitHub Releases, extract and point to the full path:
{
"mcpServers": {
"last9": {
"command": "C:\\Users\\\\AppData\\Local\\Programs\\last9-mcp-server.exe",
"env": {
"LAST9_REFRESH_TOKEN": ""
}
}
}
}The NPM route is easier on Windows — no path management.
Environment Variables
| Variable | Default | Description |
|---|---|---|
| `LAST9_REFRESH_TOKEN` | *(required)* | Refresh token from API Access |
| `LAST9_DATASOURCE` | org default | Datasource/cluster name — useful when you have multiple Levitate clusters |
| `LAST9_API_HOST` | `app.last9.io` | Override the API host |
| `LAST9_TOOLSETS` | all tools | Comma-separated toolsets to expose (`logs`, `traces`, `metrics`, `alerts`, `dashboards`, `investigate`, `all`). Alias: `LAST9_MCP_TOOLSETS` |
| `LAST9_MAX_GET_LOGS_ENTRIES` | `5000` | Max entries for chunked `get_logs` requests |
| `LAST9_USE_LOG_SEARCH_API` | `false` | Set `true` to answer `get_logs` and `get_service_logs` with one server-side search call instead of client-side chunking |
| `LAST9_DEBUG_CHUNKING` | `false` | Set `true` to log chunk-planning details for `get_logs`, `get_service_logs`, `get_traces` |
| `LAST9_DISABLE_TELEMETRY` | `true` | Set `false` to enable internal OTel tracing |
| `OTEL_SDK_DISABLED` | — | Standard OTel env var. Overrides `LAST9_DISABLE_TELEMETRY` |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | — | OTLP collector endpoint (only when telemetry is enabled) |
| `OTEL_EXPORTER_OTLP_HEADERS` | — | OTLP auth headers (only when telemetry is enabled) |
What It Can Do
Service Health
- `get_service_summary` — Ranked fleet `(service, env)` rows: interval request_count, throughput_rpm, HTTP 4xx/5xx counts, and gRPC error counts
- `get_service_environments` — Available environments for your services. Run this first — other APM tools need `env` from here
- `get_service_performance_details` — Full breakdown: throughput, error rate, p50/p90/p95/avg/max, apdex, availability
- `get_service_operations_summary` — Operations grouped by HTTP endpoints, DB calls, messaging, HTTP clients
- `get_service_dependency_graph` — Dependency map with throughput, latency, and error rates for upstream/downstream/infra
- `get_apm_service_deviations` — Compare a current window against an equal-duration baseline: regressions/improvements, Apdex reconciliation, and a terminal outcome (fleet or single service)
- `get_exceptions` — Server-side exceptions with service and span filters
Database Observability
Four tools that go directly at your database performance, derived from OpenTelemetry trace spans. No extra instrumentation needed if you're already using OTel.
- `get_databases` — Discover all databases across your infrastructure: DB type, host, throughput (queries/min), p95 latency, error rate, number of dependent services
- `get_database_slow_queries` — The actual slowest query executions, ordered by duration, with trace IDs for drilling into full traces
- `get_database_queries` — Query patterns and aggregates: how often a query runs, average/p95 duration, error rate
- `get_database_server_metrics` — Server-side metrics from the DB host itself (CPU, connections, buffer hit rates — depends on your DB system)
Supports PostgreSQL, MySQL, MongoDB, Redis, Aerospike, and anything else OTel traces with a `db_system` attribute.
Prometheus / PromQL
- `prometheus_range_query` — PromQL range queries over any metric
- `prometheus_instant_query` — Instant queries; use rollup functions like `avg_over_time`, `sum_over_time`
- `prometheus_label_values` — Label values for a given series
- `prometheus_labels` — All labels available for a series
Point these at a different datasource/cluster than the default by setting `LAST9_DATASOURCE`.
Logs
- `get_logs` — Full JSON pipeline log queries (aggregations, filters, field extraction)
- `get_service_logs` — Raw log lines for a service, filterable by severity and body content
- `get_log_attributes` — Global catalog of attributes in the log schema for a time window
- `get_log_attributes_for_pipeline` — Log fields actually present for an in-progress pipeline (scoped discovery), each with its exact `filter_field`
- `get_drop_rules` — Log drop rules from Last9 Control Plane
- `add_drop_rule` — Create a new drop rule to cut log volume at the source
Traces
- `get_traces` — JSON pipeline trace queries for broad searches and aggregations
- `get_service_traces` — Traces by exact trace ID or service name. Use this when you have a trace ID — it's faster
- `get_trace_attributes` — Global catalog of attributes in the trace schema
- `get_trace_attributes_for_pipeline` — Attributes actually present for an in-progress pipeline (scoped discovery), each with its exact `filter_field`
- `get_trace_attribute_values` — Distinct values for a trace attribute, optionally scoped to a pipeline
- `get_trace_attribute_deviations` — Ranks attribute values that differ between two bounded span cohorts (slow vs fast, error vs non-error, or two time windows). Correlation, not cause
- `get_trace_waterfall` — One exact trace as a parent/child waterfall with interval-union self-time, slowest spans, and graph warnings
Change Events & Alerts
- `get_change_events` — Deployments, config changes, rollbacks. Correlate incidents with what changed
- `get_alert_config` — Alert rule configurations — searchable by name, severity, type, tags
- `get_alerts` — Currently firing alerts within a time window
- `get_alert_rule_state` — Historical firing state (1/0) per alert rule over a time range, grouped by `rule_id`. Filterable by alert group, rule name, label filters, and state.
- `get_notification_channels` — Configured notification channels (Slack, PagerDuty, email, etc.)
Custom Dashboards
- `list_dashboards` — All custom dashboards in your org: IDs, names, and metadata
- `get_dashboard` — Full dashboard definition by ID, including panels and queries
- `create_dashboard` — Create a new custom dashboard with panels, queries, and metadata
- `update_dashboard` — Update an existing dashboard by ID (readonly system dashboards return an error)
- `delete_dashboard` — Delete a custom dashboard by ID
- `list_dashboard_snapshots` — Frozen point-in-time snapshots for a dashboard (metadata only)
- `get_dashboard_snapshot` — Full frozen snapshot including panel data for RCA / shareable views
- `delete_dashboard_snapshot` — Delete a frozen snapshot by ID
Fuzzy Name Resolution
- `did_you_mean` — When the agent isn't sure about an entity name, this returns the closest matches from your catalog (services, environments, hosts, databases, K8s deployments/namespaces, jobs). Up to 3 suggestions with similarity scores. The server calls this automatically before most tools when a name lookup returns empty.
Service Profile
- `get_service_profile` — What a service's telemetry actually looks like, before you query it: which signals exist, language and runtime, deployment environments, the shape of its logs, and a recommended ingest fix where one applies. Lets the agent skip trace tools when a service has no traces, and parse severity from the log body when `SeverityText` is empty instead of filtering on it and finding nothing.
How It Works
Deep links on every response. Every tool returns a `deep_link` field — a direct URL into the Last9 dashboard for that exact query and time range. The agent can hand you the link; you click it; you're there.
Toolsets. By default the server exposes every tool. Automation hosts that only need investigation (logs/traces/metrics) can set `LAST9_TOOLSETS=investigate` (or pass `--toolsets=investigate`) so `tools/list` stays small without client-side mass-disable. Named packs: `logs`, `traces`, `metrics`, `alerts`, `dashboards`, `investigate`, `all`. Unknown names fail fast. The `metrics` pack alone does not include `list_datasources` or `did_you_mean` — use `investigate` (or combine toolsets) when you need those discovery helpers.
Tool reference resources. Long logjson/tracejson/service-logs/metrics manuals are MCP resources (`last9://reference/logjson`, `last9://reference/tracejson`, `last9://reference/service_logs`, `last9://reference/metrics`, `last9://reference/investigation`), not always-on tool description text. Critical query rules stay on the tool description so agents that never call `resources/read` still get correct construction guidance. Discover org-specific fields with `get_log_attributes` / `get_log_attributes_for_pipeline` (and the trace equivalents)—they are not injected into descriptions.
Chunked large results. `get_logs` and `get_traces` handle large result sets through chunking rather than truncating. The default limit is 5000 entries for logs; configurable via `LAST9_MAX_GET_LOGS_ENTRIES`.
Development
HTTP mode, curl testing, building from source
Run in HTTP Mode
export LAST9_REFRESH_TOKEN="your_refresh_token"
export LAST9_HTTP=true
export LAST9_PORT=8080
./last9-mcp-serverServer starts at `http://localhost:8080/mcp`.
Test with curl
The Streamable HTTP handler runs in stateless mode, so any request is served independently. An `initialize` handshake and an `Mcp-Session-Id` header are optional — clients that send them still work (the header is accepted and ignored), and clients can also skip straight to `tools/list` / `tools/call`. Every tool is an independent request/response query; the server issues no server→client notifications, so `GET /mcp` (the SSE stream) returns `405`.
# List tools — a session handshake is optional in stateless mode
curl -s -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}'
# Call a tool
curl -s -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_service_logs",
"arguments": {
"service_name": "your-service-name",
"lookback_minutes": 30,
"limit": 10
}
}
}'Build from Source
git clone https://github.com/last9/last9-mcp-server.git
cd last9-mcp-server
go build -o last9-mcp-server
LAST9_HTTP=true ./last9-mcp-server`LAST9_HTTP=true` is for local development. For actual usage, the hosted HTTP endpoint is easier.
Tool Reference
All parameters, time input standards, and details
Time Input
- Absolute times (`start_time_iso`/`end_time_iso`, or `time_iso`) take precedence over `lookback_minutes`.
- For relative windows: use `lookback_minutes`.
- For absolute windows: use RFC3339/ISO8601 — `2026-02-09T15:04:05Z`.
- Legacy `YYYY-MM-DD HH:MM:SS` is accepted for compatibility only.
get_exceptions
- `limit` (integer, optional): Max exceptions. Default: 20.
- `lookback_minutes` (integer, optional): Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional): Absolute time range.
- `service_name` (string, optional): Filter by service.
- `span_name` (string, optional): Filter by span name.
- `env` (string, optional): Filter by environment.
get_service_summary
- `start_time_iso` / `end_time_iso` (string, optional)
- `env` (string, optional): PromQL regex. Defaults to `.*`. Exact match needs anchors (e.g. `^prod$`).
- `sort_by` (string, optional): `request_count` (default), `throughput_rpm`, `http_4xx_count`, `http_5xx_count`, or `grpc_error_count`.
- `limit` (integer, optional): Max ranked rows. Omit or 0 means 10; values above 100 clamp to 100.
get_service_environments
- `start_time_iso` / `end_time_iso` (string, optional)
> All other APM tools require an `env` value. Use `""` if this returns empty.
get_service_performance_details
- `service_name` (string, required)
- `lookback_minutes` (integer, optional): Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional)
- `env` (string, optional): Defaults to `prod`.
get_service_operations_summary
- `service_name` (string, required)
- `lookback_minutes` (integer, optional): Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional)
- `env` (string, optional): Defaults to `prod`.
get_service_dependency_graph
- `service_name` (string, optional)
- `lookback_minutes` (integer, optional): Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional)
- `env` (string, optional): Defaults to `prod`.
get_apm_service_deviations
- `service_name` (string, optional): Omit for fleet scope; provide for one service and its operation correlations.
- `lookback_minutes` (integer, optional): Current window. Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional): Explicit current window.
- `baseline_start_time_iso` / `baseline_end_time_iso` (string, optional): Explicit baseline. Defaults to the immediately preceding equal-duration window.
- `datasource` (string, optional): Restrict the comparison to one datasource.
- `env` (string, optional): Defaults to `prod`.
- `max_services` / `max_operations` (integer, optional): Default 10, max 10 each.
get_databases
- `env` (string, optional): Filter by environment. Default: all.
- `lookback_minutes` (integer, optional): Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional)
get_database_slow_queries
- `db_system` (string, optional): e.g. `postgresql`, `mysql`, `mongodb`, `redis`.
- `host` (string, optional): Database host (`net_peer_name`).
- `service_name` (string, optional): Calling service name.
- `env` (string, optional)
- `min_duration_ms` (float, optional): Minimum query duration in ms.
- `lookback_minutes` (integer, optional): Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional)
- `limit` (integer, optional): Default: 20.
get_database_queries
- `db_system` (string, optional)
- `host` (string, optional)
- `service_name` (string, optional)
- `env` (string, optional)
- `lookback_minutes` (integer, optional): Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional)
- `limit` (integer, optional): Default: 20.
get_database_server_metrics
- `db_system` (string, required): e.g. `postgresql`, `mysql`, `mongodb`, `redis`, `aerospike`.
- `host` (string, optional)
- `lookback_minutes` (integer, optional): Default: 60.
- `start_time_iso` / `end_time_iso` (string, optional)
prometheus_range_query
- `query` (string, required): The PromQL query.
- `start_time_iso` / `end_time_iso` (string, optional): Defaults to last 60 min.
- `lookback_minutes` (float, optional): Default: 60.
prometheus_instant_query
- `query` (string, required)
- `time_iso` (string, optional): Defaults to now.
- `lookback_minutes` (float, optional)
prometheus_label_values
- `match_query` (string, optional): PromQL filter.
- `label` (string, required): Label name.
- `start_time_iso` / `end_time_iso` (string, optional)
prometheus_labels
- `match_query` (string, optional): PromQL filter.
- `start_time_iso` / `end_time_iso` (string, optional)
get_logs
- `logjson_query` (array, required): JSON pipeline query.
- `lookback_minutes` (integer, optional): Default: 5.
- `start_time_iso` / `end_time_iso` (string, optional)
- `limit` (integer, optional): Server default: 5000.
- `index` (string, optional): `physical_index:` or `rehydration_index:`.
For log-based service inventory, query `physical_index_service_count` first:
sum by (name, service_name, env) (physical_index_service_count{destination="logs"})Use `service_name` as `ServiceName`, `env` as the environment when present, and `name` as the physical index name. If `name="default"`, omit `index`; for a non-default physical index selected by the user, pass `index: "physical_index:"`. If the backend rejects explicit physical index filtering, retry without `index` and report that explicit physical index filtering is unavailable for that backend.
get_service_logs
- `service_name` (string, required)
- `lookback_minutes` (integer, optional): Default: 60.
- `limit` (integer, optional): Default: 20.
- `env` (string, optional)
- `severity_filters` (array, optional): e.g. `["error", "warn"]`. OR logic.
- `body_filters` (array, optional): e.g. `["timeout", "failed"]`. OR logic.
- `start_time_iso` / `end_time_iso` (string, optional)
- `index` (string, optional)
Multiple filter types combine with AND. Each array uses OR internally.
Use `get_logs` for broad aggregate counts first; use `get_service_logs` only after narrowing to a service/env/index and a small sample set.
get_log_attributes
- `lookback_minutes` (integer, optional): Default: 15.
- `start_time_iso` / `end_time_iso` (string, optional)
- `region` (string, optional)
- `index` (string, optional)
get_log_attributes_for_pipeline
- `pipeline` (array, required): Prior filter stages to scope discovery, e.g. `[{"type":"filter","query":{"$eq":["ServiceName",""]}}]`.
- `lookback_minutes` (integer, optional): Default: 15.
- `start_time_iso` / `end_time_iso` (string, optional)
- `region` (string, optional)
- `index` (string, optional)
get_drop_rules
No parameters. Lists drop rules via `GET /otel_settings/drop?region=...`.
add_drop_rule
- `name` (string, required)
- `filters` (array, required): Each filter: `key`, `value`, `operator` (`equals`/`not_equals`), `conjunction` (`and`).
- Filter keys must use `attributes["key_name"]` or `resource.attributes["key_name"]` (required by the Last9 API).
- Creates the rule via `POST /otel_settings/drop?region=...&cluster_id=...`.
get_traces
Use for broad searches and aggregations. For exact trace ID lookup, use `get_service_traces`.
- `tracejson_query` (array, required)
- `start_time_iso` / `end_time_iso` (string, optional)
- `lookback_minutes` (integer, optional): Default: 60.
- `limit` (integer, optional): Default: 5000.
get_service_traces
Exactly one of `trace_id` or `service_name` is required.
- `trace_id` (string, optional): Default lookback: 72 hours.
- `service_name` (string, optional): Default lookback: 60 min.
- `lookback_minutes` (integer, optional)
- `start_time_iso` / `end_time_iso` (string, optional)
- `limit` (integer, optional): Default: 10.
- `env` (string, optional)
get_trace_attributes
- `lookback_minutes` (integer, optional): Default: 15.
- `start_time_iso` / `end_time_iso` (string, optional)
- `region` (string, optional)
get_trace_attributes_for_pipeline
- `pipeline` (array, required): Prior filter stages to scope discovery, e.g. `[{"type":"filter","query":{"$eq":["ServiceName",""]}}]`.
- `lookback_minutes` (integer, optional): Default: 15.
- `start_time_iso` / `end_time_iso` (string, optional)
- `region` (string, optional)
get_trace_attribute_values
- `tag_name` (string, required): Attribute name from `get_trace_attributes` (e.g. `resource_department` or `attributes['http.method']`).
- `pipeline` (array, optional): Prior filter stages to scope the values; omit for global values.
- `region` (string, optional)
get_trace_attribute_deviations
- `comparison_mode` (string, required): `latency`, `errors`, or `time`.
- `service_name` (string, required)
- `environment` (string, required): Exact `deployment.environment` value.
- `operation` (string, optional)
- `filters` (array, optional): Trace JSON filter conditions.
- `candidate_attributes` (array, optional): Maximum 8; omit for bounded discovery.
- `latency_threshold_ms` (number, optional): Required for `latency` mode; rejected for other modes.
- `start_time_iso` / `end_time_iso` (string, optional)
- `lookback_minutes` (integer, optional): Default: 15. Maximum: 15.
- `baseline_start_time_iso` / `baseline_end_time_iso` (string, optional): Required for `time` mode; non-overlapping and equal in duration to the target window.
- `minimum_cohort_size` (integer, optional): Default: 100. Minimum: 20.
- `minimum_value_support` (integer, optional): Default: 20. Minimum: 10.
- `limit` (integer, optional): Default: 10. Maximum: 10.
Requires the companion backend capability to be enabled.
get_trace_waterfall
- `trace_id` (string, required)
- `environment` (string, optional)
- `start_time_iso` / `end_time_iso` (string, optional)
- `lookback_minutes` (integer, optional): Default: 4320 (72 hours).
- `selected_span_id` (string, optional): Returns attributes, events, and links for that span only.
- `max_spans` (integer, optional): Default: 500. Maximum: 1000.
Returns an `investigation-evidence/v1` envelope; the waterfall is under `data`.
get_change_events
- `start_time_iso` / `end_time_iso` (string, optional)
- `lookback_minutes` (integer, optional): Default: 60.
- `service_name` (string, optional)
- `env` (string, optional)
- `event_name` (string, optional): Call without this first to get `available_event_names`.
get_alert_config
- `search_term` (string, optional): Free-text search across name, group, data source, tags.
- `rule_name` (string, optional)
- `severity` (string, optional)
- `rule_type` (string, optional): `static` or `anomaly`.
- `alert_group_name` / `alert_group_type` / `data_source_name` (string, optional)
- `tags` (array, optional): All must match (AND logic).
get_alerts
- `time_iso` (string, optional): Evaluation time in RFC3339.
- `window` (integer, optional): Lookback in seconds. Default: 900. Range: 60–86400.
- `lookback_minutes` (integer, optional): Range: 1–1440.
get_alert_rule_state
- `start_time` (integer, required): Unix epoch start of the range (inclusive).
- `end_time` (integer, required): Unix epoch end of the range (inclusive).
- `step` (integer, required): Resolution in seconds between samples. The number of samples `((end_time - start_time) / step + 1)` is capped at 100.
- `alert_group_id` (string, optional): Filter by alert group ID.
- `rule_name` (string, optional): Regex filter on rule name.
- `alert_group_name` (string, optional): Regex filter on alert group name.
- `label_filters` (string, optional): Comma-separated `key=value` label filters.
- `state` (string, optional): Filter by state (e.g. `firing`).
Returns a JSON map of `rule_id -> [{timestamp, is_firing}]`. A timestamp at which a rule is absent from the upstream response is reported as `is_firing=0` — this means "not observed as firing", not a confirmed normal state.
get_notification_channels
No parameters. Returns all configured notification channels (Slack, PagerDuty, email, webhooks, etc.).
did_you_mean
- `query` (string, required): The name to search for — partial, misspelled, or abbreviated.
- `type` (string, optional): Restrict to entity type: `service`, `environment`, `host`, `database`, `k8s_deployment`, `k8s_namespace`, `job`.
Returns up to 3 closest matches with similarity scores. Use this before any tool call where the entity name is uncertain. If a previous call returned empty results, try this before retrying.
get_service_profile
- `service_name` (string, required): Service to derive a telemetry profile for.
- `datasource` (string, optional): Datasource name. Omit for the default.
Returns a short investigation brief followed by the full profile as raw JSON: signal presence (`logs`/`traces`/`metrics` as `present`, `absent`, or `unknown`), language and runtime, deployment environments, log `signal_shape` (`log_format`, `severity_set`, `level_field`), and a recommended ingest fix where one applies. Derived upstream and cached with a ~15 minute TTL.
Call it before any service-scoped investigation so tool selection matches the service's actual telemetry — skip trace tools when `traces` is `absent`, and when `severity_set` is `none` or `partial` parse severity from `level_field` in the log body rather than using `severity_filters`. `metrics` is always `unknown` and `dependencies` is unpopulated in v1. When `logs` and `traces` are both `absent`, confirm the name with `did_you_mean` before concluding the service is unmonitored.
list_dashboards
No parameters. Returns all custom dashboards in the org as a JSON array with `id`, `name`, and metadata.
get_dashboard
- `id` (string, required): Dashboard UUID.
- `region` (string, optional): Region for panel query population. Defaults to configured datasource region.
create_dashboard
- `dashboard` (object, required): Dashboard definition with `name` and `panels[]`. Each panel requires `name`, `version`, `layout` (`x`, `y`, `w`, `h`), `visualization.type`, and `queries[]`.
- `metadata` (object, optional): Dashboard metadata — `_category` and `_type` fields (e.g. `{"_category":"custom","_type":"metrics"}`).
update_dashboard
- `id` (string, required): Dashboard UUID to update.
- `dashboard` (object, required): Full replacement dashboard body (same shape as create).
- `metadata` (object, optional): Replacement metadata. Readonly system dashboards return a 403 error.
delete_dashboard
- `id` (string, required): Dashboard UUID to delete. Readonly system dashboards cannot be deleted.
list_dashboard_snapshots
- `dashboard_id` (string, required): Dashboard UUID whose snapshots to list.
Returns metadata only (`id`, `name`, `expires_at`, etc.). Use `get_dashboard_snapshot` for frozen panel data.
get_dashboard_snapshot
- `id` (string, required): Snapshot UUID.
Returns the full frozen snapshot including `dashboard_definition`, `panel_data`, `time_range`, and `variables`.
delete_dashboard_snapshot
- `id` (string, required): Snapshot UUID to delete.
Testing
See TESTING.md for integration test setup and instructions.

Frequently asked questions
What is last9-mcp-server?
last9-mcp-server is Last9 MCP Server
How do I install last9-mcp-server?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is last9-mcp-server open source?
Yes — it is hosted on GitHub at https://github.com/last9/last9-mcp-server and has 45 stars.
Related MCP tools
Self-hosted MCP Gateway and Registry for AI agents Go-based implementation. Trusted by 600+ developers. Trusted by 600+ developers.
Expose your FastAPI endpoints as Model Context Protocol (MCP) tools, with Auth! Python-based implementation. Trusted by 11000+ developers.
Put an end to code hallucinations! GitMCP is a free, open-source, remote MCP server for any GitHub project TypeScript-based implementation.
CTTF: MCP integration between Cursor and Figma, allowing Cursor Agentic AI to communicate with Figma for reading designs and modifying them programmatically.
An MCP server that allows MCP clients like Claude Desktop or Cursor to perform actions in the Unity Editor C#-based implementation.
:robot: The free, Open Source alternative to OpenAI, Claude and others. Self-hosted and local-first. Drop-in replacement for OpenAI, running on consumer-gra...
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP