Skip to main content

Fast static linter for MCP servers. Catches vague, colliding, or misleading tool descriptions before agents pick the wrong tool.

Project description

mcpolish

A static linter for Model Context Protocol servers

Catch vague, colliding, or misleading tool descriptions before agents pick the wrong tool.

| Documentation | Quickstart | Rules | Glossary | Design doc | Test report |

pypi python license rules tests


About

When you build an MCP server, every tool you expose carries an English description. The AI agent (Claude, GPT, Gemini, Cursor, and so on) reads that description to decide which tool to call. If the description is vague, generic, or misleading, the agent picks the wrong tool.

In tests across 10,831 public MCP servers (Wang et al., February 2026), bad descriptions caused agents to pick the wrong tool 52 percentage points more often. That paper catalogued 18 specific problems. mcpolish detects 23 of them, before you ship.

mcpolish is to MCP server quality what ESLint is to JavaScript style: a fast static check with stable rule IDs that runs in your editor, your pre-commit hook, and your CI pipeline.

mcpolish is fast with:

  • Sub-second scans on a typical MCP server. Verified 6 ms on a 3-tool file, 67 ms on a 40-file project.
  • One parse, twenty-three checks. mcpolish reads each file once into an intermediate representation, then every rule runs against the same in-memory view.
  • Zero external calls. The default engine runs offline.

mcpolish is flexible with:

  • Five output formats: terminal, JSON, SARIF, GitLab Code Quality, GitHub PR-comment Markdown.
  • Per-rule configuration in pyproject.toml. Whitelist names, raise thresholds, retune category weights.
  • Two-tier auto-fix: safe fixes apply only deterministic edits; risky renames need --unsafe-fix.
  • Three optional LLM-judged rules for the cases static heuristics miss. Off by default.

mcpolish covers:

  • Schema problems (missing descriptions, broken JSON Schema, missing required arrays).
  • Naming problems (generic names, redundant namespace prefixes, verb inconsistency, cross-server collisions, mixed casing).
  • Description quality (too short, too long, no examples, no trigger conditions, jargon density, marketing qualifiers, ambiguity).
  • Consistency between schema and description (param type mismatch, undocumented side effects, duplicate descriptions).
  • Security smells (zero-width prompt injection, operator-style instructions baked into descriptions).

See the rules index for the full table.

Quickstart

pip install mcpolish

mcpolish lint .
mcpolish score . --json
mcpolish explain MP010

Sample run on a real server file:

$ mcpolish lint weather_server.py
mcpolish 0.1.0
server: weather  (1 tool in 1 file)

weather_server.py:6:1: MP010 [W] tool name `get` is too generic
   -> consider a more specific name like `get_<noun>` or `<verb>_<thing>`
   -> https://mcpolish.dev/rules/MP010
weather_server.py:6:1: MP020 [W] tool `get` description is 12 chars (minimum 50)
   -> state what the tool does and when an agent should pick it
   -> https://mcpolish.dev/rules/MP020

Found 2 issues (0 errors, 2 warnings, 0 notes). score: 86/100

Documentation

The full documentation lives under docs/. Common entry points:

If you want to... Go here
Run mcpolish for the first time Quickstart
Understand the diagnostic lines Understanding the output
Wire mcpolish into CI GitHub Actions, GitLab CI, pre-commit
Lint a multi-file project Multi-file server
Customise which rules run Customising rules
Look up one specific rule Rules index
Find what a technical word means Glossary
Use the Python API Python API

The 23 rules

Each rule has a stable identifier like MP010 and a documentation page.

Category Rules
Schema MP001, MP002, MP003, MP004, MP005
Naming MP010, MP011, MP012, MP013, MP014
Description MP020, MP021, MP022, MP023, MP024, MP025, MP026 (LLM)
Consistency MP030, MP031 (LLM), MP032 (LLM), MP033
Security MP040, MP041

Print the full list in your terminal:

mcpolish explain          # one line per rule
mcpolish explain MP010    # details for one rule

See the rules index for the categorised table and links to every rule's detail page.

Configuration

Settings go in pyproject.toml:

[tool.mcpolish]
target-version = "2025-11"
select = ["MP001-MP041"]
ignore = ["MP025"]
registry = "official"

[tool.mcpolish.MP010]
allow = ["search"]

[tool.mcpolish.MP020]
min_chars = 80

See Configuration for every knob.

Integrations

GitHub Actions

- uses: vtensor/mcpolish-action@v1
  with:
    fail-on: error
    report: sarif

GitLab CI

mcpolish:
  image: python:3.12
  script:
    - pip install mcpolish
    - mcpolish lint . --format gitlab > codequality.json
  artifacts:
    reports:
      codequality: codequality.json

Pre-commit hook

repos:
  - repo: https://github.com/vtensor/mcpolish
    rev: v0.1.0
    hooks:
      - id: mcpolish

CLI cheat sheet

mcpolish lint .                  # lint everything reachable
  --select MP010                 # keep only specific rules (range syntax: MP001-MP005)
  --ignore MP020                 # drop specific rules
  --llm openai:gpt-4o            # enable the 3 LLM-judged rules
  --registry official            # cross-server collision check (default)
  --registry off                 # local rules only
  --fix                          # apply safe autofixes
  --unsafe-fix                   # apply risky autofixes (renames)
  --format tty|json|sarif|gitlab|pr-comment
  --fail-on error|warn|note|never

mcpolish score . --json --badge badge.svg
mcpolish explain MP010
mcpolish doctor

Full reference: CLI reference.

Python API

import mcpolish

report = mcpolish.lint("server.py")
print(report.score)              # 0 to 100

for d in report.diagnostics:
    print(d.rule_id, d.location(), d.message)

See Python API.

Why this exists

  • Wang et al., arXiv:2602.18914, February 2026: 10,831 public MCP servers analysed, 18 description smells catalogued, controlled mutation experiment proving each smell causes wrong-tool selection (p < 0.001).
  • Li et al., arXiv:2602.03580, February 2026: static analysis of 10,240 servers; 3,449 with parameter type mismatches, 1,326 with undocumented side effects.
  • Snyk acquired Invariant Labs (mcp-scan) in June 2025. Agentic-AI security is now a real budget line.
  • MCP was donated to the Linux Foundation's Agentic AI Foundation in December 2025. OpenAI, AWS, Google, Microsoft, Cloudflare, and Bloomberg are members.

The ecosystem grew to over 23,000 servers on Glama, 20,000 on MCP.so, and 12,000 on Smithery with no quality gate. mcpolish is that gate.

Project status

Version 0.1.0
Python 3.11 and newer
Rules shipped 23
Tests 132 passing
Performance 6 to 67 ms on real fixtures
License Apache 2.0
Status Beta. The 23 rule IDs are stable forever.

See MCPOLISH.md for the full design document and VERIFICATION.md for the end-to-end verification report.

Contributing

Contributions are welcome. Bug reports, rule proposals, and documentation improvements are equally valued.

See CONTRIBUTING.md for the developer setup and the workflow. See CODE_OF_CONDUCT.md for community expectations. See SECURITY.md to report a security issue privately.

License

Apache 2.0. See LICENSE.

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

mcpolish-0.1.1.tar.gz (155.6 kB view details)

Uploaded Source

Built Distribution

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

mcpolish-0.1.1-py3-none-any.whl (74.7 kB view details)

Uploaded Python 3

File details

Details for the file mcpolish-0.1.1.tar.gz.

File metadata

  • Download URL: mcpolish-0.1.1.tar.gz
  • Upload date:
  • Size: 155.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mcpolish-0.1.1.tar.gz
Algorithm Hash digest
SHA256 9693d5ab05ece7d55b6e52e1c15b08d8b0311e84331cec8bd7b8cc79a1ec3292
MD5 f8f789cac3da86c5cbb5993c875ed95b
BLAKE2b-256 3f174e0c5428152dad8d23c0424cedf167c55c4d6462a654087a7596a37818e9

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcpolish-0.1.1.tar.gz:

Publisher: publish.yml on vtensor/mcpolish

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

File details

Details for the file mcpolish-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: mcpolish-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 74.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mcpolish-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 34674a3e2132a94e3004c4b6bb86628fb942c2bde3575cb9d1841d88d83a67ae
MD5 32e9eb0b956d7b43b27406d0635d9e3d
BLAKE2b-256 03ba700254f30fa7dafed8acab640b075f8a4522ac7d91b7e09351378c3cdc61

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcpolish-0.1.1-py3-none-any.whl:

Publisher: publish.yml on vtensor/mcpolish

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