Report tools (app__<app>__run_now, app__<app>__set_setting)
Tool names: app__<app>__run_now, app__<app>__set_setting
Scopes: apps:invoke
When to use
A report is an app that the report builder makes, for example northwind-costs. People see it as a role on their team, for example the Finance Manager or the Marketing Assistant, under Apps. Each report has the tables records, settings, runs and held (the app-table family reads them). A report app also has two more tools:
app__<app>__run_nowstarts a manual run now. It is the same as Run now in the app, with the same checks. Use it to test a report after a change, or when the person asks for a fresh report.app__<app>__set_settingsets one setting of the report, for example the currency or who gets the report. Use it in place ofapp__<app>__settings__createandapp__<app>__settings__update: you send the value as plain JSON, you do not need the row id or its version, and the value is checked against the report's settings schema before anything changes.
Products, accounts, suppliers, the product tag and its tag map, and the shared-cost rules are not settings. They are on the business's Our business page, the document company/our-business.md in the Company project, which every report reads on each run. Read it with readDoc. The page wins, field by field: the setting cost_centres counts only while the page lists no products, vendors only while it lists no suppliers, tag_key and centre_map only while it has no product tags, and allocation_rules only while it has no shared-cost rules. Once the page holds a field, a change to the matching setting has no effect. A person changes the page on the report's Our business tab, or asks Sasha in Studio chat.
The tool names use the app id with each - changed to _. For example, the report northwind-costs has app__northwind_costs__run_now.
Who gets the tools:
- Both tools need
apps:invoke, the same scope as the other app tools. The person must also haveuseormanageaccess on the app. run_nowis in the tool list for an admin or a staff user.set_settingis in the tool list for an admin only. A member has neither tool. This is the same as in the app, where only an admin sees Settings and a member cannot press Run now.- No new scope is needed, so a connection made before these tools existed gets them without a reconnect.
Arguments of run_now:
idempotencyKey(required): a new key, 1 to 128 characters, for each run you start. The confirmation is bound to it.confirmationToken: only after a confirmation, as described below.
Arguments of set_setting:
key(required): the setting, for examplecurrency. It must be a setting of the report's pack.value: the new value as plain JSON: a string, a number, a list or an object. Never send JSON inside a string: the text[{"id":"aws"}]is refused for a setting that takes a list.idempotencyKey(required) andconfirmationToken, as forrun_now.
A key that has no row gets a new row. A key that has a row is replaced with the new value. The report's next run uses it, and every user of the report sees it.
What a run gives back
run_now returns { "ok": true, "executionId": "..." } when the run starts. A run takes minutes and continues after the call returns. To follow it, call app__<app>__runs__list and look for the row whose execution_id is the executionId: status is running until the run ends, then completed with an outcome. The report that the run made is in app__<app>__records__list.
When the run cannot start, run_now returns { "ok": false, "reason": "..." }. This is a result, not an error.
Confirmation for a change
Both tools change something, so a person must approve each call:
- In the Sasha web interface, the first call returns a result that is not an error and changes nothing.
structuredContent.confirmationhasrequired: true, aconfirmationToken,expiresAt,effectsand adescription. Forset_setting, the description shows the key and the value before and after, cut to about 80 characters each. Sasha shows the person a Confirm box for the change. Wait until the person says they confirmed, then call the tool again with the same arguments, the sameidempotencyKeyand theconfirmationToken. The token works only after the person presses Confirm, once, for those exact arguments, for 10 minutes. A call before that changes nothing. If the person declines, do not call the tool again. - A client that offers MCP form elicitation asks the person directly.
- A client that can do neither is refused with
APP_CONFIRMATION_REQUIRED.
Example
Set the currency of the northwind-costs report to pounds, in the Sasha web interface. Call app__northwind_costs__set_setting:
{ "key": "currency", "value": "GBP", "idempotencyKey": "currency-gbp-1" }
The first call returns the challenge. This is the structuredContent from a run of the handler on test data, with the app id changed:
{
"confirmation": {
"required": true,
"confirmationToken": "6cfa74176ea4b07507c9e15c159a555c6727f9e31193f3bd55eee152ed5a1d2e",
"expiresAt": "2026-10-17T12:30:57.129Z",
"effects": { "readOnly": false, "destructive": false, "idempotent": true },
"description": "Set \"currency\" in the settings of the \"northwind-costs\" report. Before: \"USD\". After: \"GBP\"."
}
}
After the person approves, send the same arguments with the token:
{
"key": "currency",
"value": "GBP",
"idempotencyKey": "currency-gbp-1",
"confirmationToken": "6cfa74176ea4b07507c9e15c159a555c6727f9e31193f3bd55eee152ed5a1d2e"
}
{ "ok": true, "key": "currency", "created": false, "value": "GBP" }
Then start a test run with app__northwind_costs__run_now, after its own confirmation:
{ "idempotencyKey": "run-2026-10-17-1" }
{ "ok": true, "executionId": "a76b12ea-45f0-45cf-aeac-9f6117d20c81" }
Refusals and what to do
A refusal is an error result. The text is the error message, and structuredContent.error holds code, message, retryable, a diagnosticId to quote, and sometimes details.field.
APP_FIELD_UNDECLARED(app_field_undeclared, fieldkey): the key is not a setting of this report. Check the spelling.app__<app>__settings__listshows the keys that have a value now.APP_INPUT_INVALID(app_input_invalid): the value does not match the setting's schema, orvalueis missing.details.fieldis the property that failed (for examplecentrein one item of a list), orvalue. Nothing changed. Fix the value and send it with a newidempotencyKey.APP_ACTION_UNAVAILABLE(app_action_unavailable, fieldschema): Sasha cannot find a settings schema for this report, so it cannot check a value. Tell the person. An admin can change the setting in the app.APP_ACCESS_DENIED(app_access_denied): the person no longer has access to the app, or their role no longer allows this tool. The role is read again on each call.APP_CONFIRMATION_REQUIRED: this client cannot confirm a change, and a retry will not help. The person can make the change in the Sasha web interface.APP_CONFIRMATION_DECLINED: the person was asked and said no. Do not send the same change again unless they say yes.APP_OPERATION_UNAVAILABLE(fieldoperation): runs cannot start on this instance now. Try again later.APP_IDEMPOTENCY_MISMATCHorAPP_CONFLICT: the key was used for a different change, or the row changed at the same moment. Send the change again with a newidempotencyKey.run_nowreturns{ "ok": false, "reason": ... }when the run cannot start, for exampleagent_busy(another run of this report is going: follow it inruns__list),agent_paused,agent_expiredorauthority_missing. Tell the person the reason. An admin can resume a paused report in the app.- If the connection does not hold
apps:invoke, or the person's role does not get the tool, the tool is not in your tool list, and a call returnsMCP error -32602: Tool app__northwind_costs__set_setting not found(with the name you called).
Related
- The
app-tablefamily reads the report'srecords,runsandsettings. - The
open-appfamily opens the report in its own view. - The
app-actionfamily has the same confirmation steps. getDocshas thereportsandpermissionssections.