feat(mcp): add XML validation and auto-fix to MCP server (#336)

* feat(mcp): add XML validation and auto-fix to MCP server

- Add xml-validation.ts with validateAndFixXml function
- Integrate validation into display_diagram tool (fails if unfixable)
- Integrate validation into edit_diagram tool (auto-fix each operation)
- Fix bug: typo fixes now run before foreign tag removal
- Fix bug: use before/after comparison instead of regex .test()

* style: auto-format with Biome

* chore(mcp): bump version to 0.1.3

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Dayuan Jiang
2025-12-21 00:32:51 +09:00
committed by GitHub
parent 378bef435e
commit 938faff6b2
7 changed files with 1036 additions and 67 deletions

View File

@@ -41,6 +41,7 @@ import {
startHttpServer,
} from "./http-server.js"
import { log } from "./logger.js"
import { validateAndFixXml } from "./xml-validation.js"
// Server configuration
const config = {
@@ -160,7 +161,7 @@ server.registerTool(
.describe("The draw.io XML to display (mxGraphModel format)"),
},
},
async ({ xml }) => {
async ({ xml: inputXml }) => {
try {
if (!currentSession) {
return {
@@ -174,6 +175,26 @@ server.registerTool(
}
}
// Validate and auto-fix XML
let xml = inputXml
const { valid, error, fixed, fixes } = validateAndFixXml(xml)
if (fixed) {
xml = fixed
log.info(`XML auto-fixed: ${fixes.join(", ")}`)
}
if (!valid && error) {
log.error(`XML validation failed: ${error}`)
return {
content: [
{
type: "text",
text: `Error: XML validation failed - ${error}`,
},
],
isError: true,
}
}
log.info(`Displaying diagram, ${xml.length} chars`)
// Update session state
@@ -274,10 +295,31 @@ server.registerTool(
log.info(`Editing diagram with ${operations.length} operation(s)`)
// Validate and auto-fix new_xml for each operation
const validatedOps = operations.map((op) => {
if (op.new_xml) {
const { valid, error, fixed, fixes } = validateAndFixXml(
op.new_xml,
)
if (fixed) {
log.info(
`Operation ${op.type} ${op.cell_id}: XML auto-fixed: ${fixes.join(", ")}`,
)
return { ...op, new_xml: fixed }
}
if (!valid && error) {
log.warn(
`Operation ${op.type} ${op.cell_id}: XML validation failed: ${error}`,
)
}
}
return op
})
// Apply operations
const { result, errors } = applyDiagramOperations(
currentSession.xml,
operations as DiagramOperation[],
validatedOps as DiagramOperation[],
)
if (errors.length > 0) {