Lint your MCP server before a model chokes on it. Checks MCP tool definitions — names that break function-calling, weak descriptions, invalid input schemas, and the context budget your toolset eats every request — from a tools/list JSON or by speaking the protocol to a live server over stdio. Local, no API key.
oh-my-mcp
Lint your MCP server before a model chokes on it.
npx oh-my-mcp --cmd "node your-server.js"
Everyone's shipping MCP servers. And the tool definitions are full of silent footguns the protocol won't catch for you:
- a tool name with a space or a dot — which breaks function-calling the moment a client maps it to an OpenAI-style function name,
- a description the model can't act on ("search") or a param with no description — so the model picks the wrong tool or fills the wrong args,
- an
inputSchemathatrequireds a property it never defines, - and the one nobody measures: how much of the model's context window your whole toolset eats on every single request.
oh-my-mcp reads your tool definitions — from a tools/list JSON or by speaking
the protocol to a live server over stdio — and grades them. Local,
deterministic, no API key.
$ npx oh-my-mcp --cmd "node weather-server.js"
● oh-my-mcp · weather-server v1.0.0 (live, MCP 2025-06-18)
Server-wide
✗ Duplicate tool name "list_items" (2 tools share it) — the model can't address them.
· Your 6 tool definitions cost ~157 tokens of context on every single request.
B get weather 83/100 · ~28 tok
✗ Name "get weather" has characters that break function-calling. → Use only [a-zA-Z0-9_-].
! Param "location" has no description — the model leans on these to fill arguments.
B search_database 83/100
✗ inputSchema problem at inputSchema.required: requires "query", which is not in properties
…
30/100 (F) 4 errors · 4 warnings · ~157 ctx tokens
Three ways to point it at your tools
# 1. a live server — spawn it and run the MCP handshake, then lint what it serves
npx oh-my-mcp --cmd "node server.js"
npx oh-my-mcp --cmd "npx -y @some/mcp-server"
# 2. every server in your MCP client config (claude_desktop_config.json / mcp.json)
npx oh-my-mcp --servers ~/Library/Application\ Support/Claude/claude_desktop_config.json
# 3. a tools/list JSON you already have
npx oh-my-mcp tools.json
some-server | npx oh-my-mcp --stdin
In live mode it runs the real initialize → tools/list handshake and also checks
the protocol itself (missing serverInfo, protocolVersion, malformed
tools/list). Non-JSON log lines on stdout are ignored; a silent server times out
instead of hanging.
What it checks
| Group | Examples |
| ----- | -------- |
| Breaks tool-calling | names outside [a-zA-Z0-9_-] or >64 chars, duplicate names, readOnlyHint on a tool whose name screams mutation |
| The model can't use it well | missing/one-word descriptions, params with no description, mixed snake/camel naming |
| Input schema | not a valid JSON Schema, required referencing a missing property, params with no type, non-object top level |
| Wastes context | the total token cost of your toolset on every request; individual over-long descriptions |
| Protocol (live) | missing serverInfo/protocolVersion, no tools capability, malformed tools/list |
Every finding rolls up into a per-tool and overall 0–100 score (A–F) you can gate in CI.
Install
npx oh-my-mcp --cmd "node server.js" # no install
npm i -g oh-my-mcp # the bin is also `omm`
Node ≥ 18. The lint core is dependency-free and browser-safe.
Gate it in CI
oh-my-mcp exits non-zero on any error (or below --min-score), so a bad tool
definition can't ship:
# .github/workflows/ci.yml
- run: npx oh-my-mcp --cmd "node dist/server.js" --min-score 80
oh-my-mcp tools.json --json report.json # machine-readable
oh-my-mcp tools.json --md report.md # paste into a PR
Library API
The lint engine is pure (browser-safe), so you can lint a pasted tools/list:
import { extractTools, analyze, DEFAULT_CONFIG } from "oh-my-mcp";
const report = analyze(extractTools(toolsListResult), DEFAULT_CONFIG, { label: "my-server", mode: "file" });
console.log(report.score, report.tools[0].findings);
Roadmap
- 🌐 Web playground — paste a
tools/list, see the report (the core already runs in a browser). - Resources & prompts (not just tools), and
tools/callsmoke tests. - A
--fixthat rewrites names/schemas where it safely can. - More client configs auto-discovered (Cursor, VS Code, Windsurf).
💖 Sponsor
Free, MIT, built in spare time. If it caught a tool def before a model did:
- ⭐ Star the repo — so the next person building an MCP server finds it.
- 🍋 Sponsor via Lemon Squeezy — one-time or recurring.
License
MIT © oh-my-mcp contributors