MCP server
Call the JOGL Network API as tools from an LLM agent over Model Context Protocol.
The MCP server exposes the same handlers as the REST API as tools an LLM agent can call, over stateless JSON-RPC 2.0. Authentication, scopes, rate limits, and every community fence are identical to the HTTP surface because both transports call the same shared handlers — they can't diverge.
Endpoint
A single HTTP POST endpoint (stateless — no sessions):
https://my.jogl.network/mcp- OAuth one-click connector → this branded URL is required. It is the resource identifier
the WorkOS AuthKit tokens are bound to (the expected JWT
aud), and the host that serves RFC 9728 discovery. Pointing an OAuth client at the raw Supabase function URL breaks the discovery/token handshake. - Static
jogl_*API key → the same branded URL works, and it is what the app hands you. The raw Supabase function URL (https://<project-ref>.supabase.co/functions/v1/mcp, the same project ref as the REST base URL) reaches the same server, because the branded host is a transparent proxy in front of the function. The snippets below use the branded URL, which needs no ref.
The in-product Settings → API/MCP → "Connect a tool" panel hands out that /mcp endpoint in
both the OAuth and the static-key snippets. It falls back to the raw function URL only on
preview or local builds, where no branded host exists — that URL stays usable with a static key
anywhere.
On the wire it is a valid stateless Streamable-HTTP MCP server: it answers a POST with a
single JSON response and negotiates MCP-Protocol-Version (negotiated through 2025-11-25,
negotiating newer clients — including the modern 2026-07-28 era — down; 2024-11-05 is
accepted on the header but not negotiated, since its HTTP+SSE transport isn't hosted here).
A GET probe is answered by intent: an unauthenticated GET
returns HTTP 401 with a WWW-Authenticate header pointing at the RFC 9728
protected-resource metadata — this is the OAuth discovery challenge, not a failure, and a
connector follows it. An authenticated GET returns 405 (there is no standalone GET SSE
channel; progress is streamed only inline on a POST tools/call).
Progress streaming for long calls. There is one exception to the single-response rule: for
a tools/call where the client sends a progressToken and includes
Accept: text/event-stream, the server streams the response as SSE, emitting periodic
notifications/progress heartbeats while the tool runs and the final JSON-RPC result as the
last event. Each heartbeat resets the client's request timeout, so a long search can outlive
an agent client's ~60s ceiling. Clients that don't opt in (no progressToken, or no SSE in
Accept) get the ordinary single JSON response — use the async search job contract instead
(see search / get_search_result).
Authentication
Send your API key on every request (including initialize and tools/list, so the tool
surface isn't enumerable without a key):
Authorization: Bearer jogl_live_…The same header also accepts a short-lived OAuth 2.1 access token (a JWT) issued through
the WorkOS AuthKit connector — the one-click connector path — verified against its
configured issuer/audience; an ordinary Supabase app-session token is not accepted. An
invalid, revoked, or expired static key returns a JSON-RPC error -32001 inside HTTP 200, and
so does a rate-limit hit (with data.retryAfterSeconds); a missing credential or a bad
OAuth token returns HTTP 401 with a WWW-Authenticate challenge so the connector can run the
RFC 9728 discovery/refresh handshake. That 401 is reached only by a well-formed request
carrying an id — do not build a client that waits for it on any other request shape.
Unparseable JSON, a batch, or a malformed envelope is answered with a JSON-RPC error inside
HTTP 200 before authentication is consulted at all, and a notification (no id) is
answered with the empty 202 whether or not the credential was good.
A few wire details worth knowing: JSON-RPC batches are not supported (send one request per
POST); a notification is answered with an empty 202; the SSE progress heartbeat fires every
5 seconds; and the REST Idempotency-Key header has no MCP equivalent, so retry the write
tools with care.
Tools
Each tool is 1:1 with a REST endpoint and enforces the same scope + fences:
| Tool | Scope |
|---|---|
get_me | (none) |
search / get_search_result | search:read |
get_my_profile / get_member / list_members | profile:read |
self_enrich / get_my_enrich_run | self:enrich |
enrich_community / get_run_status | enrich:write / enrich:read |
add_members / erase_member | member:write |
Searches started through the search tool are billed exactly like the REST endpoint —
see Credits.
Connecting a client
Claude Code
claude mcp add --transport http --scope user jogl-network \
https://my.jogl.network/mcp \
--header "Authorization: Bearer jogl_live_…"--scope user stores it in your user config so it's available in every project. Verify with
claude mcp list (it should show ✓ Connected). Tools become callable on the next
session start.
Project-scoped .mcp.json (never commit a key)
{
"mcpServers": {
"jogl-network": {
"type": "http",
"url": "https://my.jogl.network/mcp",
"headers": { "Authorization": "Bearer ${JOGL_API_KEY:-}" }
}
}
}Use the empty-default form ${JOGL_API_KEY:-} (not a bare ${JOGL_API_KEY}) so an unset
variable doesn't break parsing of the whole file. Export JOGL_API_KEY in your shell (local)
or set it in the environment's variables (Claude Code on the web).
Claude Desktop (static key)
Desktop's connector UI is OAuth-only, so for a static key bridge through
@automattic/mcp-remote in
claude_desktop_config.json, keeping the key in env:
{
"mcpServers": {
"jogl-network": {
"command": "npx",
"args": [
"-y", "@automattic/mcp-remote",
"https://my.jogl.network/mcp",
"--header", "Authorization:${AUTH_HEADER}"
],
"env": { "AUTH_HEADER": "Bearer jogl_live_…" }
}
}
}For the OAuth one-click connector path (Claude Desktop, Claude.ai, and other OAuth-capable clients), use the in-product Settings → API/MCP → "Connect a tool" panel — it walks you through the flow with the correct URL pre-filled.