loki-tail-mcp
An MCP server for Grafana Loki, designed around how LLMs actually query logs: compact output, hard row caps, and a fuzzy container-name rescue that turns the classic empty-result-because-wrong-name failure into an auto-corrected retry or an actionable suggestion list. Built on the Python MCP SDK (FastMCP); runs as a local stdio server or a containerized Streamable HTTP service with bearer auth.
Tools
| Tool | Notes |
|---|---|
loki_tail_container |
"What is service X saying?" — the primary tool. Accepts approximate names: service vocabulary (vpn, proxy), bare names (sonarr), typos. On zero results it distinguishes valid-but-quiet from unknown name, auto-substitutes a unique fuzzy match (flagged in the output), or suggests candidates. |
loki_query_range |
Raw LogQL range query — multi-container correlation ({container=~"a|b"} |= "...") and metric queries (count_over_time(...)). |
loki_query_instant |
Instant query at a point in time (metric queries). |
loki_list_containers |
Durable container names (ephemeral CI/batch names hidden). |
loki_list_labels / loki_list_label_values |
Raw label discovery. |
loki_patterns |
Log pattern mining — thousands of lines → ranked recurring templates with counts. Requires the server-side pattern ingester (pattern_ingester.enabled: true). |
loki_log_volume |
Rank containers by log bytes over a window — "which service suddenly got noisy". |
loki_detected_fields |
Fields Loki can auto-extract from a stream (name/type/cardinality/parser) — discover | logfmt | status>=500 opportunities before writing LogQL. |
The name-resolution design
Matching always runs against live label values, never a hardcoded
list, so it survives renames. Resolution tries, in order: exact match →
alias vocabulary → substring both ways → typo distance (difflib). A
unique candidate is tailed automatically and flagged; multiple candidates
become a ranked suggestion list. Auto-generated container names
(docker/podman adjective_noun, hex-suffixed batch workers) are filtered
out of discovery and suggestions but stay queryable via raw LogQL.
The built-in alias vocabulary covers the common self-hosted stack
(vpn→gluetun, proxy→traefik, movies→radarr, …). Entries whose
targets don't exist in your fleet are inert; extend with your own via
LOKI_ALIASES.
Quick start (stdio)
// e.g. Claude Desktop claude_desktop_config.json / Claude Code .mcp.json
{
"mcpServers": {
"loki": {
"command": "uv",
"args": ["run", "--project", "/path/to/loki-tail-mcp", "loki-tail-mcp", "--stdio"],
"env": { "LOKI_URL": "http://your-loki-host:3100" }
}
}
}
stdio mode has no network surface and skips bearer auth — the client owns the process.
HTTP mode (container)
The bundled Containerfile builds a Streamable HTTP server at /mcp
(stateless — restarts never strand client sessions). HTTP mode refuses
to start without MCP_BEARER_TOKEN; clients authenticate with
Authorization: Bearer <token>.
podman build -t loki-tail-mcp . # or: docker build -t loki-tail-mcp .
podman run -d --name loki-tail-mcp -p 8325:8325 \
-e LOKI_URL=http://your-loki-host:3100 \
-e MCP_BEARER_TOKEN=some-long-random-token \
loki-tail-mcp
loki_tail_mcp.healthcheck does a full HTTP round-trip to /mcp (the 401
counts as alive); wire it to your container healthcheck. Terminate TLS at
a reverse proxy — the server itself speaks plain HTTP.
Configuration
| Env var | Default | Purpose |
|---|---|---|
LOKI_URL |
http://loki:3100 |
Loki base URL. |
LOKI_TENANT_ID |
(empty) | Sent as X-Scope-OrgID for multi-tenant Loki. |
LOKI_BASIC_AUTH |
(empty) | user:password for a basic-auth-fronted Loki (reverse proxy, Grafana Cloud). |
LOKI_TIMEOUT |
30 |
Upstream request timeout (s). |
LOKI_DEFAULT_LIMIT / LOKI_MAX_LIMIT |
100 / 1000 |
Row caps — Loki will happily return millions of rows; an MCP client will happily feed them to an LLM. Neither is what you want. |
LOKI_ALIASES |
(empty) | Extra vocabulary merged over the built-ins: term=fragment or term=frag|frag2, comma-separated (e.g. cache=redis|valkey,db=postgres). |
LOKI_EPHEMERAL_PATTERNS |
(built-ins) | Comma-separated regexes marking names as ephemeral; replaces the defaults when set. |
PORT |
8325 |
HTTP listen port. |
MCP_BEARER_TOKEN |
(empty) | Required in HTTP mode; server refuses to start without it. Not used in --stdio mode. |
Testing
# Full suite — mocked HTTP + pure resolution logic, no Loki needed
uv run --extra test pytest tests/ -v
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loki_tail_mcp-0.1.0.tar.gz.
File metadata
- Download URL: loki_tail_mcp-0.1.0.tar.gz
- Upload date:
- Size: 55.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a94c8717cab14ff298becb58b83913efadca113066469ed1c659968f8d06699
|
|
| MD5 |
33f87c8ba74ceeb9129243fed3b898b6
|
|
| BLAKE2b-256 |
67eba77581133868bdc93495f63754036184244b8e684854e8d61e2c1db9a854
|
File details
Details for the file loki_tail_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: loki_tail_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51c64b06754c46649dccc15bee3dffe53ede44a05e8d9692801455ef1b7be4c4
|
|
| MD5 |
007a0dd0346e550e2fd357f01d8faef5
|
|
| BLAKE2b-256 |
7049d7ff3e7df3714f70558e512bb2bcd8f7dac12b6903148edbe5455d920bef
|