Public MCP Service¶
Intended public endpoint¶
The first deployable HeyAira service is a real remote MCP server, not only a local development process.
Proposed public URL:
https://mcp.heyaira.eu/mcp
The mcp subdomain keeps the service boundary separate from a future product website at heyaira.eu.
Public surface¶
The public service has one MCP protocol endpoint:
POST /mcp— MCP Streamable HTTP requests;GET /mcp— protocol session/event behavior as required by the official SDK;DELETE /mcp— session termination when supported by the transport.
Operational and human-facing endpoints are separate from MCP:
GET /healthz— shallow liveness response, with no secrets or database contents;GET /docs— human-readable setup and tool documentation;GET /— short service identity page linking to/docs.
MCP tools are not separate REST endpoints. Clients discover them through the MCP protocol using tools/list and call them through /mcp.
Authenticated clients should call server_identity before any mutation. It
returns the configured resource, logical instance, environment, service
revision, and authenticated project without exposing tokens, DSNs, or internal
hostnames.
Authentication¶
The public registration flow uses MCP-standard OAuth 2.1 Authorization Code
with PKCE. The authorization server must publish protected-resource metadata
and authorization-server metadata, accept the resource parameter, validate
exact redirect URIs and issue access tokens audience-bound to the HeyAira MCP
resource.
The existing project-scoped static Bearer token remains available for internal Codex and CLI compatibility:
Authorization: Bearer <project-token>
The server must:
- require a valid OAuth access token or approved internal Bearer credential for every MCP request;
- map the credential to exactly one HeyAira project and permitted scopes;
- reject missing, malformed, expired/revoked, wrong-audience, or unknown tokens;
- never accept
project_idfrom model input as an authorization decision; - avoid logging the header or token value;
- return a generic unauthorized response without revealing whether a token or project exists.
OAuth is implemented as a standards-based adapter around the same project authorization boundary. GitHub tokens are never accepted as HeyAira MCP tokens and are never passed through to downstream services.
The metadata and authorization endpoints are:
GET /.well-known/oauth-protected-resource/mcp;GET /.well-known/oauth-authorization-server;GET /authorize;POST /token;POST /registerwhen dynamic client registration is enabled;POST /revokewhen token revocation is enabled.
The authorization page is an MVP HeyAira consent boundary at /oauth/consent.
It accepts an existing project access token only to select the project and
derive the identity's role. The token is not returned to the OAuth client.
User and organization sign-in, GitHub App installation, and repository API
operations are separate follow-up integrations.
Tool catalogue¶
The first server exposes only the minimal continuity surface:
Startup recovery¶
continuity_context— return a bounded read-only snapshot of project identity, recent memory, open tasks, and recent work-session receipts.runtime_bootstrap_get— return pinned, allowlisted project document references for continuity bootstrap; requiresdocuments:read.git_document_get— read one bounded UTF-8 fragment from an allowlisted commit-pinned GitHub document; requiresdocuments:read.
Memory¶
memory_add— append a note or decision to the authenticated project; optionalidempotency_keymakes safe retries return the original result;memory_get— retrieve one memory entry by ID within the authenticated project;memory_search— search active project memory, or list recent active entries when no query is supplied.
Tasks¶
task_create— create a project task; optionalidempotency_keymakes safe retries return the original result;task_get— retrieve one task by ID within the authenticated project;task_list— list project tasks with a bounded result set;task_update— update a task using mandatoryexpected_versionconcurrency control.
Mutations also require write_context containing the expected resource,
instance_id, and project_id. The server compares these values with trusted
configuration and the authenticated project before changing state. Missing or
mismatched context is rejected without changing domain records and produces a
redacted audit event. Clients must stop after task_get returns task not
found; they must not recreate, migrate, or search other projects.
Work state¶
Work-session receipts are part of the durable state model. The initial implementation may expose them through the smallest possible additional operation or attach them to task updates, but they must record the logical worker/thread and Git checkpoint needed for a code handoff.
Receipt identity is unique per (task_id, session_ref). Task updates remain
atomic with their receipt insert and require expected_version; a stale
retry is rejected without changing the task or adding a receipt.
See the continuity protocol for startup recovery, persisted event guidance, and duplicate-prevention rules.
Every tool description must explain its purpose, required parameters, project boundary, result shape, and failure behavior. Examples on /docs use synthetic data only.
Client registration information¶
The public documentation must provide:
- server URL:
https://mcp.heyaira.eu/mcp; - transport: Streamable HTTP;
- authentication: OAuth 2.1 for public clients; internal HTTP Bearer compatibility for Codex/CLI;
- resource identifier:
https://mcp.heyaira.eu/mcp; - token placement: protected client configuration, never repository files;
- available tools and schemas;
- the
server_identityandwrite_contextsafety contract; - a synthetic smoke-test sequence;
- limitations of the private pilot;
- support/contact and version information when those are decided.
The documentation must not contain a real token, database password, private key, memory entry, or production repository content.
Deployment boundary¶
- PostgreSQL is reachable only inside the private container network.
- The MCP service listens on a controlled internal or loopback port.
- TLS terminates at an approved HTTPS edge or reverse proxy for
mcp.heyaira.eu. - All application containers and volumes are owned by
heyairaand run rootless. - Voyana users, containers, volumes, databases, and credentials are out of scope.
- Cloudflare DNS/proxy/tunnel configuration is a separate infrastructure step and must be explicitly verified before public registration.
Synthetic smoke test¶
After creating a project token, run:
.venv/bin/python scripts/smoke_mcp.py \
--url https://mcp.heyaira.eu/mcp \
--token-file /secure/local/path/heyaira-token
The default smoke test checks /healthz, rejects an unauthenticated MCP
request, discovers the ten tools, writes and reads memory, creates and updates
a task, records a work-session receipt, and rejects a stale task version. F1
document tools are discovered but are not exercised by that state-only smoke
test. The opt-in tests/test_f1_mcp_e2e.py test covers the full isolated
runtime_bootstrap_get -> git_document_get path against PostgreSQL with a
synthetic provider; it does not claim public GitHub or production deployment.
Public acceptance¶
The public infrastructure portion is complete only when an external MCP client can:
- reach the domain over HTTPS;
- complete MCP initialization and tool discovery;
- call a memory write and a memory read with a valid project token;
- receive a safe failure without a token;
- confirm that PostgreSQL is not publicly reachable;
- read the human documentation and reproduce the synthetic smoke test.