infura-mcp-server
Version:
Model Context Protocol (MCP) server providing comprehensive read-only Ethereum blockchain access through Infura's infrastructure. Connect Claude Desktop, VS Code, and Cursor to 29 secure Ethereum JSON-RPC tools across 30+ networks including Ethereum, Poly
212 lines (197 loc) • 6.6 kB
JavaScript
/**
* Constants for Infura MCP Server
*
* This module contains all configuration constants used throughout the server.
* Constants are organized by category:
* - Response size limits
* - Session management
* - Rate limiting
* - Retry configuration
* - Response formatting
*
* Modify these values to tune server behavior for different environments
* or performance requirements.
*
* @module constants
*
* @example
* import {
* CHARACTER_LIMIT,
* MAX_RETRIES,
* truncationMessage
* } from './lib/constants.js';
*
* if (response.length > CHARACTER_LIMIT) {
* response = response.slice(0, CHARACTER_LIMIT);
* }
*/
// ============================================================================
// Response Size Limits
// ============================================================================
/**
* Maximum character count for API response content.
*
* Responses exceeding this limit will be truncated to prevent memory issues
* and ensure reasonable response times. Set to 100KB (100,000 characters).
*
* @constant {number}
* @default 100000
*
* @example
* if (responseText.length > CHARACTER_LIMIT) {
* responseText = responseText.slice(0, CHARACTER_LIMIT) + '... [truncated]';
* }
*/
export const CHARACTER_LIMIT = 100000; // 100KB max response
/**
* Maximum number of log entries returned per eth_getLogs query.
*
* Large log queries can be extremely slow and resource-intensive.
* This limit prevents runaway queries and encourages pagination.
*
* @constant {number}
* @default 1000
*
* @example
* const logs = await callInfura('eth_getLogs', [filter], network);
* if (logs.length > LOGS_RESULT_LIMIT) {
* // Suggest narrowing the block range
* }
*/
export const LOGS_RESULT_LIMIT = 1000; // Max logs per eth_getLogs query
// ============================================================================
// Session Management
// ============================================================================
/**
* Session timeout duration in milliseconds.
*
* Inactive sessions will be automatically cleaned up after this duration
* to prevent memory leaks. Set to 30 minutes (1,800,000 ms).
*
* @constant {number}
* @default 1800000
*
* @example
* const isSessionExpired = (Date.now() - session.lastActivity) > SESSION_TIMEOUT_MS;
*/
export const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
/**
* Maximum number of concurrent sessions allowed.
*
* When this limit is reached, the oldest inactive sessions will be
* evicted to make room for new connections. This prevents unbounded
* memory growth.
*
* @constant {number}
* @default 1000
*
* @example
* if (activeSessions.size >= MAX_SESSIONS) {
* evictOldestSession();
* }
*/
export const MAX_SESSIONS = 1000;
// ============================================================================
// Rate Limiting
// ============================================================================
/**
* Rate limit window duration in milliseconds.
*
* Request counts are tracked within this sliding window.
* Set to 1 minute (60,000 ms).
*
* @constant {number}
* @default 60000
*
* @example
* const windowStart = Date.now() - RATE_LIMIT_WINDOW_MS;
* const requestsInWindow = requests.filter(t => t > windowStart).length;
*/
export const RATE_LIMIT_WINDOW_MS = 60 * 1000; // 1 minute
/**
* Maximum number of requests allowed per rate limit window.
*
* Requests exceeding this limit will be rejected with a rate limit error.
* This protects both the server and the Infura API from overload.
*
* @constant {number}
* @default 100
*
* @example
* if (requestsInWindow >= RATE_LIMIT_MAX_REQUESTS) {
* throw new Error('Rate limit exceeded');
* }
*/
export const RATE_LIMIT_MAX_REQUESTS = 100; // per window
// ============================================================================
// Retry Configuration
// ============================================================================
/**
* Maximum number of retry attempts for transient failures.
*
* Used by the Infura client for automatic retry logic. After this many
* total attempts (including the initial request), the error will be
* propagated to the caller.
*
* @constant {number}
* @default 3
*
* @example
* for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
* try {
* return await makeRequest();
* } catch (error) {
* if (!error.isTransient || attempt === MAX_RETRIES - 1) throw error;
* }
* }
*/
export const MAX_RETRIES = 3;
/**
* Initial retry delay in milliseconds for exponential backoff.
*
* Subsequent retries will use increasing delays: 1s, 2s, 4s (for 3 retries).
* This follows the formula: delay = INITIAL_RETRY_DELAY_MS * 2^attempt
*
* @constant {number}
* @default 1000
*
* @example
* // Exponential backoff calculation
* const delay = INITIAL_RETRY_DELAY_MS * Math.pow(2, attemptNumber);
* // attempt 0: 1000ms
* // attempt 1: 2000ms
* // attempt 2: 4000ms
*/
export const INITIAL_RETRY_DELAY_MS = 1000;
// ============================================================================
// Response Formatting
// ============================================================================
/**
* Generates a truncation notice message for large responses.
*
* This message is appended to truncated responses to inform users that
* not all data is shown due to character limits. It includes the item count
* for context and suggests using pagination or filters for complete results.
*
* @function truncationMessage
* @param {number} itemCount - The number of items in the result
* @param {number} charLimit - The character limit where truncation occurred
* @returns {string} A formatted truncation notice message
*
* @example
* // Response exceeded CHARACTER_LIMIT
* if (textContent.length > CHARACTER_LIMIT) {
* const truncated = textContent.substring(0, CHARACTER_LIMIT);
* const message = truncationMessage(logs.length, CHARACTER_LIMIT);
* return truncated + message;
* }
* // Output: "\n\n[Response truncated at 100,000 characters. 5000 items found. Use pagination or filters for complete results.]"
*
* @example
* truncationMessage(5000, 100000);
* // Returns: "\n\n[Response truncated at 100,000 characters. 5000 items found. Use pagination or filters for complete results.]"
*/
export const truncationMessage = (itemCount, charLimit) => {
const itemText = itemCount === 1 ? "1 item" : `${itemCount} items`;
return `\n\n[Response truncated at ${charLimit.toLocaleString()} characters. ${itemText} found. Use pagination or filters for complete results.]`;
};