Endpoint
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: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.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 gets403 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.
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: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:
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: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: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 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 traces in observability.