Skip to main content

Tool-Semantics — Behavioral compatibility for agent tools

Tool-Semantics

Know when an MCP change breaks the agent — not just the schema.

Behavioral compatibility testing for MCP tools and AI-agent interfaces.

CI Python 3.11+ License Apache-2.0 Good first issues


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

Manifest → Snapshot → Diff Engine → Report

Tool-Semantics pipeline SVG

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

Tool-Semantics compare 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 / -v logs paths, tool counts, and change totals to stderr (default Rich UX unchanged).
  • --config loads ignore rules; if omitted, .tool-semantics.toml in the cwd is used when present.
  • capture-mcp speaks 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.

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

tool_semantics-0.2.0.tar.gz (2.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tool_semantics-0.2.0-py3-none-any.whl (25.5 kB view details)

Uploaded Python 3

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

Hashes for tool_semantics-0.2.0.tar.gz
Algorithm Hash digest
SHA256 eae4d54062810e4dc011ca987240852eb77682fc4c196a68ac74658914af8a5d
MD5 959aa54fdc95055aa01404c20ac97596
BLAKE2b-256 b599f6b9531b96dc1f8ddccb270f334ce0eaee2a287cf3d792ff83d7604b104f

See more details on using hashes here.

Provenance

The following attestation bundles were made for tool_semantics-0.2.0.tar.gz:

Publisher: publish.yml on askmy-stack/tool-semantics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for tool_semantics-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5227dba679f87bb6a120f5c6544d5404231597679233fe046496e19b0bc279bc
MD5 7878e79f0b1729a761a15e6c476b3748
BLAKE2b-256 315062334e30e725b40fda1117b9e89f55c732c92c02bf4bd3ffd511f2af2f6a

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page