Thanks to visit codestin.com
Credit goes to github.com

Skip to content

kriskimmerle/mcplint

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mcplint

MCP Server Source Code Security Linter — Zero-dependency static analysis for MCP (Model Context Protocol) server Python code.

43% of MCP server implementations contain command injection flaws. 30% permit unrestricted URL fetching. mcplint catches these issues before deployment.

Why mcplint?

Existing MCP security tools (mcpwn, mcp-scan, Cisco mcp-scanner) are runtime scanners — they connect to running MCP servers and probe them. mcplint is different: it statically analyzes your source code before you ship it.

Think of it as ESLint for MCP servers. Catch command injection, SQL injection, SSRF, path traversal, and tool description poisoning in your CI pipeline — not in production.

Quick Start

# Scan an MCP server file
python mcplint.py server.py

# Scan a directory
python mcplint.py src/

# CI mode (exit 1 if issues found)
python mcplint.py --check server.py

# JSON output
python mcplint.py --json server.py

# Only show high+ severity
python mcplint.py --severity high server.py

# Show fix suggestions
python mcplint.py --verbose server.py

# Read from stdin
cat server.py | python mcplint.py -

What It Catches

mcplint detects 15 categories of security issues in MCP tool, resource, and prompt handlers:

Rule Severity What It Detects
ML01 🔴 CRITICAL Command Injection — User input passed to subprocess/os.system/os.popen with shell execution
ML02 🟠 HIGH Path Traversal — User input used in file operations without sanitization
ML03 🔴 CRITICAL SQL Injection — User input formatted into SQL queries (f-strings, .format(), %, concatenation)
ML04 🟠 HIGH SSRF — User-controlled URLs in HTTP requests
ML05 🔴 CRITICAL Code Execution — User input passed to eval/exec/compile
ML06 🔴 CRITICAL Unsafe Deserialization — pickle/yaml.load/marshal in tool handlers
ML07 🔴 CRITICAL Hardcoded Secrets — API keys, tokens, private keys in source code
ML08 🟡 MEDIUM Missing Input Validation — Tool parameters without type annotations
ML09 🟠 HIGH Sensitive File Access — References to .env, .ssh, credentials files
ML10 🟡 MEDIUM Information Disclosure — Returning tracebacks, exception details, env vars
ML11 🟡 MEDIUM Missing Error Handling — Risky operations without try/except
ML12 🔴 CRITICAL Description Injection — Prompt injection patterns in tool docstrings
ML13 🟡 MEDIUM Excessive Permissions — shell=True without user input, sudo commands
ML14 🟡 MEDIUM Missing Timeout — HTTP/subprocess calls without timeout parameter
ML15 🔵 LOW Resource Leaks — Files opened without context managers

How It Works

mcplint uses Python's ast module to understand your MCP server code:

  1. Finds MCP handlers — Detects @mcp.tool(), @server.tool(), @mcp.resource(), @mcp.prompt() decorators (works with FastMCP, official SDK, and custom setups)
  2. Identifies user input — Tool parameters come from LLMs/users and are treated as untrusted
  3. Traces data flow — Follows parameter usage through function bodies to find dangerous sinks
  4. Checks descriptions — Scans tool docstrings for prompt injection patterns

Example

Given this vulnerable MCP server:

import subprocess
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Demo")

@mcp.tool()
def run_command(command: str) -> str:
    """Execute a shell command"""
    return subprocess.check_output(command, shell=True).decode()

@mcp.tool()
def search_db(query: str) -> str:
    """Search the database"""
    cursor.execute(f"SELECT * FROM data WHERE q = '{query}'")
    return str(cursor.fetchall())

mcplint output:

────────────────────────────────────────────────────────────
  server.py
────────────────────────────────────────────────────────────
  🔴 CRITICAL ML01 L9: Command injection: tool 'run_command' passes user input
     to subprocess.check_output() with shell execution (tool: run_command)
  🔴 CRITICAL ML03 L14: SQL injection: tool 'search_db' uses f-string with
     user input in SQL query (tool: search_db)

════════════════════════════════════════════════════════════
  mcplint — F (0/100)
  2 finding(s): 🔴 2 critical
════════════════════════════════════════════════════════════

CI Integration

GitHub Actions

- name: Lint MCP Server
  run: python mcplint.py --check --severity medium src/

Pre-commit

- repo: local
  hooks:
    - id: mcplint
      name: mcplint
      entry: python mcplint.py --check
      language: python
      files: '\.py$'

Configuration

Flag Description
--check Exit 1 if any findings (for CI)
--json JSON output
--severity Minimum severity: info, low, medium, high, critical
--ignore Comma-separated rules to skip: ML07,ML15
--verbose / -v Show fix suggestions
--no-color Disable emoji output

Key Design Decisions

  • MCP-aware: Only scans files with MCP decorators. Non-MCP Python files are silently skipped.
  • User input tracking: Tool parameters are treated as untrusted. Static string arguments are not flagged as injection risks.
  • Zero false positives on safe patterns: Parameterized SQL queries, yaml.safe_load(), static URLs with user data in params — all pass clean.
  • Description analysis: The only static tool that checks for prompt injection in tool docstrings (a real MCP attack vector per Elastic Security Labs).

Requirements

  • Python 3.9+
  • Zero dependencies

References

License

MIT

About

Static security linter for MCP (Model Context Protocol) configuration files. 17 rules, secret detection, A-F grading, CI mode. Zero deps.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages