UWAC API
Universal Web App Connectors: agent DID auth plus connect, callback, disconnect, and invoke for the OAuth vault that turns external app credentials into per-user MCP tools.
UWAC (Universal Web App Connectors) is the Matrix control plane that lets an agent act inside a user's external apps (Gmail, Calendar, and more) without the agent ever holding the OAuth token. The token is vaulted server-side; only scoped results return to the daemon. The OAuth token never crosses the wire to the agent.
Architecture
agent (per-user daemon)
| MCP stdio
v
tools/uwac/uwac.mjs --HTTP--> uwacd (shared Fly app)
+ agent-DID auth (challenge/verify, ed25519)
+ OAuth connect (GoTrue scope-elevation PKCE)
+ token vault (AES-256-GCM at rest)
+ tool invoke (scope+consequence gate -> provider API)
|
v injects token server-side
Google / GitHub / Slack / ...
Routes
| Method | Path | Purpose |
|---|---|---|
| GET | /healthz | Liveness |
| GET | / | Service root / info |
| POST | /v1/agent/auth/challenge | Request a nonce for the agent DID |
| POST | /v1/agent/auth/verify | Verify the signed nonce, mint a session token |
| POST | /v1/connect | Begin an OAuth connect flow for a connector |
| GET | /v1/connect/callback | OAuth redirect callback (completes the connection) |
| POST | /v1/disconnect | Revoke and remove a connection |
| POST | /v1/invoke | Invoke a connector tool with the stored credential |
Authentication
Two-layer auth:
- Transport bearer -- shared
MATRIX_UWAC_TOKENproves the caller is a Matrix daemon (router-injected). - Principal -- the daemon's ed25519 executor key signs a challenge; uwacd resolves the owner Supabase
user_idfrom the DID label (did:matrix:<user_id>:<keyfp>), which is the same ID that consented the app via GoTrue.
The OAuth token never crosses the wire to the daemon.
Connect flow
POST /v1/connect with the connector ID returns an authorization URL. Send the user there.
The provider redirects to GET /v1/connect/callback; UWAC exchanges the code and stores the credential in the vault (AES-256-GCM at rest).
POST /v1/invoke runs a connector tool on the user's behalf using the vaulted credential, exposed to the agent as an MCP tool.
Connector tools
Each connected app exposes scoped tools as MCP tools. The tool registry is generated from the Go source of truth and advertised via uwac-tools.json.
Current connectors:
| Connector | Tools | Scopes |
|---|---|---|
google-workspace | Gmail (send, search, read), Calendar (list, create, update) | gmail.modify, calendar.events |
Additional connectors (GitHub, Slack) are planned.
MCP integration
The stdio MCP proxy at tools/uwac/uwac.mjs bridges the daemon's MCP tool manager to uwacd over HTTP. It reads the tool registry from uwac-tools.json and forwards calls to the UWAC invoke endpoint.
Regenerate the tool registry:
go run ./cmd/uwacd -dump-tools > ../tools/uwac/uwac-tools.json
Self-test the proxy:
node ../tools/uwac/uwac.mjs --selftest
Credentials live in the vault, never in agent manifests or prompts. The agent only ever sees a tool surface, not the underlying tokens.
Status
First slice implemented end-to-end: agent-DID auth, GoTrue scope-elevation connect, in-memory encrypted vault, and the google-workspace connector (Gmail + Calendar). Not yet wired: Postgres-backed vault + background refresher, marketplace UI, and production deploy.
