mcp server
eyes
Eyes: agents pay a nearby human a few dollars to check something in the physical world
Set up
Runs on your computer. Pick your agent and operating system.
This project does not publish an install method we can turn into a config. Follow the README instead.
README
synced Oct 26, 2026Your agent asks a question about a real place. A nearby person takes a live photo and answers it.
Site · Worker app · Connect · Deploy · Status
The kind of photo Eyes returns: is the cafe open right now? The sign says yes.
Agents can read the internet but cannot see the street. Eyes is an MCP server that lets an agent pay a nearby person about $3 to go and look. Built for YC's "Make Something Agents Want" hackathon (Oct 17-18, 2026) by Ayaan, Jerry and Shryuk.
Features
- MCP tools: 13 model-visible tools to quote, ask, wait, accept answers, review classifier refusals and manage tasks and money; plus app-only
confirm_ask. REST and non-UI automation retain direct dispatch. - ChatGPT and Claude apps: configured at the dedicated MCP host; OAuth Continue hands a new key to the client automatically. Saving it is optional for direct API use.
- iMessage dispatch: the 3 nearest workers get a text; first YES wins.
- Email channel: reply EMAIL in your existing Eyes iMessage conversation for a link to send your first email; offers, links and sign-in by email, with mobile still required.
- Photo checks: GPS within 150 m, taken live and narrowly moderated; no answer-correctness judgment.
- Escrow: bounty plus $0.50 fee held on ask; refunded if no answer.
- Prepaid balance:
get_balance.top_up_urlopens Stripe Checkout to add funds; payments are in test mode. - Safety: rules and an AI check refuse private-person, home, vehicle or face-targeted requests; this is separate from photo moderation and is not a blanket ban on faces in photos.
- Classifier review:
report_classifierandget_classifier_report; internal Approve/Reject controls, with approval allowing only an explicit retry of the same agent's exact request for 24 hours—not automatic dispatch or charging. - Owner controls: spend caps, allowed task types, key rotation.
- Worker location: HERE links, a Shortcut or the iPhone app.
- Ops dashboard: internal.eyes.pictures: tasks, money, reviews, tickets, live map.
Quick start
-
Get a key: no dashboard needed; the test balance is $20.
curl -X POST https://api.eyes.pictures/v1/signup \ -H "content-type: application/json" -d '{"name":"my-agent"}' -
Connect: from Claude Code (ChatGPT, claude.ai, Claude Desktop and Cursor are in docs/CONNECT.md):
claude mcp add --transport http eyes https://mcp.eyes.pictures/mcp \ --header "Authorization: Bearer $EYES_API_KEY" -
Ask:
claude -p 'Use quote_task to check the line at the Ferry Building, San Francisco'
Prefer the Manufact CLI? npx -y mcp-use@2.10.1 client connect eyes https://mcp.eyes.pictures/mcp --protocol legacy -H "Authorization: Bearer $EYES_API_KEY". To be a worker, open https://app.eyes.pictures on an iPhone. Until workers have opted in near a place, ask_eyes there returns no_workers_nearby and charges nothing. https://api.eyes.pictures/status says which parts are live.
MCP is live at https://mcp.eyes.pictures/mcp, with ChatGPT and Claude configured there. OAuth issuer and card origins match each host. REST signup, balance, uploads and webhooks stay at https://api.eyes.pictures; legacy api.eyes.pictures/mcp connectors remain supported. This does not mean every third-party connector has migrated. See OAuth setup.
Stripe's provider integration is live, but payments and the $20 signup credit are test-only: no real money moves. Marketplace version 1.0.3 is a configured draft with preflight complete, not submitted or published; legal owner attestations and test-mode limits remain. The new ChatGPT card protocol and live API are verified. Follow-up in-chat visual checks on the operator's test accounts were quota-blocked on 2026-10-18, not unavailable for all users; see STATUS.
How it works
In ChatGPT and Claude connectors, the model prepares a read-only draft and the user confirms in the card before Eyes sends or escrows anything. REST, CLI and non-UI MCP can dispatch directly. All dispatches call one EyesService, and each money move is one plpgsql function, so it runs in one transaction (ADR-003). The full flow is in docs/SPEC.md.
Photo moderation rejects only confirmed graphic gore or explicit sexual content. Uncertain content is allowed; provider failures fall back to Claude, and no valid provider verdict means manual review with escrow held. The agent decides whether the answer is correct.
sequenceDiagram
participant A as Agent (MCP / REST)
participant E as Eyes API (Manufact Cloud)
participant W as Worker iPhone (iMessage)
participant C as Capture page (app.eyes.pictures)
A->>E: quote_task, then ask_eyes
E->>E: safety check, escrow $3.50 (InsForge Postgres)
E->>W: offer text (Inkbox)
W->>E: YES (first YES wins)
E->>W: capture link
W->>C: live photo + GPS
C->>E: upload (InsForge storage)
E->>E: GPS, freshness, moderation (clef, Claude on provider failure)
A->>E: await_answer (long poll, 55 s per call)
E-->>A: answer, photo, checks
E->>W: $3 Stripe Connect transfer + paid text
Repository layout
apps/mcp/: API server: MCP tools, REST, webhooks, OAuth,/status.apps/edge/: Cloudflare Workers: thin API forwarder, cron, uptime monitor—not the MCP/API server host.apps/web/: landing site, worker app and the ops dashboard (internal.eyes.pictures).apps/mobile/: Expo iPhone app that sends background location.packages/: core, engine, db, comms, payments, safety, verify, ui.cli/: theeyesCLI and generated agent docs (llms-full.txt, OpenAPI).scripts/: live smoke, owner link, task resolve, migrations, intent check.evals/,e2e/: safety evals and the Playwright golden path.intent/: why each file exists (INDEX), ADRs, verdicts.
More docs
- Connect from ChatGPT, Claude, Claude Code and Cursor
- Deploy, live smoke, roll back, alerts
- Spec
- Status and live verification
- Plan
- Demo runbook
- Decisions (ADRs)
- Agent docs: llms.txt
- Report a bug
To develop locally you need Node 26, pnpm and Docker: pnpm install && pnpm verify:fast runs lint, typecheck, unit, contract, safety fixtures and the intent check without a database. pnpm db:up && pnpm db:migrate && pnpm test:integration adds Postgres, and pnpm test:e2e runs Playwright on fakes.
Built with
Every outside provider and service Eyes uses, and how. "Live" means the deployed server at api.eyes.pictures uses it today; "test" means it runs in a sandbox or test mode, so no real money moves.
| Provider | What Eyes uses it for | Where in the repo | Status |
|---|---|---|---|
| Manufact Cloud | Hosts the actual MCP/API server (eyes-prod), including REST, webhooks, OAuth and the ops dashboard; origin https://warm-spark-aocdd.run.mcp-use.com, public MCP https://mcp.eyes.pictures/mcp | apps/mcp, Dockerfile, docs/DEPLOY.md §2 | live |
| Cloudflare Workers | eyes-api is a thin forwarder for mcp.eyes.pictures, api.eyes.pictures and internal.eyes.pictures to Manufact; static Workers serve eyes.pictures and app.eyes.pictures | apps/edge/api, apps/web/landing, apps/web/worker | live |
| Manufact gateway (optional) | https://dark-steel-ofaoa.run.mcp-use.com/mcp proxies the public MCP endpoint for gateway analytics; this is separate from the Manufact server host | docs/CONNECT.md | optional |
| Cloudflare Containers + Durable Objects | Previous API hosting path; not the current production origin | apps/edge/api/worker.js | legacy |
| Cloudflare KV + Cron | eyes-monitor checks /healthz every minute, keeps state in KV, texts an alert after two failures | apps/edge/monitor | live |
| Cloudflare DNS | eyes.pictures zone and custom domains, including the dedicated MCP host | wrangler configs above | live |
Cloudflare Workers AI (clef-omni) | First-pass task safety classifier; photo moderation rejects only confirmed graphic gore or explicit sexual content | packages/safety, packages/verify | live |
| Cloudflare Browser Integrity rule | Zone security setting on the domains | Cloudflare dashboard only, not in the repo | live (not verifiable from the repo) |
| InsForge | Postgres with RPC functions and RLS for the ledger, claims and expiry; migrations through the migrations endpoint | packages/db, scripts/insforge-migrate.ts | live |
| InsForge Storage | Public photos bucket for captures; faces alone do not reject or delete photos (photo policy) | packages/db | live |
| InsForge Sites | Earlier host of the worker web (*.insforge.site); replaced by app.eyes.pictures | docs/DEPLOY.md §3 | earlier |
| Stripe | Checkout top-ups, Connect Express onboarding, $3 transfers on verified answers, transfer reversals on confirmed fraud, signed webhooks | packages/payments | test mode |
| Inkbox | Shared iMessage line: inbound webhook, offer and paid texts, START/STOP/HELP/HERE replies, texts with location codes and the app link; uptime alerts; first-contact owner/ops email fallback when Primitive refuses delivery | packages/comms/src/inkbox.ts | live |
| Inkbox (limitation) | An iMessage "Share My Location" arrives as a lone U+FFFD, so Eyes replies with a HERE link instead (ADR-037) | packages/comms | live |
| Primitive | Outbound DNS verified and one owner Gmail delivery confirmed; unrestricted sending is still off, first-contact fallback uses Inkbox, and external custom-alias SPF remains unresolved | packages/comms/src/primitive.ts | limited live verification |
| Anthropic Claude | Fallback for task-safety or photo provider failures only; used alone without Cloudflare | packages/safety, packages/verify | live |
| OpenStreetMap Nominatim | Geocodes place names in quote_task and ask_eyes | apps/mcp/src/geo.ts | live |
| OpenStreetMap tiles + Leaflet (unpkg) | Maps on the ops dashboard and live map | apps/web/dashboard | live |
| Apple Maps / Google Maps links | Reads coordinates from map links a worker texts in; the capture page links to Google Maps directions | packages/core/src/util.ts, apps/web/worker/src/capture.ts | live |
| mcp-use | MCP server framework for tools and widgets; Manufact CLI connect path on the landing page | apps/mcp, apps/web/landing | live |
| OpenAI Apps SDK / MCP Apps | ChatGPT app and Claude connector cards (quote, task, balance) with host-matched OAuth and card origins | apps/mcp, docs/CONNECT.md | supported |
| Expo / React Native + Apple | iPhone app with persistent connection across task photos; current distribution is ad hoc, not TestFlight | apps/mobile | ad hoc |
| ClickHouse | Optional copy of the ops event log and Trends charts; Postgres stays the source of truth | apps/web/dashboard/src/clickhouse.ts | optional, off on the host |
| Astro, Tailwind, GSAP | Landing and worker web; Better-T-Stack conventions | apps/web | live |
| Playwright, Vitest, Biome | E2E, unit/contract/safety/integration tests, lint and format | e2e, vitest.config.ts, biome.json | test |
| GitHub | Code, PRs, issues; Actions run CI, live smoke and the safety LLM eval | .github/workflows | live |
.env.example also lists keys for Armature analytics and Blaxel sandboxes; no code uses them yet.