recommend_template
Recommends matching built-in templates for a described document purpose, preventing conversion errors from incorrect template guesses.
Instructions
Suggest the best built-in template(s) for a described purpose. Use this when the user describes WHAT the document is (e.g. 'Q4 board pack', 'API reference', 'wedding invitation', 'legal contract') without naming a template. Returns ranked recommendations with rationale.
Why this exists: AI assistants often guess template names that don't exist. This tool maps purpose → real template names from MDMagic's catalog, so convert_document doesn't fail with 'template not found'.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| purpose | Yes | Free-text description of the document's purpose. Examples: 'Q4 board pack for investors', 'restaurant menu', 'developer API documentation', 'wedding invitation'. | |
| topN | No | How many recommendations to return (1-5, default 3) |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| purpose | No | Echoes back the purpose that was matched | |
| rationale | No | Why these templates were picked | |
| recommendations | Yes | Ranked list of template IDs to pass to convert_document |
Implementation Reference
- src/tools/recommendTemplate.ts:81-146 (handler)Main handler function for recommend_template. Parses input via Zod schema, scores purpose text against keyword rules, picks winning template recommendations, optionally validates them against the API, and returns a formatted text response.
export async function handleRecommendTemplate( apiClient: MDMagicApiClient, args: any ): Promise<CallToolResult> { try { const input = recommendTemplateSchema.parse(args); console.error(`[recommend_template] Purpose: "${input.purpose}"`); // Score each rule by number of pattern matches against the purpose string const matched: Array<{ recommend: string[]; rationale: string; score: number }> = []; for (const rule of KEYWORD_RULES) { let score = 0; for (const pat of rule.patterns) { if (pat.test(input.purpose)) score++; } if (score > 0) matched.push({ ...rule, score }); } // Pick winning rule (highest score; ties → first declared, which is most specific) matched.sort((a, b) => b.score - a.score); const winner = matched[0]; let picked: string[]; let rationale: string; if (winner) { picked = winner.recommend.slice(0, input.topN); rationale = winner.rationale; } else { // No strong match — recommend safe defaults that work for most prose picked = ['Professional_Azure', 'Executive_Platinum', 'Minimalist_Pro'].slice(0, input.topN); rationale = 'No strong keyword match — these are versatile templates that work for most general-purpose documents.'; } // Optionally: validate the recommended templates exist on the API. // If the catalog has shifted, fall back gracefully without erroring. let validated = picked; try { const builtin = await apiClient.getTemplates(); const known = new Set((builtin.templates || []).map(t => (t.id || '').toLowerCase())); validated = picked.filter(p => known.has(p.toLowerCase())); if (validated.length === 0) { validated = picked; // API returned nothing useful; show recommendations anyway } } catch { // Network/auth failure — keep the keyword-derived list } const lines = [ `🎯 **Template recommendations for: "${input.purpose}"**`, '', `**Why these**: ${rationale}`, '', `**Top ${validated.length}:**`, ]; validated.forEach((id, i) => { lines.push(`${i + 1}. \`${id}\``); }); lines.push(''); lines.push('💡 Pass any of these as `templateName` to `convert_document`. Call `list_all_templates` to see the full catalog including custom templates.'); return { content: [{ type: 'text', text: lines.join('\n') }] }; } catch (error: any) { console.error('[recommend_template] Error:', error.message); throw error; } } - src/tools/recommendTemplate.ts:6-9 (schema)Zod schema defining input validation: `purpose` (string) and `topN` (integer 1-5, default 3).
export const recommendTemplateSchema = z.object({ purpose: z.string().describe('What the document is for. Examples: "Q4 board pack", "API reference docs", "wedding invitation", "legal contract", "data analysis report".'), topN: z.number().int().min(1).max(5).default(3).describe('How many recommendations to return (1-5).') }); - src/tools/index.ts:57-58 (registration)Switch-case registration dispatching 'recommend_template' tool name to handleRecommendTemplate.
case 'recommend_template': return await handleRecommendTemplate(apiClient, request.params.arguments); - src/tools/index.ts:12-12 (registration)Import of handleRecommendTemplate from the recommendTemplate module.
import { handleRecommendTemplate } from './recommendTemplate.js'; - src/tools/recommendTemplate.ts:18-79 (helper)Keyword rule definitions mapping regex patterns to template recommendations with rationale. Covers legal, executive, finance, technical, data, creative, food, wellness, minimalist, and generic business categories.
const KEYWORD_RULES: Array<{ patterns: RegExp[]; recommend: string[]; rationale: string }> = [ // Legal / contracts { patterns: [/\b(legal|contract|agreement|nda|terms|policy|compliance|statute|brief|affidavit|deed|will|testament)\b/i], recommend: ['Legal_Burgundy', 'Modern_Legal', 'Executive_Platinum'], rationale: 'Legal templates emphasise traditional formatting, signature blocks, and section numbering.' }, // Executive / board / strategy { patterns: [/\b(board|exec|executive|strategy|strategic|c[\-\s]?suite|leadership|quarterly|annual report|investor|stakeholder|q[1-4]\b)\b/i], recommend: ['Executive_Platinum', 'Premium_Bronze', 'Professional_Azure'], rationale: 'Executive-grade typography and conservative styling suited to leadership audiences.' }, // Finance / numbers / accounting { patterns: [/\b(financial|finance|budget|accounting|p&l|balance sheet|forecast|invoice|revenue|earnings)\b/i], recommend: ['Financial_Blue', 'Executive_Platinum', 'Professional_Azure'], rationale: 'Financial templates handle tables, footnotes, and figure-heavy content cleanly.' }, // Code / API / technical docs { patterns: [/\b(api|reference|sdk|developer|technical doc|architecture|engineering|spec(ification)?|readme|changelog|release notes|code|programming|library)\b/i], recommend: ['Code_Documentation', 'Deep_Data_Blue', 'Professional_Azure'], rationale: 'Technical templates render code blocks, diagrams, and structured headings well.' }, // Data / analytics / research { patterns: [/\b(data|analytics|analysis|research|study|metrics|kpi|dashboard|report card|whitepaper|white paper)\b/i], recommend: ['Deep_Data_Blue', 'Financial_Blue', 'Code_Documentation'], rationale: 'Data-focused templates support charts, tables, and figure captions.' }, // Creative / marketing / fun { patterns: [/\b(invitation|invite|wedding|party|birthday|menu|brochure|flyer|poster|marketing|campaign|brand|creative)\b/i], recommend: ['Designer_Indigo', 'Artistic_Aqua', 'Sunset_Vibes'], rationale: 'Creative templates use distinctive typography and colour to grab attention.' }, // Food / restaurant / casual { patterns: [/\b(menu|recipe|food|restaurant|cafe|cooking)\b/i], recommend: ['Cheese_Burger', 'Sunset_Vibes', 'Designer_Indigo'], rationale: 'Casual, food-friendly typography that reads warm rather than corporate.' }, // Wellness / lifestyle / mindfulness { patterns: [/\b(wellness|yoga|meditation|mindfulness|health|wellbeing|lifestyle|nature|garden|holistic)\b/i], recommend: ['Sage_Serenity', 'Artistic_Aqua', 'Minimalist_Pro'], rationale: 'Calm, nature-inspired styling appropriate for wellness/lifestyle content.' }, // Minimalist / clean { patterns: [/\b(minimal|clean|simple|stripped|bare)\b/i], recommend: ['Minimalist_Pro', 'Professional_Azure', 'Designer_Indigo'], rationale: 'Clean, low-ornament templates that put content first.' }, // Generic business / proposal / corporate { patterns: [/\b(business|corporate|proposal|pitch|deck|memo|briefing)\b/i], recommend: ['Professional_Azure', 'Business_Purple', 'Executive_Platinum'], rationale: 'General-purpose business templates suited to internal and external audiences.' }, ];