OAuth 2.1
FieldMCP is a standard OAuth 2.1 Authorization Server. MCP clients (Claude Desktop, Cursor, custom apps) authenticate using the standard OAuth 2.1 flow with PKCE — no proprietary integration needed.
When an MCP client connects, FieldMCP handles everything: the farmer logs into John Deere, selects which organizations to share, and the MCP client receives tokens to make API calls.
How It Works
- MCP client discovers FieldMCP via
/.well-known/oauth-authorization-server - MCP client redirects to
/authorizewith PKCE challenge - Farmer logs into John Deere and selects organizations
- FieldMCP issues the MCP client a signed JWT access token + refresh token
- MCP client uses the JWT to call
/mcp
sequenceDiagram
participant Client as MCP Client
participant FMCP as FieldMCP
participant JD as John Deere
Client->>FMCP: GET /authorize
FMCP->>JD: redirect to JD login
Note over JD: farmer logs in
JD->>FMCP: callback with code
FMCP->>Client: auth code + redirect
Client->>FMCP: POST /token
FMCP->>Client: JWT + refresh token
Client->>FMCP: POST /mcp (Bearer JWT)
FMCP->>JD: JD API calls
JD->>FMCP: data
FMCP->>Client: tool resultsDiscovery
MCP clients discover FieldMCP's OAuth endpoints automatically:
# Authorization Server metadata (RFC 8414)
curl https://api.fieldmcp.com/.well-known/oauth-authorization-server
# Protected Resource metadata (RFC 9728)
curl https://api.fieldmcp.com/.well-known/oauth-protected-resource/mcp
# Public signing keys (JWKS)
curl https://api.fieldmcp.com/.well-known/jwks.jsonThe AS metadata includes a registration_endpoint for Dynamic Client Registration (RFC 7591). MCP clients like Claude Desktop use this to self-register automatically — no manual app creation needed.
Authorization Request
Redirect the user to /authorize with these parameters:
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Obtained via Dynamic Client Registration, or your enterprise app's UUID |
redirect_uri | Yes | Must exactly match a registered redirect URI |
code_challenge | Yes | PKCE S256 challenge |
state | Recommended | Opaque value for CSRF protection |
scope | Optional | Space-separated scopes (defaults to ag1 ag2 ag3 offline_access) |
resource | Optional | RFC 8707 resource indicator |
https://api.fieldmcp.com/authorize?
client_id=YOUR_APP_ID&
redirect_uri=https://yourapp.com/callback&
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
state=abc123
Token Exchange
Exchange the authorization code for tokens:
curl -X POST https://api.fieldmcp.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&\
code=AUTH_CODE&\
code_verifier=YOUR_PKCE_VERIFIER&\
client_id=YOUR_APP_ID&\
redirect_uri=https://yourapp.com/callback"Response:
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "opaque-refresh-token",
"scope": "ag1 ag2 ag3 offline_access"
}Token Refresh
Access tokens expire after 1 hour. Use the refresh token to get new ones:
curl -X POST https://api.fieldmcp.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token&\
refresh_token=YOUR_REFRESH_TOKEN&\
client_id=YOUR_APP_ID"Refresh tokens are rotated on each use (the old token has a 30-second grace period for retries). Refresh tokens expire after 90 days.
Token Revocation
Revoke a refresh token when disconnecting:
curl -X POST https://api.fieldmcp.com/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=YOUR_REFRESH_TOKEN&token_type_hint=refresh_token"Access tokens (JWTs) cannot be revoked — they expire naturally after 1 hour.
Using the Access Token
Pass the JWT in the Authorization header when calling the MCP endpoint:
POST /mcp
Authorization: Bearer eyJ...
Content-Type: application/json
The JWT contains the developer ID, farmer ID, and scopes. No X-Farmer-Id header is needed — the farmer is identified by the OAuth flow.
Connecting a Farmer
Farmers connect their John Deere accounts through the OAuth flow above. When using Claude Desktop or another MCP client, the connection happens automatically on first use — the farmer logs into John Deere and authorizes access.
You can also manage connections in the Dashboard.
Scopes
| Scope | Access |
|---|---|
ag1 | Fields, boundaries, farms, clients |
ag2 | Equipment, telemetry, operations |
ag3 | Agronomic data, prescriptions |
offline_access | Refresh token for long-lived access |
Errors
| Error | Cause | Resolution |
|---|---|---|
invalid_client | Unknown client_id | Check your app ID in the Dashboard |
invalid_redirect_uri | redirect_uri not registered | Register the URI in your app settings |
invalid_grant | Expired/replayed auth code or bad PKCE | Restart the OAuth flow |
access_denied | Developer subscription inactive | Check your subscription status |
invalid_token (401 on /mcp) | JWT expired or invalid | Refresh the access token |