Skip to content

ADR-0004: MCP server as a separate Node process

  • Status: Accepted
  • Date: 2026-05-03
  • Affected: backend/mcp/arcive-memory-mcp/

Context

Memory retrieval is needed in three places: the chat API (/api/chat), the voice service (Pipecat), and — at V1.0 — public MCP clients (Claude Desktop, ChatGPT, Cursor). Today each path has its own inline Voyage + pgvector call. That’s a duplication problem and a coupling problem: changing how retrieval works means editing two or three call sites.

docs/01_SOFTWARE_PLAN.md §7 V0.3 calls for an “internal MCP server … used by agents/roles as the retrieval layer.” V1.0 promotes it to a public endpoint.

Options considered

Option A — Embed MCP server inside the Next.js app

  • Pros: One process; no extra deploy; shares Supabase clients.
  • Cons: MCP needs a long-lived process; serverless functions don’t fit. Can’t be exposed publicly without splitting it out anyway — V1.0 work would just undo this.

Option B — Embed MCP server as another Edge Function

  • Pros: Stays in Supabase.
  • Cons: Edge Functions are HTTP request/response, not the persistent Streamable HTTP shape MCP uses. Workable but awkward.

Option C — Standalone Node service (chosen)

  • Pros: Long-lived process matches the protocol. Single source of truth for retrieval logic. V1.0 public endpoint just adds auth + rate limit, no rewrite. Deploys anywhere Node runs (Modal, Fly, Cloudflare Workers with a small adapter).
  • Cons: One more service to deploy and observe. CI must add a step to typecheck it (currently skipped — see PROGRESS).

Decision

Stand up the MCP server as a standalone Node service in backend/mcp/arcive-memory-mcp/. Streamable HTTP transport per the MCP spec. Three tools at V0.3: search_memories, get_person, timeline_window. Per-request auth via Supabase user JWT in Authorization: Bearer ….

Internal use only at V0.3. V1.0 promotes the same service to public by adding rate limiting and surfacing a Pro-tier endpoint URL.

Consequences

  • /api/chat doesn’t yet use this server — V0.3 work to swap it. Until then we have temporary duplication. Documented in PROGRESS.
  • Voice service (Pipecat) doesn’t yet use this server either. V0.2-extended / V0.3 work.
  • Standalone project means it isn’t in the pnpm workspace; CI doesn’t typecheck it by default. Acceptable for a scaffold; add to CI before production.
  • When V1.0 promotes to public MCP, the same service answers external clients. A user’s Pro-tier subscription gates external access.

Notes

The MCP TypeScript SDK ships its own JSON Schema generation; we hand-roll three schemas in index.ts to avoid the heavier zod-to-json-schema dep. Swap to the library if we add many more tools.