A local AI agent for inspecting InfluxDB telemetry and creating or modifying Grafana dashboards using the Model Context Protocol (MCP).
The project uses a locally hosted LLM through llama.cpp, an MCP server written in Python, InfluxDB 2.x, and Grafana.
Local machine / server
┌──────────────────────────────────────────────────────────────┐
│ │
│ llama.cpp │
│ llama-server │
│ Qwen3 │
│ OpenAI-compatible API :8080 │
│ ▲ │
│ │ │
│ │ /v1/chat/completions │
│ │ │
│ agent.py │
│ │ │
│ │ MCP over STDIO │
│ ▼ │
│ server.py │
│ │ │
└────────────┼─────────────────────────────────────────────────┘
│
├──────────────► InfluxDB 2.x
│ :8086
│
└──────────────► Grafana
:3000
agent.py is the LLM agent loop.
server.py is the MCP server exposing controlled InfluxDB and Grafana operations to the agent.
llama-server provides the local OpenAI-compatible LLM API.
The LLM does not receive InfluxDB or Grafana credentials. Authentication and API access remain inside the MCP server.
The agent can:
- Discover InfluxDB measurements
- Discover fields belonging to a measurement
- Discover tag keys
- Discover tag values
- Inspect recent measurement data
- Discover Grafana datasources
- Retrieve existing Grafana dashboards
- Create Grafana dashboards
- Update existing dashboards
- Add InfluxDB-backed Grafana time-series panels
- Automatically back up dashboards before updates
- Protect dashboard updates using Grafana version checking
Example interaction:
> What GPU measurements and fields are available? Use the tools to inspect InfluxDB
[tool] influx_list_measurements({})
[tool] influx_list_fields({'measurement': 'nvidia_smi'})
The available GPU measurement is nvidia_smi...
The goal is to support requests such as:
Add GPU temperature and GPU utilization panels to my Grafana dashboard.
The agent can inspect the actual InfluxDB schema rather than relying on guessed measurement or field names.
Tested on Ubuntu with Python 3.12.
A modern Debian/Ubuntu installation should work with minor adjustments.
Required system packages:
sudo apt update
sudo apt install -y python3 python3-venv python3-pip git curl jqPython 3.12 or newer is recommended.
Check:
python3 --versionInfluxDB 2.x is required.
The MCP server uses the InfluxDB v2 HTTP API and Flux queries.
You need:
- InfluxDB URL
- Organization
- Bucket
- API token with appropriate read permissions
Example:
INFLUX_URL=http://192.168.1.194:8086
INFLUX_ORG=home
INFLUX_BUCKET=homeassistant
Do not store a real token in the repository.
Grafana must be reachable from the machine running server.py.
You need:
- Grafana URL
- Grafana service account token/API token
The token requires sufficient permissions for the operations you intend the agent to perform.
For read-only operation, dashboard and datasource read permissions are sufficient.
For dashboard creation/modification, the Grafana identity must also have permission to create and edit dashboards.
Example:
GRAFANA_URL=http://192.168.1.194:3000
A working llama.cpp installation with llama-server is required for the local LLM agent.
Repository:
https://github.com/ggml-org/llama.cpp
Build llama.cpp according to the upstream instructions for your hardware.
GPU acceleration is strongly recommended.
Clone the repository:
git clone <repository-url>
cd dashboard-agentCreate a Python virtual environment:
python3 -m venv .venvActivate it:
source .venv/bin/activateUpgrade pip:
python -m pip install --upgrade pipInstall the Python dependencies:
pip install -r requirements.txtVerify MCP:
python -c 'import importlib.metadata; print(importlib.metadata.version("mcp"))'Verify the source files compile:
python -m py_compile server.py agent.pyCopy the example environment file:
cp .env.example .envEdit it:
nano .envConfiguration format:
INFLUX_URL=http://localhost:8086
INFLUX_ORG=home
INFLUX_BUCKET=my_bucket
INFLUX_TOKEN=replace-me
GRAFANA_URL=http://localhost:3000
GRAFANA_TOKEN=replace-meNever commit .env.
The included .gitignore excludes:
.env
.venv/
__pycache__/
*.pyc
backups/
node_modules/
Check InfluxDB health:
curl -sS "$INFLUX_URL/health" | jqA healthy InfluxDB server should report:
{
"status": "pass"
}Check Grafana:
curl -sS "$GRAFANA_URL/api/health" | jqTest authentication:
curl -sS -o /dev/null -w 'Grafana API: HTTP %{http_code}\n' \
-H "Authorization: Bearer $GRAFANA_TOKEN" \
"$GRAFANA_URL/api/user"Expected:
Grafana API: HTTP 200
The MCP server is implemented in:
server.py
It communicates with InfluxDB and Grafana and exposes controlled tools to MCP clients.
Lists measurements in the configured InfluxDB bucket.
Lists field names belonging to a measurement.
Example conceptually:
influx_list_fields(
measurement="nvidia_smi"
)
Lists tag keys associated with a measurement.
Lists known values for a specific tag.
Example:
measurement = nvidia_smi
tag = host
Returns a small number of recent raw samples.
This tool is intended for inspecting actual values, not schema discovery.
Prefer:
influx_list_fields
influx_list_tag_keys
influx_list_tag_values
when discovering the schema.
Lists Grafana datasources and their UIDs.
This allows the agent to discover the InfluxDB datasource rather than requiring the datasource UID to be supplied manually.
Retrieves an existing Grafana dashboard by UID.
Creates a new dashboard.
Updates an existing dashboard.
Updates use optimistic version checking.
The caller supplies the dashboard version it previously read. If the version in Grafana has changed, the operation fails instead of silently overwriting somebody else's changes.
A JSON backup is also created before an update.
Adds an InfluxDB-backed time-series panel to an existing dashboard.
The tool handles:
- Dashboard retrieval
- Version validation
- Backup
- Panel ID allocation
- Panel placement
- Flux query generation
- Grafana dashboard update
This higher-level interface is preferred over having the LLM construct an entire Grafana dashboard document.
Before modifying an existing dashboard, the MCP server creates a JSON backup.
Default directory:
/opt/dashboard-agent/backups
The backup directory is excluded from Git.
Example filename:
a7pv6t-v1-20260930T180000Z.json
A different location can be configured with:
GRAFANA_BACKUP_DIR=/path/to/backupsMCP Inspector is useful during development but is not required when running the actual agent.
Run:
mcp dev server.pyThe Inspector requires Node.js/npm.
Recent versions of MCP Inspector require a recent Node.js version. Node 22+ is recommended.
When running on a remote server over SSH, create an SSH tunnel from your workstation:
ssh -L 6274:127.0.0.1:6274 user@serverThen open the Inspector URL printed by mcp dev in the local browser.
The Inspector launches server.py as an MCP STDIO subprocess when the connection is established.
For normal agent operation, MCP Inspector is not required.
The current tested model is Qwen3 using a GGUF quantization.
Example:
./build/bin/llama-server -hf Qwen/Qwen3-8B-GGUF:Q4_K_M -ngl 20 -c 8192 --alias qwen3-8b --reasoning off --jinja --host 0.0.0.0 --port 8080Important options:
-hf
Loads the model from Hugging Face.
-ngl
Controls GPU layer offloading. The appropriate value depends on GPU VRAM.
-c 8192
Sets the model context size.
--alias qwen3-8b
Defines the model name exposed through the API.
--jinja
Enables Jinja chat templates required for structured tool/function calling.
--reasoning off
Disables Qwen3 reasoning output.
For this agent workload, disabling reasoning can significantly reduce latency because many operations involve straightforward tool selection rather than complex reasoning.
Check the API:
curl -s http://127.0.0.1:8080/v1/models | jqStart the local LLM server first.
Then activate the project environment:
cd /opt/dashboard-agent
source .venv/bin/activateRun:
python agent.pyExpected startup:
Dashboard Agent
Model: qwen3-8b
MCP tools: 10
Type 'quit' to exit.
>
Example:
> What GPU measurements and fields are available? Use the tools to inspect InfluxDB
The agent may perform:
[tool] influx_list_measurements({})
[tool] influx_list_fields({'measurement': 'nvidia_smi'})
and then return the discovered fields.
Exit with:
quit
The execution flow is:
User
│
▼
agent.py
│
├──── OpenAI-compatible HTTP API ────► llama-server
│ │
│ ▼
│ Qwen3
│ │
│ structured tool request
│◄────────────────────────────────────────┘
│
│ MCP
▼
server.py
│
├────────► InfluxDB
│
└────────► Grafana
The MCP tool result is returned to the model, which can then choose another tool or provide the final response.
agent.py starts server.py itself using MCP STDIO. You do not need to run server.py or mcp dev separately during normal agent operation.
The following file must remain private:
.env
Never place real InfluxDB or Grafana tokens in:
README.md.env.example- source code
- Git commits
- issue reports
Use dedicated credentials for the dashboard agent.
Do not reuse InfluxDB administrative tokens when a read-only token is sufficient.
For Grafana, grant only the dashboard permissions the agent requires.
The LLM does not need direct credentials for Grafana or InfluxDB.
Credentials remain in server.py's environment.
The model only receives access to the explicitly exposed MCP tools.
This is intentional: prefer narrow operations such as:
grafana_add_timeseries_panel
over giving the model arbitrary authenticated HTTP access to Grafana.
Dashboard writes use version checking to reduce the chance of overwriting concurrent changes.
Existing dashboards are backed up before updates.
For initial development, use a dedicated test dashboard before allowing the agent to modify important production dashboards.
Local tool-calling models can generate substantial amounts of context.
Avoid returning unnecessarily large tool responses.
Schema discovery should use the dedicated tools rather than raw measurement inspection.
For example, prefer:
influx_list_fields("nvidia_smi")
instead of retrieving hundreds of raw telemetry samples.
The current development environment uses an 8192-token context window.
Small local models may be more effective when MCP tools are:
- Narrow
- High-level
- Well-described
- Predictable
- Limited in output size
The project intentionally moves Grafana-specific implementation details into Python rather than requiring the LLM to generate large dashboard JSON documents.
The following functionality has been tested end-to-end:
- InfluxDB connectivity
- Grafana connectivity
- MCP server startup
- MCP Inspector connectivity
- InfluxDB measurement discovery
- InfluxDB field discovery
- InfluxDB tag discovery
- Grafana datasource discovery
- Grafana dashboard retrieval
- Grafana dashboard creation
- Grafana dashboard modification
- Automatic dashboard backup
- Version-protected dashboard updates
- Creation of a working InfluxDB-backed Grafana time-series panel
- Qwen3 structured function calling through llama.cpp
- Autonomous MCP tool selection from the local LLM agent
This project is currently experimental.
Recommended next improvements include:
- Hard limits on MCP tool-result size
- More compact measurement search tools
- Grafana dashboard search/list tools
- Additional panel types
- Better datasource selection
- Configurable LLM model/base URL
- Improved error handling
- Automated dependency installation
- Tests
- systemd service definitions
- Optional web/chat interface
No license has been selected yet.