Skip to main content
Glama
smart-formatting.ts11.4 kB
// Smart formatting utilities for MCP Sigmund import { QueryParams, } from './types.js'; // Provides display hints and user-friendly formatting suggestions export interface DisplayHint { display_hint: string; user_profile: string; suggested_format: { show_account_number?: 'full' | 'partial' | 'hidden'; currency_format?: 'symbol' | 'code' | 'both'; include_pending?: boolean; show_technical_details?: boolean; transaction_display?: 'simple' | 'detailed' | 'professional'; date_format?: 'relative' | 'absolute' | 'both'; group_by?: 'date' | 'category' | 'merchant' | 'none'; }; visual_hint?: string; context_hints?: string[]; } export interface SmartResponse<T> { data: T; display_hint: string; user_profile: string; suggested_format: DisplayHint['suggested_format']; visual_hint?: string; context_hints?: string[]; timestamp: string; } // Display hint configurations for different query types export const DISPLAY_HINTS: { [key: string]: DisplayHint } = { // Account and balance queries simple_balance: { display_hint: 'simple_balance', user_profile: 'retail_banking', suggested_format: { show_account_number: 'partial', currency_format: 'symbol', include_pending: false, show_technical_details: false, transaction_display: 'simple', date_format: 'relative', group_by: 'none', }, context_hints: [ 'Show clear, single balance amount', 'Hide account numbers except last 4 digits', 'Use friendly currency symbols', ], }, account_summary: { display_hint: 'account_summary', user_profile: 'retail_banking', suggested_format: { show_account_number: 'partial', currency_format: 'symbol', include_pending: true, show_technical_details: false, transaction_display: 'simple', date_format: 'relative', group_by: 'none', }, context_hints: [ 'Show account details with balance', 'Include recent transaction summary', 'Use friendly descriptions', ], }, // Transaction queries transaction_list: { display_hint: 'transaction_list', user_profile: 'retail_banking', suggested_format: { show_account_number: 'hidden', currency_format: 'symbol', include_pending: false, show_technical_details: false, transaction_display: 'simple', date_format: 'relative', group_by: 'date', }, context_hints: [ 'Show merchant names instead of technical descriptions', 'Group by date for easy reading', 'Hide reference numbers and technical codes', ], }, recent_transactions: { display_hint: 'recent_transactions', user_profile: 'retail_banking', suggested_format: { show_account_number: 'hidden', currency_format: 'symbol', include_pending: false, show_technical_details: false, transaction_display: 'simple', date_format: 'relative', group_by: 'none', }, visual_hint: 'transaction_timeline', context_hints: [ 'Show last few transactions in simple format', 'Use "Today", "Yesterday", "3 days ago" for dates', 'Focus on merchant names and amounts', ], }, // Analysis queries spending_analysis: { display_hint: 'spending_analysis', user_profile: 'retail_banking', suggested_format: { show_account_number: 'hidden', currency_format: 'symbol', include_pending: false, show_technical_details: false, transaction_display: 'simple', date_format: 'absolute', group_by: 'category', }, visual_hint: 'spending_pie_chart', context_hints: [ 'Group spending by category', 'Show visual breakdown with percentages', 'Use friendly category names', 'Highlight top spending areas', ], }, cashflow_analysis: { display_hint: 'cashflow_analysis', user_profile: 'retail_banking', suggested_format: { show_account_number: 'hidden', currency_format: 'symbol', include_pending: false, show_technical_details: false, transaction_display: 'simple', date_format: 'absolute', group_by: 'date', }, visual_hint: 'cashflow_line_chart', context_hints: [ 'Show monthly income vs expenses', 'Use clear visual indicators for positive/negative', 'Group by month for trend analysis', ], }, financial_overview: { display_hint: 'financial_overview', user_profile: 'retail_banking', suggested_format: { show_account_number: 'partial', currency_format: 'symbol', include_pending: true, show_technical_details: false, transaction_display: 'simple', date_format: 'absolute', group_by: 'none', }, context_hints: [ 'Show high-level financial health', 'Include key metrics and trends', 'Use clear, non-technical language', ], }, // Professional/Developer queries professional_report: { display_hint: 'professional_report', user_profile: 'business', suggested_format: { show_account_number: 'full', currency_format: 'both', include_pending: true, show_technical_details: true, transaction_display: 'professional', date_format: 'absolute', group_by: 'category', }, context_hints: [ 'Include all technical details', 'Show full account numbers', 'Use professional terminology', 'Suitable for accounting/tax purposes', ], }, developer_data: { display_hint: 'developer_data', user_profile: 'developer', suggested_format: { show_account_number: 'full', currency_format: 'code', include_pending: true, show_technical_details: true, transaction_display: 'detailed', date_format: 'absolute', group_by: 'none', }, context_hints: [ 'Include all raw data fields', 'Show technical IDs and references', 'Use precise data formats', 'Suitable for integration/development', ], }, }; // Context detection based on user query patterns export function detectUserContext(query: string, params: QueryParams): string { const queryLower = query.toLowerCase(); const hasParams = Object.keys(params || {}).length > 0; // Professional context indicators if ( queryLower.includes('tax') || queryLower.includes('accountant') || queryLower.includes('business') || queryLower.includes('professional') || queryLower.includes('report') || queryLower.includes('export') ) { return 'professional_report'; } // Developer context indicators if ( queryLower.includes('api') || queryLower.includes('json') || queryLower.includes('raw') || queryLower.includes('data') || queryLower.includes('integration') || queryLower.includes('developer') ) { return 'developer_data'; } // Simple balance queries if (queryLower.includes('balance') && !hasParams) { return 'simple_balance'; } // Account summary queries if (queryLower.includes('account') && !queryLower.includes('transaction')) { return 'account_summary'; } // Recent transactions if ( queryLower.includes('recent') || queryLower.includes('last') || (queryLower.includes('transaction') && params?.limit && typeof params.limit === 'number' && params.limit <= 10) ) { return 'recent_transactions'; } // Transaction lists if (queryLower.includes('transaction') || queryLower.includes('history')) { return 'transaction_list'; } // Analysis queries if ( queryLower.includes('spending') || queryLower.includes('expense') || queryLower.includes('category') ) { return 'spending_analysis'; } if ( queryLower.includes('cashflow') || queryLower.includes('income') || queryLower.includes('monthly') ) { return 'cashflow_analysis'; } if ( queryLower.includes('overview') || queryLower.includes('summary') || queryLower.includes('financial') ) { return 'financial_overview'; } // Default to simple balance for unknown queries return 'simple_balance'; } // Get display hint configuration export function getDisplayHint(context: string): DisplayHint { return ( DISPLAY_HINTS[context as keyof typeof DISPLAY_HINTS] || DISPLAY_HINTS.simple_balance ); } // Create smart response with display hints export function createSmartResponse<T>( data: T, query: string, params: QueryParams = {} ): SmartResponse<T> { const context = detectUserContext(query, params); const hint = getDisplayHint(context); return { data, display_hint: hint.display_hint, user_profile: hint.user_profile, suggested_format: hint.suggested_format, visual_hint: hint.visual_hint, context_hints: hint.context_hints, timestamp: new Date().toISOString(), }; } // Transaction description simplification export function simplifyTransactionDescription(description: string): string { if (!description) return 'Transaction'; const desc = description.toLowerCase(); // Replace technical terms with friendly ones const replacements: { [key: string]: string } = { 'sepa-basislastschrift': 'Automatic payment', 'sepa basislastschrift': 'Automatic payment', 'pos mit pin': 'Card payment', 'pos mit pin.': 'Card payment', barauszahlung: 'Cash withdrawal', gehalt: 'Salary', miete: 'Rent', lastschrift: 'Direct debit', überweisung: 'Transfer', dauerauftrag: 'Standing order', einzahlung: 'Deposit', abhebung: 'Withdrawal', }; let simplified = description; // Apply replacements for (const [technical, friendly] of Object.entries(replacements)) { if (desc.includes(technical)) { simplified = friendly; break; } } // Clean up common patterns simplified = simplified .replace(/^pos mit pin\.?\s*/i, 'Card payment - ') .replace(/^sepa-basislastschrift\s*/i, 'Automatic payment - ') .replace(/^barauszahlung,?\s*/i, 'Cash withdrawal - ') .replace(/\s+mit\s+pin\.?$/i, '') .replace(/\s+pin\.?$/i, ''); return simplified || 'Transaction'; } // Format currency based on suggestion export function formatCurrency( amount: number, currency: string, format: 'symbol' | 'code' | 'both' = 'symbol' ): string { const symbols: { [key: string]: string } = { EUR: '€', USD: '$', GBP: '£', CHF: 'CHF', }; const symbol = symbols[currency] || currency; const formattedAmount = new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(Math.abs(amount)); switch (format) { case 'symbol': return `${symbol}${formattedAmount}`; case 'code': return `${formattedAmount} ${currency}`; case 'both': return `${symbol}${formattedAmount} (${currency})`; default: return `${symbol}${formattedAmount}`; } } // Format account number based on suggestion export function formatAccountNumber( accountNumber: string, format: 'full' | 'partial' | 'hidden' = 'partial' ): string { if (!accountNumber) return ''; switch (format) { case 'full': return accountNumber; case 'partial': return `****${accountNumber.slice(-4)}`; case 'hidden': return '****'; default: return `****${accountNumber.slice(-4)}`; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/radup/mcp-sigmund'

If you have feedback or need assistance with the MCP directory API, please join our Discord server