# Windsurf (Devin Desktop)

> Set up Spicrawl in Windsurf, now named Devin Desktop: add the hosted MCP server, install the agent skill, and add a rule so the agent fetches web pages cheaply and handles errors correctly.

Source: https://docs.spicrawl.com/agents/windsurf

Windsurf is now called **Devin Desktop** (renamed on 2026-06-02; same editor, and Cognition's docs at `docs.windsurf.com` redirect to `docs.devin.ai/desktop`). This page covers both names. Devin Desktop has two agents, and they configure MCP differently:

| Agent                                           | Where MCP servers live                                                                                             |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| **Devin Local**, the default agent for new tabs | The Devin CLI files `.devin/mcp_config.json`, `.devin/mcp_config.local.json` and `~/.config/devin/mcp_config.json` |
| **Cascade**, the legacy agent                   | `~/.config/devin/mcp_config.json`, with `serverUrl` and `${env:VAR}` interpolation                                 |

Set your key first, in the environment Devin Desktop starts from:

```bash
export SPICRAWL_API_KEY=spicrawl_live_...   # add to your shell profile, then restart Devin Desktop
```

## 1. Add the MCP server

**Devin Local**

Add the server in local scope. It is saved to `.devin/mcp_config.local.json`, which Devin gitignores, so the key stays out of your repository:

```bash
devin mcp add spicrawl https://mcp.spicrawl.com/mcp -H "Authorization: Bearer $SPICRAWL_API_KEY"
```

Your shell expands `$SPICRAWL_API_KEY`, so the file holds the key itself. The equivalent file:

```json title=".devin/mcp_config.local.json"
{
  "mcpServers": {
    "spicrawl": {
      "url": "https://mcp.spicrawl.com/mcp",
      "headers": { "Authorization": "Bearer spicrawl_live_..." }
    }
  }
}
```

Use `-s user` to write `~/.config/devin/mcp_config.json` (`%APPDATA%\devin\mcp_config.json` on Windows) for every project. Do not use `-s project`, which writes the shared, committed `.devin/mcp_config.json`. Check with `devin mcp list`. Remote servers use Streamable HTTP by default.

**Cascade (legacy)**

Open the Cascade panel, click the `...` (Actions) menu at the top right, then the **Open MCP config file** icon in the MCPs section. Add the server under `mcpServers`. Cascade replaces `${env:SPICRAWL_API_KEY}` with the variable's value, so the file holds no key:

```json title="~/.config/devin/mcp_config.json"
{
  "mcpServers": {
    "spicrawl": {
      "serverUrl": "https://mcp.spicrawl.com/mcp",
      "headers": { "Authorization": "Bearer ${env:SPICRAWL_API_KEY}" }
    }
  }
}
```

The file is at `$XDG_CONFIG_HOME/devin/mcp_config.json` (default `~/.config/devin/mcp_config.json`) on macOS and Linux, and `%APPDATA%\devin\mcp_config.json` on Windows. An unset variable resolves to an empty string, so the server then answers 401.

The server exposes 25 `spicrawl_*` tools. See [MCP server](https://docs.spicrawl.com/agents/mcp.md) for each tool.

> **Tool limit:** Cascade allows 100 tools in total across all enabled servers. Spicrawl uses 25 of them. If you are near the limit, disable other servers or list tool names in a server's `disabledTools` array in `mcp_config.json`.

> **Team allowlists:** On a Teams or Enterprise plan, an admin can allowlist MCP servers. Once one server is allowlisted, every other server is blocked for the team. Ask the admin to add Server ID `spicrawl` (case-sensitive, the key name in your config) and to leave &#x2A;*Server Config (JSON)** empty to accept any configuration.

## 2. Install the skill

Devin Desktop loads skills from `.devin/skills/`, `.windsurf/skills/` and `.agents/skills/` in the project, and from `~/.config/devin/skills/` for every project. `.agents/skills/` is what the CLI's `codex` client writes:

```bash
spicrawl skill install --client codex
```

This writes `.agents/skills/spicrawl/SKILL.md`. Without the CLI:

```bash
mkdir -p .agents/skills/spicrawl
curl -fsSL https://app.spicrawl.com/skill.md -o .agents/skills/spicrawl/SKILL.md
```

See [Agent skill](https://docs.spicrawl.com/agents/skill.md).

## 3. Add a rule

Save this as `.devin/rules/spicrawl.md` (`.windsurf/rules/` still works, and `.devin/` wins when both exist). With `trigger: model_decision` only the `description` sits in the prompt, and the agent reads the rule when a task involves web data. Use `trigger: always_on` to include it in every message. A rule file is limited to 12,000 characters.

```markdown title=".devin/rules/spicrawl.md"
---
trigger: model_decision
description: Fetching, scraping or extracting data from web pages with Spicrawl
---

# Web data (Spicrawl)

Use Spicrawl to read web pages: the spicrawl_* MCP tools in chat, or
POST https://api.spicrawl.com/v1/scrape with `Authorization: Bearer $SPICRAWL_API_KEY` in code.
Docs: https://docs.spicrawl.com/llms.txt (append .md to any page URL for Markdown).

- Ask for markdown: `response_format: "markdown"` (API default is html); on spicrawl_scrape, `format: "markdown"`.
- Check the site's status, not only the HTTP status: `X-Target-Status` header, or `status`
  in the JSON envelope (spicrawl_scrape with `format: "json"`). 200 is the page; 404/410
  mean it does not exist; 403/429/503 mean the site refused, so escalate.
- On an error, switch on `code`. Retry only when `retryable` is true, after
  `retry_after_seconds`. Read `diagnostics.hint` and change what it names first.
  Never retry ERR::REQUEST::*, ERR::AUTH::* or ERR::LIMIT::QUOTA_EXCEEDED.
- Escalate one step at a time and stop at the first that works:
  plain fetch (1 credit) -> `js_render: true` (3) -> add the user's own `proxy`
  if they have one. Empty or skeleton content means render; ERR::UPSTREAM::CHALLENGE
  or a 403 target status means retry once, then the user's own proxy.
- Set `max_cost` on every request to the price of the step you intend.
- Keep the cache on (default). Set `cache: false` only for prices, stock or other live data.
- Trim tokens with `main_content_only` (on by default for markdown), `include_tags`, `exclude_tags`.
- For more than 20 URLs, use a batch job (spicrawl_batch_submit / POST /v1/batch).
  Batch items return raw HTML and apply only render, proxy and block_resources settings.
- Never print or commit SPICRAWL_API_KEY. Log `X-Request-Id` for failures.
```

Devin Desktop also reads `AGENTS.md` at the project root as an always-on rule. If you already keep agent instructions there, paste the same section into it instead of creating a rule file.

## A first task to try

Open a new agent tab and ask:

```text
Use Spicrawl to read https://example.com/pricing as markdown. List each plan with its monthly price.
If the page comes back empty, retry with rendering.
```

The agent should call `spicrawl_scrape` with `url` and `format: "markdown"`, and add `render: true` only if the first result is empty. For a coding task:

```text
Add a fetchPage(url) function to this project that calls the Spicrawl API for markdown,
following the Spicrawl rule's error-handling steps. Read the key from process.env.SPICRAWL_API_KEY.
```

Compare the result with the reference implementation in [Best practices](https://docs.spicrawl.com/agents/best-practices.md).

## Troubleshooting

| Symptom                                                                       | Fix                                                                                                                                                              |
| ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 401 from the server (Cascade)                                                 | `SPICRAWL_API_KEY` was not set when Devin Desktop started, so the header was empty. Export it and restart from that shell.                                       |
| 401 from the server (Devin Local)                                             | The key in `.devin/mcp_config.local.json` is wrong or empty. Run `devin mcp remove spicrawl` and add it again.                                                   |
| Spicrawl does not appear in the MCP list                                      | You edited the file for the other agent. Devin Local reads the `.devin/` files and `devin mcp add`. Cascade reads its own MCP config file from the Actions menu. |
| The server is blocked                                                         | A team allowlist is active. Ask the admin to allowlist Server ID `spicrawl`.                                                                                     |
| Tools are missing or capped                                                   | Cascade allows 100 tools across all servers. Disable other servers.                                                                                              |
| The agent writes `js_render` on `spicrawl_scrape` and gets "unknown argument" | The tool's argument is `render`. The API field is `js_render`.                                                                                                   |
| Usage tools return `ERR::AUTH::INSUFFICIENT_SCOPE`                            | Grant the `read` scope to the key in the dashboard.                                                                                                              |
