GuidesAI Agent Integration

AI Agent Integration

Use FirstHandAPI as a tool in your AI agent workflows with the MCP server or SDK.

MCP Server

The FirstHandAPI MCP server lets AI agents (Claude Code, Cursor, etc.) post content collection jobs and retrieve files directly.

Installation

npm install @firsthandapi/mcp-server

Claude Code Configuration

Register the server with the claude mcp CLI:

claude mcp add firsthand \
  --env FIRSTHAND_API_KEY=fh_live_... \
  -- npx @firsthandapi/mcp-server

Or edit ~/.claude.json directly:

{
  "mcpServers": {
    "firsthand": {
      "command": "npx",
      "args": ["@firsthandapi/mcp-server"],
      "env": {
        "FIRSTHAND_API_KEY": "fh_live_..."
      }
    }
  }
}

Claude Desktop Configuration

Edit ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or %APPDATA%\Claude\claude_desktop_config.json on Windows:

{
  "mcpServers": {
    "firsthand": {
      "command": "npx",
      "args": ["@firsthandapi/mcp-server"],
      "env": {
        "FIRSTHAND_API_KEY": "fh_live_..."
      }
    }
  }
}

Restart Claude Desktop after editing.

Cursor Configuration

Add to Cursor’s settings (Settings → MCP Servers):

{
  "firsthand": {
    "command": "npx",
    "args": ["@firsthandapi/mcp-server"],
    "env": {
      "FIRSTHAND_API_KEY": "fh_live_..."
    }
  }
}

Available Tools

The server exposes 7 tools covering the complete job lifecycle:

ToolDescription
create_jobPost a content collection job. Required: type, description, files_needed, accepted_formats, price_per_file_cents. Optional: min_star_rating, location, files_per_submission, metadata. Returns {id, status, created_at}.
create_job_and_waitPost a job and block until completion. Accepts an extra max_wait_seconds (default 120, max 300). Returns the final job state plus timed_out_waiting if the deadline was hit. Best for single-shot agent workflows.
get_jobFetch current status + progress counters for a job by ID.
list_jobsBrowse recent jobs; supports status, limit, cursor filters.
cancel_jobCancel a pending job (only works if not yet fully in progress). Returns the cancelled job with cancelled_at.
get_job_filesRetrieve approved files for a completed job — includes pre-signed S3 URLs and AI-generated annotation metadata (object labels, OCR, scene, transcripts, keyframes).
get_creditsReturn the current organization credit balance in cents. Call before create_job to avoid insufficient_credits errors.

All tools auto-attach the configured API key and use idempotency keys on writes.

End-to-End Agent Pattern

A typical agent flow using create_job_and_wait:

User: "Find me 25 photos of residential mailboxes in Austin, TX"

Agent:
  1. get_credits               → balance = 15,000 ¢
  2. create_job_and_wait({
       type: "data_collection",
       description: "Clear photo of a residential mailbox, front view,
                     in daylight. House number should be visible.",
       files_needed: 25,
       accepted_formats: ["image/jpeg", "image/png"],
       price_per_file_cents: 50,
       location: { city: "Austin", state: "TX" },
       max_wait_seconds: 300
     })
     → returns {id: "job_01JQ...", status: "completed", files_approved: 25}
  3. get_job_files("job_01JQ...")
     → returns 25 files with download_url + annotations
  4. Agent uses annotations.text_extraction.full_text to extract house numbers
     and annotations.scene.setting to verify residential context.

For long-running jobs, call create_job (immediate return) and subscribe to the job.completed webhook instead of blocking with create_job_and_wait.

Error Handling

The server surfaces API errors as MCP tool errors with the original message. insufficient_credits (HTTP 402) gets extra actionable text suggesting get_credits + the dashboard link. Other errors pass through verbatim with the original request_id for support.

SDK Integration

For programmatic agent workflows, use the SDK:

const job = await client.createJob({
  type: 'data_collection',
  description: 'Clear product photos on white background...',
  files_needed: 20,
  accepted_formats: ['image/jpeg', 'image/png'],
  price_per_file_cents: 100,
});
 
// Wait for job completion
const completed = await client.getJob(job.id);
if (completed.status === 'completed') {
  const files = await client.getJobFiles(job.id);
  // Process files...
}

Webhook Integration

For event-driven workflows, subscribe to job and submission events:

// Wait for submission.approved events as files come in
const endpoint = await client.createWebhookEndpoint({
  url: 'https://your-agent.com/webhooks/firsthand',
  events: ['submission.approved', 'job.completed'],
});

The agent can process files incrementally as they are approved, rather than waiting for the entire job to complete.