Skip to content

ADR 0034: User-bound API/MCP access and versioned contracts

Use user-owned opaque personal access tokens for external REST/MCP clients. Store only a hash of a cryptographically random 256-bit secret in sys_api_credentials, with immutable owner/name/channel/read-only/expiry metadata, creation/last-use timestamps and access state through explicit token revocation. Revoking a token cannot restore that token; replacement creates a new identity/secret. Secrets are returned exactly once on successful creation. No passwords, bearer secrets or hashes enter journals, list responses or logs.

Creation requires the owner’s real unexpired interactive session and current local password. An ordinary user lists/revokes only their own credentials; installation Administrators can inspect/revoke other users’ credentials. Bearer credentials cannot create/manage credentials or manage password/sessions. They execute all other permitted operations under the owner’s current rights, optionally further restricted to read-only and selected transports. Password changes and user deactivation revoke outstanding tokens. Global model barriers serialize revocation/account changes against operations; each operation revalidates its external request context after acquiring its normal locks. Cookie sessions are checked for current ownership, existence and wall-clock expiry under a shared row lock; personal and OAuth tokens retain their existing transactional checks. Trusted internal/operator calls have no external context and still pass normal actor authorization. Journal SQL defaults take trusted transaction-local channel/credential/name values, so field/relationship/security helpers share provenance without accepting an actor from request inputs.

REST remains JSON POST operations at /api/v1/<operation> and MCP remains stateless Streamable HTTP at /mcp, exposing those same operations and a read-only contract resource. API version 1.0.0, explicit major pinning and machine-readable errors are independent of the application and MCP protocol versions. Derive a portable OpenAPI 3.1 input/output contract from shared Zod schemas and TypeScript response types; check generated-source drift and validate successful integration-test responses against those schemas. Package a small typed bearer client with HTTPS/loopback enforcement, no cookie mixing, no redirect following, no secret persistence and no automatic mutation retry. The public how-to/reference is API and MCP access.

The contract generator is pinned as development tooling. Its glob dependency is constrained to the patched upstream package; the HTTP static-file package uses its patched upstream release. No custom dependency fork or alternate authentication framework is introduced. The current unreleased installation is recreated under ADR 0028; released update tooling remains separate.

Token management uses a two-column mobile table with access/state/expiry below the token name and an accessible named revoke action. Confirmation identifies the credential and account. Token journal events have dedicated creation/revocation labels, named account context, channel/read-only details and regional expiry formatting; raw IDs/values remain in Technical details.

Accepted V1 interoperability refinement — 2026-11-05

Section titled “Accepted V1 interoperability refinement — 2026-11-05”

The implemented personal-token slice remains as described above. V1 additionally targets MCP 2026-07-28, standard HTTP OAuth authorization, schema-bound structured tool outputs and precise tool descriptions/annotations. The official SDK 2.4.0 now supplies 2026-07-28 discovery/envelopes, contract-bound structured results and conservative tool annotations locally; standard HTTP OAuth is implemented locally and the scoped live Codex exercise is recorded in the quality report. PRD section 9.2 owns scope and acceptance; the API guide owns the compatibility reference.

OAuth adds delegated MCP access for an xObject user, separate from interactive login and future external SSO. Use Authorization Code with PKCE, protected-resource metadata and authorization-server discovery, supported client identity/registration mechanisms, audience/resource validation and current-user/credential rechecks. Bound granted access to the same administrative/object/record/field ceilings; consent never grants rights the user lacks. The implemented Bearer-only profile uses the maintained Better Auth 1.7.18 MCP/OAuth/CIMD plugins, S256 PKCE, signed consent, public HTTPS metadata transport, hashed opaque 15-minute access tokens and rotating seven-day refresh tokens. It binds MCP resources and live sessions, serializes token issuance against security changes, journals issued/revoked token state atomically and provides own-user application revocation. REST personal tokens remain distinct. DPoP, anonymous DCR and client-credentials grants are disabled. Existing owner/Admin credential management and its interactive-password requirements must not become accessible through delegated Bearer tools. Personal tokens remain a deliberate direct-client option; they are not an OAuth discovery implementation.

The official SDK owns protocol machinery and supported-version negotiation; do not implement a provider-specific dialect. V1 live provider testing uses OpenAI only, with local SDK/contract tests alongside it. Other providers are documented opportunities, not accepted compatibility. Exact client/model/protocol combinations and product-access constraints are recorded during testing. The quality report owns subsequent live client/model evidence and its limits.

Accepted supplied-skills refinement — 2026-11-05

Section titled “Accepted supplied-skills refinement — 2026-11-05”

PRD section 9.3 defines the V1 foundation, module and model-design workflows. Publish versioned SKILL.md content and references through the official SDK’s io.modelcontextprotocol/skills extension, with declared capabilities and authorized resource access. Skill discovery and instructions use the caller’s active/permitted module context and current metadata. All actions retain the existing backend rights, validation, optimistic versions and atomic journals; a skill is a workflow layer, not a parallel execution/authorization path.

An optional OpenAI plugin may package the same skill sources with the MCP connection. Keep protocol extension support and plugin/local skill packaging distinct, reuse one canonical source and record actual client capabilities during OpenAI-only acceptance. No automatic installation/activation or cross-provider compatibility is presumed. The official Skills extension now serves four canonical workflows with current-context discovery/read filtering and private zero-lifetime resources. Local SDK acceptance covers discovery, content digest verification and denied direct reads. The optional portable package is schema-checked; live Codex acceptance also loaded and used installed Foundation/Projects instructions. The tested host did not expose/negotiate native MCP Skills activation; resource/package loading remains distinct.

Integration scenarios cover one-time secrets, owner isolation, password confirmation, channels/read-only restrictions, expiry, revocation/revoke-all/password rotation, current rights, API/MCP parity, audit provenance, transaction rollback and contract reference/response validation. Browser acceptance covers account/user management, creation drafts, lifecycle controls and retained-history views; real token generation is additionally exercised through isolated backend sessions. The development guide records actual results. The current implementation remains unreleased. The quality report records accepted local Codex OAuth/skill paths; cloud-hosted integrations, external SSO and distributed rate limiting retain their separate scope.