tesouro-direto-mcp
Version:
Model Context Protocol (MCP) server for Tesouro Direto API integration
101 lines (100 loc) • 3.17 kB
JavaScript
import { logger } from '../utils/logger.js';
import { fetchTesouroDiretoAPI } from '../api/tesouroDireto.js';
// Cache duration in milliseconds (10 minutes)
const CACHE_DURATION_MS = 10 * 60 * 1000;
// Cache configuration
const cacheConfig = {
isEnabled: process.env.USE_MCP_CACHE !== 'false',
durationMs: CACHE_DURATION_MS
};
let cachedData = null;
/**
* Helper function to check if cache is enabled and log if disabled
*/
function withCache(operation, fn) {
if (!cacheConfig.isEnabled) {
logger.debug(`Cache is disabled via USE_MCP_CACHE environment variable, skipping ${operation}`);
return null;
}
return fn();
}
/**
* Checks if the cached data is valid based on the BizSts timestamp
*/
export function isCacheValid() {
return withCache('cache validation', () => {
if (!cachedData)
return false;
const now = new Date();
const bizTime = new Date(cachedData.bizTimestamp);
const bizAge = now.getTime() - bizTime.getTime();
logger.debug("Cache BizSts age is " + (bizAge / 1000) + " seconds");
// Check if BizSts timestamp is less than 10 minutes old
return bizAge < cacheConfig.durationMs;
}) ?? false;
}
/**
* Gets data from cache if valid, otherwise returns null
*/
export function getFromCache() {
return withCache('cache retrieval', () => {
if (isCacheValid()) {
logger.info('Returning data from cache, BizSts age: ' +
((new Date().getTime() - new Date(cachedData.bizTimestamp).getTime()) / 1000) + ' seconds');
return cachedData.data;
}
logger.info('Cache invalid or expired');
return null;
});
}
/**
* Stores API response in cache
*/
export function storeInCache(data) {
withCache('cache storage', () => {
cachedData = {
data,
timestamp: new Date().toISOString(),
bizTimestamp: data.BizSts.dtTm
};
logger.info(`Data cached with BizSts timestamp: ${data.BizSts.dtTm}`);
});
}
/**
* Checks if the new data has a different BizSts timestamp than the cached data
* Used to determine if we should update the cache
*/
export function hasNewData(newData) {
if (!cacheConfig.isEnabled)
return true;
if (!cachedData)
return true;
return cachedData.bizTimestamp !== newData.BizSts.dtTm;
}
/**
* Clears the cache
*/
export function clearCache() {
withCache('cache clearing', () => {
cachedData = null;
logger.info('Cache cleared');
});
}
/**
* Gets API data with caching logic
* Attempts to get data from cache first, falls back to API if needed
*/
export async function getApiDataWithCache(context = 'API request') {
// Try to get data from cache first
let responseData = getFromCache();
// If nothing in cache, fetch from API
if (!responseData) {
logger.info(`Fetching fresh data for ${context}`);
responseData = await fetchTesouroDiretoAPI();
// Store in cache if it's new data
if (hasNewData(responseData)) {
storeInCache(responseData);
}
}
return responseData;
}