assurance-mcp
Give your agent a way to find out what it missed.
An agent cannot audit its own reading. Ask one whether it saw everything and it will tell you yes, because from the inside a complete answer and an answer built on two thirds of the data feel identical. These tools answer that from the outside, in arithmetic, with no model involved.
Read-only by construction. No writes, no deletes, no network, no telemetry. Proven by
test_the_server_never_writes in this repository: no tool opens a file for writing, and no
requests, urllib, shutil, os.remove, os.replace or symlink_to call exists in the package.
Install
python3 -m venv .venv
source .venv/bin/activate
pip install assurance-mcp
Python 3.10 or newer. Pulls in assurance-core for the
decision logic and assurance-cli for the filesystem I/O.
Configure your MCP client
Cursor (~/.cursor/mcp.json), Claude Desktop, or any MCP client:
{
"mcpServers": {
"assurance": {
"command": "/absolute/path/to/.venv/bin/python",
"args": ["-m", "assurance_mcp.server"],
"env": {}
}
}
}
Restart the client. You should see four tools.
Tools
| Tool | What it answers | Needs a folder? |
|---|---|---|
check_set_coverage_tool |
Did the run cover everything it was supposed to, over any two sets of keys? | No |
check_coverage_tool |
Which periods are present in a folder of dated files, and which are not? | Yes |
check_staleness_tool |
Do a document's figures still match a source file the caller names? | Yes |
list_dated_files_tool |
Which reporting periods does this folder hold? | Yes |
check_set_coverage_tool — the one that fits your problem
The other three are folder-shaped, which answers one question well and most questions not at all. This one takes two lists the agent already holds. Keys are anything you can name.
You: Before you answer, check what you retrieved against what the question spans.
Agent: check_set_coverage_tool(
expected = ["acme/msa.md", "acme/amendment-1.md", "acme/amendment-2.md", "acme/amendment-3.md"],
found = ["acme/msa.md", "acme/amendment-1.md", "globex/msa.md"],
scope = "documents this question spans",
where = "the retrieved set",
derivation = "metadata filter tenant=acme, top_k=3")
→ { "complete": false, "read": 2, "required": 4,
"summary": "2 of 4 documents this question spans — not in the retrieved set:
acme/amendment-2.md, acme/amendment-3.md — metadata filter tenant=acme, top_k=3",
"missing": [{"key": "acme/amendment-2.md", ...}, {"key": "acme/amendment-3.md", ...}],
"unexpected": ["globex/msa.md"] }
Agent: I've read 2 of the 4 documents this question spans. Amendment 2 and amendment 3 were not
retrieved, and the terms may have changed in them — I shouldn't answer yet. I also pulled a
Globex document into an Acme question, which I've discarded.
That is a different sentence from any an agent produces on its own, and it is the sentence that stops a wrong answer from being delivered confidently.
Use it for: retrieved chunks against documents the question spans · files reviewed against
git diff --name-only · controls with evidence against controls in scope · partitions loaded
against partitions declared · eval cases run against cases declared · records processed against
records enumerated.
expected is your declaration and is never inferred here. A denominator the tool invents is a
denominator nobody can argue with.
check_coverage_tool — a folder of dated files
You: Check coverage on ~/reports
Agent: check_coverage_tool("/Users/you/reports")
→ { "complete": false,
"summary": "22 of 24 months from 2024-01 to 2025-12 in reports —
not in this folder: March 2025, July 2025 —
Range inferred from filenames: earliest 2024-01, latest 2025-12.",
"coverage": { "read": 22, "required": 24,
"missing": [{"key": "2025-03", "label": "March 2025"},
{"key": "2025-07", "label": "July 2025"}] } }
Agent: 22 of 24 months are present. March 2025 and July 2025 are not in this folder.
Monthly, quarterly, weekly, daily and numbered runs (INV-0001, run_042) are all recognised. The
derivation is returned with the ratio so the agent can surface a denominator you can disagree
with, rather than only a result.
Works from a cold start — no prior state, no database, no model, no key.
Hard limits (honest)
- CSV and TSV only for profiling — no XLSX dependency in this package
- Staleness needs recorded facts — pass
recorded_facts, or the document must be readable tabular data; otherwise the answer isuncheckable, never silence - No cross-document inference. Comparing figures across files that merely look related produced 21 false positives on a real corpus, so this package refuses to do it
- The caller names the folder boundary — paths cannot escape it via
..or a symlink check_set_coverage_toolnever invents your expected set, which is the whole point of it
Also in this family
- assurance-core — the pure decision modules, zero dependencies
- assurance-cli — the same checks as a command, for CI
Run the tests
pip install -e ".[dev]" && python -m pytest -q
Licence
Apache-2.0. See LICENSE. Upstream is I-Ops; this repo is a publication, never a source.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file assurance_mcp-0.2.0.tar.gz.
File metadata
- Download URL: assurance_mcp-0.2.0.tar.gz
- Upload date:
- Size: 15.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f959938084c172ff9595282e774e06061bbae7b3e8924da711a52868cc7f410
|
|
| MD5 |
32f01dc51e02a3a369b56adbac07fd1c
|
|
| BLAKE2b-256 |
297ad7302eba248d433a0c63a8d779322388dc9ed515bc484bc9d2837c2f5c6c
|
Provenance
The following attestation bundles were made for assurance_mcp-0.2.0.tar.gz:
Publisher:
publish.yml on i-ops-hq/assurance-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
assurance_mcp-0.2.0.tar.gz -
Subject digest:
1f959938084c172ff9595282e774e06061bbae7b3e8924da711a52868cc7f410 - Sigstore transparency entry: 2643247164
- Sigstore integration time:
-
Permalink:
i-ops-hq/assurance-mcp@06b535c0e043da94c7ab66c29118bf3a1f90b202 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/i-ops-hq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@06b535c0e043da94c7ab66c29118bf3a1f90b202 -
Trigger Event:
push
-
Statement type:
File details
Details for the file assurance_mcp-0.2.0-py3-none-any.whl.
File metadata
- Download URL: assurance_mcp-0.2.0-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5987afa9a62877b7d77a5181b36d86f12005e39ebd8edfc338e3f3807907610
|
|
| MD5 |
337eaa58a5f0f2646461b25e6ea9ad8e
|
|
| BLAKE2b-256 |
ca801c1eab6068bd733c1924562b1d1db7d75f927ced6c31ecaec2d554b9adfb
|
Provenance
The following attestation bundles were made for assurance_mcp-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on i-ops-hq/assurance-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
assurance_mcp-0.2.0-py3-none-any.whl -
Subject digest:
a5987afa9a62877b7d77a5181b36d86f12005e39ebd8edfc338e3f3807907610 - Sigstore transparency entry: 2643247458
- Sigstore integration time:
-
Permalink:
i-ops-hq/assurance-mcp@06b535c0e043da94c7ab66c29118bf3a1f90b202 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/i-ops-hq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@06b535c0e043da94c7ab66c29118bf3a1f90b202 -
Trigger Event:
push
-
Statement type: