atlasent-mcp
OfficialProvides a guard decorator for LangChain agents to enforce authorization policies on tool invocations.
@atlasent/mcp-server
Authorize every AI agent tool call before it executes.
An MCP server that plugs into any Model Context Protocol-compatible agent (Claude Desktop, Cursor, Claude Code, Copilot, LangChain) and enforces a simple contract: no protected action runs until AtlaSent has authorized it. Denied calls never reach the target system. Allowed calls return a permit token you can verify afterwards to close the audit loop.
Ships with a local rules engine so you can run the full evaluate → act → verify flow in under a minute, with zero credentials. The hosted AtlaSent backend is a configuration swap, not a rewrite.
When an agent "gets stamped" before acting — a human submits, approves, or stamps the prepared work — that stamp is an authorization event. AtlaSent turns it into a permit you verify before execution. Human approval is one source of authority; a policy rule, a deployment gate, or a risk-engine decision are others. Every source produces the same thing: a verifiable permit.
Run the demo in 60 seconds
git clone https://github.com/AtlaSent-Systems-Inc/atlasent-mcp-server.git
cd atlasent-mcp-server
npm install
npm run build
npm run demoYou'll see five scenarios run end-to-end — two use cases in one demo:
Deploy gate (CI/CD pipelines):
Scenario A: agent attempts unauthorized deploy (prod, no approvals)
[1] Agent calls deploy_service
[2] MCP intercepts → calls authorize(ctx) → policy engine decides
[3] Tool execution BLOCKED
✓ deploy did NOT run. The target system was not touched.
✓ reason: Production action 'production.deploy' requires at least one approval...
Scenario B: agent attempts authorized deploy (prod, with approval)
[3] Tool execution PROCEEDS
result: {"status":"deployed","service":"billing-api",...}
Scenario C: verify_permit closes the audit loop
result: {"outcome":"verified","valid":true,...}Agent tool call governance (MCP / AI-native builders):
Scenario D: agent evaluates agent.db.delete without a change window
[1] Agent calls evaluate before running agent.db.delete
[3] Tool execution HELD — awaiting human review
✓ database delete did NOT run. Queued for human review.
Scenario E: agent evaluates agent.search.web (safe read)
[3] Tool execution PROCEEDS — agent searches the web
✓ web search authorized.
[4] verify_permit closes the audit loop: {"outcome":"verified","valid":true}AtlaSent governs any action_type — not just deploys. The same evaluate →
permit → verify flow that gates CI/CD pipelines also governs your agent's
database writes, web searches, and external API calls.
The demo uses local mode (no API key needed). To run the same demo against the hosted AtlaSent backend once your API key is issued:
ATLASENT_MODE=remote \
ATLASENT_API_KEY=ask_live_xxx \
ATLASENT_BASE_URL=https://api.atlasent.io/functions/v1 \
ATLASENT_MCP_READONLY=1 \
npm run demo
ATLASENT_BASE_URLdefaults tohttps://api.atlasent.io/functions/v1. You can omit it unless you are on a self-hosted deployment.
ATLASENT_MCP_READONLY=1 is recommended for any live-API demo — see Read-only mode below.
Related MCP server: AgentWall
Agent tool call governance
AtlaSent is not a deploy gate product. It is execution-time authorization infrastructure. The action_type field is yours to define — any string your agent platform uses to name a tool invocation becomes a protected action.
Common agent action types:
// Database mutations
"agent.db.write" // INSERT / UPDATE
"agent.db.delete" // DELETE / TRUNCATE (destructive — triggers hold)
// External network calls
"agent.search.web" // Read-only web search
"agent.api.post" // Outbound POST to an external service
// File system
"agent.fs.write" // Write or overwrite a file
"agent.fs.delete" // Delete a file
// Code execution
"agent.code.execute" // Run user-supplied codePattern — agent evaluates before every sensitive tool call:
// Before running a tool, the agent calls evaluate
const ctx = {
action_type: "agent.db.delete", // your action namespace
actor_id: "agent:data-pipeline", // which agent is acting
environment: "production",
// any context your policies need
};
const decision = await authorize(ctx); // interception point
if (decision.decision !== "allow") {
// Tell the LLM the tool was blocked and why
return `Tool blocked: ${decision.reason}`;
}
// Run the tool
const result = await runDatabaseDelete(ctx);
// Close the audit loop
await verify(decision.permit_token, ctx);If you are using LangChain, the @atlasent/guard package wraps this pattern as a one-liner decorator — see atlasent-sdk.
If you are building your own MCP server with protected tools, copy the deploy_service handler in src/server.ts — it is the canonical 20-line interception pattern. Wire atlasent_evaluate before any tool that writes, deletes, calls external APIs, or runs code.
Tools
atlasent_evaluate — evaluate an action against AtlaSent policies
Evaluate whether a subject is permitted to perform an action on a resource. Returns a decision (allow/deny/hold/escalate), a permit_token if allowed, an evaluation_id, and an optional reason.
Input: { subject, action, resource, org_id, context? }
Output: { decision, permit_token?, evaluation_id?, reason?, ... }Example:
{
"subject": "user:alice",
"action": "production.deploy",
"resource": "env:prod",
"org_id": "org_abc123",
"context": { "ip": "10.0.0.1" }
}atlasent_list_policies — list all policies for an organization
Returns all policies for the given org, optionally filtered by status.
Input: { org_id, status? } (status: "draft" | "shadow" | "enforce")
Output: array of policy objectsExample: { "org_id": "org_abc123", "status": "enforce" }
atlasent_get_policy — get a single policy by ID
Fetches the full policy definition for a given policy_id.
Input: { policy_id, org_id }
Output: policy objectExample: { "policy_id": "pol_xyz789", "org_id": "org_abc123" }
atlasent_list_audit_events — query the audit event log
Query recent evaluation decisions. Use to verify that an evaluation was recorded or to investigate a sequence of decisions.
Input: { org_id, evaluation_id?, from?, to?, limit? }
(from/to: ISO 8601; limit: 1–100, default 20)
Output: array of audit event objectsExample:
{
"org_id": "org_abc123",
"from": "2025-01-01T00:00:00Z",
"to": "2025-01-02T00:00:00Z",
"limit": 50
}atlasent_create_policy — create an authorization policy
Mutating tool — gated off when
ATLASENT_MCP_READONLY=1.
Define a new authorization rule. New policies are created in draft state (no enforcement) and must be promoted to shadow or enforce to take effect.
Input: { org_id, policy_id, title, policy_type, rules, description?, status?, ... }
Output: { policy_id, title, status, ... }atlasent_update_policy — update an existing policy
Mutating tool — gated off when
ATLASENT_MCP_READONLY=1.
Partial-update (PATCH) a policy's rules, metadata, or lifecycle status (e.g. promote draft → enforce).
Input: { policy_id, org_id, title?, rules?, status?, ... }
Output: { policy_id, status, ... }atlasent_delete_policy — permanently delete a policy
Destructive tool — gated off when
ATLASENT_MCP_READONLY=1.
Irreversibly remove a policy. Prefer setting status: "archived" via atlasent_update_policy when you only want to disable enforcement.
Input: { policy_id, org_id }
Output: {} (empty on success)atlasent_list_permits — list issued permits
Paginated list of permits for an organization, with optional filters by status, actor, action type, and time range.
Input: { org_id, status?, actor_id?, action_type?, from?, to?, limit?, cursor? }
Output: { permits: [...], next_cursor? }atlasent_revoke_permit — revoke an issued permit
Destructive tool — gated off when
ATLASENT_MCP_READONLY=1.
Immediately invalidate a permit so subsequent verify calls fail with permit_revoked. Idempotent.
Input: { permit_id, org_id, reason? }
Output: { revoked, permit_id, ... }atlasent_permit — issue a permit token out-of-band
Mutating tool — gated off when
ATLASENT_MCP_READONLY=1.
Mint a time-limited permit for a subject/action/resource outside of the standard evaluate flow — for example when a human pre-approves access.
Input: { subject, action, resource, org_id, ttl_seconds?, context? }
Output: { permit_token, expires_at?, ... }atlasent_verify_permit — verify a permit token (v1 REST)
Verify a permit token is currently valid for a given subject/action/resource. Use after completing an authorized action to close the audit loop.
Input: { permit_token, org_id, action?, resource? }
Output: { valid, outcome, reason? }atlasent_create_approval_request — request human approval
Submit an action for human sign-off. Call when atlasent_evaluate returns hold or when the agent knows approval is required. Do not proceed until resolved.
Input: { subject, action, resource, org_id, justification?, context? }
Output: { approval_request_id, status, created_at, ... }atlasent_resolve_approval_request — approve or deny a request
Approve or deny a pending approval request on behalf of a human reviewer.
Input: { approval_request_id, org_id, resolution, resolver_id, comment? }
(resolution: "approve" | "deny")
Output: { approval_request_id, status, resolver_id, ... }atlasent_record_execution_evaluation — record execution outcome
Record the outcome of an authorized action to complete the full audit loop: evaluate → execute → record.
Input: { evaluation_id, org_id, outcome, executed_at?, details? }
(outcome: "success" | "failure" | "skipped")
Output: { execution_id, outcome, recorded_at, ... }atlasent_create_webhook — register a webhook
Mutating tool — gated off when
ATLASENT_MCP_READONLY=1.
Subscribe an external HTTPS endpoint to real-time AtlaSent events (e.g. evaluation.deny, approval.requested, permit.revoked).
Input: { org_id, url, events, description?, secret? }
Output: { webhook_id, url, events, secret?, ... }atlasent_delete_webhook — remove a webhook
Destructive tool — gated off when
ATLASENT_MCP_READONLY=1.
Permanently deregister a webhook. AtlaSent stops sending events to that URL immediately.
Input: { webhook_id, org_id }
Output: {} (empty on success)evaluate — for agents that gate themselves (local/remote mode)
The agent calls evaluate before any sensitive action and respects the decision.
Input: { action_type, actor_id, environment, approvals?, change_window? }
Output: { decision: "allow" | "deny" | "hold", permit_token?, reason?, audit_id?, ... }verify_permit — close the audit loop
After the action runs, the agent calls verify_permit with the issued token.
Input: { permit_token, action_type, actor_id, environment, ... }
Output: { outcome: "verified" | "expired" | "invalid" | "error", valid: boolean, ... }deploy_service — demo of the interception pattern
A protected tool that authorizes itself before executing. Every call:
Builds an action context from the tool arguments
Calls
authorize(ctx)— this is the interception pointIf the decision is anything other than
allow, returns the decision and does NOT executeOn
allow, runs the deploy and returns the result plus the permit token
See src/server.ts (the deploy_service handler) for the exact 20-line pattern every protected tool should follow. In production, your domain tools live on other MCP servers and call AtlaSent's evaluate tool before executing; this demo co-locates them so you can see the full flow today.
Execution Flow
┌─────────────┐
│ Agent │ wants to call a protected tool
└─────┬───────┘
│
▼
┌───────────────────────┐
│ Protected tool │
│ (e.g. deploy_service) │
└─────┬───────────────────┘
│ (1) build ActionContext
▼
┌─────────────────┐ ┌──────────────────────────┐
│ authorize(ctx) │──────▶│ engine (local | remote) │
└─────┬───────────┘ └────────┬─────────────────┘
│ (2) Decision │
│ allow | deny | hold │
▼ ▼
┌────────────────────────────────────┐
│ decision === "allow"? │
└──┬───────────────────────┬───────────────┘
│ no │ yes
▼ ▼
BLOCKED (3) execute the action
return decision │
▼
(4) return { decision, permit_token, result }
│
▼
later: verify_permit closes the audit loopThe interception point is step (2): authorize() runs before the action. That's the entire guarantee — if decision !== "allow", the action does not run.
Decision envelope
Every authorization result uses the same shape, so agents and hosts handle all outcomes uniformly:
type Decision =
| { decision: "allow"; permit_token: string; audit_id?: string; conditions?: string[] }
| { decision: "deny"; reason: string; audit_id?: string }
| { decision: "hold"; reason: string; hold_id?: string; audit_id?: string };Verification has a parallel shape:
type VerifyResult = {
outcome: "verified" | "expired" | "invalid" | "error";
valid: boolean;
reason?: string;
audit_id?: string;
};Handling each case:
Decision | Agent behavior |
| Proceed. Pass |
| Do not proceed. Surface |
| Do not proceed. Tell the user the action is queued for human review; reference |
verification failure (verify returns | Flag the action for review. Something happened outside policy. |
Local vs Remote mode
The engine behind authorize() is pluggable. The same tool handlers work in both modes — swapping the backend is a configuration change.
Mode | When selected | What it does |
|
| Runs a small in-process rules engine ( |
|
| Calls the hosted AtlaSent backend at |
Local rules (for demos):
Production action + no approvals → deny
Destructive action (
delete,drop,destroy,truncate,purge,wipe,rm) + nochange_window→ holdOtherwise → allow (with a
pt_local_*permit valid for 5 minutes)
Environment variables:
Variable | Required | Default | Purpose |
| no | auto-detect | Force |
| remote only | — | Bearer token for the hosted API (prefix: |
| no |
| AtlaSent API base URL. Leave unset to use the hosted SaaS endpoint. Override only for self-hosted deployments. |
| no | — | Optional |
| no |
| Per-tool calls per minute (token bucket) |
| no | (unset) | If |
Read-only mode (for live demos)
In local mode, every tool either calls the in-process rules engine or short-circuits with no side effects, so it doesn't matter what the agent tries to do. The story is different the moment you point the server at a live AtlaSent backend with ATLASENT_MODE=remote and a real API key: the mutating CRUD tools call the hosted API directly. They do not go through the authorize() interception. An adversarial prompt, a hallucinated "let me clean up" step, or a tool-misuse mistake by the agent can damage real demo-org state.
Set ATLASENT_MCP_READONLY=1 (or true) and the server will skip registration of these 7 tools at startup:
atlasent_create_policyatlasent_update_policyatlasent_delete_policyatlasent_create_webhookatlasent_delete_webhookatlasent_revoke_permitatlasent_permit
Everything else stays available, including the full demo flow:
The agent-gating loop (
evaluate→verify_permit) and the protected-tool demo (deploy_service)All read tools (
atlasent_list_policies,atlasent_get_policy,atlasent_list_permits,atlasent_list_audit_events,atlasent_evaluate,atlasent_verify_permit)The approval-request workflow (
atlasent_create_approval_request,atlasent_resolve_approval_request,atlasent_record_execution_evaluation)
On startup, the server emits a server.readonly_mode structured log line to stderr listing the disabled tools so the operator can confirm the gate is active.
When to enable: any live demo (customer call, conference, screencast) that uses a real API key — even on a dedicated demo org. The cost is zero (the read flow, the approval flow, and the deploy_service proof all stay functional); the upside is that no LLM mishap can destroy live state. Disable the flag only when you are intentionally exercising the mutating tools from a trusted operator console.
Claude Desktop config
{
"mcpServers": {
"atlasent": {
"command": "npx",
"args": ["-y", "@atlasent/mcp-server"],
"env": {
"ATLASENT_MODE": "remote",
"ATLASENT_API_KEY": "ask_live_xxxxxxxxxxxxxxxx",
"ATLASENT_BASE_URL": "https://api.atlasent.io/functions/v1",
"ATLASENT_MCP_READONLY": "1"
}
}
}
}Location: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows).
Remove ATLASENT_MCP_READONLY from env only when you intend to use the mutating CRUD tools from a trusted operator session.
Cursor config
Add to .cursor/mcp.json in your project root (or ~/.cursor/mcp.json globally), same shape as above.
Claude Code
claude mcp add atlasent -- npx -y @atlasent/mcp-server
export ATLASENT_API_KEY=ask_live_xxxxxxxxxxxxxxxx
export ATLASENT_BASE_URL=https://api.atlasent.io/functions/v1 # omit to use the default SaaS endpoint
export ATLASENT_MCP_READONLY=1 # safe default; unset for ops sessionsFail-closed guarantees
Every error path collapses to { decision: "deny" }:
API unreachable → deny
Request timeout (10s) → deny
Malformed response → deny
Remote returns
allowwithout apermit_token→ denyUnknown/invalid decision string → deny
Verify returns an unrecognized
verify_error_code→ invalid (treated as not valid)
The agent never proceeds without an explicit allow.
How the hosted backend plugs in
Nothing in the tool handlers changes when you move from local to remote. The deploy_service handler calls authorize(ctx); authorize() reads ATLASENT_MODE on every call and picks the engine. Switching to the hosted backend is three env vars.
The remote adapter (src/engine.ts) speaks the AtlaSent API shape directly.
POST /v1-evaluaterequest:
{ action_type, actor_id, context }— flat top-level fields. mcp-server passesenvironment,approvals, andchange_windowinsidecontextso policy expressions can read them.response:
{ decision, permit_token?, request_id, expires_at?, denial?, ... }— top-levelpermit_token(raw UUID) is exposed to MCP hosts as the MCP envelope'spermit_token;request_idbecomesaudit_id.
POST /v1-verify-permitrequest:
{ permit_token, action_type, actor_id }response:
{ valid, outcome: "allow" | "deny", verify_error_code?, reason? }— serveroutcome === "allow"becomesverified;verify_error_codeis mapped toexpired/invalid/errorand falls through toinvalidfor anything unrecognized.
Development
npm install
npm run build # compile TypeScript
npm test # 26 unit tests (local + remote mocked) + readonly-mode tests
npm run test:integration # requires ATLASENT_API_KEY + ATLASENT_BASE_URL; skips otherwise
npm run demo # end-to-end authorization demo (local mode)License
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/AtlaSent-Systems-Inc/atlasent-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server