Add permission-scoped MCP, readiness checks, and management UI improvements
This commit is contained in:
+83
@@ -0,0 +1,83 @@
|
||||
# Assistant access (MCP)
|
||||
|
||||
Open **Albums → Assistants** (`/dashboard/assistants`) and create a connection.
|
||||
The endpoint is `https://ma.hadlock.tech/api/mcp`, using Streamable HTTP. Configure
|
||||
your MCP client to send `Authorization: Bearer <token>` on every request. Tokens
|
||||
are displayed once, stored only as SHA-256 hashes, expire after 1–365 days, and
|
||||
can be revoked in that screen. Keep them in the client's secret storage, never
|
||||
in prompts or source control. This version uses bearer tokens, not OAuth discovery;
|
||||
clients must support custom authorization headers. No public/anonymous access.
|
||||
|
||||
## Permissions
|
||||
|
||||
Tokens default to read-only statistics/discovery permissions. Enable only the
|
||||
existing event, group, and platform permissions needed by that assistant.
|
||||
Selections are a ceiling: the same current memberships/roles used by the web UI
|
||||
are re-evaluated for every action. Selecting platform permissions never makes an
|
||||
ordinary account a platform administrator. Removing a role restricts existing
|
||||
tokens; revoking a token blocks new requests, not work already executing.
|
||||
|
||||
Private photo access is separately restricted by `photos.private.read`, including
|
||||
when the token belongs to an owner/admin. Read-only tokens cannot call write tools
|
||||
even if they include management permissions for reading associated data.
|
||||
|
||||
The explicit tool allowlist covers platform stats/settings/users/roles/allowances,
|
||||
groups and memberships, events and schedules, photos/submission/note moderation,
|
||||
guest lists and notification emails, invitations, exports, and banner/sign workflows.
|
||||
It does not expose sessions, token management, guest authentication, SQL, arbitrary
|
||||
HTTP requests, or shell commands. New application procedures require explicit review
|
||||
before being added to the MCP catalog.
|
||||
|
||||
## Calling tools
|
||||
|
||||
Tool names use underscores, for example `manager_stats` and `group_rename`.
|
||||
Existing application input goes under `input`. Dates are ISO-8601 strings.
|
||||
|
||||
```json
|
||||
{"name":"manager_stats","arguments":{"input":{"eventId":"EVENT_UUID"}}}
|
||||
```
|
||||
|
||||
Every write requires `confirm: true` in addition to a write-enabled token and the
|
||||
required permissions. This is an explicit API acknowledgement, not proof that a
|
||||
human approved the action; configure your assistant to ask before destructive
|
||||
actions or sending messages.
|
||||
|
||||
```json
|
||||
{"name":"group_rename","arguments":{"input":{"groupId":"GROUP_UUID","name":"Wedding team"},"confirm":true}}
|
||||
```
|
||||
|
||||
Do not automatically retry writes after an ambiguous connection failure. Re-read
|
||||
state first: mutations may have succeeded and are not universally idempotent.
|
||||
List outputs are paginated with top-level `offset` and `limit` (default 50, max
|
||||
100), returning `items`, `total`, and `nextOffset`. Application-specific filters
|
||||
and page fields remain inside `input`. Some application queries impose their own
|
||||
limits; `total` then reflects that result set rather than all database records.
|
||||
|
||||
Uploads still go directly to storage using signed URLs. MCP never proxies original
|
||||
files. Tool results may contain personal data or signed URLs according to the
|
||||
selected permissions—treat the connected assistant as a data recipient. Guest
|
||||
notes, names, and other content returned by tools are untrusted data, not instructions.
|
||||
|
||||
Calls have per-client and per-token rate limits, a 64 KiB request-body cap, origin
|
||||
validation, and no-cache responses. Tool audit entries record token/user ids,
|
||||
tool name and success, not raw arguments, credentials, or guest data. Existing
|
||||
mutation audit entries remain unchanged. No production token is created automatically.
|
||||
|
||||
## Verification
|
||||
|
||||
```sh
|
||||
MCP_INTEGRATION=1 bun --env-file=.env test apps/web/src/server/mcp/mcp.integration.test.ts
|
||||
```
|
||||
|
||||
The integration test refuses non-local databases and does not send email.
|
||||
|
||||
## Coolify health checks
|
||||
|
||||
Both Compose definitions use `/api/health/ready` for web readiness (bounded DB
|
||||
probe) and a loopback-only worker `/health` endpoint on port 3001. The worker
|
||||
checks DB connectivity and loop heartbeats; a loop stalled for 15 minutes is
|
||||
unhealthy. Long exports can exceed this threshold and should be investigated.
|
||||
`/api/health` remains process liveness. Responses omit internal dependency details.
|
||||
Checks run every 30 seconds, with a 5-second timeout and three retries. No worker
|
||||
health port is published. Docker health status by itself does not automatically
|
||||
restart an unhealthy container; it supplies readiness information to Coolify.
|
||||
Reference in New Issue
Block a user