https://github.com/msradam/triage-agent
A support-triage MCP agent built with BurrMCP: investigate before you decide, enforced by the state-machine graph.
https://github.com/msradam/triage-agent
apache-burr burrmcp example llm-agents mcp model-context-protocol state-machine
Last synced: about 7 hours ago
JSON representation
A support-triage MCP agent built with BurrMCP: investigate before you decide, enforced by the state-machine graph.
- Host: GitHub
- URL: https://github.com/msradam/triage-agent
- Owner: msradam
- Created: 2026-05-25T02:20:24.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-05-25T03:03:48.000Z (about 1 month ago)
- Last Synced: 2026-05-25T04:27:08.173Z (about 1 month ago)
- Topics: apache-burr, burrmcp, example, llm-agents, mcp, model-context-protocol, state-machine
- Language: Python
- Size: 999 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# triage-agent
A support-ticket triage agent built with
[Theodosia](https://github.com/msradam/theodosia): a triage workflow defined as a
[Burr](https://burr.dagworks.io/) state machine and served as an
[MCP](https://modelcontextprotocol.io/) server. An LLM classifies the ticket,
gathers context, and decides, one enforced transition at a time.
```mermaid
stateDiagram-v2
[*] --> classify
classify --> gather_context
gather_context --> gather_context
gather_context --> resolve
gather_context --> escalate
resolve --> [*]
escalate --> [*]
```
This diagram is the contract. The agent can only move along these edges; the
server refuses any step that is not a reachable transition. The gate is
structural: there is no edge from `classify` straight to `resolve` or
`escalate`, so an agent that tries to close a ticket before gathering any
context gets a refusal. This is the step up from a toy: a real "investigate
before you decide" policy, enforced by the graph rather than asked of the model.
An LLM drives it over MCP. Here fast-agent connects a Llama-3.3-70B model
(on Together); when the model calls an action with the wrong inputs, the server
returns a structured error and the model corrects itself:

The same workflow is observable from the terminal. `triage-agent render` prints
the graph; `triage-agent sessions show` replays a recorded run:

## Install
```bash
git clone https://github.com/msradam/triage-agent.git
cd triage-agent
uv venv --python 3.13
uv pip install -e .
```
## Run it as an agent
The repo ships an `.mcp.json` pointing a client at `triage-agent serve`.
### Claude Code
```bash
claude mcp add --transport stdio triage-agent -- uv run triage-agent serve
claude
```
Then: "A customer was double-charged. Triage it." Claude classifies, records
findings with `gather_context`, then resolves or escalates.
### fast-agent (terminal REPL)
The repo ships a `fastagent.config.yaml` defining this server, so:
```bash
uvx fast-agent-mcp go --servers triage-agent -m "A customer was double-charged. Triage it."
```
It uses Gemini by default (set `GOOGLE_API_KEY`). To drive it with a Together
model instead, set `GENERIC_API_KEY` and add
`--model generic.meta-llama/Llama-3.3-70B-Instruct-Turbo`.
### MCPJam (one npx command, browser playground, free models)
```bash
npx @mcpjam/inspector
```
Add the server with command `uv`, args `run triage-agent serve`.
## Watch what it did
```bash
uv run triage-agent sessions show # per-step timeline; refused decisions in red
uv run triage-agent watch # live-tail
```
Every step and refusal is also hash-chained into a tamper-evident `ledger.jsonl`
next to the session's tracker log. Recompute the chain and confirm nothing was
edited, reordered, or deleted after the fact with:
```bash
uv run triage-agent verify # exits nonzero and names the broken line if the chain is altered
```
## License
Apache 2.0. Built on [Theodosia](https://github.com/msradam/theodosia),
[Apache Burr](https://github.com/apache/burr), and
[FastMCP](https://github.com/jlowin/fastmcp).