Skip to content
Conduit

mcp server

mcp-trustlint

Security contract testing, tool-poisoning detection, and drift gates for Model Context Protocol servers.

hugocaav/mcp-trustlintcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

Before you start

  • uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "mcp-trustlint": {
      "command": "uvx",
      "args": [
        "mcp-trustlint"
      ]
    }
  }
}

same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12

Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs

README

synced Oct 21, 2026

MCP TrustLint

CI Python 3.11+ License: Apache-2.0 Status: Alpha

Security contract testing for Model Context Protocol servers.

MCP TrustLint connects to a real MCP server, inventories the tools exposed to AI agents, and flags dangerous or deceptive metadata before the server reaches a user. It is designed for MCP authors who want a fast local check and a stable CI signal without executing any tools.

[!IMPORTANT] MCP TrustLint is alpha software. The passive scanner is read-only, but its findings are signals for human review rather than proof that a server is safe.

Why this exists

An MCP tool definition is part API contract and part instruction presented to an AI model. A server can look harmless while advertising hidden instructions, unexpected command execution, broad filesystem access, or schemas that enable more agency than the tool name suggests.

MCP TrustLint makes that trust boundary visible. Today it answers four useful questions:

  1. What tools does this server expose?
  2. Do their descriptions try to manipulate the model?
  3. Do their descriptions or parameters imply risky capabilities?
  4. Has the live contract changed since it was reviewed?

Capability graphs, richer policy gates, and controlled red-team testing are tracked in the public roadmap.

Quick start

git clone https://github.com/hugocaav/mcp-trustlint.git
cd mcp-trustlint
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e .

Inspect a local stdio server:

mcp-trustlint inspect "python tests/fixtures/poisoned_server.py"

Scan it with deterministic, offline rules:

mcp-trustlint scan "python tests/fixtures/poisoned_server.py"

The included fixture is intentionally vulnerable but behaviorally harmless. A scan finds hidden instructions in search_docs, the misleading shell capability advertised by add_numbers, and the legitimate file access exposed by read_file. The benign get_weather control is not flagged.

Remote Streamable HTTP and legacy SSE targets use the same commands:

mcp-trustlint scan https://example.com/mcp

Contract drift

Create a canonical snapshot after reviewing a server:

mcp-trustlint snapshot "python server.py"
git add mcp-trustlint.lock.json

Compare a future build against the approved contract:

mcp-trustlint diff "python server.py"

diff exits with status 1 when a tool is added or removed, a model-facing description changes, or an input schema changes. Snapshot fingerprints are stable across tool ordering. Stored target labels remove URL credentials, query strings, and stdio arguments so lockfiles do not capture secrets.

GitHub Action

Commit the approved snapshot, then add the contract gate to a workflow:

permissions:
  contents: read

steps:
  - uses: actions/checkout@v4
  - uses: hugocaav/mcp-trustlint@v0.1.0a1
    with:
      target: python server.py
      baseline: mcp-trustlint.lock.json

The action installs the pinned repository release and fails the job on any unapproved drift.

Reports

Terminal output is grouped by tool and color-coded by severity. JSON is suitable for automation, while SARIF can be uploaded to GitHub Code Scanning.

mcp-trustlint scan TARGET --format json --output report.json
mcp-trustlint scan TARGET --format sarif --output report.sarif

Every finding includes a stable check identifier, severity, title, OWASP Agentic Security reference, detection source, evidence, and remediation.

Optional semantic classifier

Deterministic checks are always enabled and make no model API calls. The optional OpenAI classifier looks for paraphrased or obfuscated tool poisoning:

python -m pip install -e ".[llm]"
export OPENAI_API_KEY="your-key"
mcp-trustlint scan TARGET --llm

Use --llm-debug only for diagnostics. Debug output is written to stderr. Never commit API keys; .env is ignored and is not loaded automatically.

Architecture

flowchart LR
    A["stdio / HTTP / SSE target"] --> B["MCP handshake"]
    B --> C["Tool inventory"]
    C --> D["Deterministic checks"]
    C --> E["Optional LLM classifier"]
    D --> F["Normalized findings"]
    E --> F
    F --> G["Terminal"]
    F --> H["JSON"]
    F --> I["SARIF"]
    C --> J["Canonical snapshot"]
    J --> K["Contract diff / CI gate"]

The client completes the MCP initialize handshake before requesting tools/list. Tool metadata is treated as untrusted input throughout the scan. See Architecture and Threat model for the design boundaries.

Current checks

RuleWhat it detectsDefault severity
tool_poisoningModel-directed instructions, concealment, exfiltration language, and sensitive pathsHigh
risky_capabilitiesCommand execution, filesystem, network, write, and read signalsHigh to Low
llm_poisoningSemantic hidden instructions and scope violationsConfidence-based
contract_driftTools, descriptions, or schemas changed after approvalHigh to Low

The full rule behavior and known limitations are documented in Rule reference.

Security properties

  • Passive scans never invoke MCP tools.
  • Tool descriptions and schemas are treated as attacker-controlled data.
  • The default scanner is offline after connecting to the target.
  • LLM use is explicit and isolated behind --llm.
  • Structured model output is validated and failures do not crash the scan.
  • Reports do not include OPENAI_API_KEY.

MCP TrustLint currently analyzes declared metadata, not implementation behavior. A clean report does not prove that a server is benign, correctly authorized, or sandboxed. Read the threat model before using results as a security decision.

Development

source .venv/bin/activate
python -m pip install -e ".[dev,llm]"
ruff check .
ruff format --check .
mypy src/mcp_trustlint
pytest --cov=mcp_trustlint

Contributions should begin with CONTRIBUTING.md. Security issues should follow SECURITY.md rather than a public issue.

License

Licensed under the Apache License 2.0.

↑↓ navigate openesc close