> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nimbleway.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Vercel eve

> Give a Vercel eve agent real-time web search, page extraction, and cited deep research with Nimble.

## Overview

[eve](https://eve.dev) is Vercel's filesystem-first framework for durable AI agents. An agent is a directory: instructions, tools, skills, and connections are all files. The [`@nimble-way/eve`](https://www.npmjs.com/package/@nimble-way/eve) extension adds Nimble web data to that directory in one line.

* **Mount once, get four tools**: search, extract, and two deep-research run tools.
* **Can take over eve's built-ins**: replace `web_search` and `web_fetch` so every turn uses Nimble. See [Replace the built-in web search and fetch](#replace-the-built-in-web-search-and-fetch).
* **Bundled skill**: teaches the agent when to search and when to extract.
* **Durable deep research**: start a Web Search Agent run, collect the cited answer minutes later.

<Note>
  Building a Vercel AI SDK app rather than an eve agent? Use the [Vercel AI SDK connector](/integrations/connectors/vercel-ai-sdk) instead. The two packages are separate: `@nimble-way/eve` targets eve, `@nimble-way/ai-sdk` targets the AI SDK directly.
</Note>

## Prerequisites

eve needs **Node.js 24 or later**, newer than most Nimble integrations require. Run `node --version` first.

<AccordionGroup>
  <Accordion title="An eve project on 0.27.8 or later">
    Create one with `npx eve@latest init my-agent`, or use an existing project. 0.27.8 is the extension's floor, but prefer a current release: eve ships frequently, and these examples are verified against 0.33.2.
  </Accordion>

  <Accordion title="NIMBLE_API_KEY">
    Required by every tool. Get a key from the [dashboard](https://online.nimbleway.com/settings/api-keys). eve loads `.env` and `.env.local` automatically. The key resolves at call time, so `eve info` and builds work without it.
  </Accordion>

  <Accordion title="No agent instance required">
    The key is the only credential. Unlike the [AI SDK package](/integrations/connectors/vercel-ai-sdk), the run tools need no pre-created [Web Search Agent](/nimble-sdk/web-search-agents/overview) and no `NIMBLE_AGENT_ID`. Omit `agentName` and Nimble creates an agent for the run, then returns its ID. Pass `agentName` to create or reuse a stable named agent instead.
  </Accordion>
</AccordionGroup>

## Quick Start

<Steps>
  <Step title="Create or open an eve project">
    ```bash theme={"system"}
    npx eve@latest init my-agent
    cd my-agent
    ```
  </Step>

  <Step title="Install the extension">
    ```bash theme={"system"}
    npm install @nimble-way/eve
    ```
  </Step>

  <Step title="Set your API key">
    ```bash theme={"system"}
    echo 'NIMBLE_API_KEY=your-api-key' >> .env.local
    ```
  </Step>

  <Step title="Mount the extension">
    The filename sets the tool prefix. `nimble.ts` gives you `nimble__search`, `nimble__extract`, `nimble__agent_start`, and `nimble__agent_result`.

    ```ts theme={"system"}
    // agent/extensions/nimble.ts
    import nimble from '@nimble-way/eve';

    export default nimble({});
    ```
  </Step>

  <Step title="Verify">
    ```bash theme={"system"}
    npx eve info
    ```

    The output lists `nimble__search`, `nimble__extract`, `nimble__agent_start`, `nimble__agent_result`, and the `nimble__web-research` skill.
  </Step>
</Steps>

## How it works

<Steps>
  <Step title="The mount names the tools">
    eve derives identity from paths, so renaming the mount file renames every tool it contributes. Nothing declares a name.
  </Step>

  <Step title="The model picks a tool">
    The bundled skill tells the model to search when it does not know which page holds the answer, and to extract when it already has a URL.
  </Step>

  <Step title="Nimble runs the request">
    Tools run in your app's Node process, so they read `NIMBLE_API_KEY` from your environment. Calls abort with the run.
  </Step>

  <Step title="The model answers">
    Results return as structured output the model cites in its reply.
  </Step>
</Steps>

## Tools

<CardGroup cols={2}>
  <Card title="nimble__search" icon="magnifying-glass">
    Ranked web results with title, URL, and snippet. Full page content in deep mode.
  </Card>

  <Card title="nimble__extract" icon="file-lines">
    Fetch a URL and return clean markdown or HTML, plus the links found on the page.
  </Card>

  <Card title="nimble__agent_start" icon="play">
    Start a Web Search Agent run. Returns identifiers immediately, without waiting.
  </Card>

  <Card title="nimble__agent_result" icon="file-check">
    Resume a started run and return the cited answer. Never creates a run.
  </Card>
</CardGroup>

The extension also contributes a `nimble__web-research` skill. eve loads it on demand through `load_skill`, and it recognizes both the namespaced and the promoted tool names.

### Search response

The extension normalizes the [Search API](/nimble-sdk/web-tools/search) response into camelCase and flattens the per-result metadata, so these shapes differ from the raw API reference.

```ts theme={"system"}
{
  query: string;
  requestId?: string;
  totalResults?: number;
  results: Array<{
    title: string;
    url: string;
    description?: string;
    content?: string;     // deep searches only
    position?: number;
    entityType?: string;
  }>;
}
```

### Extract response

```ts theme={"system"}
{
  url: string;           // final URL after redirects
  status: string;        // e.g. 'success'
  statusCode?: number;
  format: 'markdown' | 'html';
  content: string;       // truncated to maxContentLength
  links?: string[];
}
```

### Deep research

These two tools drive a [Web Search Agent](/nimble-sdk/web-search-agents/overview) run: an autonomous agent that plans, searches, reads, and cross-checks many sources, then returns a cited answer.

**Reach for this instead of looping search and extract yourself.** When the question needs many sources, a run does the planning, deduplication, and cross-checking server-side, and returns [trust metadata](/nimble-sdk/web-search-agents/trust): per-claim citations and confidence, so the answer carries its own provenance. One billed run replaces a dozen model turns of search-then-read, so it is usually cheaper as well as better sourced. Use `nimble__search` for a quick fact and a run for a report.

`nimble__agent_start` takes an `input` task and optional `agentName`, `effort`, `skill`, `inputData`, `outputSchema`, `previousInteractionId`, and `sources`. It returns the run, agent, and interaction identifiers:

```ts theme={"system"}
{
  runId: string;
  agentId: string;
  interactionId?: string;
}
```

Pass those to `nimble__agent_result`, which waits for a terminal state and returns the cited answer. The model calls both tools itself, so there is nothing to orchestrate. Splitting the lifecycle matters because a run takes minutes: eve records the identifiers from the first step before the second begins polling.

## Replace the built-in web search and fetch

eve ships `web_search` and `web_fetch` in its default harness. They differ from Nimble in reach and in what they return.

|                           | eve built-in                                                                                                                                          | Nimble                                      |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `web_search` availability | Provider-managed, supported providers only                                                                                                            | Every model                                 |
| `web_search` backend      | A provider-managed backend, currently Exa on AI Gateway models (eve 0.32.0)                                                                           | Nimble Web Search                           |
| `web_fetch` rendering     | Plain fetch, no JavaScript                                                                                                                            | Rendered page, cleaned content              |
| `web_fetch` reach         | Limited by eve's SSRF guard, which stops the agent reaching internal network addresses: HTTPS only, no private hosts, no automatic redirect following | Follows redirects and reports the final URL |
| Deep research             | Not available                                                                                                                                         | Web Search Agent runs with citations        |

**Promote `web_search` in most agents.** The built-in only exists on supported model providers, so an agent that promotes it searches consistently on every model.

**Promote `web_fetch` when the agent reads real pages**, which is most research agents. Skip it when untrusted input can steer the agent to arbitrary URLs, because the swap replaces eve's SSRF guard. See [Promoting the fetch tool changes your security model](#promoting-the-fetch-tool-changes-your-security-model).

Optional. The Quick Start setup already works. Promote when you want every agent turn to use Nimble, with no instruction changes.

eve treats a file at `agent/tools/web_search.ts` as a replacement for its built-in of the same name. Only your own agent directory can replace a built-in, which is why the promote files live in `agent/tools/` and not inside the npm package.

Promoting does not remove the namespaced tool. The model would see both `web_search` and `nimble__search`, two entries doing the same job, and may call either. So each promotion needs two files: one to promote, one to disable the duplicate.

Disable files must live inside the extension mount, so the mount becomes a directory first:

1. Create `agent/extensions/nimble/extension.ts` with the same contents as the `nimble.ts` from Quick Start.
2. **Delete the old `agent/extensions/nimble.ts`.** Leaving it in place mounts the extension twice.
3. Add one disable file per promoted tool, named after the **extension's** tool (`search`, `extract`), not the built-in it replaced (`web_search`, `web_fetch`).

Promoting both tools gives five files:

```text theme={"system"}
agent/
  extensions/
    nimble/
      extension.ts       # mounts the extension
      tools/
        search.ts        # disables nimble__search
        extract.ts       # disables nimble__extract
  tools/
    web_search.ts        # Nimble Search in the built-in slot
    web_fetch.ts         # Nimble Extract in the built-in slot
```

```ts agent/extensions/nimble/extension.ts theme={"system"}
import nimble from '@nimble-way/eve';

export default nimble({});
```

```ts agent/tools/web_search.ts theme={"system"}
export { search as default } from '@nimble-way/eve/tools';
```

```ts agent/extensions/nimble/tools/search.ts theme={"system"}
import { disableTool } from 'eve/tools';

export default disableTool();
```

```ts agent/tools/web_fetch.ts theme={"system"}
export { extract as default } from '@nimble-way/eve/tools';
```

```ts agent/extensions/nimble/tools/extract.ts theme={"system"}
import { disableTool } from 'eve/tools';

export default disableTool();
```

`eve info` now lists `web_search` and `web_fetch`, both Nimble-backed.

### Promoting the fetch tool changes your security model

eve's built-in `web_fetch` has enforced an SSRF guard since eve 0.27.9. It requires HTTPS, rejects non-public destinations during DNS resolution, and returns redirect targets without following them. On 0.27.8, the extension's floor, that guard does not exist yet, so the tradeoff below does not apply. Upgrade rather than rely on it.

Promoting Nimble Extract into that slot replaces those checks. Fetches leave your app runtime and go through Nimble's infrastructure instead, which is what makes rendered pages and redirect following possible.

That is the right trade for most research agents, because the whole point is reading real pages. It is the wrong trade if the agent can be steered to arbitrary URLs by untrusted input. In that case, keep the built-in `web_fetch`, use `nimble__extract` alongside it, and let your instructions decide which to call. You can also gate the tool with `approval` from `eve/tools/approval`, or apply your own URL allowlist before the call.

Promoting `web_search` carries no equivalent tradeoff. It has no local executor to bypass.

### Promote one tool or both

**Default: promote `web_search`, keep the built-in `web_fetch`.** Replacing `web_search` costs nothing, because it has no local executor to bypass. Replacing `web_fetch` gives up eve's SSRF guard, which is worth it only when the agent's inputs are trusted.

To promote one tool, create only that tool's two files. The other stays available as `nimble__search` or `nimble__extract`.

## Configuration

Pass options where the extension is mounted. All are optional.

```ts theme={"system"}
// agent/extensions/nimble.ts
import nimble from '@nimble-way/eve';

export default nimble({
  search: { depth: 'lite', maxResults: 5, country: 'US', locale: 'en' },
  extract: { format: 'markdown' },
  agent: { pollIntervalMs: 10_000, timeoutMs: 420_000 },
});
```

<AccordionGroup>
  <Accordion title="apiKey">
    Nimble API credentials. Defaults to `process.env.NIMBLE_API_KEY`. Resolved at call time.
  </Accordion>

  <Accordion title="search.depth">
    `'lite'` returns snippets (fast); `'deep'` returns full page content in results. Default `'lite'`.
  </Accordion>

  <Accordion title="search.maxResults">
    Default result count when the model does not ask for a specific number. Default `5`.
  </Accordion>

  <Accordion title="search.maxResultsCap">
    Hard upper limit on what the model can request. Default `10`.
  </Accordion>

  <Accordion title="search.maxContentLength">
    Per-result content truncation, in characters. Default `10_000`.
  </Accordion>

  <Accordion title="search.country / search.locale">
    Result localization. Defaults `'US'` and `'en'`.
  </Accordion>

  <Accordion title="extract.format">
    `'markdown'` for cleaned main content, or `'html'`. Default `'markdown'`.
  </Accordion>

  <Accordion title="extract.country">
    Two-letter country code for geolocation and proxy selection. Optional.
  </Accordion>

  <Accordion title="extract.maxContentLength">
    Extracted content truncation, in characters. Default `50_000`.
  </Accordion>

  <Accordion title="agent.pollIntervalMs">
    Status polling interval for Web Search Agent runs. Default `10_000`. Runs take minutes, so a shorter interval mostly adds requests without returning the answer sooner. Polling counts against your [rate limit](/nimble-sdk/admin/rate-limits) like any other call.
  </Accordion>

  <Accordion title="agent.timeoutMs">
    Bounded deadline for reaching a terminal run state. Default `420_000`.
  </Accordion>
</AccordionGroup>

## Use the MCP server instead

Prefer no npm dependency? eve has first-class MCP connections, and the [Nimble MCP Server](/integrations/mcp-server/mcp-server) works with them as-is. That page owns the server reference: transport, auth, and the full tool inventory. This section covers only the eve wiring.

There are two ways to authenticate. Start with the API key, and switch to OAuth if you need it.

Create one file:

```ts theme={"system"}
// agent/connections/nimble.ts
import { defineMcpClientConnection } from 'eve/connections';

export default defineMcpClientConnection({
  url: 'https://mcp.nimbleway.com/mcp',
  description: 'Nimble web data: search the web, extract pages, map and crawl sites.',
  auth: {
    getToken: async () => ({ token: process.env.NIMBLE_API_KEY! }),
  },
});
```

The Nimble MCP server also advertises [OAuth 2.1](/integrations/overview#oauth-sign-in), so [Vercel Connect](https://vercel.com/docs/connect) can own the consent flow and token storage. To use it, run:

```bash theme={"system"}
npm install @vercel/connect
vercel link
vercel connect create https://mcp.nimbleway.com/mcp --name nimble
vercel connect attach <connector-uid> --yes
vercel env pull
```

Then swap the `auth` field in the same file for the Connect version:

```ts agent/connections/nimble.ts theme={"system"}
import { connect } from '@vercel/connect/eve';
// ...
  auth: connect('mcp.nimbleway.com/nimble'),
```

eve gives the model a built-in `connection_search` tool that discovers these at run time, so there is nothing to register. It prefixes the connection name and leaves the remote name alone, so `nimble_search` on the server surfaces as `nimble__nimble_search`.

Narrow the surface with `tools.allow`, which takes bare remote names:

```ts agent/connections/nimble.ts theme={"system"}
export default defineMcpClientConnection({
  url: 'https://mcp.nimbleway.com/mcp',
  description: 'Nimble web data: search the web, extract pages, map and crawl sites.',
  auth: { getToken: async () => ({ token: process.env.NIMBLE_API_KEY! }) },
  tools: { allow: ['nimble_search', 'nimble_extract'] },
});
```

### Which path to pick

|                                       | Extension                         | MCP connection                                                                 |
| ------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------ |
| Install                               | `npm install @nimble-way/eve`     | No dependency                                                                  |
| Tool names                            | `nimble__search`                  | `nimble__nimble_search`                                                        |
| Promote to `web_search` / `web_fetch` | Yes                               | No                                                                             |
| Tuned defaults and truncation caps    | Yes                               | Server defaults                                                                |
| OAuth                                 | No, API key                       | Yes, through Vercel Connect                                                    |
| Products                              | Search, Extract, Web Search Agent | [Everything the MCP server exposes](/integrations/mcp-server/mcp-server#tools) |

Use the extension for promoted built-ins and configurable defaults. Use MCP for a zero-install setup, OAuth, or access to Map and Crawl.

## What the extension covers

The extension ships Search, Extract, and Web Search Agent runs. Search returns ranked results at `lite` or `deep` depth, and Extract returns readable content and links.

For anything else, reach the full platform through the [MCP connection](#use-the-mcp-server-instead) or call the APIs directly: [Map](/nimble-sdk/web-tools/map) and [Crawl](/nimble-sdk/web-tools/crawl) for whole-site work, and the [focus modes](/nimble-sdk/web-tools/search#focus-modes) for news, social, and the other targeted searches.

## Before you ship

* **Page content stays data, not instructions.** The bundled `nimble__web-research` skill already tells the model to treat fetched pages as material to quote and reason over, never as commands. Repeat it in your own instructions for defense in depth.
* **Promoting `web_fetch` bypasses eve's SSRF guard.** See [Promoting the fetch tool changes your security model](#promoting-the-fetch-tool-changes-your-security-model).
* **Web Search Agent runs are billable.** Each `nimble__agent_start` call starts a paid run. The tool never retries a create, so a resumed poll cannot double-charge you.
* **Check your `eve` version.** The extension declares `eve` as a wildcard peer, so npm may install any release. Projects created with `eve init` are already pinned. If you added `eve` by hand, pin it in `package.json`.

## Resources

<CardGroup cols={2}>
  <Card title="npm Package" icon="npm" href="https://www.npmjs.com/package/@nimble-way/eve">
    `@nimble-way/eve` on npm.
  </Card>

  <Card title="GitHub Repository" icon="github" href="https://github.com/Nimbleway/eve">
    Source, README, and an example agent.
  </Card>

  <Card title="eve Documentation" icon="book" href="https://eve.dev/docs">
    Vercel's framework documentation.
  </Card>

  <Card title="Nimble MCP Server" icon="server" href="/integrations/mcp-server/mcp-server">
    The hosted server behind the MCP path.
  </Card>

  <Card title="Web Search API" icon="magnifying-glass" href="/nimble-sdk/web-tools/search">
    Nimble's underlying search capability.
  </Card>

  <Card title="Extract API" icon="file-lines" href="/nimble-sdk/web-tools/extract/quickstart">
    Nimble's underlying page extraction capability.
  </Card>

  <Card title="Web Search Agent" icon="robot" href="/nimble-sdk/web-search-agents/overview">
    The deep-research capability behind the run tools.
  </Card>
</CardGroup>
