@markdy/mcp-server 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +68 -8
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -668,7 +668,8 @@ var EDGE_OPERATORS = {
668
668
  "->": "request",
669
669
  "<-": "response",
670
670
  "~>": "event",
671
- "--": "dependency"
671
+ "--": "dependency",
672
+ "..>": "dependency"
672
673
  };
673
674
  var RESERVED_SELECTORS = /* @__PURE__ */ new Set(["$title", "$nodes", "$edges"]);
674
675
  var CUE_ALIASES = {
@@ -916,7 +917,7 @@ var THEMES = {
916
917
  dependency: "#818cf8"
917
918
  },
918
919
  fonts: {
919
- title: "Georgia, Times New Roman, serif",
920
+ title: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Inter, sans-serif",
920
921
  nodeName: "ui-sans-serif, system-ui, sans-serif",
921
922
  mono: "ui-monospace, SFMono-Regular, Menlo, monospace"
922
923
  },
@@ -1137,7 +1138,7 @@ var ParseError = class extends Error {
1137
1138
  this.column = column;
1138
1139
  }
1139
1140
  };
1140
- var FLOW_OP_RE = /(->|<-|~>|--)/;
1141
+ var FLOW_OP_RE = /(->|<-|~>|--|\.\.>|<->)/;
1141
1142
  function stripComment(line) {
1142
1143
  let inString = false;
1143
1144
  let escaped = false;
@@ -1189,7 +1190,7 @@ function parseProps(raw) {
1189
1190
  i = raw.length - parsed.rest.length;
1190
1191
  continue;
1191
1192
  }
1192
- const keyMatch = raw.slice(i).match(/^(\w[\w.-]*)=/);
1193
+ const keyMatch = raw.slice(i).match(/^(@?[\w.-]+)=/);
1193
1194
  if (!keyMatch) {
1194
1195
  i++;
1195
1196
  continue;
@@ -1307,6 +1308,14 @@ function tokenizeFlowChain(line) {
1307
1308
  current += ch;
1308
1309
  continue;
1309
1310
  }
1311
+ const op3 = line.slice(i, i + 3);
1312
+ if (op3 === "..>" || op3 === "<->") {
1313
+ if (current.trim()) parts.push(current.trim());
1314
+ parts.push(op3);
1315
+ current = "";
1316
+ i += 2;
1317
+ continue;
1318
+ }
1310
1319
  const op = line.slice(i, i + 2);
1311
1320
  if (op === "->" || op === "<-" || op === "~>" || op === "--") {
1312
1321
  if (current.trim()) parts.push(current.trim());
@@ -1330,11 +1339,27 @@ function parseFlowChain(line, lineNo) {
1330
1339
  let from = splitTargetLabel(parts[i++], lineNo).node;
1331
1340
  while (i < parts.length) {
1332
1341
  const opToken = parts[i++];
1333
- const op = EDGE_OPERATORS[opToken];
1334
- if (!op) throw new ParseError(`unknown flow operator '${opToken}'`, lineNo);
1335
1342
  if (i >= parts.length) throw new ParseError(`expected target after '${opToken}'`, lineNo);
1336
1343
  const { node: to, label } = splitTargetLabel(parts[i++], lineNo);
1337
1344
  if (!to) throw new ParseError(`expected target node after '${opToken}'`, lineNo);
1345
+ if (opToken === "<->") {
1346
+ segments.push({
1347
+ from,
1348
+ op: "request",
1349
+ to,
1350
+ label
1351
+ });
1352
+ segments.push({
1353
+ from: to,
1354
+ op: "response",
1355
+ to: from,
1356
+ label
1357
+ });
1358
+ from = to;
1359
+ continue;
1360
+ }
1361
+ const op = EDGE_OPERATORS[opToken];
1362
+ if (!op) throw new ParseError(`unknown flow operator '${opToken}'`, lineNo);
1338
1363
  segments.push({
1339
1364
  from: op === "response" ? to : from,
1340
1365
  op,
@@ -2131,7 +2156,13 @@ function matchNode(node, selector) {
2131
2156
  if (selector.kindEquals && node.kind.toLowerCase() !== selector.kindEquals.toLowerCase()) return false;
2132
2157
  if (selector.roleEquals) {
2133
2158
  const role = nodeRole(node.kind);
2134
- if (role.toLowerCase() !== selector.roleEquals.toLowerCase()) return false;
2159
+ const targetRole = selector.roleEquals.toLowerCase();
2160
+ if (targetRole === "gateway") {
2161
+ const isGateway = role === "network" || ["gateway", "api_gateway", "reverse_proxy", "proxy", "router"].includes(node.kind.toLowerCase());
2162
+ if (!isGateway) return false;
2163
+ } else if (role.toLowerCase() !== targetRole) {
2164
+ return false;
2165
+ }
2135
2166
  }
2136
2167
  if (selector.labelContains) {
2137
2168
  const target = (node.label || node.id).toLowerCase();
@@ -2292,6 +2323,30 @@ var ARCH_RULE_PRESETS = {
2292
2323
  from: { roleEquals: "security" }
2293
2324
  }
2294
2325
  ]
2326
+ },
2327
+ deploymentOwnership: {
2328
+ id: "deployment-ownership",
2329
+ name: "Deployment Ownership & Regional Governance",
2330
+ description: "Ensure production stateful stores and services are guarded in explicit group perimeters",
2331
+ rules: [
2332
+ {
2333
+ id: "no-unprotected-public-database",
2334
+ name: "No Public Database Exposure",
2335
+ description: "Databases and stateful stores must not be directly accessed from public browser/mobile clients.",
2336
+ severity: "error",
2337
+ type: "cannot-connect",
2338
+ from: { roleEquals: "client" },
2339
+ to: { roleEquals: "data" }
2340
+ },
2341
+ {
2342
+ id: "no-cross-region-sync-bypasses",
2343
+ name: "Synchronous Request Cycle Prevention",
2344
+ description: "Synchronous requests must not form cycles across microservices.",
2345
+ severity: "error",
2346
+ type: "forbidden-cycle",
2347
+ edge: { kind: "request" }
2348
+ }
2349
+ ]
2295
2350
  }
2296
2351
  };
2297
2352
  function validateArchitecture(ast, rules = [
@@ -2299,7 +2354,7 @@ function validateArchitecture(ast, rules = [
2299
2354
  ...ARCH_RULE_PRESETS.microservicesGovernance.rules
2300
2355
  ]) {
2301
2356
  const violations = [];
2302
- const nodes = Object.values(ast.nodes);
2357
+ const nodes = Object.values(ast?.nodes || {});
2303
2358
  const nodeMap = new Map(nodes.map((n) => [n.id, n]));
2304
2359
  const edges = extractAllEdges(ast);
2305
2360
  for (const rule of rules) {
@@ -2346,6 +2401,11 @@ function validateArchitecture(ast, rules = [
2346
2401
  break;
2347
2402
  }
2348
2403
  case "forbidden-cycle": {
2404
+ const dtype = ast.meta?.type || ast.config?.type || "architecture";
2405
+ const nonServiceArchetypes = ["state", "sequence", "layers", "flywheel", "loop", "venn"];
2406
+ if (nonServiceArchetypes.includes(dtype)) {
2407
+ break;
2408
+ }
2349
2409
  const cycleInfo = detectCycleInGraph(nodes, edges, rule.edge);
2350
2410
  if (cycleInfo) {
2351
2411
  violations.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markdy/mcp-server",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "Model Context Protocol server for Markdy diagram validation, transpilation, and generation.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,8 +39,8 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@modelcontextprotocol/sdk": "^1.6.1",
42
- "@markdy/compat": "1.2.0",
43
- "@markdy/core": "1.2.0"
42
+ "@markdy/core": "1.3.1",
43
+ "@markdy/compat": "1.3.1"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^25.9.5",