@martinloop/mcp 0.5.6 → 0.5.7

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 (40) hide show
  1. package/README.md +137 -175
  2. package/dist/arcade/resource.js +20 -20
  3. package/dist/package-version.d.ts +1 -1
  4. package/dist/package-version.js +1 -1
  5. package/dist/resources.js +148 -160
  6. package/dist/server.js +192 -43
  7. package/dist/tools/execution-policy.js +1 -1
  8. package/dist/tools/get-status.d.ts +2 -4
  9. package/dist/tools/get-status.js +6 -3
  10. package/dist/tools/preflight.d.ts +1 -1
  11. package/dist/tools/run-loop.d.ts +1 -1
  12. package/dist/tools/run-loop.js +3 -1
  13. package/dist/tools/run-store.js +1 -1
  14. package/dist/tools/tool-support.d.ts +3 -2
  15. package/dist/tools/tool-support.js +9 -2
  16. package/dist/tools/workflow-governance.d.ts +1 -1
  17. package/dist/tools/workflow-governance.js +1 -1
  18. package/dist/vendor/adapters/openai-compatible.js +6 -6
  19. package/dist/vendor/adapters/verifier-only.js +1 -1
  20. package/dist/vendor/contracts/execution-policy.js +1 -1
  21. package/dist/vendor/contracts/exits.d.ts +1 -1
  22. package/dist/vendor/contracts/governance.d.ts +1 -1
  23. package/dist/vendor/contracts/index.d.ts +1 -1
  24. package/dist/vendor/contracts/index.js +1 -2
  25. package/dist/vendor/contracts/operator.d.ts +1 -1
  26. package/dist/vendor/contracts/operator.js +1 -2
  27. package/dist/vendor/core/compiler.d.ts +2 -2
  28. package/dist/vendor/core/compiler.js +3 -1
  29. package/dist/vendor/core/exits.js +9 -4
  30. package/dist/vendor/core/grounding.d.ts +1 -0
  31. package/dist/vendor/core/grounding.js +28 -1
  32. package/dist/vendor/core/index.d.ts +2 -2
  33. package/dist/vendor/core/index.js +3 -1
  34. package/dist/vendor/core/policy-compiler.js +17 -1
  35. package/dist/vendor/core/policy.d.ts +1 -1
  36. package/dist/vendor/core/policy.js +7 -5
  37. package/dist/vendor/presentation/motion.js +0 -4
  38. package/dist/workflow-state.js +1 -1
  39. package/package.json +90 -81
  40. package/server.json +21 -21
@@ -20,7 +20,7 @@ export interface CompilerAdapterRequest {
20
20
  focus: string;
21
21
  remainingBudgetUsd: number;
22
22
  remainingIterations: number;
23
- remainingTokens: number;
23
+ remainingTokens?: number;
24
24
  };
25
25
  previousAttempts: LoopAttempt[];
26
26
  }
@@ -41,7 +41,7 @@ export interface PromptPacket {
41
41
  budgetEnvelope: {
42
42
  remainingBudgetUsd: number;
43
43
  remainingIterations: number;
44
- remainingTokens: number;
44
+ remainingTokens?: number;
45
45
  };
46
46
  }
47
47
  /**
@@ -41,7 +41,9 @@ export function compilePromptPacket(request) {
41
41
  budgetEnvelope: {
42
42
  remainingBudgetUsd: request.context.remainingBudgetUsd,
43
43
  remainingIterations: request.context.remainingIterations,
44
- remainingTokens: request.context.remainingTokens
44
+ ...(request.context.remainingTokens !== undefined
45
+ ? { remainingTokens: request.context.remainingTokens }
46
+ : {})
45
47
  }
46
48
  };
47
49
  }
@@ -26,7 +26,10 @@ export function createDefaultExitPolicy(budget, overrides = {}) {
26
26
  schemaVersion: "exit-policy/1",
27
27
  goal: { verifierRequired: true, minimumScore: 1 },
28
28
  turns: { max: budget.maxIterations },
29
- budget: { maxUsd: budget.maxUsd, maxTokens: budget.maxTokens },
29
+ budget: {
30
+ maxUsd: budget.maxUsd,
31
+ ...(budget.maxTokens !== undefined ? { maxTokens: budget.maxTokens } : {})
32
+ },
30
33
  wallClock: { maxElapsedMs: 30 * 60 * 1000 },
31
34
  progress: { windowSize: 3, unchangedStateLimit: 3 },
32
35
  errors: { maxConsecutive: 3 },
@@ -49,7 +52,9 @@ export function createDefaultExitPolicy(budget, overrides = {}) {
49
52
  export function validateExitPolicy(policy) {
50
53
  assertFinitePositive("turns.max", policy.turns.max);
51
54
  assertFinitePositive("budget.maxUsd", policy.budget.maxUsd);
52
- assertFinitePositive("budget.maxTokens", policy.budget.maxTokens);
55
+ if (policy.budget.maxTokens !== undefined) {
56
+ assertFinitePositive("budget.maxTokens", policy.budget.maxTokens);
57
+ }
53
58
  assertFinitePositive("wallClock.maxElapsedMs", policy.wallClock.maxElapsedMs);
54
59
  assertFinitePositive("progress.windowSize", policy.progress.windowSize);
55
60
  assertFinitePositive("progress.unchangedStateLimit", policy.progress.unchangedStateLimit);
@@ -117,13 +122,13 @@ export function evaluateExitPolicy(policy, snapshot) {
117
122
  }
118
123
  // 5. Budget cap
119
124
  const usdExceeded = snapshot.actualUsd >= policy.budget.maxUsd;
120
- const tokensExceeded = snapshot.tokensUsed >= policy.budget.maxTokens;
125
+ const tokensExceeded = policy.budget.maxTokens !== undefined && snapshot.tokensUsed >= policy.budget.maxTokens;
121
126
  if (usdExceeded || tokensExceeded) {
122
127
  push("budget_cap", "Run token or dollar budget reached.", {
123
128
  actualUsd: snapshot.actualUsd,
124
129
  maxUsd: policy.budget.maxUsd,
125
130
  tokensUsed: snapshot.tokensUsed,
126
- maxTokens: policy.budget.maxTokens,
131
+ ...(policy.budget.maxTokens !== undefined ? { maxTokens: policy.budget.maxTokens } : {}),
127
132
  usdExceeded,
128
133
  tokensExceeded
129
134
  });
@@ -9,6 +9,7 @@ export interface RepoGroundingIndex {
9
9
  createdAt: string;
10
10
  fileCount: number;
11
11
  files: RepoGroundingFile[];
12
+ trackedPaths?: string[];
12
13
  repositoryFingerprint?: string;
13
14
  }
14
15
  export interface RepoGroundingHit {
@@ -1,7 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { execFile } from "node:child_process";
2
3
  import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
3
4
  import { homedir } from "node:os";
4
5
  import { extname, join, relative } from "node:path";
6
+ import { promisify } from "node:util";
7
+ const execFileAsync = promisify(execFile);
5
8
  const TEXT_EXTENSIONS = new Set([
6
9
  ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs",
7
10
  ".json", ".md", ".yaml", ".yml", ".py", ".go",
@@ -42,21 +45,42 @@ export async function loadOrBuildRepoGroundingIndex(repoRoot) {
42
45
  export async function buildRepoGroundingIndex(repoRoot, repositoryFingerprint) {
43
46
  const files = [];
44
47
  const discovered = await walk(repoRoot, repoRoot, files, { count: 0 });
48
+ const trackedPaths = await loadTrackedPaths(repoRoot);
45
49
  return {
46
50
  schemaVersion: "martin.grounding.v1",
47
51
  repoRoot,
48
52
  createdAt: new Date().toISOString(),
49
53
  fileCount: discovered.count,
50
54
  files,
55
+ ...(trackedPaths.length > 0 ? { trackedPaths } : {}),
51
56
  repositoryFingerprint: repositoryFingerprint ?? await computeRepositoryFingerprint(repoRoot)
52
57
  };
53
58
  }
54
59
  async function computeRepositoryFingerprint(repoRoot) {
55
60
  const entries = [];
56
61
  await collectFingerprintEntries(repoRoot, repoRoot, entries, { count: 0 });
62
+ for (const trackedPath of await loadTrackedPaths(repoRoot)) {
63
+ entries.push(`tracked:${trackedPath}`);
64
+ }
57
65
  entries.sort();
58
66
  return createHash("sha256").update(entries.join("\n")).digest("hex");
59
67
  }
68
+ async function loadTrackedPaths(repoRoot) {
69
+ try {
70
+ const { stdout } = await execFileAsync("git", ["-C", repoRoot, "ls-files", "-z"], {
71
+ encoding: "utf8",
72
+ windowsHide: true
73
+ });
74
+ return stdout
75
+ .split("\0")
76
+ .map((filePath) => filePath.trim().replace(/\\/g, "/"))
77
+ .filter(Boolean)
78
+ .sort();
79
+ }
80
+ catch {
81
+ return [];
82
+ }
83
+ }
60
84
  async function collectFingerprintEntries(repoRoot, currentDir, entries, state) {
61
85
  if (state.count >= MAX_FILES)
62
86
  return;
@@ -193,7 +217,10 @@ function tokenize(input) {
193
217
  export function scanPatchForGroundingViolations(diff, index, options = {}) {
194
218
  const violations = [];
195
219
  const resolvedFiles = [];
196
- const indexedPaths = new Set(index.files.map((file) => file.path));
220
+ const indexedPaths = new Set([
221
+ ...index.files.map((file) => file.path),
222
+ ...(index.trackedPaths ?? [])
223
+ ]);
197
224
  const indexedSymbols = new Set(index.files.flatMap((file) => file.symbols.map((symbol) => symbol.toLowerCase())));
198
225
  const referencedFiles = new Set();
199
226
  const addedFiles = new Set();
@@ -75,7 +75,7 @@ export interface MartinAdapterRequest {
75
75
  focus: string;
76
76
  remainingBudgetUsd: number;
77
77
  remainingIterations: number;
78
- remainingTokens: number;
78
+ remainingTokens?: number;
79
79
  };
80
80
  previousAttempts: LoopAttempt[];
81
81
  /** Abort signal propagated from the harness — adapters should honour it. */
@@ -165,7 +165,7 @@ export interface DistilledContext {
165
165
  constraints: {
166
166
  remainingBudgetUsd: number;
167
167
  remainingIterations: number;
168
- remainingTokens: number;
168
+ remainingTokens?: number;
169
169
  };
170
170
  }
171
171
  export interface AttemptPolicyDecision {
@@ -152,7 +152,9 @@ export function distillContext(loop, options = {}) {
152
152
  constraints: {
153
153
  remainingBudgetUsd: roundUsd(loop.budget.maxUsd - loop.cost.actualUsd),
154
154
  remainingIterations: Math.max(loop.budget.maxIterations - loop.attempts.length, 0),
155
- remainingTokens: Math.max(loop.budget.maxTokens - loop.cost.tokensIn - loop.cost.tokensOut, 0)
155
+ ...(loop.budget.maxTokens !== undefined
156
+ ? { remainingTokens: Math.max(loop.budget.maxTokens - loop.cost.tokensIn - loop.cost.tokensOut, 0) }
157
+ : {})
156
158
  }
157
159
  };
158
160
  }
@@ -5,7 +5,7 @@ export function compileExecutionPolicy(input) {
5
5
  maxUsd: resolveBudgetField("maxUsd", input, provenance),
6
6
  softLimitUsd: resolveBudgetField("softLimitUsd", input, provenance),
7
7
  maxIterations: resolveBudgetField("maxIterations", input, provenance),
8
- maxTokens: resolveBudgetField("maxTokens", input, provenance)
8
+ ...resolveOptionalTokenBudget(input, provenance)
9
9
  };
10
10
  if (budget.softLimitUsd >= budget.maxUsd) {
11
11
  budget.softLimitUsd = Math.round(budget.maxUsd * 0.75 * 100) / 100;
@@ -103,6 +103,22 @@ export function compileExecutionPolicy(input) {
103
103
  provenance
104
104
  });
105
105
  }
106
+ function resolveOptionalTokenBudget(input, provenance) {
107
+ if (input.request.budgetOverrides?.maxTokens && input.request.budget.maxTokens !== undefined) {
108
+ provenance.push({ field: "budget.maxTokens", source: "request", value: String(input.request.budget.maxTokens) });
109
+ return { maxTokens: input.request.budget.maxTokens };
110
+ }
111
+ const configValue = input.config?.budget?.maxTokens;
112
+ if (typeof configValue === "number" && Number.isFinite(configValue)) {
113
+ provenance.push({ field: "budget.maxTokens", source: "config", value: String(configValue) });
114
+ return { maxTokens: configValue };
115
+ }
116
+ if (input.defaults.budget.maxTokens !== undefined) {
117
+ provenance.push({ field: "budget.maxTokens", source: "default", value: String(input.defaults.budget.maxTokens) });
118
+ return { maxTokens: input.defaults.budget.maxTokens };
119
+ }
120
+ return {};
121
+ }
106
122
  function resolveBudgetField(field, input, provenance) {
107
123
  if (input.request.budgetOverrides?.[field]) {
108
124
  const value = input.request.budget[field];
@@ -12,7 +12,7 @@ export interface CostGovernorState {
12
12
  shouldStop: boolean;
13
13
  remainingBudgetUsd: number;
14
14
  remainingIterations: number;
15
- remainingTokens: number;
15
+ remainingTokens?: number;
16
16
  recommendedIntervention?: InterventionType;
17
17
  }
18
18
  export interface ExitDecision {
@@ -165,16 +165,18 @@ export function classifyFailure(input) {
165
165
  export function evaluateCostGovernor(input) {
166
166
  const remainingBudgetUsd = roundUsd(input.budget.maxUsd - input.cost.actualUsd);
167
167
  const remainingIterations = Math.max(input.budget.maxIterations - input.attemptsUsed, 0);
168
- const remainingTokens = Math.max(input.budget.maxTokens - input.cost.tokensIn - input.cost.tokensOut, 0);
168
+ const remainingTokens = input.budget.maxTokens === undefined
169
+ ? undefined
170
+ : Math.max(input.budget.maxTokens - input.cost.tokensIn - input.cost.tokensOut, 0);
169
171
  if (input.cost.actualUsd >= input.budget.maxUsd ||
170
172
  input.attemptsUsed >= input.budget.maxIterations ||
171
- remainingTokens <= 0) {
173
+ (remainingTokens !== undefined && remainingTokens <= 0)) {
172
174
  return {
173
175
  pressure: "hard_limit",
174
176
  shouldStop: true,
175
177
  remainingBudgetUsd,
176
178
  remainingIterations,
177
- remainingTokens,
179
+ ...(remainingTokens !== undefined ? { remainingTokens } : {}),
178
180
  recommendedIntervention: "stop_loop"
179
181
  };
180
182
  }
@@ -184,7 +186,7 @@ export function evaluateCostGovernor(input) {
184
186
  shouldStop: false,
185
187
  remainingBudgetUsd,
186
188
  remainingIterations,
187
- remainingTokens,
189
+ ...(remainingTokens !== undefined ? { remainingTokens } : {}),
188
190
  recommendedIntervention: "compress_context"
189
191
  };
190
192
  }
@@ -193,7 +195,7 @@ export function evaluateCostGovernor(input) {
193
195
  shouldStop: false,
194
196
  remainingBudgetUsd,
195
197
  remainingIterations,
196
- remainingTokens
198
+ ...(remainingTokens !== undefined ? { remainingTokens } : {})
197
199
  };
198
200
  }
199
201
  export function calculateCostPerOutcome(input) {
@@ -10,10 +10,6 @@ export function canAnimate(env = {}) {
10
10
  if (mode !== "human") {
11
11
  return false;
12
12
  }
13
- const noColor = env.noColor ?? Object.prototype.hasOwnProperty.call(process.env, "NO_COLOR");
14
- if (noColor) {
15
- return false;
16
- }
17
13
  const stdoutTty = env.stdoutIsTty ?? process.stdout.isTTY === true;
18
14
  if (!stdoutTty) {
19
15
  return false;
@@ -145,7 +145,7 @@ function hashBudget(budget) {
145
145
  maxUsd: Number(budget.maxUsd.toFixed(4)),
146
146
  softLimitUsd: Number(budget.softLimitUsd.toFixed(4)),
147
147
  maxIterations: budget.maxIterations,
148
- maxTokens: budget.maxTokens
148
+ ...(budget.maxTokens !== undefined ? { maxTokens: budget.maxTokens } : {})
149
149
  };
150
150
  return createHash("sha256").update(JSON.stringify(normalized)).digest("hex").slice(0, 12);
151
151
  }
package/package.json CHANGED
@@ -1,81 +1,90 @@
1
- {
2
- "name": "@martinloop/mcp",
3
- "version": "0.5.6",
4
- "mcpName": "io.github.Keesan12/martin-loop",
5
- "private": false,
6
- "type": "module",
7
- "description": "MCP server for AI coding agents — verifier gates, stop limits, and Verified Handoffs.",
8
- "license": "Apache-2.0",
9
- "author": "MartinLoop contributors",
10
- "homepage": "https://martinloop.com/",
11
- "repository": {
12
- "type": "git",
13
- "url": "git+https://github.com/Keesan12/martin-loop.git",
14
- "directory": "packages/mcp"
15
- },
16
- "bugs": {
17
- "url": "https://github.com/Keesan12/martin-loop/issues"
18
- },
19
- "keywords": [
20
- "mcp",
21
- "model-context-protocol",
22
- "martin-loop",
23
- "ai-agent",
24
- "claude",
25
- "codex",
26
- "martin_doctor",
27
- "martin_triage_runs",
28
- "martin_run_dossier",
29
- "mcp-resources",
30
- "mcp-prompts"
31
- ],
32
- "bin": {
33
- "mcp": "./dist/server.js",
34
- "martin-loop-mcp": "./dist/server.js"
35
- },
36
- "exports": {
37
- "./server.json": "./server.json",
38
- "./package.json": "./package.json"
39
- },
40
- "files": [
41
- "dist",
42
- "README.md",
43
- "server.json"
44
- ],
45
- "engines": {
46
- "node": ">=20.0.0"
47
- },
48
- "publishConfig": {
49
- "access": "public"
50
- },
51
- "scripts": {
52
- "build": "node ./scripts/build-package.mjs",
53
- "prepack": "pnpm build",
54
- "smoke:pack": "node ./scripts/smoke-package.mjs",
55
- "smoke:published": "node ./scripts/smoke-published-package.mjs",
56
- "smoke:published:pack": "node ./scripts/smoke-published-package.mjs --package-spec=pack",
57
- "verify:release": "node --test ../../scripts/tests/publish-mcp-workflow.test.mjs ../../scripts/tests/mcp-publish-reliability.test.mjs ../../scripts/tests/mcp-release-docs.test.mjs",
58
- "test:baseline": "node ./scripts/run-test-lane.mjs baseline",
59
- "test": "vitest run --maxWorkers=1",
60
- "lint": "tsc -p tsconfig.json --noEmit",
61
- "start": "node dist/server.js",
62
- "inspect:live": "node ./scripts/inspect-live.mjs",
63
- "mcpb:build": "node ./mcpb/build-mcpb.mjs",
64
- "mcpb:validate": "mcpb validate ./dist-mcpb/martinloop",
65
- "mcpb:smoke": "node ./mcpb/smoke-mcpb.mjs"
66
- },
67
- "dependencies": {
68
- "@modelcontextprotocol/sdk": "^1.29.0",
69
- "@open-policy-agent/opa-wasm": "^1.10.0",
70
- "@opentelemetry/api-logs": "^0.214.0",
71
- "@opentelemetry/exporter-logs-otlp-http": "^0.214.0",
72
- "@opentelemetry/resources": "^2.6.1",
73
- "@opentelemetry/sdk-logs": "^0.214.0",
74
- "ts-morph": "^21.0.0"
75
- },
76
- "devDependencies": {
77
- "@anthropic-ai/mcpb": "2.1.2",
78
- "@martin/contracts": "workspace:*",
79
- "@martin/presentation": "workspace:*"
80
- }
81
- }
1
+ {
2
+ "name": "@martinloop/mcp",
3
+ "version": "0.5.7",
4
+ "mcpName": "io.github.Keesan12/martin-loop",
5
+ "private": false,
6
+ "type": "module",
7
+ "description": "MCP server for AI coding agents \u00e2\u20ac\u201d verifier gates, stop limits, and Verified Handoffs.",
8
+ "license": "Apache-2.0",
9
+ "author": "MartinLoop contributors",
10
+ "homepage": "https://martinloop.com/",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/Keesan12/martin-loop.git",
14
+ "directory": "packages/mcp"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/Keesan12/martin-loop/issues"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "mcp-server",
22
+ "model-context-protocol",
23
+ "coding-agent",
24
+ "coding-agents",
25
+ "ai-coding-agent",
26
+ "ai-coding-agents",
27
+ "autonomous-coding",
28
+ "claude-code",
29
+ "codex",
30
+ "gemini-cli",
31
+ "cursor",
32
+ "vscode",
33
+ "agent-runtime",
34
+ "agent-verification",
35
+ "developer-tools",
36
+ "software-engineering",
37
+ "martin-loop"
38
+ ],
39
+ "bin": {
40
+ "mcp": "./dist/server.js",
41
+ "martin-loop-mcp": "./dist/server.js"
42
+ },
43
+ "exports": {
44
+ "./server.json": "./server.json",
45
+ "./package.json": "./package.json"
46
+ },
47
+ "files": [
48
+ "dist",
49
+ "README.md",
50
+ "server.json"
51
+ ],
52
+ "engines": {
53
+ "node": ">=20.0.0"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "scripts": {
59
+ "build": "node ./scripts/build-package.mjs",
60
+ "version:sync": "node ./scripts/version-sync.mjs",
61
+ "version:check": "node ./scripts/verify-version-consistency.mjs",
62
+ "prepack": "pnpm build",
63
+ "smoke:pack": "node ./scripts/smoke-package.mjs",
64
+ "smoke:published": "node ./scripts/smoke-published-package.mjs",
65
+ "smoke:published:pack": "node ./scripts/smoke-published-package.mjs --package-spec=pack",
66
+ "verify:release": "node --test ../../scripts/tests/publish-mcp-workflow.test.mjs ../../scripts/tests/mcp-publish-reliability.test.mjs ../../scripts/tests/mcp-release-docs.test.mjs",
67
+ "test:baseline": "node ./scripts/run-test-lane.mjs baseline",
68
+ "test": "vitest run --maxWorkers=1",
69
+ "lint": "tsc -p tsconfig.json --noEmit",
70
+ "start": "node dist/server.js",
71
+ "inspect:live": "node ./scripts/inspect-live.mjs",
72
+ "mcpb:build": "node ./mcpb/build-mcpb.mjs",
73
+ "mcpb:validate": "mcpb validate ./dist-mcpb/martinloop",
74
+ "mcpb:smoke": "node ./mcpb/smoke-mcpb.mjs"
75
+ },
76
+ "dependencies": {
77
+ "@modelcontextprotocol/sdk": "^1.29.0",
78
+ "@open-policy-agent/opa-wasm": "^1.10.0",
79
+ "@opentelemetry/api-logs": "^0.214.0",
80
+ "@opentelemetry/exporter-logs-otlp-http": "^0.214.0",
81
+ "@opentelemetry/resources": "^2.6.1",
82
+ "@opentelemetry/sdk-logs": "^0.214.0",
83
+ "ts-morph": "^21.0.0"
84
+ },
85
+ "devDependencies": {
86
+ "@anthropic-ai/mcpb": "2.1.2",
87
+ "@martin/contracts": "workspace:*",
88
+ "@martin/presentation": "workspace:*"
89
+ }
90
+ }
package/server.json CHANGED
@@ -1,21 +1,21 @@
1
- {
2
- "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
- "name": "io.github.Keesan12/martin-loop",
4
- "title": "Martin Loop",
5
- "description": "MCP server for AI coding agents — verifier gates, stop limits, and Verified Handoffs.",
6
- "repository": {
7
- "url": "https://github.com/Keesan12/martin-loop",
8
- "source": "github"
9
- },
10
- "version": "0.5.6",
11
- "packages": [
12
- {
13
- "registryType": "npm",
14
- "identifier": "@martinloop/mcp",
15
- "version": "0.5.6",
16
- "transport": {
17
- "type": "stdio"
18
- }
19
- }
20
- ]
21
- }
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.Keesan12/martin-loop",
4
+ "title": "Martin Loop",
5
+ "description": "One system around coding agents to run, verify, recover, and hand off software work.",
6
+ "repository": {
7
+ "url": "https://github.com/Keesan12/martin-loop",
8
+ "source": "github"
9
+ },
10
+ "version": "0.5.7",
11
+ "packages": [
12
+ {
13
+ "registryType": "npm",
14
+ "identifier": "@martinloop/mcp",
15
+ "version": "0.5.7",
16
+ "transport": {
17
+ "type": "stdio"
18
+ }
19
+ }
20
+ ]
21
+ }