PolicyGraph is a safety-first MCP host and single-step agent runtime for tool-mediated LLM interactions designed for enterprise-style and regulated environments.
It enforces safety and governance guarantees by construction, rather than relying on model behavior alone.
Key properties:
- default-deny tool execution (operator-controlled allowlist)
- schema-constrained planning (LLM must output a strict JSON plan)
- typed tool outputs (Pydantic parsing)
- evidence-locked summaries (summaries must quote verbatim evidence)
- deterministic control flow (workflow-level determinism with replayable execution traces)
- audit-friendly traces (structured per-run trace artifacts)
The design is intentionally narrow:
- at most one tool call per user request
- read-only tools are the default assumption
- no autonomous multi-step loops, memory, or background jobs
This scope supports a publishable research artifact with:
- a concrete threat model,
- enforceable safety guarantees,
- and reproducible evaluations.
See docs/quickstart.md.
PolicyGraph is not a new LLM or agent framework.
Its contribution is a governed execution model for MCP tools that enforces safety properties independently of model correctness:
- Default-deny tool execution using an operator-controlled allowlist
- Schema-constrained planning and execution that rejects malformed or unauthorized plans before tool invocation
- Evidence-locked summarization, where every generated claim must include verbatim evidence from tool output
- Audit-ready trace artifacts emitted for every run
These guarantees hold even if the planner model is compromised or adversarial.
- Policy gate (input)
- Blocks obviously unsafe requests before any tool discovery or execution.
- Operator allowlist (default deny)
- A tool is callable only if it is:
- discovered live from MCP servers (
tools/list), and - explicitly listed in
config/allowlist.json.
- discovered live from MCP servers (
- Strict JSON plan
- The planner must emit exactly one of:
{ "type": "call_tool", "server": "...", "tool": "...", "args": {...} }{ "type": "final_answer", "answer": "...", "needs_more_info": true }
- Schema validation
- Tool arguments must match the MCP
inputSchemaexactly:- required fields present
- no extra keys
- correct types
- Typed output parsing
- Tool outputs are parsed into tool-specific Pydantic models.
- Invalid or unexpected outputs are rejected.
- Grounded summaries
- Each summary bullet must include an
evidencefield that is a verbatim substring of the tool output. - Unsupported claims are rejected by construction.
This project intentionally does not address:
- multi-step autonomous agents
- long-term memory or learning
- retrieval routing or RAG optimization
- Kubernetes orchestration or observability pipelines
These are deferred to future work and a separate platform-level implementation.
-
Tool allowlist
- Path:
config/allowlist.json - Override with:
SAFE_ALLOWLIST_PATH
- Path:
-
Tracing
- Set
SAFE_TRACE_DIR=eval/tracesto persist per-run JSON traces
- Set
-
Summarization
- Set
SAFE_SUMMARIZE=1(or ask a query containing “summarize”)
- Set
Runs locally without MCP servers or an LLM.
These tests validate safety gates independently of model behavior, demonstrating enforcement even under adversarial or malformed inputs.
python -m src.eval.offline_gate_evalWrites results to:
eval/results/offline_gate_eval.json
SAFE_TRACE_DIR=eval/traces \
python -m src.eval.end_to_end_eval --cases eval/cases_end_to_end.jsonlThis compares:
MultiMCPHost.ask_once(SAFE) vssrc.eval.naive_agent.naive_ask_once(baseline)
Outputs:
eval/results/<timestamp>_metrics.jsoneval/results/<timestamp>_runs.jsonleval/results/<timestamp>_table.md
src/host/— MCP host, policy gate, planner/validator, typed parsing, grounded summarization, tracingsrc/graph/— LangGraph single-step state machine (optional)services/— toy MCP servers (SharePoint, ServiceNow, Policy KB)config/— operator allowlisteval/— evaluation cases + results outputdocs/— architecture + threat model + contracts
docs/architecture.mddocs/agent-contract.mddocs/safety-threat-model.mddocs/tool-contracts.md
Apache-2.0