We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kuro-tomo/shopify-agentic-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
/**
* Merchant Signature — HMAC-SHA256 cart content attestation
*
* Generates and verifies a merchant_signature for CartPayload.
* Proves the merchant (gateway) has reviewed and approved the cart
* contents before the buyer's agent signs the cart mandate.
*
* Canonical form: JSON.stringify({ checkout_id, line_items, totals })
* sorted keys, no whitespace, then HMAC-SHA256 with the merchant secret.
*/
import { createHmac, timingSafeEqual } from 'node:crypto';
import type { LineItem, CheckoutTotals } from '../types.js';
interface CartContent {
checkout_id: string;
line_items: LineItem[];
totals: CheckoutTotals;
}
/**
* Build the canonical string for HMAC signing.
* Uses deterministic JSON serialization (sorted keys).
*/
function canonicalize(content: CartContent): string {
return JSON.stringify(content, Object.keys(content).sort());
}
/**
* Generate a merchant_signature for the given cart content.
*
* @param content - The cart data to sign (checkout_id, line_items, totals)
* @param secret - The merchant secret (AP2_SIGNING_PRIVATE_KEY or API_SECRET)
* @returns Hex-encoded HMAC-SHA256 signature
*/
export function generateMerchantSignature(content: CartContent, secret: string): string {
const canonical = canonicalize(content);
return createHmac('sha256', secret).update(canonical).digest('hex');
}
/**
* Verify a merchant_signature against the given cart content.
*
* @param signature - The hex-encoded HMAC-SHA256 to verify
* @param content - The cart data that was signed
* @param secret - The merchant secret used for signing
* @returns true if the signature is valid
*/
export function verifyMerchantSignature(
signature: string,
content: CartContent,
secret: string,
): boolean {
const expected = generateMerchantSignature(content, secret);
try {
const sigBuffer = Buffer.from(signature, 'hex');
const expectedBuffer = Buffer.from(expected, 'hex');
if (sigBuffer.length !== expectedBuffer.length) {
return false;
}
return timingSafeEqual(sigBuffer, expectedBuffer);
} catch {
return false;
}
}