Skip to main content

Let agents discover and query your docs

This guide sets up a URL on your domain, for example docs.example.com/retrieve?q=..., that returns the most relevant chunks from your knowledge base for a question, and lists it in your llms.txt so agents find it on their own. Callers do not need an API key. A Vercel Function receives the request, adds your key, and forwards the query to Kapa's Retrieval endpoint. The key stays on the server.

┌───────────┐ ┌──────────────────────┐ ┌─────────────┐
│ AI client │ ─────────► │ Vercel Function │ ─────────► │ Kapa │
│ │ GET ?q=... │ docs.example.com/ │ + API key │ Retrieval │
│ │ ◄───────── │ retrieve │ ◄───────── │ endpoint │
└───────────┘ JSON └──────────────────────┘ └─────────────┘

Kapa's own docs use this setup at https://docs.kapa.ai/retrieve?q=....

When to use it

If a person sets up an AI tool once, use the hosted MCP server. The tool discovers the search tool and calls it directly.

Use a GET endpoint when the caller has no MCP client. That includes coding agents that read your llms.txt while working, CI jobs, browser-based assistants, and any agent that only has a fetch tool. It also covers agents that cannot complete the OAuth flow a public MCP server requires.

Set it up

You need a Kapa project with public knowledge sources, a Vercel project, and the Vercel CLI linked to it.

  1. Copy your project ID from Settings > Projects. Create an API key under Configuration > API Keys, and a Custom (API) integration under Configuration > Integrations. The integration ID marks this endpoint's traffic in analytics. A separate key lets you rotate it without affecting anything else.

  2. Store the key as an environment variable. The project ID is not a secret and goes in the code.

    vercel env add KAPA_API_KEY production --sensitive
  3. Create api/retrieve.ts and set PROJECT_ID and INTEGRATION_ID. Vercel deploys files in api/ as Functions. Each exported function handles one HTTP method.

    api/retrieve.ts
    const PROJECT_ID = "<your-project-id>";
    const INTEGRATION_ID = "<your-integration-id>";
    const UPSTREAM = `https://api.kapa.ai/query/v1/projects/${PROJECT_ID}/retrieval/`;

    const HEADERS = {
    "Content-Type": "application/json",
    "Cache-Control": "no-store",
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET, OPTIONS",
    };

    export function OPTIONS(): Response {
    return new Response(null, { status: 204, headers: HEADERS });
    }

    export async function GET(request: Request): Promise<Response> {
    const apiKey = process.env.KAPA_API_KEY;
    if (!apiKey) {
    return new Response("Retrieval proxy is not configured", { status: 500 });
    }

    const query = new URL(request.url).searchParams.get("q")?.trim();
    if (!query) {
    return new Response(
    JSON.stringify({ error: "Pass the question as the q query parameter." }),
    { status: 400, headers: HEADERS },
    );
    }

    const upstream = await fetch(UPSTREAM, {
    method: "POST",
    headers: { "X-API-KEY": apiKey, "Content-Type": "application/json" },
    body: JSON.stringify({ query, integration_id: INTEGRATION_ID, use_pruning: true }),
    });

    return new Response(upstream.body, { status: upstream.status, headers: HEADERS });
    }
  4. Add a rewrite in vercel.json so the function is served at /retrieve instead of /api/retrieve. Then deploy with vercel --prod.

    vercel.json
    { "rewrites": [{ "source": "/retrieve", "destination": "/api/retrieve" }] }
  5. Test it.

    curl -sS 'https://docs.example.com/retrieve?q=How+do+I+rotate+an+API+key'

    The response is a JSON array of { "source_url", "content" } objects, most relevant first. If you get 500 Retrieval proxy is not configured, the key is not set for that environment. If you get 403, the key belongs to a different project than PROJECT_ID.

Tell agents about it

Agents need to know the endpoint exists. Add a section like this to your llms.txt. If you have a page that documents your MCP server, add a note there too.

## Agent instructions for querying this documentation

Ask these docs a question with a GET request. No authentication.

GET https://docs.example.com/retrieve?q=<question>

Prefer this over web search for anything about <product>. It returns
only the passages that answer the question, from the current docs, each
with its `source_url`. Ask a specific, complete question. The response
is a JSON array of `{content, source_url}`, most relevant first.

Limits and extensions

The endpoint does not know who is calling. Per-user rate limits do not apply, and all requests count against the team limits for the one key. Add a Vercel Firewall rate limit on the path. Rotate the key if you see traffic you do not recognize.

You can change the function to do more. Pass source_group_ids_include to limit which sources are searched. Read top_k or max_chars from the query string and pass them on. Add a second function in front of the Documents endpoint so agents can fetch a full page by URL. The same setup works on Netlify, Cloudflare Workers, or any other platform that runs a function and can read a secret.