solhint-mcp
Lint and autofix Solidity smart contracts with Solhint, from any MCP client — Claude Code, OpenAI Codex, Cursor, Windsurf, Claude Desktop, and anything else that speaks the protocol. Nothing in it is specific to one vendor.
Your agent gets seven tools: lint_solidity, lint_file, lint_project,
fix_solidity, fix_file, explain_rule and get_config.
Solhint's CLI points users at this package — protofire/solhint#801, shipped in Solhint 6.2.5.
Installation
Add this to your MCP client's configuration, with the Solidity project as the working directory:
{
"mcpServers": {
"solhint": {
"command": "npx",
"args": ["-y", "solhint-mcp"]
}
}
}
Requires Node.js 20 or newer. On native Windows, clients that launch servers through
npx generally need "command": "cmd" with "args": ["/c", "npx", "-y", "solhint-mcp"].
One server process lints one project: its working directory is the project root, so start another process for a different project. A Solhint installed in that project takes precedence over the copy bundled here.
How it runs Solhint
The server calls Solhint through its JavaScript API. It does not start a shell, invoke
npx solhint, make update checks, or parse CLI output.
Client-specific shortcuts
Claude Code — from the Solidity project directory:
claude mcp add solhint -- npx -y solhint-mcp
The default local scope associates the server with the current project. Use
--scope project before -- if the configuration should be committed in .mcp.json.
On native Windows, Claude Code requires cmd /c:
claude mcp add solhint -- cmd /c npx -y solhint-mcp
OpenAI Codex — Codex uses TOML, not the JSON block above, and shares one configuration across the Codex CLI, the ChatGPT desktop app and the IDE extension. From the Solidity project directory:
codex mcp add solhint -- npx -y solhint-mcp
Or add it by hand to ~/.codex/config.toml, or to .codex/config.toml to scope it
to one project:
[mcp_servers.solhint]
command = "npx"
args = ["-y", "solhint-mcp"]
Cursor / Windsurf — add the JSON block above to the editor's MCP settings.
Claude Desktop — installation is separate from Claude Code. This package is a
stdio npm server, not a packaged Desktop Extension (.mcpb). Configure it as a local
development MCP server only if the client launches it with the Solidity project as its
working directory. See Anthropic's current
local-server instructions.
Tools
| Tool | Input | Description |
|---|---|---|
lint_solidity | { code, config? } | Lint a Solidity source string |
lint_file | { filePath } | Lint one .sol file inside the project |
lint_project | { pattern? } | Lint a project-relative glob |
fix_solidity | { code, config? } | Autofix a Solidity source string |
fix_file | { filePath, write? } | Autofix one .sol file |
explain_rule | { ruleId } | Explain any rule the linter ships |
get_config | {} | Show the project's Solhint config |
lint_project autodetects contracts/**/*.sol, then src/**/*.sol, and finally
**/*.sol. Paths and patterns outside the project root are rejected.
The fix_* tools apply Solhint's own autofixes and then re-lint, so what they report
as remaining is what is genuinely left rather than the pre-fix report. fix_solidity
returns the corrected source and touches nothing on disk. fix_file previews by
default and only writes when called with write: true — Solhint's CLI asks for a
backup before --fix, and an MCP client should not rewrite someone's contracts
without being asked either.
explain_rule reads the documentation Solhint ships with each rule, so it covers the
whole registry and always describes the version this project runs: description,
category, default severity, configurable options, notes and the good/bad examples when
the rule defines them.
If your repository already documents a lint command
An agent follows an explicit instruction in your repository over a tool description.
If AGENTS.md, CLAUDE.md, .cursorrules or a similar agent playbook says how to
lint, for example:
- Solidity lint: `npm run lint:sol`
the agent will run that command and never reach for these tools. That is reasonable behaviour, not a misconfiguration, but it means the server goes unused until you say it is there. Mention it alongside the command:
- Solidity lint: prefer the `solhint` MCP tools (`lint_file`, `lint_project`,
`fix_file`, `explain_rule`, `get_config`) when that server is configured; they run this project's
own Solhint with its config. Fall back to `npm run lint:sol` when the server is
unavailable.
The two are complementary. The command is what a person and CI run. The tools are what
an agent runs, and their advantage is that the invocation cannot drift: no unquoted
** collapsing to a single level, no forgotten config, no stray flag. A shell glob
written by hand can silently cover a fraction of a project; lint_project cannot.
Configuration
lint_solidity uses configuration in this order:
- The complete
configobject supplied to the tool. - The configuration found in the project root.
{ "extends": "solhint:recommended" }.
An explicit config replaces the project config; it is not merged. File and project linting use Solhint's per-file configuration hierarchy and the same recommended fallback when no configuration exists.
The server prefers a compatible solhint (>=6.1.0 <7.0.0) installed by the project.
If none exists, it uses its bundled, tested version. An installed but incompatible
project version produces an explicit error. Pass --bundled-solhint only when you
intentionally want the bundled version.
Solhint 6.0.x is excluded because its plugin loader can terminate the host process when a configured plugin cannot be loaded, which is unsafe for an in-process MCP server.
Protocol and current limitations
The server uses @modelcontextprotocol/server 2.x over stdio. It supports the current
2026-07-28 lifecycle and the SDK's legacy compatibility path.
Solhint currently resolves shareable configs and plugins relative to process.cwd().
That is why this release supports one project per process. A third-party plugin that
writes to stdout synchronously is redirected to stderr while linting so it cannot corrupt
the MCP channel. Full plugin isolation, cancellation, and lint timeouts are deferred to a
worker-based release.
Docker
docker build -t solhint-mcp .
docker run -i --rm -v "$PWD":/project solhint-mcp
The server lints whatever directory it starts in, so the Solidity project is mounted at
/project, which is the image's working directory. -i is required because the server
speaks MCP over stdio; no port is exposed. A Solhint installed in the mounted project
takes precedence over the image's own copy.
MCP Registry
Listed as io.github.vschernoff/solhint-mcp. server.json in this repository is the
registry manifest; its name must stay identical to mcpName in package.json, and
both version fields must match the published npm version, or a registry publish is
rejected.
Credits and licence
MIT. The linting runner, tool surface and test suite were originally written by Diego Bale (@dbale-arg) for protofire/solhint and moved here with his agreement, so the MCP server can be maintained and released independently of Solhint's release cycle. See NOTICE for the file-level breakdown.
Solhint is maintained by Protofire. This package depends on it; it is not part of it.