diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d637ca..37167c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.2.4] - 2026-02-01 + +- Accept MCP arguments/input and validate payloads +- Emit MCP image content with `data` + `mimeType` fields + ## [0.2.3] - 2026-02-01 - Harden MCP request handling @@ -26,4 +31,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.0] - 2026-02-01 - Initial release - diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index b30ea06..c7b9082 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "mermkit" -version = "0.2.3" +version = "0.2.4" description = "Python bindings for mermkit (Mermaid rendering toolkit)" readme = "README.md" requires-python = ">=3.8" diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml index bb159eb..6557668 100644 --- a/bindings/rust/Cargo.toml +++ b/bindings/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mermkit" -version = "0.2.3" +version = "0.2.4" edition = "2021" description = "Rust bindings for mermkit (Mermaid rendering toolkit)" license = "MIT" diff --git a/package.json b/package.json index b170c1b..1d7385e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "mermkit", "private": true, - "version": "0.2.3", + "version": "0.2.4", "repository": { "type": "git", "url": "https://github.com/MermaidKit/mermkit.git" diff --git a/packages/adapters/package.json b/packages/adapters/package.json index ee0d625..b9be307 100644 --- a/packages/adapters/package.json +++ b/packages/adapters/package.json @@ -1,6 +1,6 @@ { "name": "@mermkit/adapters", - "version": "0.2.3", + "version": "0.2.4", "repository": { "type": "git", "url": "https://github.com/MermaidKit/mermkit.git" @@ -18,6 +18,6 @@ "build": "tsc -b" }, "dependencies": { - "@mermkit/core": "0.2.3" + "@mermkit/core": "0.2.4" } } diff --git a/packages/cli/package.json b/packages/cli/package.json index b6d12a0..5e69fa9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@mermkit/cli", - "version": "0.2.3", + "version": "0.2.4", "repository": { "type": "git", "url": "https://github.com/MermaidKit/mermkit.git" @@ -19,8 +19,8 @@ "build": "tsc -b" }, "dependencies": { - "@mermkit/core": "0.2.3", - "@mermkit/render": "0.2.3", - "@mermkit/adapters": "0.2.3" + "@mermkit/core": "0.2.4", + "@mermkit/render": "0.2.4", + "@mermkit/adapters": "0.2.4" } } diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index 53b10c9..ba4b72c 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -842,7 +842,9 @@ async function cmdMcp(): Promise { if (request.method === "tools/call") { const params = request.params ?? {}; const toolName = resolveMcpToolName((params as { name?: unknown }).name); - const toolInput = (params.input ?? {}) as Record; + const toolInput = ((params as { input?: unknown; arguments?: unknown }).input ?? + (params as { arguments?: unknown }).arguments ?? + {}) as Record; try { if (!toolName) { @@ -871,7 +873,10 @@ async function cmdMcp(): Promise { async function executeMcpTool(name: string, input: Record): Promise> { if (name === "mermkit.render") { - const source = input.diagram as string; + if (typeof input.diagram !== "string") { + throw new Error("diagram is required and must be a string"); + } + const source = input.diagram; const options = (input.options ?? {}) as Record; const diagram = { id: "diagram-1", source: normalizeDiagram(source) }; const result = await render(diagram, { @@ -885,18 +890,24 @@ async function executeMcpTool(name: string, input: Record): Pro if (format === "ascii") { return [{ type: "text", text: new TextDecoder().decode(result.bytes) }]; } - const mediaType = result.mime; - return [{ type: "image", source: { type: "base64", mediaType, data: Buffer.from(result.bytes).toString("base64") } }]; + const mimeType = result.mime ?? "application/octet-stream"; + return [{ type: "image", data: Buffer.from(result.bytes).toString("base64"), mimeType }]; } if (name === "mermkit.renderBatch") { - const diagrams = input.diagrams as Array<{ id?: string; source: string }>; + if (!Array.isArray(input.diagrams)) { + throw new Error("diagrams is required and must be an array"); + } + const diagrams = input.diagrams as Array<{ id?: string; source?: string }>; const options = (input.options ?? {}) as Record; const results: Array<{ type: string; [key: string]: unknown }> = []; for (let i = 0; i < diagrams.length; i++) { const item = diagrams[i]; const diagramId = item.id ?? `diagram-${i + 1}`; try { + if (typeof item.source !== "string") { + throw new Error("diagram source must be a string"); + } const diagram = { id: diagramId, source: normalizeDiagram(item.source) }; const result = await render(diagram, { format: (options.format as "svg" | "png" | "pdf" | "ascii") ?? "svg", @@ -909,7 +920,8 @@ async function executeMcpTool(name: string, input: Record): Pro if (format === "ascii") { results.push({ type: "text", text: `[${diagramId}]\n${new TextDecoder().decode(result.bytes)}` }); } else { - results.push({ type: "image", source: { type: "base64", mediaType: result.mime, data: Buffer.from(result.bytes).toString("base64") } }); + const mimeType = result.mime ?? "application/octet-stream"; + results.push({ type: "image", data: Buffer.from(result.bytes).toString("base64"), mimeType }); } } catch (error) { results.push({ type: "text", text: `[${diagramId}] error: ${errorMessage(error)}` }); @@ -919,14 +931,20 @@ async function executeMcpTool(name: string, input: Record): Pro } if (name === "mermkit.extract") { - const markdown = input.markdown as string; + if (typeof input.markdown !== "string") { + throw new Error("markdown is required and must be a string"); + } + const markdown = input.markdown; const diagrams = extractDiagrams(markdown); const text = diagrams.map((d) => `[${d.id}]\n${d.source}`).join("\n\n"); return [{ type: "text", text: text || "no diagrams found" }]; } if (name === "mermkit.term") { - const source = input.diagram as string; + if (typeof input.diagram !== "string") { + throw new Error("diagram is required and must be a string"); + } + const source = input.diagram; const diagram = { id: "diagram-1", source: normalizeDiagram(source) }; const result = await renderForTerminal(diagram, detectCapabilities()); return [{ type: "text", text: result.text ?? "unable to render for terminal" }]; diff --git a/packages/core/package.json b/packages/core/package.json index 195b4b5..d47c4df 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@mermkit/core", - "version": "0.2.3", + "version": "0.2.4", "repository": { "type": "git", "url": "https://github.com/MermaidKit/mermkit.git" diff --git a/packages/render/package.json b/packages/render/package.json index 499fb55..75a05be 100644 --- a/packages/render/package.json +++ b/packages/render/package.json @@ -1,6 +1,6 @@ { "name": "@mermkit/render", - "version": "0.2.3", + "version": "0.2.4", "repository": { "type": "git", "url": "https://github.com/MermaidKit/mermkit.git" @@ -18,7 +18,7 @@ "build": "tsc -b" }, "dependencies": { - "@mermkit/core": "0.2.3" + "@mermkit/core": "0.2.4" }, "optionalDependencies": { "dompurify": "^3.1.5",