scp_get_loyalty
Retrieve customer loyalty status and points from authorized merchants using the Shopper Context Protocol to access e-commerce data securely.
Instructions
Get loyalty status and points from a merchant. Domain must be authorized first.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Merchant domain |
Implementation Reference
- src/server.ts:851-867 (handler)Primary handler function for the scp_get_loyalty tool. Validates authorization, retrieves the access token, calls the HTTP client to fetch loyalty data from the merchant's SCP endpoint, and returns the result as formatted JSON.* Tool handler: scp_get_loyalty */ async function handleGetLoyalty(domain: string) { const { auth, accessToken } = await checkAuthorizationOrThrow(domain); const token = await accessToken; const data = await scpClient.getLoyalty(auth.scp_endpoint, token); return { content: [ { type: 'text', text: JSON.stringify(data, null, 2) } ] }; }
- src/server.ts:399-412 (schema)Input schema definition registered for the scp_get_loyalty tool, requiring a 'domain' parameter.{ name: 'scp_get_loyalty', description: 'Get loyalty status and points from a merchant. Domain must be authorized first.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' } }, required: ['domain'] } },
- src/server.ts:303-538 (registration)Tool registration within the ListToolsRequestSchema handler, where scp_get_loyalty is included in the list of available tools with its schema.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'scp_authorize', description: 'BEFORE USING THIS ENSURE THE DOMAIN SUPPORTS SCP BY CALLING scp_discover FIRST. Authorize access to a merchant\'s customer context via SCP. Must be called before accessing any customer data. IMPORTANT: You must ask the user for their REAL email address - never use placeholder emails like user@example.com. Ask: "What email address do you use with [Merchant]?" and wait for their response.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain (e.g., \'acmestore.com\')' }, email: { type: 'string', description: 'Customer\'s REAL email address (must ask user for this - never use example.com or placeholder emails)' }, scopes: { type: 'array', items: { type: 'string' }, description: 'Requested scopes (e.g., [\'orders\', \'loyalty\', \'intent:read\']). Best practice: request all needed scopes upfront.' } }, required: ['domain', 'email', 'scopes'] } }, { name: 'scp_check_authorization', description: 'Check if authorized with a merchant domain', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' } }, required: ['domain'] } }, { name: 'scp_revoke_authorization', description: 'Revoke authorization with a merchant domain', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' } }, required: ['domain'] } }, { name: 'scp_discover', description: 'Discover SCP endpoint for a merchant domain via DNS', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' } }, required: ['domain'] } }, { name: 'scp_get_orders', description: 'Get order history from a merchant. Domain must be authorized first.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' }, limit: { type: 'number', description: 'Maximum number of orders to return', default: 10 }, offset: { type: 'number', description: 'Number of orders to skip', default: 0 }, status: { type: 'array', items: { type: 'string' }, description: 'Filter by order status (e.g., [\'delivered\', \'shipped\'])' } }, required: ['domain'] } }, { name: 'scp_get_loyalty', description: 'Get loyalty status and points from a merchant. Domain must be authorized first.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' } }, required: ['domain'] } }, { name: 'scp_get_offers', description: 'Get active personalized offers from a merchant. Domain must be authorized first.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' }, active_only: { type: 'boolean', description: 'Only return active offers', default: true } }, required: ['domain'] } }, { name: 'scp_get_preferences', description: 'Get saved customer preferences (sizes, styles, addresses) from a merchant. Domain must be authorized first.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' } }, required: ['domain'] } }, { name: 'scp_get_intents', description: 'Get shopping intents from a merchant. Domain must be authorized first.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' }, status: { type: 'array', items: { type: 'string' }, description: 'Filter by status (e.g., [\'active\', \'in_progress\'])' }, limit: { type: 'number', description: 'Maximum number of intents to return', default: 10 } }, required: ['domain'] } }, { name: 'scp_create_intent', description: 'Create a new shopping intent with a merchant. Domain must be authorized with intent:create scope.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' }, base_intent: { type: 'string', description: 'Natural language description of the shopping goal' }, context: { type: 'object', description: 'Additional context about the intent' }, mechanism: { type: 'string', description: 'How the intent was created', default: 'conversational_ai' }, ai_assistant: { type: 'string', description: 'Name of the AI assistant' }, visibility: { type: 'string', description: 'Who can see this intent', enum: ['merchant_only', 'shared_with_customer'], default: 'merchant_only' } }, required: ['domain', 'base_intent'] } }, { name: 'scp_update_intent', description: 'Update an existing shopping intent. Domain must be authorized with intent:write scope.', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'Merchant domain' }, intent_id: { type: 'string', description: 'Intent ID to update' }, status: { type: 'string', description: 'New status' }, context: { type: 'object', description: 'Updated context' }, add_milestone: { type: 'string', description: 'Add a milestone note' } }, required: ['domain', 'intent_id'] } } ] }));
- src/http/client.ts:102-107 (helper)Helper function in the HTTP client that performs the actual JSON-RPC call to the merchant's SCP endpoint for retrieving loyalty information.export async function getLoyalty( endpoint: string, accessToken: string ): Promise<any> { return makeRPCRequest(endpoint, accessToken, 'scp.get_loyalty'); }
- src/server.ts:811-825 (helper)Shared helper function used by scp_get_loyalty and other data-access tools to check authorization and retrieve the access token, throwing a helpful error if not authorized.async function checkAuthorizationOrThrow(domain: string): Promise<{ auth: any; accessToken: Promise<string> }> { const auth = await getAuthorization(domain); if (!auth) { const errorMessage = `❌ Not authorized with ${domain}.\n\n` + `Please authorize first by calling:\n` + `scp_authorize with domain="${domain}", email="your@email.com", and scopes=["orders", "loyalty", "preferences", "intent:read", "intent:create"]`; throw new Error(errorMessage); } return { auth, accessToken: getValidAccessToken(domain) }; }