The Particle Pro MCP server is an OAuth 2.1 protected resource. There are no API keys, no shared secrets, and no static bearer tokens — every request carries a short-lived JWT minted by the Particle Pro Authorization Server and bound to the MCP resource via itsDocumentation Index
Fetch the complete documentation index at: https://docs.particle.pro/llms.txt
Use this file to discover all available pages before exploring further.
aud claim.
This page is for client implementers. If you are using a stock MCP client (Claude Code, Cursor, VS Code, Claude Desktop) the OAuth flow is automatic — see the Quickstart.
At a glance
| Protected resource | https://mcp.particle.pro |
| Resource metadata | https://mcp.particle.pro/.well-known/oauth-protected-resource (and /mcp sub-path) |
| Authorization Server | https://api.particle.pro |
| AS metadata | https://api.particle.pro/.well-known/oauth-authorization-server |
| JWKS | https://api.particle.pro/.well-known/jwks.json |
| Grant types | authorization_code, refresh_token |
| PKCE | Required, code_challenge_method=S256 only |
| Auth methods | none (public clients), client_secret_basic, client_secret_post |
| Scopes | mcp:read, mcp:write |
| Access token TTL | 15 minutes |
| Refresh token TTL | 30 days, rotated on every use |
Discovery
Start from the resource. Fetch the protected-resource metadata document:authorization_servers:
401 with a WWW-Authenticate header pointing at the resource-metadata document, so a client that doesn’t pre-fetch metadata still discovers the AS:
bearer token required, grant revoked or unknown) is in the response body, not the header.
Client registration
You have two ways to register a client.Dynamic Client Registration (RFC 7591)
The simplest path. POST to the registration endpoint with at leastclient_name and redirect_uris:
token_endpoint_auth_method:none(i.e. public client, PKCE-only)grant_types:["authorization_code", "refresh_token"]response_types:["code"]
token_endpoint_auth_method other than none) the response includes client_secret exactly once — store it securely, the AS does not return it again.
Client ID Metadata Document (CIMD)
Agents that already publish a metadata document at an HTTPS URL can skip DCR entirely and pass the URL itself asclient_id to /oauth/authorize. The AS fetches the document, validates it, and caches it. The CIMD spec is draft-ietf-oauth-client-id-metadata-document.
Use this when your agent runs in many places (you don’t want to register N clients) but has a stable identity (your domain).
Authorization code with PKCE
Generate a high-entropycode_verifier, then derive its S256 challenge:
response_type=code(only flow supported)client_id— from registration or CIMD URLredirect_uri— must match a value the client registeredcode_challenge+code_challenge_method=S256— PKCE is mandatoryresource=https://mcp.particle.pro— RFC 8707 audience binding; the AS rejects any other value
scope is optional. If omitted the AS issues mcp:read mcp:write by default. Naming an unknown scope is rejected (the AS will redirect with error=invalid_scope rather than silently up-scoping).
The user signs in (if not already), picks a project, and approves the requested scopes. The AS redirects back to your redirect_uri:
client_secret_basic— dropclient_idfrom the form body and sendclient_id:client_secretURL-form-encoded in an HTTP BasicAuthorizationheader.client_secret_post— keepclient_idin the form body and add aclient_secretfield alongside it.
token_endpoint_auth_method=none) keep client_id in the form body and send no secret.
Response:
Calling the MCP endpoint
Send the access token as a bearer in theAuthorization header. The MCP server only accepts header-borne tokens (bearer_methods_supported: ["header"]) — no query-string tokens, no form-body tokens.
- Verify the JWT signature against the rotating JWKS at
https://api.particle.pro/.well-known/jwks.json. - Confirm
iss=https://api.particle.pro,aud=https://mcp.particle.pro, andexpis in the future. - Look up the
grant_idclaim — the grant must still be active (not revoked, not user-disabled). - Confirm the token’s
sub,client_id, andproject_idclaims match the grant row (defense in depth against a buggy or compromised signer).
401 with a WWW-Authenticate challenge.
Refresh and rotation
When the access token nears expiry, exchange the refresh token:Revocation
Either side can revoke a grant:https://platform.particle.pro → Connected Applications. Once a grant is revoked, all access tokens issued from it stop validating immediately at the resource server (the grant lookup fails) and the refresh token can no longer be exchanged.
Audience binding (RFC 8707)
Every authorization request and every token request must includeresource=https://mcp.particle.pro. The AS rejects mismatches with error=invalid_target. The minted access token carries aud=https://mcp.particle.pro, and the MCP server rejects any token with a different aud — even a valid token issued for some hypothetical other Particle resource would not work here. This is the standard “confused deputy” safeguard.
Scopes
Two scopes today; finer-grained scopes can be added as the surface grows:| Scope | Granted access |
|---|---|
mcp:read | Read your Particle Pro data via MCP tools. |
mcp:write | Take actions on your behalf in Particle Pro via MCP tools. (All current tools are read-only — mcp:write is reserved for future write tools.) |
readOnlyHint: true; mcp:write is requested by default but does not unlock additional surface yet.
Key rotation
The AS uses RS256 with a rotating JWKS. The signer publishes the “next” key well before promoting it to “active” and keeps “retired” keys live long enough for outstanding tokens to expire (15-minute access-token TTL). Validators cache the JWKS for up to 5 minutes — a freshkid will be picked up within that window.
See also
- Quickstart — install snippets for stock MCP clients.
- Errors — how tool errors surface (different from REST
application/problem+json). auth_required— REST-side auth error code.