MCP Server

Call ByteKit web capture as a native tool from Claude, Cursor, and any MCP-compatible agent — hosted over HTTP or run locally over stdio.

The ByteKit MCP server exposes scraping, search, screenshots, and account lookups as Model Context Protocol tools. Your agent calls scrape_url or screenshot_url the same way it calls any other tool — no wrapper to write, no headless browser to manage.

There are two ways to connect: a hosted HTTP endpoint (nothing to install) and a local stdio server (npx @hunt-labs/bytekit-mcp).

Authentication

Both paths authenticate with a ByteKit API key. Sign up at app.bytekit.com and create a key (prefixed sk_live_). The local server reads it from the BYTEKIT_API_KEY environment variable (or the --api-key flag); the hosted endpoint takes it as a bearer token.

Option 1 — Hosted HTTP (no install)

Point any MCP client that speaks the Streamable HTTP transport at:

https://api.bytekit.com/mcp

Send your API key as a bearer token. Example client config for a host that speaks Streamable HTTP directly (Cursor and most hosts accept this shape):

{
  "mcpServers": {
    "bytekit": {
      "url": "https://api.bytekit.com/mcp",
      "headers": {
        "Authorization": "Bearer sk_live_xxx"
      }
    }
  }
}

Paste your real key in place of sk_live_xxx. A JSON config file is not a shell: most hosts read these values verbatim and do not substitute environment variables inside headers, so writing Bearer $BYTEKIT_API_KEY here sends that text to the API as the token, verbatim, and the API answers 401.

Claude Desktop does not accept this shape. claude_desktop_config.json only launches local stdio subprocesses (command/args/env) — it has no native url-based remote-server entry, so pasting the config above into it will not connect. To reach the hosted endpoint from Claude Desktop, either:

  • add ByteKit as a Connector (Settings → Connectors → Add custom connector), or
  • bridge it locally with mcp-remote:
{
  "mcpServers": {
    "bytekit": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.bytekit.com/mcp",
        "--header",
        "Authorization:${AUTH_HEADER}"
      ],
      "env": {
        "AUTH_HEADER": "Bearer sk_live_xxx"
      }
    }
  }
}

Two details in that snippet are load-bearing, and both are documented by mcp-remote itself:

  • ${AUTH_HEADER}, not $AUTH_HEADER. Claude Desktop launches command/args directly, with no shell in between, so it does not expand $VAR anywhere in the config. mcp-remote does its own substitution on --header values, but only of the braced ${VAR} form, reading it from the process environment the env block supplies. A bare $BYTEKIT_API_KEY is passed through untouched and authenticates as that literal string — a guaranteed 401.
  • No space after the colon in Authorization:${AUTH_HEADER}. The header value carries the space (Bearer sk_live_xxx) instead. mcp-remote's README documents this as the workaround for a Cursor / Claude Desktop (Windows) bug where spaces inside args are not escaped when it invokes npx, mangling the value: "Authorization:${AUTH_HEADER}" // note no spaces around ':' with "AUTH_HEADER": "Bearer <auth-token>" // spaces OK in env vars.

Or skip the hosted endpoint entirely and run the local stdio server (Option 2 below), which Claude Desktop supports natively.

Option 2 — Local stdio (npx)

Run the server as a local subprocess over stdio. Nothing to install globally — npx fetches it on demand:

npx @hunt-labs/bytekit-mcp --api-key $BYTEKIT_API_KEY

Or set the key in your environment and omit the flag:

export BYTEKIT_API_KEY=sk_live_xxx
npx @hunt-labs/bytekit-mcp

Client config for a stdio server:

{
  "mcpServers": {
    "bytekit": {
      "command": "npx",
      "args": ["-y", "@hunt-labs/bytekit-mcp"],
      "env": {
        "BYTEKIT_API_KEY": "sk_live_xxx"
      }
    }
  }
}

API-key resolution order

The local server resolves the key in this order:

  1. --api-key <key> flag
  2. BYTEKIT_API_KEY environment variable

Tool inventory

ToolWhat it does
scrape_urlFetch a URL and return HTML, clean markdown, links, or images.
web_searchRun a web search and return ranked organic results.
screenshot_urlCapture a screenshot of a page (desktop/mobile, PNG/JPEG).
get_resultFetch a previously created screenshot by id.
get_accountReturn account details, plan, and current usage/quota.
list_docsList every page in the bundled ByteKit documentation.
search_docsSearch the bundled documentation.
get_docFetch the full markdown of one documentation page.

The server also exposes resources (bytekit://account, bytekit://screenshot/{id}) and prompts (summarize_webpage, extract_structured_data, research_topic) that MCP hosts can surface directly.

Limits

The hosted POST /mcp endpoint caps request bodies at 1 MB. MCP tool arguments are small (a URL plus a few options), so this comfortably covers every tool and prompt in the matrix above — including research_topic, the largest legitimate call, which carries a list of URLs. An oversized request gets a 413 with a JSON-RPC-shaped error body rather than a dropped connection.

Every route in the table below carries its own body-size limit, sized to that route's shape rather than reused from /mcp (a bulk endpoint's realistic payload is far larger than an MCP tool call). This covers both the capture/data create endpoints and the unauthenticated webhook-ingress receivers, which need a guard for the same reason — their handlers read the full body before any check runs:

EndpointLimitError
POST /v1/scrape, /v1/search, /v1/scrape/bulk, /v1/schema512 KB400 request_too_large
POST /v1/fetch512 KB400 request_too_large
POST /v1/screenshots512 KB400 request_too_large
POST /v1/monitors512 KB400 request_too_large
POST /v1/sitemap512 KB400 request_too_large
POST /v1/bulk4 MB pre-auth (chunked) / 32 MB fail-safe (declared length) / per-plan up to 28.7 MB400 request_too_large
POST /v1/fetch/bulk2 MB pre-auth (chunked) / 20 MB fail-safe (declared length) / per-plan up to 16.8 MB400 request_too_large
POST /v1/webhook-deliveries/{id}/retry64 KB400 request_too_large
POST /v1/webhooks/stripe (internal, Stripe ingress)256 KB400 (bespoke { error } body)
POST /webhooks/clerk (internal, Clerk ingress)256 KB400 request_too_large (bespoke { error } body)
POST /mcp1 MB413 (JSON-RPC error)

The two bulk endpoints are guarded in a two-tier shape, not by a single ceiling. A streamed body with no Content-Length header is capped at the small pre-auth limit (4 MB / 2 MB) before your API key is checked; a body that declares Content-Length is instead bounded there by a larger fail-safe (32 MB / 20 MB) rather than the real limit, since that branch reads nothing until your key is verified. Once your key is verified, a second check re-gates the body against your account's own max_bulk_size — sized off the documented custom production account's real max_bulk_size of 50,000 URLs or per-item configs (root CLAUDE.md: "50k bulk") — which reaches 28.7 MB / 16.8 MB for that account. A standard-plan account's effective ceiling is exactly the pre-auth limit; either tier's overrun returns 400 request_too_large.

Next steps