estimate_conversion_cost
Estimate credit cost for a document conversion before executing. Returns word count, page estimate, and credit breakdown to prevent insufficient balance errors.
Instructions
Estimate credit cost for a conversion BEFORE running it. Returns word count, page calculation (300 words/page), and a credit breakdown by format and template type. Use this when the user asks 'how much will this cost?' or when you suspect a conversion might exceed their balance — convert_document refuses to run if credits are insufficient, so estimating first is friendlier.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | Markdown content to estimate credit cost for | |
| templateName | Yes | Template ID or name (UUID for custom templates, name for system templates) | |
| outputFormat | Yes | Output format(s): docx (DOCX only), pdf (DOCX+PDF), html (DOCX+HTML), all/all-formats (DOCX+PDF+HTML) | |
| pageSize | No | Page size for the document | |
| orientation | No | Page orientation |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| wordCount | No | Word count of the markdown content | |
| pageCount | No | Estimated page count (300 words/page) | |
| totalCredits | Yes | Total credits required for this conversion | |
| breakdown | No | Human-readable breakdown of how credits are calculated |
Implementation Reference
- Core handler function that estimates credit cost for a document conversion. Takes content, templateName, outputFormat (and optional pageSize/orientation), calculates credits via CreditCalculator, fetches current balance, and returns a formatted string with word count, page calculation, credit breakdown, and balance comparison.
export async function handleEstimateConversionCost( creditCalculator: CreditCalculator, args: { content: string; templateName: string; outputFormat: string; pageSize?: string; orientation?: string; } ): Promise<string> { try { console.error('[EstimateConversionCost] Calculating credit estimate...'); const { content, templateName, outputFormat } = args; // Determine output formats based on request let outputFormats: string[]; if (outputFormat === 'docx') { outputFormats = ['docx']; // DOCX only } else if (outputFormat === 'all' || outputFormat === 'all-formats') { outputFormats = ['docx', 'pdf', 'html']; // ALL THREE FORMATS } else { outputFormats = ['docx', outputFormat]; // DOCX + one other format } // Calculate credits const calculation = await creditCalculator.calculateCredits(content, templateName, outputFormats); // Get current balance for comparison const balance = await creditCalculator.getCreditBalance(); // Format output description const formatDescription = outputFormats.length === 1 ? 'DOCX only' : outputFormats.length === 2 ? `DOCX + ${outputFormats[1].toUpperCase()}` : 'DOCX + PDF + HTML (all formats)'; // Determine template type const templateType = templateName.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i) ? 'Custom Template' : 'System Template'; const response = [ `💳 **Credit Cost Estimate**`, ``, `**Content Analysis:**`, `- Word Count: ${calculation.wordCount} words`, `- Pages: ${calculation.pages} (${calculation.wordsPerPage} words per page)`, `- Template: ${templateType}`, `- Output: ${formatDescription}`, ``, `**Credit Breakdown:**`, `- ${calculation.breakdown}`, ``, `**Your Balance:**`, `- Current Credits: ${balance.total_credits}`, `- After Conversion: ${balance.total_credits - calculation.totalCredits} credits`, ``, balance.total_credits >= calculation.totalCredits ? `✅ **You have sufficient credits!** Would you like to proceed with the conversion?` : `❌ **Insufficient credits!** You need ${calculation.totalCredits - balance.total_credits} more credits to perform this conversion.` ].join('\n'); console.error(`[EstimateConversionCost] ✅ Estimated ${calculation.totalCredits} credits for conversion`); return response; } catch (error) { console.error('[EstimateConversionCost] ❌ Error estimating conversion cost:', error); const mcpError = handleApiError(error); return `❌ Error estimating conversion cost: ${mcpError.message}`; } } - src/tools/creditTools.ts:39-125 (handler)Alternative handler in creditTools.ts that wraps the same logic with Zod schema validation (estimateConversionCostSchema). Returns a CallToolResult with structured content. This is the handler actually referenced in the unified tool registration (src/tools/index.ts).
export async function handleEstimateConversionCost( creditCalculator: CreditCalculator, args: any ): Promise<CallToolResult> { try { console.error('[estimate_conversion_cost] Estimating conversion cost...'); const input = estimateConversionCostSchema.parse(args); const { content, templateName, outputFormat } = input; // Determine output formats based on request let outputFormats: string[]; if (outputFormat === 'docx') { outputFormats = ['docx']; // DOCX only } else if (outputFormat === 'all' || outputFormat === 'all-formats') { outputFormats = ['docx', 'pdf', 'html']; // ALL THREE FORMATS } else { outputFormats = ['docx', outputFormat]; // DOCX + one other format } // Calculate credits const calculation = await creditCalculator.calculateCredits(content, templateName, outputFormats); // Get current balance for comparison const balance = await creditCalculator.getCreditBalance(); // Format output description const formatDescription = outputFormats.length === 1 ? 'DOCX only' : outputFormats.length === 2 ? `DOCX + ${outputFormats[1].toUpperCase()}` : 'DOCX + PDF + HTML (all formats)'; // Determine template type const templateType = templateName.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i) ? 'Custom Template' : 'System Template'; return { content: [ { type: 'text', text: `💳 **Credit Cost Estimate** **Content Analysis:** - Word Count: ${calculation.wordCount} words - Template: ${templateType} - Output: ${formatDescription} **Credit Breakdown:** - ${calculation.breakdown} **Your Balance:** - Current Credits: ${balance.total_credits} - After Conversion: ${balance.total_credits - calculation.totalCredits} credits ${balance.total_credits >= calculation.totalCredits ? `✅ **You have sufficient credits!** Would you like to proceed with the conversion?` : `❌ **Insufficient credits!** You need ${calculation.totalCredits - balance.total_credits} more credits to perform this conversion.`} 💡 This is an estimate. Actual cost may vary slightly based on document complexity.` } ] }; } catch (error: any) { console.error('[estimate_conversion_cost] Error:', error); if (error.name === 'ZodError') { const issues = error.issues.map((issue: any) => `- ${issue.path.join('.')}: ${issue.message}`).join('\n'); return { content: [ { type: 'text', text: `❌ Invalid parameters: ${issues} 💡 Please check your input and try again.` } ], isError: true }; } throw error; // Let unified handler deal with it } } - src/utils/validation.ts:42-48 (schema)Zod schema for runtime input validation: validates content (string), templateName (string), outputFormat (enum docx/pdf/html/all/all-formats), pageSize (enum A3/A4/Executive/US_Legal/US_Letter, default A4), orientation (enum Portrait/Landscape, default Portrait).
export const estimateConversionCostSchema = z.object({ content: z.string().describe("Markdown content to estimate credit cost for"), templateName: z.string().describe("Template ID or name (UUID for custom templates, name for system templates)"), outputFormat: z.enum(['docx', 'pdf', 'html', 'all', 'all-formats']).describe("Output format(s): docx (DOCX only), pdf (DOCX+PDF), html (DOCX+HTML), all/all-formats (DOCX+PDF+HTML)"), pageSize: z.enum(['A3', 'A4', 'Executive', 'US_Legal', 'US_Letter']).default('A4').describe("Page size for the document"), orientation: z.enum(['Portrait', 'Landscape']).default('Portrait').describe("Page orientation") }); - Tool definition object with name 'estimate_conversion_cost', description, and inputSchema (JSON Schema) defining the same parameters as the Zod schema. Also serves as a standalone tool definition in its own file.
export const estimateConversionCost: Tool = { name: 'estimate_conversion_cost', description: 'Estimate credit cost for a conversion without performing it. Shows word count, page calculation, and detailed credit breakdown.', inputSchema: { type: 'object', properties: { content: { type: 'string', description: 'Markdown content to estimate credit cost for' }, templateName: { type: 'string', description: 'Template ID or name (UUID for custom templates, name for system templates)' }, outputFormat: { type: 'string', enum: ['docx', 'pdf', 'html', 'all', 'all-formats'], description: 'Output format(s): docx (DOCX only), pdf (DOCX+PDF), html (DOCX+HTML), all/all-formats (DOCX+PDF+HTML)' }, pageSize: { type: 'string', enum: ['A3', 'A4', 'Executive', 'US_Legal', 'US_Letter'], description: 'Page size for the document', default: 'A4' }, orientation: { type: 'string', enum: ['Portrait', 'Landscape'], description: 'Page orientation', default: 'Portrait' } }, required: ['content', 'templateName', 'outputFormat'] } }; - src/tools/index.ts:48-79 (registration)Unified handler registration: routes 'estimate_conversion_cost' tool requests to handleEstimateConversionCost(creditCalculator, args) from creditTools.ts.
case 'estimate_conversion_cost': return await handleEstimateConversionCost(creditCalculator, request.params.arguments); case 'validate_markdown': return await handleValidateMarkdown(apiClient, request.params.arguments); case 'get_template_details': return await handleGetTemplateDetails(apiClient, request.params.arguments); case 'recommend_template': return await handleRecommendTemplate(apiClient, request.params.arguments); default: throw new Error(`Unknown tool: ${toolName}`); } } catch (error: any) { console.error(`[MCP] Error handling ${toolName}:`, error); return { content: [ { type: "text", text: `❌ Error: ${error.message}` } ], isError: true }; } }); console.error('✅ All MCP tools registered successfully with unified handler'); console.error('📋 Available tools: convert_document, list_all_templates, list_builtin_templates, list_custom_templates, show_default_settings, check_credit_balance, estimate_conversion_cost, validate_markdown, get_template_details, recommend_template'); }