skip to content

Generic MCP client

Connect any MCP client to the broker over Streamable HTTP with OAuth discovery, using curl to check each step.

awaiting reviewupdated view markdown ->

Tier 3: protocol-level instructions checked live against the broker on 2026-10-21. This page makes no claim about a specific client. It is the fallback for a client that is not in the support matrix, and the reference for what a compliant client does under the hood.

The transport

The broker serves MCP Streamable HTTP at one endpoint:

https://agentregistrar.dev/mcp
  • Requests are POST with a JSON-RPC 2.0 body.
  • The client sends Accept: application/json, text/event-stream. A response may be a JSON body or an event stream.
  • Every request needs Authorization: Bearer <token>, including initialize. An unauthenticated request gets 401 before any JSON-RPC method runs.
  • The broker opens connections with the classic MCP initialize handshake. After initialization, clients send the negotiated protocol revision in MCP-Protocol-Version.
  • The server advertises tools and resources. It does not advertise prompts.

The token is an MCP bearer token issued by the broker's OAuth server. It is not an agent assertion. An assertion is minted later by identity_prove and sent only to the relying party's agent_signup endpoint, never to /mcp.

The OAuth chain

  1. An unauthenticated request returns 401 with a WWW-Authenticate challenge naming the protected-resource metadata.
  2. GET /.well-known/oauth-protected-resource names the resource (https://agentregistrar.dev/mcp) and the authorization server.
  3. GET /.well-known/oauth-authorization-server gives the authorization, token, registration and JWKS endpoints, the supported grant types, S256 PKCE and the supported scopes.
  4. The client registers itself: a Client ID Metadata Document URL as client_id, or POST /api/oauth/register for dynamic registration.
  5. The client opens /oauth/authorize with response_type=code, code_challenge, code_challenge_method=S256, its client_id and a loopback redirect URI, and the human approves.
  6. The client exchanges the code at /api/oauth/token with the code_verifier, then calls /mcp with the bearer token.

The broker accepts loopback redirect URIs on any port, and HTTPS redirect URIs on any host, for dynamic registration. It supports public clients (token_endpoint_auth_method: none) and client_secret_post.

Check the discovery documents

Start with the unauthenticated request and read the challenge:

curl -sS -D - -o /dev/null https://agentregistrar.dev/mcp

Live output, headers only:

HTTP/2 401
www-authenticate: Bearer resource_metadata="https://agentregistrar.dev/.well-known/oauth-protected-resource", scope="mcp:tools tos:accept signup:free_tier"

Then read the two metadata documents:

curl -sS https://agentregistrar.dev/.well-known/oauth-protected-resource
curl -sS https://agentregistrar.dev/.well-known/oauth-authorization-server

Live output:

{
  "resource": "https://agentregistrar.dev/mcp",
  "authorization_servers": ["https://agentregistrar.dev"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["mcp:tools", "tos:accept", "signup:free_tier"]
}
{
  "issuer": "https://agentregistrar.dev",
  "authorization_endpoint": "https://agentregistrar.dev/oauth/authorize",
  "token_endpoint": "https://agentregistrar.dev/api/oauth/token",
  "registration_endpoint": "https://agentregistrar.dev/api/oauth/register",
  "jwks_uri": "https://agentregistrar.dev/.well-known/jwks.json",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["none", "client_secret_post"],
  "code_challenge_methods_supported": ["S256"],
  "client_id_metadata_document_supported": true,
  "scopes_supported": ["mcp:tools", "tos:accept", "signup:free_tier"]
}

Both returned 200 application/json with Access-Control-Allow-Origin: *. The JWKS returned 200 application/json with one key.

Register a client

Dynamic registration takes a client name and at least one redirect URI:

curl -sS -X POST https://agentregistrar.dev/api/oauth/register \
  -H 'Content-Type: application/json' \
  -d '{
    "client_name": "my-mcp-client",
    "redirect_uris": ["http://127.0.0.1:49731/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"],
    "token_endpoint_auth_method": "none"
  }'

A live run on 2026-10-21 returned 201 with a body in this shape:

{
  "client_id": "cli_<ulid>",
  "client_id_issued_at": 1792607788,
  "client_name": "my-mcp-client",
  "redirect_uris": ["http://127.0.0.1:49731/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}

A redirect URI that is neither loopback nor HTTPS is rejected with 400:

{"error":"invalid_redirect_uri","error_description":"All redirect_uris must be loopback (http://127.0.0.1, http://localhost) or HTTPS URLs."}

A client that supports Client ID Metadata Documents skips this call and sends its metadata-document URL as the client_id; the broker fetches and caches it. The metadata advertises client_id_metadata_document_supported: true.

Call the server

Without a token, initialize and tools/list both return 401. That is the expected result, not a transport failure:

curl -sS -X POST https://agentregistrar.dev/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl-check","version":"0.0.0"}}}'

Live output:

{"jsonrpc":"2.0","error":{"code":-32001,"message":"Unauthorized: Missing, invalid, expired, or revoked MCP Bearer token."},"id":null}

With a token from your own OAuth session, the same request returns the initialization result. Replace <token> with the bearer token the client obtained; never commit a real token:

curl -sS -X POST https://agentregistrar.dev/mcp \
  -H "Authorization: Bearer <token>" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl-check","version":"0.0.0"}}}'

List the tools:

curl -sS -X POST https://agentregistrar.dev/mcp \
  -H "Authorization: Bearer <token>" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'

The result contains nine tools: identity_register, identity_whoami, identity_signup, identity_prove, identity_record_signup, inbox_list, inbox_read, inbox_wait_for_email and inbox_send. Input schemas are published by tools/list; the human-readable contract is in the reference.

A first identity call is:

curl -sS -X POST https://agentregistrar.dev/mcp \
  -H "Authorization: Bearer <token>" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"identity_whoami","arguments":{}}}'

The result names the agent bound to the session, its inbox address and its scopes. A bare identity_whoami auto-provisions the broker defaults, opencode-agent with harness: "opencode-v2", when the session has no agent; call identity_register with a name and harness first to label the agent for this client. If the call returns 401, the token is missing or expired; if it returns 403, the human account has not signed the master agreement or is suspended.

What remains unverified

The discovery documents, the 401 challenge, the DCR success and error responses, and the token endpoint's invalid_grant response were checked live. The authenticated half, initialize and tools/list with a real token, was not executed here, because completing OAuth requires a human in a browser. The tool names come from the broker's tool schema, not from a live authenticated response on this machine.

Next step

For a client-specific path, return to the support matrix. For the failures that stop this chain, see OAuth troubleshooting. For the full signup, see the agent quickstart.

sections

type to search.

up/down navigateenter selectesc close