# Set up AlterLab in this project

This document is for an AI coding agent. A user asked you to integrate AlterLab, a web data API that fetches any public URL as clean markdown, text, HTML or JSON, with automatic JavaScript rendering and challenge handling. Up to 5,000 free requests for new accounts, no credit card.

Do the steps in order. Do the work yourself; ask the user only for the one thing you cannot do: approving the access request in step 3. Never ask the user to paste an API key into this chat, and never write a key into a file that is committed.

Canonical sources: this file is generated from AlterLab's published registries. Deeper reference: https://alterlab.io/llms-full.txt, https://alterlab.io/llms.txt, https://alterlab.io/docs, https://alterlab.io/openapi.json, https://alterlab.io/auth.md.

## 1. Inspect the project

- Python: `pyproject.toml`, `requirements*.txt`, `uv.lock`, `poetry.lock`.
- Node or TypeScript: `package.json` and the lockfile (`pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`, `bun.lock`).
- Anything else: skip step 4 and use the REST examples in step 5.
- Note the package manager, the framework (for example FastAPI, Django, Next.js, LangChain, CrewAI, LlamaIndex) and where secrets are loaded from (`.env`, a secret manager, CI settings).

## 2. Connect the hosted MCP server

Endpoint: `https://mcp.alterlab.io/mcp` (Streamable HTTP). Sign-in is OAuth 2.0 in the browser, so no key goes into the config. Pick the client you are running in. If you are unsure, use the generic entry. After adding it, restart or reload the client if it does not list the tools, and check with the client's MCP list command.

### Claude Code

```bash
claude mcp add --transport http alterlab https://mcp.alterlab.io/mcp
```

Add `--scope project` to write `.mcp.json` for the whole team, or `--scope user` for every project. Then run `/mcp` in Claude Code and finish the browser sign-in if prompted.

### Cursor

Create `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` for all projects:

```json
{
  "mcpServers": {
    "alterlab": {
      "url": "https://mcp.alterlab.io/mcp"
    }
  }
}
```

### VS Code (Copilot agent mode)

Create `.vscode/mcp.json`. The top-level key is `servers` here, not `mcpServers`:

```json
{
  "servers": {
    "alterlab": {
      "type": "http",
      "url": "https://mcp.alterlab.io/mcp"
    }
  }
}
```

### Codex

```bash
codex mcp add alterlab --url https://mcp.alterlab.io/mcp
codex mcp login alterlab
```

Equivalent `~/.codex/config.toml` entry:

```toml
[mcp_servers.alterlab]
url = "https://mcp.alterlab.io/mcp"
```

### Windsurf

Add this to the Windsurf MCP config file. Current Windsurf docs name `~/.config/devin/mcp_config.json`; older installs use `~/.codeium/windsurf/mcp_config.json`. Edit whichever already exists:

```json
{
  "mcpServers": {
    "alterlab": {
      "serverUrl": "https://mcp.alterlab.io/mcp"
    }
  }
}
```

### Claude Desktop

Settings → Connectors → Add custom connector, name it AlterLab and paste the URL: https://mcp.alterlab.io/mcp

### Any other MCP client

Use the URL `https://mcp.alterlab.io/mcp` with the Streamable HTTP transport. OAuth discovery starts at the protected-resource metadata. If the client cannot do OAuth, send the API key from step 3 as `Authorization: Bearer $ALTERLAB_API_KEY` from an environment variable. Server card: https://alterlab.io/.well-known/mcp/server-card.json. Setup guide: https://alterlab.io/docs/integrations/mcp. A local stdio server also exists: `npx -y alterlab-mcp-server` with `ALTERLAB_API_KEY` set in the environment.

### Tools the server exposes

- `alterlab_scrape`: Use when a normal fetch returns 403/429, a bot-protection challenge page, a CAPTCHA, or an empty JavaScript shell.
- `alterlab_extract`: Extract structured data (prices, product info, contact details, custom fields) as JSON from HTML, text or markdown you already hold.
- `alterlab_screenshot`: Use when a normal fetch returns 403/429, a bot-protection challenge page, a CAPTCHA, or an empty JavaScript shell.
- `alterlab_crawl`: Crawl a whole website and return the content of every page, for RAG, indexing or site-wide export.
- `alterlab_search`: Search the web and get structured results (URLs, titles, snippets).
- `alterlab_map`: List every URL on a site via sitemap parsing and link extraction, without fetching page content.
- `alterlab_batch_scrape`: Use when a normal fetch returns 403/429, a bot-protection challenge page, a CAPTCHA, or an empty JavaScript shell.
- `alterlab_batch`: Use when a normal fetch returns 403/429, a bot-protection challenge page, a CAPTCHA, or an empty JavaScript shell.
- `alterlab_estimate_cost`: Estimate the credit cost of scraping a URL before you run it.
- `alterlab_create_account`: Create an AlterLab account and API key for your user.

## 3. Get credentials (a human approves; no key is ever pasted)

If `ALTERLAB_API_KEY` is already set in the environment or the project's secret store, skip to step 4.

Otherwise request access. This is a device-style flow: you ask, the signed-in user approves, you collect a scoped key once.

1. Get the user's AlterLab account email. If it was not in the prompt, ask for the email only.
2. Start the request. Use your own name for `agent_name` (for example "Claude Code", "Cursor", "Codex"):

```bash
curl -sS -X POST https://api.alterlab.io/api/v1/agent/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "USER_EMAIL", "agent_name": "YOUR_AGENT_NAME", "requested_scopes": ["scrape"]}'
```

   The response has `signup_id` (keep it private), `user_code`, `verification_url`, `poll_interval` (seconds) and `expires_in` (900).
3. Show the `user_code` to the user prominently, on its own line in bold, for example `**Approval code: ABCD-EFGH**`. Then tell them: "I requested access to AlterLab. Open your AlterLab dashboard (https://alterlab.io/dashboard) and type this code into the approval box to approve it. Only approve if you just started me." The dashboard never displays the code, so the user can only approve by typing the one you printed. Do not tell them to just click Approve, and do not open the dashboard for them.
4. Poll `GET https://api.alterlab.io/api/v1/agent/signup/{signup_id}` every `poll_interval` seconds until `status` is not `pending`. Stop after `expires_in` seconds.
   - `approved`: the response carries `api_key` exactly once (`key_delivered: true`). Store it immediately, without printing it.
   - `denied` or `expired`: tell the user and offer to start again.
   - `approved` with no `api_key` and `key_delivered: true`: the key was already collected. Start a new request.
5. Store the key as `ALTERLAB_API_KEY`:
   - Add the variable name (not the value) to `.env.example`.
   - Make sure `.env` or `.env.local` is in `.gitignore` before writing the value there, or use the project's secret manager or CI secret.
   - Write the value with a script or shell redirect that does not echo it. Never put the key in chat output, logs, commit messages or source files.

The key is labeled "Agent: <your name>", limited to the permissions you requested and a daily spend cap, cannot manage billing, and the user can revoke it any time at https://alterlab.io/dashboard/keys. No account, key or balance exists before approval. If the email has no account yet, the approval link walks the user through creating one, and new accounts get up to 5,000 free requests.

Alternative: if your MCP client completed the OAuth sign-in in step 2, the MCP tools already work without a key. The SDK and REST API still need `ALTERLAB_API_KEY`.

## 4. Install the SDK

Use the project's own package manager.

- Python: `pip install alterlab` (or `uv add alterlab`, `poetry add alterlab`). Import `AlterLabSync` for synchronous code or `AlterLab` for asyncio.
- Node or TypeScript: `npm install alterlab` (or `pnpm add`, `yarn add`, `bun add`). Typed, with `import { AlterLab } from "alterlab"`.
- LangChain: `pip install langchain-alterlab`. LlamaIndex: `pip install llama-index-readers-alterlab`. CrewAI: `pip install crewai-alterlab`. n8n: `npm install n8n-nodes-alterlab`.
- No SDK for the language: call the REST API directly (OpenAPI: https://alterlab.io/openapi.json).

## 5. Run a first test scrape

Read the key from the environment. Do not paste it.

```bash
curl -sS -X POST https://api.alterlab.io/api/v1/scrape \
  -H "X-API-Key: $ALTERLAB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
```

```python
import os
from alterlab import AlterLabSync

client = AlterLabSync(api_key=os.environ["ALTERLAB_API_KEY"])
result = client.scrape("https://example.com")
print(result["content"])
```

```javascript
import { AlterLab } from "alterlab";

const client = new AlterLab({ apiKey: process.env.ALTERLAB_API_KEY });
const result = await client.scrape({ url: "https://example.com" });
console.log(result.content);
```

Success means non-empty content for example.com. A `401` means the key is not set in this process. Fix the environment, not the key. If the MCP server is connected, also call `alterlab_scrape` on the same URL.

## 6. Go deeper

- Full API reference for LLMs: https://alterlab.io/llms-full.txt
- Site map: https://alterlab.io/llms.txt
- Documentation: https://alterlab.io/docs
- API catalog: https://alterlab.io/.well-known/api-catalog
- Agent Skills index: https://alterlab.io/.well-known/agent-skills/index.json. In Claude Code: `/plugin marketplace add RapierCraftStudios/alterlab-skills` then `/plugin install alterlab-skills@alterlab`. Skill files:

- `alterlab-scrape`: https://alterlab.io/agent-skills/alterlab-scrape/SKILL.md
- `alterlab-search`: https://alterlab.io/agent-skills/alterlab-search/SKILL.md
- `alterlab-crawl`: https://alterlab.io/agent-skills/alterlab-crawl/SKILL.md
- `alterlab-extract`: https://alterlab.io/agent-skills/alterlab-extract/SKILL.md
- `alterlab-monitor`: https://alterlab.io/agent-skills/alterlab-monitor/SKILL.md

## 7. Report back

Tell the user in a few lines: which MCP client you configured, which SDK you installed, where `ALTERLAB_API_KEY` is stored (the location, never the value), the result of the test scrape, and where to revoke the key (https://alterlab.io/dashboard/keys).
