Paste an mcpServers config to validate it. Checks the transport shape, catches common mistakes and flags hard-coded secrets. Free, runs in your browser.
MCP clients are unhelpfully quiet about broken configuration. A missing comma, a server with neither a command nor a url, a httpUrl key where url was meant — and the server simply does not appear. No error, no toast, no log entry you would think to look for. You restart the client, the tool list is unchanged, and you start suspecting the server itself.
This validator turns that silence into a list. Paste your config, and it parses the JSON, checks the structure a client actually requires, classifies each server's transport, and scans the environment variables and headers for credentials you probably did not mean to commit. Results appear live as you type, split into errors that will stop the config working and warnings that will not. It runs entirely in your browser — nothing is uploaded, which is the only responsible way to lint a file that by nature contains tokens.
The checks are worth listing precisely, because knowing what a linter does not look at is as useful as knowing what it does.
| Check | Severity | Fires when |
|---|---|---|
| JSON parses | Error | The text is not valid JSON. Reports the parser's message plus a line hint. |
| Root is an object | Error | The top level is an array, a scalar, or null. |
| Servers key present | Error | Neither mcpServers nor servers exists at the root. |
| Servers value is an object | Error | The servers key holds an array or a scalar instead of a name-to-config map. |
| Servers map non-empty | Warning | The object exists but defines nothing. |
| Each server is an object | Error | A server name maps to a string, array or null. |
| Exactly one transport | Error | A server has neither command nor url, or has both. |
| Misnamed URL key | Error | No url, but one of httpUrl, serverUrl, endpoint, uri or href is present. Names the key and the fix. |
command is a non-empty string | Error | The key exists but holds an empty string or a non-string. |
args is an array | Error | args is present but is not an array. |
args holds only strings | Warning | An array element is a number, boolean or object. |
env / headers are objects | Error | Either is present but is an array, scalar or null. |
url is a non-empty string | Error | The key exists but is empty or not a string. |
url is absolute http(s) | Warning | It does not begin with http:// or https://. |
| Plain HTTP off-localhost | Warning | http:// to anything other than localhost or 127.0.0.1. |
| Recognised remote transport | Warning | A type or transport value that is not http, sse, streamable-http or streamableHttp. |
| Hard-coded secrets | Warning | See the section below. |
A config is reported as valid when there are zero errors. Warnings alone give you a "Valid (with warnings)" badge — they are things worth fixing, not things that will stop the client loading the file.
The validator accepts mcpServers (Claude Code, Claude Desktop, Cursor) or servers (VS Code), checking for mcpServers first. Everything downstream is identical, and findings are labelled with whichever key you actually used, so the field path in a message reads servers.my-server.args or mcpServers.my-server.args to match your file.
It does not, however, tell you that you used the wrong one for your client. A file with servers validates cleanly even if you are about to paste it into Claude. The structural check is client-agnostic; picking the right key for the right client is a step earlier, and the MCP server config generator emits the correct dialect for each.
An MCP server is either local, launched as a process and spoken to over stdio, or remote, reached over HTTP. In config terms that means command or url — exactly one. The validator treats both violations as errors:
command behind. Which one wins is client-dependent, so it may work on your machine and not a colleague's.The misnamed-key check is the same failure with a friendlier cause. If there is no command and no url but there is an endpoint or an httpUrl, the tool assumes you meant a remote server and tells you to rename the key rather than just reporting an absence. Remote MCP servers use url.
The scanner walks every string value inside each server's env and headers objects and flags two different things.
Values that look like real credentials. These are matched against a fixed set of patterns:
| Pattern name | Recognises |
|---|---|
| OpenAI / Anthropic style key | An sk- prefix followed by 16 or more identifier characters |
| GitHub token | ghp_, gho_, ghu_, ghs_ or ghr_ plus 20 or more alphanumerics |
| AWS access key id | AKIA followed by 16 uppercase alphanumerics |
| Google API key | AIza followed by 30 or more identifier characters |
| Slack token | xoxb-, xoxa-, xoxp-, xoxr- or xoxs- plus 10 or more characters |
| Bearer token | The word Bearer followed by 16 or more token characters |
| JWT | An eyJ-prefixed three-segment dotted token |
| Long high-entropy string | A whole value of 32 or more base64-style characters |
Key names that suggest a credential. Separately, the name is matched against terms including token, secret, api_key, apikey, password, auth, authorization, access_key, private_key, client_secret, bearer, credential and session_key. If the name looks sensitive and the value is a literal, you get a warning even when the value matches none of the patterns above — an internal token with no recognisable prefix is still a token.
Both checks skip anything that is obviously a placeholder, so the tool stays quiet about the things it should. Recognised as placeholders: an empty value, shell-style indirection such as ${API_KEY} or $API_KEY, Windows-style %API_KEY%, angle-bracket stand-ins, plain booleans, null, bare numbers, and any value containing words like your, example, placeholder, changeme, here, todo, replace or a run of x's. Every warning includes the suggested rewrite in ${VARIABLE} form with the name upper-cased and non-alphanumerics turned into underscores.
Findings are grouped with errors first, each showing a field path such as mcpServers.remote-docs.url, an approximate line number, and a message that names the fix rather than restating the rule. The Copy report button produces a plain-text summary — a status line with the server count or the error and warning totals, then one line per finding in [SEVERITY] field (line N): message form. That format exists to be pasted into a ticket or a message to whoever owns the config.
The Load example button fills the box with a two-server config that deliberately contains both an sk- style key in env and a GitHub token in an Authorization header, so you can see the secret scanner fire without pasting anything of your own.
config.toml will fail at the parse step. The error message says so explicitly rather than leaving you guessing.mcp.json containing // comments — which the editor itself tolerates — will be reported as invalid. Strip the comments before pasting.type value is only checked on remote servers. A type alongside a command is not examined.servers for VS Code, mcpServers for the others.command and args in a terminal yourself. Clients spawn processes without your interactive shell's PATH, so a command that works for you may not be found by the client; an absolute path settles it.url with the same headers and check the status code before blaming the client.When the parse fails, the tool reports the parser's own message together with a line hint derived from the character position in that message. The messages are terse but they are predictable, and a handful of causes account for nearly all of them.
| What you see | What it usually means |
|---|---|
| Unexpected token at a position mid-file | A missing or extra comma, most often after the last entry in an object. |
| Unexpected end of JSON input | An unclosed brace — usually the outermost one, after pasting an inner block on its own. |
| Unexpected token in a comment line | // or /* */ in the file. Strict JSON has no comments. |
| Unexpected token near a quotation mark | Smart quotes from a document or chat client instead of straight ASCII quotes. |
| Bad escape in a string | A Windows path with single backslashes. Each one must be doubled inside a JSON string. |
| An error on line 1 of a file that looks fine | TOML pasted into a JSON validator — the message says so explicitly. |
Because the parse is all-or-nothing, a single syntax error suppresses every structural and secret finding in the file. Fix the JSON first, then re-read the report: the second pass is usually where the real problems appear.