@atlasent/mcp-server brings AtlaSent authorization to agents that speak the Model Context Protocol: Claude Desktop, Claude Code, Cursor, Windsurf, or your own MCP host. The agent asks AtlaSent before a consequential action, receives a Decision, and on allow gets a bounded Permit that must pass verification before the side effect runs.
- npm:
@atlasent/mcp-server(see npm for the current release) - MCP Registry:
io.github.Atlasent/mcp-server - Source: Atlasent/atlasent-mcp-server (Apache-2.0)
How it works
allow Decision alone is not the gate: the Permit has to verify immediately before the protected side effect.
Modes
The server runs in one of two modes, chosen byATLASENT_MODE:
When
ATLASENT_MODE is unset, the server uses remote if ATLASENT_API_KEY is set and local otherwise.
Install
Try it with no account (local mode)
ATLASENT_MODE=local, then ask your agent to “deploy billing-api to production.” The built-in rules deny it because it has no approvals.
Connect to AtlaSent (remote mode)
- Create an account.
- In the console, open API keys and create a key with the
evaluate:writeandverify:executescopes. - Add the server to your MCP host with the key, as shown below.
Claude Desktop
Add toclaude_desktop_config.json, then restart Claude Desktop:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Cursor and Windsurf
Use the samemcpServers block:
- Cursor:
.cursor/mcp.jsonin the project, or~/.cursor/mcp.jsonglobally. - Windsurf:
~/.codeium/windsurf/mcp_config.json.
npx, arguments ["-y", "@atlasent/mcp-server"], and the same environment variables. Registry-aware hosts can install it directly as io.github.Atlasent/mcp-server.
Streamable HTTP transport
The server speaks stdio by default. For hosts that connect over HTTP, start it with--transport streamable-http (or set ATLASENT_MCP_TRANSPORT=streamable-http):
http://127.0.0.1:3333/mcp. ATLASENT_MCP_HTTP_HOST, ATLASENT_MCP_HTTP_PORT, and ATLASENT_MCP_HTTP_PATH change that. Set ATLASENT_MCP_HTTP_BEARER to require hosts to send Authorization: Bearer <value>; when it’s unset, the server accepts requests without host authentication and logs a warning at startup, so leave it unset only for loopback, single-user use. The bearer authenticates your host to this server; ATLASENT_API_KEY still authenticates this server to AtlaSent.
Claude Code plugin
A separate, local-only Claude Code plugin makes destructive and shipping commands (for exampleDROP TABLE, terraform destroy, git push --force, production deploys) wait for a person at the keyboard. It needs no account.
Docker
The repository ships aDockerfile. Build it from a clone of the source repository:
Environment variables
Core tools
The server also exposes read and administrative tools for policies, permits, audit events, evidence exports, webhooks, SCIM, SIEM, and VQP. Call MCP
tools/list for the exact inventory of the version you installed.
No tool approves an action. Approvals are made by a person in the AtlaSent console, never by an agent.
Agent pattern
Fail-closed behavior
Treat each of these as stop:- any Decision other than
allow - a missing Permit
- an authentication, network, or API error (the server turns errors into
deny, or intovalid: falseon verify) - an invalid, expired, revoked, replayed, or mismatched Permit
- a missing required binding
Binding the Permit to the exact payload and target
To make a Permit valid only for one exact payload, bind a digest at evaluate time and present the same digest at verify time.- Send
execution_payload_hashas a bare 64-character hexadecimal SHA-256 digest at the top level of the evaluate request, not insidecontextand not with asha256:prefix. For ordinary action types the API drops a value, without an error, in any other shape and binds the Permit to its own hash of the request instead, so your digest never constrains execution. Change-control action types deny it outright. - The MCP server helps: it strips a
sha256:prefix, converts the digest to lowercase, and refuses anything that isn’t a 64-hex SHA-256 value rather than sending it. - Check
execution_payload_hash_acceptedin the evaluate response.falsemeans the Permit isn’t bound to your digest. - Pass
target_idto bind the Permit to one target. Presenting a different target at verify time fails. Presenting a target at verify time that was never bound at evaluate time checks nothing.
Change plans and approvals
production.deploy, infrastructure.change, production.rollback, and secret.configuration.change require a change_plan ({ operation, revision?, artifact_ref? }, with a revision or an artifact reference). Pass it to deploy_service, evaluate, or atlasent_evaluate.
When an action is held for a person, the result carries an approval_request_id. Call atlasent_await_approval with it. A rejection, expiry, or timeout returns no Permit, and the action doesn’t run. If your plan changed while you waited, pass the new plan as change_plan and the server files one linked re-request for it.