Each BeforeQuery knowledge base ships a built-in MCP server (JSON-RPC 2.0 over Streamable HTTP). Any MCP-compatible client — AI-powered IDEs, desktop assistants, agent frameworks — can search and query your knowledge base as native tools.

Endpoint

Authentication (client key): X-Client-Key header, Authorization: Bearer bq_pk_..., or ?client_key= query parameter. One URL for every knowledge base — the client key selects which one, because a key belongs to exactly one. Nothing in the URL to fill in.

A readable address

Give the knowledge base an address under Knowledge Base → Integrations → Connect to AI Tools and the same server answers on something that names it:
The address you type is the last part — acme. Copy the finished URL from the dashboard rather than assembling it by hand.

What makes a valid address

The rules are DNS’s, not ours. The address is a hostname label even where it appears in a path, so that a knowledge base keeps the same name if a deployment ever moves it onto one: It’s stored lowercased, since hostnames are case-insensitive and Acme and acme are one host. Some names are reserved: infrastructure the deployment needs for itself (api, app, cdn, www, mail, static, health…) and names someone could use to impersonate us (admin, support, security, billing, beforequery…). A stranger asked to install mcp.beforequery.com/support has no way to tell it isn’t ours. Changing the address is a key rotation, not a rename: everyone who installed the old URL loses the server the moment it stops answering. Addresses are globally unique across all live knowledge bases, so a taken one comes back as “already taken, pick another”.
Self-hosting. Set APP_MCP_HOST=mcp.example.com and a knowledge base named acme answers at https://mcp.example.com/acme. It needs one DNS record and one ordinary certificate — no wildcard anywhere.It’s empty by default, which disables readable addresses entirely. Nothing degrades: every knowledge base is still reached at /mcp with its client key. What you give up is OAuth, which needs a URL naming a knowledge base before any credential exists.A subdomain form (acme.mcp.example.com) was supported and removed. It needed a wildcard DNS record and a wildcard certificate — Let’s Encrypt issues wildcards only over the DNS-01 challenge, and a wildcard one level down isn’t covered by Cloudflare’s Universal SSL at all — so it was an address many deployments simply couldn’t turn on.Pick a dedicated hostname: every name under it becomes claimable by a customer.Scheme and port follow your deployment’s base URL, so a local run prints http://localhost:8280/acme rather than an https address that nothing answers on.
Pointing your own DNS record at this server gains you nothing. The address only selects a knowledge base — the client key still has to be valid, still has to be enabled for MCP, and still has to belong to the knowledge base the address named. The two must agree.An address that doesn’t exist returns 404, not 403: there’s no credential involved yet, and confirming that a name exists would let anyone enumerate customers.

Turn on MCP for a key

MCP access is a permission on the client key, not on the origin allowlist. Tick Allow MCP access on a public key; a key without it gets 403 MCP_NOT_ENABLED. This is a separate permission because an MCP client is not a browser and sends no Origin header — so a key restricted to your own domain would be refused on every MCP call. Keys that already had an origin allowlist were left with MCP off, so nothing started serving MCP without you asking; new keys default to on.
Issue a dedicated key for MCP. rate_limit_per_min is per key, so one key shared by your widget and every reader who installed the server shares one quota — and revoking it after abuse takes the widget down too.

Supported methods

initialize, tools/list, tools/call, ping. initialize returns instructions naming the knowledge base (“These tools search the Acme documentation…”). Clients put that in the system prompt; without it a model faced with four generically-named tools often won’t call them at all and will answer from training data instead.

Tools

get_documents takes up to 10 URLs per call, and each page is truncated at 20,000 characters. Search returns passages, which is the right unit until one gets cut mid-procedure — and sources with no public URL at all (uploaded files, web clips, connector content behind someone else’s login) can’t be read in full any other way.
Scope is a property of the key, never a tool argument. No tool takes a knowledge-base or group parameter, so the calling model can’t widen what it reaches by asking. Every tool applies the key’s allowed_groups and excludes restricted documents — get_documents included, since it bypasses retrieval and would otherwise bypass every check retrieval performs, and list_sources, since source names alone say what a knowledge base holds. A document scoped away and a URL never indexed look identical.Internal knowledge bases have no public surface and are not reachable here at all.

Install it

Copy the ready-made snippet from Knowledge Base → Integrations → Connect to AI Tools — it fills in your address and key, and has a tab per tool. They differ in more than formatting, so copy the one for your editor rather than adapting another:
VS Code keys its servers under servers rather than mcpServers and wants an explicit type — a Cursor block pasted into it does nothing. Codex’s codex mcp add takes a stdio command, so a remote server has no CLI form there. Any other client takes the URL and the header directly: it is JSON-RPC 2.0 over Streamable HTTP, and the key is accepted as X-Client-Key, as Authorization: Bearer, or as ?client_key=. Without an address, the URL is https://api.agents.beforequery.com/mcp — everything else is the same, and there is nothing to substitute into it.

Sign in instead of sharing a key

Turn on Let anyone connect with a Google or GitHub sign-in and the install command carries no credential at all — drop the --header flag and the headers / http_headers line:
The editor is challenged on first use and opens a browser, where the reader verifies with Google or GitHub. It’s standard OAuth 2.1 — dynamic client registration, PKCE (S256 required), rotating refresh tokens, single-use authorization codes — so any compliant MCP client handles it without configuration. This is what to use when you’d otherwise be pasting one key into a dozen editors: nobody holds a shared secret, and access is per person. It requires an address, because the discovery documents live alongside one and the shared /mcp endpoint names no knowledge base for a credential-less caller to be challenged about. On a self-hosted install that also means APP_MCP_HOST has to be set — the dashboard disables the toggle until it is, rather than storing a flag no client can act on. Internal knowledge bases are excluded here as they are everywhere else public.

Call it from the agents SDK

@beforequery/agents wraps the MCP tools with typed methods (the initialize handshake happens lazily):

Raw JSON-RPC example

One server for your whole team

The server above exposes one knowledge base and is scoped by a client key — right for publishing docs to readers outside your workspace. For your own team there is a second server that authenticates a person instead:
It resolves every knowledge base the signed-in member may chat in, across every workspace they belong to, and searches all of them at once — one endpoint per employee rather than one key per knowledge base. Its tools add list_knowledge_bases, and search_docs / ask_question / get_documents / list_sources accept knowledge_base_ids, group_ids and source_ids (each intersected with what the caller may read, never widened). Restricted documents are included, as they are everywhere else a workspace member looks. This is the only MCP surface that reaches an internal knowledge base.

Sign in to it

Install it with no credential at all:
The editor is challenged on first use and opens a browser, which lands on your own sign-in page — password, Google, GitHub, SAML or OIDC, whatever your workspace already uses. Approve the editor and it holds a token bound to your account. This is the form to hand to a team, because it is the only one that enforces per person access. A pasted credential is as transferable as the string it is; a sign-in is not. Someone without permission signs in and reaches nothing, and the knowledge bases you can search are resolved on every request — so granting or removing someone’s access takes effect on their next question rather than at their next login.

Headless clients

A script, a CI job or an agent runtime cannot open a browser. For those, create a personal access token at Profile → Access tokens and install it as a header:
The token is shown once, on creation, and stored hashed — if you lose it, issue another. It carries no expiry unless you set one, you may hold ten at a time, and revoking one takes effect immediately. It is accepted on this endpoint and nowhere else: presented to any other route it is refused, so what it can do is exactly what this server does — search and answer from the knowledge bases you may already chat in. It cannot create another token either, so a leaked one cannot renew itself.
The dashboard’s own session token is also accepted here, which is convenient for a quick test. Don’t install with it: it expires after 7 days, and it is your whole session — the same credential that can delete a knowledge base or read billing — sitting in cleartext in an editor’s config file. Use an access token.
MCP calls are recorded as mcp traces in observability.