validate_markdown
Pre-validate markdown to catch malformed tables, unclosed code fences, and broken task lists before conversion, returning a safety status and detected features.
Instructions
Pre-flight markdown validation BEFORE conversion. Catches malformed tables (mismatched pipes), unclosed code fences, broken task lists, and unsupported syntax. Returns a green/amber/red status plus the detected markdown features.
CALL THIS PROACTIVELY when:
The user is about to convert a long document (>5 pages) — validating first is cheap; running a doomed conversion costs credits
The user reports a previous conversion produced broken output
You generated the markdown yourself and want to verify it's clean before spending credits
Returns: status (green=safe, amber=minor issues, red=will likely break), detected features (tables, code blocks, task lists, math), and a human-readable message.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | Markdown content to validate | |
| filename | No | Optional filename label for the response (defaults to 'content.md') |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filename | No | Filename label echoed back | |
| status | Yes | Validation verdict | |
| message | Yes | Human-readable explanation of any issues | |
| inputFormat | No | Detected markdown flavour (e.g. gfm, commonmark) | |
| additionalPandocFlags | No | Pandoc flags that will be applied | |
| detectedFeatures | No | Map of markdown features found in the content |
Implementation Reference
- src/tools/validateMarkdown.ts:17-59 (handler)Main handler function for the validate_markdown tool. Validates markdown content via the API client, interprets the result (green/amber/red status), and returns a formatted human-readable response with recommendations.
export async function handleValidateMarkdown( apiClient: MDMagicApiClient, args: any ): Promise<CallToolResult> { try { const input = validateMarkdownSchema.parse(args); console.error(`[validate_markdown] Validating ${input.content.length} bytes...`); const result = await apiClient.validateMarkdownContent(input.content, input.filename); const emoji = STATUS_EMOJI[result.status] || '❓'; const detectedList = Object.entries(result.detectedFeatures || {}) .filter(([, v]) => v) .map(([k]) => k); const lines = [ `${emoji} **Markdown validation: ${result.status.toUpperCase()}**`, '', `**File**: ${result.filename}`, `**Detected format**: ${result.inputFormat || 'unknown'}`, `**Message**: ${result.message}`, ]; if (detectedList.length > 0) { lines.push('', `**Features detected**: ${detectedList.join(', ')}`); } if (result.status === 'red') { lines.push('', '⚠️ **Recommendation**: Fix the issues above before calling `convert_document` — a red status usually produces broken output and still costs credits.'); } else if (result.status === 'amber') { lines.push('', 'ℹ️ Conversion will work but may have minor rendering issues. Safe to proceed.'); } else { lines.push('', '✅ Ready for conversion. Call `convert_document` next.'); } return { content: [{ type: 'text', text: lines.join('\n') }] }; } catch (error: any) { console.error('[validate_markdown] Error:', error.message); throw error; } } - src/tools/validateMarkdown.ts:6-9 (schema)Zod schema defining the input for validate_markdown: content (required string) and filename (optional string).
export const validateMarkdownSchema = z.object({ content: z.string().describe('Markdown content to validate'), filename: z.string().optional().describe('Optional filename for the response label') }); - src/services/apiClient.ts:123-136 (helper)API client method validateMarkdownContent that POSTs the content to /api/validate-markdown/content endpoint and returns the validation result (status, message, inputFormat, detectedFeatures, etc.).
async validateMarkdownContent(content: string, filename?: string): Promise<{ filename: string; status: 'green' | 'amber' | 'red' | string; message: string; inputFormat: string | null; additionalPandocFlags: string[]; detectedFeatures: Record<string, any>; }> { const response: AxiosResponse = await this._client.post('/api/validate-markdown/content', { content, filename: filename || 'content.md' }); return response.data; } - src/tools/index.ts:51-52 (registration)Registration of validate_markdown in the unified tool dispatcher switch-case, routing requests to handleValidateMarkdown.
case 'validate_markdown': return await handleValidateMarkdown(apiClient, request.params.arguments); - src/index.ts:297-332 (registration)Tool registration metadata including name, description (with proactive usage guidance), annotations, inputSchema, and outputSchema for the MCP server capabilities listing.
{ name: "validate_markdown", description: "Pre-flight markdown validation BEFORE conversion. Catches malformed tables (mismatched pipes), unclosed code fences, broken task lists, and unsupported syntax. Returns a green/amber/red status plus the detected markdown features.\n\nCALL THIS PROACTIVELY when:\n- The user is about to convert a long document (>5 pages) — validating first is cheap; running a doomed conversion costs credits\n- The user reports a previous conversion produced broken output\n- You generated the markdown yourself and want to verify it's clean before spending credits\n\nReturns: status (green=safe, amber=minor issues, red=will likely break), detected features (tables, code blocks, task lists, math), and a human-readable message.", annotations: { title: "Validate markdown before conversion", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }, inputSchema: { type: "object" as const, properties: { content: { type: "string", description: "Markdown content to validate" }, filename: { type: "string", description: "Optional filename label for the response (defaults to 'content.md')" } }, required: ["content"] }, outputSchema: { type: "object" as const, properties: { filename: { type: "string", description: "Filename label echoed back" }, status: { type: "string", enum: ["green", "amber", "red"], description: "Validation verdict" }, message: { type: "string", description: "Human-readable explanation of any issues" }, inputFormat: { type: ["string", "null"], description: "Detected markdown flavour (e.g. gfm, commonmark)" }, additionalPandocFlags: { type: "array", items: { type: "string" }, description: "Pandoc flags that will be applied" }, detectedFeatures: { type: "object", description: "Map of markdown features found in the content" } }, required: ["status", "message"] }