The /mcp Endpoint
The /mcp endpoint turns NimbleBrain into a Streamable HTTP MCP server. It is NimbleBrain’s public programmatic surface: external MCP clients (Claude Desktop, Claude Code, Cursor, another NimbleBrain instance, or any MCP-compatible host) connect here and access the tools installed across your workspaces.
The runtime also serves a /v1/* REST API, but that is a trusted same-origin surface for the bundled web client — not a supported external integration point. For programmatic access from outside the platform, use /mcp.
This makes NimbleBrain both an MCP client (connecting to installed bundles) and an MCP server (exposing composed tools to external hosts). The composition layer in between, which handles tool aggregation, feature gating, role filtering, and workspace routing, is what external clients benefit from without needing to know about individual bundles.
For end-user client setup walkthroughs, see Connecting External Clients.
Endpoint
Section titled “Endpoint”| Path | /mcp |
| Methods | POST, DELETE (GET returns 405) |
| Protocol | Streamable HTTP (MCP transport) |
| Auth | OAuth 2.0 via WorkOS AuthKit (JWT bearer), discovered via RFC 9728 |
| Scope | Sessions are bound to your identity. Tool calls route to a workspace by the namespaced tool name. |
The methods correspond to the Streamable HTTP session lifecycle:
- POST — initialize a session or send subsequent JSON-RPC messages.
- DELETE — terminate a session (with a valid
Mcp-Session-Id). - GET — returns
405 Method Not AllowedwithAllow: POST, DELETE. NimbleBrain does not offer the optional GET-style server-to-client SSE channel; progress and task updates flow over the POST that started them. Spec-compliant clients fall back to POST-only automatically.
Authentication
Section titled “Authentication”Authentication is OAuth-based. There is no static API key.
The first time a client hits /mcp without a valid JWT, it receives a 401 with a WWW-Authenticate header:
Bearer error="unauthorized", error_description="Authorization required", resource_metadata="https://your-instance/.well-known/oauth-protected-resource"Clients that implement RFC 9728 (Protected Resource Metadata) and RFC 8414 (Authorization Server Metadata) — Claude Code, Claude Desktop, and Cursor all do — follow the discovery chain automatically, open a browser for user login against AuthKit, and attach the returned JWT on subsequent requests.
Adapter configuration (dev, oidc, or workos) lives in instance.json. See auth adapters for the full setup, including the workos adapter and authkitDomain required to enable MCP OAuth.
OAuth discovery endpoints
Section titled “OAuth discovery endpoints”NimbleBrain serves two unauthenticated discovery endpoints that MCP clients fetch during the OAuth flow. Both return 404 MCP OAuth not configured unless the workos adapter has an authkitDomain set.
GET /.well-known/oauth-protected-resource
Section titled “GET /.well-known/oauth-protected-resource”RFC 9728 Protected Resource Metadata. Clients fetch this after the 401’s WWW-Authenticate header points them here. It tells them which authorization server to use.
{ "resource": "https://your-instance", "authorization_servers": ["https://your-subdomain.authkit.app"], "bearer_methods_supported": ["header"]}GET /.well-known/oauth-authorization-server
Section titled “GET /.well-known/oauth-authorization-server”RFC 8414 Authorization Server Metadata, proxied from AuthKit for older MCP clients that look for this endpoint instead of Protected Resource Metadata.
The flow
Section titled “The flow”- Client
POSTs to/mcpwith no token and gets401+WWW-Authenticatecarrying theresource_metadataURL. - Client fetches
/.well-known/oauth-protected-resourceto learn the authorization server (AuthKit). - Client runs the OAuth authorization-code flow against AuthKit, opening a browser for user login.
- AuthKit issues a JWT; the client attaches it as
Authorization: Bearer <jwt>on every/mcprequest thereafter.
NimbleBrain verifies each access token against AuthKit’s JWKS endpoint (RS256, issuer validation). When organizationId is set on the adapter, only members of that WorkOS organization can authenticate.
Sessions
Section titled “Sessions”Each initialize creates a new MCP session tracked server-side and addressed by the Mcp-Session-Id response header. Include that header on every subsequent request in the session.
Sessions are closed on DELETE /mcp (with a valid Mcp-Session-Id), transport close, idle-TTL eviction, or server shutdown.
Session-miss reasons
Section titled “Session-miss reasons”When the server can’t serve a request because the session isn’t available, the 404 response includes error.data.reason:
{ "jsonrpc": "2.0", "error": { "code": -32000, "message": "Session not found", "data": { "reason": "not_found" } }, "id": null}| Reason | Meaning |
|---|---|
not_found | The session registry has no record. Most often idle-TTL eviction, or the session never existed. |
unavailable | The session exists in the registry, but the live transport isn’t on this process. Possible causes: process restart since initialize, or a sticky-routing miss. |
Spec-compliant clients re-initialize on either reason.
Running behind a reverse proxy
Section titled “Running behind a reverse proxy”The OAuth resource URL advertised on /.well-known/oauth-protected-resource (and the one in the WWW-Authenticate header) must match the scheme the client connected on. If you terminate TLS at an upstream proxy, the pod sees an internal http:// connection while the client used https://, which makes OAuth resource validation fail.
NimbleBrain honors X-Forwarded-Proto to derive the advertised scheme. Configure your proxy (ALB, nginx, Caddy) to set it based on the actual client connection. The Host header (url.host) is used verbatim; X-Forwarded-Host is deliberately not honored.
What’s exposed
Section titled “What’s exposed”The endpoint aggregates:
- Tools from installed and running bundles across your workspaces, plus identity-owned tools.
- Tool discovery —
tools/listreturns every tool visible to the caller. - Tool execution —
tools/callroutes to the correct workspace and bundle based on the namespaced tool name.
Two filters apply to both tools/list and tools/call:
- Feature flags — tools whose controlling flag is
falseare excluded (for example, theskills__*authoring tools whenskillManagementisfalse). See Feature Flags. - Role — admin-only tools (such as
nb__manage_users,nb__manage_workspaces) are excluded when the caller’s role is not admin or owner.
Testing manually
Section titled “Testing manually”In dev mode (no auth), you can hit the endpoint with curl:
# Initialize a sessioncurl -i -X POST http://localhost:27247/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-03-26", "capabilities": {}, "clientInfo": { "name": "curl", "version": "1.0" } } }'Extract the Mcp-Session-Id response header and use it on subsequent calls:
curl -X POST http://localhost:27247/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "Mcp-Session-Id: <session-id>" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":2}'With auth enabled, include Authorization: Bearer <jwt> on every request.
Related
Section titled “Related”- Connecting External Clients — setup walkthroughs for Claude Code, Claude Desktop, and Cursor.
- Auth adapters —
dev/oidc/workosconfiguration ininstance.json. - Feature Flags — full list of flags and enforcement points.