@morphism-systems/mcp-server 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # @morphism-systems/mcp-server
2
+
3
+ Governance MCP server for AI agents. Validate governance policies, compute maturity scores, track convergence and drift metrics.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npx @morphism-systems/mcp-server
9
+ ```
10
+
11
+ ## MCP Config
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "morphism-governance": {
17
+ "command": "npx",
18
+ "args": ["@morphism-systems/mcp-server"]
19
+ }
20
+ }
21
+ }
22
+ ```
23
+
24
+ ## Tools
25
+
26
+ | Tool | Description |
27
+ |------|-------------|
28
+ | `governance_validate` | Run full governance validation pipeline |
29
+ | `governance_score` | Compute maturity score (0-105) |
30
+ | `compute_kappa` | Convergence metric (kappa < 1 = converging) |
31
+ | `compute_delta` | Drift metric between governance states |
32
+ | `ssot_verify` | Verify SSOT integrity |
33
+
34
+ ## Why Morphism
35
+
36
+ Governance-as-code with mathematical guarantees. [Learn more](https://morphism.systems).
37
+
38
+ ## License
39
+
40
+ MIT
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+
6
+ // src/server.ts
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+
9
+ // src/tools/validate.ts
10
+ import { z } from "zod";
11
+ import { execSync } from "child_process";
12
+ var ValidateInput = z.object({
13
+ project_path: z.string().describe("Path to the project root to validate"),
14
+ mode: z.enum(["categorical", "pipeline", "full"]).optional().default("full").describe(
15
+ "categorical: naturality + sheaf + kappa only; pipeline: legacy file checks; full: both"
16
+ )
17
+ });
18
+ function runPython(cmd, cwd) {
19
+ try {
20
+ const stdout = execSync(cmd, { cwd, encoding: "utf-8", timeout: 6e4 });
21
+ return { stdout, stderr: "", ok: true };
22
+ } catch (err) {
23
+ return { stdout: err.stdout || "", stderr: err.stderr || "", ok: false };
24
+ }
25
+ }
26
+ async function governanceValidate(input) {
27
+ const { project_path, mode } = input;
28
+ const catScript = `
29
+ import json, sys
30
+ sys.path.insert(0, '${project_path}/src')
31
+ from pathlib import Path
32
+ from morphism.governance_category import full_categorical_validation
33
+ result = full_categorical_validation(Path('${project_path}'))
34
+ print(json.dumps(result))
35
+ `;
36
+ const catResult = runPython(
37
+ `python3 -c "${catScript.replace(/\n/g, "; ").replace(/"/g, '\\"')}"`,
38
+ project_path
39
+ );
40
+ let categorical = null;
41
+ if (catResult.ok && catResult.stdout.trim()) {
42
+ try {
43
+ categorical = JSON.parse(catResult.stdout.trim());
44
+ } catch (_) {
45
+ }
46
+ }
47
+ let pipelineOutput = "";
48
+ let pipelineOk = true;
49
+ if (mode === "pipeline" || mode === "full") {
50
+ const pipe = runPython("python3 scripts/verify_pipeline.py", project_path);
51
+ pipelineOutput = pipe.stdout + pipe.stderr;
52
+ pipelineOk = pipe.ok;
53
+ }
54
+ if (categorical) {
55
+ const proofScript = `
56
+ import json, sys
57
+ sys.path.insert(0, '${project_path}/src')
58
+ from pathlib import Path
59
+ from morphism.governance_category import full_categorical_validation, compute_runtime_evidence
60
+ from morphism.proof.artifact import generate_proof_artifact, write_proof_artifact
61
+ root = Path('${project_path}')
62
+ cat = full_categorical_validation(root)
63
+ gov_vec = cat['governance_vector']
64
+ kappa = cat['kappa']
65
+ proof = generate_proof_artifact(
66
+ root=root,
67
+ naturality_result=cat['naturality'],
68
+ chain_morphisms=[v['morphism'] for v in cat['naturality'].get('verdicts', [])],
69
+ chain_source='Policy',
70
+ chain_target='Runbook',
71
+ convergence_data={'kappa': kappa, 'governance_vector': gov_vec, 'vector_labels': cat['vector_labels'], 'l_inf_distance': kappa},
72
+ sheaf_radius=cat['sheaf']['consistency_radius'],
73
+ drift_types=cat['sheaf']['drift_types'],
74
+ governance_score=sum(gov_vec) / len(gov_vec) if gov_vec else 0.0,
75
+ )
76
+ p = write_proof_artifact(proof, root)
77
+ print(str(p))
78
+ `;
79
+ const proofResult = runPython(
80
+ `python3 -c "${proofScript.replace(/\n/g, "; ").replace(/"/g, '\\"')}"`,
81
+ project_path
82
+ );
83
+ const proofPath = proofResult.ok ? proofResult.stdout.trim() : void 0;
84
+ const nat = categorical.naturality || {};
85
+ return {
86
+ valid: categorical.all_valid && pipelineOk,
87
+ kappa: categorical.kappa,
88
+ governance_vector: categorical.governance_vector,
89
+ vector_labels: categorical.vector_labels,
90
+ naturality: {
91
+ all_natural: nat.all_natural ?? false,
92
+ summary: nat.summary ?? "",
93
+ total: nat.total ?? 0
94
+ },
95
+ sheaf: {
96
+ consistency_radius: categorical.sheaf?.consistency_radius ?? 0,
97
+ severity: categorical.sheaf?.severity ?? "unknown",
98
+ drift_types: categorical.sheaf?.drift_types ?? []
99
+ },
100
+ categorical_errors: categorical.categorical_errors ?? [],
101
+ proof_artifact_path: proofPath,
102
+ output: pipelineOutput || void 0
103
+ };
104
+ }
105
+ const legacy = runPython("python3 scripts/verify_pipeline.py", project_path);
106
+ return {
107
+ valid: legacy.ok,
108
+ output: legacy.stdout,
109
+ error: legacy.stderr || catResult.stderr || void 0
110
+ };
111
+ }
112
+
113
+ // src/tools/score.ts
114
+ import { z as z2 } from "zod";
115
+ var ScoreInput = z2.object({
116
+ project_path: z2.string().describe("Path to the project root")
117
+ });
118
+ async function governanceScore(input) {
119
+ const { execSync: execSync3 } = await import("child_process");
120
+ try {
121
+ const result = execSync3(
122
+ `python3 scripts/maturity_score.py --ci --threshold 0`,
123
+ { cwd: input.project_path, encoding: "utf-8", timeout: 3e4 }
124
+ );
125
+ const match = result.match(/(\d+)\s*\/\s*(\d+)/);
126
+ if (match) {
127
+ return { score: parseInt(match[1]), total: parseInt(match[2]), output: result };
128
+ }
129
+ return { output: result };
130
+ } catch (err) {
131
+ const error = err;
132
+ return { error: error.stderr || error.stdout || "Unknown error" };
133
+ }
134
+ }
135
+
136
+ // src/tools/kappa.ts
137
+ import { z as z3 } from "zod";
138
+ import { execSync as execSync2 } from "child_process";
139
+ var KappaInput = z3.object({
140
+ scores: z3.array(z3.number()).optional().describe("Legacy scalar score sequence (backward compat)"),
141
+ governance_vector: z3.array(z3.number()).optional().describe(
142
+ "7-dimensional governance state vector [Policy, GitHook, CIWorkflow, SSOTAtom, Document, SecurityGate, Runbook]"
143
+ ),
144
+ kappa_history: z3.array(z3.number()).optional().describe(
145
+ "Historical kappa values for convergence trajectory check"
146
+ ),
147
+ project_path: z3.string().optional().describe(
148
+ "If provided, compute vector from live project state (ignores governance_vector)"
149
+ ),
150
+ tolerance: z3.number().optional().default(1e-6)
151
+ });
152
+ var GOVERNANCE_OBJECTS = [
153
+ "Policy",
154
+ "GitHook",
155
+ "CIWorkflow",
156
+ "SSOTAtom",
157
+ "Document",
158
+ "SecurityGate",
159
+ "Runbook"
160
+ ];
161
+ var WEIGHTS = {
162
+ Policy: 1.5,
163
+ GitHook: 1.2,
164
+ CIWorkflow: 1.2,
165
+ SSOTAtom: 1,
166
+ Document: 0.8,
167
+ SecurityGate: 1.5,
168
+ Runbook: 0.9
169
+ };
170
+ function vectorKappa(v, ideal = []) {
171
+ const n = GOVERNANCE_OBJECTS.length;
172
+ if (v.length !== n) return NaN;
173
+ const target = ideal.length === n ? ideal : new Array(n).fill(1);
174
+ return Math.max(...GOVERNANCE_OBJECTS.map(
175
+ (obj, i) => (WEIGHTS[obj] ?? 1) * Math.abs(target[i] - v[i])
176
+ ));
177
+ }
178
+ function legacyKappa(scores, tolerance) {
179
+ if (scores.length < 3) return 0;
180
+ const deltas = scores.slice(1).map((s, i) => Math.abs(s - scores[i]));
181
+ if (deltas[deltas.length - 1] <= tolerance) return 0;
182
+ const ratios = [];
183
+ for (let i = 1; i < deltas.length; i++) {
184
+ if (deltas[i - 1] > tolerance) ratios.push(deltas[i] / deltas[i - 1]);
185
+ }
186
+ return ratios.length > 0 ? ratios.reduce((a, b) => a + b, 0) / ratios.length : 0;
187
+ }
188
+ function isConverging(history, tolerance = 1e-4) {
189
+ for (let i = 0; i < history.length - 1; i++) {
190
+ if (history[i + 1] > history[i] + tolerance) return false;
191
+ }
192
+ return true;
193
+ }
194
+ function computeKappa(input) {
195
+ const tolerance = input.tolerance ?? 1e-6;
196
+ if (input.project_path) {
197
+ try {
198
+ const out = execSync2(
199
+ `python3 -c "
200
+ import json, sys
201
+ sys.path.insert(0, '${input.project_path}/src')
202
+ from pathlib import Path
203
+ from morphism.governance_category import compute_runtime_evidence, compute_governance_vector, compute_vector_kappa
204
+ ev, _ = compute_runtime_evidence(Path('${input.project_path}'))
205
+ vec = compute_governance_vector(ev)
206
+ k = compute_vector_kappa(vec)
207
+ print(json.dumps({'vector': vec, 'kappa': k}))
208
+ "`,
209
+ { cwd: input.project_path, encoding: "utf-8", timeout: 3e4 }
210
+ );
211
+ const parsed = JSON.parse(out.trim());
212
+ const kappa = parsed.kappa;
213
+ const history = input.kappa_history ? [...input.kappa_history, kappa] : [kappa];
214
+ return {
215
+ kappa,
216
+ governance_vector: parsed.vector,
217
+ vector_labels: GOVERNANCE_OBJECTS,
218
+ converging: isConverging(history),
219
+ kappa_history: history,
220
+ method: "vector_linf_formal",
221
+ interpretation: interpretKappa(kappa)
222
+ };
223
+ } catch (_) {
224
+ }
225
+ }
226
+ if (input.governance_vector && input.governance_vector.length === GOVERNANCE_OBJECTS.length) {
227
+ const kappa = vectorKappa(input.governance_vector);
228
+ const history = input.kappa_history ? [...input.kappa_history, kappa] : [kappa];
229
+ return {
230
+ kappa,
231
+ governance_vector: input.governance_vector,
232
+ vector_labels: GOVERNANCE_OBJECTS,
233
+ converging: isConverging(history),
234
+ kappa_history: history,
235
+ method: "vector_linf_formal",
236
+ interpretation: interpretKappa(kappa)
237
+ };
238
+ }
239
+ if (input.scores && input.scores.length >= 2) {
240
+ const kappa = legacyKappa(input.scores, tolerance);
241
+ return {
242
+ kappa,
243
+ converges: kappa < 1,
244
+ method: "legacy_scalar_ratio",
245
+ interpretation: kappa === 0 ? "Converged or insufficient data" : kappa < 1 ? `Converging (\u03BA=${kappa.toFixed(4)}) \u2014 NOTE: scalar heuristic, use governance_vector for formal \u03BA` : `Diverging (\u03BA=${kappa.toFixed(4)})`
246
+ };
247
+ }
248
+ return { error: "Provide governance_vector (preferred), scores, or project_path" };
249
+ }
250
+ function interpretKappa(k) {
251
+ if (k === 0) return "Fixed point: governance is fully compliant";
252
+ if (k < 0.1) return `\u03BA=${k.toFixed(3)}: Excellent \u2014 near fixed point`;
253
+ if (k < 0.3) return `\u03BA=${k.toFixed(3)}: Good \u2014 governance converging`;
254
+ if (k < 0.6) return `\u03BA=${k.toFixed(3)}: WARNING \u2014 significant compliance gaps`;
255
+ return `\u03BA=${k.toFixed(3)}: CRITICAL \u2014 governance far from fixed point`;
256
+ }
257
+
258
+ // src/tools/delta.ts
259
+ import { z as z4 } from "zod";
260
+ var DeltaInput = z4.object({
261
+ baseline: z4.union([z4.number(), z4.array(z4.number())]).describe("Baseline state"),
262
+ current: z4.union([z4.number(), z4.array(z4.number())]).describe("Current state")
263
+ });
264
+ function robustnessDelta(baseline, current) {
265
+ if (typeof baseline === "number" && typeof current === "number") {
266
+ return Math.abs(current - baseline);
267
+ }
268
+ if (Array.isArray(baseline) && Array.isArray(current)) {
269
+ if (baseline.length !== current.length) return Infinity;
270
+ if (baseline.length === 0) return 0;
271
+ const sum = baseline.reduce((acc, b, i) => acc + Math.abs(current[i] - b), 0);
272
+ return sum / baseline.length;
273
+ }
274
+ return 0;
275
+ }
276
+ function computeDelta(input) {
277
+ const delta = robustnessDelta(input.baseline, input.current);
278
+ return {
279
+ delta,
280
+ drifted: delta > 0,
281
+ severity: delta === 0 ? "none" : delta < 5 ? "low" : delta < 15 ? "medium" : "high"
282
+ };
283
+ }
284
+
285
+ // src/tools/ssot.ts
286
+ import { z as z5 } from "zod";
287
+ var SsotInput = z5.object({
288
+ project_path: z5.string().describe("Path to the project root")
289
+ });
290
+ async function ssotVerify(input) {
291
+ const { execSync: execSync3 } = await import("child_process");
292
+ try {
293
+ const result = execSync3(
294
+ `python3 scripts/ssot_verify.py`,
295
+ { cwd: input.project_path, encoding: "utf-8", timeout: 3e4 }
296
+ );
297
+ return { valid: true, output: result };
298
+ } catch (err) {
299
+ const error = err;
300
+ return { valid: false, output: error.stdout || "", error: error.stderr || "" };
301
+ }
302
+ }
303
+
304
+ // src/server.ts
305
+ function createServer() {
306
+ const server2 = new McpServer({
307
+ name: "morphism-governance",
308
+ version: "0.1.0"
309
+ });
310
+ server2.tool(
311
+ "governance_validate",
312
+ "Run the full governance validation pipeline on a project.",
313
+ ValidateInput.shape,
314
+ async (input) => ({
315
+ content: [{ type: "text", text: JSON.stringify(await governanceValidate(input), null, 2) }]
316
+ })
317
+ );
318
+ server2.tool(
319
+ "governance_score",
320
+ "Compute the governance maturity score (0-105) for a project.",
321
+ ScoreInput.shape,
322
+ async (input) => ({
323
+ content: [{ type: "text", text: JSON.stringify(await governanceScore(input), null, 2) }]
324
+ })
325
+ );
326
+ server2.tool(
327
+ "compute_kappa",
328
+ "Compute convergence metric \u03BA from governance scores. \u03BA < 1 means converging.",
329
+ KappaInput.shape,
330
+ async (input) => ({
331
+ content: [{ type: "text", text: JSON.stringify(computeKappa(input), null, 2) }]
332
+ })
333
+ );
334
+ server2.tool(
335
+ "compute_delta",
336
+ "Compute drift metric \u03B4 between baseline and current governance state.",
337
+ DeltaInput.shape,
338
+ async (input) => ({
339
+ content: [{ type: "text", text: JSON.stringify(computeDelta(input), null, 2) }]
340
+ })
341
+ );
342
+ server2.tool(
343
+ "ssot_verify",
344
+ "Verify SSOT integrity \u2014 check for drift between source of truth atoms.",
345
+ SsotInput.shape,
346
+ async (input) => ({
347
+ content: [{ type: "text", text: JSON.stringify(await ssotVerify(input), null, 2) }]
348
+ })
349
+ );
350
+ return server2;
351
+ }
352
+
353
+ // src/index.ts
354
+ var server = createServer();
355
+ var transport = new StdioServerTransport();
356
+ await server.connect(transport);
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@morphism-systems/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "Governance MCP server — validation, maturity scoring, convergence and drift metrics",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "morphism-mcp": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsup src/index.ts --format esm --dts --clean",
12
+ "typecheck": "tsc --noEmit",
13
+ "test": "vitest run",
14
+ "lint": "echo 'no lint configured'"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "model-context-protocol",
19
+ "ai-governance",
20
+ "morphism",
21
+ "governance-as-code"
22
+ ],
23
+ "license": "BUSL-1.1",
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "dependencies": {
28
+ "@modelcontextprotocol/sdk": "^1.12.1",
29
+ "zod": "^3.24.0"
30
+ },
31
+ "devDependencies": {
32
+ "tsup": "^8.4.0",
33
+ "typescript": "^5.8.3",
34
+ "vitest": "^3.0.0"
35
+ }
36
+ }