MCP tools

Give an agent the same eleven operations the dashboard has, with an API key that bounds what it may touch.

@davidapps/mcp is a local stdio server that gives an agent the same operations you have. It holds no state, opens no database connection, and stores no credential: each tool turns into exactly one authenticated call to the HTTP API, and the answer comes back as it arrived.

That one-for-one shape is the point. Anything an agent can do here, you can do in the dashboard and with a plain HTTP call. The scope a tool needs is the scope its operation needs, and every call lands in History the same way.

Install it

The package is built and install-verified but not published to a registry yet. Install it from this workspace, or from a tarball you packed yourself, into the project where the agent runs. Once it is published, the usual install will work; until then, treat a registry install as unavailable rather than as something to work around.

Configure a client

The command is davidapps-mcp. It reads two values from its environment and refuses to start without either:

DA_BASE_URL=https://id.davidapps.dev
DA_API_KEY=dak_...

Put both in your client's secret or environment configuration. Do not commit them, and do not paste a key into a prompt — the server never writes a key anywhere, and that is only worth something if you do not either.

Create keys on Settings → API keys. The secret is shown once, at creation, and cannot be retrieved afterwards. Give a key the fewest scopes it needs, and bind it to a single app unless it genuinely has to work across all of them. A key bound to one app that is used for another, or for an operation that is not about a specific app such as setup_app, is refused with API_KEY_FORBIDDEN — the same answer either way, so a rejected call tells the caller nothing about what exists.

The tools

Eleven tools, eleven operations. Each advertises the scope it needs in its davidapps.dev/requiredScope metadata, and the API enforces that scope regardless of what the client believed.

ToolScopeOperation
setup_appapps:writePOST /api/v1/apps/setup
grant_accessaccess:writePOST /api/v1/apps/{appId}/access/grants
create_groupaccess:writePOST /api/v1/groups
add_to_groupaccess:writePOST /api/v1/groups/{groupId}/members
create_share_linkgrants:writePOST /api/v1/apps/{appId}/grants/share-links
rotate_secretgrants:writePOST /api/v1/apps/{appId}/grants/{grantId}/rotate
get_ingress_snippetapps:readGET /api/v1/apps/{appId}/ingress-snippet
resolve_accessapps:readPOST /api/v1/apps/{appId}/access/resolve
read_auditaudit:readGET /api/v1/audit
set_app_credentialapps:writePUT /api/v1/apps/{appId}/credentials/{provider}
get_user_provider_tokenvault:readPOST /api/v1/apps/{appId}/vault/token

The full scope list is apps:read, apps:write, access:write, grants:write, vault:read, and audit:read. Request and response shapes are in the HTTP API reference, which is generated from the same contracts these tools are built on, so the two cannot drift.

Two of them deserve care. rotate_secret replaces a shared password, share link, or bypass token and invalidates the old one, so it is marked destructive. set_app_credential replaces an app's stored provider credential; the value you send is encrypted at rest and never returned by any later read.

Setting an app up from nothing

  1. Call setup_app with the app's exact hostnames, how it lets people in, its sign-up policy, and any development addresses. Keep the returned secret in your client's secret store. It is shown once and the server does not write it anywhere.
  2. Hand the public part of that result to the checked-in setup-auth skill. It writes a public configuration file, an environment example, and an inactive secret template — with no credential values in any of them.
  3. Call get_ingress_snippet, review the addressing rules (nginx YAML and, where needed, the Envoy SecurityPolicy), apply them through your own deployment, and test the protected hostname. See Protect an app. The checked-in agent skills under .agents/skills are the playbooks for that work.
  4. Replace the broad key you started with by one bound to that app, carrying only the scopes it still needs.

The repository acceptance command pnpm phase6:proof runs this whole sequence from a fresh temporary Git repository against a packed, installed copy of the package and a live API, and additionally checks that the generated files have not drifted, that a key bound to one app cannot reach another, and that a full local database restore leaves share-link sign-in still working.

Reading failures

Errors come back as the API's own envelope — a stable code and a short message — and nothing more. If the server itself could not make the request, the code is MCP_CLIENT. There is no stack trace, no upstream status, and no detail about what exists on the other side.

On this page