robworks-code

MCP Surface Lint

Community robworks-code
Updated

Static checks over an MCP tool surface: find where a caller can do the wrong thing and get no error back. Also runs as an MCP server.

title: MCP Surface Lintemoji: 🔎colorFrom: indigocolorTo: graysdk: gradiosdk_version: 6.20.0app_file: app.pypinned: falselicense: mitshort_description: Find where an MCP tool surface lets a caller fail silentlytags:

  • mcp
  • mcp-server
  • developer-tools
  • static-analysis

MCP Surface Lint

Static checks over an MCP tool surface. Every rule answers one question:

Could a caller do the wrong thing and get no error back?

A tool that crashes on bad input is fine. A tool that accepts bad input andreturns something plausible is the expensive kind of broken, because neither thecaller nor the person reading the transcript has any signal that it happened.

Paste a tools/list response, get back the specific places that can happen.

This app is also an MCP server, so an agent can lint an agent interfacewithout going through the UI.

Using it as an MCP server

Launched with demo.launch(mcp_server=True). Point a client at:

https://<space-host>/gradio_api/mcp/sse

Two tools are published:

Tool Purpose
lint_tool_surface(surface_json) Run every rule over a surface, return findings with severities
list_rules() Enumerate the checks, their ids, and their severities

The UI event handlers are deliberately excluded with api_name=False. Withoutthat, Gradio also publishes analyse, analyse_1, and explain as tools: aduplicate-name pair plus a handler taking a gr.State that cannot survive a toolcall. This linter flags all three patterns, so shipping them would be a poor look.

The rules

Id Severity Catches
MCP001 high Tool has no description
MCP002 low Description too short to distinguish from a neighbour
MCP003 high No inputSchema at all
MCP004 high Parameter with no description
MCP005 high Parameter with no declared type
MCP006 medium String parameter that is really a closed set, with no enum
MCP007 high Properties declared but no required list
MCP008 low Numeric parameter with no bounds
MCP009 medium Unconstrained object parameter
MCP010 medium Description never says what failure looks like
MCP011 high Destructive verb with no guard parameter and no warning
MCP012 medium Two tools a caller cannot choose between by name
MCP013 medium Two tools sharing an identical description

Names are compared after crude stemming, because list_user_records andlist_users_record are the same tool as far as a caller is concerned and rawtoken comparison misses that entirely.

What it found in its own surface

Pointed at its own published schema, the linter returns exactly one finding, andit is not in this repo:

[high] MCP007 lint_tool_surface: Schema declares properties but no 'required' list

Gradio's get_input_schema builds {"type": "object", "properties": {...}} andnever emits a required array. The information is already there: the sameparameter dicts it iterates carry parameter_has_default, and Gradio's owngradio skills command uses that field to mark a parameter required. Thepractical effect is that every Gradio MCP server publishes tools whosearguments all look optional, so a caller that omits a mandatory one produces aschema-valid call.

Reported upstream as gradio-app/gradio#13670.

Running locally

pip install -r requirements.txt
python app.py

Tests:

python -m pytest -q

Rules are only worth what their tests are worth, so there is also a mutationmatrix. It neuters each rule in turn and records which tests fail. A rule with nofailing test is either dead code or unguarded, and you cannot tell which withoutlooking:

python mutation_check.py

It refuses to report anything unless the baseline suite is green first, and itdisables bytecode caching, because every mutated file is the same length andCPython validates a cached .pyc on (mtime, size). Inside one second that pairdoes not change, so the interpreter happily re-imports the previous mutation'sbytecode and the whole matrix reports the wrong rule's result.

License

MIT.

MCP Server · Populars

MCP Server · New

    DareDev256

    FCPXML MCP

    🎬 The first AI-powered MCP server for Final Cut Pro XML. Control your edits with natural language.

    Community DareDev256
    acunningham-ship-it

    Veil

    Stealth browser for AI agents — real Chrome over raw CDP, no Playwright/Puppeteer. TypeScript + MCP-native. Passes sannysoft 57/57, bypasses Cloudflare.

    Cassette-Editor

    Oh My Cassette: Chat Your Raw Clips Into a Finished Cut

    你的随身 AI 剪辑搭档 | Pocket AI co-editor for video montage — AI video editing plugin & MCP server for Claude Code, Codex, Hermes & OpenCode

    Community Cassette-Editor
    trendsmcp-ai

    Trends MCP

    MCP server for live trend data. Query Google Search, YouTube, TikTok, Reddit, Amazon, Wikipedia, News sentiment, Web Traffic, App Downloads, Steam, npm and more. Works with Claude, Cursor, VS Code, GitHub Copilot, ChatGPT, Windsurf, Cline, Raycast and any MCP-compatible.

    Community trendsmcp-ai
    jacob-bd

    Gemini Notebook (formerly Google NotebookLM) CLI & MCP Server

    Programmatic access to Gemini Notebook - via command-line interface (CLI), Model Context Protocol (MCP) server, and AI agent skills.

    Community jacob-bd