# LabMCP A collection of Model Context Protocol (MCP) servers written in Go. ## MCP Servers ### Nixpkgs Search (`nixpkgs-search`) - Primary Combined search for NixOS options and Nix packages from nixpkgs. Provides two separate MCP servers: - **Options server**: Search NixOS configuration options (`nixpkgs-search options serve`) - **Packages server**: Search Nix packages (`nixpkgs-search packages serve`) Both servers share the same database, allowing you to index once and serve both. ### Home Manager Options (`hm-options`) Search and query Home Manager configuration options across multiple home-manager revisions. Designed to help Claude (and other MCP clients) answer questions about Home Manager configuration. ### Lab Monitoring (`lab-monitoring`) Query Prometheus metrics, Alertmanager alerts, and Loki logs from your monitoring stack. Unlike other servers, this queries live HTTP APIs — no database or indexing needed. - List and inspect alerts from Alertmanager - Execute PromQL queries against Prometheus - Search metric names with metadata - View scrape target health - Manage alert silences - Query logs via LogQL (when Loki is configured) ### NixOS Options (`nixos-options`) - Legacy Search and query NixOS configuration options. **Note**: Prefer using `nixpkgs-search` instead, which includes this functionality plus package search. ### Shared Features (nixpkgs-search, hm-options, nixos-options) - Full-text search across option/package names and descriptions - Query specific options/packages with full metadata - Index multiple revisions (by git hash or channel name) - Fetch module source files - Support for PostgreSQL and SQLite backends ## Installation ### Using Nix Flakes ```bash # Build the packages nix build git+https://git.t-juice.club/torjus/labmcp#nixpkgs-search nix build git+https://git.t-juice.club/torjus/labmcp#hm-options nix build git+https://git.t-juice.club/torjus/labmcp#lab-monitoring # Or run directly nix run git+https://git.t-juice.club/torjus/labmcp#nixpkgs-search -- --help nix run git+https://git.t-juice.club/torjus/labmcp#hm-options -- --help nix run git+https://git.t-juice.club/torjus/labmcp#lab-monitoring -- --help ``` ### From Source ```bash go install git.t-juice.club/torjus/labmcp/cmd/nixpkgs-search@latest go install git.t-juice.club/torjus/labmcp/cmd/hm-options@latest go install git.t-juice.club/torjus/labmcp/cmd/lab-monitoring@latest ``` ## Usage ### As MCP Server (STDIO) Configure in your MCP client (e.g., Claude Desktop): ```json { "mcpServers": { "nixpkgs-options": { "command": "nixpkgs-search", "args": ["options", "serve"], "env": { "NIXPKGS_SEARCH_DATABASE": "sqlite:///path/to/nixpkgs-search.db" } }, "nixpkgs-packages": { "command": "nixpkgs-search", "args": ["packages", "serve"], "env": { "NIXPKGS_SEARCH_DATABASE": "sqlite:///path/to/nixpkgs-search.db" } }, "hm-options": { "command": "hm-options", "args": ["serve"], "env": { "HM_OPTIONS_DATABASE": "sqlite:///path/to/hm-options.db" } }, "lab-monitoring": { "command": "lab-monitoring", "args": ["serve"], "env": { "PROMETHEUS_URL": "http://prometheus.example.com:9090", "ALERTMANAGER_URL": "http://alertmanager.example.com:9093", "LOKI_URL": "http://loki.example.com:3100" } } } } ``` Alternatively, if you have Nix installed, you can use the flake directly without installing the packages: ```json { "mcpServers": { "nixpkgs-options": { "command": "nix", "args": ["run", "git+https://git.t-juice.club/torjus/labmcp#nixpkgs-search", "--", "options", "serve"], "env": { "NIXPKGS_SEARCH_DATABASE": "sqlite:///path/to/nixpkgs-search.db" } }, "nixpkgs-packages": { "command": "nix", "args": ["run", "git+https://git.t-juice.club/torjus/labmcp#nixpkgs-search", "--", "packages", "serve"], "env": { "NIXPKGS_SEARCH_DATABASE": "sqlite:///path/to/nixpkgs-search.db" } }, "hm-options": { "command": "nix", "args": ["run", "git+https://git.t-juice.club/torjus/labmcp#hm-options", "--", "serve"], "env": { "HM_OPTIONS_DATABASE": "sqlite:///path/to/hm-options.db" } }, "lab-monitoring": { "command": "nix", "args": ["run", "git+https://git.t-juice.club/torjus/labmcp#lab-monitoring", "--", "serve"], "env": { "PROMETHEUS_URL": "http://prometheus.example.com:9090", "ALERTMANAGER_URL": "http://alertmanager.example.com:9093", "LOKI_URL": "http://loki.example.com:3100" } } } } ``` ### As MCP Server (HTTP) All servers can run over HTTP with Server-Sent Events (SSE) for web-based MCP clients: ```bash # Start HTTP server on default address nixpkgs-search options serve --transport http nixpkgs-search packages serve --transport http hm-options serve --transport http lab-monitoring serve --transport http # Custom address and CORS configuration nixpkgs-search options serve --transport http \ --http-address 0.0.0.0:8080 \ --allowed-origins https://example.com # With TLS nixpkgs-search options serve --transport http \ --tls-cert /path/to/cert.pem \ --tls-key /path/to/key.pem ``` HTTP transport endpoints: - `POST /mcp` - JSON-RPC requests (returns `Mcp-Session-Id` header on initialize) - `GET /mcp` - SSE stream for server notifications (requires `Mcp-Session-Id` header) - `DELETE /mcp` - Terminate session ### CLI Examples **Index a revision (nixpkgs-search):** ```bash # Index both options and packages nixpkgs-search index nixos-unstable # Index by git hash nixpkgs-search index e6eae2ee2110f3d31110d5c222cd395303343b08 # Index options only (faster, skip packages) nixpkgs-search index --no-packages nixos-unstable # Index packages only (skip options) nixpkgs-search index --no-options nixos-unstable # Index without file contents (faster, disables get_file tool) nixpkgs-search index --no-files nixos-unstable ``` **Index a revision (hm-options):** ```bash # Index by channel name hm-options index hm-unstable # Index without file contents hm-options index --no-files release-24.11 ``` **List indexed revisions:** ```bash nixpkgs-search list hm-options list ``` **Search for options:** ```bash # NixOS options via nixpkgs-search nixpkgs-search options search nginx nixpkgs-search options search -n 10 postgresql # Home Manager options hm-options search git hm-options search -n 10 neovim ``` **Search for packages:** ```bash nixpkgs-search packages search firefox nixpkgs-search packages search -n 10 python # Filter by status nixpkgs-search packages search --unfree nvidia nixpkgs-search packages search --broken deprecated-package ``` **Get option/package details:** ```bash nixpkgs-search options get services.nginx.enable nixpkgs-search packages get firefox hm-options get programs.git.enable ``` **Lab Monitoring CLI:** ```bash # List alerts lab-monitoring alerts lab-monitoring alerts --state active lab-monitoring alerts --severity critical # Execute PromQL queries lab-monitoring query 'up' lab-monitoring query 'rate(http_requests_total[5m])' # List scrape targets lab-monitoring targets # Search metrics lab-monitoring metrics node lab-monitoring metrics -n 20 cpu # Query logs from Loki (requires LOKI_URL) lab-monitoring logs '{job="varlogs"}' lab-monitoring logs '{job="nginx"} |= "error"' --start 2h --limit 50 lab-monitoring logs '{job="systemd"}' --direction forward # List Loki labels lab-monitoring labels lab-monitoring labels --values job ``` **Delete an indexed revision:** ```bash nixpkgs-search delete nixos-23.11 hm-options delete release-23.11 ``` ## Configuration ### Environment Variables | Variable | Description | Default | |----------|-------------|---------| | `NIXPKGS_SEARCH_DATABASE` | Database connection string for nixpkgs-search | `sqlite://nixpkgs-search.db` | | `HM_OPTIONS_DATABASE` | Database connection string for hm-options | `sqlite://hm-options.db` | | `NIXOS_OPTIONS_DATABASE` | Database connection string for nixos-options (legacy) | `sqlite://nixos-options.db` | | `PROMETHEUS_URL` | Prometheus base URL for lab-monitoring | `http://localhost:9090` | | `ALERTMANAGER_URL` | Alertmanager base URL for lab-monitoring | `http://localhost:9093` | | `LOKI_URL` | Loki base URL for lab-monitoring (optional, enables log tools) | *(none)* | ### Database Connection Strings **SQLite:** ```bash export NIXPKGS_SEARCH_DATABASE="sqlite:///path/to/database.db" export NIXPKGS_SEARCH_DATABASE="sqlite://:memory:" # In-memory ``` **PostgreSQL:** ```bash export NIXPKGS_SEARCH_DATABASE="postgres://user:pass@localhost/nixpkgs_search?sslmode=disable" ``` ### Command-Line Flags The database can also be specified via the `-d` or `--database` flag: ```bash nixpkgs-search -d "postgres://localhost/nixpkgs" options serve nixpkgs-search -d "sqlite://my.db" index nixos-unstable hm-options -d "sqlite://my.db" index hm-unstable ``` ## MCP Tools ### Options Servers (nixpkgs-search options, hm-options) | Tool | Description | |------|-------------| | `search_options` | Search for options by name or description | | `get_option` | Get full details for a specific option | | `get_file` | Fetch source file contents from the repository | | `index_revision` | Index a revision | | `list_revisions` | List all indexed revisions | | `delete_revision` | Delete an indexed revision | ### Packages Server (nixpkgs-search packages) | Tool | Description | |------|-------------| | `search_packages` | Search for packages by name or description | | `get_package` | Get full details for a specific package | | `get_file` | Fetch source file contents from nixpkgs | | `index_revision` | Index a revision | | `list_revisions` | List all indexed revisions | | `delete_revision` | Delete an indexed revision | ### Monitoring Server (lab-monitoring) | Tool | Description | |------|-------------| | `list_alerts` | List alerts with optional filters (state, severity, receiver) | | `get_alert` | Get full details for a specific alert by fingerprint | | `search_metrics` | Search metric names with substring filter, enriched with metadata | | `get_metric_metadata` | Get type, help text, and unit for a specific metric | | `query` | Execute an instant PromQL query | | `list_targets` | List scrape targets with health status | | `list_silences` | List active/pending alert silences | | `create_silence` | Create a new alert silence (requires `--enable-silences` flag) | | `query_logs` | Execute a LogQL range query against Loki (requires `LOKI_URL`) | | `list_labels` | List available label names from Loki (requires `LOKI_URL`) | | `list_label_values` | List values for a specific label from Loki (requires `LOKI_URL`) | ## NixOS Modules NixOS modules are provided for running the MCP servers as systemd services. ### nixpkgs-search (Recommended) The `nixpkgs-search` module runs two separate MCP servers (options and packages) that share a database: ```nix { inputs.labmcp.url = "git+https://git.t-juice.club/torjus/labmcp"; outputs = { self, nixpkgs, labmcp }: { nixosConfigurations.myhost = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ labmcp.nixosModules.nixpkgs-search-mcp { services.nixpkgs-search = { enable = true; indexOnStart = [ "nixos-unstable" ]; # Both options and packages servers are enabled by default }; } ]; }; }; } ``` **Options-only configuration:** ```nix { services.nixpkgs-search = { enable = true; indexOnStart = [ "nixos-unstable" ]; indexFlags = [ "--no-packages" ]; # Faster indexing packages.enable = false; # Don't run packages server }; } ``` ### hm-options ```nix { inputs.labmcp.url = "git+https://git.t-juice.club/torjus/labmcp"; outputs = { self, nixpkgs, labmcp }: { nixosConfigurations.myhost = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ labmcp.nixosModules.hm-options-mcp { services.hm-options-mcp = { enable = true; indexOnStart = [ "hm-unstable" ]; }; } ]; }; }; } ``` ### lab-monitoring ```nix { inputs.labmcp.url = "git+https://git.t-juice.club/torjus/labmcp"; outputs = { self, nixpkgs, labmcp }: { nixosConfigurations.myhost = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ labmcp.nixosModules.lab-monitoring-mcp { services.lab-monitoring = { enable = true; prometheusUrl = "http://prometheus.example.com:9090"; alertmanagerUrl = "http://alertmanager.example.com:9093"; enableSilences = true; # Optional: enable create_silence tool }; } ]; }; }; } ``` ### nixos-options (Legacy) ```nix { inputs.labmcp.url = "git+https://git.t-juice.club/torjus/labmcp"; outputs = { self, nixpkgs, labmcp }: { nixosConfigurations.myhost = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ labmcp.nixosModules.nixos-options-mcp { services.nixos-options-mcp = { enable = true; indexOnStart = [ "nixos-unstable" ]; }; } ]; }; }; } ``` ### Module Options #### nixpkgs-search | Option | Type | Default | Description | |--------|------|---------|-------------| | `enable` | bool | `false` | Enable the service | | `package` | package | from flake | Package to use | | `database.type` | enum | `"sqlite"` | `"sqlite"` or `"postgres"` | | `database.name` | string | `"nixpkgs-search.db"` | SQLite database filename | | `database.connectionString` | string | `""` | PostgreSQL connection URL (stored in Nix store) | | `database.connectionStringFile` | path | `null` | Path to file with PostgreSQL connection URL (recommended for secrets) | | `indexOnStart` | list of string | `[]` | Revisions to index on service start | | `indexFlags` | list of string | `[]` | Additional flags for indexing (e.g., `["--no-packages"]`) | | `user` | string | `"nixpkgs-search"` | User to run the service as | | `group` | string | `"nixpkgs-search"` | Group to run the service as | | `dataDir` | path | `/var/lib/nixpkgs-search` | Directory for data storage | | `options.enable` | bool | `true` | Enable the options MCP server | | `options.http.address` | string | `"127.0.0.1:8082"` | HTTP listen address for options server | | `options.openFirewall` | bool | `false` | Open firewall for options HTTP port | | `packages.enable` | bool | `true` | Enable the packages MCP server | | `packages.http.address` | string | `"127.0.0.1:8083"` | HTTP listen address for packages server | | `packages.openFirewall` | bool | `false` | Open firewall for packages HTTP port | Both `options.http` and `packages.http` also support: - `endpoint` (default: `"/mcp"`) - `allowedOrigins` (default: `[]`) - `sessionTTL` (default: `"30m"`) - `tls.enable`, `tls.certFile`, `tls.keyFile` #### lab-monitoring | Option | Type | Default | Description | |--------|------|---------|-------------| | `enable` | bool | `false` | Enable the service | | `package` | package | from flake | Package to use | | `prometheusUrl` | string | `"http://localhost:9090"` | Prometheus base URL | | `alertmanagerUrl` | string | `"http://localhost:9093"` | Alertmanager base URL | | `lokiUrl` | nullOr string | `null` | Loki base URL (enables log query tools when set) | | `enableSilences` | bool | `false` | Enable the create_silence tool (write operation) | | `http.address` | string | `"127.0.0.1:8084"` | HTTP listen address | | `http.endpoint` | string | `"/mcp"` | HTTP endpoint path | | `http.allowedOrigins` | list of string | `[]` | Allowed CORS origins (empty = localhost only) | | `http.sessionTTL` | string | `"30m"` | Session timeout (Go duration format) | | `http.tls.enable` | bool | `false` | Enable TLS | | `http.tls.certFile` | path | `null` | TLS certificate file | | `http.tls.keyFile` | path | `null` | TLS private key file | | `openFirewall` | bool | `false` | Open firewall for HTTP port | The lab-monitoring module uses `DynamicUser=true`, so no separate user/group configuration is needed. #### hm-options-mcp / nixos-options-mcp (Legacy) | Option | Type | Default | Description | |--------|------|---------|-------------| | `enable` | bool | `false` | Enable the service | | `package` | package | from flake | Package to use | | `database.type` | enum | `"sqlite"` | `"sqlite"` or `"postgres"` | | `database.name` | string | `"*.db"` | SQLite database filename | | `database.connectionString` | string | `""` | PostgreSQL connection URL (stored in Nix store) | | `database.connectionStringFile` | path | `null` | Path to file with PostgreSQL connection URL (recommended for secrets) | | `indexOnStart` | list of string | `[]` | Revisions to index on service start | | `user` | string | `"*-mcp"` | User to run the service as | | `group` | string | `"*-mcp"` | Group to run the service as | | `dataDir` | path | `/var/lib/*-mcp` | Directory for data storage | | `http.address` | string | `"127.0.0.1:808x"` | HTTP listen address | | `http.endpoint` | string | `"/mcp"` | HTTP endpoint path | | `http.allowedOrigins` | list of string | `[]` | Allowed CORS origins (empty = localhost only) | | `http.sessionTTL` | string | `"30m"` | Session timeout (Go duration format) | | `http.tls.enable` | bool | `false` | Enable TLS | | `http.tls.certFile` | path | `null` | TLS certificate file | | `http.tls.keyFile` | path | `null` | TLS private key file | | `openFirewall` | bool | `false` | Open firewall for HTTP port | ### PostgreSQL Example Using `connectionStringFile` (recommended for production with sensitive credentials): ```nix { services.nixpkgs-search = { enable = true; database = { type = "postgres"; # File contains: postgres://user:secret@localhost/nixpkgs_search?sslmode=disable connectionStringFile = "/run/secrets/nixpkgs-search-db"; }; indexOnStart = [ "nixos-unstable" ]; }; # Example with agenix or sops-nix for secret management # age.secrets.nixpkgs-search-db.file = ./secrets/nixpkgs-search-db.age; } ``` ## Development ```bash # Enter development shell nix develop # Run tests go test ./... # Run benchmarks go test -bench=. ./internal/database/... # Build go build ./cmd/nixpkgs-search go build ./cmd/hm-options go build ./cmd/lab-monitoring ``` ## License MIT