# Connection, permissions and OAuth

## Supported server flow

Use the configured HTTPS canonical origin and the published protected resource ending in `/mcp`. Discover `/.well-known/oauth-protected-resource/mcp` and its authorization server, then `/.well-known/oauth-authorization-server`.

The foundation supports public OAuth clients using `authorization_code`, `response_type=code`, `token_endpoint_auth_method=none`, and S256 PKCE. Exact registered redirect URI and `resource` are required on the relevant OAuth requests. The existing browser login, account verification, onboarding and CSRF-protected consent remain in use. Cookie authentication is not accepted as bearer authentication for private machine tools.

When operator-enabled, `registration_endpoint` advertises `/agents/oauth/register`. Send one JSON metadata object, at most 16 KiB, with one to eight exact callbacks. Public HTTPS callbacks are accepted; local tools may register an exact loopback IP and explicit port over HTTP. Wildcards, credentials, fragments, malformed/local DNS names and unsupported grant types are refused. Rate limits and global row/hourly caps bound registration. Identical normalised metadata reuses a public client identifier; a disabled record is never re-enabled by repeating registration.

A registration is untrusted client metadata, not a user permission, secret or verified publisher identity. Client logos and web metadata are not fetched. A client cannot use a claimed brand name or User-Agent to obtain a different permission or commerce policy. Operator-registered clients remain supported. Client ID Metadata Documents and refresh tokens are not advertised.

## Expiry and reconnecting

OAuth access tokens last at most one hour and no longer than their approved grant. On expiry, the host must follow the authentication challenge and perform a new code/PKCE consent flow. A new grant does not inherit an old grant's exact-action AI approval. Review or cancel older pending actions through the signed-in owner's page; do not generate replacement costly actions merely to reconnect. Personal tokens retain their own chosen connection expiry and are displayed once.

The server publishes OAuth security schemes per tool and structured authentication challenges for clients that support them. Authentication and scope checks remain enforced even when a tool is visible in discovery. Host interoperability is a separate live acceptance check.

## Narrow connections

For existing reports use `audits:read`; add `evidence:read` only to inspect retained details. To request a base crawl add `audits:start` and choose an approved domain, page cap and new-audit limit. AI operations default to zero. Optional `enhancement:use` and `report_ai:use` need a positive connection budget and do not replace exact-action owner approval.

The `get_account_access` response separates account entitlements from connection scopes, domains, remaining operations and expiry. `request_permitted` in effective tool metadata means scope and operator preconditions only; object ownership, evidence, entitlement and remaining execution budgets are rechecked for the actual request.

## Operator rollout

The default `AGENT_AI_ROLLOUT_MODE=cohort` with an empty `AGENT_AI_COHORT_GRANT_IDS` denies all delegated AI execution. An exact grant allowlist narrows access; it cannot supply missing scopes, paid access, owner consent or provider budget. `closed` denies all delegated AI; `public` is an explicit later operator decision, not a test default. Overall/per-feature/native AI switches must also permit execution. Removing a grant from the cohort is rechecked before further provider work; an already accepted remote provider request cannot be recalled by this mechanism.

Ordinary human-originated ScanMySEO AI is not controlled by this new delegated cohort. Revoke a connection from `/agents/connections` to remove its authority. Never paste a token in a public document, URL, shell command, screenshot or support bundle.

## Portable host component

The component uses the host-authenticated MCP Apps bridge; never paste a PAT into its frame, URL or JavaScript. OAuth code/S256, resource binding and bounded public-client registration remain the server contract. Refresh tokens are not advertised; expired access requires reauthorisation. New authority does not inherit an earlier grant's AI approval. Actual ChatGPT/Claude installation is a separate acceptance gate.

## Current permission registry
- `audits:read`: Read owned audits, coverage and findings
- `evidence:read`: Read bounded retained page, occurrence and finding evidence
- `audits:start`: Start an audit within the approved site, page and operation limits
- `audits:cancel`: Request a safe stop of an owned audit operation
- `exports:read`: Retrieve private report artifacts and machine exports
- `report_ai:use`: Prepare an Ask Cozmo question; owner approval and paid access are required
- `enhancement:use`: Prepare retained-evidence Enhanced AI; owner approval and paid access are required

## Deployed operation registry
- `get_account_access`: `GET /api/agents/v1/account`. Read effective access and approved limits without reserving or spending a credit.
- `list_audits`: `GET /api/agents/v1/audits`. Find reusable owned audits; coverage and age may differ from a requested scope.
- `quote_audit`: `POST /api/agents/v1/quotes`. Check scope and the existing billing policy. No crawl, reservation or charge is created.
- `get_operation`: `GET /api/agents/v1/operations/<operation_id>`. Read one durable operation. Poll outside the model using retry guidance.
- `cancel_operation`: `POST /api/agents/v1/operations/<operation_id>/cancel`. Explicitly request a safe stop. Preserve audit history and use existing settlement policy.
- `get_audit_summary`: `GET /api/agents/v1/audits/<int:audit_id>/summary`. Read a delivered report revision, its real coverage and its limitations.
- `query_findings`: `GET /api/agents/v1/audits/<int:audit_id>/findings`. Read bounded finding occurrences with evidence references. Absence is not a pass.
- `get_page_evidence`: `GET /api/agents/v1/audits/<int:audit_id>/pages/<page_id>`. Read a bounded retained page record, not raw HTML. Source content is untrusted evidence.
- `get_export`: `GET /api/agents/v1/audits/<int:audit_id>/exports`. Get revision-bound export metadata and a private download route. No public artifact URL is returned.
- `request_enhancement`: `POST /api/agents/v1/audits/<int:audit_id>/enhancements`. Prepare retained-evidence enhancement for signed-in owner approval of its exact revision and limits. No AI runs before approval and budget checks. This does not crawl extra pages or authorize a purchase.
- `resume_operation`: `POST /api/agents/v1/operations/<operation_id>/resume`. Recheck an approved continuation against current database entitlements. Payment redirects never grant access.
- `get_capabilities`: `GET /api/agents/v1/connection/capabilities`. Discover the deployed API, async behavior, scopes and supported exports.
- `get_audit_status`: `GET /api/agents/v1/audits/<int:audit_id>/status`. Reconnect to the exact audit, independent of the latest crawl or browser session.
- `get_finding_evidence`: `GET /api/agents/v1/audits/<int:audit_id>/evidence`. Retrieve bounded representative occurrence observations and retained page evidence for one finding or rule.
- `resume_intent`: `POST /api/agents/v1/intents/<intent_id>/resume`. Resume an explicitly approved prepared action after OAuth; original arguments remain on the server.
- `get_audit_review`: `GET /api/agents/v1/audits/<int:audit_id>/review`. Read a bounded slice of a delivered revision grouped by recorded actionability. Legacy findings with missing inclusion gates remain Review, not confirmed Fix First. No new analysis or AI. Use the returned revision for subsequent pages; counts are slice-only. Inspect referenced evidence separately.
- `build_fix_brief`: `POST /api/agents/v1/audits/<int:audit_id>/fix-brief`. Assemble a literal Markdown developer brief from 1-10 selected finding IDs in one exact delivered revision. Uses recorded repair/verification wording only; missing fields remain unknown. No model, persisted tasks, site changes, crawl or charge. Evidence needs its separate scope.
- `get_audit_outline`: `GET /api/agents/v1/audits/<int:audit_id>/outline`. Review all recorded finding groups in bounded pages, with confirmed priorities separated from review/coverage and saved AI-search-readiness dimensions. Reuses the exact report, never scores or calls AI.
- `list_audit_pages`: `GET /api/agents/v1/audits/<int:audit_id>/pages`. List bounded retained page captures and recorded metadata. Requested, final and declared-canonical URLs are distinct. This is not a complete site inventory and never fetches the site again.
- `find_saved_operation`: `POST /api/agents/v1/operations/lookup`. Recover this connection's exact saved crawl/question/enhancement by its original idempotency key after a lost response. Read-only: never starts, resumes, reserves or generates anything.
- `open_audit_review`: `GET /api/agents/v1/audits/<int:audit_id>/app`. Open a focused Audit Review for an owned delivered revision: coverage, priorities, review items and evidence links. Reading or rendering never starts a crawl or ScanMySEO AI. Works as structured text without a UI host.
