buzzabout docs
MCP

Authentication

Two authentication paths for buzzabout's MCP server — x-api-key for headless agents, OAuth/JWT for interactive clients.

The buzzabout MCP server accepts two authentication paths on the same URL. Pick the one that matches your client.

PathBest forHow
x-api-key headerHeadless agents, CI, custom scripts, server-side LLM pipelinesSend x-api-key: bz_live_... on every request
OAuth → JWTInteractive MCP clients (Claude Desktop, IDE assistants, chat UIs)Client redirects to buzzabout, exchanges code for a JWT, sends Authorization: Bearer <jwt>

Both resolve to the same authenticated User in the server. Every tool sees the same identity regardless of how the request authenticated. Per-tool auth-path requirements are documented inline in the tools reference; headless callers that need to invoke the assistant should use the REST surface (POST /v1/ask) instead.

Endpoint

https://mcp.buzzabout-staging.com/mcp/

Streamable-HTTP transport. The trailing slash is required — the unslashed /mcp returns a 307 redirect that strips the request body in many MCP clients.

Path 1 — x-api-key

Mint a key in the web app under Settings → API keys → New key. Copy the value (bz_live_...) once; the rest is hashed and not retrievable again. Lifecycle and rotation are documented under REST authentication.

Send the header on every MCP request:

POST /mcp/ HTTP/1.1
Host: mcp.buzzabout-staging.com
x-api-key: bz_live_...
Content-Type: application/json
Accept: application/json,text/event-stream
agent.py
import asyncio
import os

from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client


async def main() -> None:
    headers = {"x-api-key": os.environ["BUZZABOUT_KEY"]}

    async with streamablehttp_client(
        "https://mcp.buzzabout-staging.com/mcp/",
        headers=headers,
    ) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()

            tools = await session.list_tools()
            for tool in tools.tools:
                print(tool.name)

            result = await session.call_tool(
                "buzzabout__list_datasets",
                arguments={"limit": 5},
            )
            print(result.content)


asyncio.run(main())
agent.ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://mcp.buzzabout-staging.com/mcp/"),
  {
    requestInit: {
      headers: { "x-api-key": process.env.BUZZABOUT_KEY! },
    },
  },
);

const client = new Client({ name: "my-agent", version: "0.1.0" });
await client.connect(transport);

const tools = await client.listTools();
for (const tool of tools.tools) {
  console.log(tool.name);
}

const result = await client.callTool({
  name: "buzzabout__list_datasets",
  arguments: { limit: 5 },
});
console.log(result.content);
curl -X POST https://mcp.buzzabout-staging.com/mcp/ \
  -H "x-api-key: $BUZZABOUT_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json,text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list"
  }'

Path 2 — OAuth → JWT

Interactive MCP hosts that support OAuth (Claude Desktop, several IDE assistants, chat UIs) discover the flow automatically via the WWW-Authenticate: Bearer resource_metadata="..." header.

The user-visible flow:

  1. The host attempts a tool call without credentials.
  2. The server responds 401 with a WWW-Authenticate header pointing at the OAuth metadata document.
  3. The host opens a browser tab to mcp.buzzabout-staging.com/mcp/oauth/authorize.
  4. The user signs in with their buzzabout account.
  5. The host exchanges the redirect code for a JWT and stores it locally.
  6. Subsequent requests carry Authorization: Bearer <jwt>.

The JWT carries the same User claims as an x-api-key request. No configuration is required on your side beyond pointing the host at the URL above — see Use in your agent for the host-side wiring.

Auth resolution internals

Each request hits a dual-auth ASGI middleware:

  1. Check x-api-key. If valid → resolve user, proceed.
  2. Otherwise fall back to Authorization: Bearer <jwt>. If valid → resolve user, proceed.
  3. If neither resolves → respond 401 with WWW-Authenticate: Bearer resource_metadata="...".

A single integration can mix transports cleanly: some hosts attach an api-key, others go through OAuth, and the server treats them the same.

Tool errors

Tool errors come back inside the MCP tool/call result as a structured JSON payload — same error_code taxonomy as the REST API:

{
  "error": {
    "code": "dataset_not_found",
    "message": "Dataset not found",
    "status": 404
  }
}

Match on code (stable); show message to humans. status mirrors the HTTP status the equivalent REST call would return.

Transport errors (401, 429) come back as MCP transport errors, not tool-level errors. Handle them at the SDK transport layer.

Next steps

On this page