Featured

Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger
Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free
6,000+ web scrapers for your AI agent, start free logo6,000+ web scrapers for your AI agent, start free

Apify gives your agent live web data: 6,000+ prebuilt scrapers and actors, MCP-ready. Sign up free with $5 in usage credits.

Try Apify free
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free
Reach 48,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here

Works with

Claude CodeClaude DesktopCursorVS CodeClineCodex CLIOpenClaw+ any MCP client

Install to Claude Code

This server doesn't publish a one-line install command. Follow the setup in the source repository.

Summary

AI-powered lead qualification system with an MCP server for Claude Desktop, enabling campaign management, lead search, status updates, and CSV import.

README.md

Outreacher

An AI-powered lead qualification system with an MCP server for Claude Desktop and a Next.js SaaS frontend — built within 3 days.

All dev tooling runs via Docker. You do not need Go, Node, Bun, goose, or sqlc installed locally. Developers: see CLAUDE.md for commands, conventions, and test instructions.

[!TIP] This project demonstrates and acts as a foundation boilerplate for 2-mode operation of an AI MCP as: 1) Single-tenant Claude Desktop Go binary (individual use) 2) Multi-tenant Next.js SaaS + chat LLM + MCP Go server (hosted environment) The project architecture includes: AI SDK + assistant-ui chat Example MCP development Shared backend code for both binary and server operation Claude Code (and other development agent) usage and best practices Docker best practices for development and production Database security role/schema best practices (adopted early for scale)

📸 Demo & Walkthrough

See the full demo with screenshots and flows here: 👉 View Demo Docs

---

Architecture

Claude Desktop
  └── bin/outreacher-mcp-0.1.0-linux-amd64  (Go stdio binary, WSL)
        └── localhost:5432  (standalone postgres, volume: outreacher_standalone_data)

Browser / Next.js frontend
  └── app (Next.js, :3000)
        └── mcp (:3001, Go SSE server, air hot reload)
              └── postgres (internal only, volume: outreacher_postgres-data)

Two runtime modes — standalone binary for Claude Desktop, Docker Compose for development. Important: use separate named volumes for each mode to avoid data directory conflicts.

---

Tech Stack

  • Next.js 15 (App Router, Bun)
  • Go MCP server (mcp/) — stdio + SSE transports, pgx/v5, sqlc, goose migrations
  • PostgreSQL 16app schema, named Docker volume
  • Docker Compose — dev stack with air hot reload on the Go server

---

DB Users

| User | Password | Role | |---|---|---| | admin | admin | Owns schema, runs DDL and migrations | | app | app | Next.js runtime — member of app_crud + direct nextauth grants | | mcp | mcp | MCP server runtime — member of app_crud | | reporter | reporter | Read-only access — member of app_read |

Group roles (no LOGIN) — DEFAULT PRIVILEGES auto-cover new tables/sequences/types:

  • app_crud — SELECT/INSERT/UPDATE/DELETE on app schema
  • app_read — SELECT on app schema

DATABASE_URLmcp user (MCP server) or app user (Next.js). DATABASE_ADMIN_URLadmin user (goose only).

---

Schema (app)

Multi-tenancy

| Table | Key fields | |---|---| | organizations | id, name, slug (unique), is_system | | campaigns | id, organization_id, name, slug, is_default | | users | id, email†, slug (unique), name, is_system | | organization_memberships | organization_id, user_id, role (owner\|admin\|member) | | campaign_memberships | campaign_id, user_id, role (admin\|member\|viewer) |

Domain (scoped to campaign_id)

| Table | Key fields | |---|---| | companies | id, campaign_id, name, domain, industry, linkedin_url | | signals | id, description — global, no campaign scope | | signal_keywords | signal_id, keyword — global | | company_signals | company_id, signal_id | | leads | id, campaign_id, name, email†, linkedin_url†, company_id, title, status, score, location, phone | | notes | id, lead_id, content, created_at | | contact_identifiers | campaign_id, type, value — dedup key, PK is (campaign_id, type, value) |

† nullable. Leads are deduplicated by contact_identifiers, not by email.

Lead status flow: new → contacted → qualified → disqualified → converted

---

MCP Tools

Domain tools (all accept optional campaign_id; defaults to startup campaign)

| Tool | Description | |---|---| | search_leads | Filter by name, email, status, company, campaign_id | | get_lead | Full lead detail with company and notes | | update_lead_status | Advance a lead through the status flow | | create_followup_note | Append a note to a lead | | import_csv | Import from CSV text (auto-detects Gojiberry, Revli formats) | | search_companies | Search companies by name or domain | | get_company | Full company detail with signals |

Campaign management (stdio binary only)

| Tool | Description | |---|---| | list_campaigns | List all campaigns for the current org | | get_campaign | Get campaign details by id | | create_campaign | Create a new campaign under the current org | | rename_campaign | Rename a campaign's display name |

---

Mode 1 — Claude Desktop (Go binary via WSL)

Build the binary:

npm run build:mcp
# outputs bin/outreacher-mcp-0.1.0-linux-amd64   (stdio, WSL)
#         bin/outreacher-mcp-0.1.0-darwin-arm64   (stdio, macOS Apple Silicon)
#         bin/outreacher-mcp-0.1.0-darwin-amd64   (stdio, macOS Intel)
#         bin/outreacher-mcp-0.1.0-windows-amd64.exe
#         bin/outreacher-server-0.1.0             (SSE server)

Start standalone postgres:

docker run -d --name outreacher-pg --restart always \
  -p 5432:5432 \
  -e POSTGRES_DB=outreacher \
  -e POSTGRES_USER=admin \
  -e POSTGRES_PASSWORD=admin \
  -v outreacher_standalone_data:/var/lib/postgresql/data \
  -v "$(pwd)/postgres/init:/docker-entrypoint-initdb.d" \
  postgres:16-alpine

Run migrations:

PG_IP=$(docker inspect outreacher-pg --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
docker run --rm \
  -v "$(pwd)/mcp:/src" -w /src \
  --add-host=postgres:$PG_IP \
  golang:1.24-alpine \
  sh -c 'go run github.com/pressly/goose/v3/cmd/goose@latest \
    -dir migrations postgres \
    "postgresql://admin:admin@postgres:5432/outreacher" up'

Claude Desktop config (Settings → Developer → Edit Config):

{
  "mcpServers": {
    "Outreacher": {
      "command": "wsl.exe",
      "args": [
        "~/Code/outreacher/bin/outreacher-mcp-0.1.0-linux-amd64",
        "--database-url", "postgresql://mcp:mcp@localhost:5432/outreacher",
        "--openai-api-key", "sk-proj-..."
      ]
    }
  }
}

Replace <user> with your WSL username. ANTHROPIC_API_KEY enables LLM-based CSV extraction for unknown formats; omit to use the built-in parsers only. Restart Claude Desktop after saving — the hammer icon confirms tools are connected.

The binary idempotently bootstraps system_default_org, system_default_user, and the Default campaign on first run.

---

Mode 2 — Docker Compose (dev stack)

Copy .env.example to .env and fill in API keys, then:

docker compose up --build -d

| Service | Host port | Notes | |---|---|---| | app | 3000 | Next.js dev server | | mcp | 3001 | Go SSE server, air hot reload | | postgres | — | Internal only |

First-time migrations:

docker run --rm --network outreacher_default \
  -v "$(pwd)/mcp:/src" -w /src \
  golang:1.24-alpine \
  sh -c 'go run github.com/pressly/goose/v3/cmd/goose@latest \
    -dir migrations postgres \
    "postgresql://admin:admin@outreacher-postgres-1:5432/outreacher" up'

If the mcp container exited while waiting for migrations, restart it:

docker compose restart mcp

---

Imports

fixtures/imports/ is gitignored — it contains live personal data used for local development and debugging only. Supported formats: Gojiberry, Revli startup contacts, Revli investor contacts, Revli startup companies, Revli investor companies.

© Copyright

© 2026 Vitruvian Technology, Corp. All rights reserved.

This code is provided under a noncommercial license for evaluation and research purposes only.

See related servers & alternatives →

Related MCP servers

Browse all →

Related guides

Hand-picked reading to help you choose and use Search servers.