Skip to main content

MCP Tool Poisoning Scanner — Defensive scanning + offensive pentest tooling for MCP servers. Maps to OWASP MCP Top 10.

Project description

MCP Tool Auditor

Scan MCP server tool definitions for poisoning, injection, and OWASP MCP Top 10 vulnerabilities.

CI PyPI Python 3.10+ License: MIT OWASP MCP Top 10

Most MCP scanners read tool definitions. This one also watches tool behavior — it calls tools and catches Advanced Tool Poisoning Attacks (ATPA) that look benign on paper and turn malicious at runtime.

mcp-tool-auditor is a comprehensive security scanner for Model Context Protocol (MCP) servers. It detects tool poisoning, full-schema poisoning (FSP), rug-pull attacks (including tool shadowing and tampered baselines), cross-tool composition risk, and ATPA (Advanced Tool Poisoning Attacks) — across tool, resource, prompt, and server-instruction definitions, not just tool descriptions — while mapping findings to the OWASP MCP Top 10 framework.

The project also includes authorized offensive tooling for penetration testers and security researchers to simulate realistic MCP attack scenarios in controlled environments.


Features

Defensive Scanner

Feature What It Detects
Static Signatures 40+ patterns such as "ignore security", "always use this tool", "send full conversation", and "authoritative source"
Heuristic Analysis Imperative language scoring, authority spoofing, Unicode hidden characters, and excessive agency claims
Multi-Surface Scanning The same signature/heuristic engine also runs on resources, prompts, and the server's initialize instructions string — not just tool descriptions
Schema Anomaly Detection Full-Schema Poisoning (FSP), sidenote parameter injection, enum injection, poisoned defaults, and required-array abuse
Special Token Injection (STI) Chat-template control tokens (<|im_start|>, [INST], DeepSeek's fullwidth <|User|>, ...) via exact/Unicode-normalized/structural/encoded matching, plus an optional real-tokenizer-backed tier — in definitions and tool call output
Cross-Tool Composition Risk Flags a server exposing both a sensitive-data-access tool and an egress-capable tool — individually benign, chainable into exfiltration
Rug-Pull Detection HMAC-signed SHA-256 schema fingerprinting; check detects both unexpected tool changes and tampered baseline files
Behavioral / ATPA Detection Calls tools and inspects responses for the benign→malicious time-bomb signature, output injection, and exfil instructions
LLM Semantic Judge (opt-in) --llm-judge sends descriptions to Claude to catch paraphrased poisoning that dodges static signatures
OAuth 2.1 Detection Reports MCP 2025-06-18 OAuth-protected servers clearly (401 + WWW-Authenticate) instead of a generic error
Continuous Monitoring watch re-scans on an interval and alerts a webhook on newly-observed findings
Engagement Scope Guardrails --engagement refuses to scan targets outside an authorized-scope file
Client-Ready Reporting --format pentest — engagement header, executive summary, methodology, evidence, remediation
Retest Workflow retest --baseline <report> diffs a re-scan into Fixed / Still Present / New
OWASP Mapping Labels findings across the OWASP MCP Top 10 (active detection for MCP01, MCP02, MCP03, MCP05)

Offensive Tooling

Tool What It Simulates
Description Injection Server Classic Tool Poisoning Attacks using malicious tool descriptions
FSP Generator CyberArk-style schema poisoning variants
ATPA Server Behavioral poisoning that becomes malicious after a configurable threshold
Rug-Pull Server Serves clean tools initially, then swaps to malicious definitions
Tool Shadowing Server Mimics trusted tool names while embedding injected payloads
STI Simulation Server Benign tool definitions; injects a chat-template control token into responses after a configurable call threshold

Installation

From PyPI (recommended)

pip install mcp-tool-auditor

Or run it without installing anything into your environment, via uv:

uvx mcp-tool-auditor --help

The default install is offline and needs no API key or token — it's pyyaml and requests, nothing else. The optional LLM semantic judge (--llm-judge) is a separate extra so it doesn't pull in an API client or require credentials for everyone:

pip install 'mcp-tool-auditor[llm]'

From source (development)

git clone https://github.com/perparimmjeku/mcp-auditor.git
cd mcp-auditor
python -m pip install -e ".[dev]"
python -m pytest

See CONTRIBUTING.md for the full development workflow and RELEASING.md for how versions get published to PyPI.


Quick Start

Scan an MCP Server

mcp-tool-auditor scan url http://localhost:8080/mcp

Generate a Markdown Report

mcp-tool-auditor scan url http://localhost:8080/mcp \
  --format markdown \
  -o report.md

Scan MCP Servers from a Configuration File

mcp-tool-auditor scan config \
  ~/.config/Claude/claude_desktop_config.json

Register a Baseline Fingerprint

mcp-tool-auditor register url http://localhost:8080/mcp

Baselines are HMAC-SHA256 signed, so check can tell a legitimate tool change from a tampered/forged baseline file (RUGPULL_BASELINE_TAMPERED). By default the signing key is a local file (~/.mcp-tool-auditor/fingerprints/.hmac_key); for CI use, supply your own out-of-band key so the key and the baseline file don't share a trust boundary:

export MCP_TOOL_AUDITOR_BASELINE_KEY="$(openssl rand -hex 32)"   # store in your CI secrets

Check for Rug-Pull Changes

mcp-tool-auditor check url http://localhost:8080/mcp

Continuous Monitoring

Point-in-time scans miss drift that happens between runs. watch re-scans on an interval and POSTs newly-observed findings to a webhook (Slack/Discord/PagerDuty/anything with a webhook endpoint):

mcp-tool-auditor watch url http://localhost:8080/mcp \
  --interval 300 \
  --check-rugpull \
  --webhook https://hooks.example.com/services/T000/B000/XXXX

Each finding is alerted once (in-memory dedup for the process's lifetime), so a standing issue doesn't repeat-alert every interval.

Behavioral / ATPA Detection

Static scans read tool definitions; behavioral probing actually calls tools and inspects their responses to catch Advanced Tool Poisoning Attacks (ATPA) — tools that act benign, then return poisoned output after a few calls.

# Live probe (executes real tool calls — authorized testing only)
mcp-tool-auditor behavior url http://localhost:8080/mcp --calls 6 --yes
mcp-tool-auditor behavior stdio --calls 6 -- npx @modelcontextprotocol/server-everything

# Offline: analyze a recorded transcript (tool name -> list of response strings)
mcp-tool-auditor behavior import responses.json --format json

Findings: BEHAV_ATPA_TRANSITION (benign→malicious time-bomb), BEHAV_OUTPUT_INJECTION, BEHAV_RESPONSE_DIVERGENCE, and BEHAV_CALL_ERROR. Live modes require an authorization acknowledgement (--yes or MCP_TOOL_AUDITOR_ASSUME_AUTHORIZED=1).

Authenticated Scanning (real engagements)

# Auth header + route through Burp; tune signal with confidence and suppressions
mcp-tool-auditor scan url https://target/mcp \
  -H "Authorization: Bearer $TOKEN" \
  --proxy http://127.0.0.1:8080 \
  --min-confidence HIGH \
  --suppress HEUR_IMPERATIVE

Findings carry a confidence level (HIGH/MEDIUM/LOW); --min-confidence filters noisy heuristics and --suppressions <file> silences accepted false positives. URL transport speaks full MCP Streamable HTTP (session id + protocol-version headers) at protocol version 2025-06-18. If the server requires OAuth 2.1, the scan reports a clear OAUTH_REQUIRED finding (with protected-resource metadata, if discoverable) instead of a generic HTTP error — complete the OAuth flow yourself and pass the resulting bearer token via --header; this tool does not perform interactive OAuth login.

LLM Semantic Judge (opt-in)

Static signatures and heuristics match fixed phrases; an attacker can dodge them by rephrasing the same intent differently. --llm-judge sends tool/resource/prompt text to Claude and asks it to judge intent instead of pattern-match text:

pip install 'mcp-tool-auditor[llm]'
export ANTHROPIC_API_KEY="sk-ant-..."
mcp-tool-auditor scan url http://localhost:8080/mcp --llm-judge

This is opt-in only and never runs by default — it sends third-party server content to Anthropic's API, which is a data-handling decision the operator must make explicitly. Flagged items get the LLM_SEMANTIC_POISONING rule (MEDIUM confidence; review the exact wording before rejecting a tool on this alone).

Real Pentest Engagements: Scope, Client Reports, Retest

Three pieces built specifically for running this as part of a real, authorized engagement rather than a CI job:

1. Engagement/scope file — declare the authorized scope once; scans against a stdio/url target outside it are refused before anything touches the network:

{
  "client": "Acme Corp",
  "tester": "J. Doe",
  "start_date": "2026-07-01",
  "end_date": "2026-07-15",
  "notes": "Authorized MCP tool poisoning assessment, ref. SOW-1234",
  "allowed_targets": ["https://*.acme-client.example.com/*", "https://mcp.acme.example.com/mcp"]
}
mcp-tool-auditor --engagement engagement.json scan url https://mcp.acme.example.com/mcp
# scan url https://other-company.example.com/mcp would be refused before connecting

allowed_targets entries are exact strings or shell-glob patterns. An engagement file with no allowed_targets still works — it just carries report metadata (client/tester/ dates) without restricting scope. Scope is enforced for scan stdio/url, behavior stdio/url, watch url, register, and check; scan config/local/watch config don't currently enforce it per-server since they aggregate arbitrary local configs.

2. Client-ready reports--format pentest produces an engagement header, executive summary, methodology section, and full evidence (the actual tool/resource/ prompt text) plus remediation guidance per finding — built to hand to a client, not just a CI log:

mcp-tool-auditor --engagement engagement.json scan url https://mcp.acme.example.com/mcp \
  --format pentest -o report.md

3. Retest — after the client remediates, re-scan and diff against the original report to show what's Fixed / Still Present / New:

mcp-tool-auditor scan url https://mcp.acme.example.com/mcp --format json -o baseline.json
# ... client remediates ...
mcp-tool-auditor retest --baseline baseline.json url https://mcp.acme.example.com/mcp \
  --format pentest -o retest-report.md

--fail-on on retest gates on unresolved findings only (Still Present + New) — a clean retest where everything's Fixed exits 0.

Auto-Discover and Scan Local MCP Configs

# Finds and scans configs for Claude Desktop, Cursor, VS Code, Windsurf, Zed
mcp-tool-auditor scan local

Export SARIF and Explain Findings

# SARIF for GitHub code-scanning / GitLab / DefectDojo ingestion
mcp-tool-auditor scan import tools.json --format sarif -o results.sarif

# Get remediation guidance for any finding rule
mcp-tool-auditor explain BEHAV_ATPA_TRANSITION
mcp-tool-auditor explain --list

SARIF 2.1.0 output is deterministic — driver.rules[] sorted by rule id and results[] sorted by (ruleId, tool_name, field, message), so re-scanning unchanged findings produces byte-identical output and diffs cleanly in CI. Each reportingDescriptor carries helpUri (links docs/RULES.md) alongside the existing remediation text, plus an empty atlas_ids placeholder in properties so a future MITRE ATLAS mapping can be added without a schema change. Each result's properties bag carries owasp_id, attack_type, confidence, and retest_status (present — null on a plain scan, set on retest --format sarif) so nothing from a Finding is lost in translation, and DefectDojo's generic SARIF importer picks all of it up.

Source-Scan (Prompt-In-Shell-Out)

Goes one level deeper than definitions/behavior: reads an MCP server's source code (Python via AST, JS/TS via heuristics) and flags shell-injection sinks fed by LLM-controlled tool arguments — subprocess(shell=True), os.system, child_process.exec, etc.

mcp-tool-auditor source-scan ./my-mcp-server                 # human-readable
mcp-tool-auditor source-scan ./my-mcp-server --format sarif  # code-scanning
mcp-tool-auditor source-scan ./my-mcp-server --fail-on CRITICAL  # CI gate

It only opens files that import an MCP SDK, so it won't flag shell calls in unrelated code.

Special Token Injection (STI)

Chat-template control tokens (<|im_start|>, [INST], <|start_header_id|>, DeepSeek's fullwidth <|User|>, and more — registry in signatures/sti_tokens.yaml, grouped by model family, easy to extend via PR) spoof or close a conversation turn in whatever prompt an MCP client eventually builds from tool/resource/prompt text. Runs by default across all four surfaces, plus tool call output (behavior command) to catch a token a tool only emits after N calls:

mcp-tool-auditor scan url http://localhost:8080/mcp          # exact/normalized/structural tiers
mcp-tool-auditor scan url http://localhost:8080/mcp --sti-decode  # + bounded base64/hex tier
mcp-tool-auditor behavior url http://localhost:8080/mcp --calls 6 --yes  # scans tool output too

--sti-decode is opt-in and off by default: it only considers length-banded base64/hex substrings (never "decode every string"), and only compares decoded bytes against the token registry, never the looser structural shape check — bounding both cost and false positives. Findings: STI_EXACT/STI_NORMALIZED (HIGH confidence — obfuscation is more suspicious than the plain token, not less), STI_STRUCTURAL/STI_ENCODED (MEDIUM). A tool that legitimately documents a token (e.g. a Llama-2 prompt-formatting helper mentioning [INST]) still produces a finding — detection can't tell intent from text alone — but it's suppressible like any other rule (--suppress STI_EXACT or a suppressions file entry).

Tokenizer-Aware STI (optional)

The tiers above answer "does this text look like a known control token?" by string matching. --sti-tokenizer answers a stronger question: will this string actually be parsed as a special token by the tokenizer a target deployment runs, rather than being split into ordinary byte-pair pieces? That's deployment-relative — <|im_start|> is one reserved token under ChatML/Qwen and inert plaintext under a tokenizer that's never heard of it — and it requires a real tokenizer's real vocabulary to answer; no amount of string-matching against our own token registry can (seeding a tokenizer with our own strings and checking they round-trip would only ever confirm what the string tiers already catch).

pip install 'mcp-tool-auditor[tokenizers]'
mcp-tool-auditor scan url http://localhost:8080/mcp --sti-tokenizer chatml,mistral

--sti-tokenizer takes a comma list of target families: chatml, qwen (alias for the same ChatML-family tokenizer), mistral, deepseek. Each resolves to a real, offline, license-verified tokenizer.json vendored in the package (see tokenizer_assets/THIRD_PARTY_NOTICES.md for source/license per file) — loaded via Tokenizer.from_str() and importlib.resources, never Tokenizer.from_pretrained(), never a network call, at scan time or anywhere else. llama3 and gemma are recognized names with no offline-redistributable asset yet (Meta's Llama Community License and Gemma's Terms of Use both require attribution/notice machinery incompatible with a silent pip install) — requesting them prints a clear message and the four string tiers still cover that family's known tokens. Without the [tokenizers] extra installed, --sti-tokenizer does the same: warns with an install hint, never crashes, never disables anything else.

What confirmation actually changes: a string-tier match that a real target tokenizer resolves to an actual special/added-vocabulary token id is upgraded to one STI_TOKENIZER finding (HIGH confidence — a confirmed resolution against the real target is the strongest signal this scanner has). A string-tier match the tokenizer does not confirm is left completely unchanged — that divergence is itself signal, not something to hide. Concretely: [INST]/[/INST] are Llama-2-style prompt-template convention, not tokens Mistral's real tokenizer treats specially — --sti-tokenizer mistral correctly leaves them as plain STI_EXACT, while --sti-tokenizer chatml in the same scan upgrades real ChatML control tokens to STI_TOKENIZER. The tier can also catch tokens the string registry has never heard of: it encodes the entire text and checks every resulting token id against the target's real added-vocabulary set, not just our own regex/registry candidates.

Generate Offensive Test Servers

mcp-tool-auditor generate all --output-dir ./pentest_servers

CI/CD Integration

Gate merges on poisoning findings and upload results to GitHub Security.

GitHub Action

# .github/workflows/mcp-audit.yml
name: MCP Audit
on: [push, pull_request]

jobs:
  audit:
    runs-on: ubuntu-latest
    permissions:
      security-events: write   # to upload SARIF
    steps:
      - uses: actions/checkout@v4

      - name: Scan tool definitions
        uses: perparimmjeku/mcp-auditor@main
        with:
          command: scan import tools.json --format sarif -o mcp.sarif --fail-on HIGH

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: mcp.sarif

Until the package is on PyPI, point the action at the repo: with: { install-spec: "git+https://github.com/perparimmjeku/mcp-auditor.git" }

Plain CLI in any pipeline

# Exit code 2 if any HIGH+ finding is present — fails the build
mcp-tool-auditor scan import tools.json --fail-on HIGH

Verbose Output, Logs, and Metrics

mcp-tool-auditor -v scan import tests/fixtures/poisoned_tools.json

By default, structured logs are written under ~/.mcp-tool-auditor/logs and scan metrics are appended to ~/.mcp-tool-auditor/metrics.jsonl. Use --no-log-file or --no-metrics to disable those side effects for a run.

Configuration

mcp-tool-auditor --config ./config.yaml scan url http://localhost:8080/mcp

The CLI accepts JSON or YAML config files. CLI flags still take precedence for scan output format and minimum severity.

Offensive Simulation Acknowledgement

mcp-tool-auditor attack --yes atpa --port 8080 --threshold 3

Offensive simulation servers show an authorization warning before they start. Use --yes only for non-interactive, authorized lab runs.


Detection Coverage & Sample Reports


OWASP MCP Top 10 Mapping

OWASP ID Issue Detection
MCP01 Token Mismanagement & Secret Exposure ST_IGNORE_PREVIOUS, ST_BYPASS, ST_IGNORE_SECURITY
MCP02 Privilege Escalation via Scope Creep HEUR_AGENCY, COMPOSITION_CONFUSED_DEPUTY, credential-related signatures
MCP03 Tool Poisoning Signatures, heuristics, FSP, rug-pull/shadowing, STI (STI_EXACT/STI_NORMALIZED/STI_STRUCTURAL/STI_ENCODED), and behavioral/ATPA detection
MCP05 Command Injection & Execution ST_EXECUTE, ST_CODE_EXEC, command-related schema findings

Findings are actively emitted for MCP01, MCP02, MCP03, and MCP05. Reports also recognize the remaining OWASP MCP Top 10 IDs (MCP04, MCP06–MCP10) by label, but the current analyzers do not yet emit findings for them.


Offensive Testing Examples

# Start an ATPA simulation server
mcp-tool-auditor attack atpa --port 8080 --threshold 3

# Start a rug-pull simulation server
mcp-tool-auditor attack rugpull --port 8081 --switch-after 5

# Start an STI (Special Token Injection) simulation server -- benign
# definitions, injects a chat-template control token into responses
# after --threshold calls
mcp-tool-auditor attack sti --port 8082 --threshold 3

# Generate standalone attack servers
mcp-tool-auditor generate all --output-dir ./test_servers

python ./test_servers/server_description_injection.py

Architecture

mcp-tool-auditor/
├── mcp_tool_auditor/
│   ├── __init__.py
│   ├── cli.py
│   ├── config.py
│   ├── logging_config.py
│   ├── metrics.py
│   ├── security.py
│   ├── validation.py
│   ├── watch.py
│   ├── engagement.py
│   ├── auditor/
│   │   ├── __init__.py
│   │   ├── scanner.py
│   │   ├── models.py
│   │   ├── discovery.py
│   │   ├── remediation.py
│   │   ├── analyzers/
│   │   │   ├── __init__.py
│   │   │   ├── static.py
│   │   │   ├── heuristic.py
│   │   │   ├── schema.py
│   │   │   ├── rugpull.py
│   │   │   ├── behavioral.py
│   │   │   ├── composition.py
│   │   │   ├── llm_judge.py
│   │   │   ├── sti.py
│   │   │   ├── sti_tokenizer.py
│   │   │   ├── surface.py
│   │   │   └── patterns.py
│   │   ├── signatures/
│   │   │   ├── __init__.py
│   │   │   ├── descriptions.yaml
│   │   │   └── sti_tokens.yaml
│   │   ├── tokenizer_assets/
│   │   │   ├── __init__.py
│   │   │   ├── THIRD_PARTY_NOTICES.md
│   │   │   ├── chatml_qwen.tokenizer.json
│   │   │   ├── mistral.tokenizer.json
│   │   │   └── deepseek.tokenizer.json
│   │   └── reporters/
│   │       ├── __init__.py
│   │       ├── json_reporter.py
│   │       ├── markdown_reporter.py
│   │       ├── pentest_reporter.py
│   │       └── sarif_reporter.py
│   └── offensive/
│       ├── __init__.py
│       ├── poisoner.py
│       ├── atpa_server.py
│       ├── rugpull_sim.py
│       └── sti_server.py
├── tests/
│   ├── __init__.py
│   ├── conftest.py
│   ├── test_scanner.py
│   ├── test_patterns.py
│   ├── test_behavioral.py
│   ├── test_behavior_integration.py
│   ├── test_cli_behavior.py
│   ├── test_confidence_suppressions.py
│   ├── test_discovery.py
│   ├── test_engagement.py
│   ├── test_http_auth_session.py
│   ├── test_llm_judge.py
│   ├── test_pentest_reporter.py
│   ├── test_remediation.py
│   ├── test_retest.py
│   ├── test_rugpull_signing.py
│   ├── test_sarif_reporter.py
│   ├── test_scope_enforcement.py
│   ├── test_source_scan.py
│   ├── test_sti_analyzer.py
│   ├── test_sti_behavioral.py
│   ├── test_sti_offensive.py
│   ├── test_sti_tokenizer.py
│   ├── test_surface_scanning.py
│   ├── test_watch.py
│   └── fixtures/
│       ├── __init__.py
│       ├── poisoned_tools.json
│       └── source/
├── config.yaml
├── pyproject.toml
├── CONTRIBUTING.md
├── SECURITY.md
├── LICENSE
└── README.md

Configuration

See config.yaml for example scanner settings. Pass a config file with --config (JSON or YAML); CLI flags override the file for output format and minimum severity.

Default Configuration

auditor:
  severity_threshold: MEDIUM

  heuristic_analysis:
    description_length_threshold: 500
    imperative_threshold: 2

  schema_analysis:
    check_fsp_params: true
    check_required_array: true
    check_enum_values: true

Contributing

Pull requests are welcome.

Please see CONTRIBUTING.md for development guidelines, coding standards, and testing procedures.

Security issues should follow SECURITY.md.


License

MIT License — see the LICENSE file for details.


Legal Disclaimer

This tool is intended strictly for:

  • Authorized penetration testing
  • Defensive security research
  • Educational and lab environments
  • Controlled validation of MCP security controls

Users must have explicit permission before testing any target systems.

The authors assume no liability for misuse, unauthorized testing, or damages caused by improper use of this software.


Package Metadata

mcp_tool_auditor/__init__.py

"""MCP Tool Auditor package."""

__version__ = "1.8.0"
__author__ = "Përparim Mjeku"
__license__ = "MIT"

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_tool_auditor-1.8.0.tar.gz (4.6 MB view details)

Uploaded Source

Built Distribution

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

mcp_tool_auditor-1.8.0-py3-none-any.whl (4.7 MB view details)

Uploaded Python 3

File details

Details for the file mcp_tool_auditor-1.8.0.tar.gz.

File metadata

  • Download URL: mcp_tool_auditor-1.8.0.tar.gz
  • Upload date:
  • Size: 4.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mcp_tool_auditor-1.8.0.tar.gz
Algorithm Hash digest
SHA256 b5583b46426c70640e6553800a10e2cc9f98f2173711c47a9588473267e1558a
MD5 5bd64cf14a5ca51e9fa54cc789a9d98b
BLAKE2b-256 b861f962e22be319f625de4a59bd4171d3e1f9d284165959251b33d0e3334284

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_tool_auditor-1.8.0.tar.gz:

Publisher: publish.yml on perparimmjeku/mcp-auditor

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

File details

Details for the file mcp_tool_auditor-1.8.0-py3-none-any.whl.

File metadata

File hashes

Hashes for mcp_tool_auditor-1.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3069f5568acb376b3d886ccd8ddd157a141edd5ab2671a2046a2bcdd1cf8394b
MD5 587b837c4e48c52dd2829fbbd85219c2
BLAKE2b-256 462a5ed14a9a2c68c361051d40a676e863638ab8a1e1f3d6be06a2efff4069f0

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_tool_auditor-1.8.0-py3-none-any.whl:

Publisher: publish.yml on perparimmjeku/mcp-auditor

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 Pingdom Monitoring Sentry Error logging StatusPage Status page