# Set up Magpie (for AI agents)

You were asked to set up Magpie: Southeast Asian ecommerce data (Shopee,
Tokopedia, TikTok Shop, Lazada, Blibli; live Amazon pages) for this user. Follow
these steps in order. Tell the user briefly what you are doing at each step.

**Rules for the whole setup**
- Never ask the user for an API key, never ask them to paste one into this
  conversation, and never print one. Sign-in always happens in the user's browser.
- Do not install anything other than what a step below says.
- If a step fails, say what failed and continue with the next step that does not
  depend on it.

## Step 1 — Where are you running?

- **A chat app without a terminal (Claude.ai, ChatGPT, Claude desktop chat):**
  you cannot change your own settings. Tell the user exactly this, then stop:

  > Add Magpie as a connector: open Settings → Connectors (ChatGPT: Settings →
  > Apps & Connectors → Developer mode → Create), add the URL
  > `https://mcp-staging.magpieiq.com/v2/mcp`, choose OAuth if asked, click Connect and sign
  > in. Then ask me a question such as "who leads Facial Serum on Shopee
  > Indonesia?"

- **A coding agent with a shell (Claude Code, Cursor, Codex, opencode, …):**
  continue with Step 2.

## Step 2 — Sign in once

One sign-in gives a key that both your Magpie tools and the Magpie CLI use. The
key is saved to `~/.magpie/credentials` (owner-only) and is never shown in chat.

**Ask the user one question:** "Sign in with your browser (Google, Microsoft or
email link — one click if you're already signed in to Google) or by email?"
Recommend the browser when you run on the user's own computer, and email when
you run on a remote machine, container or SSH session. Never ask for a key.

Sign-in runs as **two separate commands**, so you can show the user the code
before anything waits. Shells often only hand you a command's output once it
exits, so a single command that prints the code and then waits would hide the
code until the user had already approved — and the code is the user's only way
to tell that the request is yours.

**1. Start.** If `python3` works, run this. Set `EMAIL` to the user's address
for email sign-in, or leave it empty for the browser. It prints the code (and the
link for browser sign-in) and exits immediately:

```python
import json, os, socket, sys, time, urllib.error, urllib.parse, urllib.request
BASE = "https://api-staging.magpieiq.com"
EMAIL = ""            # the user's email for email sign-in; empty = browser
CLIENT = "AI agent"   # your name, e.g. "Claude Code"

req = urllib.request.Request(BASE + "/data/v1/device/code", data=urllib.parse.urlencode(
    dict({"client_name": CLIENT, "host_label": socket.gethostname()}, **({"email": EMAIL} if EMAIL else {}))).encode())
try:
    with urllib.request.urlopen(req, timeout=30) as r:
        code = json.load(r)
except urllib.error.HTTPError as e:
    code = json.load(e)
if "device_code" not in code:
    sys.exit("Could not start sign-in: " + str(code.get("error", code)))
pending = os.path.expanduser("~/.magpie/pending-login.json")
os.makedirs(os.path.dirname(pending), exist_ok=True)
fd = os.open(pending, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
with os.fdopen(fd, "w") as f:
    json.dump({"base": BASE, "device_code": code["device_code"], "interval": code.get("interval", 5),
               "deadline": time.time() + code.get("expires_in", 600)}, f)
print("Code:", code["user_code"])
if EMAIL and code.get("email_sent", True):
    print("Email sent to", EMAIL)
else:
    print("Open:", code["verification_uri_complete"])
```

**2. Tell the user, before you run anything else.** Always include the code:
- **Browser:** "Open this link, sign in, check that the page shows code <code>,
  and click Approve: <link>." On the user's own computer you may open the link
  for them (`open` on macOS, `xdg-open` on Linux, `start` on Windows).
- **Email:** "Check your inbox for 'Approve <your name> on <machine> — Magpie'.
  Only approve if it shows code <code>. Click Approve sign-in, then Approve."

**3. Wait.** Then run this; it waits for the approval and saves the key itself:

```python
import json, os, sys, time, urllib.error, urllib.parse, urllib.request
pending = os.path.expanduser("~/.magpie/pending-login.json")
if not os.path.exists(pending):
    sys.exit("No sign-in in progress; run the start step again.")
p = json.load(open(pending))
interval = p["interval"]
while time.time() < p["deadline"]:
    time.sleep(interval)
    req = urllib.request.Request(p["base"] + "/data/v1/device/token", data=urllib.parse.urlencode({
        "grant_type": "urn:ietf:params:oauth:grant-type:device_code", "device_code": p["device_code"]}).encode())
    try:
        with urllib.request.urlopen(req, timeout=30) as r:
            t = json.load(r)
    except urllib.error.HTTPError as e:
        t = json.load(e)
    err = t.get("error")
    if err == "authorization_pending":
        continue
    if err == "slow_down":
        interval += 5
        continue
    os.remove(pending)
    if err:
        sys.exit("Sign-in stopped: " + err)
    path = os.path.expanduser("~/.magpie/credentials")
    creds = json.load(open(path)) if os.path.exists(path) else {"version": 1, "profiles": {}}
    creds.setdefault("profiles", {})[p["base"]] = {"api_key": t["api_key"]}
    fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
    with os.fdopen(fd, "w") as f:
        json.dump(creds, f)
    os.chmod(path, 0o600)
    print("Signed in as", t.get("account_email", "your account"))
    break
else:
    os.remove(pending)
    sys.exit("Sign-in timed out; run the start step again.")
```

If your tool can't run a 10-minute command, run the wait step in the background
or run it again after the user says they approved — it picks up where it left off.

On the approval page the user can set a daily spending cap for this agent. New
accounts get free trial credits; there is no registration form and no sales
call. The request expires after 10 minutes; at most 3 emails per address per hour.

If the Magpie CLI is installed (`magpie --version` works), `magpie login` (add
`--email <address>` for email) does the same and writes the same file, but it
prints the code and then waits in one command — only use it if you can show the
user its output while it is still running (e.g. run it in the background and read
its output); otherwise use the two steps above.

## Step 3 — Connect the Magpie MCP server with that key

The server URL is `https://mcp-staging.magpieiq.com/v2/mcp`. Register it for the agent you
are running in, sending the saved key as a header. These commands read the key
from the file, so it never appears in the conversation. Each is safe to re-run.

- **Claude Code:**
  ```bash
  claude mcp remove --scope user magpie 2>/dev/null
  claude mcp add --transport http --scope user magpie https://mcp-staging.magpieiq.com/v2/mcp --header "Authorization: Bearer $(python3 -c 'import json,os;print(json.load(open(os.path.expanduser("~/.magpie/credentials")))["profiles"]["https://api-staging.magpieiq.com"]["api_key"])')"
  ```
- **Cursor or opencode:** run this, with `AGENT` set to `cursor` or `opencode`:
  ```python
  import json, os
  AGENT = "cursor"
  key = json.load(open(os.path.expanduser("~/.magpie/credentials")))["profiles"]["https://api-staging.magpieiq.com"]["api_key"]
  url, headers = "https://mcp-staging.magpieiq.com/v2/mcp", {"Authorization": "Bearer " + key}
  path, top, entry = {
      "cursor": ("~/.cursor/mcp.json", "mcpServers", {"url": url, "headers": headers}),
      "opencode": ("~/.config/opencode/opencode.json", "mcp",
                   {"type": "remote", "url": url, "enabled": True, "headers": headers}),
  }[AGENT]
  p = os.path.expanduser(path)
  os.makedirs(os.path.dirname(p), exist_ok=True)
  cfg = json.load(open(p)) if os.path.exists(p) else {}
  cfg.setdefault(top, {})["magpie"] = entry
  fd = os.open(p, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
  with os.fdopen(fd, "w") as f:
      json.dump(cfg, f, indent=2)
  print("Magpie added to", path)
  ```
- **Codex:** append `[mcp_servers.magpie]` with `url = "https://mcp-staging.magpieiq.com/v2/mcp"`
  to `~/.codex/config.toml` if it is not there, then run `codex mcp login magpie`
  (Codex signs its MCP connection in through the browser; the CLI keeps using the
  saved key).
- **Any other agent that supports remote MCP servers:** add the URL with the
  header `Authorization: Bearer <key from ~/.magpie/credentials>`, written by a
  script, never typed into chat.

**No `python3`?** Register the URL without a header (the Claude Code command
without `--header`, or the config entry without `headers`). The first Magpie tool
call then opens the MCP server's own browser sign-in (in Claude Code: `/mcp` →
magpie → Authenticate). That signs in the tools only, not the CLI.

Some agents only load new MCP servers after a restart. If the Magpie tools do
not appear, ask the user to restart the agent and come back.

If the Magpie CLI is installed, `magpie init` registers the server for every
agent it finds.

### Packages: only when the task needs them

The MCP server is the default and gives you all of Magpie's data. Do not install
a package just to ask questions. Install one only in these cases, and tell the
user what you chose and why:

- **The user works in Python** (notebook, script, pipeline, or the project has a
  `pyproject.toml` / `requirements.txt`), or needs a bulk Parquet export loaded
  into pandas or DuckDB: install the Python client, which also provides the
  `magpie` CLI. Prefer `uv tool install magpie-data` (or `pipx install
  magpie-data`) for the CLI, or `pip install magpie-data` inside the project's
  own environment for code.
- **Several coding agents on this machine should get Magpie at once**, and
  `node --version` works: run `npx -y @magpieiq/cli init`. It only sets things
  up; it adds no data beyond the MCP server.
- **Otherwise**: install nothing.

Check availability first: `pip index versions magpie-data` or
`npm view @magpieiq/cli version`. If the package is not found, it is not
published yet: skip the install, stay on the MCP server, and tell the user the
package is coming soon. Check runtimes with `python3 --version`,
`uv --version` and `node --version`; never install a language runtime.

## Step 4 — Save the Magpie skill

So that future sessions know how to use Magpie without being told, save the
skill file from `https://data-staging.magpieiq.com/skill/SKILL.md` unchanged:

- **Claude Code:** `~/.claude/skills/magpie-ecommerce-data/SKILL.md`
- **Codex:** `~/.codex/skills/magpie-ecommerce-data/SKILL.md`
- **Other agents:** their user-level skills or rules directory, if they have one;
  otherwise skip this step.

Download it with a plain HTTP GET (e.g. `curl -fsSL`); it is public and needs no key.

## Step 5 — Verify and hand over

1. Call the `discover` tool (or `GET https://api-staging.magpieiq.com/agent/v1/capabilities`)
   and confirm it lists endpoints.
2. If signed in, report the credit balance when a response carries
   `meta.balance`.
3. Offer two first questions, one per kind of answer:
   - **Data:** "Who leads Facial Serum on Shopee Indonesia, and how has that
     changed over the last six months?"
   - **Live:** "What does this Tokopedia product cost right now?" (have the
     user paste a product link). Live scraping runs as a job that can take up
     to about a minute; quote it first with `estimate: true`, then run it.

Before any paid call, get a free quote with `estimate: true` and tell the user
the price. The full method, error codes and recipes are in the skill
(`https://data-staging.magpieiq.com/skill/SKILL.md`).
