OpenLint MCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@OpenLint MCPvalidate my .openlint.yaml ruleset and flag any issues"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
openlint-mcp
An MCP server for OpenLint. It lets AI tools such as Claude, Codex and OpenCode check OpenLint rulesets, and, as the remaining milestones land, lint OpenAPI, AsyncAPI and Arazzo documents and look up rules.
The server runs locally over stdio and builds only on the published @openlint/* npm packages. Design and milestones: docs/v1-plan.md.
Status: early development. The package isn't on npm yet, so install it from source (below). Once it's published,
node /abs/path/to/openlint-mcp/dist/index.jsin the examples becomesnpx -y @openlint/openlint-mcp.
Tools
All tools are read-only.
Tool | What it does | Status |
| Lists the rulesets the server is configured with | Available |
| Checks a YAML or JSON ruleset without running any code, and warns about anything | Available |
| Lints an OpenAPI, AsyncAPI or Arazzo document | Planned (milestone 3) |
| Look up the rules in a ruleset | Planned (milestone 4) |
Related MCP server: Spotlight MCP
Install from source
Requires Node.js ^22.22.1 || >=24.
git clone https://github.com/miqui/openlint-mcp.git
cd openlint-mcp
npm ci
npm run build
npm run smoke # optional: starts the built server over stdio and calls its toolsThe server's command is node /abs/path/to/openlint-mcp/dist/index.js. Run pwd in the clone to get the absolute path.
Configure rulesets
Option | Meaning |
| The default ruleset: a YAML, JSON or JS ruleset file |
| An extra named ruleset. Repeat the option to add more. |
| The default ruleset, when there is no unnamed |
Which one is the default: an unnamed
--ruleset, thenOPENLINT_RULESET, then the first named ruleset.Filenames that contain
=:--ruleset team=prod.yamlmeans a ruleset namedteam, loaded fromprod.yaml. To load a file calledteam=prod.yaml, start the path with./or/, as in--ruleset ./team=prod.yaml.No ruleset configured: the server uses the
oas,asyncapiandarazzorulesets from@openlint/openlint-rulesets(recommended rules).Use absolute paths. AI tools usually start MCP servers from a different working directory than your project, so relative paths may not resolve.
Custom functions are supported in configured rulesets (
functions,functionsDir, and JS rulesets).Errors at startup: if a ruleset fails to load, the server prints the error to stderr and exits. Your AI tool will show the server as failed; its MCP logs have the message.
Rulesets that an AI tool passes inline in a tool call are untrusted, so they are restricted:
no custom functions
extendsonly names a configured ruleset,oas,asyncapi,arazzo, or one of the aliasesspectral:oas,spectral:asyncapi,spectral:arazzo,openlint:openapi,openlint:asyncapiandopenlint:arazzoformatsonly names formats exported by@openlint/openlint-formats
validate_ruleset explains what was refused.
Use with AI tools
In every example, replace /abs/path/to/openlint-mcp with the absolute path of your clone, and /abs/path/to/.openlint.yaml with your ruleset. The --ruleset … part is optional. Without it, the server uses the default rulesets above.
Claude Code
Add the server with the claude CLI. Everything after -- is the server's own command line:
claude mcp add openlint -- node /abs/path/to/openlint-mcp/dist/index.js --ruleset /abs/path/to/.openlint.yamlChoose where the setting is stored with --scope:
local(default): only you, only this project.project: everyone working on the project. It is written to.mcp.jsonin the project root, for committing. Claude Code asks each person to approve the server the first time.user: only you, in all your projects.
A project-scoped .mcp.json looks like this:
{
"mcpServers": {
"openlint": {
"type": "stdio",
"command": "node",
"args": ["/abs/path/to/openlint-mcp/dist/index.js", "--ruleset", "/abs/path/to/.openlint.yaml"],
"env": {}
}
}
}The paths in a committed .mcp.json must work on every teammate's machine. If your checkouts live in different places, have each person run claude mcp add with the default local scope instead.
To set the ruleset through the environment instead, use -e OPENLINT_RULESET=/abs/path/to/.openlint.yaml before --.
Check it's connected: run claude mcp list, or /mcp inside a Claude Code session.
Docs: Claude Code MCP.
Claude Desktop
Open Settings → Developer → Edit Config. That opens claude_desktop_config.json:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
Add the server:
{
"mcpServers": {
"openlint": {
"command": "/abs/path/to/node",
"args": ["/abs/path/to/openlint-mcp/dist/index.js", "--ruleset", "/abs/path/to/.openlint.yaml"]
}
}
}Use the absolute path to
node(runwhich node, orwhere nodeon Windows). Desktop apps often don't see thePATHfrom your shell, especially with version managers like nvm or asdf.On Windows, escape backslashes in JSON paths:
"C:\\Users\\you\\openlint-mcp\\dist\\index.js".Restart: quit Claude Desktop completely and start it again.
If it doesn't connect, check the logs. On macOS they're at
~/Library/Logs/Claude/mcp-server-openlint.log.
Docs: Connect to local MCP servers.
Codex
Add the server with the codex CLI. The CLI, the IDE extension and the ChatGPT desktop app share this configuration:
codex mcp add openlint -- node /abs/path/to/openlint-mcp/dist/index.js --ruleset /abs/path/to/.openlint.yamlThis writes to ~/.codex/config.toml. You can also edit that file directly:
[mcp_servers.openlint]
command = "node"
args = ["/abs/path/to/openlint-mcp/dist/index.js", "--ruleset", "/abs/path/to/.openlint.yaml"]
# Optional, instead of --ruleset:
# [mcp_servers.openlint.env]
# OPENLINT_RULESET = "/abs/path/to/.openlint.yaml"Environment variable from the CLI:
codex mcp add openlint --env OPENLINT_RULESET=/abs/path/to/.openlint.yaml -- node /abs/path/to/openlint-mcp/dist/index.js.Per project: a
.codex/config.tomlin a trusted project can hold the same table.
Check it's connected: run codex mcp list, or /mcp inside the Codex TUI.
Docs: Codex MCP.
OpenCode
Add the server with the opencode CLI. Without --global, it goes into the project's configuration:
opencode mcp add openlint -- node /abs/path/to/openlint-mcp/dist/index.js --ruleset /abs/path/to/.openlint.yamlIn some older versions, opencode mcp add doesn't take a name and command, and asks for them instead. Enter openlint as the name, choose a local server, and give the same command.
Or edit opencode.json (or opencode.jsonc) in the project root, or ~/.config/opencode/opencode.json for all projects. The format in OpenCode's current docs (V2) puts servers under mcp.servers:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"servers": {
"openlint": {
"type": "local",
"command": ["node", "/abs/path/to/openlint-mcp/dist/index.js", "--ruleset", "/abs/path/to/.openlint.yaml"],
// Optional, instead of --ruleset:
// "environment": { "OPENLINT_RULESET": "/abs/path/to/.openlint.yaml" }
},
},
},
}Older versions (V1) put servers directly under mcp, and use enabled:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"openlint": {
"type": "local",
"command": ["node", "/abs/path/to/openlint-mcp/dist/index.js", "--ruleset", "/abs/path/to/.openlint.yaml"],
"enabled": true,
},
},
}If you're not sure which format your version uses, opencode mcp add writes the right one.
Check it's connected: run opencode mcp list, or /mcps inside OpenCode.
Docs: OpenCode MCP servers.
Try it
Once the server is connected, ask your AI tool things like:
"Which OpenLint rulesets are configured?"
"Write an OpenLint ruleset that requires
info.contactin OpenAPI 3.1 documents, and validate it withvalidate_ruleset."
Development
npm ci
npm run lint # Prettier, ESLint and type-check
npm test # Vitest
npm run build # TypeScript 7 → dist/
npm run smoke # the built server over stdioCommit messages and PR titles follow conventional commits, as in OpenLint's CONTRIBUTING.md.
License
Available Tools
2 toolslist_rulesetsList rulesetsARead-only
Lists the rulesets this server is configured with. Pass a name as the ruleset argument of other tools; when ruleset is omitted, the default ruleset is used. ruleCount counts the rules that are enabled.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| rulesets | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds genuinely useful behavioral context beyond that: the names returned are valid `ruleset` arguments elsewhere, and omission falls back to a default ruleset, which implies a hidden default configuration state an agent should know about.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, each carrying distinct information: what is listed, how to use the result, and what `ruleCount` means. Nothing is redundant and the core action is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read-only tool with an output schema present, the description need not explain return values, and it already clarifies the one ambiguous output field (`ruleCount` counts enabled rules). Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4 and there is no parameter semantics to compensate for. The description correctly spends no space on inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Lists the rulesets this server is configured with" names a specific verb and resource and scopes it to this server, which cleanly separates it from the sibling validate_ruleset. An agent knows exactly what it gets back without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains what to do with the result (pass a listed name as the `ruleset` argument of other tools) and states the fallback behavior when `ruleset` is omitted (the default ruleset is used). It gives clear context for use but does not state explicit exclusions or contrast with validate_ruleset.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_rulesetValidate rulesetARead-only
Checks a YAML or JSON OpenLint ruleset without running any code. valid means the ruleset is well formed. warnings list what lint_document would refuse when the ruleset is passed inline (custom functions, or extending files, URLs or packages); such rulesets can still be configured on the server with --ruleset. JavaScript rulesets are not supported.
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | The ruleset as YAML or JSON text |
Output Schema
| Name | Required | Description |
|---|---|---|
| valid | Yes | |
| errors | Yes | |
| warnings | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint/openWorldHint annotations, it adds real context: no code is executed, JavaScript rulesets are unsupported, and what `valid` and `warnings` signify. However, it doesn't state what happens on malformed YAML/JSON input (throw vs valid=false), which is a meaningful behavioral gap for a validation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core action and followed by result semantics. The closing notes on server-side --ruleset and JavaScript are useful rather than padding, though the sentence about warnings is dense and packs several conditions.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-format detail isn't required, yet the description still explains the two key fields. For a one-parameter validation tool this is essentially complete; only error behavior on unparseable input is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With a single required parameter and 100% schema coverage, the schema already carries the load. The description's mention of 'YAML or JSON' reinforces the accepted format but adds nothing about string encoding, size limits, or file-vs-inline handling.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: 'Checks a YAML or JSON OpenLint ruleset without running any code', which tells an agent exactly what the tool operates on and that it is static analysis. It implicitly separates itself from list_rulesets by taking ruleset content rather than enumerating stored rulesets, but never names the sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the decision-relevant context: warnings indicate what 'lint_document would refuse when the ruleset is passed inline', and notes such rulesets 'can still be configured on the server with --ruleset'. That is clear guidance on when this tool's output matters and what to do with each outcome, though there is no explicit statement of when to call this versus list_rulesets.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.0.0- First observed
list_rulesets - First observed
validate_ruleset
TDQS
Scored across 2 tools
The two tools perform clearly distinct actions: listing configured rulesets versus validating a ruleset definition. Although both concern rulesets, the descriptions make the boundary unambiguous, so an agent can easily choose the right one.
Both names follow a consistent snake_case verb_noun pattern (list_rulesets, validate_ruleset). The convention is predictable and readable.
Two tools is borderline thin for a server whose apparent purpose is linting. The set covers only ruleset introspection, leaving the core linting action absent.
The description of validate_ruleset references lint_document, which is not exposed as a tool, so the central operation of an OpenLint server is missing. There is also no way to inspect individual rules within a ruleset, leaving significant gaps for agent workflows.
Maintenance
Related MCP Connectors
Deterministic validation for AI-generated artifacts: JSON Schema, OpenAPI response, SQL syntax.
Scores how well AI agents will use your API, 0-100, from its OpenAPI spec. Free and read-only.
Checks AI-written code against your rules as it is written, and keeps a record of what it found.
Detect breaking changes, generate changelogs, diff, and validate OpenAPI specs.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to browse, read, compare, and validate OpenAPI contracts for providers and consumers.1MIT
- AlicenseAqualityBmaintenanceEnables AI agents to lint API artifacts (OpenAPI, AsyncAPI, Arazzo) and manage rulesets conversationally via the Model Context Protocol.4Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with OpenAPI documents for analysis, validation, and management through structured interfaces.1,070 npm3ISC
- AlicenseAqualityDmaintenanceEnables AI clients to validate OpenAPI specs, compare versions, detect breaking changes, and generate changelogs.4MIT