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.
| Tool | Scope | Operation |
|---|---|---|
setup_app | apps:write | POST /api/v1/apps/setup |
grant_access | access:write | POST /api/v1/apps/{appId}/access/grants |
create_group | access:write | POST /api/v1/groups |
add_to_group | access:write | POST /api/v1/groups/{groupId}/members |
create_share_link | grants:write | POST /api/v1/apps/{appId}/grants/share-links |
rotate_secret | grants:write | POST /api/v1/apps/{appId}/grants/{grantId}/rotate |
get_ingress_snippet | apps:read | GET /api/v1/apps/{appId}/ingress-snippet |
resolve_access | apps:read | POST /api/v1/apps/{appId}/access/resolve |
read_audit | audit:read | GET /api/v1/audit |
set_app_credential | apps:write | PUT /api/v1/apps/{appId}/credentials/{provider} |
get_user_provider_token | vault:read | POST /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
- Call
setup_appwith 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. - Hand the public part of that result to the checked-in
setup-authskill. It writes a public configuration file, an environment example, and an inactive secret template — with no credential values in any of them. - Call
get_ingress_snippet, review the addressing rules (nginx YAML and, where needed, the EnvoySecurityPolicy), apply them through your own deployment, and test the protected hostname. See Protect an app. The checked-in agent skills under.agents/skillsare the playbooks for that work. - 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.