A clean, modern, homelab-first IP address manager — faster than phpIPAM, simpler than Netbox, and built from day one to be driven by AI assistants through MCP.
- Web UI — dark-mode-first React SPA: section/subnet sidebar tree, host tables, slide-over editing, one-click "allocate next free IP"
- REST API — FastAPI with API-key auth, OpenAPI docs at
/api/v1/docs - MCP server — 16 hand-curated tools at
/mcp(Streamable HTTP) so your AI assistant can query and update your IPAM - Custom device types — define your own types with icons in Settings (seeded with sensible defaults); renames cascade to hosts
- Bulk operations — CSV import in the UI and
bulk_create_hosts/bulk_delete_hostsMCP tools (paste a UniFi export at your assistant); per-record results, partial failures never abort the batch. Multi-select delete in the host table, and force-delete for a whole subnet with confirmation. - Audit log — every write (UI, API, or MCP) is recorded with before/after snapshots, so you can always review what your assistant changed
- Zero ops — single container, SQLite in a volume, backup = download one file
See TLG-IPAM-Project-Brief.md for the full specification.
cp .env.example .env # then set a strong API_KEY, e.g. openssl rand -hex 32
docker compose up --buildOpen http://localhost:8080, paste your API key, done.
The MCP server at /mcp speaks Streamable HTTP with API-key auth, so any MCP-capable client can use it. Claude Desktop setup is documented below; instructions for other clients (ChatGPT, Codex CLI, …) coming soon.
Claude Desktop's native connectors want OAuth, so API-key auth goes through mcp-remote. Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
"mcpServers": {
"tlg-ipam": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"http://localhost:8080/mcp",
"--header", "X-API-Key:${TLG_IPAM_KEY}"
]
}
}with TLG_IPAM_KEY set in your environment. Then ask your assistant things like:
"What IPs are free in the services VLAN?" "Register the new PBS container at 10.10.20.45." "Allocate the next free IP for a new LXC called grafana-01." "What did you change yesterday?"
Backend (Python 3.12+):
cd api
python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest # test suite
API_KEY=dev-key .venv/bin/uvicorn app.main:app --port 8080 --reloadFrontend (Node 20+), with /api proxied to the backend on :8080:
cd web
npm install
npm run dev"Next free IP" never hands out the network or broadcast address, the subnet gateway, anything inside the DHCP pool (dhcp_start–dhcp_end), or anything in a reserved range — but manually registering a host inside those is deliberate and allowed. Duplicate IPs are blocked by a database unique constraint, not just API validation. Overlapping CIDRs are rejected within a section but allowed across sections (useful for VPN vs LAN views of the same space).
Hosts inherit their subnet's default domain suffix, with an optional per-host override; the API returns the computed FQDN either way.
MIT — see LICENSE.