From security alert to investigated narrative
Traditional alert handling often requires an analyst to open an incident, extract entities, formulate several queries, correlate the results and write a summary. This project tests whether a locally hosted LLM can perform a useful portion of that investigative work by calling real security tools—not simply summarising a preassembled log extract.
Repetitive incident triage
A Cowrie honeypot generates frequent Sentinel incidents. Investigating each source IP manually is useful for research, but time-consuming and repetitive.
Evidence-led AI investigation
Pass incident context into an agent, allow it to query Sentinel through MCP, and produce a readable SOC report delivered to Discord.
How the components fit together
The model runs locally through Ollama on a Windows host with an AMD Radeon RX 7600 XT (16 GB VRAM). n8n runs in Docker on an Ubuntu VM, while the Azure MCP Server provides access to Sentinel's Log Analytics workspace. The workflow's tool access is scoped to querying Cowrie telemetry.
| Component | Role |
|---|---|
| Microsoft Sentinel | Generates and stores incidents; provides source entities and activity timestamps. |
| Cowrie SSH honeypot | Captures simulated SSH logins, session events and attacker-supplied commands. |
| n8n | Orchestrates incident retrieval, conditional processing, agent execution, output formatting and Discord delivery. |
| Azure MCP Server | Exposes the monitor_workspace_log_query tool for real Log Analytics queries. |
| Ollama + Qwen3:14b | Locally hosted agent that generates queries, reviews results and writes the investigation. |
| Discord | Receives the final report through the existing messaging integration. |
Investigation logic and tool use
Retrieve incident context
n8n retrieves Sentinel incidents, obtains associated entities and passes the source IP plus incident first/last activity times to the agent. The investigation window expands by one hour on each side.
Call a real security tool
The agent uses MCP_Client_monitor with monitor_workspace_log_query. MCP requires the physical table cowrie_JSON_CL, while the KQL itself uses the saved function Cowrie_Normalized.
Investigate based on findings
A baseline query counts events, sessions, successful and failed logins, and command events. The agent can follow up with authentication details, command analysis and session correlation when warranted.
Produce and deliver a report
Qwen assembles a SOC-style report with observed activity, interpretation, caveats and follow-up suggestions. n8n formats and sends the output to Discord.
Example baseline KQL
Cowrie_Normalized
| where TimeGenerated >= datetime(START_TIME)
| where TimeGenerated <= datetime(END_TIME)
| where SourceIp == "SOURCE_IP"
| summarize
TotalEvents = count(),
DistinctSessions = dcount(Session),
FailedLogins = countif(EventID == "cowrie.login.failed"),
SuccessfulLogins = countif(EventID == "cowrie.login.success"),
Commands = countif(EventID == "cowrie.command.input")The placeholders above are illustrative. At execution time, the agent substitutes the current incident's IP and expanded UTC timestamps.
Handling long attacker commands
Some captured Cowrie commands exceeded 10,000 characters. Sending complete command strings into a small model context reduced investigation quality. The revised KQL groups commands by their input string but returns only a preview, character length, SHA-256 hash and execution frequency.
| summarize CommandCount = count(),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated) by Input
| extend CommandLength = strlen(Input),
CommandPreview = substring(Input, 0, 500),
CommandHash = hash_sha256(Input)
| project CommandCount, FirstSeen, LastSeen,
CommandLength, CommandPreview, CommandHashThis preserves useful investigative indicators while limiting the data sent to the LLM. The hash represents the command string, not a downloaded executable.
A working end-to-end investigation
In the latest demonstrated run, the n8n workflow completed successfully in approximately 3 minutes 52 seconds. The agent made three successful MCP calls, and the resulting SOC report was passed through the workflow's Discord delivery path.
The verified baseline also showed two command input events. The agent's report described commands attempting to alter .ssh and write an SSH public key to authorized_keys, behaviour consistent with an attempted persistence mechanism in the simulated SSH environment.
The report also illustrates why analyst review remains important: one described command timestamp preceded the login timestamp of the session to which the report associated it. A future evidence-validation step should catch inconsistencies of this kind automatically.
What made the PoC work
Tool calling is not the same as evidence integrity
Earlier tests produced plausible but unsupported usernames, Linux commands and hashes. Real tool access did not by itself prevent hallucinations. The report must be evaluated against the underlying MCP results.
Context length matters
The n8n Ollama Chat Model context setting was found at 2,048 tokens and increased to 8,192. The subsequent test showed three successful tool calls and a more coherent investigation. This is an observed improvement, not proof that context length was the only cause.
Compact queries beat raw log dumps
Aggregated statistics and bounded command previews reduce model load while preserving relevant telemetry. This was especially important for lengthy attacker-supplied shell commands.
Errors should be recoverable
One earlier run sent an invalid MCP command and workspace. The agent recovered by retrying with the correct monitor_workspace_log_query command and sentinel workspace, demonstrating useful—but not perfect—tool resilience.
Security and scope boundaries
- Cowrie is a simulated SSH service: successful honeypot authentication does not prove compromise of a real host or account.
- Captured commands are attacker-supplied evidence; they must not be executed by the agent or interpreted as instructions.
- Tool access should remain read-only and least-privilege. Credentials and secrets should not be embedded in portfolio materials.
- The local model is used for investigation and narrative generation; findings still require appropriate confidence and validation.
From manual PoC to unattended triage
The investigation and Discord reporting path works. The next development milestone is reliable autonomous triggering and deduplication, without repeatedly processing the same Sentinel incident.
Five-minute schedule
Replace manual-only execution with an n8n Schedule Trigger that polls Sentinel for recent incidents.
Persistent deduplication
Use an n8n Data Table keyed by a stable Sentinel incident ID to track processing, completion and failure states.
Safe sequential processing
Queue or process incidents one at a time to avoid overlapping GPU-intensive investigations, especially during incident bursts.
Evidence validation
Capture intermediate MCP results and compare structured evidence against the generated report before Discord delivery.
At approximately 50 Sentinel incidents per day, the estimated inference workload is roughly 3–4 hours daily if each incident takes around four minutes. Actual capacity will depend on incident complexity, scheduling, retries and GPU performance.
What this project demonstrates
This PoC goes beyond prompting an LLM to summarise logs. It demonstrates an agent using a real MCP interface to query live security telemetry, adapt its investigation to the data returned, recover from at least some tool errors and communicate a useful SOC narrative through an existing messaging workflow.
The system is not production-ready, and its reports are not guaranteed to be fully accurate. As a homelab engineering project, however, it establishes a functioning integration across incident management, KQL, MCP, local inference, workflow automation and analyst-facing reporting—providing a practical foundation for unattended, evidence-checked incident triage.