← all work
VOICE AIApr–May 2026

Mirarsan agent that runs the whole study

One chat. The agent sources people, runs the voice interviews, and writes the report.

18
tools, 2 transports
165/165
server tests
Sole
architect
3 wk
build

Mirars runs an entire research study end to end: it sources candidates, emails the invites, runs the voice interviews, and writes the report. I was sole architect, start to finish over three weeks, of a Gemini agent loop with iteration caps, Zod-parsed tool arguments, token accounting, and exponential-backoff retry on 429/5xx.

One registry of 18 Zod-typed tools drives two transports: the /chat agent and a Streamable-HTTP MCP server. A new tool is one file plus one registry line — zero per-transport duplication. The candidate pipeline fires three ICP-derived Exa queries in parallel, dedupes by URL, embeds in one batched call, and bulk-upserts into pgvector keyed by linkedin_url.

Voice interviews run on ElevenLabs Convai. When Gemini started throwing 503s and drifting JSON shapes in production, I moved transcript analysis to OpenAI strict structured output.

The hard part

Zero-config MCP authentication

Exposing the agent as an MCP server meant clients had to authenticate with no UI to fill in. I built a device-authorization flow keyed by the Mcp-Session-Id that races a url-mode elicitation against a push approval, and reads a -32602 rejection as the cue to fall back to a clickable resource_link instead of stranding the client. A tool drops into Claude Code or Cursor and authorizes itself — nothing for the user to configure.

Highlights

  • Sole architect of a Gemini agent loop with iteration caps, Zod-parsed tool args, token accounting, and exponential-backoff retry.
  • Drove two transports from one registry of 18 Zod-typed tools — a /chat agent and a Streamable-HTTP MCP server — with zero per-transport duplication.
  • Shipped zero-config MCP auth: a device-authorization flow keyed by Mcp-Session-Id races a url-mode elicitation against a push approval, falling back to a clickable resource_link on -32602 rejection.
  • Built the candidate pipeline: 3 parallel Exa queries deduped by URL, one batched embedding call, idempotent pgvector upserts keyed by linkedin_url.
  • Hardened production by moving transcript analysis to OpenAI strict structured output — 165/165 server tests green.

Stack

TypeScriptHonoGemini (@google/genai)OpenAIElevenLabs ConvaiExaSupabase + pgvectorReact 19 + Vite