unifi-siem-lens
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@unifi-siem-lensCheck for pending security finding analyses and post a recommendation for the most critical one."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
UniFi SIEM Lens
Visualization dashboard and code-driven analysis layer for UniFi IDS/IPS security events — trend charts, anomaly/repeat-offender detection, and a "queue for Claude" handoff so a Claude Code session can turn a flagged finding into an actual recommendation, without this service needing any API key of its own.

Why this exists
This is the third of three companion projects for running an LLM against a UDM Pro:
unifi-mcp-server— exposes the UniFi Network API (firewall rules, networks, clients, traffic rules, port forwarding, monitoring) as MCP tools.unifi-siem-sink— listens for UniFi's SIEM/syslog export and stores IPS/IDS and Security-category events (the one thing the Network API doesn't expose) in SQLite, queryable over MCP.unifi-siem-lens(this project) — sits on top ofunifi-siem-sink's event store. Where the other two projects hand raw data to an LLM one query at a time, lens does the first pass itself: it runs scheduled, code-driven heuristics (new signature/source-IP detection, internal-source flagging, repeat-offender tracking, statistical anomaly detection) against the sink's event history, turns anything interesting into a finding, and renders trends and findings on a dashboard. When a finding is worth a closer look, one click queues it for analysis — a Claude Code session (running on your Claude subscription, no separate API key) checks in over MCP, reasons about the finding with the real events as context, and posts a recommendation back into the app. A second, purely code-driven layer goes further for the common case: a handful of rules (a trusted admin's own console login, WAN/operational noise, a blocked hit from a known reputation/blocklist IDS signature) auto-dismiss a finding the moment it's detected, with no Claude Code session involved at all — see Rule-based auto-triage below.
Run all three and an LLM gets full visibility into the network (via
unifi-mcp-server), full visibility into the security event stream (via
unifi-siem-sink), and a standing analyst that's already triaged the noise
before you ever open a chat (via unifi-siem-lens).
Related MCP server: kibana-mcp
Quick Start (Docker)
Requires unifi-siem-sink already running as a container — lens reads its
event database read-only via --volumes-from.
1. Create a .env file
SINK_DB_PATH=/data/events.db
LAN_CIDRS=10.0.0.0/8,192.168.0.0/16,172.16.0.0/12
MCP_SECRET=<choose-a-strong-secret>SINK_DB_PATH=/data/events.db matches the mount point unifi-siem-sink
uses internally — see step 2.
2. Run the container
docker run -d \
--name unifi-siem-lens \
--env-file .env \
-p 3002:3002 \
-v unifi-siem-lens-data:/lens-data \
--volumes-from unifi-siem-sink:ro \
ghcr.io/ianchesal/unifi-siem-lens:latest--volumes-from unifi-siem-sink:ro mounts the sink container's /data
volume (containing events.db) into this container read-only, at the same
path. If your sink container has a different name (check with
docker ps), or you're running it via docker compose under a different
project name, adjust unifi-siem-sink above to match.
3. Open the dashboard
http://<homelab-ip>:3002
4. Add to Claude Code for the analysis handoff
{
"mcpServers": {
"unifi-siem-lens": {
"type": "http",
"url": "http://<homelab-ip>:3002/mcp",
"headers": { "Authorization": "Bearer <your-MCP_SECRET>" }
}
}
}Then, in a Claude Code session with this configured, ask it to check for pending analyses. It'll fetch any findings you've queued from the dashboard, reason about them with the actual event context, and post recommendations back — which then show up next to the finding.
Dashboard & MCP tools
Surface | What it gives you |
Dashboard ( | Events-over-time, top signatures, top source IPs, and severity-distribution charts; a findings list with status tabs (Active/New/Acknowledged/Dismissed/Resolved/All), an "Analyze all" button, and per-finding Acknowledge/Dismiss/Analyze actions. Each answered finding shows whether its recommendation came "via Claude Code" or was "auto-triaged by rule". |
Admin ( | One-off maintenance actions — currently just the rule-triage backfill (see below). |
| Liveness + sink DB / schema-contract status. |
| Re-checks every existing |
| List analysis requests queued from the dashboard, awaiting a recommendation. |
| Full context for one request: the finding, its trigger/baseline history, and the relevant raw events. |
| Post a recommendation + risk level back for a pending request. |
Rule-based auto-triage
Most findings a live network throws off don't need an LLM at all: your own
console logins, the gateway's WAN-health blips, and routine reputation-list
scans that UniFi already auto-blocked. Rather than queuing every one of
these for a Claude Code session, lens checks each new new_signature/
new_source_ip finding against three rules the moment it's detected, and
auto-dismisses it — with a canned, code-generated recommendation, no
Claude Code session involved — if every event behind it is fully explained
by one of them:
Trusted admin login — a console login from an admin name in
TRUSTED_ADMIN_NAMES(see Environment Variables below; empty by default, so this rule never fires unconfigured).Operational noise — WAN/device-health telemetry, not a security signal.
Reputation/blocklist scan — a blocked hit from a known reputation-feed IDS signature family (
SAFE_SIGNATURE_PREFIXES).
A finding that isn't fully explained by a rule (mixed events, an unrecognized signature, an untrusted admin name) is left alone exactly as before — it still needs a manual "Analyze this" and a Claude Code session.
Because this only runs at the moment a finding is first created, findings
already sitting in the database before you configure TRUSTED_ADMIN_NAMES
(or before you upgrade to a lens version that has this feature) never get a
rule pass on their own. Visit /admin and click Run backfill to
sweep the auto-triage rules over your existing new/acknowledged
findings — safe to run repeatedly, it only ever touches findings still
sitting at those two statuses.
Claude Code skill: analyzing findings
If you're working in this repo with Claude Code, server/.claude/skills/analyzing-findings/
ships a skill (scoped to the server workspace, since it drives the MCP
analysis handoff) that automates the ad hoc "check for pending analyses"
workflow beyond what a plain request to Claude Code does on its own:
Drains the entire
get_pending_analysesqueue, not just one request.Enriches each finding by resolving source/destination IPs to hostnames via
unifi-mcp-server's client list, when that server is configured and reachable (falls back to IP-only otherwise).Cross-references findings in the same batch that share a root cause (same source IP or signature) so their recommendations note the connection instead of being analyzed in isolation.
After answering each finding, flags any that look like good candidates for a new rule-based auto-triage rule — a low-risk, fully-explained pattern that has recurred and isn't already covered by an existing rule — without writing the rule code itself; that stays a deliberate, reviewed change to
ruleTriage.ts.
Ask a Claude Code session working in this repo to "reanalyze findings" or
invoke it directly as /server:analyzing-findings.
Environment Variables
Variable | Required | Default | Description |
| yes | — | Path to |
| yes | — | Bearer token clients must send as |
| no |
| Port the dashboard/API/MCP server listens on |
| no |
| Bind address. Defaults to localhost-only — the dashboard/REST API have no authentication of their own (only |
| no |
| Lens's own SQLite store — findings, baselines, seen-entity tracking, analysis-request queue |
| no | (none) | Comma-separated CIDRs treated as internal/LAN for the internal-source heuristic, e.g. |
| no | (none) | Comma-separated admin display names (as they appear in UniFi's own audit log, e.g. |
| no |
| Comma-separated IDS/IPS signature prefixes (Emerging Threats' reputation/blocklist rule-family naming convention) that auto-dismiss a finding when every backing event is a blocked hit from one of these signature families. Prefixes are matched via SQL |
| no | (unset) | Optional |
| no | (unset) | Bearer token sent as |
| no |
|
|
Development (Running from a Repo Clone)
Setup
git clone https://github.com/ianchesal/unifi-siem-lens
cd unifi-siem-lens
npm install
cp server/.env.example server/.env
# edit server/.env: set SINK_DB_PATH to your unifi-siem-sink events.db, and MCP_SECRET to a strong secret
# (docker cp unifi-siem-sink-unifi-siem-sink-1:/data/events.db ./server/data/events.db)Run with Docker Compose
docker compose up -d --buildExposes 3002/tcp for the dashboard/API/MCP endpoint. Requires
unifi-siem-sink running as a container named unifi-siem-sink (adjust
docker-compose.yml's volumes_from if yours is named differently) —
lens's own state persists in the lens-data named volume.
Run locally
npm run devStarts the server (http://localhost:3002) and the Vite dev server
(http://localhost:5173, proxying /api to the server) together. The
server's /mcp endpoint is served directly on port 3002 and is not
proxied through Vite.
Note: If
npm run dev -w serverfails to boot (a known issue on Node 24.x/25.x — seeunifi-siem-sink's CLAUDE.md for details), usenpm run build -w server && npm run start -w serverinstead, alongsidenpm run dev -w webfor the frontend.
Production build
npm run build
npm startBuilds both packages and serves the built dashboard + API + MCP endpoint
from a single process on PORT (default 3002).
Tests
npm test # server test suite (vitest)
npm run lint # biome (server) + oxlint (web)Cutting a release
Releases are tag-driven. Pushing a v* tag to GitHub triggers
.github/workflows/release.yml, which:
Builds and pushes a Docker image to
ghcr.io/ianchesal/unifi-siem-lens(taggedlatest,{major}.{minor}, and{version})Creates a GitHub Release with auto-generated notes
Steps to release:
Ensure all changes are merged to
mainand CI is green.Decide the new version (follows semver:
MAJOR.MINOR.PATCH).Update
"version"inpackage.json(root) to the new version.Commit:
git commit -m "chore: release v{version}" package.jsonTag:
git tag v{version}Push both:
git push origin main && git push origin v{version}
The release workflow fires automatically on the tag push. No manual Docker build or GitHub Release creation needed.
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Enable secure connectivity between Sentry issues and debugging data, and LLM clients, using a Model Context Protocol (MCP) server.
A paid remote MCP for AI SDK data query MCP, built to return verdicts, receipts, usage logs, and aud
A paid remote MCP for AI SDK eval dashboard, built to return verdicts, receipts, usage logs, and aud
Track agent ROI and enrich companies via MCP. Remote, OAuth 2.1, no install or keys.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides AI assistants with access to UniFi Network and Protect infrastructure for managing devices, monitoring clients, analyzing network health, viewing camera snapshots, and getting optimization recommendations across multiple UniFi controllers.2
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage Kibana security alerts, rules, and exception lists via the Model Context Protocol.12MIT
- AlicenseNot gradedqualityCmaintenanceEnables MCP-capable clients to interact with UniFi Site Manager and UniFi Dream Machine telemetry, providing tools for client details, ISP metrics, and more.4MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI-powered security investigation and threat analysis by connecting MCP-compatible clients to Uptycs Juno.Apache 2.0
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ianchesal/unifi-siem-lens'
If you have feedback or need assistance with the MCP directory API, please join our Discord server