Reference

MCP client guard

Screen dynamic client registrations and the accounts those clients bind to.

Registration endpoint

POST https://nolgard.com/v1/mcp/register
{"secret":"sk_…","clientId":"c_7f21","clientName":"Claude","redirectUris":["https://claude.ai/api/mcp/auth_callback"],"ip":"198.51.100.9","userAgent":"…"}

{"decision":"allow","reasons":[]}

Call this inside your Dynamic Client Registration endpoint, before you persist the client. A remote MCP server has to accept open registration under the MCP authorization spec (2026-07-28), so the registration itself is the only place to judge the client.

Registration request fields

FieldTypeNotes
secretstringRequired. Site secret.
clientIdstringRequired. The client id you are about to issue, up to 256 characters.
clientNamestringOptional. The name the client claims, up to 200 characters.
redirectUrisstring[]Required. 1 to 10 redirect URIs.
ipstringOptional. IP address of the registering caller.
userAgentstringOptional. User agent of the registering caller.

Response: decision is allow, challenge or block, with reasons.

Registration reasons and defaults

ReasonDefaultDecision
mcp_register_burstMore than 10 registrations an hour from one network prefix, IPv4 /24 or IPv6 /48 (networkRegistrations 10), or more than 500 an hour for the site (siteRegistrations 500)challenge
mcp_redirect_insecureA redirect that is neither https nor loopback http per RFC 8252, an IP-literal host that is not loopback, or userinfo or a fragment in the URI. Private-use schemes such as cursor:// are allowedblock
mcp_name_spoofThe client name claims Claude or ChatGPT while sending the browser to another web host. The documented callbacks are https://claude.ai/api/mcp/auth_callback and https://chatgpt.com/connector/oauth/… Native apps on loopback or custom schemes are never spoofsblock
mcp_redirect_spreadMore than 3 distinct redirect hosts (redirectHosts 3)challenge

Bind endpoint

POST https://nolgard.com/v1/mcp/bind
{"secret":"sk_…","clientId":"c_7f21","accountId":"user_42"}

{"decision":"allow","reasons":[]}

Call this after the user finishes OAuth consent, when the client becomes linked to an account. decision is allow, limit or block.

ReasonDefaultDecision
mcp_client_accountsOne client bound to more than 5 accounts in a day (clientAccounts 5): a resold or shared clientlimit
mcp_account_clientsOne account binding more than 10 new clients in a day (accountClients 10): a client farmlimit
mcp_client_blockedThe client was blocked at registrationblock
mcp_client_unregisteredThe client never passed registration. Telemetry onlyno change

Errors

StatusError
400invalid-input
401invalid-secret
403read-only (demo site)
429rate-limited

Webhook

mcp.registration
{"clientIdHash":"a19f…","clientName":"Claude","decision":"block","reasons":["mcp_name_spoof"]}

Fires on a blocked registration, once per network per day. See Webhooks and clawback.

SDK

const registration = await nolgard.mcp.register({
  clientId,
  clientName: metadata.client_name,
  redirectUris: metadata.redirect_uris,
  ip: clientIp
});
if (registration.decision === 'block') return reject();

const bind = await nolgard.mcp.bind({ clientId, accountId: user.id });

See SDKs.

Per-client usage abuse

Registration and binding cover who the client is. For what it then does, pass the OAuth client_id as apiKeyId to /v1/usage and /v1/spend; the API key guard then tracks that client like any other key.

Dashboard and data retention

Settings → MCP clients shows registrations, bindings and the thresholds behind them. All defaults are owner-editable: networkRegistrations 10, siteRegistrations 500, redirectHosts 3, clientAccounts 5, accountClients 10.

Client ids are stored only as salted hashes. Client name and redirect hostnames are kept 30 days.

Limits

  • Defaults are logical starting points rather than measured guarantees. Tune them for your client population.
  • Shared office networks and CI runners register from one prefix and can hit the burst threshold.
  • A legitimate client with several deployment hosts can trip redirect spread.
  • Name checks cover Claude and ChatGPT callbacks only. Any other brand name is not verified.
  • Bind counts reflect one day. A shared client used by a small team looks like a resold client.
  • Infrastructure rate limits still matter; this guard judges clients rather than request volume.