ticket-triage-mcp
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., "@ticket-triage-mcpLook up customer account for email jane@example.com"
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.
AI Ticket Triage Agent — LangGraph + MCP
A production-shaped support workflow that classifies messy requests, extracts evidence from PDF attachments, calls two internal systems through MCP, drafts a grounded reply, and routes uncertain cases to a human instead of guessing.
Evaluation scorecard
Stage | Result |
Classification accuracy | 100% (20/20) |
Field extraction F1 | 100% |
Draft policy checks | 100% |
Deliberately unanswerable cases escalated | 100% (5/5) |
Case-specific escalation reasons | 100% (5/5) |
False escalation rate | 0% (0/15) |
Runtime error rate | 0% |
Offline latency | 4.6 ms p50 / 6.7 ms p95 |
These are reproducible results from the committed synthetic corpus, measured on a local Windows
development machine. Latency varies by hardware; the evaluator reports every per-case result in
artifacts/scorecard.json. The five hard cases cover missing evidence,
conflicting identifiers, an unreadable attachment, an ambiguous request, and a record absent from
the internal system. The artifact also records its generation time, corpus hash, Python version,
commit identifier, and tool transport so stale results are visible.
Why this project exists
Most agent demos show only the happy path. This one makes abstention a tested behavior. The agent can return one of two bounded outcomes:
drafted— required identifiers were extracted, both read-only MCP checks completed, and the supplied references were verified.escalated— confidence or evidence failed policy, so the agent emits a non-committal holding response, a human queue, the missing evidence, and an auditable reason.
That decision is not hidden in a prompt. It is an explicit conditional edge in the LangGraph state machine and a metric in CI.
What it does
Email + PDF
│
▼
classify ──► extract ──► intake safety gate
│
unsafe ───┴─── safe
│ │
▼ ▼
human queue MCP tool 1: customer account
│
MCP tool 2: billing / incident
│
post-tool safety gate
│ │
unverified verified
│ │
▼ ▼
human queue grounded draftThe two MCP tools are deliberately narrow and read-only:
lookup_customer_accountperforms an exact account/email match.lookup_billing_or_incidentchecks billing, service incident, or bounded support context.
The graph always uses one transport-neutral MCP tool contract. Offline evaluation uses the fast in-process adapter; Docker Compose runs the portfolio UI against a persistent, real JSON-RPC-over-stdio MCP server. Both transports are integration-tested, so orchestration never depends on the deployment choice.
Run it locally
Prerequisites: Python 3.11–3.13 and uv.
git clone https://github.com/Mohemed-Amine-Chalhy/ai-ticket-triage.git
cd ai-ticket-triage
uv sync --extra dev --locked
uv run uvicorn ai_ticket_triage.web:app --reloadOpen http://127.0.0.1:8000. The web UI includes all 20 labelled examples, a PDF uploader, the graph trace, extracted fields, MCP call evidence, the final decision, and the scorecard.
The command above uses the fast in-process adapter. To run the exact UI shown in the MCP demo, start the locked container instead; Compose enables the persistent stdio server by default:
docker compose up --buildRegenerate all four portfolio proof images from the current scorecard and an actual verbose test run:
make proofNo API key is required. All names, emails, accounts, invoices, services, and incidents are fake;
emails use the reserved example.test domain.
CLI demo
Run an answerable fixture:
uv run ticket-triage triage --case billing_duplicate_chargeRun a failure case and inspect the human handoff:
uv run ticket-triage triage --case failure_unreadable_attachmentRun a real PDF:
uv run ticket-triage triage \
--text "I was charged twice; details are attached." \
--pdf data/sample_attachments/duplicate-charge.pdfExercise the actual stdio MCP boundary:
uv run ticket-triage triage \
--case billing_duplicate_charge \
--transport stdioReproduce the scorecard
uv run ticket-triage-eval \
--output artifacts/scorecard.json \
--markdown-output artifacts/scorecard.md \
--fail-on-runtime-error \
--enforce-portfolio-targetsThe evaluator scores each stage independently: exact category match, micro field-level F1, declarative draft checks, semantic handoff-reason grounding, escalation precision/recall, false escalations, runtime failures, and p50/p95/max latency. See Evaluation methodology.
Use the MCP server independently
Start the bundled official-SDK server over stdio:
uv run ticket-triage-mcpExample configuration for a local stdio MCP host:
{
"mcpServers": {
"ticket-triage-tools": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/ai-ticket-triage",
"run",
"ticket-triage-mcp"
]
}
}
}This is a transport-neutral tool boundary: another compatible agent or desktop host can use the same two contracts without importing the LangGraph application. For remote hosts, put the server behind an authenticated Streamable HTTP deployment; the portfolio demo intentionally exposes only local stdio and in-process transports.
Engineering choices
Concern | Implementation |
Orchestration | Compiled |
Safety | Two policy gates; low confidence, conflicts, missing evidence, unreadable files, tool failures, and misses all escalate |
Documents |
|
Tool boundary | Official MCP Python SDK, exactly two read-only tools, normalized error envelopes, timeouts |
Contracts | Pydantic models with forbidden extra fields and JSON-safe public results |
Evaluation | 20 versioned JSON labels, per-stage metrics, case diagnostics, runtime-error capture |
API | FastAPI, generated OpenAPI docs, upload limits, request IDs, safe error responses, security headers |
Operations | Locked dependencies, Docker health check, structured logs, CI lint/type/test/coverage gates |
Privacy | Synthetic fixtures only; raw PDF bytes are excluded from model serialization |
Deterministic by design
The default classifier, extractor, and draft composer are deterministic. That makes safety regressions reproducible, keeps the public demo credential-free, and separates workflow quality from model variance. A hosted model can replace those nodes behind the same typed contracts; in a real rollout, its candidate outputs should still pass through the same evidence and tool gates. This repository does not claim that a 20-case synthetic benchmark predicts live-data quality.
Repository map
src/ai_ticket_triage/
├── agent.py # LangGraph state machine and tool orchestration
├── classifier.py # deterministic category scoring with evidence
├── extractor.py # PDF/text extraction and conflict detection
├── confidence.py # bounded-failure policy gates
├── drafting.py # grounded replies and safe holding responses
├── mcp_server.py # official MCP server; exactly two tools
├── mcp_client.py # in-process and real stdio MCP gateways
├── internal_api.py # mock read-only service adapters
├── evaluation.py # corpus runner and scorecard metrics
├── web.py # FastAPI application
└── static/ # responsive portfolio UI
data/cases/ # 20 synthetic labelled fixtures
tests/ # unit, API, workflow, evaluator, and MCP integration tests
artifacts/ # committed scorecard and proof outputs
assets/ # portfolio-ready architecture and result images
docs/ # architecture, evaluation, security, runbook, portfolio copyQuality commands
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pytest --cov=ai_ticket_triage --cov-report=term-missing
uv run ticket-triage-eval --fail-on-runtime-error --enforce-portfolio-targets
docker compose up --buildDocumentation
Known limits
Text-based PDFs only; scanned documents need OCR and a malware-scanning pipeline.
Synthetic exact-match internal systems, not a live CRM or billing platform.
English fixtures and a four-class taxonomy.
No durable queue, authentication, rate limiting, or distributed tracing in this local demo.
Deterministic language logic is a reliability baseline, not a substitute for evaluation on a representative, privacy-reviewed production dataset.
Those omissions are intentional weekend-project boundaries. The interfaces isolate each missing production concern so it can be added without rewriting the graph.
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
Read-only Frasma MCP: profile, knowledge search, diagnostic handoff. No email.
A paid remote MCP for AI SDK data query MCP, built to return verdicts, receipts, usage logs, and aud
Read-only MCP access to sessions, funnels, campaigns, errors, live visitors, and anomalies.
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/Mohemed-Amine-Chalhy/ai-ticket-triage'
If you have feedback or need assistance with the MCP directory API, please join our Discord server