Guide

Agents

Two tools on MCP and AI SDK and Pi and OMP. A bounded page per source with hasMore and truncated so the agent narrows the call instead of drowning.

Every agent host gets the same two tools, backed by the same executor: urls_discover and urls_providers. What changes between hosts is only how the answer is printed.

MCP

jsonmcp.json
{
  "mcpServers": {
    "urls": {
      "command": "npx",
      "args": ["-y", "@agntn/urls", "mcp"]
    }
  }
}

Set VIRUSTOTAL_API_KEY or URLSCAN_API_KEY in the server's environment when you want those sources at full strength. Building your own server? createMcpServer from @agntn/urls/mcp returns a configured McpServer.

AI SDK

ts
import { discoverTool, providersTool } from "@agntn/urls/ai";
import { generateText } from "ai";

const { text } = await generateText({
  model,
  tools: { urls_discover: discoverTool, urls_providers: providersTool },
  prompt: "Which JavaScript files has example.com shipped over the years?",
});

AI SDK 7 or newer. The tool passes its abortSignal down to the sources.

Pi and OMP

shell
pi install npm:@agntn/urls
omp plugin install @agntn/urls

Both extensions print URLs one per line, with a note at the end when the source had more. They take the host's cancel signal too.

Why a page and not everything?

A busy domain has tens of thousands of URLs, and an agent that gets all of them in its context isn't smarter, just slower and more expensive. So the agent tools answer with a page: at most 100 URLs per source unless the call sets limit. The library and CLI stay unbounded.

Each page says what cut it:

FieldMeaning
countURLs on this page
limitthe bound that applied, the caller's or 100
hasMorethe source had more than fits, or stopped on its own with more advertised
truncatedthe source stopped on its own, its page safeguard or a cursor it won't follow

hasMore without truncated means the limit cut it: raise limit, or narrow with match, ext or urlScope. With truncated a higher limit won't help, since the source itself gave up. Filters won't either, because they work on what the source returned. Another source might.

What an answer looks like

json
{
  "provider": "wayback",
  "count": 2,
  "limit": 2,
  "hasMore": true,
  "truncated": false,
  "urls": [
    {
      "url": "http://example.com:80/",
      "source": "wayback",
      "input": "example.com",
      "firstSeen": "2002-01-20T14:25:10Z",
      "lastSeen": "2002-01-20T14:25:10Z"
    }
  ]
}

(Shortened to one record.) With provider: "all" the answer is a list of { provider, result } or { provider, error }, one per source.

The query URL behind each record, reference, stays out of the MCP and AI SDK answers. It's the same for every URL of one request and would only burn tokens. Pass reference: true when you need it.

Try it without an agent

The explorer runs urls_discover through the docs worker and shows the exact text an MCP client gets.