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 asrevision;/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.