@adrata/adrata-mcp
v1.0.76
Published
Adrata MCP Server — connect Claude Code, Codex, Gemini, Cursor, and other AI tools to governed workspace documents, files, messages, sales workflows, and meetings. Additional toolsets load with enable_toolset.
Maintainers
Readme
@adrata/adrata-mcp
Connect Claude Code, Cursor, Windsurf, VS Code, and Claude Desktop to your Adrata CRM workspace via the Model Context Protocol.
Three tiers: Free (no account needed), Pro (API key), Enterprise (OAuth workspace connection).
Tool names and cached catalogs
Use workspace names such as get_document, read_messages, manage_messages,
and list_files. Legacy paper_*, oasis_*, galaxy_* and multiverse_*
names are hidden from discovery but remain callable compatibility aliases.
Both names use the same workspace authorization, schema validation, approval,
idempotency, audit and revision requirements. No alias grants additional access.
The server identifies itself as Adrata. Name the client connection adrata
to display adrata.get_document or mcp__adrata__get_document; the connector
key controls that prefix, not the server. Existing connection keys keep working.
After updating the MCP package, reconnect or refresh the client's tool catalog.
The published 1.0.69 package already includes get_document and the optional
Adrata/owned-agent sender schema, so an older catalog can hide them even when
the API supports them. manage_messages posts only supplied authorized text;
preview is the default, and live posting still requires approval, reason and an
idempotency key. No connection settings are changed automatically.
Two names, one server
This package is also published as @adrata/starfield-mcp
(binary starfield-mcp), for people wiring a coding agent to their Starfield
board rather than to the CRM. It is not a fork and not a subset: it depends on
this package, defaults ADRATA_MCP_SERVER_NAME to Starfield so the client's
server list says Starfield, and imports the same server.js. Same governed tool surface,
same tiers, same governed-write contract, and nothing to keep in sync.
Install whichever name matches what you are doing. If you already have one, you do not need the other.
Installation
Adrata CLI installer
For Claude Code and Codex, use the CLI installer so the assistant gets both MCP access and the Adrata operating instructions:
adrata login --api-url=https://api.adrata.com --token=<api_key> --workspace=<workspace_id>
adrata install --target=all --scope=projectThe installer writes .claude/mcp.json, .claude/CLAUDE.md,
.codex/config.toml, and AGENTS.md for the current project, plus the bundled
Agent Skills into .claude/skills, .codex/skills, and .agents/skills. It
does not embed secrets in the MCP config; the MCP server reads the token from
ADRATA_CONFIG_FILE.
Aliases: adrata gtm install and adrata agent install.
Codex only reads TOML. Its MCP config lives under [mcp_servers.<name>] in
~/.codex/config.toml or <project>/.codex/config.toml. A .codex/mcp.json is
ignored — no error, no server, no clue why. This is the Codex CLI configuration;
consumer ChatGPT connects to remote MCP apps separately, as described below.
Codex also ignores a project config.toml in a directory it has not been told
to trust, and says nothing about that either. On a fresh clone, answer "Yes,
allow Codex to work in this folder" on first launch, or add to
~/.codex/config.toml:
[projects."/absolute/path/to/your/checkout"]
trust_level = "trusted"Skills load in untrusted projects; MCP servers do not. codex mcp list, run
from the project directory, prints exactly what Codex will start — use it to
confirm rather than guessing from the file.
Claude Code
claude mcp add adrata -- npx -y @adrata/adrata-mcpOr add to .claude/mcp.json:
{
"mcpServers": {
"adrata": {
"command": "npx",
"args": ["-y", "@adrata/adrata-mcp"],
"env": {
"ADRATA_API_KEY": "ak_your_key_here"
}
}
}
}Codex CLI
TOML, not JSON. Add to ~/.codex/config.toml (or <project>/.codex/config.toml
for one repo):
[mcp_servers.adrata]
command = "npx"
args = ["-y", "@adrata/adrata-mcp"]
[mcp_servers.adrata.env]
ADRATA_API_KEY = "ak_your_key_here"Then verify from the project directory:
codex mcp list # adrata must appear; if it does not, the project is untrustedCursor
Add to .cursor/mcp.json:
{
"mcpServers": {
"adrata": {
"command": "npx",
"args": ["-y", "@adrata/adrata-mcp"],
"env": {
"ADRATA_API_KEY": "ak_your_key_here"
}
}
}
}Windsurf
Add to .windsurf/mcp.json:
{
"servers": {
"adrata": {
"command": "npx",
"args": ["-y", "@adrata/adrata-mcp"],
"env": {
"ADRATA_API_KEY": "ak_your_key_here"
}
}
}
}Note: Windsurf uses "servers" instead of "mcpServers".
VS Code
Add to .vscode/mcp.json:
{
"mcpServers": {
"adrata": {
"command": "npx",
"args": ["-y", "@adrata/adrata-mcp"],
"env": {
"ADRATA_API_KEY": "ak_your_key_here"
}
}
}
}Claude Desktop local stdio
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"adrata": {
"command": "npx",
"args": ["-y", "@adrata/adrata-mcp"],
"env": {
"ADRATA_API_KEY": "ak_your_key_here"
}
}
}
}Claude web, Claude Desktop, and Cowork: remote connection
Use a deployed HTTPS endpoint, normally https://mcp.adrata.com/mcp, after its
DNS, certificate, OAuth discovery, and authenticated tool checks pass. A local
stdio installation does not connect claude.ai or Cowork. Remote requests come
from Anthropic's cloud, including when the client is Claude Desktop.
In Claude's custom connector settings, add the server URL and complete Adrata sign-in and workspace consent. Team/Enterprise administrators first add the connector to their organization; each member then connects their own Adrata account. Never distribute another person's token or use a shared owner's API key. Adrata still checks the active seat, product access and each file's ACL.
Replicated hosted servers use stateless HTTP: each request may reach a different
server task. The supported toolsets are registered for every request, with the
same tier, domain, scope and workspace checks. enable_toolset can report that
a group is already available; no caller's loaded-tool state or credentials are
shared with another caller. Local stdio and stateful local HTTP retain on-demand
toolset loading. After a connection failure, check the original write's receipt
before retrying; a new connection does not authorize a duplicate write.
Current supported clients and setup are documented in Claude's remote connector instructions.
ChatGPT web: remote MCP app
ChatGPT does not read ~/.codex/config.toml or run local stdio servers. Full
custom MCP read/write support is currently a beta on ChatGPT web for Business,
Enterprise and Edu. Pro custom MCP apps have a different capability surface;
do not promise full write support based on a successful Codex installation.
Verify desktop-client support separately; the documented full-write setup is web.
A workspace owner/admin enables developer mode, adds the deployed HTTPS MCP URL in Apps, selects OAuth, and publishes the approved tools. Each member signs in to their own Adrata account and selects an authorized workspace. Changed tool definitions need administrator review/refresh; publishing a new server does not silently refresh the app's tool snapshot. Ordinary user writes retain Adrata's approval, reason, revision and idempotency controls.
See OpenAI's developer mode and MCP app instructions.
For onboarding, prepare the connector configuration before sending an invitation. A person without an active Adrata account and workspace seat cannot authorize it. Invite or grant access only after the owner explicitly authorizes onboarding.
Tiers
| Tier | Credentials | What You Get |
|------|------------|--------------|
| Free | None | Search, email sync, demo scheduling, memory, morning brief teaser |
| Pro | ADRATA_API_KEY | + Intelligence, analytics, enrichment, meetings, speedrun, coaching |
| Enterprise | OAuth (connect_workspace) | + CRM CRUD, sequences, campaigns, bulk ops, workspace admin |
Get your API key from Settings > API Keys in Adrata. Enterprise users authenticate via the connect_workspace tool or by setting ADRATA_OAUTH_TOKEN.
Lightspeed queue access
Use the existing queue API for all eight management actions below. The two MCP queue tools expose a smaller read/lifecycle surface. Neither creates permission to send mail, place a call, impersonate a teammate or bypass an execution review.
Create the least-privilege connection
An authorized workspace admin opens Settings → API keys, completes the requested two-step verification, and names the connection for its purpose.
Select read:actions for queue reads. Select write:actions only when the connection is authorized to change queue work. Both choices start unchecked.
write:actionsalso implies reads on the server. These scopes cover action tasks as well as Lightspeed queues. They are different fromwrite:tasks, which is work-board access; clear that default if it is not needed.Create the key, copy its secret once and keep it in the integration's secret storage. A scope grant does not change the key owner's current seat or role. Use the intended workspace and owner; unrelated/foreign queues stay hidden.
Start with a read, using
X-API-Key: <your-own-key>:GET /api/v1/dialer/runs GET /api/v1/dialer/runs/<runId>/managementRead the actual
data.id,managementRevision,ownerUserIdanditems. A 401/403 is an authentication or authorization refusal, not an empty queue. Check the key, workspace, active seat and granted scope; do not switch to a broader shared credential to get past it.
For MCP, refresh the client tool catalog and connect the intended workspace with
connect_workspace. Queue tools are in the Enterprise tier; setting a bare
Pro API key does not by itself expose them. Request writeAccess only when writes
are needed and review the resulting OAuth consent. The client and API still
check the granted scopes. Hosted endpoint availability and client onboarding
are separate from a working local stdio connection.
| MCP tool | Supported behavior |
| --- | --- |
| get_lightspeed_runs | List accessible runs, or read one exact runId. |
| manage_lightspeed_run | Create, pause, resume, finish, or record an observed outcome. Writes preview by default; a live write requires dryRun:false, approved:true, a reason and one stable idempotencyKey. |
| manage_lightspeed_run with action:call | Return executed:false and an interactive run link. It does not place a call. |
Creating a run sends nothing. An outcome is an observation to record, never a
substitute for a provider receipt. Do not record sent merely because a draft,
queue item or API request exists.
Review and change future work
The management door is POST /api/v1/dialer/runs/<runId>/management. Pause a
running queue first; end and grade an active call before editing future work.
Use the exact latest item/task identifiers returned by the authorized GET.
Every command has an action, the observed expectedRevision, a stable body
idempotencyKey (1–128 characters) and an auditReason. An agent-originated write
also carries X-Adrata-Actor, X-Adrata-Reason, X-Adrata-Approved: true and an
Idempotency-Key header. Set approval only after the intended action is reviewed;
these headers are caller assertions and do not replace server authorization.
Keep the same header key, body key and exact body together for that one attempt.
| action | Additional fields | Confirm through a fresh authorized read |
| --- | --- | --- |
| add | items:[{personId:"…"}] (1–500) | The intended person/task appears exactly once; existing identities are retained. |
| snooze | itemIds:["…"], snoozedUntil as a future timestamp | The exact item has queueState:"snoozed" and the chosen time. |
| restore | itemIds:["…"] | The eligible item is active again; restore does not send or complete it. |
| remove | itemIds:["…"] | The item is absent from the current queue; historical outreach remains. |
| mark_done | itemIds:["…"] | The queue item is done and linked task is closed without outreach. No sent/delivered outcome is invented. |
| assign | itemIds:["…"], assigneeId | Response data.assignedRunId identifies the target run. Verify target owner/task and source removal within current reporting permissions. |
| schedule | itemIds, schedule as below | The same linked tasks have exact taskDueAt, taskPriority and a fresh taskUpdatedAt. |
| retention | retention:{inactivityDays:30}; no selected items | retentionDays matches. Use 1–365 days, or null to turn inactivity expiry off. This does not delete tasks or outreach history. |
A schedule includes due:{mode:"keep"}, {mode:"clear"} or
{mode:"set",at:"<timestamp>"}, an IANA timezone, optional priority
(LOW, NORMAL, HIGH, URGENT), and expectedTasks containing each selected
itemId, taskId and the exact previously read updatedAt (from taskUpdatedAt).
Read versions again after a confirmed change. An old task version must not be
silently replaced with the latest one when recovering an uncertain attempt.
A successful management response is {success:true,data:{run,assignedRunId}}.
Inspect data.run.managementRevision and exact resulting identities, then GET
the management snapshot again. Queue state, canonical task state and outreach
outcome are different facts; a done task is not delivered email.
Recover without issuing a second command
- After a timeout, unreadable response or 5xx, retain the original keys, body, run/item/task IDs and versions. The write may already have committed. GET the current management snapshot; do not mint a new key or silently rebase and repeat the mutation. A GET confirms current state, not which key caused it.
- If replay is needed, use only that unchanged original command and keys. The durable management command receipt deduplicates the same body key for the same actor/run. Reusing it with a different body is a conflict, not an edit.
- A 409 can mean stale revision, changed payload or an HTTP idempotency attempt still in progress. Preserve an uncertain attempt, read again, and resolve it before reviewing a distinct new change. The HTTP cache has a 24-hour lifetime; its expiry does not prove the original command failed or erase the durable management receipt.
- Unknown, unrelated or inaccessible run/item IDs must not be substituted with another owner's latest queue. Revocation and scope/seat refusals are not permission to create another credential or retry with broader access.
Tools by Tier
Free Tier (no account needed)
| Tool | Description |
|------|-------------|
| find_company | Search company profile using AI knowledge |
| find_person | Search person profile using AI knowledge |
| search_companies | Search companies in CRM |
| search_people | Search people in CRM |
| search_leads | Search leads |
| search_emails | Search emails |
| get_email | Get email by ID |
| count_emails | Count emails matching criteria |
| check_inbox | Check inbox for new emails |
| find_or_create_person | Find or create a person record |
| find_or_create_company | Find or create a company record |
| get_demo_availability | Check demo availability slots |
| schedule_demo | Schedule a product demo |
| describe_fields | Schema introspection for entity fields |
| list_custom_fields | List available custom fields |
| save_memory | Store a fact or insight (local in free tier) |
| recall | Search saved memories |
| who_am_i | View user profile and usage stats |
| forget | Remove a saved memory |
| morning_brief | Daily briefing (teaser in free tier, full in pro+) |
| upgrade_account | Open signup/upgrade page |
| check_subscription | Check current plan and usage |
| connect_workspace | Connect Adrata workspace via OAuth |
| disconnect_workspace | Disconnect workspace |
| workspace_status | Check workspace connection status |
| inspect_provider_catalog | Inspect available integration providers |
| list_provider_endpoints | Inspect provider endpoints/actions before workflow drafting |
| validate_integration_manifest | Validate a custom integration manifest |
| validate_extension_manifest | Validate a custom extension manifest |
| draft_workflow | Draft a headless workflow manifest |
| validate_workflow_draft | Validate workflow permissions, audit, policy, and replay rules |
| dry_run_workflow | Dry-run or locally plan a workflow execution |
| adrata_api_catalog | Explain governed full-platform API access |
| inspect_provider_catalog | Inspect available integration providers |
| list_provider_endpoints | Inspect provider endpoints/actions before workflow drafting |
| validate_integration_manifest | Validate a custom integration manifest |
| validate_extension_manifest | Validate a custom extension manifest |
| draft_workflow | Draft a headless workflow manifest |
| validate_workflow_draft | Validate workflow permissions, audit, policy, and replay rules |
| dry_run_workflow | Dry-run or locally plan a workflow execution |
| list_toolsets | List available composite toolsets |
| enable_toolset | Enable a composite toolset |
Pro Tier (requires API key)
All free tools plus:
| Tool | Description |
|------|-------------|
| get_company | Get full company details |
| get_person | Get full person details |
| get_opportunity | Get opportunity details |
| get_action | Get action details |
| enrich_company | AI-powered company enrichment |
| enrich_person | AI-powered contact enrichment |
| get_intent_signals | Buying intent signals for a company |
| list_customer_signals | First-party customer signals (the store live plays fire from) for the workspace or a subject |
| get_deal_authority | Map decision makers and authority |
| get_competitor_intel | Competitive intelligence brief |
| score_company_icp | Score company against ideal customer profile |
| get_icp_distribution | ICP score distribution analytics |
| get_pipeline_metrics | Pipeline analytics dashboard |
| get_forecast_data | Revenue forecast data |
| get_activity_summary | Activity summary for a time period |
| count_records | Count records by entity type |
| get_priority_pursuits | Evidence-ranked daily account and next-move list |
| get_speedrun_list | Legacy alias for get_priority_pursuits |
| list_meetings | List scheduled meetings |
| get_meeting | Get meeting details |
| get_meeting_summary | AI-generated meeting summary |
| get_meeting_action_items | Action items from a meeting |
| list_actions | List actions |
| list_overdue_actions | List overdue actions |
| list_today_actions | List actions due today |
| list_notes | List notes for an entity |
| log_interaction | Log a sales interaction |
| qualify_company | Composite: full company qualification |
| research_company | Composite: deep company research |
| research_person | Composite: deep person research |
| discover_prospects | Composite: find new prospects |
| get_next_contacts | Composite: next best contacts to reach |
| commit_lead_to_outbound | Governed: commit a lead above the /targets line — Pipeline's Outbound stage |
| release_lead_from_outbound | Governed: take a lead back out of Outbound |
| list_outbound_leads | Who is committed to Outbound right now |
| get_competitive_intel | Composite: competitive analysis |
| get_meeting_brief | Composite: pre-meeting intelligence |
| get_deal_coaching | Composite: deal coaching insights |
| get_signals_dashboard | Composite: signals overview |
| get_forecast | Composite: forecast summary |
| draft_email | Composite: draft a sales email |
| get_outreach_analytics | Composite: outreach performance |
| get_network_paths | Composite: relationship paths |
| search_emails_composite | Composite: advanced email search |
| get_email_thread | Composite: full email thread |
| find_intro_path | Find a warm relationship path |
| get_network_stats | Network coverage and intro health |
| list_webhook_events | Supported webhook event catalog |
Enterprise Tier (requires OAuth)
All free and pro tools plus:
| Tool | Description |
|------|-------------|
| create_company | Create a company record |
| update_company | Update company fields |
| delete_company | Delete a company |
| create_person | Create a person record |
| update_person | Update person fields |
| delete_person | Delete a person |
| create_opportunity | Create an opportunity |
| update_opportunity | Update opportunity fields |
| delete_opportunity | Delete an opportunity |
| create_action | Create an action/task |
| update_action | Update an action |
| complete_action | Mark an action complete |
| delete_action | Delete an action |
| create_note | Create a note |
| update_note | Update a note |
| delete_note | Delete a note |
| get_company_people | List people at a company |
| get_company_opportunities | List opportunities for a company |
| get_company_actions | List actions for a company |
| search_opportunities | Search opportunities |
| list_buyer_groups | List buyer groups |
| get_buyer_group | Get buyer group details |
| create_buyer_group | Create a buyer group |
| add_buyer_group_member | Add member to buyer group |
| get_buyer_group_members | List buyer group members |
| list_intro_requests | List tracked warm intro requests |
| get_intro_pipeline | View the warm intro pipeline |
| create_intro_request | Create a tracked warm intro request |
| update_intro_request | Update intro request status |
| list_agent_tasks | List long-running agent/background tasks |
| create_agent_task | Create a long-running agent/background task |
| get_agent_task | Get task status and result |
| cancel_agent_task | Cancel a running task |
| adrata_api_request | Governed low-level request to allowlisted, non-sensitive platform APIs |
| adrata_ai_tool_catalog | List the AI CRM tools Adrata chat can use |
| adrata_ai_tool_execute | Execute the same governed ToolDispatcher path used by Adrata chat |
| get_account_read | Grounded no-loss account/deal read via the chat ToolDispatcher |
| rank_paths_to_power | Ranked warm/network paths to decision makers via the chat ToolDispatcher |
| recommend_deal_move | Read-only no-loss next deal move recommendation via the chat ToolDispatcher |
| list_external_pipelines | List refreshable Channels such as YC, Techstars, CSV, LinkedIn, and sequence sources |
| list_external_pipeline_members | Preview Channel members before import |
| import_external_pipeline_members | Import Channel members through Adrata bulk import |
| list_external_companies | Query nightly-refreshed external company catalogs |
| import_external_companies | Import selected external catalog companies |
| rank_companies_by_icp | Rank imported companies against the workspace ICP profile |
| rank_people_by_icp | Rank imported people against the workspace ICP profile (title/persona + firmographics) |
| check_batch_import_status | Poll bulk import progress and enrichment status |
| move_pipeline_card | Move a pipeline card and publish realtime UI updates |
| list_webhooks | List outbound webhook subscriptions |
| create_webhook | Create a webhook subscription |
| update_webhook | Update webhook URL, events, or filters |
| delete_webhook | Delete a webhook subscription |
| test_webhook | Queue a signed webhook test event |
| list_webhook_deliveries | List delivery attempts |
| get_webhook_delivery | Inspect a delivery attempt |
| replay_webhook_delivery | Replay a delivery attempt |
| test_provider_credential | Run a dry-run or live credential health test with policy/audit metadata |
| request_deployment | Request custom integration or extension deployment after manifest validation |
| request_workflow_deployment | Request workflow deployment after a prior dry-run id |
| replay_workflow_run | Dry-run or request replay for a workflow run |
| list_campaigns | List email campaigns |
| get_campaign | Get campaign details |
| list_sequences | List email sequences |
| get_sequence | Get sequence details |
| list_users | List workspace users |
| get_user | Get user details |
| get_current_user | Get current authenticated user |
| send_email | Send an email |
| reply_to_email | Reply to an email thread |
| manage_sequences | Manage sequence enrollment |
| bulk_import | Bulk import records from CSV |
| export_data | Export records as JSON/CSV |
| manage_custom_fields | Manage custom field definitions |
| get_workspace_settings | View workspace configuration |
| manage_company | Composite: full company management |
| manage_person | Composite: full person management |
| manage_opportunity | Composite: full opportunity management |
| manage_activity | Composite: full activity management |
| manage_buyer_group | Composite: full buyer group management |
| get_action_history | Composite: action history timeline |
| make_call | Composite: initiate a call |
| send_sms | Composite: send SMS message |
| get_communication_status | Composite: read a call/SMS dispatch outcome and its carrier |
| list_calling_identities | Composite: which numbers the seller can call or text from |
| get_call_transcript | Composite: retrieve call transcript |
| check_calendar | Composite: check calendar availability |
| schedule_meeting | Composite: schedule a meeting |
| manage_domains | Composite: email domain management |
| manage_mailboxes | Composite: mailbox configuration |
| get_deliverability | Composite: email deliverability metrics |
| connect_provider | Composite: connect email provider |
| manage_workspace | Composite: workspace settings |
| manage_data | Composite: data operations |
Agent API Bridge Governance
adrata_api_request is a broad fallback for platform API access. Prefer targeted
tools such as adrata_ai_tool_execute, move_pipeline_card, webhook tools,
integration tools, and workspace/user tools when they exist.
The bridge enforces least-privilege deny rules for sensitive administrative
surfaces even when those route families are present in the platform allowlist:
/api/v1/billing, /api/v1/api-keys, /api/v1/observability,
/api/v1/users, /api/v1/integrations, /api/v1/custom-integrations,
and /api/v1/webhooks.
Write requests through adrata_api_request default to dry-run. A live
POST, PUT, PATCH, or DELETE requires dryRun:false, approved:true,
a non-empty reason, and an idempotencyKey; the MCP bridge forwards the
reason, actor, and idempotency metadata as request headers.
Known gap: the MCP bridge now applies a consistent approval/idempotency envelope,
but not every downstream API endpoint has a uniform server-side envelope yet.
Treat adrata_api_request as a governed escape hatch and use higher-level MCP
tools for privileged operations.
Files and collaboration
Files tools use the same documents, revisions and access checks as the app. Product access and the caller's permission to each item are required; connecting an agent does not grant it access to other people's private files.
- Use
create_fileandupdate_filefor documents, spreadsheets, presentations, designs, Sites (kind: site), Boards (kind: board) and Dusk films (kind: dusk). Structured content uses the same validators as the editors. Sites save HTML drafts; they do not deploy automatically. Read before updating and supply the exactexpectedRevisionso a concurrent edit is preserved. Successful writes return persisted readback. - Use
create_folderandmanage_fileto organize files, star them, and move them into or out of trash.delete_filepermanently deletes an already trashed item and is classified as a destructive write. - Use the file sharing tools for named recipients. Public snapshot links use the document share tools; public access and recipient access are separate grants with separate revocation.
- Comments can refer to a whole artifact, exact text at a revision, or a design
frame and coordinates.
update_file_comment_statusresolves, reopens or archives a comment.restore_file_versionrestores a historical version only when the supplied current revision still matches.
Writes carry the existing approval, reason and idempotency controls. Native Adrata tools use the same canonical operations, so history and attribution stay with the artifact when work moves between the app and an external agent.
Media and Data wallet
upload_file_media uploads actual base64 image/audio/video bytes through the
authenticated Drive service. Preview first, then pass dryRun: false, approved:
true, a reason and a stable idempotency key. The decoded limit is 512 KiB so the
request fits the hosted MCP envelope. Larger files use Drive's normal upload UI.
The returned fileId can be imported into a film or referenced by a validated
artifact. A failed transfer reports the reserved file ID; retry identical inputs
with the same key. The tool never reads local paths or follows supplied URLs.
Dusk frame extraction, audio extraction and video export run through
dusk_process_media in an active, paired Dusk companion session with the film
open. Each operation requires browser approval and the current film revision.
These operations are separate from the cloud MCP artifact and upload tools.
get_data_wallet reads the authenticated workspace's token ledger under the
API's owner/admin rules. Exact decimal strings keep large balances accurate;
commercial credits are separate. Missing wallets and authorization failures are
reported explicitly. This tool does not create wallets or move funds.
Custom Fields
Companies, People, and Opportunities support customFields -- a JSONB object that gets merged on update. Add any key-value pairs without losing existing data.
"Update this company's customFields with outreach_status: contacted"Action Metadata
Actions support metadata -- a JSONB object for type-specific data. Use it for LinkedIn message copy, call notes, meeting attendees, etc.
"Log a linkedin_connection_request action for this person with metadata containing the message I sent"Running several MCP processes under separate identities
~/.config/adrata/agent.json -- the session adrata login writes -- is
machine-wide. Every MCP process on a host where anyone has ever run
adrata login therefore authenticates as that one person, including a process
that was launched with its own ADRATA_API_KEY: the key is still sent as
X-API-Key, but the bearer token is what the API resolves the caller from.
Usually that is exactly right. It is wrong when several processes on one host
are supposed to act as different principals -- a fleet of QA lanes, each
holding its own key so that its board writes are graded as an independent agent
rather than as the shared human. The API is not confused in that case: it
correctly grades a human session's write as human, records it, returns 200,
and counts it toward nothing.
Set ADRATA_MCP_PREFER_API_KEY=1 in that process's env, alongside its
ADRATA_API_KEY, and it acts as its own api_key:<id> actor.
{
"mcpServers": {
"adrata": {
"command": "npx",
"args": ["-y", "@adrata/starfield-mcp@latest"],
"env": {
"ADRATA_API_KEY": "ak_this_lanes_own_key",
"ADRATA_MCP_PREFER_API_KEY": "1"
}
}
}
}Three things it deliberately does not do:
- It only reads the environment variable. A token sitting in
~/.config/adrata/cli.jsonis ambient machine state, not a statement of intent by whoever launched this process, and never triggers the preference. - It does not outrank
ADRATA_OAUTH_TOKEN, which stays first in the chain. - It does not touch named identity pools (
ADRATA_MCP_IDENTITY_POOL), which return before the credential chain is consulted at all.
With the flag unset -- the default, and every ordinary single-user install -- the credential chain is byte-for-byte what it was.
Environment Variables
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| ADRATA_API_KEY | No | -- | Your API key from Settings > API Keys. Enables pro tier. |
| ADRATA_OAUTH_TOKEN | No | -- | OAuth bearer token. Enables enterprise tier. |
| ADRATA_MCP_PREFER_API_KEY | No | unset (off) | 1/true/yes/on makes an env-var ADRATA_API_KEY outrank the shared adrata login session and any stored connect_workspace session, and grants it enterprise tier. Leave it unset unless this process was deliberately given its own credential -- see below. |
| ADRATA_API_URL | No | https://api.adrata.com | API base URL |
| ADRATA_MCP_SERVER_NAME | No | @adrata/adrata-mcp | Display name reported in serverInfo. @adrata/starfield-mcp sets it to Starfield. Does not change the tool prefix, which comes from your client's config key. |
| ADRATA_MCP_TRANSPORT | No | stdio | Transport: stdio or http |
| ADRATA_MCP_PORT | No | 3100 | Port for HTTP transport |
| ADRATA_MCP_STATELESS | No | false | true uses a fresh authenticated protocol server per request; use for horizontally scaled hosted tasks without shared session state. |
| ADRATA_MCP_CORS_ORIGINS | No | * | Comma-separated CORS origins for HTTP transport |
| ADRATA_MCP_REQUIRE_AUTH | No | true | Require Bearer auth for HTTP /mcp; set false only for isolated local testing |
| ADRATA_MCP_RESOURCE | No | ${AS}/api/v1/mcp | RFC 8707 canonical resource URI this server binds tokens to |
| ADRATA_MCP_AUTHORIZATION_SERVER | No | ADRATA_API_URL | Authorization server(s) advertised in RFC 9728 metadata |
| ADRATA_MCP_ACCEPTED_AUDIENCES | No | adrata,<resource> | Extra token audiences accepted by the resource server |
| ADRATA_MCP_AUDIENCE_ENFORCEMENT | No | lenient | strict rejects JWTs that carry no aud claim at all |
| ADRATA_MCP_EXACT_RESOURCE | No | false | For general stateless HTTP only: require the configured resource audience; generic adrata alone is insufficient. |
| ADRATA_MCP_DELEGATION_REQUIRED | No | false | For general stateless HTTP only: exchange the client token for a distinct caller-bound API token on every request. Missing setup refuses access. |
| ADRATA_MCP_DELEGATION_CLIENTS | No | unset | Hosted operator secret: workspace-keyed exchange-only broker configuration. Never put this in client settings or ordinary plaintext task environment. |
| ADRATA_MCP_ENABLED_DOMAINS | No | (all) | Least-privilege scoping: comma list of tool packs (e.g. crm,email) |
| ADRATA_MCP_CLIENT_ID | No | dynamic registration | Operator-provisioned public OAuth client override. Most installations should leave this unset. |
| ADRATA_MCP_PRINT_AUTH_URL | No | 0 | Set to 1 to print the authorization URL for headless/manual browser use. |
Authorization (MCP 2025-06-18 spec)
The hosted HTTP transport is an OAuth 2.1 resource server hardened to the 2025 MCP authorization spec:
- OAuth 2.1 + PKCE (S256). Browser
connect_workspaceflow with a short-lived (15 min) access token and a rotating refresh token. - RFC 8707 Resource Indicators. The client sends
resourceon the authorize + token requests; the authorization server binds the token'saudto that MCP resource. - Resource binding and separate upstream credentials. The new general stateless hosted rollout requires both exact-resource and delegation modes. It exchanges each MCP client token at the authorization server using a workspace-bound, exchange-only broker. Only the distinct, short-lived API token reaches tools; the original token is never a data-API bearer. Audience validation alone is not a no-passthrough guarantee. Legacy stdio/stateful behavior remains unchanged and is not the basis for this hosted rollout.
- RFC 9728 Protected Resource Metadata. Served unauthenticated at
GET /.well-known/oauth-protected-resource, describing this resource and its authorization server(s) so clients can discover how to authenticate. - Honest tool annotations. Every tool advertises truthful
readOnly/destructive/idempotent/openWorldhints plus adomaintag. Write and destructive tools are confirmation-gated (host prompt) and are additionally tier-gated + audit-logged server-side; the governed API bridge requiresdryRun:false+approved:true+reason+idempotencyKeyfor any live write. - Confused-deputy / tool-poisoning defenses. Annotations and descriptions are derived from real behaviour, never from untrusted model input; audience binding rejects tokens intended for a different resource. Canonical API checks retain the caller, workspace, consent, scope and delegation lineage.
- Scoped per-domain tool packs. Set
ADRATA_MCP_ENABLED_DOMAINSto grant a least-privilege subset (e.g.crm,email); out-of-scope tools are refused at dispatch. Workspace-lifecycle tools stay available in every scope.
General hosted release boundary
The canonical general endpoint is https://mcp.adrata.com/mcp. Production stays
disabled until its authorization server and MCP use path are qualified
together, followed by actual DNS, TLS, health, metadata and user-owned OAuth
checks. A local test or an image build does not establish hosted availability.
Settings links to /developers/mcp for current setup and recovery instructions.
The new production task sets stateless, exact-resource and delegation modes.
Its Secrets Manager configuration maps an exact workspace ID to clientId,
clientSecret and an explicit scopes ceiling. This broker is an independently
registered, workspace-bound confidential OAuth client allowed only the
standard token-exchange grant; it cannot mint a standalone client_credentials
token. There is no automatic client provisioning or owner-credential fallback.
Missing configuration returns a setup error; users reconnect with their own
account and selected workspace rather than sharing an administrator's key.
Every request performs one form-encoded RFC 8693 exchange with Basic broker authentication over HTTPS. Remote plaintext HTTP is refused before any request; only exact IP loopback origins with explicit non-default ports are admitted for owned local fixtures. The API token must be distinct, retain the same human/workspace, use only the consent/broker scope intersection, expire within 60 seconds and the original grant's expiry, and preserve original human verification context. Canonical API validation additionally checks parent grant/client/seat liveness; short expiry does not substitute for revocation. The client-facing token never becomes an API data credential. Exchange failure does not retry or fall back.
The production Terraform gate requires the exact production image digest and full source commit, plus an explicit qualified authorization-chain assertion. Public discovery is a separate, default-false final promotion. Rollback hides discovery first; local stdio setup remains available. No endpoint, secret or permission is created by the configuration defaults.
MCP Registry
This server ships a server.json manifest for the official
MCP Registry.
To publish/update the listing:
# 1. Install the registry publisher CLI
brew install mcp-publisher # or: go install github.com/modelcontextprotocol/registry/cmd/publisher@latest
# 2. Authenticate the com.adrata namespace (GitHub or DNS-verified)
mcp-publisher login github
# 3. Validate and publish from code/mcp/
mcp-publisher publish ./server.jsonThe namespace com.adrata/* is verified via the adrata/adrata GitHub repo.
Bump version in both server.json and package.json before republishing.
Enterprise Setup: OAuth Flow
Enterprise authentication uses the connect_workspace tool for a browser-based OAuth flow:
- Call
connect_workspacein your AI tool - The MCP package dynamically registers a per-attempt native/public client (no embedded secret)
- A browser opens Adrata sign-in and a dark-mode workspace consent screen
- Adrata returns to an exact IP-literal loopback callback protected by state + PKCE
- Tokens and the issued client ID are stored encrypted in
~/.adrata/tokens.json - Rotating refresh tokens keep the session alive and preserve the MCP resource audience
Alternatively, set ADRATA_OAUTH_TOKEN directly for CI/CD or scripted environments.
Independent QA worker identities
Run QA1 and QA2 as separate MCP processes with separate OAuth stores. Each
process must complete its own interactive connect_workspace({ writeAccess:
true }) flow, which gives it a distinct dynamically registered OAuth client
and token set:
# QA1 process
ADRATA_MCP_IDENTITY_POOL=qa1 \
ADRATA_MCP_CONFIG_DIR=/var/lib/adrata/mcp/qa1 \
npx -y @adrata/adrata-mcp
# QA2 process
ADRATA_MCP_IDENTITY_POOL=qa2 \
ADRATA_MCP_CONFIG_DIR=/var/lib/adrata/mcp/qa2 \
npx -y @adrata/adrata-mcpA named pool intentionally ignores ADRATA_OAUTH_TOKEN, the shared
adrata login session, API keys, CLI tokens, and ~/.adrata/tokens.json.
Missing or shared ADRATA_MCP_CONFIG_DIR configuration fails closed; do not
copy one pool's token file into another. The pool name is process routing
metadata, while the independently issued OAuth credential is the QA identity.
Troubleshooting
Server fails to start
- Verify Node.js >= 18:
node --version - Check npx can resolve the package:
npx -y @adrata/adrata-mcp --version - Look for error messages in the AI tool's MCP server logs
"Tool requires pro tier" message
- Set
ADRATA_API_KEYin the env config of your MCP server definition - Get your key from Settings > API Keys in Adrata
- Restart the MCP server after adding the key
"Tool requires enterprise tier" message
- Run
connect_workspaceto authenticate via OAuth - Or set
ADRATA_OAUTH_TOKENin the env config - Enterprise requires an active Adrata Enterprise subscription
OAuth token expired
- The server auto-refreshes stored tokens from
~/.adrata/tokens.json - If refresh fails, run
connect_workspaceagain - Never delete or disconnect the shared
~/.adrata/tokens.jsonsession as a repair step; that silently signs every local agent out. Re-runconnect_workspacein the affected process. For a named QA pool, use that pool's ownADRATA_MCP_CONFIG_DIRand complete consent there.
Tools return empty results
- Verify your API key has access to the workspace
- Check that the entity exists in your CRM
- For enterprise tools, confirm your OAuth token has the required scopes
HTTP transport mode
- Set
ADRATA_MCP_TRANSPORT=httpfor Streamable HTTP transport - Server listens on port 3100 by default (configurable via
ADRATA_MCP_PORT) - Hosted and local HTTP mode require
Authorization: Bearer ...by default - Configure CORS origins if calling from a web client
Rate limiting
- Free tier: subject to standard rate limits
- Pro tier: higher rate limits per API key
- Enterprise tier: workspace-level rate limits based on plan
Local credential storage and upgrades
Local MCP profiles store OAuth credentials in an authenticated tokens.json
envelope, encrypted with a random 32-byte tokens.key. On POSIX systems the
profile directory must be owned by the current user with mode 0700, and the
key and token files must have mode 0600. Keep the profile under a trusted home
directory: its ancestors must not be replaceable by another OS user. This is
filesystem isolation, not an OS keychain; processes running as the same user
can access both files. Windows ACL equivalence has not been established.
Before upgrading an existing profile to envelope version 2, stop all MCP workers using it, upgrade them together, and restart them. The first successful read authenticates and validates the version 1 credentials, then migrates them. Older workers cannot read version 2. Do not run old and new workers against the same profile. Corrupted credentials or a missing/wrong key are preserved rather than silently overwritten. Keep the key and envelope together when backing up a profile; moving them to a different profile path requires reconnecting because encryption binds the original profile identity.
Writes use complete temporary files and atomic publication. File contents are
flushed, but parent directories are not synced; this is not a guarantee of
persistence through power loss. A process crash can leave .tokens-store.lock.
If the busy error persists, stop every process using that profile and confirm
none can restart automatically. Only then remove that profile's stale lock and
restart the upgraded workers. Do not remove a lock from an active profile, or
remove tokens.key to repair a lock. The program deliberately does not steal a
lock based on its age. If credentials cannot be recovered, disconnect and
reauthorize through the normal account flow.
A crash during exclusive key publication can also leave a
tokens.key.<pid>.<nonce>.tmp hard link. With every profile writer stopped,
an operator can inspect that temporary entry and the canonical tokens.key:
both must be regular files owned by the profile user, have private permissions,
and have the same device and inode. Remove only the verified temporary link,
keep the canonical key, and confirm its link count is one before restarting.
Do not remove unrelated entries or relax the hard-link check. An analogous
orphan .tokens-store.lock.<pid>.<nonce>.tmp can be removed after the same
stopped-writer and ownership checks. Preserve the profile for investigation
if these checks fail.
