Pear MCP integration guide
Build a Pear MCP integration with authentication, volume attribution, account selection, and trading tools.
Use this guide to build an MCP client or a server-side integration for Pear. If you only want to connect an existing MCP client, read the Orchard MCP user guide.
Integration flow
A complete trading flow has eight steps:
- Connect to the Pear MCP endpoint.
- Authenticate the user with OAuth 2.0 or an API key.
- Call
list_trade_accountsand select a trade account. - Call
sync_accountbefore you read positions. - Call read tools to find assets and review account data.
- Call a
plan_*tool and show the plan to the user. - After user approval, call the matching
execute_*tool. - Sync the account and check the execution result.
A read-only integration uses steps 1 through 5. It does not need the write scope.
Choose an authentication method
Pear supports two authentication methods.
| Method | Use it for | Credential |
|---|---|---|
| OAuth 2.0 | A client where a user signs in and approves access | Bearer access token |
| API key | A trusted server-side integration | x-api-key header |
Use OAuth 2.0 for a user-facing client. Do not put an API key in browser code.
Authentication does not connect an exchange account. Users connect and manage trade accounts in the Pear application. Never ask a user to send exchange credentials through an MCP tool.
Service contract
| Item | Value |
|---|---|
| MCP endpoint | https://mcp.pearprotocol.io/mcp |
| Transport | Streamable HTTP with JSON responses |
| Health endpoint | GET https://mcp.pearprotocol.io/health |
| Protected-resource metadata | GET https://mcp.pearprotocol.io/.well-known/oauth-protected-resource/mcp |
| OAuth authorization server | https://pro-gateway.pearprotocol.io |
| Authentication | OAuth 2.0 bearer token or x-api-key |
| Read scope | mcp:read |
| Write scope | mcp:write |
| Request limit | 100 MCP HTTP requests per authenticated user in 60 seconds |
Connect and authenticate
OAuth 2.0 flow
The Pear authorization server uses the authorization code flow with PKCE S256. It supports dynamic client registration and refresh tokens. The client is public. Set token_endpoint_auth_method to none.
Use this flow:
- Send an unauthenticated request to the MCP endpoint.
- Read the
WWW-Authenticateresponse header. - Get the RFC 9728 metadata URL from
resource_metadata. - Get the protected-resource metadata from that URL.
- Get the authorization server URL from
authorization_servers[0]. - Get the authorization server metadata.
- Register the application at the listed
registration_endpointwhen you do not have a client registration. - Redirect the user to the listed
authorization_endpoint. - Send an authorization code request with PKCE S256.
- Let the Pear page handle sign-in and consent.
- Exchange the authorization code at the listed
token_endpoint. - Send the access token in the
Authorization: Bearer <access-token>header. - Use the refresh token when the access token expires.
Store state and the PKCE verifier in one short-lived authorization transaction. Compare the returned state with the stored value. Stop the flow when the values do not match.
Request only the scopes that the application needs.
| Scope | Access |
|---|---|
mcp:read | 13 read tools and the pear://asset-filters resource |
mcp:write | 16 write tools, including all plan_* tools |
mcp:read mcp:write | All tools and resources |
Register an OAuth client
Send this request to the registration endpoint:
POST <registration_endpoint>
Content-Type: application/json
{
"redirect_uris": ["https://client.example.com/oauth/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"client_name": "Example MCP Client"
}The redirect URI must use HTTPS. Pear also accepts an HTTP redirect URI for localhost, 127.0.0.1, or ::1.
Request an authorization code
Send these parameters to the authorization endpoint:
response_type=code
client_id=<oauth-client-id>
redirect_uri=<registered-redirect-uri>
scope=mcp:read mcp:write
state=<random-state>
code_challenge=<base64url-sha256-verifier>
code_challenge_method=S256Exchange the authorization code
Send the returned code as form data:
POST <token_endpoint>
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=<oauth-client-id>&redirect_uri=<registered-redirect-uri>&code=<authorization-code>&code_verifier=<pkce-verifier>The OAuth client_id identifies the OAuth application. It does not identify the integration for volume attribution.
API key flow
Send the API key in the x-api-key header on each MCP request.
API keys have these scopes:
| API key scope | MCP scopes | Access |
|---|---|---|
read | mcp:read | Read tools only |
read_write | mcp:read, mcp:write | All tools |
You cannot create or revoke an API key through MCP. A signed-in user can create a key in the Pear application. The user can also call POST /api-keys on the Pear gateway.
POST https://pro-gateway.pearprotocol.io/api-keys
Authorization: Bearer <first-party-session-token>
Content-Type: application/json
{
"label": "Example MCP integration",
"scope": "read_write",
"expiresAt": "2027-01-01T00:00:00Z"
}expiresAt is optional. The response returns the raw key one time. Store the key in a secret manager.
Use GET /api-keys to list keys. Use DELETE /api-keys/:id to revoke a key.
The MCP validates a key through GET /auth/api-key/me. An unknown, expired, or revoked key gets HTTP 401.
An API key has priority when a request has both credential headers. An invalid API key does not fall back to the bearer token.
Send an MCP request
Use an MCP SDK in production. This raw request shows API-key authentication and optional volume attribution:
curl https://mcp.pearprotocol.io/mcp \
--request POST \
--header 'content-type: application/json' \
--header 'accept: application/json, text/event-stream' \
--header 'x-api-key: <api-key>' \
--header 'x-client-id: <client-code>' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}'For OAuth, replace x-api-key with Authorization: Bearer <access-token>.
Add volume attribution
Add a Pear-issued code to each MCP request that needs volume attribution:
x-api-key: <api-key>
x-client-id: <client-code>The value must be an active client_ids.code that Pear assigned. The value is not any of these identifiers:
- OAuth
client_id - API key UUID
- Raw API key
- User UUID
- Trade account UUID
Pear records the code on supported executions and fills. Pear can then group trading volume by integration.
x-client-id is an attribution label. It is not an authentication credential. Pear checks that the code exists and is active. Pear does not bind the code to an API key or OAuth client.
Send x-client-id on every request that needs attribution. The value does not continue to the next request.
When you omit x-client-id, the trade has no integration attribution unless the service has a default code. An unknown or inactive code causes the related write to fail.
Attribution covers market trades, TWAP schedules, conditional triggers, and manual rebalances. Ladder creation and automatic rebalance settings do not automatically receive the default attribution code.
These fields have separate purposes:
| Field | Purpose |
|---|---|
x-api-key or bearer token | Identifies and authorizes the user |
x-client-id | Identifies the integration for volume attribution |
tradeAccountId | Selects the connected exchange account |
Build the account flow
A trade account is a connected exchange account. It tells Pear which exchange, wallet, or subaccount a tool must use.
Users manage trade accounts in the Pear application. MCP does not create, change, delete, restore, or return credentials for a trade account.
Select an account
Call list_trade_accounts when the client does not have a current account. This tool does not need a tradeAccountId.
Use this selection flow:
- Call
list_trade_accounts. - If the list is empty, tell the user to connect an account in Pear.
- If the list has one active account, omit
tradeAccountId. MCP selects that account. - If the list has multiple active accounts, show an account picker.
- Pass the selected account
idastradeAccountId. - Keep the selection for the current task.
- Pass the same ID to later account-scoped calls.
Use the same tradeAccountId for both parts of a plan_* and execute_* flow. A plan token belongs to one user and one trade account.
Use Alias, Connector as the account label. For example, use Main, Hyperliquid. Show a short exchangeIdentifier only when two accounts have the same label.
The tool can return these account errors:
| Condition | Client action |
|---|---|
| No account | Ask the user to connect an account in Pear. |
| Multiple accounts with no selection | Show the returned account list and ask the user to select one. |
| Unknown account or another user's account | Refresh the account list and ask the user to select again. |
Do not show the raw error as the only response. Tell the user what action to take.
All order tools are account-scoped. Position, balance, execution, TCA, pending-order, rebalance, saved-basket, cancellation, management, and synchronization tools are also account-scoped.
Market discovery, basket discovery, prediction-market search, notifications, and list_trade_accounts do not need an account selection.
Account fields
Each account from list_trade_accounts has these fields:
| Field | Client use |
|---|---|
id | Pass this stable ID to account-scoped tools. You do not have to show it in the label. |
alias | Use this user-defined name as the main label. |
connector | Show the connected exchange, such as Hyperliquid, Binance, Bybit, OKX, or Lighter. |
exchangeIdentifier | Show a short form when this value is an address. |
metadata | Show only details that help the user identify the account. |
createdAt, updatedAt | Do not show these values in a normal account picker. |
deletedAt | This field exists only for a deleted account. |
list_trade_accounts accepts includeDeleted. Keep this value false during normal use. An account-scoped tool cannot use a deleted account.
Sync the account
Call sync_account after the user connects an account. Call it before the first position read. Call it again after an order settles.
The tool imports exchange positions and fills into Pear. It does not place an order.
Build the trade flow
Every action that places an order uses a plan tool and an execute tool.
- Call the matching
plan_*tool. - Keep the returned single-use
planToken. - Show the complete plan to the user.
- Wait for user approval.
- Call the matching
execute_*tool. - Send the token and the required routing field.
- Check the execution result.
- Call
sync_accountafter the order settles.
A plan validates and sizes the action. It does not place an order.
An execute_* tool does not accept the original planning fields. It uses the stored plan. The token belongs to one user, trade account, tool family, and routing mode.
Handle an unclear execution result
Do not create a new plan after an unclear execution result. First call these tools:
- Call
sync_account. - Call
get_position. - Call
get_executionwhen you have an execution ID.
Use this recovery flow for binding_mismatch, execution_in_progress, and unknown or expired token responses. These responses do not prove that Pear did not place an order.
Handle schemas and responses
Use MCP tools/list as the source for each input schema. The server validates arguments before it calls the execution engine.
Interactive hosts can show widgets for markets, positions, orders, baskets, notifications, plans, and execution receipts. Other hosts receive structured JSON or JSON text.
The server rejects a plain JSON-text response above an estimated 25,000 tokens. This limit does not apply to widget-backed structured responses. Use filters, limit, cursor, or offset to request less data.
Tool reference
The current manifest contains 29 tools. It has 13 read tools and 16 write tools.
Read tools
These tools require mcp:read.
| Tool | Account | Purpose |
|---|---|---|
discover_assets | No | Searches the asset catalog across connectors. It supports filters, sorting, cursor paging, and compact or full output. Read pear://asset-filters before you use connector, asset-class, or category filters. |
get_account_summary | Yes | Returns exchange balances when params.scope is balance. Returns Pear performance statistics when params.scope is stats. |
get_execution | Yes | Returns one execution by executionId. Use it to check execution and order errors after a write. |
get_position | Yes | Returns all open Pear positions with profit and loss, funding, leverage, triggers, current executions, and stale-data signals. |
get_position_history | Yes | Returns recent closed positions. The default limit is 10. |
get_tca | Yes | Returns transaction-cost analysis for execution, position, or summary. Execution and position requests need the related ID. |
list_auto_rebalance | Yes | Lists settings when params.scope is configs. Lists position drift checks when params.scope is events. |
list_baskets | No | Lists live pair and basket markets for a connector. It supports scope, symbol search, limit, and offset. |
list_notifications | No | Lists all, read, or unread notifications. It supports optional ISO 8601 start and end dates. |
list_pending_orders | Yes | Lists schedules, triggers, or ladders. A ladder request can include ladderId to return its settings and rung triggers. |
list_saved_baskets | Yes | Lists saved basket templates with current price, change, and funding data. |
list_trade_accounts | No | Lists connected trade accounts. It never returns exchange credentials. |
search_prediction_markets | No | Searches open Kalshi or Polymarket markets. plan_open_basket can use the returned market IDs in a prediction-market condition. |
Order plan and execute tools
These tools require mcp:write.
| Tool | Purpose |
|---|---|
plan_open_basket | Plans a basket open with a market, TWAP, trigger, or ladder order. It returns a plan and planToken. |
execute_open_basket | Places the approved open plan. Send the same executionStyle, the planToken, and tradeAccountId when needed. A market order can also use expectedTotalNotionalUsd as a check. |
plan_close_basket | Plans a market or TWAP close. A market close can target one position, selected symbols, or all positions. A TWAP close targets one position. |
execute_close_basket | Places the approved close plan. Send the same executionStyle and planToken. |
plan_set_position_tpsl | Plans one take-profit, stop-loss, or trailing close trigger. Plan take-profit and stop-loss triggers separately. |
execute_set_position_tpsl | Starts the exact trigger in the approved plan. |
plan_rebalance_position | Plans new target weights for an open basket. It shows the current weights, target weights, and estimated USD changes. |
execute_rebalance_position | Places the approved rebalance. The engine calculates trade changes from current prices. |
plan_adjust_position | Plans an increase or decrease for one leg or all legs. It supports percent or USD size. A decrease cannot reverse a leg. |
execute_adjust_position | Places the approved adjustment. The engine calculates quantity from the current price for a USD size. |
plan_enable_auto_rebalance | Plans an automatic rebalance setting. params.weightSource is live_beta or initial_weight. live_beta also uses a 1h, 4h, or 1d time frame. |
execute_enable_auto_rebalance | Starts the approved automatic rebalance setting. Send the same weightSource and planToken. |
Other write tools
These tools require mcp:write.
| Tool | Account | Purpose |
|---|---|---|
cancel_pending_order | Yes | Cancels one or all TWAP schedules, one or all triggers, or one ladder and its active rungs. It does not use a plan token. |
manage_saved_basket | Yes | Saves, changes, or deletes basket templates. It does not use a plan token. |
set_notification_read_state | No | Marks one notification as read or unread. It can also mark all notifications before a time as read. |
sync_account | Yes | Matches Pear positions and fills with exchange data. It does not place an order or use a plan token. |
MCP resources
The mcp:read scope exposes pear://asset-filters. This resource returns the connectors, asset classes, and categories that discover_assets accepts.
MCP Apps hosts can also read hash-pinned ui:// resources for the registered widgets. These resources show tool results. They do not change authentication or tool behavior.
Errors and security
| Condition | Result |
|---|---|
| Missing or invalid credentials | HTTP 401 with an RFC 9728 challenge |
| Too many requests | HTTP 429 with Retry-After |
| Read-only credential calls a write tool | MCP protocol error because the tool is not registered |
| Both credential headers are present | The API key has priority |
| Plan token is reused or expired | The write fails or returns the stored replay result |
The MCP validates bearer JWTs locally. It does not check OAuth grant revocation on every request. The Pear gateway checks revocation for engine-backed calls. A revoked token can reach cache-only reads until the JWT expires.
API keys never appear in tool arguments or tool results. MCP does not expose exchange credentials or trade-account changes as tools.
Plan tokens are single-use and expire. Redis stores token state and the replay result.
Each MCP request receives only the tools that its verified scopes allow.
Integration checklist
Before release, verify these items:
- Use OAuth 2.0 with PKCE S256 for a user-facing client.
- Use a
read_writeAPI key only when the integration needs write tools. - Keep API keys out of source control and browser storage.
- Send
x-client-idon each request that needs volume attribution. - Confirm that Pear activated the
client_ids.code. - Call
list_trade_accountsbefore the first account-scoped tool. - Call
sync_accountbefore position reads and after settled executions. - Show each
plan_*result before you call the matchingexecute_*tool. - Page large read results.
- Handle HTTP 401, HTTP 429, tool errors, and unclear execution results.