@martinloop/mcp 0.2.0 → 0.2.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.
- package/README.md +118 -182
- package/dist/discovery-metadata.d.ts +21 -0
- package/dist/discovery-metadata.js +152 -0
- package/dist/discovery-support.d.ts +62 -0
- package/dist/discovery-support.js +224 -0
- package/dist/package-version.d.ts +1 -0
- package/dist/package-version.js +3 -0
- package/dist/prompts.d.ts +13 -3
- package/dist/prompts.js +537 -74
- package/dist/resources.d.ts +35 -5
- package/dist/resources.js +788 -71
- package/dist/server-validation.d.ts +2 -3
- package/dist/server-validation.js +375 -119
- package/dist/server.d.ts +76 -7
- package/dist/server.js +1478 -394
- package/dist/tools/doctor.d.ts +2 -0
- package/dist/tools/doctor.js +18 -6
- package/dist/tools/eval.d.ts +24 -0
- package/dist/tools/eval.js +65 -0
- package/dist/tools/get-attempt.d.ts +13 -6
- package/dist/tools/get-attempt.js +14 -5
- package/dist/tools/get-run.d.ts +19 -12
- package/dist/tools/get-run.js +20 -11
- package/dist/tools/get-status.d.ts +19 -0
- package/dist/tools/get-status.js +30 -2
- package/dist/tools/get-verification-results.d.ts +10 -7
- package/dist/tools/get-verification-results.js +11 -6
- package/dist/tools/inspect-loop.d.ts +9 -0
- package/dist/tools/inspect-loop.js +11 -2
- package/dist/tools/list-runs.d.ts +25 -5
- package/dist/tools/list-runs.js +21 -4
- package/dist/tools/logs.d.ts +25 -0
- package/dist/tools/logs.js +49 -0
- package/dist/tools/plan.d.ts +20 -0
- package/dist/tools/plan.js +10 -0
- package/dist/tools/pr-tools.d.ts +31 -0
- package/dist/tools/pr-tools.js +111 -0
- package/dist/tools/preflight.d.ts +10 -0
- package/dist/tools/preflight.js +18 -4
- package/dist/tools/run-controls.d.ts +36 -0
- package/dist/tools/run-controls.js +88 -0
- package/dist/tools/run-dossier.d.ts +51 -4
- package/dist/tools/run-dossier.js +100 -5
- package/dist/tools/run-loop.d.ts +19 -0
- package/dist/tools/run-loop.js +61 -4
- package/dist/tools/run-store.d.ts +57 -3
- package/dist/tools/run-store.js +404 -53
- package/dist/tools/tool-errors.d.ts +37 -0
- package/dist/tools/tool-errors.js +170 -0
- package/dist/tools/tool-response.d.ts +16 -0
- package/dist/tools/tool-response.js +34 -0
- package/dist/tools/tool-support.d.ts +92 -2
- package/dist/tools/tool-support.js +385 -63
- package/dist/tools/triage-runs.d.ts +33 -0
- package/dist/tools/triage-runs.js +138 -0
- package/dist/tools/workflow-governance.d.ts +133 -0
- package/dist/tools/workflow-governance.js +581 -0
- package/dist/vendor/adapters/claude-cli.js +0 -1
- package/dist/vendor/adapters/cli-bridge.d.ts +5 -0
- package/dist/vendor/adapters/cli-bridge.js +16 -9
- package/dist/vendor/adapters/direct-provider.js +0 -1
- package/dist/vendor/adapters/index.d.ts +2 -1
- package/dist/vendor/adapters/index.js +2 -1
- package/dist/vendor/adapters/openai-compatible.d.ts +47 -0
- package/dist/vendor/adapters/openai-compatible.js +242 -0
- package/dist/vendor/adapters/runtime-support.js +0 -1
- package/dist/vendor/adapters/stub-agent-cli.js +0 -1
- package/dist/vendor/adapters/stub-direct-provider.js +0 -1
- package/dist/vendor/adapters/verifier-only.js +0 -1
- package/dist/vendor/contracts/governance.js +0 -1
- package/dist/vendor/contracts/index.d.ts +2 -0
- package/dist/vendor/contracts/index.js +1 -1
- package/dist/vendor/contracts/operator.d.ts +19 -0
- package/dist/vendor/contracts/operator.js +11 -0
- package/dist/vendor/core/compiler.js +0 -1
- package/dist/vendor/core/context-integrity.js +0 -1
- package/dist/vendor/core/grounding.js +0 -1
- package/dist/vendor/core/index.js +1 -2
- package/dist/vendor/core/leash.js +19 -12
- package/dist/vendor/core/persistence/compiler.js +0 -1
- package/dist/vendor/core/persistence/index.js +0 -1
- package/dist/vendor/core/persistence/ledger.js +0 -1
- package/dist/vendor/core/persistence/runs-reader.js +0 -1
- package/dist/vendor/core/persistence/store.js +0 -1
- package/dist/vendor/core/policy.js +0 -1
- package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
- package/dist/vendor/core/red-blue/red-phase.js +135 -0
- package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
- package/dist/vendor/core/red-blue/risk-tiers.js +32 -0
- package/dist/vendor/core/rollback.js +2 -3
- package/dist/workflow-state.d.ts +25 -0
- package/dist/workflow-state.js +102 -0
- package/package.json +12 -7
- package/server.json +2 -2
- package/dist/tools/cockpit-support.d.ts +0 -69
- package/dist/tools/cockpit-support.js +0 -108
package/dist/server.js
CHANGED
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Martin Loop MCP Server
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* martin_run — execute a full Martin loop on a coding task
|
|
9
|
-
* martin_inspect — summarise a saved loop record file
|
|
10
|
-
* martin_status — return cost and pressure state from a loop record
|
|
5
|
+
* Martin Loop MCP is a governed execution cockpit for AI coding agents.
|
|
6
|
+
* It exposes execution, diagnostics, run inspection, resources, and prompts
|
|
7
|
+
* over the Model Context Protocol (stdio transport).
|
|
11
8
|
*
|
|
12
9
|
* Setup (Claude Code):
|
|
13
10
|
* macOS/Linux: claude mcp add --scope user martin-loop -- npx @martinloop/mcp
|
|
@@ -19,444 +16,1531 @@
|
|
|
19
16
|
* Manual start:
|
|
20
17
|
* node dist/server.js
|
|
21
18
|
*/
|
|
22
|
-
import {
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
import { realpathSync } from "node:fs";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import { resolveRunsRoot } from "./vendor/core/index.js";
|
|
23
23
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
24
24
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25
25
|
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
26
|
+
import { MARTIN_MCP_PACKAGE_VERSION } from "./package-version.js";
|
|
27
|
+
import { getMartinPrompt, listMartinPrompts } from "./prompts.js";
|
|
28
|
+
import { listMartinResources, listMartinResourceTemplates, readMartinResource } from "./resources.js";
|
|
26
29
|
import { martinDoctorTool } from "./tools/doctor.js";
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
30
|
+
import { martinEvalTool } from "./tools/eval.js";
|
|
31
|
+
import { martinGetAttemptTool } from "./tools/get-attempt.js";
|
|
32
|
+
import { martinGetRunTool } from "./tools/get-run.js";
|
|
33
|
+
import { martinGetVerificationResultsTool } from "./tools/get-verification-results.js";
|
|
29
34
|
import { getStatusTool } from "./tools/get-status.js";
|
|
30
|
-
import { getVerificationResultsTool } from "./tools/get-verification-results.js";
|
|
31
35
|
import { inspectLoopTool } from "./tools/inspect-loop.js";
|
|
32
|
-
import {
|
|
36
|
+
import { martinListRunsTool } from "./tools/list-runs.js";
|
|
37
|
+
import { martinLogsTool } from "./tools/logs.js";
|
|
38
|
+
import { martinPlanTool } from "./tools/plan.js";
|
|
33
39
|
import { martinPreflightTool } from "./tools/preflight.js";
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
40
|
+
import { martinCreatePrTool, martinPrSummaryTool, martinReviewPrTool } from "./tools/pr-tools.js";
|
|
41
|
+
import { martinRunDossierTool } from "./tools/run-dossier.js";
|
|
42
|
+
import { createRunControlReceipt } from "./tools/run-controls.js";
|
|
43
|
+
import { martinTriageRunsTool } from "./tools/triage-runs.js";
|
|
36
44
|
import { runLoopTool } from "./tools/run-loop.js";
|
|
37
|
-
import {
|
|
45
|
+
import { createToolErrorResult, createToolSuccessResult } from "./tools/tool-response.js";
|
|
46
|
+
import { MartinToolError, toToolFailure } from "./tools/tool-errors.js";
|
|
38
47
|
import { sanitizeToolErrorMessage, validateToolInput } from "./server-validation.js";
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
48
|
+
import { recordMcpWorkflowStep } from "./workflow-state.js";
|
|
49
|
+
const stringArraySchema = {
|
|
50
|
+
type: "array",
|
|
51
|
+
items: { type: "string" }
|
|
52
|
+
};
|
|
53
|
+
const loopPreviewSchema = {
|
|
54
|
+
type: "object",
|
|
55
|
+
additionalProperties: true,
|
|
56
|
+
properties: {
|
|
57
|
+
loopId: { type: "string" },
|
|
58
|
+
title: { type: "string" },
|
|
59
|
+
objective: { type: "string" },
|
|
60
|
+
status: { type: "string" },
|
|
61
|
+
lifecycleState: { type: "string" },
|
|
62
|
+
createdAt: { type: "string" },
|
|
63
|
+
updatedAt: { type: "string" },
|
|
64
|
+
attempts: { type: "integer" },
|
|
65
|
+
costUsd: { type: "number" },
|
|
66
|
+
avoidedUsd: { type: "number" },
|
|
67
|
+
pressure: { type: "string" },
|
|
68
|
+
shouldStop: { type: "boolean" },
|
|
69
|
+
remainingBudgetUsd: { type: "number" },
|
|
70
|
+
remainingIterations: { type: "integer" },
|
|
71
|
+
remainingTokens: { type: "integer" },
|
|
72
|
+
lastAttempt: {
|
|
73
|
+
type: "object",
|
|
74
|
+
additionalProperties: true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
required: [
|
|
78
|
+
"loopId",
|
|
79
|
+
"title",
|
|
80
|
+
"objective",
|
|
81
|
+
"status",
|
|
82
|
+
"lifecycleState",
|
|
83
|
+
"attempts",
|
|
84
|
+
"costUsd",
|
|
85
|
+
"avoidedUsd",
|
|
86
|
+
"pressure",
|
|
87
|
+
"shouldStop",
|
|
88
|
+
"remainingBudgetUsd",
|
|
89
|
+
"remainingIterations",
|
|
90
|
+
"remainingTokens"
|
|
91
|
+
]
|
|
92
|
+
};
|
|
93
|
+
const budgetSchema = {
|
|
94
|
+
type: "object",
|
|
95
|
+
additionalProperties: false,
|
|
96
|
+
properties: {
|
|
97
|
+
maxUsd: { type: "number" },
|
|
98
|
+
softLimitUsd: { type: "number" },
|
|
99
|
+
maxIterations: { type: "integer" },
|
|
100
|
+
maxTokens: { type: "integer" }
|
|
101
|
+
},
|
|
102
|
+
required: ["maxUsd", "softLimitUsd", "maxIterations", "maxTokens"]
|
|
103
|
+
};
|
|
104
|
+
const costSchema = {
|
|
105
|
+
type: "object",
|
|
106
|
+
additionalProperties: false,
|
|
107
|
+
properties: {
|
|
108
|
+
actualUsd: { type: "number" },
|
|
109
|
+
avoidedUsd: { type: "number" },
|
|
110
|
+
tokensIn: { type: "integer" },
|
|
111
|
+
tokensOut: { type: "integer" }
|
|
112
|
+
},
|
|
113
|
+
required: ["actualUsd", "avoidedUsd", "tokensIn", "tokensOut"]
|
|
114
|
+
};
|
|
115
|
+
const verificationSchema = {
|
|
116
|
+
type: "object",
|
|
117
|
+
additionalProperties: true,
|
|
118
|
+
properties: {
|
|
119
|
+
status: { type: "string", enum: ["passed", "failed", "unavailable"] },
|
|
120
|
+
eventCount: { type: "integer" },
|
|
121
|
+
ledgerEventCount: { type: "integer" },
|
|
122
|
+
latestAttemptIndex: { type: "integer" },
|
|
123
|
+
completedAt: { type: "string" },
|
|
124
|
+
summary: { type: "string" },
|
|
125
|
+
warnings: stringArraySchema
|
|
126
|
+
},
|
|
127
|
+
required: ["status", "eventCount", "ledgerEventCount", "warnings"]
|
|
128
|
+
};
|
|
129
|
+
const artifactSummarySchema = {
|
|
130
|
+
type: "object",
|
|
131
|
+
additionalProperties: true,
|
|
132
|
+
properties: {
|
|
133
|
+
totalCount: { type: "integer" },
|
|
134
|
+
kinds: {
|
|
135
|
+
type: "object",
|
|
136
|
+
additionalProperties: { type: "integer" }
|
|
69
137
|
},
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
inputSchema: {
|
|
138
|
+
highlights: {
|
|
139
|
+
type: "array",
|
|
140
|
+
items: {
|
|
74
141
|
type: "object",
|
|
75
142
|
additionalProperties: false,
|
|
76
143
|
properties: {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
workingDirectory: {
|
|
82
|
-
type: "string",
|
|
83
|
-
description: "Optional repo-root override resolved under the MCP workspace root (or current working directory). Must stay within that safe root."
|
|
84
|
-
},
|
|
85
|
-
engine: {
|
|
86
|
-
type: "string",
|
|
87
|
-
enum: ["claude", "codex"],
|
|
88
|
-
description: "Which agent CLI to use. Defaults to 'claude'."
|
|
89
|
-
},
|
|
90
|
-
model: {
|
|
91
|
-
type: "string",
|
|
92
|
-
description: "Model override passed to the CLI (e.g. 'claude-opus-4-6', 'o3')."
|
|
93
|
-
},
|
|
94
|
-
maxUsd: {
|
|
95
|
-
type: "number",
|
|
96
|
-
exclusiveMinimum: 0,
|
|
97
|
-
description: "Hard budget ceiling in USD. Defaults to 25."
|
|
98
|
-
},
|
|
99
|
-
maxIterations: {
|
|
100
|
-
type: "integer",
|
|
101
|
-
exclusiveMinimum: 0,
|
|
102
|
-
description: "Maximum number of loop attempts. Defaults to 8."
|
|
103
|
-
},
|
|
104
|
-
maxTokens: {
|
|
105
|
-
type: "integer",
|
|
106
|
-
exclusiveMinimum: 0,
|
|
107
|
-
description: "Maximum total tokens across all attempts. Defaults to 80000."
|
|
108
|
-
},
|
|
109
|
-
verificationPlan: {
|
|
110
|
-
type: "array",
|
|
111
|
-
items: { type: "string" },
|
|
112
|
-
description: "Shell commands that must all exit 0 for the task to be considered complete (e.g. ['pnpm test', 'pnpm build'])."
|
|
113
|
-
},
|
|
114
|
-
allowedPaths: {
|
|
115
|
-
type: "array",
|
|
116
|
-
items: { type: "string" },
|
|
117
|
-
description: "Repo-relative path globs Martin may modify, such as ['src/**', 'tests/**']. Absolute paths and '..' traversal are rejected."
|
|
118
|
-
},
|
|
119
|
-
deniedPaths: {
|
|
120
|
-
type: "array",
|
|
121
|
-
items: { type: "string" },
|
|
122
|
-
description: "Repo-relative path globs Martin must never modify, such as ['.env', 'docs/security/**']. Absolute paths and '..' traversal are rejected."
|
|
123
|
-
},
|
|
124
|
-
workspaceId: {
|
|
125
|
-
type: "string",
|
|
126
|
-
description: "Workspace identifier for telemetry. Defaults to 'ws_mcp'."
|
|
127
|
-
},
|
|
128
|
-
projectId: {
|
|
129
|
-
type: "string",
|
|
130
|
-
description: "Project identifier for telemetry. Defaults to 'proj_mcp'."
|
|
131
|
-
}
|
|
144
|
+
artifactId: { type: "string" },
|
|
145
|
+
kind: { type: "string" },
|
|
146
|
+
label: { type: "string" },
|
|
147
|
+
uri: { type: "string" }
|
|
132
148
|
},
|
|
133
|
-
required: ["
|
|
149
|
+
required: ["artifactId", "kind", "label", "uri"]
|
|
134
150
|
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
required: ["totalCount", "kinds", "highlights"]
|
|
154
|
+
};
|
|
155
|
+
const attemptArtifactsSchema = {
|
|
156
|
+
type: "object",
|
|
157
|
+
additionalProperties: false,
|
|
158
|
+
properties: {
|
|
159
|
+
directory: { type: "string" },
|
|
160
|
+
available: { type: "boolean" },
|
|
161
|
+
files: stringArraySchema
|
|
162
|
+
},
|
|
163
|
+
required: ["directory", "available", "files"]
|
|
164
|
+
};
|
|
165
|
+
const attemptSummarySchema = {
|
|
166
|
+
type: "object",
|
|
167
|
+
additionalProperties: true,
|
|
168
|
+
properties: {
|
|
169
|
+
index: { type: "integer" },
|
|
170
|
+
attemptId: { type: "string" },
|
|
171
|
+
adapterId: { type: "string" },
|
|
172
|
+
model: { type: "string" },
|
|
173
|
+
failureClass: { type: "string" },
|
|
174
|
+
intervention: { type: "string" },
|
|
175
|
+
startedAt: { type: "string" },
|
|
176
|
+
completedAt: { type: "string" },
|
|
177
|
+
summary: { type: "string" },
|
|
178
|
+
artifacts: attemptArtifactsSchema,
|
|
179
|
+
artifactFiles: stringArraySchema
|
|
180
|
+
},
|
|
181
|
+
required: ["index"]
|
|
182
|
+
};
|
|
183
|
+
const inspectionPathsSchema = {
|
|
184
|
+
type: "object",
|
|
185
|
+
additionalProperties: true,
|
|
186
|
+
properties: {
|
|
187
|
+
runsRoot: { type: "string" },
|
|
188
|
+
runDirectory: { type: "string" },
|
|
189
|
+
loopRecordPath: { type: "string" },
|
|
190
|
+
ledgerPath: { type: "string" },
|
|
191
|
+
canonicalRunDirectory: { type: "string" },
|
|
192
|
+
canonicalLoopRecordPath: { type: "string" }
|
|
193
|
+
},
|
|
194
|
+
required: ["runsRoot"]
|
|
195
|
+
};
|
|
196
|
+
const eventSummarySchema = {
|
|
197
|
+
type: "object",
|
|
198
|
+
additionalProperties: true,
|
|
199
|
+
properties: {
|
|
200
|
+
type: { type: "string" },
|
|
201
|
+
timestamp: { type: "string" },
|
|
202
|
+
lifecycleState: { type: "string" },
|
|
203
|
+
payload: {
|
|
204
|
+
type: "object",
|
|
205
|
+
additionalProperties: true
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
required: ["type", "payload"]
|
|
209
|
+
};
|
|
210
|
+
const runOutputSchema = {
|
|
211
|
+
type: "object",
|
|
212
|
+
additionalProperties: true,
|
|
213
|
+
properties: {
|
|
214
|
+
status: { type: "string" },
|
|
215
|
+
lifecycleState: { type: "string" },
|
|
216
|
+
reason: { type: "string" },
|
|
217
|
+
attempts: { type: "integer" },
|
|
218
|
+
costUsd: { type: "number" },
|
|
219
|
+
verificationPassed: { type: "boolean" },
|
|
220
|
+
loopId: { type: "string" },
|
|
221
|
+
pressure: { type: "string" },
|
|
222
|
+
shouldStop: { type: "boolean" },
|
|
223
|
+
remainingBudgetUsd: { type: "number" },
|
|
224
|
+
remainingIterations: { type: "integer" },
|
|
225
|
+
remainingTokens: { type: "integer" },
|
|
226
|
+
engine: { type: "string" },
|
|
227
|
+
workingDirectory: { type: "string" },
|
|
228
|
+
budget: budgetSchema,
|
|
229
|
+
inspection: {
|
|
230
|
+
type: "object",
|
|
231
|
+
additionalProperties: true,
|
|
232
|
+
properties: {
|
|
233
|
+
runsRoot: { type: "string" },
|
|
234
|
+
runDirectory: { type: "string" },
|
|
235
|
+
loopRecordPath: { type: "string" },
|
|
236
|
+
ledgerPath: { type: "string" },
|
|
237
|
+
loop: loopPreviewSchema,
|
|
238
|
+
verification: verificationSchema,
|
|
239
|
+
artifacts: artifactSummarySchema
|
|
240
|
+
},
|
|
241
|
+
required: ["runsRoot", "runDirectory", "loopRecordPath", "ledgerPath", "loop", "verification", "artifacts"]
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
required: [
|
|
245
|
+
"status",
|
|
246
|
+
"lifecycleState",
|
|
247
|
+
"reason",
|
|
248
|
+
"attempts",
|
|
249
|
+
"costUsd",
|
|
250
|
+
"verificationPassed",
|
|
251
|
+
"loopId",
|
|
252
|
+
"pressure",
|
|
253
|
+
"shouldStop",
|
|
254
|
+
"remainingBudgetUsd",
|
|
255
|
+
"remainingIterations",
|
|
256
|
+
"remainingTokens",
|
|
257
|
+
"engine",
|
|
258
|
+
"workingDirectory",
|
|
259
|
+
"budget",
|
|
260
|
+
"inspection"
|
|
261
|
+
]
|
|
262
|
+
};
|
|
263
|
+
const inspectOutputSchema = {
|
|
264
|
+
type: "object",
|
|
265
|
+
additionalProperties: true,
|
|
266
|
+
properties: {
|
|
267
|
+
source: { type: "string" },
|
|
268
|
+
loopCount: { type: "integer" },
|
|
269
|
+
portfolio: {
|
|
270
|
+
type: "object",
|
|
271
|
+
additionalProperties: true
|
|
135
272
|
},
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
273
|
+
latestRun: loopPreviewSchema,
|
|
274
|
+
recentRuns: {
|
|
275
|
+
type: "array",
|
|
276
|
+
items: loopPreviewSchema
|
|
277
|
+
},
|
|
278
|
+
statusBreakdown: {
|
|
279
|
+
type: "object",
|
|
280
|
+
additionalProperties: { type: "integer" }
|
|
281
|
+
},
|
|
282
|
+
lifecycleBreakdown: {
|
|
283
|
+
type: "object",
|
|
284
|
+
additionalProperties: { type: "integer" }
|
|
285
|
+
},
|
|
286
|
+
inspection: {
|
|
287
|
+
type: "object",
|
|
288
|
+
additionalProperties: false,
|
|
289
|
+
properties: {
|
|
290
|
+
sourceKind: { type: "string", enum: ["file", "runs_root"] }
|
|
291
|
+
},
|
|
292
|
+
required: ["sourceKind"]
|
|
293
|
+
},
|
|
294
|
+
warnings: stringArraySchema
|
|
295
|
+
},
|
|
296
|
+
required: [
|
|
297
|
+
"source",
|
|
298
|
+
"loopCount",
|
|
299
|
+
"portfolio",
|
|
300
|
+
"recentRuns",
|
|
301
|
+
"statusBreakdown",
|
|
302
|
+
"lifecycleBreakdown",
|
|
303
|
+
"inspection",
|
|
304
|
+
"warnings"
|
|
305
|
+
]
|
|
306
|
+
};
|
|
307
|
+
const statusOutputSchema = {
|
|
308
|
+
type: "object",
|
|
309
|
+
additionalProperties: true,
|
|
310
|
+
properties: {
|
|
311
|
+
source: { type: "string" },
|
|
312
|
+
loopId: { type: "string" },
|
|
313
|
+
status: { type: "string" },
|
|
314
|
+
lifecycleState: { type: "string" },
|
|
315
|
+
attempts: { type: "integer" },
|
|
316
|
+
costUsd: { type: "number" },
|
|
317
|
+
avoidedUsd: { type: "number" },
|
|
318
|
+
pressure: { type: "string" },
|
|
319
|
+
shouldStop: { type: "boolean" },
|
|
320
|
+
remainingBudgetUsd: { type: "number" },
|
|
321
|
+
remainingIterations: { type: "integer" },
|
|
322
|
+
remainingTokens: { type: "integer" },
|
|
323
|
+
budget: budgetSchema,
|
|
324
|
+
inspection: {
|
|
325
|
+
type: "object",
|
|
326
|
+
additionalProperties: false,
|
|
327
|
+
properties: {
|
|
328
|
+
loop: loopPreviewSchema
|
|
329
|
+
},
|
|
330
|
+
required: ["loop"]
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
required: [
|
|
334
|
+
"source",
|
|
335
|
+
"loopId",
|
|
336
|
+
"status",
|
|
337
|
+
"lifecycleState",
|
|
338
|
+
"attempts",
|
|
339
|
+
"costUsd",
|
|
340
|
+
"avoidedUsd",
|
|
341
|
+
"pressure",
|
|
342
|
+
"shouldStop",
|
|
343
|
+
"remainingBudgetUsd",
|
|
344
|
+
"remainingIterations",
|
|
345
|
+
"remainingTokens",
|
|
346
|
+
"budget",
|
|
347
|
+
"inspection"
|
|
348
|
+
]
|
|
349
|
+
};
|
|
350
|
+
const doctorOutputSchema = {
|
|
351
|
+
type: "object",
|
|
352
|
+
additionalProperties: true,
|
|
353
|
+
properties: {
|
|
354
|
+
status: { type: "string", enum: ["ok", "degraded"] },
|
|
355
|
+
summary: { type: "string" },
|
|
356
|
+
server: {
|
|
357
|
+
type: "object",
|
|
358
|
+
additionalProperties: false,
|
|
359
|
+
properties: {
|
|
360
|
+
name: { type: "string" },
|
|
361
|
+
nodeVersion: { type: "string" },
|
|
362
|
+
platform: { type: "string" }
|
|
363
|
+
},
|
|
364
|
+
required: ["name", "nodeVersion", "platform"]
|
|
365
|
+
},
|
|
366
|
+
environment: {
|
|
367
|
+
type: "object",
|
|
368
|
+
additionalProperties: false,
|
|
369
|
+
properties: {
|
|
370
|
+
workspaceRoot: { type: "string" },
|
|
371
|
+
workingDirectory: { type: "string" },
|
|
372
|
+
runsRoot: { type: "string" },
|
|
373
|
+
mode: { type: "string", enum: ["live", "stub"] },
|
|
374
|
+
liveMode: { type: "boolean" }
|
|
375
|
+
},
|
|
376
|
+
required: ["workspaceRoot", "workingDirectory", "runsRoot", "mode", "liveMode"]
|
|
377
|
+
},
|
|
378
|
+
engines: {
|
|
379
|
+
type: "object",
|
|
380
|
+
additionalProperties: true
|
|
381
|
+
},
|
|
382
|
+
requestedEngine: { type: "string" },
|
|
383
|
+
runStore: {
|
|
384
|
+
type: "object",
|
|
385
|
+
additionalProperties: true,
|
|
386
|
+
properties: {
|
|
387
|
+
exists: { type: "boolean" },
|
|
388
|
+
loopCount: { type: "integer" },
|
|
389
|
+
latestRun: loopPreviewSchema
|
|
390
|
+
},
|
|
391
|
+
required: ["exists", "loopCount"]
|
|
392
|
+
},
|
|
393
|
+
warnings: stringArraySchema
|
|
394
|
+
},
|
|
395
|
+
required: ["status", "summary", "server", "environment", "engines", "runStore", "warnings"]
|
|
396
|
+
};
|
|
397
|
+
const preflightOutputSchema = {
|
|
398
|
+
type: "object",
|
|
399
|
+
additionalProperties: true,
|
|
400
|
+
properties: {
|
|
401
|
+
ok: { type: "boolean" },
|
|
402
|
+
summary: { type: "string" },
|
|
403
|
+
warnings: stringArraySchema,
|
|
404
|
+
readiness: {
|
|
405
|
+
type: "object",
|
|
406
|
+
additionalProperties: false,
|
|
407
|
+
properties: {
|
|
408
|
+
mode: { type: "string", enum: ["live", "stub"] },
|
|
409
|
+
liveMode: { type: "boolean" },
|
|
410
|
+
engineReady: { type: "boolean" }
|
|
411
|
+
},
|
|
412
|
+
required: ["mode", "liveMode", "engineReady"]
|
|
413
|
+
},
|
|
414
|
+
normalized: {
|
|
415
|
+
type: "object",
|
|
416
|
+
additionalProperties: true,
|
|
417
|
+
properties: {
|
|
418
|
+
objective: { type: "string" },
|
|
419
|
+
workingDirectory: { type: "string" },
|
|
420
|
+
engine: { type: "string" },
|
|
421
|
+
model: { type: "string" },
|
|
422
|
+
budget: budgetSchema,
|
|
423
|
+
verificationPlan: stringArraySchema,
|
|
424
|
+
allowedPaths: stringArraySchema,
|
|
425
|
+
deniedPaths: stringArraySchema,
|
|
426
|
+
workspaceId: { type: "string" },
|
|
427
|
+
projectId: { type: "string" }
|
|
428
|
+
},
|
|
429
|
+
required: [
|
|
430
|
+
"objective",
|
|
431
|
+
"workingDirectory",
|
|
432
|
+
"engine",
|
|
433
|
+
"budget",
|
|
434
|
+
"verificationPlan",
|
|
435
|
+
"workspaceId",
|
|
436
|
+
"projectId"
|
|
437
|
+
]
|
|
438
|
+
},
|
|
439
|
+
execution: {
|
|
440
|
+
type: "object",
|
|
441
|
+
additionalProperties: false,
|
|
442
|
+
properties: {
|
|
443
|
+
requestedEngine: { type: "string" },
|
|
444
|
+
engineAvailability: {
|
|
445
|
+
type: "object",
|
|
446
|
+
additionalProperties: true,
|
|
447
|
+
properties: {
|
|
448
|
+
available: { type: "boolean" },
|
|
449
|
+
detail: { type: "string" },
|
|
450
|
+
resolvedPath: { type: "string" }
|
|
150
451
|
},
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
452
|
+
required: ["available", "detail"]
|
|
453
|
+
},
|
|
454
|
+
runsRoot: { type: "string" },
|
|
455
|
+
pathScope: {
|
|
456
|
+
type: "object",
|
|
457
|
+
additionalProperties: false,
|
|
458
|
+
properties: {
|
|
459
|
+
repoRoot: { type: "string" },
|
|
460
|
+
allowedPathsCount: { type: "integer" },
|
|
461
|
+
deniedPathsCount: { type: "integer" },
|
|
462
|
+
hasScopeConflicts: { type: "boolean" }
|
|
155
463
|
},
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
464
|
+
required: ["repoRoot", "allowedPathsCount", "deniedPathsCount", "hasScopeConflicts"]
|
|
465
|
+
},
|
|
466
|
+
expectedRunLayout: {
|
|
467
|
+
type: "object",
|
|
468
|
+
additionalProperties: false,
|
|
469
|
+
properties: {
|
|
470
|
+
runDirectoryPattern: { type: "string" },
|
|
471
|
+
loopRecordPathPattern: { type: "string" }
|
|
159
472
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
473
|
+
required: ["runDirectoryPattern", "loopRecordPathPattern"]
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
required: ["requestedEngine", "engineAvailability", "runsRoot", "pathScope", "expectedRunLayout"]
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
required: ["ok", "summary", "warnings", "readiness", "normalized", "execution"]
|
|
480
|
+
};
|
|
481
|
+
const listRunsOutputSchema = {
|
|
482
|
+
type: "object",
|
|
483
|
+
additionalProperties: true,
|
|
484
|
+
properties: {
|
|
485
|
+
source: { type: "string" },
|
|
486
|
+
runsRoot: { type: "string" },
|
|
487
|
+
filters: {
|
|
488
|
+
type: "object",
|
|
489
|
+
additionalProperties: true
|
|
490
|
+
},
|
|
491
|
+
loopCount: { type: "integer" },
|
|
492
|
+
latestRun: loopPreviewSchema,
|
|
493
|
+
recentRuns: {
|
|
494
|
+
type: "array",
|
|
495
|
+
items: loopPreviewSchema
|
|
496
|
+
},
|
|
497
|
+
statusBreakdown: {
|
|
498
|
+
type: "object",
|
|
499
|
+
additionalProperties: { type: "integer" }
|
|
500
|
+
},
|
|
501
|
+
lifecycleBreakdown: {
|
|
502
|
+
type: "object",
|
|
503
|
+
additionalProperties: { type: "integer" }
|
|
504
|
+
},
|
|
505
|
+
warnings: stringArraySchema
|
|
506
|
+
},
|
|
507
|
+
required: [
|
|
508
|
+
"source",
|
|
509
|
+
"runsRoot",
|
|
510
|
+
"filters",
|
|
511
|
+
"loopCount",
|
|
512
|
+
"recentRuns",
|
|
513
|
+
"statusBreakdown",
|
|
514
|
+
"lifecycleBreakdown",
|
|
515
|
+
"warnings"
|
|
516
|
+
]
|
|
517
|
+
};
|
|
518
|
+
const triageFindingSchema = {
|
|
519
|
+
type: "object",
|
|
520
|
+
additionalProperties: true,
|
|
521
|
+
properties: {
|
|
522
|
+
severity: { type: "string", enum: ["critical", "high", "medium", "low"] },
|
|
523
|
+
summary: { type: "string" },
|
|
524
|
+
reasonCodes: stringArraySchema,
|
|
525
|
+
loop: loopPreviewSchema,
|
|
526
|
+
verification: verificationSchema,
|
|
527
|
+
suggestedResources: stringArraySchema,
|
|
528
|
+
suggestedPrompts: stringArraySchema
|
|
529
|
+
},
|
|
530
|
+
required: [
|
|
531
|
+
"severity",
|
|
532
|
+
"summary",
|
|
533
|
+
"reasonCodes",
|
|
534
|
+
"loop",
|
|
535
|
+
"verification",
|
|
536
|
+
"suggestedResources",
|
|
537
|
+
"suggestedPrompts"
|
|
538
|
+
]
|
|
539
|
+
};
|
|
540
|
+
const triageRunsOutputSchema = {
|
|
541
|
+
type: "object",
|
|
542
|
+
additionalProperties: true,
|
|
543
|
+
properties: {
|
|
544
|
+
source: { type: "string" },
|
|
545
|
+
runsRoot: { type: "string" },
|
|
546
|
+
filters: {
|
|
547
|
+
type: "object",
|
|
548
|
+
additionalProperties: true
|
|
549
|
+
},
|
|
550
|
+
evaluatedRuns: { type: "integer" },
|
|
551
|
+
findingCount: { type: "integer" },
|
|
552
|
+
severityBreakdown: {
|
|
553
|
+
type: "object",
|
|
554
|
+
additionalProperties: { type: "integer" }
|
|
555
|
+
},
|
|
556
|
+
findings: {
|
|
557
|
+
type: "array",
|
|
558
|
+
items: triageFindingSchema
|
|
559
|
+
},
|
|
560
|
+
warnings: stringArraySchema
|
|
561
|
+
},
|
|
562
|
+
required: [
|
|
563
|
+
"source",
|
|
564
|
+
"runsRoot",
|
|
565
|
+
"filters",
|
|
566
|
+
"evaluatedRuns",
|
|
567
|
+
"findingCount",
|
|
568
|
+
"severityBreakdown",
|
|
569
|
+
"findings",
|
|
570
|
+
"warnings"
|
|
571
|
+
]
|
|
572
|
+
};
|
|
573
|
+
const getRunOutputSchema = {
|
|
574
|
+
type: "object",
|
|
575
|
+
additionalProperties: true,
|
|
576
|
+
properties: {
|
|
577
|
+
source: { type: "string" },
|
|
578
|
+
sourceKind: { type: "string", enum: ["file", "loop_id", "latest", "runs_root"] },
|
|
579
|
+
loop: loopPreviewSchema,
|
|
580
|
+
budget: budgetSchema,
|
|
581
|
+
cost: costSchema,
|
|
582
|
+
verification: verificationSchema,
|
|
583
|
+
artifacts: artifactSummarySchema,
|
|
584
|
+
inspection: inspectionPathsSchema,
|
|
585
|
+
warnings: stringArraySchema
|
|
586
|
+
},
|
|
587
|
+
required: ["source", "sourceKind", "loop", "budget", "cost", "verification", "artifacts", "inspection", "warnings"]
|
|
588
|
+
};
|
|
589
|
+
const getAttemptOutputSchema = {
|
|
590
|
+
type: "object",
|
|
591
|
+
additionalProperties: true,
|
|
592
|
+
properties: {
|
|
593
|
+
source: { type: "string" },
|
|
594
|
+
sourceKind: { type: "string", enum: ["file", "loop_id", "latest", "runs_root"] },
|
|
595
|
+
loop: loopPreviewSchema,
|
|
596
|
+
attempt: attemptSummarySchema,
|
|
597
|
+
warnings: stringArraySchema
|
|
598
|
+
},
|
|
599
|
+
required: ["source", "sourceKind", "loop", "attempt", "warnings"]
|
|
600
|
+
};
|
|
601
|
+
const verificationResultsOutputSchema = {
|
|
602
|
+
type: "object",
|
|
603
|
+
additionalProperties: true,
|
|
604
|
+
properties: {
|
|
605
|
+
source: { type: "string" },
|
|
606
|
+
sourceKind: { type: "string", enum: ["file", "loop_id", "latest", "runs_root"] },
|
|
607
|
+
loop: loopPreviewSchema,
|
|
608
|
+
verification: verificationSchema,
|
|
609
|
+
warnings: stringArraySchema
|
|
610
|
+
},
|
|
611
|
+
required: ["source", "sourceKind", "loop", "verification", "warnings"]
|
|
612
|
+
};
|
|
613
|
+
const dossierOutputSchema = {
|
|
614
|
+
type: "object",
|
|
615
|
+
additionalProperties: true,
|
|
616
|
+
properties: {
|
|
617
|
+
source: { type: "string" },
|
|
618
|
+
sourceKind: { type: "string", enum: ["file", "loop_id", "latest", "runs_root"] },
|
|
619
|
+
loop: loopPreviewSchema,
|
|
620
|
+
budget: budgetSchema,
|
|
621
|
+
cost: costSchema,
|
|
622
|
+
attempts: {
|
|
623
|
+
type: "array",
|
|
624
|
+
items: attemptSummarySchema
|
|
625
|
+
},
|
|
626
|
+
verification: verificationSchema,
|
|
627
|
+
artifacts: artifactSummarySchema,
|
|
628
|
+
recentEvents: {
|
|
629
|
+
type: "array",
|
|
630
|
+
items: eventSummarySchema
|
|
631
|
+
},
|
|
632
|
+
related: {
|
|
633
|
+
type: "object",
|
|
634
|
+
additionalProperties: false,
|
|
635
|
+
properties: {
|
|
636
|
+
resources: stringArraySchema,
|
|
637
|
+
prompts: stringArraySchema
|
|
638
|
+
},
|
|
639
|
+
required: ["resources", "prompts"]
|
|
640
|
+
},
|
|
641
|
+
inspection: inspectionPathsSchema,
|
|
642
|
+
warnings: stringArraySchema
|
|
643
|
+
},
|
|
644
|
+
required: [
|
|
645
|
+
"source",
|
|
646
|
+
"sourceKind",
|
|
647
|
+
"loop",
|
|
648
|
+
"budget",
|
|
649
|
+
"cost",
|
|
650
|
+
"attempts",
|
|
651
|
+
"verification",
|
|
652
|
+
"artifacts",
|
|
653
|
+
"recentEvents",
|
|
654
|
+
"related",
|
|
655
|
+
"inspection",
|
|
656
|
+
"warnings"
|
|
657
|
+
]
|
|
658
|
+
};
|
|
659
|
+
const planOutputSchema = {
|
|
660
|
+
type: "object",
|
|
661
|
+
additionalProperties: true
|
|
662
|
+
};
|
|
663
|
+
const logsOutputSchema = {
|
|
664
|
+
type: "object",
|
|
665
|
+
additionalProperties: true
|
|
666
|
+
};
|
|
667
|
+
const controlOutputSchema = {
|
|
668
|
+
type: "object",
|
|
669
|
+
additionalProperties: true
|
|
670
|
+
};
|
|
671
|
+
const evalOutputSchema = {
|
|
672
|
+
type: "object",
|
|
673
|
+
additionalProperties: true
|
|
674
|
+
};
|
|
675
|
+
const prSummaryOutputSchema = {
|
|
676
|
+
type: "object",
|
|
677
|
+
additionalProperties: true
|
|
678
|
+
};
|
|
679
|
+
const prReviewOutputSchema = {
|
|
680
|
+
type: "object",
|
|
681
|
+
additionalProperties: true
|
|
682
|
+
};
|
|
683
|
+
export function createMartinMcpServer(serverInfo) {
|
|
684
|
+
const server = new Server({
|
|
685
|
+
name: serverInfo?.name ?? "martin-loop",
|
|
686
|
+
version: serverInfo?.version ?? MARTIN_MCP_PACKAGE_VERSION
|
|
687
|
+
}, { capabilities: { tools: {}, resources: {}, prompts: {} } });
|
|
688
|
+
server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
689
|
+
tools: [
|
|
690
|
+
{
|
|
691
|
+
name: "martin_run",
|
|
692
|
+
description: "Execute a governed Martin Loop run on a coding task and return the run summary, spend, artifact rollup, and verification state. This hard-blocks until martin_doctor, martin_plan, and martin_preflight receipts exist for the same task.",
|
|
693
|
+
annotations: {
|
|
694
|
+
destructiveHint: true,
|
|
695
|
+
idempotentHint: false,
|
|
696
|
+
openWorldHint: false
|
|
697
|
+
},
|
|
698
|
+
inputSchema: {
|
|
699
|
+
type: "object",
|
|
700
|
+
additionalProperties: false,
|
|
701
|
+
properties: {
|
|
702
|
+
objective: {
|
|
703
|
+
type: "string",
|
|
704
|
+
description: "The coding task to complete. Be specific about what needs to change."
|
|
705
|
+
},
|
|
706
|
+
workingDirectory: {
|
|
707
|
+
type: "string",
|
|
708
|
+
description: "Optional repo-root override resolved under the MCP workspace root. Must stay within that safe root."
|
|
709
|
+
},
|
|
710
|
+
engine: {
|
|
711
|
+
type: "string",
|
|
712
|
+
enum: ["claude", "codex"],
|
|
713
|
+
description: "Which agent CLI to use. Defaults to claude."
|
|
714
|
+
},
|
|
715
|
+
model: {
|
|
716
|
+
type: "string",
|
|
717
|
+
description: "Optional model override passed to the CLI."
|
|
718
|
+
},
|
|
719
|
+
maxUsd: {
|
|
720
|
+
type: "number",
|
|
721
|
+
exclusiveMinimum: 0,
|
|
722
|
+
description: "Hard budget ceiling in USD."
|
|
723
|
+
},
|
|
724
|
+
maxIterations: {
|
|
725
|
+
type: "integer",
|
|
726
|
+
exclusiveMinimum: 0,
|
|
727
|
+
description: "Maximum number of loop attempts."
|
|
728
|
+
},
|
|
729
|
+
maxTokens: {
|
|
730
|
+
type: "integer",
|
|
731
|
+
exclusiveMinimum: 0,
|
|
732
|
+
description: "Maximum total tokens across all attempts."
|
|
733
|
+
},
|
|
734
|
+
verificationPlan: {
|
|
735
|
+
type: "array",
|
|
736
|
+
items: { type: "string" },
|
|
737
|
+
description: "Commands that must all exit 0 for the task to be considered complete."
|
|
738
|
+
},
|
|
739
|
+
allowedPaths: {
|
|
740
|
+
type: "array",
|
|
741
|
+
items: { type: "string" },
|
|
742
|
+
description: "Repo-relative path globs Martin may modify."
|
|
743
|
+
},
|
|
744
|
+
deniedPaths: {
|
|
745
|
+
type: "array",
|
|
746
|
+
items: { type: "string" },
|
|
747
|
+
description: "Repo-relative path globs Martin must never modify."
|
|
748
|
+
},
|
|
749
|
+
workspaceId: {
|
|
750
|
+
type: "string",
|
|
751
|
+
description: "Workspace identifier for telemetry."
|
|
752
|
+
},
|
|
753
|
+
projectId: {
|
|
754
|
+
type: "string",
|
|
755
|
+
description: "Project identifier for telemetry."
|
|
756
|
+
}
|
|
164
757
|
},
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
758
|
+
required: ["objective"]
|
|
759
|
+
},
|
|
760
|
+
outputSchema: runOutputSchema
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
name: "martin_inspect",
|
|
764
|
+
description: "Summarise Martin Loop run records from a saved loop file or run-store directory.",
|
|
765
|
+
annotations: {
|
|
766
|
+
readOnlyHint: true,
|
|
767
|
+
idempotentHint: true
|
|
768
|
+
},
|
|
769
|
+
inputSchema: {
|
|
770
|
+
type: "object",
|
|
771
|
+
additionalProperties: false,
|
|
772
|
+
properties: {
|
|
773
|
+
file: {
|
|
774
|
+
type: "string",
|
|
775
|
+
description: "Optional path under the Martin runs root to a loop-record.json file, a legacy .jsonl file, or a run-store directory."
|
|
776
|
+
},
|
|
777
|
+
runsDir: {
|
|
778
|
+
type: "string",
|
|
779
|
+
description: "Optional runs-root override resolved under the default Martin runs root."
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
},
|
|
783
|
+
outputSchema: inspectOutputSchema
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
name: "martin_status",
|
|
787
|
+
description: "Return the current budget and cost state of a Martin loop record.",
|
|
788
|
+
annotations: {
|
|
789
|
+
readOnlyHint: true,
|
|
790
|
+
idempotentHint: true
|
|
791
|
+
},
|
|
792
|
+
inputSchema: {
|
|
793
|
+
type: "object",
|
|
794
|
+
additionalProperties: false,
|
|
795
|
+
properties: {
|
|
796
|
+
loopJson: { type: "string", description: "JSON-serialized LoopRecord." },
|
|
797
|
+
file: {
|
|
798
|
+
type: "string",
|
|
799
|
+
description: "Optional path under the Martin runs root to a loop-record.json file, a legacy .jsonl file, or a run-store directory."
|
|
800
|
+
},
|
|
801
|
+
loopId: {
|
|
802
|
+
type: "string",
|
|
803
|
+
description: "Loop ID resolved as <runsDir>/<loopId>/loop-record.json."
|
|
804
|
+
},
|
|
805
|
+
runsDir: {
|
|
806
|
+
type: "string",
|
|
807
|
+
description: "Optional runs-root override resolved under the default Martin runs root."
|
|
808
|
+
},
|
|
809
|
+
latest: {
|
|
810
|
+
const: true,
|
|
811
|
+
description: "When true, loads the most recently updated loop record in the runs directory."
|
|
812
|
+
}
|
|
169
813
|
},
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
814
|
+
oneOf: [
|
|
815
|
+
{ required: ["loopJson"] },
|
|
816
|
+
{ required: ["file"] },
|
|
817
|
+
{ required: ["loopId"] },
|
|
818
|
+
{ required: ["latest"] }
|
|
819
|
+
]
|
|
820
|
+
},
|
|
821
|
+
outputSchema: statusOutputSchema
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
name: "martin_doctor",
|
|
825
|
+
description: "Read-only environment and run-store diagnostics for the Martin MCP server. This is the expected first call before governed work begins.",
|
|
826
|
+
annotations: {
|
|
827
|
+
readOnlyHint: true,
|
|
828
|
+
idempotentHint: true
|
|
829
|
+
},
|
|
830
|
+
inputSchema: {
|
|
831
|
+
type: "object",
|
|
832
|
+
additionalProperties: false,
|
|
833
|
+
properties: {
|
|
834
|
+
workingDirectory: {
|
|
835
|
+
type: "string",
|
|
836
|
+
description: "Optional repo-root override for doctor context."
|
|
837
|
+
},
|
|
838
|
+
runsDir: {
|
|
839
|
+
type: "string",
|
|
840
|
+
description: "Optional runs-root override resolved under the default Martin runs root."
|
|
841
|
+
},
|
|
842
|
+
engine: {
|
|
843
|
+
type: "string",
|
|
844
|
+
enum: ["claude", "codex"],
|
|
845
|
+
description: "Optional engine to highlight in diagnostics."
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
},
|
|
849
|
+
outputSchema: doctorOutputSchema
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
name: "martin_plan",
|
|
853
|
+
description: "Read-only planning step that turns an objective into a scoped implementation plan, verifier proposal, policy pack, and risk recommendation. Use before preflight and before any real coding run.",
|
|
854
|
+
annotations: {
|
|
855
|
+
readOnlyHint: true,
|
|
856
|
+
idempotentHint: true
|
|
857
|
+
},
|
|
858
|
+
inputSchema: {
|
|
859
|
+
type: "object",
|
|
860
|
+
additionalProperties: false,
|
|
861
|
+
properties: {
|
|
862
|
+
objective: { type: "string", description: "The coding objective to plan." },
|
|
863
|
+
workingDirectory: {
|
|
864
|
+
type: "string",
|
|
865
|
+
description: "Optional repo-root override resolved under the MCP workspace root."
|
|
866
|
+
},
|
|
867
|
+
context: { type: "string", description: "Optional extra issue or bug context." },
|
|
868
|
+
policyPack: {
|
|
869
|
+
type: "string",
|
|
870
|
+
enum: ["solo-founder", "startup-team", "enterprise-strict", "oss-maintainer", "security-sensitive"]
|
|
871
|
+
},
|
|
872
|
+
verificationPlan: { type: "array", items: { type: "string" } },
|
|
873
|
+
allowedPaths: { type: "array", items: { type: "string" } },
|
|
874
|
+
deniedPaths: { type: "array", items: { type: "string" } },
|
|
875
|
+
maxUsd: { type: "number", exclusiveMinimum: 0 },
|
|
876
|
+
maxIterations: { type: "integer", exclusiveMinimum: 0 },
|
|
877
|
+
maxTokens: { type: "integer", exclusiveMinimum: 0 },
|
|
878
|
+
maxMinutes: { type: "integer", exclusiveMinimum: 0 },
|
|
879
|
+
maxFilesChanged: { type: "integer", exclusiveMinimum: 0 },
|
|
880
|
+
maxCommands: { type: "integer", exclusiveMinimum: 0 }
|
|
174
881
|
},
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
882
|
+
required: ["objective"]
|
|
883
|
+
},
|
|
884
|
+
outputSchema: planOutputSchema
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
name: "martin_preflight",
|
|
888
|
+
description: "Read-only validation of a planned Martin run before any execution or spend. This is the last required step before martin_run.",
|
|
889
|
+
annotations: {
|
|
890
|
+
readOnlyHint: true,
|
|
891
|
+
idempotentHint: true
|
|
892
|
+
},
|
|
893
|
+
inputSchema: {
|
|
894
|
+
type: "object",
|
|
895
|
+
additionalProperties: false,
|
|
896
|
+
properties: {
|
|
897
|
+
objective: {
|
|
898
|
+
type: "string",
|
|
899
|
+
description: "The coding task to validate."
|
|
900
|
+
},
|
|
901
|
+
workingDirectory: {
|
|
902
|
+
type: "string",
|
|
903
|
+
description: "Optional repo-root override resolved under the MCP workspace root."
|
|
904
|
+
},
|
|
905
|
+
engine: {
|
|
906
|
+
type: "string",
|
|
907
|
+
enum: ["claude", "codex"],
|
|
908
|
+
description: "Which agent CLI would be used. Defaults to claude."
|
|
909
|
+
},
|
|
910
|
+
model: {
|
|
911
|
+
type: "string",
|
|
912
|
+
description: "Model override passed to the CLI."
|
|
913
|
+
},
|
|
914
|
+
context: {
|
|
915
|
+
type: "string",
|
|
916
|
+
description: "Optional issue context carried into the run contract."
|
|
917
|
+
},
|
|
918
|
+
policyPack: {
|
|
919
|
+
type: "string",
|
|
920
|
+
enum: ["solo-founder", "startup-team", "enterprise-strict", "oss-maintainer", "security-sensitive"]
|
|
921
|
+
},
|
|
922
|
+
maxUsd: {
|
|
923
|
+
type: "number",
|
|
924
|
+
exclusiveMinimum: 0,
|
|
925
|
+
description: "Hard budget ceiling in USD."
|
|
926
|
+
},
|
|
927
|
+
maxIterations: {
|
|
928
|
+
type: "integer",
|
|
929
|
+
exclusiveMinimum: 0,
|
|
930
|
+
description: "Maximum number of loop attempts."
|
|
931
|
+
},
|
|
932
|
+
maxTokens: {
|
|
933
|
+
type: "integer",
|
|
934
|
+
exclusiveMinimum: 0,
|
|
935
|
+
description: "Maximum total tokens across all attempts."
|
|
936
|
+
},
|
|
937
|
+
maxMinutes: {
|
|
938
|
+
type: "integer",
|
|
939
|
+
exclusiveMinimum: 0,
|
|
940
|
+
description: "Estimated wall-clock minutes allowed for the run contract."
|
|
941
|
+
},
|
|
942
|
+
maxFilesChanged: {
|
|
943
|
+
type: "integer",
|
|
944
|
+
exclusiveMinimum: 0,
|
|
945
|
+
description: "Estimated maximum files changed for the run contract."
|
|
946
|
+
},
|
|
947
|
+
maxCommands: {
|
|
948
|
+
type: "integer",
|
|
949
|
+
exclusiveMinimum: 0,
|
|
950
|
+
description: "Estimated maximum commands allowed for the run contract."
|
|
951
|
+
},
|
|
952
|
+
verificationPlan: {
|
|
953
|
+
type: "array",
|
|
954
|
+
items: { type: "string" },
|
|
955
|
+
description: "Commands that must all exit 0 for completion."
|
|
956
|
+
},
|
|
957
|
+
allowedPaths: {
|
|
958
|
+
type: "array",
|
|
959
|
+
items: { type: "string" },
|
|
960
|
+
description: "Repo-relative path globs Martin may modify."
|
|
961
|
+
},
|
|
962
|
+
deniedPaths: {
|
|
963
|
+
type: "array",
|
|
964
|
+
items: { type: "string" },
|
|
965
|
+
description: "Repo-relative path globs Martin must never modify."
|
|
966
|
+
},
|
|
967
|
+
workspaceId: { type: "string" },
|
|
968
|
+
projectId: { type: "string" }
|
|
179
969
|
},
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
970
|
+
required: ["objective"]
|
|
971
|
+
},
|
|
972
|
+
outputSchema: preflightOutputSchema
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
name: "martin_logs",
|
|
976
|
+
description: "Read recent Martin loop events, ledger entries, and operator control receipts for live observability.",
|
|
977
|
+
annotations: {
|
|
978
|
+
readOnlyHint: true,
|
|
979
|
+
idempotentHint: true
|
|
980
|
+
},
|
|
981
|
+
inputSchema: {
|
|
982
|
+
type: "object",
|
|
983
|
+
additionalProperties: false,
|
|
984
|
+
properties: {
|
|
985
|
+
file: { type: "string" },
|
|
986
|
+
loopId: { type: "string" },
|
|
987
|
+
runsDir: { type: "string" },
|
|
988
|
+
latest: { const: true },
|
|
989
|
+
limit: { type: "integer", minimum: 1 }
|
|
184
990
|
},
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
991
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
992
|
+
},
|
|
993
|
+
outputSchema: logsOutputSchema
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
name: "martin_pause",
|
|
997
|
+
description: "Record a durable pause request for a Martin run so humans and runtimes can see that execution should pause before risky follow-up work.",
|
|
998
|
+
annotations: {
|
|
999
|
+
destructiveHint: true,
|
|
1000
|
+
idempotentHint: false
|
|
1001
|
+
},
|
|
1002
|
+
inputSchema: {
|
|
1003
|
+
type: "object",
|
|
1004
|
+
additionalProperties: false,
|
|
1005
|
+
properties: {
|
|
1006
|
+
file: { type: "string" },
|
|
1007
|
+
loopId: { type: "string" },
|
|
1008
|
+
runsDir: { type: "string" },
|
|
1009
|
+
latest: { const: true },
|
|
1010
|
+
reason: { type: "string" },
|
|
1011
|
+
requestedBy: { type: "string" }
|
|
189
1012
|
},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
1013
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
1014
|
+
},
|
|
1015
|
+
outputSchema: controlOutputSchema
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
name: "martin_cancel",
|
|
1019
|
+
description: "Record a durable cancellation request for a Martin run. This writes a control receipt; it does not silently kill a process without evidence.",
|
|
1020
|
+
annotations: {
|
|
1021
|
+
destructiveHint: true,
|
|
1022
|
+
idempotentHint: false
|
|
1023
|
+
},
|
|
1024
|
+
inputSchema: {
|
|
1025
|
+
type: "object",
|
|
1026
|
+
additionalProperties: false,
|
|
1027
|
+
properties: {
|
|
1028
|
+
file: { type: "string" },
|
|
1029
|
+
loopId: { type: "string" },
|
|
1030
|
+
runsDir: { type: "string" },
|
|
1031
|
+
latest: { const: true },
|
|
1032
|
+
reason: { type: "string" },
|
|
1033
|
+
requestedBy: { type: "string" }
|
|
193
1034
|
},
|
|
194
|
-
|
|
195
|
-
type: "string",
|
|
196
|
-
description: "Project identifier for telemetry. Defaults to 'proj_mcp'."
|
|
197
|
-
}
|
|
1035
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
198
1036
|
},
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
1037
|
+
outputSchema: controlOutputSchema
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
name: "martin_continue",
|
|
1041
|
+
description: "Record a durable continue or resume request for a Martin run after a human pause or approval checkpoint.",
|
|
1042
|
+
annotations: {
|
|
1043
|
+
destructiveHint: true,
|
|
1044
|
+
idempotentHint: false
|
|
1045
|
+
},
|
|
1046
|
+
inputSchema: {
|
|
1047
|
+
type: "object",
|
|
1048
|
+
additionalProperties: false,
|
|
1049
|
+
properties: {
|
|
1050
|
+
file: { type: "string" },
|
|
1051
|
+
loopId: { type: "string" },
|
|
1052
|
+
runsDir: { type: "string" },
|
|
1053
|
+
latest: { const: true },
|
|
1054
|
+
reason: { type: "string" },
|
|
1055
|
+
requestedBy: { type: "string" }
|
|
212
1056
|
},
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
1057
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
1058
|
+
},
|
|
1059
|
+
outputSchema: controlOutputSchema
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
name: "martin_list_runs",
|
|
1063
|
+
description: "List recent Martin runs from the run store with lightweight filters for status, lifecycle, engine metadata, and recency.",
|
|
1064
|
+
annotations: {
|
|
1065
|
+
readOnlyHint: true,
|
|
1066
|
+
idempotentHint: true
|
|
1067
|
+
},
|
|
1068
|
+
inputSchema: {
|
|
1069
|
+
type: "object",
|
|
1070
|
+
additionalProperties: false,
|
|
1071
|
+
properties: {
|
|
1072
|
+
runsDir: { type: "string", description: "Optional runs-root override." },
|
|
1073
|
+
limit: {
|
|
1074
|
+
type: "integer",
|
|
1075
|
+
minimum: 1,
|
|
1076
|
+
description: "Maximum number of runs to return. Defaults to 20."
|
|
1077
|
+
},
|
|
1078
|
+
status: { type: "string", description: "Filter by loop status." },
|
|
1079
|
+
lifecycleState: { type: "string", description: "Filter by lifecycle state." },
|
|
1080
|
+
adapterId: { type: "string", description: "Filter by attempt adapter ID." },
|
|
1081
|
+
model: { type: "string", description: "Filter by attempt model." },
|
|
1082
|
+
updatedAfter: {
|
|
1083
|
+
type: "string",
|
|
1084
|
+
description: "Optional ISO-8601 timestamp for recency filtering."
|
|
1085
|
+
}
|
|
216
1086
|
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
description: "
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
1087
|
+
},
|
|
1088
|
+
outputSchema: listRunsOutputSchema
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
name: "martin_triage_runs",
|
|
1092
|
+
description: "Prioritize Martin runs that need operator or agent attention based on verification, lifecycle, and budget pressure.",
|
|
1093
|
+
annotations: {
|
|
1094
|
+
readOnlyHint: true,
|
|
1095
|
+
idempotentHint: true
|
|
1096
|
+
},
|
|
1097
|
+
inputSchema: {
|
|
1098
|
+
type: "object",
|
|
1099
|
+
additionalProperties: false,
|
|
1100
|
+
properties: {
|
|
1101
|
+
runsDir: { type: "string", description: "Optional runs-root override." },
|
|
1102
|
+
limit: {
|
|
1103
|
+
type: "integer",
|
|
1104
|
+
minimum: 1,
|
|
1105
|
+
description: "Maximum number of runs to triage. Defaults to 20."
|
|
1106
|
+
},
|
|
1107
|
+
status: { type: "string", description: "Filter by loop status." },
|
|
1108
|
+
lifecycleState: {
|
|
1109
|
+
type: "string",
|
|
1110
|
+
description: "Filter by lifecycle state."
|
|
1111
|
+
},
|
|
1112
|
+
adapterId: { type: "string", description: "Filter by attempt adapter ID." },
|
|
1113
|
+
model: { type: "string", description: "Filter by attempt model." },
|
|
1114
|
+
updatedAfter: {
|
|
1115
|
+
type: "string",
|
|
1116
|
+
description: "Optional ISO-8601 timestamp for recency filtering."
|
|
1117
|
+
},
|
|
1118
|
+
includeHealthy: {
|
|
1119
|
+
type: "boolean",
|
|
1120
|
+
description: "When true, include healthy runs instead of only attention-worthy findings."
|
|
1121
|
+
}
|
|
246
1122
|
}
|
|
247
1123
|
},
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
1124
|
+
outputSchema: triageRunsOutputSchema
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
name: "martin_get_run",
|
|
1128
|
+
description: "Load one Martin run and return its budget, cost, verification, artifact, and canonical path summary.",
|
|
1129
|
+
annotations: {
|
|
1130
|
+
readOnlyHint: true,
|
|
1131
|
+
idempotentHint: true
|
|
1132
|
+
},
|
|
1133
|
+
inputSchema: {
|
|
1134
|
+
type: "object",
|
|
1135
|
+
additionalProperties: false,
|
|
1136
|
+
properties: {
|
|
1137
|
+
file: {
|
|
1138
|
+
type: "string",
|
|
1139
|
+
description: "Path to a canonical loop-record.json, legacy file, or run-store directory."
|
|
1140
|
+
},
|
|
1141
|
+
loopId: { type: "string", description: "Loop ID under the run store." },
|
|
1142
|
+
runsDir: { type: "string", description: "Optional runs-root override." },
|
|
1143
|
+
latest: {
|
|
1144
|
+
const: true,
|
|
1145
|
+
description: "When true, loads the most recently updated loop record in the run store."
|
|
1146
|
+
}
|
|
266
1147
|
},
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
1148
|
+
oneOf: [
|
|
1149
|
+
{ required: ["file"] },
|
|
1150
|
+
{ required: ["loopId"] },
|
|
1151
|
+
{ required: ["latest"] }
|
|
1152
|
+
]
|
|
1153
|
+
},
|
|
1154
|
+
outputSchema: getRunOutputSchema
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
name: "martin_get_attempt",
|
|
1158
|
+
description: "Load one Martin attempt summary with artifact directory references for a canonical run.",
|
|
1159
|
+
annotations: {
|
|
1160
|
+
readOnlyHint: true,
|
|
1161
|
+
idempotentHint: true
|
|
1162
|
+
},
|
|
1163
|
+
inputSchema: {
|
|
1164
|
+
type: "object",
|
|
1165
|
+
additionalProperties: false,
|
|
1166
|
+
properties: {
|
|
1167
|
+
file: {
|
|
1168
|
+
type: "string",
|
|
1169
|
+
description: "Path to a canonical loop-record.json file or run directory."
|
|
1170
|
+
},
|
|
1171
|
+
loopId: { type: "string", description: "Loop ID under the run store." },
|
|
1172
|
+
runsDir: { type: "string", description: "Optional runs-root override." },
|
|
1173
|
+
attemptIndex: {
|
|
1174
|
+
type: "integer",
|
|
1175
|
+
minimum: 1,
|
|
1176
|
+
description: "Attempt index to inspect. Defaults to the latest attempt."
|
|
1177
|
+
}
|
|
285
1178
|
},
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
1179
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }]
|
|
1180
|
+
},
|
|
1181
|
+
outputSchema: getAttemptOutputSchema
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
name: "martin_get_verification_results",
|
|
1185
|
+
description: "Load verification evidence for a Martin run from stored loop events and ledger entries.",
|
|
1186
|
+
annotations: {
|
|
1187
|
+
readOnlyHint: true,
|
|
1188
|
+
idempotentHint: true
|
|
1189
|
+
},
|
|
1190
|
+
inputSchema: {
|
|
1191
|
+
type: "object",
|
|
1192
|
+
additionalProperties: false,
|
|
1193
|
+
properties: {
|
|
1194
|
+
file: {
|
|
1195
|
+
type: "string",
|
|
1196
|
+
description: "Path to a canonical loop-record.json file or run directory."
|
|
1197
|
+
},
|
|
1198
|
+
loopId: { type: "string", description: "Loop ID under the run store." },
|
|
1199
|
+
runsDir: { type: "string", description: "Optional runs-root override." }
|
|
289
1200
|
},
|
|
290
|
-
|
|
291
|
-
const: true,
|
|
292
|
-
description: "When true, loads the most recently updated loop record in the runs directory."
|
|
293
|
-
}
|
|
1201
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }]
|
|
294
1202
|
},
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
1203
|
+
outputSchema: verificationResultsOutputSchema
|
|
1204
|
+
},
|
|
1205
|
+
{
|
|
1206
|
+
name: "martin_run_dossier",
|
|
1207
|
+
description: "Return the full governed execution dossier for one Martin run, including attempts, events, artifacts, and related discovery surfaces.",
|
|
1208
|
+
annotations: {
|
|
1209
|
+
readOnlyHint: true,
|
|
1210
|
+
idempotentHint: true
|
|
1211
|
+
},
|
|
1212
|
+
inputSchema: {
|
|
1213
|
+
type: "object",
|
|
1214
|
+
additionalProperties: false,
|
|
1215
|
+
properties: {
|
|
1216
|
+
file: {
|
|
1217
|
+
type: "string",
|
|
1218
|
+
description: "Path to a canonical loop-record.json, legacy file, or run-store directory."
|
|
1219
|
+
},
|
|
1220
|
+
loopId: { type: "string", description: "Loop ID under the run store." },
|
|
1221
|
+
runsDir: { type: "string", description: "Optional runs-root override." },
|
|
1222
|
+
latest: {
|
|
1223
|
+
const: true,
|
|
1224
|
+
description: "When true, loads the most recently updated loop record in the run store."
|
|
1225
|
+
}
|
|
308
1226
|
},
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
1227
|
+
oneOf: [
|
|
1228
|
+
{ required: ["file"] },
|
|
1229
|
+
{ required: ["loopId"] },
|
|
1230
|
+
{ required: ["latest"] }
|
|
1231
|
+
]
|
|
1232
|
+
},
|
|
1233
|
+
outputSchema: dossierOutputSchema
|
|
1234
|
+
},
|
|
1235
|
+
{
|
|
1236
|
+
name: "martin_dossier",
|
|
1237
|
+
description: "Alias for martin_run_dossier with support for JSON, Markdown, or GitHub PR formatting. Use after martin_run to understand what happened and whether the result is actually safe to trust.",
|
|
1238
|
+
annotations: {
|
|
1239
|
+
readOnlyHint: true,
|
|
1240
|
+
idempotentHint: true
|
|
1241
|
+
},
|
|
1242
|
+
inputSchema: {
|
|
1243
|
+
type: "object",
|
|
1244
|
+
additionalProperties: false,
|
|
1245
|
+
properties: {
|
|
1246
|
+
file: { type: "string" },
|
|
1247
|
+
loopId: { type: "string" },
|
|
1248
|
+
runsDir: { type: "string" },
|
|
1249
|
+
latest: { const: true },
|
|
1250
|
+
format: { type: "string", enum: ["json", "md", "github-pr"] }
|
|
313
1251
|
},
|
|
314
|
-
|
|
315
|
-
type: "string",
|
|
316
|
-
description: "Optional runs-root override resolved under the default Martin runs root. Defaults to MARTIN_RUNS_DIR or ~/.martin/runs."
|
|
317
|
-
}
|
|
1252
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
318
1253
|
},
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
1254
|
+
outputSchema: dossierOutputSchema
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
name: "martin_eval",
|
|
1258
|
+
description: "Grade a Martin run for task completion, verifier health, diff discipline, risk, and reviewability.",
|
|
1259
|
+
annotations: {
|
|
1260
|
+
readOnlyHint: true,
|
|
1261
|
+
idempotentHint: true
|
|
1262
|
+
},
|
|
1263
|
+
inputSchema: {
|
|
1264
|
+
type: "object",
|
|
1265
|
+
additionalProperties: false,
|
|
1266
|
+
properties: {
|
|
1267
|
+
file: { type: "string" },
|
|
1268
|
+
loopId: { type: "string" },
|
|
1269
|
+
runsDir: { type: "string" },
|
|
1270
|
+
latest: { const: true }
|
|
332
1271
|
},
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
1272
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
1273
|
+
},
|
|
1274
|
+
outputSchema: evalOutputSchema
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
name: "martin_pr_summary",
|
|
1278
|
+
description: "Generate a PR title and body with a MartinLoop dossier block for a completed run.",
|
|
1279
|
+
annotations: {
|
|
1280
|
+
readOnlyHint: true,
|
|
1281
|
+
idempotentHint: true
|
|
1282
|
+
},
|
|
1283
|
+
inputSchema: {
|
|
1284
|
+
type: "object",
|
|
1285
|
+
additionalProperties: false,
|
|
1286
|
+
properties: {
|
|
1287
|
+
file: { type: "string" },
|
|
1288
|
+
loopId: { type: "string" },
|
|
1289
|
+
runsDir: { type: "string" },
|
|
1290
|
+
latest: { const: true },
|
|
1291
|
+
format: { type: "string", enum: ["json", "md", "github-pr"] }
|
|
336
1292
|
},
|
|
337
|
-
|
|
338
|
-
const: true,
|
|
339
|
-
description: "When true, loads the most recently updated loop record in the runs directory."
|
|
340
|
-
}
|
|
1293
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
341
1294
|
},
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
1295
|
+
outputSchema: prSummaryOutputSchema
|
|
1296
|
+
},
|
|
1297
|
+
{
|
|
1298
|
+
name: "martin_create_pr",
|
|
1299
|
+
description: "Create or preview a GitHub PR with a MartinLoop dossier body. Use execute=true to actually call gh.",
|
|
1300
|
+
annotations: {
|
|
1301
|
+
destructiveHint: true,
|
|
1302
|
+
idempotentHint: false
|
|
1303
|
+
},
|
|
1304
|
+
inputSchema: {
|
|
1305
|
+
type: "object",
|
|
1306
|
+
additionalProperties: false,
|
|
1307
|
+
properties: {
|
|
1308
|
+
file: { type: "string" },
|
|
1309
|
+
loopId: { type: "string" },
|
|
1310
|
+
runsDir: { type: "string" },
|
|
1311
|
+
latest: { const: true },
|
|
1312
|
+
format: { type: "string", enum: ["json", "md", "github-pr"] },
|
|
1313
|
+
title: { type: "string" },
|
|
1314
|
+
base: { type: "string" },
|
|
1315
|
+
execute: { type: "boolean" }
|
|
355
1316
|
},
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
1317
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
1318
|
+
},
|
|
1319
|
+
outputSchema: prSummaryOutputSchema
|
|
1320
|
+
},
|
|
1321
|
+
{
|
|
1322
|
+
name: "martin_review_pr",
|
|
1323
|
+
description: "Review a PR or PR draft against the Martin dossier and evaluation evidence.",
|
|
1324
|
+
annotations: {
|
|
1325
|
+
readOnlyHint: true,
|
|
1326
|
+
idempotentHint: true
|
|
1327
|
+
},
|
|
1328
|
+
inputSchema: {
|
|
1329
|
+
type: "object",
|
|
1330
|
+
additionalProperties: false,
|
|
1331
|
+
properties: {
|
|
1332
|
+
file: { type: "string" },
|
|
1333
|
+
loopId: { type: "string" },
|
|
1334
|
+
runsDir: { type: "string" },
|
|
1335
|
+
latest: { const: true },
|
|
1336
|
+
format: { type: "string", enum: ["json", "md", "github-pr"] },
|
|
1337
|
+
prBody: { type: "string" }
|
|
359
1338
|
},
|
|
360
|
-
|
|
361
|
-
const: true,
|
|
362
|
-
description: "When true, loads the most recently updated loop record in the runs directory."
|
|
363
|
-
}
|
|
1339
|
+
oneOf: [{ required: ["file"] }, { required: ["loopId"] }, { required: ["latest"] }]
|
|
364
1340
|
},
|
|
365
|
-
|
|
1341
|
+
outputSchema: prReviewOutputSchema
|
|
366
1342
|
}
|
|
1343
|
+
]
|
|
1344
|
+
}));
|
|
1345
|
+
server.setRequestHandler(ListResourcesRequestSchema, () => ({
|
|
1346
|
+
...listMartinResources()
|
|
1347
|
+
}));
|
|
1348
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, () => ({
|
|
1349
|
+
...listMartinResourceTemplates()
|
|
1350
|
+
}));
|
|
1351
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
1352
|
+
try {
|
|
1353
|
+
return await readMartinResource({ uri: request.params.uri });
|
|
367
1354
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
server.setRequestHandler(ListResourcesRequestSchema, () => ({
|
|
374
|
-
resources: listMartinResources()
|
|
375
|
-
}));
|
|
376
|
-
server.setRequestHandler(ListResourceTemplatesRequestSchema, () => ({
|
|
377
|
-
resourceTemplates: listMartinResourceTemplates()
|
|
378
|
-
}));
|
|
379
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
380
|
-
return readMartinResource(request.params.uri);
|
|
381
|
-
});
|
|
382
|
-
server.setRequestHandler(ListPromptsRequestSchema, () => ({
|
|
383
|
-
prompts: listMartinPrompts()
|
|
384
|
-
}));
|
|
385
|
-
server.setRequestHandler(GetPromptRequestSchema, (request) => {
|
|
386
|
-
return getMartinPrompt(request.params.name, request.params.arguments ?? {});
|
|
387
|
-
});
|
|
388
|
-
// ---------------------------------------------------------------------------
|
|
389
|
-
// Tool dispatch
|
|
390
|
-
// ---------------------------------------------------------------------------
|
|
391
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
392
|
-
const { name, arguments: args } = request.params;
|
|
393
|
-
try {
|
|
394
|
-
if (name === "martin_doctor") {
|
|
395
|
-
const input = validateToolInput("martin_doctor", args);
|
|
396
|
-
const output = await martinDoctorTool(input);
|
|
397
|
-
return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }] };
|
|
398
|
-
}
|
|
399
|
-
if (name === "martin_preflight") {
|
|
400
|
-
const input = validateToolInput("martin_preflight", args);
|
|
401
|
-
const output = await martinPreflightTool(input);
|
|
402
|
-
return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }] };
|
|
403
|
-
}
|
|
404
|
-
if (name === "martin_run") {
|
|
405
|
-
const input = validateToolInput("martin_run", args);
|
|
406
|
-
const output = await runLoopTool(input);
|
|
407
|
-
return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }] };
|
|
408
|
-
}
|
|
409
|
-
if (name === "martin_inspect") {
|
|
410
|
-
const input = validateToolInput("martin_inspect", args);
|
|
411
|
-
const output = await inspectLoopTool(input);
|
|
412
|
-
return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }] };
|
|
413
|
-
}
|
|
414
|
-
if (name === "martin_status") {
|
|
415
|
-
const input = validateToolInput("martin_status", args);
|
|
416
|
-
const output = await getStatusTool(input);
|
|
417
|
-
return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }] };
|
|
418
|
-
}
|
|
419
|
-
if (name === "martin_list_runs") {
|
|
420
|
-
const input = validateToolInput("martin_list_runs", args);
|
|
421
|
-
const output = await listRunsTool(input);
|
|
422
|
-
return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }] };
|
|
1355
|
+
catch (error) {
|
|
1356
|
+
if (error instanceof MartinToolError) {
|
|
1357
|
+
throw error;
|
|
1358
|
+
}
|
|
1359
|
+
throw new Error(sanitizeToolErrorMessage(error));
|
|
423
1360
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
1361
|
+
});
|
|
1362
|
+
server.setRequestHandler(ListPromptsRequestSchema, () => ({
|
|
1363
|
+
...listMartinPrompts()
|
|
1364
|
+
}));
|
|
1365
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
1366
|
+
try {
|
|
1367
|
+
return await getMartinPrompt({
|
|
1368
|
+
name: request.params.name,
|
|
1369
|
+
arguments: request.params.arguments
|
|
1370
|
+
});
|
|
428
1371
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
1372
|
+
catch (error) {
|
|
1373
|
+
if (error instanceof MartinToolError) {
|
|
1374
|
+
throw error;
|
|
1375
|
+
}
|
|
1376
|
+
throw new Error(sanitizeToolErrorMessage(error));
|
|
433
1377
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
1378
|
+
});
|
|
1379
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1380
|
+
const { name, arguments: args } = request.params;
|
|
1381
|
+
try {
|
|
1382
|
+
if (name === "martin_run") {
|
|
1383
|
+
const input = validateToolInput("martin_run", args);
|
|
1384
|
+
const output = await runLoopTool(input);
|
|
1385
|
+
return createToolSuccessResult(output, `Run ${output.loopId} is ${output.status}/${output.lifecycleState} after ${output.attempts} attempt(s); spend ${output.costUsd.toFixed(2)} USD.`);
|
|
1386
|
+
}
|
|
1387
|
+
if (name === "martin_inspect") {
|
|
1388
|
+
const input = validateToolInput("martin_inspect", args);
|
|
1389
|
+
const output = await inspectLoopTool(input);
|
|
1390
|
+
return createToolSuccessResult(output, `Inspected ${output.loopCount} run(s) from ${output.source}; total actual spend ${output.portfolio.totalActualUsd.toFixed(2)} USD.`);
|
|
1391
|
+
}
|
|
1392
|
+
if (name === "martin_status") {
|
|
1393
|
+
const input = validateToolInput("martin_status", args);
|
|
1394
|
+
const output = await getStatusTool(input);
|
|
1395
|
+
return createToolSuccessResult(output, `Loop ${output.loopId} is ${output.status}/${output.lifecycleState}; pressure is ${output.pressure} with ${output.remainingBudgetUsd.toFixed(2)} USD remaining.`);
|
|
1396
|
+
}
|
|
1397
|
+
if (name === "martin_doctor") {
|
|
1398
|
+
const input = validateToolInput("martin_doctor", args);
|
|
1399
|
+
const output = await martinDoctorTool(input);
|
|
1400
|
+
await recordMcpWorkflowStep({
|
|
1401
|
+
runsRoot: output.environment.runsRoot,
|
|
1402
|
+
step: "doctor",
|
|
1403
|
+
workingDirectory: output.environment.workingDirectory,
|
|
1404
|
+
engine: input.engine
|
|
1405
|
+
}).catch(() => { });
|
|
1406
|
+
return createToolSuccessResult(output, output.summary);
|
|
1407
|
+
}
|
|
1408
|
+
if (name === "martin_plan") {
|
|
1409
|
+
const input = validateToolInput("martin_plan", args);
|
|
1410
|
+
const output = await martinPlanTool(input);
|
|
1411
|
+
await recordMcpWorkflowStep({
|
|
1412
|
+
runsRoot: resolveRunsRoot(process.env),
|
|
1413
|
+
step: "plan",
|
|
1414
|
+
workingDirectory: output.workingDirectory,
|
|
1415
|
+
objective: output.objective
|
|
1416
|
+
}).catch(() => { });
|
|
1417
|
+
return createToolSuccessResult(output, `Plan ready for ${output.objective} with ${output.risk.level} risk and ${output.approvalRecommendation.replace(/_/gu, " ")} approval.`);
|
|
1418
|
+
}
|
|
1419
|
+
if (name === "martin_preflight") {
|
|
1420
|
+
const input = validateToolInput("martin_preflight", args);
|
|
1421
|
+
const output = await martinPreflightTool(input);
|
|
1422
|
+
if (output.ok) {
|
|
1423
|
+
await recordMcpWorkflowStep({
|
|
1424
|
+
runsRoot: output.execution.runsRoot,
|
|
1425
|
+
step: "preflight",
|
|
1426
|
+
workingDirectory: output.normalized.workingDirectory,
|
|
1427
|
+
objective: output.normalized.objective,
|
|
1428
|
+
engine: output.normalized.engine,
|
|
1429
|
+
verificationPlan: output.normalized.verificationPlan
|
|
1430
|
+
}).catch(() => { });
|
|
1431
|
+
}
|
|
1432
|
+
return createToolSuccessResult(output, output.summary);
|
|
1433
|
+
}
|
|
1434
|
+
if (name === "martin_logs") {
|
|
1435
|
+
const input = validateToolInput("martin_logs", args);
|
|
1436
|
+
const output = await martinLogsTool(input);
|
|
1437
|
+
return createToolSuccessResult(output, `Loaded ${output.logCount} log entries for Martin run ${output.loopId}.`);
|
|
1438
|
+
}
|
|
1439
|
+
if (name === "martin_pause") {
|
|
1440
|
+
const input = validateToolInput("martin_pause", args);
|
|
1441
|
+
const output = await createRunControlReceipt("pause", input);
|
|
1442
|
+
return createToolSuccessResult(output, output.summary);
|
|
1443
|
+
}
|
|
1444
|
+
if (name === "martin_cancel") {
|
|
1445
|
+
const input = validateToolInput("martin_cancel", args);
|
|
1446
|
+
const output = await createRunControlReceipt("cancel", input);
|
|
1447
|
+
return createToolSuccessResult(output, output.summary);
|
|
1448
|
+
}
|
|
1449
|
+
if (name === "martin_continue") {
|
|
1450
|
+
const input = validateToolInput("martin_continue", args);
|
|
1451
|
+
const output = await createRunControlReceipt("continue", input);
|
|
1452
|
+
return createToolSuccessResult(output, output.summary);
|
|
1453
|
+
}
|
|
1454
|
+
if (name === "martin_list_runs") {
|
|
1455
|
+
const input = validateToolInput("martin_list_runs", args);
|
|
1456
|
+
const output = await martinListRunsTool(input);
|
|
1457
|
+
return createToolSuccessResult(output, `Listed ${output.loopCount} Martin run(s) from ${output.runsRoot}.`);
|
|
1458
|
+
}
|
|
1459
|
+
if (name === "martin_triage_runs") {
|
|
1460
|
+
const input = validateToolInput("martin_triage_runs", args);
|
|
1461
|
+
const output = await martinTriageRunsTool(input);
|
|
1462
|
+
return createToolSuccessResult(output, `Triaged ${output.evaluatedRuns} Martin run(s) and found ${output.findingCount} attention item(s).`);
|
|
1463
|
+
}
|
|
1464
|
+
if (name === "martin_get_run") {
|
|
1465
|
+
const input = validateToolInput("martin_get_run", args);
|
|
1466
|
+
const output = await martinGetRunTool(input);
|
|
1467
|
+
return createToolSuccessResult(output, `Loaded Martin run ${output.loop.loopId} from ${output.source}.`);
|
|
1468
|
+
}
|
|
1469
|
+
if (name === "martin_get_attempt") {
|
|
1470
|
+
const input = validateToolInput("martin_get_attempt", args);
|
|
1471
|
+
const output = await martinGetAttemptTool(input);
|
|
1472
|
+
return createToolSuccessResult(output, `Loaded attempt ${output.attempt.index} for Martin run ${output.loop.loopId}.`);
|
|
1473
|
+
}
|
|
1474
|
+
if (name === "martin_get_verification_results") {
|
|
1475
|
+
const input = validateToolInput("martin_get_verification_results", args);
|
|
1476
|
+
const output = await martinGetVerificationResultsTool(input);
|
|
1477
|
+
return createToolSuccessResult(output, `Verification for ${output.loop.loopId} is ${output.verification.status}.`);
|
|
1478
|
+
}
|
|
1479
|
+
if (name === "martin_run_dossier") {
|
|
1480
|
+
const input = validateToolInput("martin_run_dossier", args);
|
|
1481
|
+
const output = await martinRunDossierTool(input);
|
|
1482
|
+
return createToolSuccessResult(output, `Dossier ready for Martin run ${output.loop.loopId} with ${output.attempts.length} attempt(s).`);
|
|
1483
|
+
}
|
|
1484
|
+
if (name === "martin_dossier") {
|
|
1485
|
+
const input = validateToolInput("martin_dossier", args);
|
|
1486
|
+
const output = await martinRunDossierTool(input);
|
|
1487
|
+
return createToolSuccessResult(output, `Dossier ready for Martin run ${output.loop.loopId} in ${output.format} format.`);
|
|
1488
|
+
}
|
|
1489
|
+
if (name === "martin_eval") {
|
|
1490
|
+
const input = validateToolInput("martin_eval", args);
|
|
1491
|
+
const output = await martinEvalTool(input);
|
|
1492
|
+
return createToolSuccessResult(output, `Evaluation for ${output.loopId}: ${output.grade} (${output.score}).`);
|
|
1493
|
+
}
|
|
1494
|
+
if (name === "martin_pr_summary") {
|
|
1495
|
+
const input = validateToolInput("martin_pr_summary", args);
|
|
1496
|
+
const output = await martinPrSummaryTool(input);
|
|
1497
|
+
return createToolSuccessResult(output, `PR summary ready for Martin run ${output.loopId}.`);
|
|
1498
|
+
}
|
|
1499
|
+
if (name === "martin_create_pr") {
|
|
1500
|
+
const input = validateToolInput("martin_create_pr", args);
|
|
1501
|
+
const output = await martinCreatePrTool(input);
|
|
1502
|
+
return createToolSuccessResult(output, output.created
|
|
1503
|
+
? `Created PR for Martin run ${output.loopId}.`
|
|
1504
|
+
: `PR preview ready for Martin run ${output.loopId}.`);
|
|
1505
|
+
}
|
|
1506
|
+
if (name === "martin_review_pr") {
|
|
1507
|
+
const input = validateToolInput("martin_review_pr", args);
|
|
1508
|
+
const output = await martinReviewPrTool(input);
|
|
1509
|
+
return createToolSuccessResult(output, `PR review verdict for ${output.loopId}: ${output.verdict}.`);
|
|
1510
|
+
}
|
|
1511
|
+
return createToolErrorResult(toToolFailure(new Error(`Unknown tool: ${name}`)));
|
|
438
1512
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const output = await runDossierTool(input);
|
|
442
|
-
return { content: [{ type: "text", text: JSON.stringify(output, null, 2) }] };
|
|
1513
|
+
catch (error) {
|
|
1514
|
+
return createToolErrorResult(toToolFailure(error));
|
|
443
1515
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
1516
|
+
});
|
|
1517
|
+
return server;
|
|
1518
|
+
}
|
|
1519
|
+
export async function connectMartinMcpStdioServer() {
|
|
1520
|
+
const server = createMartinMcpServer();
|
|
1521
|
+
const transport = new StdioServerTransport();
|
|
1522
|
+
await server.connect(transport);
|
|
1523
|
+
return server;
|
|
1524
|
+
}
|
|
1525
|
+
export function isDirectExecutionEntry(entryPath, moduleUrl = import.meta.url) {
|
|
1526
|
+
if (typeof entryPath !== "string" || entryPath.length === 0) {
|
|
1527
|
+
return false;
|
|
1528
|
+
}
|
|
1529
|
+
const modulePath = realPathOrResolved(fileURLToPath(moduleUrl));
|
|
1530
|
+
const resolvedEntryPath = realPathOrResolved(entryPath);
|
|
1531
|
+
return modulePath === resolvedEntryPath;
|
|
1532
|
+
}
|
|
1533
|
+
function isDirectExecution() {
|
|
1534
|
+
return isDirectExecutionEntry(process.argv[1]);
|
|
1535
|
+
}
|
|
1536
|
+
function realPathOrResolved(filePath) {
|
|
1537
|
+
try {
|
|
1538
|
+
return realpathSync.native(filePath);
|
|
448
1539
|
}
|
|
449
|
-
catch
|
|
450
|
-
|
|
451
|
-
return {
|
|
452
|
-
content: [{ type: "text", text: `Tool error: ${message}` }],
|
|
453
|
-
isError: true
|
|
454
|
-
};
|
|
1540
|
+
catch {
|
|
1541
|
+
return path.resolve(filePath);
|
|
455
1542
|
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const transport = new StdioServerTransport();
|
|
461
|
-
await server.connect(transport);
|
|
462
|
-
//# sourceMappingURL=server.js.map
|
|
1543
|
+
}
|
|
1544
|
+
if (isDirectExecution()) {
|
|
1545
|
+
await connectMartinMcpStdioServer();
|
|
1546
|
+
}
|