Server data from the Official MCP Registry
Syslog receiver and MCP server for homelab log intelligence.
Syslog receiver and MCP server for homelab log intelligence.
Remote endpoints: streamable-http: https://cortex.tootie.tv/mcp
Valid MCP server (1 strong, 1 medium validity signals). No known CVEs in dependencies. Imported from the Official MCP Registry.
Endpoint verified · Requires authentication · 1 issue found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
This plugin requests these system permissions. Most are normal for its category.
Unverified package source
We couldn't verify that the installable package matches the reviewed source code. Proceed with caution.
Set these up before or after installing:
Environment variable: CORTEX_RECEIVER_HOST
Environment variable: CORTEX_TOKEN
Environment variable: CORTEX_RECEIVER_PORT
Remote Plugin
No local installation needed. Your AI client connects to the remote endpoint directly.
Add this to your MCP configuration to connect:
{
"mcpServers": {
"tv-tootie-cortex": {
"env": {
"CORTEX_TOKEN": "your-cortex-token-here",
"CORTEX_RECEIVER_HOST": "your-cortex-receiver-host-here",
"CORTEX_RECEIVER_PORT": "your-cortex-receiver-port-here"
},
"url": "https://cortex.tootie.tv/mcp"
}
}
}From the project's GitHub README.
Rust syslog receiver and MCP server for homelab log intelligence. Ingests syslog over UDP and TCP, stores it in SQLite with FTS5 full-text indexing, and exposes action-based log search, inventory, correlation, status, and analysis tools through MCP, REST, and CLI adapters backed by the shared service layer.
cortex also maintains derived projection tables for future investigation graph features. Those graph tables connect source IPs, claimed hosts, apps, services, containers, AI projects/sessions, and error signatures with evidence, but raw logs, heartbeats, inventory, signatures, and session rows remain the source of truth. The graph projection is rebuildable and intentionally has no ingest triggers. Graph rebuilds use staging tables plus a short serialized swap and record explicit projection status, source watermarks, row counts, runtime metrics, and degraded failure state.
Cortex keeps its repo and CLI name as cortex. The npm package is
cortex-rmcp, because Cortex is broader than only an MCP server. The MCP
registry name is tv.tootie/cortex, and the Docker image is
ghcr.io/jmagar/cortex:v<version>.
Most smaller Rust MCP servers in this workspace use the
<service>-rmcp repo / r<service> binary / <service>-rmcp npm pattern.
Cortex is the deliberate exception: repo cortex, CLI cortex, npm package
cortex-rmcp.
Cortex ingests syslog, OTLP, Docker, managed file-tail, inventory, heartbeat, and AI-session signals into SQLite, then exposes bounded investigation actions through MCP, REST, and CLI adapters backed by the same service layer.
Primary capabilities:
1514.Not for: replacing a SIEM, accepting arbitrary unaudited log mutations from agents, or exposing Docker/admin operations without a trusted deployment boundary. Cortex is a homelab log-intelligence service with bounded action surfaces and explicit admin gates.
MCP callers never provide credentials, tokens, keys, or secrets as action arguments. Auth tokens, upstream notification secrets, file-tail roots, and API admin credentials live in server configuration or environment variables.
Use the npm launcher for local MCP clients and quick CLI access:
npx -y cortex-rmcp --help
npx -y cortex-rmcp mcp
For a permanent command on PATH, install the launcher globally:
npm i -g cortex-rmcp
cortex --version
The package downloads the matching GitHub Release binary during postinstall.
For source builds:
cargo build --release
The first-screen 30-second path is a stdio MCP client pointed at the launcher:
{
"mcpServers": {
"cortex": {
"command": "npx",
"args": ["-y", "cortex-rmcp", "mcp"]
}
}
}
Then ask for a cheap read action first:
{"action":"status"}
For an HTTP server with syslog listeners:
export CORTEX_API_TOKEN=change-me
export CORTEX_TOKEN=change-me
cortex serve mcp
stdio launches a query-only MCP process that reads the configured Cortex database without starting network listeners:
{
"mcpServers": {
"cortex": {
"command": "cortex",
"args": ["mcp"]
}
}
}
Streamable HTTP uses the persistent server on /mcp:
{
"mcpServers": {
"cortex": {
"url": "http://127.0.0.1:3100/mcp",
"headers": {
"Authorization": "Bearer ${CORTEX_TOKEN}"
}
}
}
}
The plain JSON REST API is mounted under /api/* on the same HTTP listener and
uses CORTEX_API_TOKEN, not CORTEX_TOKEN.
| Surface | Status | Purpose |
|---|---|---|
| Syslog | Required for daemon ingest | UDP/TCP 1514 receiver for network logs |
| MCP | Required | cortex action-dispatched tool over stdio or Streamable HTTP |
| CLI | Required | Operator commands, local query workflows, setup, and ingest management |
| REST | Required for daemon mode | JSON API under /api/* with separate bearer auth |
| MCP Apps | Optional | Query widget resource for UI-capable MCP hosts |
| Web dashboard | Not shipped | Cortex does not serve a standalone browser app |
Cortex exposes one MCP tool named cortex. The required action argument
selects the operation; per-action validation happens in the handler and service
layers.
Common first-pass actions are status, errors, tail, search, timeline,
and context. Expensive or write/admin actions should only be used once a query
is scoped.
For the full action table and parameter reference, see
docs/mcp/SCHEMA.md. That document is curated from the
runtime schema and protected by drift tests; the generated runtime schema and
Rust ACTION_SPECS table are the source of truth when they disagree.
The CLI mirrors the same service layer used by MCP and REST:
cortex stats
cortex status
cortex search --query "error" --limit 20
cortex ingest inventory refresh --json
cortex ingest file-tail list
cortex setup repair
cortex serve mcp
cortex mcp
Use cortex --help and subcommand help for the full command tree. The CLI is
the preferred surface for local setup, repairs, and admin maintenance.
Cortex separates read, admin, and transport trust boundaries:
cortex:read; admin mutations require cortex:admin.CORTEX_TOKEN.CORTEX_API_TOKEN; REST admin mutations also require
X-Cortex-Admin-Token: $CORTEX_API_ADMIN_TOKEN.Generated runtime schemas and curated docs should stay aligned, but operational policy belongs in the Rust service layer, not in MCP-only glue.
The daemon listens on UDP/TCP syslog, normalizes input, writes through a batched SQLite writer, and exposes MCP/REST/CLI adapters over the shared Cortex service model. Derived graph projection tables are rebuildable from raw logs, heartbeats, inventory, signatures, and session rows; they are not the source of truth.
The detailed architecture diagram and ingest notes continue in Overview, Homelab Inventory, and the ingest sections below.
The source of truth for release identity is the version shared by Cargo.toml,
the lockfile, release metadata, package launcher metadata, plugin/registry
metadata, and container image tags.
Distribution/version invariants:
cortex-rmcp npm package version must match the GitHub Release binary it
downloads.server.json must point at the current ghcr.io/jmagar/cortex:v<version>
image.Generated artifacts include the live MCP schema returned by the server and the
schema resource exposed through MCP. Curated artifacts include this README and
the human references in docs/.
Deploy daemon mode when Cortex should receive syslog and serve HTTP MCP/REST:
CORTEX_RECEIVER_HOST=0.0.0.0 \
CORTEX_RECEIVER_PORT=1514 \
CORTEX_HOST=0.0.0.0 \
CORTEX_PORT=3100 \
CORTEX_API_TOKEN=change-me \
CORTEX_TOKEN=change-me \
cortex serve mcp
Container and multi-host deployment notes are in Installation, Multi-Host Deployment, and HTTPS / Reverse Proxy.
401 or 403 from /mcp: check CORTEX_TOKEN, OAuth, and trusted gateway
settings./api/* fails while /mcp works: check CORTEX_API_TOKEN; REST has its own
bearer token.1514, sender forwarding rules, and
CORTEX_RECEIVER_HOST.map reports missing cache: run cortex ingest inventory refresh --json.CORTEX_FILE_TAIL_ALLOWED_ROOTS
and not a symlink or sensitive mount.status, errors, tail, or scoped
search, then narrow before patterns, anomalies, or compose_doctor.Run the stdio MCP server or CLI without a manual binary install:
npx -y cortex-rmcp --help
MCP clients can use the same launcher:
{
"mcpServers": {
"cortex": {
"command": "npx",
"args": ["-y", "cortex-rmcp", "mcp"]
}
}
}
The npm package downloads the cortex binary from GitHub Releases during postinstall. Cortex keeps its repo and CLI name as cortex; the npm package is cortex-rmcp because Cortex is broader than only an MCP server.
Most Rust MCP servers use:
<service>-rmcpr<service><service>-rmcpCortex is the exception: repo cortex, CLI cortex, npm package cortex-rmcp.
┌─────────────────────────────────┐
rsyslog/syslog-ng ─▶ UDP :1514 / TCP :1514 │
network devices ─▶ ┌──────────────────────────┐ │
│ │ parse → batch writer │ │
│ │ SQLite + FTS5 (WAL mode) │ │
│ └──────────────────────────┘ │
Claude / MCP ◀──── ▶ RMCP HTTP :3100/mcp │
local MCP client ◀──▶ syslog mcp query process │
└─────────────────────────────────┘
The daemon listens on a single port for both UDP and TCP syslog (default 1514). All inbound messages are parsed, batched, and written to SQLite with full-text indexing. The MCP HTTP server runs on a separate port (default 3100) and uses RMCP Streamable HTTP in stateless JSON-response mode. Local stdio-only MCP clients can launch cortex mcp, a query-only MCP process that reads the same SQLite database without starting syslog listeners or the HTTP server.
MCP is an exposure surface, not the owner of log-intelligence business policy. Shared defaults, limits, validation, audit identity, correlation behavior, and safety gates should live in SyslogService or service-owned operation models so MCP, REST, and CLI remain consistent.
One MCP tool, cortex, is exposed. Use the required action argument to run search, filter, tail, errors, hosts, map, sessions, search_sessions, abuse, abuse_incidents, abuse_investigate, ai_correlate, topic_correlate, usage_blocks, project_context, list_ai_tools, list_ai_projects, correlate, stats, status, apps, source_ips, timeline, patterns, context, get, ingest_rate, silent_hosts, clock_skew, anomalies, compare, compose_status, compose_doctor, unaddressed_errors, ack_error, unack_error, notifications_recent, notifications_test, llm_invocations, similar_incidents, incident_context, graph, skill_events, skill_incidents, skill_investigate, mcp_events, mcp_incidents, mcp_investigate, hook_events, hook_incidents, hook_investigate, or help.
For the complete action-specific parameter reference, see docs/mcp/SCHEMA.md. For correlation behavior and AI/non-AI inclusion rules, see docs/mcp/CORRELATION.md.
| Action | Purpose |
|---|---|
search | Full-text search with filters |
filter | Structured filter-only log retrieval |
tail | Recent log entries |
errors | Error/warning summary by host and severity |
hosts | Host registry with first/last seen |
map | Cached homelab inventory plus graph-backed topology answers |
sessions | AI transcript sessions by project |
search_sessions | Ranked grouped session search |
abuse | Abuse hits in AI transcripts with same-session context |
abuse_incidents | Groups abuse hits into scored incident candidates |
abuse_investigate | Expands incidents into deterministic evidence bundles |
ai_correlate | AI transcript anchors cross-referenced against non-AI logs |
topic_correlate | Resolve a topic to graph entities and correlate all related logs into a unified timeline |
usage_blocks | AI activity in 5-hour UTC windows |
project_context | Summary for one AI project path |
list_ai_tools | Distinct AI tools with counts |
list_ai_projects | Distinct AI projects with counts |
correlate | Cross-host event correlation in a time window; omit reference_time and pass query to derive the anchor from a matching AI session |
stats | Database statistics and storage health |
status | Lightweight runtime and DB health |
apps | Distinct application names with log and host counts |
source_ips | Distinct source identifiers with hostname breakdown |
timeline | Bucketed counts over time |
patterns | Near-duplicate message template clusters |
context | Surrounding logs around a log id or timestamp |
get | One log entry by id, including raw frame |
ingest_rate | Recent ingest throughput and write-block state |
silent_hosts | Hosts whose last_seen is older than a threshold |
clock_skew | Per-host received_at minus timestamp distribution |
anomalies | Recent vs baseline volume/error comparison |
compare | Side-by-side comparison of two time ranges |
compose_status | Redacted read-only Compose deployment diagnostics |
compose_doctor | Strict Compose deployment health diagnostics |
unaddressed_errors | Repeating unacknowledged error signatures |
ack_error | Acknowledge an error signature |
unack_error | Revoke an error acknowledgement |
notifications_recent | Recent notification firings |
notifications_test | Send a test notification via Apprise |
llm_invocations | Recent LLM invocation audit records (concurrency/rate-limit/circuit-breaker denials included) |
similar_incidents | FTS5 cluster search over historical system logs |
incident_context | Full context bundle for a known time window |
graph | Resolve graph entities, neighborhoods, and evidence-backed explanations |
skill_events | List extracted AI skill-invocation events |
skill_incidents | Groups negative-signal transcript hits following a skill invocation into scored incident candidates |
skill_investigate | Expands skill-usage incidents into deterministic evidence bundles, skill-first |
mcp_events | List extracted AI MCP tool-call events |
mcp_incidents | Groups negative-signal transcript hits following an MCP tool call into scored incident candidates |
mcp_investigate | Expands MCP-usage incidents into deterministic evidence bundles, server/tool-first |
hook_events | List extracted/collected AI hook events (runtime execution and config inventory) |
hook_incidents | Groups hook failures/timeouts and other negative signals into scored incident candidates |
hook_investigate | Expands hook-usage incidents into deterministic evidence bundles, hook-first |
help | Markdown reference for all actions |
cortex ingest inventory refresh --json collects native Rust inventory into
~/.cortex/inventory and writes:
normalized/homelab.json — typed cortex.homelab_inventory.v1 cachecollection-state.json — per-collector status, warnings, timings, and artifact refsraw/<run_id>/*.txt — raw-but-redacted Compose and reverse proxy artifactscortex ingest inventory status --json reports cache freshness and warnings without
opening SQLite. The MCP map action is read-only: it reads the normalized cache
and overlays bounded live Cortex host/heartbeat data, but never triggers refresh
or returns raw artifact bodies.
map defaults to the inventory snapshot. Graph-backed modes add a typed
graph_answer envelope with answer_status, bounded topology rows, safe
evidence samples, map follow-up queries, and graph proof queries:
{"action":"map","mode":"host_services","host":"squirts"}
{"action":"map","mode":"domain_routes","domain":"adguard.tootie.tv"}
{"action":"map","mode":"service_dependencies","host":"squirts","service":"swag"}
{"action":"map","mode":"findings","finding_types":["potential_public_route","risky_mounts","collector_health"]}
mode=findings returns bounded topology risk and hygiene findings derived from
the graph plus normalized inventory/cache state. Findings include severity,
confidence, reason code, affected entities, safe evidence IDs/excerpts, and
remediation hints. They deliberately avoid raw config contents, raw artifact or
cache paths, credential-bearing upstream URLs, and raw collector warning text;
potential_public_route means configured reverse-proxy routing, not proof of
unauthenticated public internet exposure.
When the server is running, inventory refresh also projects topology evidence
into the investigation graph. The baseline refresh interval is 5 minutes, with
local Compose/proxy config watchers as lower-latency refresh triggers. Remote
Docker events streams over SSH are opt-in via
CORTEX_INVENTORY_REMOTE_DOCKER_EVENTS=true.
On first run, before normalized/homelab.json exists, map and
cortex ingest inventory status --json report cache_status: "missing". Run
cortex ingest inventory refresh --json to seed ~/.cortex/inventory and clear that
missing-cache state.
The MCP server also exposes reusable prompts for common infrastructure debugging
workflows: infra.incident-triage, infra.host-health,
infra.service-outage, infra.security-auth-review,
infra.noise-reduction, and infra.agent-change-correlation.
For the prompt catalog and argument reference, see
docs/mcp/PROMPTS.md.
cortex ships one interactive UI surface as progressive enhancement: a simple
log-search widget for MCP hosts that support MCP Apps
/ MCP-UI (_meta.ui.resourceUri). It is a single self-contained HTML resource —
no browser build step, no external dependencies, no new server routes.
ui://cortex/query-widgettext/html;profile=mcp-appcortex tool advertises it via _meta.ui.resourceUri; the widget calls the
same cortex tool with action=search over the host bridge and renders the
rows in a compact table.Non-UI hosts are unaffected. Plain MCP clients keep reading the normal
text/JSON tool results; only hosts that detect _meta.ui.resourceUri fetch and
render the ui:// resource.
Confirm the wire contract with raw JSON-RPC (no UI host required):
# Widget resource is listed
curl -s -X POST http://localhost:3100/mcp \
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"resources/list","params":{}}'
# Widget HTML is served with the MCP Apps MIME type
curl -s -X POST http://localhost:3100/mcp \
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"resources/read","params":{"uri":"ui://cortex/query-widget"}}'
# Search returns both structuredContent (for UI rows) and text (for plain clients)
curl -s -X POST http://localhost:3100/mcp \
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"cortex","arguments":{"action":"search","query":"error","limit":5}}}'
If CORTEX_TOKEN is set, add -H "Authorization: Bearer $CORTEX_TOKEN".
scripts/smoke-test.sh runs these same checks automatically. For the wire-format
details see docs/mcp/MCPUI.md.
cortex searchFull-text search across all syslog messages with optional filters. Uses SQLite FTS5 with porter stemming.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | no | — | FTS5 search query (see FTS5 query syntax) |
host | string | no | — | Exact hostname match. Use cortex with action: "hosts" to enumerate. |
source | string | no | — | Exact source identifier. Syslog entries use the verified network sender address (IP:port); OTLP rows use the verified peer IP; Docker ingest stream rows use docker://host/container/stream; Docker lifecycle event rows use docker-event://host/container/action. |
severity | string | no | — | One of: emerg alert crit err warning notice info debug |
app | string | no | — | Application name, e.g. sshd, dockerd, kernel |
since | string | no | — | Start of time range (relative like 1h/yesterday, or ISO 8601 / RFC 3339, e.g. 2025-01-15T00:00:00Z) |
until | string | no | — | End of time range (relative or ISO 8601) |
limit | integer | no | 100 | Max results (hard cap: 1000) |
Response
{
"count": 3,
"logs": [
{
"id": 12345,
"timestamp": "2025-01-15T14:30:00Z",
"hostname": "router",
"facility": "kern",
"severity": "err",
"app_name": "kernel",
"process_id": null,
"message": "kernel panic: unable to mount root",
"received_at": "2025-01-15T14:30:01.123Z",
"source_ip": "10.0.0.1:51234"
}
]
}
FTS5 examples
query: "kernel panic" # implicit AND: both terms must appear
query: "OOM AND killer" # explicit AND
query: "sshd OR pam" # boolean OR
query: "failed NOT sudo" # boolean NOT
query: '"connection refused"' # exact phrase (bypasses stemming)
query: "error*" # prefix wildcard
query: "restart*" # matches restart, restarted, restarting
cortex filterStructured filter-only retrieval for correlation workflows. This action rejects query; use search for FTS5 message-body search.
Common filters match search: host, source, severity, app, facility, exclude_facility, process_id, since, until, received_since, received_until, and limit.
Correlation aliases include source_kind (docker-stream, docker-event, agent-command, shell-history, transcript, claude, codex, gemini), plus tool, project, session_id, container, docker_host, stream, and event_action.
source_kind=file-tail filters managed file-tail rows (source_ip prefix file-tail://).
cortex tailReturn the N most recent log entries. Equivalent to tail -f across all hosts.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | no | — | Filter to a specific host |
source | string | no | — | Filter to an exact source identifier. Syslog entries use the verified network sender address (IP:port); OTLP rows use the verified peer IP; Docker ingest stream rows use docker://host/container/stream; Docker lifecycle event rows use docker-event://host/container/action. |
app | string | no | — | Filter to a specific application |
n | integer | no | 50 | Number of recent entries (hard cap: 500) |
Response
Same structure as cortex search: { "count": N, "logs": [...] }.
cortex analysis errorsSummarize warnings and errors across all hosts in a time window. Groups by hostname and severity, showing counts. Use this for quick health assessments.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
since | string | no | all time | Start of time range (ISO 8601) |
until | string | no | now | End of time range (ISO 8601) |
Severities included: emerg, alert, crit, err, warning.
Response
{
"summary": [
{ "hostname": "router", "severity": "err", "count": 42 },
{ "hostname": "router", "severity": "warning", "count": 17 },
{ "hostname": "storage", "severity": "crit", "count": 3 }
]
}
cortex hostsList all hosts that have sent syslog messages, with first/last seen timestamps and total log counts.
Parameters: none
Response
{
"hosts": [
{
"hostname": "router",
"first_seen": "2025-01-01T00:00:00.000Z",
"last_seen": "2025-01-15T14:30:00.000Z",
"log_count": 18432
}
]
}
cortex sessionsList AI transcript sessions grouped by project, tool, session, and host.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
project | string | no | — | Exact project path, e.g. /home/jmagar/workspace/cortex |
tool | string | no | — | AI tool filter: claude, codex, or gemini |
host | string | no | — | Restrict to one host |
since | string | no | — | Start of time range (ISO 8601) |
until | string | no | — | End of time range (ISO 8601) |
limit | integer | no | 100 | Max sessions (hard cap: 1000) |
Response
{
"count": 1,
"sessions": [
{
"project": "/home/jmagar/workspace/cortex",
"tool": "codex",
"session_id": "019e1506-dc81-7881-9926-4d6d4efda1ac",
"hostname": "dookie",
"first_seen": "2026-05-11T03:13:51.745Z",
"last_seen": "2026-05-11T04:10:00.000Z",
"event_count": 42
}
]
}
cortex correlate eventsSearch for related events across multiple hosts within a ±N minute window around a reference timestamp. Useful for debugging cascading failures. Results are grouped by host and ordered by time.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
reference_time | string | yes | — | Center timestamp (ISO 8601, e.g. 2025-01-15T14:30:00Z) |
window_minutes | integer | no | 5 | Minutes before and after reference_time (max 60) |
severity_min | string | no | warning | Minimum severity to include. warning returns warning/err/crit/alert/emerg. debug returns everything. |
host | string | no | — | Limit correlation to one host |
source | string | no | — | Limit correlation to an exact source identifier. Syslog entries use the verified network sender address (IP:port); OTLP rows use the verified peer IP; Docker ingest stream rows use docker://host/container/stream; Docker lifecycle event rows use docker-event://host/container/action. |
query | string | no | — | FTS5 query to narrow results |
limit | integer | no | 500 | Max total events (hard cap: 999) |
Response
{
"reference_time": "2025-01-15T14:30:00Z",
"window_minutes": 5,
"window_from": "2025-01-15T14:25:00+00:00",
"window_to": "2025-01-15T14:35:00+00:00",
"severity_min": "warning",
"total_events": 12,
"truncated": false,
"hosts_count": 3,
"hosts": [
{
"hostname": "router",
"event_count": 7,
"events": [...]
}
]
}
Note on clock skew: cortex correlate events uses the timestamp field from the syslog message, which reflects the sending device's clock. If a device clock is skewed, events may fall outside the correlation window. See Time synchronization.
cortex statsReturn database statistics including total logs, total hosts, time range covered, logical and physical DB size, free disk, configured thresholds, current write-block status, and runtime ingest observability.
Parameters: none
Response
{
"total_logs": 284917,
"total_hosts": 12,
"oldest_log": "2024-10-15T00:00:01Z",
"newest_log": "2025-01-15T14:30:00Z",
"logical_db_size_mb": "312.45",
"physical_db_size_mb": "328.00",
"free_disk_mb": "14200.00",
"max_db_size_mb": 1024,
"min_free_disk_mb": 0,
"write_blocked": false,
"runtime_observability": {
"syslog_udp_packets_received": 280000,
"syslog_tcp_connections_active": 3,
"ingest_entries_enqueued": 284917,
"ingest_queue_depth": 0,
"ingest_queue_capacity": 10000,
"ingest_queue_utilization_pct": "0.00",
"writer_batches_flushed": 2850,
"writer_logs_written": 284917,
"writer_flush_failures": 0,
"writer_logs_retained": 0,
"writer_logs_discarded": 0,
"writer_storage_blocked": false,
"last_ingest_at": "2025-01-15T14:30:05.123Z",
"last_write_at": "2025-01-15T14:30:05.400Z",
"last_error_at": null
},
"otlp": {
"logs_received": 42,
"decode_errors": 0
}
}
write_blocked: true means the storage budget is exceeded and new log ingestion is paused. See Storage budget enforcement.
cortex statusReturn lightweight runtime status without the heavier DB statistics query. Use this for dashboards and doctor checks that need current queue depth, backpressure, writer failure/drop state, listener counters, and last activity timestamps.
Parameters: none
cortex helpReturn markdown documentation for all tools in this toolset.
Parameters: none
The sections above document only the most common actions in detail. For the full 45-action surface with per-action parameters, see docs/mcp/SCHEMA.md or call action=help against a running server.
The cortex search and cortex correlate actions use SQLite FTS5 with porter stemming (tokenize='porter unicode61'). Valid query forms:
| Syntax | Example | Matches |
|---|---|---|
| Single term | panic | Any message containing "panic" or stemmed variants |
| Porter stemming | restart | restart, restarted, restarting, restarts |
| AND (default) | disk error or disk AND error | Both terms present |
| OR | sshd OR pam | Either term present |
| NOT | failed NOT sudo | "failed" present, "sudo" absent |
| Phrase | "connection refused" | Exact phrase in that order |
| Prefix wildcard | error* | Any word starting with "error" |
| Grouped | (kernel OR oom) AND panic | Grouped boolean logic |
Limits: max 512 characters, max 16 whitespace-separated terms.
Porter stemming means connect, connected, connecting, and connection all match the query connect. Phrase queries ("...") bypass stemming and require exact token order.
Each stored log entry has these fields:
| Field | Type | Description |
|---|---|---|
id | integer | Auto-increment primary key |
timestamp | text | Message timestamp (RFC 3339, UTC). From the syslog message header. |
hostname | text | Hostname from the syslog message (user-controlled, not verified) |
facility | text|null | Syslog facility name (see facilities below) |
severity | text | Syslog severity level name |
app_name | text|null | Application/process name from the syslog message |
process_id | text|null | PID from the syslog message |
message | text | Log message body (FTS5-indexed) |
received_at | text | Server-side receipt timestamp (RFC 3339, UTC). Used for retention. |
source_ip | text | Source identifier. Syslog entries use the exact network sender address (IP:port) captured from the packet/connection peer. OTLP rows use the peer IP without the ephemeral source port. Docker ingest stream rows use docker://host/container/stream; Docker lifecycle event rows use docker-event://host/container/action. |
ai_tool | text|null | AI tool name (e.g. claude, codex, gemini) |
ai_project | text|null | AI project path |
ai_session_id | text|null | AI session unique identifier |
ai_transcript_path | text|null | Full path to the source transcript file |
metadata_json | text|null | Source-specific JSON metadata. Syslog rows include parser/source provenance; OTLP rows include resource/log attributes plus trace/span ids; Docker rows include host/container/image/compose/action details; transcript rows include source kind, file path, line number, record key, and scrub status. |
cortex sessions index scans the default local transcript roots
~/.claude/projects, ~/.codex/sessions, and ~/.gemini/tmp; cortex sessions index --path PATH
can scan a known transcript directory or one explicit supported transcript file, and
cortex sessions add --file FILE imports one file. Recursive scans are limited to
~/.claude/projects, ~/.codex/sessions, ~/.gemini/tmp, or their children; broad roots such
as /, $HOME, and the current repo root are rejected before walking. The
scanner skips symlinks, counts unsupported files without parsing them, and
streams JSONL transcript files line-by-line in bounded SQLite chunks. Gemini
chat files are imported from ~/.gemini/tmp/*/chats/session-*.json; when a
Gemini file has only projectHash, Cortex stores the project as
gemini://project/<hash> so session inventory remains queryable. Use
--force to reimport a transcript path from scratch after parser changes,
--since RFC3339 to scan only recently modified files, and
cortex sessions checkpoints --errors plus cortex sessions errors to inspect structured
scanner failures.
For real-time local Claude/Codex/Gemini transcript ingestion, install the host-local watch service:
cortex setup sessions-watch-service install
cortex setup sessions-watch-service check
cortex setup sessions-watch-service remove
The watcher runs outside Docker because it needs host access to
~/.claude/projects, ~/.codex/sessions, and ~/.gemini/tmp. It writes to the configured live
SQLite DB and delegates every stable changed supported transcript file to the
same scanner path used by cortex sessions add --file FILE; Gemini session-*.json
chat files use the same checkpoint and duplicate-suppression path. Installing the watcher
disables the older polling timer so both helpers do not scan the same files.
This writes to a local SQLite file. It only reaches the fleet's shared cortex
server if that server also runs on this same host. When the server runs elsewhere
(the common case — the server typically runs on one dedicated host while Claude/Codex/
Gemini run on dev workstations), enable AI-transcript forwarding on cortex heartbeat agent instead: --ai-transcripts / CORTEX_AGENT_AI_TRANSCRIPTS=true. This adds one
more supervised stream (alongside --docker/--journald) that polls the same
transcript roots every 15s and POSTs new lines to the server's POST /v1/ai-transcripts
(bearer-authenticated, same token as heartbeats), using a local checkpoint file
(CORTEX_AGENT_AI_TRANSCRIPT_CHECKPOINT, default <cortex home>/ai-transcript-forward-checkpoint.json)
so it never resends already-forwarded lines. Gemini sessions aren't supported by the
forwarder yet (whole-file JSON, not line-based like Claude/Codex) — only Claude and
Codex transcripts forward today. The local watch service and the agent forwarder can
run at the same time without conflict; they only read the transcript files, never write them.
The optional polling fallback is still available:
cortex setup sessions-index-timer install
cortex setup sessions-index-timer check
cortex setup sessions-index-timer remove
Both helpers are deliberately not inside the Docker container. Docker Compose owns only the server/query runtime.
Imported AI transcript messages are scrubbed for known credential/token patterns
before storage and FTS indexing. The rows still live in the main logs table,
so raw actions such as search, tail, context, and get can return
scrubbed transcript text and local ai_transcript_path values within seconds of
the transcript write. Scrubbing is best-effort, not a compliance boundary.
If storage guardrails cannot recover enough space, indexing fails before
committing additional chunks.
Local command history can be correlated with system logs without introducing a separate table:
cortex ingest shell user index --path ~/.zsh_history --shell zsh
cortex setup shell agent install
export CLAUDE_CODE_SHELL_PREFIX="$HOME/.local/bin/cortex-agent-command-wrapper"
cortex ingest shell agent index --path ~/.local/state/cortex/agent-command.jsonl
cortex ingest shell agent index also accepts --server URL/--token TOKEN
to forward the spool to a remote Cortex's POST /v1/agent-commands endpoint
instead of writing to the local database — the spool is only truncated after
a successful forward. The legacy grammar cortex ingest agent-command {ingest-spool|wrap} is still accepted as a deprecated alias.
cortex ingest shell user index imports zsh extended history lines with timestamps and
durations as source_kind="shell-history" rows. Plain untimestamped history is
skipped because it cannot support time-window correlation.
cortex setup shell agent install writes a small local wrapper for Claude
Code's CLAUDE_CODE_SHELL_PREFIX. Claude Code invokes that prefix for spawned
shell commands, including Bash tool calls, hook commands, and stdio MCP server
startup commands. The wrapper preserves stdio and exit code, appends one
scrubbed JSONL record under ~/.local/state/cortex/, and
cortex ingest shell agent index imports those records as
source_kind="agent-command" rows, then truncates the locked spool after a
successful import so repeated runs only process new commands. The wrapper
records command text, cwd, duration, exit status, agent name, PID, host/user, and
CLAUDE_CODE_SESSION_ID when present. It does not capture environment
variables, stdout, or stderr by default.
Both command import paths run the AI scrubber plus command-specific redaction
for token flags, sensitive assignments, Authorization headers, URL userinfo,
curl -u, and private-key blocks before storage. Scrubbing is best-effort, not
a compliance boundary.
Documentation truncated — see the full README on GitHub.
Be the first to review this server!
by Modelcontextprotocol · Developer Tools
Web content fetching and conversion for efficient LLM usage
by Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
by Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.