MCP server
The OAuthLint MCP server lets AI coding tools check the auth code they generate, in the loop, before it ever reaches your project. It is the OAuthLint thesis made actionable: AI tools reproduce a small, predictable set of OAuth / OIDC / JWT / session / CORS / MCP server auth mistakes, so give the model a way to catch them itself.
It runs as a Model Context Protocol server over the stdio transport, the standard wiring for a local server launched by Claude Code, Claude Desktop, Cursor, Windsurf and other MCP clients.
Availability:
oauthlint-mcpis on npm. Thenpx oauthlint-mcpsetup below is all you need; MCP clients launch it for you, so there is no install step. You can also run it from source.
What you get
The server exposes four tools to the model:
scan_codescans an in-memory snippet. The model pastes the code it just wrote, names the language (javascript,typescript,python,go,java,rust,csharp,php,rubyorkotlin), and gets the findings back. The snippet is written to a private temporary file, scanned, and the temporary file is removed. It never touches your working tree.scan_pathscans a real file or directory on disk.explain_rulereturns a rule’s severity, CWE, OWASP mapping, why it matters, how to fix it, and vulnerable and safe examples (the same data asoauthlint explain).list_ruleslists the shipped rules, optionally filtered by language and minimum severity.
Findings come back as structured data the model can act on (rule id, severity, line, message, CWE, doc URL, and the autofix replacement when a rule ships one), alongside a short human-readable summary.
Requirements
The server rides on the OAuthLint CLI, so it is self-contained the same way: nothing to install and no config. On first scan it downloads and checksum-verifies a small pinned scan engine (~41 MB, one time, cached), reusing an installed opengrep or semgrep if one is on your PATH; override it with OAUTHLINT_ENGINE. If the engine cannot be obtained (offline on first run with nothing installed), the scan tools return a clear, actionable error rather than failing silently.
You need Node.js 20 or newer. There is no install step for the server itself; MCP clients launch it with npx oauthlint-mcp.
Wiring it into your tool
Each client reads an mcpServers block. Add OAuthLint to it and reload the tool.
Claude Code and Claude Desktop
For Claude Code, add the server to your project .mcp.json. For Claude Desktop, edit claude_desktop_config.json.
{
"mcpServers": {
"oauthlint": {
"command": "npx",
"args": ["-y", "oauthlint-mcp"]
}
}
}
Cursor
Edit ~/.cursor/mcp.json for all projects, or .cursor/mcp.json inside one project.
{
"mcpServers": {
"oauthlint": {
"command": "npx",
"args": ["-y", "oauthlint-mcp"]
}
}
}
Windsurf
Edit ~/.codeium/windsurf/mcp_config.json.
{
"mcpServers": {
"oauthlint": {
"command": "npx",
"args": ["-y", "oauthlint-mcp"]
}
}
}
After saving, restart or reload the tool so it discovers the server. You should then see the four OAuthLint tools available to the model.
Run from source
Until oauthlint-mcp is on npm, run it from a local checkout. Clone the repo, install dependencies, and build this package:
git clone https://github.com/Auspeo/oauthlint
cd oauthlint
pnpm install
pnpm --filter oauthlint-mcp build
That gives you an executable at mcp/bin/oauthlint-mcp.js. Point your client at it with node and the absolute path, in place of the npx command above:
{
"mcpServers": {
"oauthlint": {
"command": "node",
"args": ["/absolute/path/to/oauthlint/mcp/bin/oauthlint-mcp.js"]
}
}
}
When the npm release lands, swap this back for the npx oauthlint-mcp configuration.
Using it
Once it is wired in, you can ask the model to use it directly:
Before you give me that login handler, scan it with OAuthLint.
To make this automatic, tell the model in your system prompt or rules file to call scan_code whenever it generates authentication, token, session or CORS code, and to fix anything it reports before showing you the result. That turns OAuthLint into a guardrail the model runs against itself.
Security
The server is built to the same bar as the rest of OAuthLint:
- Snippets are written to a unique private temporary directory and removed afterwards, even on error. The temporary path is never returned to the caller.
- No input is passed through a shell. Targets are handed to Semgrep as discrete arguments after a
--separator, so a path or snippet can never be read as a flag. - Scans run with a time budget and an output cap, so a pathological input cannot hang the server or exhaust its memory.
- Inputs are validated at the protocol boundary; unknown languages, empty or oversized snippets, and bad severities are rejected before anything runs.
If Semgrep is not installed, the scan tools return a clear error with install instructions rather than failing silently.