← all work
VOICE AIApr–May 2026

Mirarsan agent that runs the whole study

An AI agent that sources candidates, runs voice interviews, and writes the study report from one chat.

18
tools, 2 transports
165/165
server tests
34/37
commits, sole author
3 wk
build

Mirars is a research agent that runs an entire study end to end: it sources candidates, emails invitations, conducts voice interviews, and writes the report. I was sole architect — 34 of 37 commits over three weeks — and built 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 powers two transports: the /chat agent and a Streamable-HTTP MCP server. Adding a tool is one file plus one registry line, with zero per-transport duplication. The candidate pipeline runs 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. After recurring 503s and JSON-shape drift in production, I migrated transcript analysis off Gemini 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 signal, and detects a -32602 rejection to fall back to a clickable resource_link instead of stranding the client. The result: a tool installs into Claude Code or Cursor and authorizes itself with nothing for the user to configure.

Highlights

  • Wrote 34 of 37 commits as sole architect, shipping a Gemini agent loop with iteration caps, Zod-parsed tool args, token accounting, and backoff retry.
  • Built one registry of 18 Zod-typed tools driving two transports — 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, and idempotent pgvector upserts keyed by linkedin_url.
  • Hardened production by moving transcript analysis to OpenAI strict structured output (165/165 server tests passing).

Stack

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