mcpField
C
CanYouGrab.it

CanYouGrab.it

远程服务
github.com/einiba开发工具14 周前更新
代码仓库

关于 CanYouGrab.it

CanYouGrab.it 是一个通过 DNS 检查域名可用性的 API,并返回可用、不可用或结果不确定的状态。它面向需要查询域名的 API 使用者,同时提供账户用量、配额和密钥管理。

主要功能

  1. 01单次批量检查最多 100 个域名
  2. 02基于 DNS 返回可用性结果
  3. 03跟踪每分钟和每月配额
  4. 04创建、轮换和撤销 API 密钥
  5. 05账户用量摘要

适用场景

  1. 01在一次请求中检查多个域名
  2. 02在应用中集成域名查询
  3. 03监控 API 配额与用量
  4. 04管理 API 使用者的凭据

MCP 相关

README 提到了 MCP 服务及其运行时,但未说明面向客户端提供的工具或功能。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://api.canyougrab.it/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
pypimcp-server-canyougrab1.1.1

工具

3
参数类型必填说明
domainsarray是

详细介绍

CanYouGrab API

域名可用性查询 API,采用 FastAPI + DNS(Unbound resolver)构建,支持订阅计费。

在线服务:

  • API:https://api.canyougrab.it
  • 开发者门户:https://portal.canyougrab.it
  • 认证:https://auth.canyougrab.it(Auth0 自定义域名)

架构概览

┌──────────────────────────────────────────────────────────────────┐
│                        Developer Portal                          │
│              (Zudoku/React on portal.canyougrab.it)              │
│   Usage Dashboard · API Keys · Pricing · API Reference (OAS)    │
└──────────────────┬───────────────────────────────────────────────┘
                   │  Auth0 JWT (portal)  /  Bearer API key (API)
                   ▼
┌──────────────────────────────────────────────────────────────────┐
│                    FastAPI Backend (v5.0.0)                       │
│                    api.canyougrab.it:8000                         │
│                                                                  │
│  ┌─────────────┐  ┌──────────┐  ┌──────────┐  ┌─────────────┐  │
│  │ app.py      │  │ keys.py  │  │billing.py│  │ auth.py     │  │
│  │ /check/bulk │  │ /keys    │  │/billing  │  │ API key +   │  │
│  │ /usage      │  │ CRUD     │  │/stripe   │  │ JWT auth    │  │
│  │             │  │ rotate   │  │ webhook  │  │             │  │
│  └──────┬──────┘  └──────────┘  └────┬─────┘  └─────────────┘  │
│         │                            │                           │
└─────────┼────────────────────────────┼───────────────────────────┘
          │                            │
          ▼                            ▼
┌─────────────────┐          ┌─────────────────┐
│  Valkey (Redis)  │          │   Stripe API     │
│  Job queue +     │          │   Subscriptions   │
│  Rate limiting   │          │   Webhooks        │
└────────┬────────┘          └─────────────────┘
         │
         ▼
┌─────────────────┐          ┌──────────────────────────────┐
│  RQ Worker       │──DNS──▶ │   Unbound Resolver            │
│  (worker.py)     │          │   (dedicated droplet)         │
│  ThreadPool(10)  │          │   NS queries via VPC          │
│  via RQ queue    │          └──────────────────────────────┘
└─────────────────┘
                             ┌──────────────────────────────┐
         ───────────────────▶│   PostgreSQL                  │
          (auth, usage,      │   API keys + Usage logs       │
           billing only)     └──────────────────────────────┘

目录结构

zuplo/
├── backend/                    # Python FastAPI backend
│   ├── app.py                  # Main API: /check/bulk, /usage, /health
│   ├── auth.py                 # API key auth (SHA-256) + Auth0 JWT auth (RS256)
│   ├── billing.py              # Stripe checkout, portal, webhooks, card-on-file, usage details
│   ├── keys.py                 # API key CRUD: create, list, rotate, revoke (+ Turnstile)
│   ├── antifraud.py            # Anti-fraud: Turnstile, device fingerprints, risk scoring
│   ├── email_utils.py          # Email normalization + disposable email detection
│   ├── dns_client.py           # DNS-based domain availability checking via Unbound
│   ├── queries.py              # PostgreSQL queries: usage tracking, auth, billing
│   ├── valkey_client.py        # Redis/Valkey job queue client (RQ-backed)
│   ├── rq_tasks.py             # RQ task function: process_domain_job()
│   ├── worker.py               # RQ worker process (ThreadPoolExecutor per job)
│   ├── migrations/             # SQL migrations
│   │   └── 001_free_tier_antifraud.sql
│   └── requirements.txt        # Python dependencies
├── portal/                     # Developer portal (Zuplo + Zudoku)
│   ├── config/
│   │   ├── routes.oas.json     # OpenAPI 3.1 spec (public API documentation)
│   │   └── policies.json       # Zuplo policies (empty — all routing is direct)
│   ├── docs/                   # Zudoku documentation portal
│   │   ├── src/
│   │   │   ├── config.ts       # API_BASE, Turnstile site key, Stripe PK
│   │   │   ├── UsageDashboard.tsx   # Usage + billing dashboard component
│   │   │   ├── PricingPage.tsx      # Plan selection + Stripe checkout
│   │   │   ├── PricingPlans.tsx     # Pricing card grid component
│   │   │   └── CardSetupPage.tsx    # Stripe Elements card-on-file for Free+
│   │   ├── public/             # Static assets (logos, banners, CSS overrides)
│   │   ├── zudoku.config.tsx   # Portal config: theme, nav, Auth0, API key mgmt
│   │   └── package.json        # Frontend dependencies (React 19, Zudoku)
│   ├── package.json            # Workspace root (Zuplo v6, TypeScript v5)
│   └── README.md               # Zuplo boilerplate (not project-specific)
├── mcp-server/                 # MCP package for ChatGPT, Claude, and remote MCP clients
│   ├── pyproject.toml          # MCP package metadata + version
│   ├── server.json             # MCP registry/server metadata
│   ├── uv.lock                 # Locked MCP runtime dependencies
│   └── src/canyougrab_mcp/
│       ├── __init__.py
│       └── server.py           # stdio + streamable-http MCP entrypoint
├── .github/workflows/
│   ├── deploy.yml              # Production deploy (on tag push v*)
│   └── deploy-dev.yml          # Dev deploy (on push to dev branch)
├── .claude/
│   └── launch.json             # Local dev server config (port 9200)
└── package.json                # Root workspace config

API 端点

公共 API(API 密钥认证:Authorization: Bearer cyg_...)
方法路径描述
POST/api/check/bulk检查最多 100 个域名。长轮询直至结果就绪(最长 30 秒)。
GET/api/account/usage已认证消费者的用量摘要。
GET/api/account/quota-check轻量级月度 + 每分钟配额检查。
GET/health健康检查(无需认证)。
门户 API(Auth0 JWT 认证)
方法路径描述
POST/api/keys创建新的 API 密钥。
GET/api/keys列出用户的 API 密钥。
POST/api/keys/{id}/rotate轮换密钥(撤销旧密钥并创建新密钥)。
DELETE/api/keys/{id}撤销(软删除)密钥。
POST/api/billing/checkout创建 Stripe Checkout 会话。
POST/api/billing/portal创建 Stripe Customer Portal 会话。
POST/api/billing/setup-card为 Free+ 创建 SetupIntent,以便保存银行卡。
POST/api/billing/confirm-free-plus验证银行卡指纹并升级到 Free+。
GET/api/billing/card-status检查用户是否已保存银行卡。
GET/api/billing/usage/detailed门户控制面板的逐密钥用量明细。
POST/api/antifraud/turnstile/verify验证 Cloudflare Turnstile 令牌。
POST/api/antifraud/device/register注册设备指纹(Fingerprint Pro)。
GET/api/antifraud/risk获取已认证用户的风险评估。
POST/api/antifraud/assess-signup在注册时运行多信号风险评估。
内部 / Webhook
方法路径描述
POST/api/account/usage/detailed多消费者用量明细。
POST/api/stripe/webhookStripe webhook 接收端(已验证签名)。

核心请求流程

域名可用性检查
Client                    FastAPI                     Valkey                      Worker              Unbound
  │                          │                          │                          │                    │
  │  POST /api/check/bulk    │                          │                          │                    │
  │  { domains: [...] }      │                          │                          │                    │
  │─────────────────────────▶│                          │                          │                    │
  │                          │── validate key ──────────│                          │                    │
  │                          │── check minute rate ────▶│ INCR ratelimit:id:min   │                    │
  │                          │── check monthly quota ──▶│ (PostgreSQL)             │                    │
  │                          │── record usage ─────────▶│ (PostgreSQL)             │                    │
  │                          │── create_job() ─────────▶│ HSET job:{uuid}          │                    │
  │                          │                          │ RQ enqueue (with retry)   │                    │
  │                          │                          │                          │                    │
  │                          │                          │◀── RQ Worker dequeues ───│                    │
  │                          │                          │                          │                    │
  │                          │                          │──── claim_job() ────────▶│                    │
  │                          │                          │                          │── ThreadPool(10)   │
  │                          │                          │                          │── check_domain_dns()
  │                          │                          │                          │── NS query ───────▶│
  │                          │                          │                          │◀── NOERROR/NXDOMAIN│
  │                          │                          │◀── complete_job() ───────│                    │
  │                          │                          │                          │                    │
  │                          │◀─ poll get_job_status() ─│                          │                    │
  │                          │   (0.3s interval, 30s    │                          │                    │
  │                          │    max timeout)          │                          │                    │
  │◀─────────────────────────│                          │                          │                    │
  │  { results: [...] }      │                          │                          │                    │
计费 / 订阅流程
User → Pricing Page → Select Plan → Auth0 login
  → POST /api/billing/checkout (JWT auth)
  → Find/create Stripe customer (linked by auth0_sub metadata)
  → Stripe Checkout Session created → redirect to Stripe
  → User pays → Stripe fires webhook
  → POST /api/stripe/webhook (HMAC-SHA256 verified)
  → checkout.session.completed → fetch subscription → get price ID
  → Map price to plan → UPDATE api_keys SET plan, lookups_limit

订阅方案

方案每月查询次数每分钟速率限制每次请求的域名数价格
Free50030/min30$0
Free+10,000100/min100$0(已保存银行卡)
Basic20,000300/min100$10/mo
Pro50,0001,000/min100$20/mo
Business300,0003,000/min100$30/mo

认证

API 密钥认证(公共 API 消费者)
  • 格式:Authorization: Bearer cyg_<token>
  • api_keys 表中存储的是经过 SHA-256 哈希处理的密钥(从不存储明文)
  • 门户中会显示密钥前缀(cyg_XXXXXXXX...)
  • 创建时仅返回一次完整密钥
  • 撤销时采用软删除(记录 revoked_at 时间戳,不会物理删除)
JWT 认证(门户 / 控制面板)
  • Auth0 租户:dev-mqe5tavp6dr62e7u
  • 自定义域名:auth.canyougrab.it
  • 算法:RS256,使用 JWKS 验证(缓存 1 小时)
  • 受众:https://api.canyougrab.it
  • 社交登录:Google、Apple(使用 Apple 登录)

通过 DNS 检查域名是否可用

域名可用性通过查询运行在独立 DigitalOcean Droplet 上的专用 Unbound 递归 DNS 解析器进行检查。工作进程通过 VPC 私有网络发送 NS 记录查询,并解读响应:

DNS 响应available含义
NOERROR + NS 记录false域名已注册并已委派
NXDOMAINtrue域名不在区域中——可能可用
NoAnswer(NOERROR,无 NS)false已注册,但处于停放状态/未委派
SERVFAIL / Timeoutnull情况不明——检查失败

Unbound 解析器会积极缓存(已注册域名缓存 7 天,NXDOMAIN 缓存 5 分钟),并直接查询 TLD 权威服务器,以避免公共解析器的速率限制。

数据库架构

使用 PostgreSQL 进行身份验证、用量跟踪和计费,而非域名查询。

PostgreSQL 表
表用途关键列
api_keys用户 API 密钥id、user_sub、email_normalized、key_hash、key_prefix、plan、lookups_limit、revoked_at
usage_log_daily每日用量汇总consumer、lookups、recorded_at(DATE,每个 consumer+日期 唯一)
usage_log_minute每分钟用量汇总consumer、lookups、minute_start(TIMESTAMP,每个 consumer+分钟 唯一)
card_fingerprints每张卡只允许一个免费账户user_sub、stripe_fingerprint(唯一组合)
device_fingerprints基于设备的多账户检测user_sub、visitor_id(Fingerprint Pro)
account_risk综合风险评分user_sub(唯一)、risk_score、risk_signals(JSONB)
Valkey(Redis)数据结构
键模式类型用途TTL
job:{uuid}Hash作业状态、域名、结果1 小时
rq:queue:canyougrab-jobsListRQ 作业队列(由 RQ 管理)—
rq:job:{uuid}HashRQ 作业元数据(重试次数、状态)可配置
ratelimit:{consumer}:{YYYYMMDDHHmm}String每分钟速率限制计数器(INCR)60s

基础设施

服务器
环境域名用途
生产环境api.canyougrab.itFastAPI + Worker
开发环境dev.canyougrab.itFastAPI + Worker
门户portal.canyougrab.itZudoku 静态站点
身份验证auth.canyougrab.itAuth0 自定义域名
外部服务
服务用途
DigitalOceanDroplet(API 服务器、Unbound 解析器)、托管 PostgreSQL、托管 Valkey
Cloudflarecanyougrab.it 区域的 DNS、CDN、SSL,Turnstile 机器人防护
Auth0用户身份验证、社交登录(Google + Apple)、签发 JWT
Stripe订阅计费、结账、客户门户、Webhook
GitHub ActionsCI/CD 部署流水线

部署流水线

生产环境部署

**触发条件:**推送匹配 v* 的 git 标签(例如 v1.0.5)

git tag v1.0.5 && git push origin v1.0.5

流水线(.github/workflows/deploy.yml):

  1. GitHub Actions 在推送 v* 标签时触发
  2. 使用 DEPLOY_SSH_KEY 通过 SSH 登录生产服务器(DEPLOY_HOST 密钥)
  3. 在服务器上检出目标引用(git fetch + git checkout <tag>)
  4. 运行仓库管理的部署脚本:/opt/canyougrab-repo/scripts/deploy-host.sh
开发环境部署

**触发条件:**推送到 dev 分支

git push origin dev

流水线(.github/workflows/deploy-dev.yml):

  1. GitHub Actions 在推送到 dev 时触发
  2. 使用相同的 DEPLOY_SSH_KEY 通过 SSH 登录开发服务器(DEV_DEPLOY_HOST 密钥)
  3. 在服务器上检出 dev 引用(git fetch + git checkout dev)
  4. 运行仓库管理的部署脚本:/opt/canyougrab-repo/scripts/deploy-host.sh
由仓库管理的主机部署脚本

两个流水线都会使用简短的内联 SSH 引导脚本,将 /opt/canyougrab-repo 更新到目标引用,然后调用该检出版本中的 scripts/deploy-host.sh。由仓库管理的部署脚本负责:

  • 使用 pip install -r requirements.txt 安装后端依赖
  • 将后端、门户和 MCP 源代码目录 rsync 到各自的运行时目录
  • 如果主机同时运行 canyougrab-mcp.service,则重新安装或刷新 mcp-server 软件包/运行时
  • 通过 systemd 重启 FastAPI(uvicorn)、工作进程和 MCP 服务

如果 /mcp 与 API 部署在同一台主机上,仅部署后端是不够的。MCP 服务必须在同一次部署中更新并重启,否则 OAuth 元数据和实际运行的 MCP 行为可能会不一致。

如果需要,仍可保留现有的 /opt/deploy.sh,作为手动兼容垫片;但自动化流水线应以仓库中的 scripts/deploy-host.sh 为唯一可信来源。

分支策略
分支用途部署到
main生产版本发布打标签后 → api.canyougrab.it
dev开发/预发布自动 → dev.canyougrab.it
功能分支正在进行的工作不自动部署

环境变量

后端(服务器上必需)
# DNS Resolver (Unbound on dedicated droplet)
DNS_RESOLVER_HOSTNAME=unbound.canyougrab.internal  # VPC internal hostname (resolved via socket.gethostbyname)
DNS_RESOLVER_PORT=53
DNS_QUERY_TIMEOUT=5.0  # Per-query timeout in seconds

# PostgreSQL (DigitalOcean Managed Database — auth, usage, billing only)
POSTGRES_HOST=         # DB cluster hostname
POSTGRES_PORT=5432
POSTGRES_DB=canyougrab
POSTGRES_USER=canyougrab
POSTGRES_PASSWORD=     # DB password
POSTGRES_SSLMODE=require

# Valkey / Redis (DigitalOcean Managed Database)
VALKEY_HOST=           # Valkey cluster hostname
VALKEY_PORT=25061
VALKEY_USERNAME=default
VALKEY_PASSWORD=       # Valkey password

# Auth0
AUTH0_DOMAIN=dev-mqe5tavp6dr62e7u.us.auth0.com
AUTH0_AUDIENCE=https://api.canyougrab.it

# Stripe
STRIPE_SECRET_KEY=     # sk_live_... (prod) or sk_test_... (dev)
STRIPE_WEBHOOK_SECRET= # whsec_... (per-environment)
STRIPE_PRICE_BASIC=    # price_... (live price ID for Basic plan)
STRIPE_PRICE_PRO=      # price_... (live price ID for Pro plan)
STRIPE_PRICE_BUSINESS= # price_... (live price ID for Business plan)

# Cloudflare Turnstile (bot prevention on key creation)
TURNSTILE_SECRET_KEY=  # 0x4AAAA... (from Cloudflare dashboard)

# Portal
PORTAL_URL=https://portal.canyougrab.it

# Worker
BATCH_CONCURRENCY=10   # Thread pool size for domain checks
VALKEY_QUEUE_NAME=canyougrab-jobs  # RQ queue name (default: canyougrab-jobs)

# Monitoring (optional — only if monitoring stack is installed)
SLACK_ALERTS_WEBHOOK_URL=  # Slack incoming webhook for Alertmanager
RQ_METRICS_PORT=9122       # Prometheus metrics exporter port

# Auto-scaler (optional — only on API host with autoscaler enabled)
DO_API_TOKEN=              # DigitalOcean API token
DO_WORKER_SNAPSHOT_ID=     # Snapshot ID for new worker droplets
AUTOSCALER_MIN_WORKERS=1
AUTOSCALER_MAX_WORKERS=5
AUTOSCALER_SCALE_UP_THRESHOLD=50
AUTOSCALER_SCALE_DOWN_IDLE_MINUTES=10
GitHub Actions 密钥
密钥用途
DEPLOY_HOST生产服务器 IP
DEV_DEPLOY_HOST开发服务器 IP
DEPLOY_SSH_KEY两台服务器共用的 SSH 私钥

本地开发

后端
cd backend
pip install -r requirements.txt

# Start API server
uvicorn app:app --reload --port 8000

# Start worker (separate terminal)
python worker.py

需要将 DNS_RESOLVER_HOST 指向一个 Unbound 实例(或使用 8.8.8.8 进行基本测试),还需要 PostgreSQL 和 Valkey/Redis(本地运行或通过隧道连接到托管实例)。

门户
cd portal/docs
npm install
npm run dev          # Starts Zudoku dev server (via zuplo)

或者使用已配置的启动服务器:

# From repo root
npx zuplo dev        # Starts on port 9200

门户开发服务器在 portal/docs/src/config.ts 中将 API_BASE 硬编码为 https://api.canyougrab.it。若要使用本地后端进行开发,请将其改为 http://localhost:8000。

SEO:.it 顶级域名的地理定位要求

由于 canyougrab.it 使用 .it 国家/地区代码顶级域名(意大利),所有面向用户的 HTML 页面(门户、文档)都必须包含表明内容面向英语用户的信号:

  1. 每个页面都必须包含 <html lang="en">。
  2. 在 <head> 中添加 Hreflang 标签:
    <link rel="alternate" hreflang="en-US" href="{page_url}" />
    <link rel="alternate" hreflang="en" href="{page_url}" />
    <link rel="alternate" hreflang="x-default" href="{page_url}" />
    
  3. 规范链接标签 — 指向自身的 <link rel="canonical" href="{page_url}" />。
  4. 所有内容均使用英语 — 任何页面上都不得出现意大利语文本。

这适用于门户(portal.canyougrab.it)、API 文档以及任何其他公开呈现的 HTML 页面。

关键设计决策

  • 实时 DNS 查询:通过向专用的 Unbound 递归解析器发送 NS 查询来检查域名是否可用。这样可以获取实时结果(没有 24 小时的区域文件延迟),自动适用于任何 TLD,并避免每日批量加载区域文件所带来的运维复杂性。Unbound 会积极缓存(已注册域名缓存 7 天),因此重复查询耗时约为 1 ms。
  • 可空的可用性状态:DNS 的故障模式比数据库查询更多。当 Unbound 返回 SERVFAIL 或超时时,API 会返回 available: null,而不是可能造成危险的误报。使用方应将 null 视为“无法确定”。
  • 批量检查使用作业队列:批量端点使用由 Valkey 提供支持的 RQ(Redis Queue)来分发作业,并支持自动重试(重试 2 次,退避间隔为 5 秒/30 秒)和失败作业跟踪。工作进程会通过线程池并行执行 DNS 查询。
  • 长轮询:批量检查端点会保持 HTTP 连接打开(每 0.3 秒轮询一次 Valkey,最长 45 秒),而不是要求客户端自行实现轮询。作业结果存储在自定义的 Valkey 哈希中(而非 RQ 内置的结果存储),因此轮询逻辑独立于队列框架。
  • 使用 SHA-256 哈希处理 API 密钥:密钥在存储前会先进行哈希处理(与密码类似),因此即使数据库泄露,原始密钥也不会暴露。
  • 通过 Stripe 元数据建立关联:通过 Stripe 客户对象上的 auth0_sub 元数据,将 Stripe 客户与 Auth0 用户关联起来,无需单独的映射表。
  • 双重跟踪用量:同时记录每日(usage_log_daily)和每分钟(usage_log_minute)用量,分别用于月度配额和每分钟速率限制。
  • 不使用 Zuplo 网关策略:项目最初使用 Zuplo 作为 API 网关,后迁移至直接使用 FastAPI(提交 3abef70)。开发者门户仍使用 Zuplo 门户/文档框架。

服务上的进程

核心服务(每台主机)
  1. FastAPI(uvicorn):在端口 8000 上提供所有 HTTP 端点
  2. RQ Worker(worker.py):处理 RQ 队列中的域名检查作业
  3. MCP 服务(如果此服务器托管 /mcp):为远程 MCP 客户端提供服务
监控堆栈(API 主机,可选)
  1. Prometheus(localhost:9090):抓取指标并评估告警规则
  2. Alertmanager(localhost:9093):将告警路由到 Slack
  3. redis_exporter(localhost:9121):将 Valkey 指标导出到 Prometheus
  4. RQ 指标导出器(localhost:9122):导出队列深度、工作进程数量和失败作业
  5. Grafana(localhost:3000,由 nginx 代理):用于查看队列运行状况的仪表板
  6. 自动扩缩容器(可选):通过 DO API 扩缩 Worker Droplet

使用以下命令安装监控堆栈:sudo bash scripts/setup-monitoring.sh

主机上的所有活动服务都必须通过 systemd 管理,并在部署期间重启。 所有自动化部署都应通过 scripts/deploy-host.sh 执行;该脚本负责重启主机上已安装的上述服务。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。