The hosted MCP server lets a member connect an AI app that speaks MCP, the Model Context Protocol, to DALP. Claude and ChatGPT are examples. The server runs inside DALP at /api/mcp, so the app needs no CLI and no API key. The app reads what the member can read. By default it prepares changes as drafts that the member opens and signs. With execution set to mandate, DALP instead runs a mint, burn, pause, resume, block or unblock from one of the organisation's agent accounts, inside that agent's on-chain mandate and with no person signing, as Execution modes describes. The app never signs, and the member's key never signs for it.
This page covers the hosted server. The dalp -- server described in CLI for AI agents is a different server, started on a person's own machine, and it is unaffected by the hosted server. Choose the hosted server when the member uses a chat app and the organisation wants a per-member grant it can see and revoke. Choose dalp -- when an agent runs next to a shell with the API key from dalp login.
An owner switches the MCP server on, the member signs the app in over OAuth, and each tool call then reads as that member or posts a draft the member signs.
Switch the server on
An organisation owner or a platform administrator switches the server on. It is off by default. The platform-wide assistant switch, which is on by default, must be on too. While the server is off, or while either assistant switch is off, every request to /api/mcp answers 403 with mcp_server_off. Sign-in and consent still complete, but the app gets no data.
- Open the Assistant page in organisation settings.
- Make sure Assistant in search is on. The MCP server needs the assistant, and with the assistant off the “Connected apps” list is hidden.
- Turn on MCP server.
The same two roles are the only ones who can switch it off, in the Console or through the Platform API. The Assistant page appears only in their navigation, and another member who opens its address cannot change the switch and sees “Only an owner can change this setting.”
When an owner turns the switch off again, every request to /api/mcp for that organisation answers 403 with mcp_server_off until an owner turns it back on.
Connect an app
Give the app the server URL. Replace <your DALP address> with the address your organisation uses for the Console:
<your DALP address>/api/mcpThe app finds the sign-in by itself. The server answers a request without a valid token with 401 and a WWW-Authenticate header that points to its protected-resource metadata. The metadata names DALP's OAuth issuer, and the app registers itself as an OAuth client without signing in, so no one creates a client by hand and DALP does not check who the app is. The registration requires PKCE, the OAuth Proof Key for Code Exchange extension that binds each sign-in to the app that started it. An access token lasts one hour and a refresh token lasts 30 days.
The metadata is served by the Platform API at /.. The WWW-Authenticate header of the 401 carries the exact address, and an app that follows it reads this document:
{
"resource": "https://dalp.northwind.example/api/mcp",
"authorization_servers": ["https://dalp.northwind.example/api/auth"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["dalp:read", "dalp:prepare"],
"resource_name": "DALP"
}The Console forwards /.well-known/* to the API, as it does /api/* and /dalp/*, so the Console address serves this metadata. A gateway in front of the Console must pass /.well-known through as well.
The server is stateless and speaks streamable HTTP. An app sends JSON-RPC requests with POST, and a GET to /api/mcp answers 405 with “This MCP server is stateless: POST JSON-RPC requests to it.”
What the member does
- The app opens a sign-in page titled with the app's name, such as Sign in to connect Claude. This page offers no account creation. The member signs in, including two-factor verification, and returns to the app's request.
- The consent page, titled with the app's name, such as “Connect Claude to DALP”, shows the Organisation the grant binds to. A member of several organisations picks one with “Choose an organisation”, and the page reloads with the choice.
- Under The app will be able to, the page lists what the app asked for: “Read the DALP data you can see”, “Prepare actions for you to review in your Actions inbox”, or both. With “Prepare actions” it also lists “Have your organisation's agent principal, if it has one, run a mint, burn, pause, resume, block or unblock within its mandate, with no one signing”, which is
executionset tomandate, as Execution modes describes. The page then states: “It cannot sign anything with your account.” - The member selects Allow or “Deny”. A member with no organisation cannot select “Allow”, and the page says “You are not a member of an organisation.” A failed answer keeps the member on the page with “Your answer could not be sent. Try again.”
The name on both pages is the name the app gave itself, so allow only apps you trust. A request that lost its signed parameters shows “This connection request is incomplete” and offers no answer. When the server is off, an owner sees “The MCP server is off” with a link, Open assistant settings. A member sees no notice, because only an owner can change the switch.
The grant belongs to one member in one organisation. The app works in that organisation only, with that member's permissions.
Read tools
The server offers the same four tools as dalp --. An app finds a tool with search_tools, reads its schema with get_tool_details, and runs a read with call_read_tool or a prepare tool with call_write_tool. The view tool show_holders is listed on its own.
The read tools are the CLI's get commands, the same set dalp -- offers through call_read_tool, described in MCP tools. Every read runs as the member who signed the app in, in the organisation the grant binds to. The app sees what the member sees and nothing else. A read returns the route's own response body, without the masking the Console assistant applies, so names, wallet addresses, balances and identity data in it reach the app and the model provider behind it. The organisation's assistant data settings do not limit what the hosted server returns.
The access token is read-only on the API. A write method sent with it answers 403 SESSION_POLICY_DENIED (DALP-0036). A route that only the Console may call refuses the token with the same code, whatever the method. A write goes through a prepare tool instead, as a draft for a person to confirm in DALP or, under a mandate, as a write one of the organisation's agents runs.
Prepare tools
Each prepare_* tool matches one Console control, such as the controls on an asset's page, and is named after it, for example prepare_asset_pause. A prepare tool takes the asset's contract address as assetId, the control's own fields and an optional execution.
search_tools and get_tool_details return each prepare tool's MCP annotations, the hints that tell an app what a tool can change. prepare_asset_mint, prepare_asset_burn, prepare_asset_pause, prepare_asset_unpause, prepare_ and prepare_ carry destructive, because with execution set to mandate they run the write at once and no person signs. The hint stays the same when a call uses inbox. Every other prepare tool carries destructive. It answers mandate with execution-unsupported, so it can only post a draft. No prepare tool is marked read-only or idempotent, because an inbox call takes no idempotency key. The app runs every prepare tool through call_write_tool, which is marked destructive whatever tool it runs.
A prepare tool checks the address and each field, reads the asset as the member, and refuses when the member does not hold the permission the control needs. When the checks pass, the platform posts a draft to the member's Actions inbox. Nothing is signed or submitted at that point.
The draft appears as a “Request from an app”. Its sheet says which app prepared it through the MCP server. Its checks record that, when the app prepared it, the member held the permission the change needs and the app filled in every required field. The member selects Review to open the item's sheet, then “Open draft”, and the existing control opens with the values filled in. The member confirms with wallet verification. Opening the draft closes the item as accepted, whether or not the member then signs.
The app learns the draft's itemId and openUrl from the tool result. The link / opens the item's sheet in the Actions inbox, and only the member it belongs to can open it.
Refusals
A refused prepare call returns an error result, not a draft. The caller fixes the cause and calls again.
A call_write_tool call that names a tool the server does not list returns the error Unknown tool: <name>. List the tools again and call one of them.
Execution modes
execution takes inbox, the default, or mandate. With inbox the draft goes to a person to sign. With mandate, DALP runs the write from an agent's account. An agent is a participant the organisation set up to act through a key the platform holds, and its mandate is the set of calls, amounts and expiry the chain enforces on it. The member's key never signs.
A mandate call names two more fields. agentId is the id of any of the organisation's agents from the Agents page: DALP checks that the agent belongs to the organisation, not that the member set it up. idempotencyKey is 8 to 128 letters, digits, dots, colons, dashes or underscores that the app sends again unchanged on a retry. A retry from the same app and member, with the same agentId and key, never runs the write twice. Another app, another member, another agent or an app that registered again as a new client starts a new write.
DALP makes the same checks as for a draft first, including the member's own permission for the control. Mint, burn, pause, resume, block and unblock run under a mandate. Any other control answers execution-unsupported. Every mint or burn row needs its holder and a positive amount with no more decimals than the asset has: DALP refuses an incomplete row or an over-precise amount instead of dropping or rounding it.
A wallet restriction freezes a participant's wallet on the tokens it lists, and DALP releases those freezes only through its lift. While one is active and lists the asset, DALP refuses an unblock of that wallet with restriction-held. The Console's “Unblock” sheet and the Platform API refuse the same unblock, so a draft prepared with inbox is refused before the member signs it.
A mandate meters transfers and approvals only, so a mandate that sets a limit on an asset cannot allow a mint or burn on it. DALP refuses such a mint or burn with mandate-refused and the reason target-not-allowed. When the mandate sets no limit on the asset and allows the call, the mint or burn runs with no amount cap. The answer carries the agent's account, the queue request and a state of queued or landed. A refused mandate call submits nothing and prepares no draft.
Views in the app
In an app that renders MCP Apps, show_holders opens a table of an asset's holders and balances, as the member can read them. The tool takes assetId.
A prepared draft has no view in the app. The prepare result carries the draft's openUrl and tells the app to give that link to the member, who opens the item in the Actions inbox.
Limits
Tool calls share the assistant's limits. The per-member and per-organisation windows are the assistant's turn windows, multiplied by ten for tool calls, and they follow whether the organisation uses the shared assistant or its own model key. A call that spends the window is refused with 429 and a Retry-After header that gives the seconds until the window resets:
{
"error": "rate_limited",
"error_description": "Too many MCP tool calls. Try again shortly."
}The error is retryable. The app waits for Retry-After and sends the call again. A batch that carries several tool calls spends one unit per call.
Other responses
Audit
Every tool call writes one audit row before the call runs and settles it with the outcome. The row records the route mcp.<tool>, the auth source oauth, the member, the organisation, and the app's id and name next to the tool's arguments. A call made through call_read_tool or call_write_tool is recorded under the tool it runs. A prepare tool is recorded as a mutation, and any other tool as a sensitive read. DALP settles the rows of one request together: when the request fails, or any call in it fails or is refused, every row of that request is recorded as failed, including a call in the same batch that succeeded. A call refused for the limit window leaves no row, because it never ran. A mandate call also writes an agent-execution row with the auth source agent, the member as actor and the submitted calls. The rows are part of the audit trail.
Connected apps and revocation
The Connected apps list on the Assistant page shows each connected app with these columns: “App”, “Member”, “Access”, “Connected” and “Last used”. “Access” reads “Read”, “Prepare actions” or both. “Last used” reads “Never” until the app uses the grant. An empty list reads “No apps are connected.”
An organisation owner sees every member's apps. A platform administrator who is not an owner sees only the apps they connected themselves.
Select “Revoke” on a row, then Revoke access to confirm:
A revoked app must be signed in again. A revoke that finds no matching grant answers as not found. The list and the revoke belong to the Console only. The published API reference, the SDK and the CLI do not offer them.
Next steps
- CLI for AI agents covers the local
dalp --server, which the hosted server leaves unaffected, and how to scope an assistant session.mcp