Skip to content

MCP endpoint and authentication

Endpoint

Every project has its own address — one project, one address:

https://mcp.heyaira.eu/p/<project-slug>/mcp

For example https://mcp.heyaira.eu/p/voyana/mcp. The address is shown as project.mcp_url by server_identity and printed by the operator's heyaira-admin create-project --slug / update-project. An address no project has answers like one a project has (401, the same metadata), so the endpoint does not reveal which slugs exist; only a malformed slug returns 404.

The shared https://mcp.heyaira.eu/mcp is deprecated, but it is not switched off. It serves the same tools and still issues new OAuth grants: an authorization request with resource set to /mcp, or with no resource at all, gets a code and tokens bound to /mcp, for whichever project's access token is entered at consent. Static project tokens are accepted there too. The Bridge and the iOS app use it. The supported address for new connections is the project's own /p/<project-slug>/mcp.

Transport: MCP Streamable HTTP.

MCP tools are discovered through tools/list and invoked through the project's address. They are not independent REST endpoints.

The machine-readable HTTP contract is the OpenAPI 3.1 document, and the generated MCP tool snapshot is available in the machine-readable contracts reference. OpenAPI describes the HTTP/OAuth surface; MCP tools/list remains authoritative for tool schemas.

Public authentication

Public clients use OAuth 2.1 Authorization Code with PKCE. The server exposes protected-resource and authorization-server metadata so a client can discover the flow. The resource identifier is the project's address:

https://mcp.heyaira.eu/p/<project-slug>/mcp

Each address is its own OAuth resource with its own protected-resource metadata, so a client that keys connectors by URL (for example claude.ai) can hold one connector per project. The consent page shows the project the address belongs to and refuses a project access token of any other project. Consent always needs that project access token; only heyaira-admin create-project issues one, and there is no self-service sign-up. A grant is accepted only on the address it was issued for, and only while that address belongs to the grant's project. A static project-scoped Bearer credential is accepted on /mcp and on its own project's address, never on another project's.

The authorization-server metadata advertises offline_access and the server issues refresh tokens. Clients should request that protocol scope together with the data scopes they need so a long-lived MCP connection does not expire after the short-lived access token. documents:read remains a separate data scope and is never added to an existing OAuth grant silently.

Every refresh rotates the refresh token. A rotated refresh token presented again more than 10 seconds after its rotation means someone holds a copy: the server revokes every access and refresh token of that grant (the tokens from one consent and all their refreshes) and the client must connect again. A replay within those 10 seconds (a refresh whose answer was lost) is refused with invalid_grant and revokes nothing.

notifications:write covers the phone writes under /bridge/v1/mobile/: registering a device, changing its preferences, revoking it, and marking notifications read. It is not a default scope; the HeyAira app requests it. A grant issued to the verified HeyAira app client (every registered callback is the app's own) may make these writes without it, so existing app sign-ins keep registering rotated APNs tokens; the role rule below applies to both. A viewer role never receives it (contributors and above may), and each of those writes rechecks the credential's current membership with the token and membership rows locked until it commits. Static project tokens keep it.

bridge:bindings:write is an explicit administrative scope for linking or unlinking a project and an enrolled Bridge identity. It is valid but is not part of the default OAuth scope set. A client must request it deliberately, and only an owner or admin may receive it. The authenticated subject must still be an owner or admin in the target project. Linking additionally requires owner or admin access to the Bridge identity's enrollment project. Unlinking does not, so the target project's administrator can always remove its own access.

Internal compatibility clients may use a project-scoped Bearer credential. Neither credential may be committed to Git or written into documentation.

Read-only first

Before a mutation, call server_identity and continuity_context. A client with a stale schema must reconnect and rediscover tools. It must not remove required fields or fall back to an unbound write path.

Operational endpoints

  • /healthz — liveness and database readiness, with the running release's commit as revision;
  • /docs — compact service-facing documentation;
  • / — service identity page;
  • /.well-known/oauth-protected-resource/p/<project-slug>/mcp — per-project protected-resource metadata (resource_name: HeyAira – <project-slug>);
  • /.well-known/oauth-protected-resource/mcp — metadata of the deprecated shared resource, which still accepts new grants;
  • /.well-known/oauth-authorization-server — authorization-server metadata.