Skip to content

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_id from 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 /register when dynamic client registration is enabled;
  • POST /revoke when 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; requires documents:read.
  • git_document_get — read one bounded UTF-8 fragment from an allowlisted commit-pinned GitHub document; requires documents:read.

Memory

  • memory_add — append a note or decision to the authenticated project; optional idempotency_key makes 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; optional idempotency_key makes 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 mandatory expected_version concurrency 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:

  1. server URL: https://mcp.heyaira.eu/mcp;
  2. transport: Streamable HTTP;
  3. authentication: OAuth 2.1 for public clients; internal HTTP Bearer compatibility for Codex/CLI;
  4. resource identifier: https://mcp.heyaira.eu/mcp;
  5. token placement: protected client configuration, never repository files;
  6. available tools and schemas;
  7. the server_identity and write_context safety contract;
  8. a synthetic smoke-test sequence;
  9. limitations of the private pilot;
  10. 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 heyaira and 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.