noodle-perplexity-mcp
Version:
A Perplexity API Model Context Protocol (MCP) server that unlocks Perplexity's search-augmented AI capabilities for LLM agents. Features robust error handling, secure input validation, and transparent reasoning with the showThinking parameter. Built with
101 lines (100 loc) • 3.66 kB
JavaScript
import { logger } from '../index.js';
// --- Pricing Data Structures ---
// Rates are typically per million tokens or per 1000 requests/searches
const PER_MILLION = 1000000;
const PER_THOUSAND = 1000;
// --- Current Perplexity Model Pricing ---
// Based on documentation from 2025-07-05
const modelPricingSheet = {
'sonar': {
tokenPricing: { input: 1.00, output: 1.00 },
actionPricing: {
requestFeesByTier: { low: 5, medium: 8, high: 12 }
}
},
'sonar-pro': {
tokenPricing: { input: 3.00, output: 15.00 },
actionPricing: {
requestFeesByTier: { low: 6, medium: 10, high: 14 }
}
},
'sonar-reasoning': {
tokenPricing: { input: 1.00, output: 5.00 },
actionPricing: {
requestFeesByTier: { low: 5, medium: 8, high: 12 }
}
},
'sonar-reasoning-pro': {
tokenPricing: { input: 2.00, output: 8.00 },
actionPricing: {
requestFeesByTier: { low: 6, medium: 10, high: 14 }
}
},
'sonar-deep-research': {
tokenPricing: {
input: 2.00,
output: 8.00,
citation: 2.00,
reasoning: 3.00,
},
actionPricing: {
searchQueryFee: 5.00
}
}
};
// --- Cost Calculation Logic ---
/**
* Calculates the estimated cost of a Perplexity API call.
*
* @param model - The name of the Perplexity model used.
* @param usage - The token and action usage data from the API response.
* @param apiTier - The API tier used ('low', 'medium', 'high'), which may affect request fees.
* @param context - The request context for logging.
* @returns The estimated cost in USD, or null if pricing info is unavailable.
*/
export function calculatePerplexityCost(model, usage, apiTier, context) {
const operation = 'calculatePerplexityCost';
const pricing = modelPricingSheet[model];
if (!pricing) {
logger.error(`Pricing information not found for model: ${model}`, { ...context, operation, model });
return null;
}
let cost = 0;
// 1. Calculate Token Costs
const { tokenPricing } = pricing;
cost += (usage.prompt_tokens / PER_MILLION) * tokenPricing.input;
cost += (usage.completion_tokens / PER_MILLION) * tokenPricing.output;
if (tokenPricing.reasoning && usage.reasoning_tokens) {
cost += (usage.reasoning_tokens / PER_MILLION) * tokenPricing.reasoning;
}
if (tokenPricing.citation && usage.citation_tokens) {
cost += (usage.citation_tokens / PER_MILLION) * tokenPricing.citation;
}
// 2. Calculate Action Costs
const { actionPricing } = pricing;
if (actionPricing.requestFeesByTier && apiTier) {
const requestFeePerThousand = actionPricing.requestFeesByTier[apiTier];
if (requestFeePerThousand !== undefined) {
cost += requestFeePerThousand / PER_THOUSAND; // Cost for a single request
}
else {
logger.warning(`API tier '${apiTier}' not found for model ${model}. Request fee not applied.`, { ...context, operation, model });
}
}
if (actionPricing.searchQueryFee && usage.search_queries) {
cost += (usage.search_queries / PER_THOUSAND) * actionPricing.searchQueryFee;
}
logger.debug(`Calculated cost for model ${model}`, {
...context,
operation,
model,
usage,
apiTier: apiTier ?? 'N/A',
estimatedCost: cost,
});
// Return cost rounded to a reasonable number of decimal places (e.g., 6)
return parseFloat(cost.toFixed(6));
}
export const costTracker = {
calculatePerplexityCost,
};