Connecting a client
Two credentials reach this server, and the choice is about who is at the keyboard.
| Sign in | API key | |
|---|---|---|
| What you handle | Nothing | A secret you place and rotate |
| Lifetime | One hour, refreshed silently | Until you revoke it |
| Read or write | Chosen by the approver, per connection | Fixed by the key's scope |
| Scoped to | One organization | One organization |
| Where you revoke it | Settings > API Keys > Connected Applications | Settings > API Keys |
| Good for | A person at an assistant | CI, a shared runner, a script |
Both reach the same tools, and both resolve your organization from the credential, never from an argument. Signing in is the only route your client can start on its own, which is why l4 mcp install installs a key instead.
Configure your client
claude mcp add --transport http levelfour https://mcp.levelfour.ai/mcpRun /mcp, choose levelfour, then Authenticate. Your browser opens the approval screen.
--scope local is the default and keeps the server to the current project. --scope user makes it available in every project. --scope project writes .mcp.json into the repository for your team, which works here because no credential is in the file: each teammate authenticates as themselves.
Confirm it registered, and remove it:
claude mcp list
claude mcp get levelfour
claude mcp remove levelfourTo send a key instead, add the header at registration time:
claude mcp add --transport http levelfour https://mcp.levelfour.ai/mcp \
--header "Authorization: Bearer $LEVELFOUR_TOKEN"--header is variadic, so it has to come after the name and the URL. Put it first and it swallows both, and the command exits having done nothing.Claude connects over OAuth and has no field for a header, so signing in is the only route. In Settings > Connectors, add a custom connector with the URL https://mcp.levelfour.ai/mcp. Claude registers itself and sends you to the approval screen.
Claude identifies itself with a metadata document served from its own domain, so this connection does not carry the unreviewed-application notice. Approving a connection explains why a locally installed client does.
Write ~/.cursor/mcp.json for every project, or .cursor/mcp.json for one:
{
"mcpServers": {
"levelfour": {
"url": "https://mcp.levelfour.ai/mcp"
}
}
}With no header, Cursor discovers that the server wants authorization and offers to sign you in. To send a key instead, add a headers block:
{
"mcpServers": {
"levelfour": {
"url": "https://mcp.levelfour.ai/mcp",
"headers": {
"Authorization": "Bearer ${env:LEVELFOUR_TOKEN}"
}
}
}
}${env:...} in url and headers, so export LEVELFOUR_TOKEN in the shell that launches Cursor and the key stays out of the file. LEVELFOUR_TOKEN is the variable l4 itself reads, so one export serves the CLI and the client. You commit a project-level .cursor/mcp.json with your code, which is the reason to keep keys out of it.Run MCP: Add Server from the Command Palette, or write .vscode/mcp.json in the workspace:
{
"servers": {
"levelfour": {
"type": "http",
"url": "https://mcp.levelfour.ai/mcp"
}
}
}VS Code prompts you to sign in on first use. To send a key instead, add a headers block with an inputs entry, which keeps the value out of the file and in the editor's own secret storage:
{
"servers": {
"levelfour": {
"type": "http",
"url": "https://mcp.levelfour.ai/mcp",
"headers": {
"Authorization": "Bearer ${input:levelfour-api-key}"
}
}
},
"inputs": [
{
"id": "levelfour-api-key",
"type": "promptString",
"description": "LevelFour API key",
"password": true
}
]
}Write ~/.codeium/windsurf/mcp_config.json. Windsurf spells the endpoint serverUrl where the others use url:
{
"mcpServers": {
"levelfour": {
"serverUrl": "https://mcp.levelfour.ai/mcp",
"headers": {
"Authorization": "Bearer l4_live_your_key_here"
}
}
}
}Restart Windsurf after saving.
A client that speaks MCP over streamable HTTP connects the same way: point it at https://mcp.levelfour.ai/mcp. If it implements MCP authorization it will discover the server, register itself and send you to the approval screen. If it does not, give it an Authorization: Bearer <key> header. Goose, Zed and Cline all work. You write their config yourself.
For a client that starts a local process rather than calling a URL, l4 mcp serve runs the read tools on your own machine against the credential in your keychain.
Getting an API key
From the dashboard. Open Settings > API Keys, create a key, and copy it. You see the value once. A read key reaches every tool that only reads. The ones that record a decision need a read-write key. See Key scopes for the full split.
From the CLI. l4 mcp install uses the credential l4 already holds and only opens the browser to mint a read key when there is none, so it doubles as the quickest way to get one. Pass --token to install a specific key instead.
Troubleshooting
A rejected credential returns 401 with a WWW-Authenticate header pointing at the server's protected resource metadata, which is how a client discovers where to authorize. The status alone does not separate the causes, so work through them in order.
| Symptom | Cause | Fix |
|---|---|---|
401, and the client offers to sign in | Normal on a first connection. The server is telling the client where to authorize | Complete the approval in the browser |
401 after signing in | The token expired and the refresh failed, or somebody closed the connection in the dashboard | Authenticate again. A closed connection stays closed until you approve a new request |
401 with a key | The key never arrived, is not an l4_live_ or l4_test_ value, or is revoked or expired. A dashboard session token is rejected before any lookup | Restart the client, confirm the header is present and starts with Bearer , and that the value is the API key itself. Create a new key if it is revoked |
401 that no valid credential fixes | The organization does not have the MCP module. The server refuses the credential rather than naming the reason | Start the connection and read the approval screen, which does name it. Then talk to your LevelFour contact |
| The approval screen says only an administrator can approve | Approving hands out a credential, so it is limited to administrators | Ask an administrator to start the connection themselves, rather than forwarding the link |
| The approval request has expired | A request is live for ten minutes and can be used once | Start the connection again from the client |
421 Misdirected Request | The request arrived under a host the server does not answer on, usually a proxy rewriting Host | Point the client straight at mcp.levelfour.ai |
429 | Too many requests on this credential or from this address | Back off for the seconds in Retry-After. Reading a result has the limits |
| A tool reports a plan restriction | Your plan does not include that content | Call get-identity to see what the plan covers |
| Tools missing after editing config | The client read its config at startup | Restart the client |
Next
- Approving a connection is what the browser asks, and when to refuse
- Tools is every tool, parameter, enum and default
- Reading a result is the shape of what comes back, and what an error looks like
- CLI authentication covers keys for
l4, including the read-write key its write commands need
MCP Overview
A remote MCP server over your cloud spend, savings backlog, and realized savings. Most tools read; the rest record a decision. Connect by signing in, no key to copy.
Approving a connection
What the LevelFour approval screen asks, why some applications carry an unreviewed notice, and when to refuse.