Tool-Semantics
Know when an MCP change breaks the agent — not just the schema.
Behavioral compatibility testing for MCP tools and AI-agent interfaces.
Why Tool-Semantics?
AI agents do not call tools the way typed clients do. They choose tools from descriptions, invent arguments from schemas, and infer side effects from naming and prose. A change that remains JSON-Schema-valid can still:
- steer the model toward the wrong tool
- drop a required argument the model used to omit
- rename enums the model still emits
- quietly escalate from read-only to write/destructive behavior
Tool-Semantics captures normalized tool-interface snapshots and diffs them for structural and semantic risk — so teams can gate MCP and tool-API changes before agents ship broken workflows.
Compatibility layers
| Layer | Question |
|---|---|
| 1. Protocol | Can the client still speak to the server? |
| 2. Schema | Are parameters and types still valid? |
| 3. Tool selection | Will models still pick the right tool? |
| 4. Execution | Do calls still succeed with prior argument patterns? |
| 5. Intent / side effects | Did risk, confirmation needs, or outcomes change? |
The MVP implements deterministic interface snapshots and structural comparison (layers 1–2, with warnings that point at 3–5), plus local MCP capture over stdio. Remote MCP transport and model-based behavioral testing are on the roadmap.
How it works
flowchart LR
A[MCP / JSON manifest] --> B[Scanner]
B --> C[Normalized snapshot]
C --> D[Diff engine]
D --> E[Compatibility report]
E --> F[CLI / CI exit codes]
Quick start
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# Capture two interface versions
tool-semantics capture examples/github_server_v1.json -o .tool-semantics/v1.json
tool-semantics capture examples/github_server_v2.json -o .tool-semantics/v2.json
# Compare — exits 1 on breaking/critical changes
tool-semantics compare .tool-semantics/v1.json .tool-semantics/v2.json \
--markdown-output .tool-semantics/report.md
Demo
Example output
Comparing the included GitHub demo manifests surfaces removals, renames via addition, description drift, and newly required parameters:
Tool-Semantics: 1.0.0 → 2.0.0
┌──────────┬────────────────────────────┬─────────────────────────┬──────────────────────────────────────────┐
│ Severity │ Code │ Subject │ Change │
├──────────┼────────────────────────────┼─────────────────────────┼──────────────────────────────────────────┤
│ breaking │ tool.removed │ search_issues │ Tool 'search_issues' was removed. │
│ info │ tool.added │ find_work_items │ Tool 'find_work_items' was added; … │
│ warning │ tool.description_changed │ create_issue │ Tool description changed; … │
│ breaking │ parameter.added_required │ create_issue.repository │ Required parameter 'repository' was … │
└──────────┴────────────────────────────┴─────────────────────────┴──────────────────────────────────────────┘
Result: breaking
Install (library)
pip install tool-semantics
# or from source: pip install -e .
from pathlib import Path
from tool_semantics.scanner import capture_manifest
from tool_semantics.diff import compare_snapshots
from tool_semantics.report import render_markdown
baseline = capture_manifest(Path("examples/github_server_v1.json"))
candidate = capture_manifest(Path("examples/github_server_v2.json"))
report = compare_snapshots(baseline, candidate)
print(render_markdown(report))
print("compatible:", report.is_compatible)
Exit codes
| Code | Meaning |
|---|---|
0 |
Compatible (no breaking/critical changes) |
1 |
Breaking or critical changes detected |
2 |
Input / capture / parse error |
CLI reference
tool-semantics --version
tool-semantics capture <manifest.json> [-o .tool-semantics/snapshot.json] [-v]
tool-semantics capture-mcp -o snap.json -- python my_mcp_server.py
tool-semantics compare <baseline.json> <candidate.json> \
[--json-output report.json] \
[--markdown-output report.md] \
[--config .tool-semantics.toml] \
[-v]
--verbose/-vlogs paths, tool counts, and change totals to stderr (default Rich UX unchanged).--configloads ignore rules; if omitted,.tool-semantics.tomlin the cwd is used when present.capture-mcpspeaks MCP JSON-RPC over stdio; secrets-like keys are redacted by default.
JSON reports include changes, is_compatible, and counts by severity.
Change-code catalog: docs/change-codes.md.
Ignore-config schema: docs/config.md.
GitHub Action: docs/github-action.md.
Publishing: docs/publishing.md.
Migration adapters: docs/adapters.md.
Optional risk field
MCP does not standardize risk. Tool-Semantics accepts an optional tool-level risk
value (read_only, external_write, destructive, unknown). Missing values
default to unknown (no false escalation). See the GitHub demo manifests for
examples.
Offline probes
from pathlib import Path
from tool_semantics.scanner import capture_manifest
from tool_semantics.probes import Probe, ProbeKind, evaluate_probes
snapshot = capture_manifest(Path("examples/github_server_v1.json"))
report = evaluate_probes(
snapshot,
[
Probe(
id="search",
intent="find issues",
expected_tool="search_issues",
required_params=["query"],
kind=ProbeKind.POSITIVE,
)
],
)
assert report.passed
Project layout
src/tool_semantics/ # scanner, models, diff engine, report, CLI
examples/ # demo MCP-style manifests
tests/ # pytest suite
docs/assets/ # README visuals
Roadmap
See ROADMAP.md for milestones: remote MCP capture, richer compatibility rules, behavioral contracts, model matrices, PR reporting, and migration adapters.
Contributing
We welcome issues and PRs — especially documentation fixes, tests, and compatibility-rule ideas.
- Read CONTRIBUTING.md
- Follow the Code of Conduct
- Browse good first issues
Security
Do not auto-execute discovered MCP tools. See SECURITY.md for reporting guidance.
License
Apache License 2.0 — see LICENSE.
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 tool_semantics-0.2.0.tar.gz.
File metadata
- Download URL: tool_semantics-0.2.0.tar.gz
- Upload date:
- Size: 2.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eae4d54062810e4dc011ca987240852eb77682fc4c196a68ac74658914af8a5d
|
|
| MD5 |
959aa54fdc95055aa01404c20ac97596
|
|
| BLAKE2b-256 |
b599f6b9531b96dc1f8ddccb270f334ce0eaee2a287cf3d792ff83d7604b104f
|
Provenance
The following attestation bundles were made for tool_semantics-0.2.0.tar.gz:
Publisher:
publish.yml on askmy-stack/tool-semantics
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tool_semantics-0.2.0.tar.gz -
Subject digest:
eae4d54062810e4dc011ca987240852eb77682fc4c196a68ac74658914af8a5d - Sigstore transparency entry: 2443395383
- Sigstore integration time:
-
Permalink:
askmy-stack/tool-semantics@179d4cb55c4f2f5b5731f78b1e213f98035608a5 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/askmy-stack
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@179d4cb55c4f2f5b5731f78b1e213f98035608a5 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file tool_semantics-0.2.0-py3-none-any.whl.
File metadata
- Download URL: tool_semantics-0.2.0-py3-none-any.whl
- Upload date:
- Size: 25.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 |
5227dba679f87bb6a120f5c6544d5404231597679233fe046496e19b0bc279bc
|
|
| MD5 |
7878e79f0b1729a761a15e6c476b3748
|
|
| BLAKE2b-256 |
315062334e30e725b40fda1117b9e89f55c732c92c02bf4bd3ffd511f2af2f6a
|
Provenance
The following attestation bundles were made for tool_semantics-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on askmy-stack/tool-semantics
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tool_semantics-0.2.0-py3-none-any.whl -
Subject digest:
5227dba679f87bb6a120f5c6544d5404231597679233fe046496e19b0bc279bc - Sigstore transparency entry: 2443395455
- Sigstore integration time:
-
Permalink:
askmy-stack/tool-semantics@179d4cb55c4f2f5b5731f78b1e213f98035608a5 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/askmy-stack
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@179d4cb55c4f2f5b5731f78b1e213f98035608a5 -
Trigger Event:
workflow_dispatch
-
Statement type: