Docs menu

Get started

Install LexLint in another MCP client

The configuration every streamable HTTP client shares, and the two fields that move between clients.

https://mcp.lexlint.io/mcp
{ "mcpServers": { "lexlint": { "url": "https://mcp.lexlint.io/mcp" } } }

Any client that speaks streamable HTTP works: the server is stateless and holds no session of its own, so nothing has to be kept between calls. The block above is the common core, and Cursor takes it exactly as written.

The shared block is a core rather than a universal config because two fields move between clients, and between them they account for nearly every failed setup: what the URL field is called, and what the transport is called. Neither is guessable and a client that dislikes your answer rarely says so. Find your client in the table before you paste.

Find your client

ClientRoot keyURL fieldTransport
CursormcpServersurlomit it
Zedcontext_serversurlomit it
AntigravitymcpServersserverUrlomit it
Devin DesktopmcpServersserverUrlomit it
Copilot in VS Codeserversurlhttp
TabninemcpServersurlhttp, or omit
ClinemcpServersurlstreamableHttp
KiromcpServersurlstreamable-http
IBM BobmcpServersurlstreamable-http
Kilo Code, the extensionmcpServersurlstreamable-http
Kilo Code, the CLImcpurlremote
ContinuemcpServers, a YAML listurlstreamable-http
Codexmcp_servers, a TOML tableurlsee the Codex page

Two of those are worth saying out loud, because they fail silently rather than loudly. VS Code reads servers, so a file that says mcpServers parses and registers nothing. What you see is a client with no LexLint tools, and nothing anywhere naming the key. Antigravity and Devin Desktop want serverUrl and reject a plain url, which is the same failure wearing a different field name. In both cases the natural conclusion is that mcp.lexlint.io is down, and it is not.

The transport is the other half, and the spellings are not interchangeable: streamableHttp is camel-cased for Cline, streamable-http is hyphenated for Kiro, Kilo and Continue, and http is VS Code's alone. Give Cline the hyphenated form and it falls back to the older SSE transport and answers 405. Where the table says to omit it, omit it: those clients infer the transport from the presence of a URL, and an unexpected value is one more thing that can be rejected.

Then add your key

Nothing above carries a key, which is deliberate: check_access answers without one, reporting key_present: false beside a sign-in link and the steps, so you can prove the connection before you have anything to paste. claim_trial_key answers keyless too, and mints one. The other six refuse until you have a key, carrying the same link in the refusal.

When you do have one it goes in a headers object, which every client in the table accepts under that name. The key goes in X-API-Key and nowhere else: an Authorization: Bearer header is read as an OAuth access token, never as a key. Mind the comma the URL line gains:

"url": "https://mcp.lexlint.io/mcp", "headers": { "X-API-Key": "${UNGOVR_API_KEY}" }

That is a second edit to the same file, and for these clients nothing will make it for you. Claude Code has /lexlint-key to write the key where the next session will read it, and Codex has its own documented step; a client outside those two has neither.

${UNGOVR_API_KEY} is the plain-environment form, and expansion is the client's job. Three of the clients above do it their own way, and a placeholder a client does not expand is sent to us as literal text, which reads back as a rejected key rather than as a config error. Cursor wants ${env:UNGOVR_API_KEY}. Continue templates secrets as ${{ secrets.UNGOVR_API_KEY }}. VS Code expands neither, and wants an input declared and referenced, which is the better shape anyway because VS Code prompts once and stores the value itself rather than leaving it in a file you might commit:

{ "inputs": [ { "type": "promptString", "id": "lexlint-key", "description": "UnGovr Open Data key", "password": true } ], "servers": { "lexlint": { "type": "http", "url": "https://mcp.lexlint.io/mcp", "headers": { "X-API-Key": "${input:lexlint-key}" } } } }

Continue is the one whose whole shape differs: a list rather than an object, and headers under requestOptions rather than at the top level.

mcpServers: - name: LexLint type: streamable-http url: https://mcp.lexlint.io/mcp requestOptions: headers: X-API-Key: ${{ secrets.UNGOVR_API_KEY }}

Anywhere your client expands nothing, paste the key literally and treat the file as the secret it then contains.

If your client only speaks stdio

Some clients, and some older builds of clients that have since added HTTP, will only launch a local process. mcp-remote bridges the two: it speaks stdio to your client and streamable HTTP to mcp.lexlint.io, and it needs nothing installed beforehand.

{ "mcpServers": { "lexlint": { "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.lexlint.io/mcp", "--header", "X-API-Key:${UNGOVR_API_KEY}"] } } }

There is no space after that colon, and putting one back breaks it on several clients: Cursor, the Codex CLI and Claude Desktop on Windows do not escape spaces inside args when they invoke npx, so the value arrives cut in half. Note also that anything written into args literally is readable in the process list by anyone else on the machine, which is a second reason to leave the key in the environment and let ${UNGOVR_API_KEY} stand.

On a managed or on-premises client

IBM Bob, Tabnine, Kiro and Copilot on GitHub Enterprise Server each read a file of your own, and all four are in the table above: Bob takes ~/.bob/mcp.json, or .bob/mcp.json committed with the project, and Tabnine takes ~/.tabnine/agent/settings.json. What changes on their governed deployments is who is allowed to write one. An administrator registers servers centrally and user-level additions may be refused, and that registration usually needs two things past the URL.

The first is reachability. mcp.lexlint.io is the only host LexLint asks for, so on an egress-filtered network it is one allowlist entry and no more, and on one that routes through an approved proxy it is one rule there. A genuinely air-gapped install is the exception and the answer is plain: LexLint is a hosted service and there is no offline build of it, so it cannot run in a network with no route out. Several of the clients above are chosen precisely for air-gapped work, and on those deployments this is not something an allowlist fixes.

The second is the key. Admin consoles rarely expand environment variables, so it goes in as a literal and the registration becomes a secret to be handled as one. A key minted for the team rather than for a person is the usual answer, since the upstream meter counts against whoever the key belongs to.

The worked run shows what a full lint looks like from the agent's side, whichever of these got you connected.