@lonca/baron-mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +20 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +24 -0
- package/dist/chunk-MUGSC3EW.js +1076 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +62 -0
- package/package.json +57 -0
|
@@ -0,0 +1,1076 @@
|
|
|
1
|
+
// src/load.ts
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { BaronError, parsePolicyJson } from "@lonca/baron-core";
|
|
4
|
+
import { createLocalKnowledgeLoop } from "@lonca/baron-knowledge-loop";
|
|
5
|
+
import {
|
|
6
|
+
buildPorts,
|
|
7
|
+
credentialsPath,
|
|
8
|
+
executeNativeRequest,
|
|
9
|
+
knowledgeDir,
|
|
10
|
+
mergeCredentials,
|
|
11
|
+
policyPath
|
|
12
|
+
} from "@lonca/baron-providers";
|
|
13
|
+
import { createRecipeService } from "@lonca/baron-recipes";
|
|
14
|
+
function readIfPresent(path) {
|
|
15
|
+
return existsSync(path) ? readFileSync(path, "utf8") : void 0;
|
|
16
|
+
}
|
|
17
|
+
function loadPorts(root, env) {
|
|
18
|
+
const path = policyPath(root);
|
|
19
|
+
const raw = readIfPresent(path);
|
|
20
|
+
if (raw === void 0) {
|
|
21
|
+
throw new BaronError(
|
|
22
|
+
`No policy found at ${path}. Run \`baron init\` first.`,
|
|
23
|
+
"POLICY_NOT_FOUND"
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
const effectiveEnv = mergeCredentials(env, readIfPresent(credentialsPath(root)));
|
|
27
|
+
const policy = parsePolicyJson(raw);
|
|
28
|
+
const boundProviders = new Set(
|
|
29
|
+
Object.values(policy.providers).filter((p) => typeof p === "string")
|
|
30
|
+
);
|
|
31
|
+
const nativeAccess = (provider, request) => {
|
|
32
|
+
if (!boundProviders.has(provider)) {
|
|
33
|
+
throw new BaronError(
|
|
34
|
+
`Provider '${provider}' is not bound in this policy; the escape hatch only reaches bound providers.`,
|
|
35
|
+
"NATIVE_UNSUPPORTED"
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return executeNativeRequest(provider, effectiveEnv, request);
|
|
39
|
+
};
|
|
40
|
+
const bound = buildPorts(policy, effectiveEnv);
|
|
41
|
+
const knowledge = createLocalKnowledgeLoop(knowledgeDir(root));
|
|
42
|
+
const recipes = createRecipeService({ ...bound, knowledge }, root);
|
|
43
|
+
return { ...bound, knowledge, nativeAccess, recipes };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/tools.ts
|
|
47
|
+
import {
|
|
48
|
+
BaronError as BaronError2,
|
|
49
|
+
ISSUE_LINK_TYPES,
|
|
50
|
+
RUN_STATUSES,
|
|
51
|
+
WORKFLOW_ROLES,
|
|
52
|
+
WORK_ITEM_TYPE_ROLES,
|
|
53
|
+
isIssueLinkType,
|
|
54
|
+
isRunStatus,
|
|
55
|
+
isWorkItemTypeRole,
|
|
56
|
+
isWorkflowRole
|
|
57
|
+
} from "@lonca/baron-core";
|
|
58
|
+
import {
|
|
59
|
+
FOLLOWUP_STATUSES,
|
|
60
|
+
isFollowupStatus
|
|
61
|
+
} from "@lonca/baron-knowledge-loop";
|
|
62
|
+
var MCP_TOOL_NAMES = {
|
|
63
|
+
create: "baron_issue_create",
|
|
64
|
+
get: "baron_issue_get",
|
|
65
|
+
transition: "baron_issue_transition",
|
|
66
|
+
comment: "baron_issue_comment",
|
|
67
|
+
link: "baron_issue_link",
|
|
68
|
+
query: "baron_issue_query"
|
|
69
|
+
};
|
|
70
|
+
var SCM_TOOL_NAMES = {
|
|
71
|
+
branchCreate: "baron_scm_branch_create",
|
|
72
|
+
prCreate: "baron_scm_pr_create",
|
|
73
|
+
prThread: "baron_scm_pr_thread",
|
|
74
|
+
prStatus: "baron_scm_pr_status"
|
|
75
|
+
};
|
|
76
|
+
var CI_TOOL_NAMES = {
|
|
77
|
+
pipelines: "baron_ci_pipelines",
|
|
78
|
+
runs: "baron_ci_runs",
|
|
79
|
+
runGet: "baron_ci_run_get",
|
|
80
|
+
runLogs: "baron_ci_run_logs",
|
|
81
|
+
runTrigger: "baron_ci_run_trigger",
|
|
82
|
+
runCancel: "baron_ci_run_cancel"
|
|
83
|
+
};
|
|
84
|
+
var NOTIFY_TOOL_NAMES = {
|
|
85
|
+
send: "baron_notify_send"
|
|
86
|
+
};
|
|
87
|
+
var DEPLOY_TOOL_NAMES = {
|
|
88
|
+
environments: "baron_deploy_environments",
|
|
89
|
+
deployments: "baron_deploy_deployments"
|
|
90
|
+
};
|
|
91
|
+
var NATIVE_TOOL_NAMES = {
|
|
92
|
+
request: "baron_native_request"
|
|
93
|
+
};
|
|
94
|
+
var RECIPE_TOOL_NAMES = {
|
|
95
|
+
list: "baron_recipe_list",
|
|
96
|
+
run: "baron_recipe_run"
|
|
97
|
+
};
|
|
98
|
+
var LOOP_TOOL_NAMES = {
|
|
99
|
+
learningAppend: "baron_learning_append",
|
|
100
|
+
learningQuery: "baron_learning_query",
|
|
101
|
+
followupAppend: "baron_followup_append",
|
|
102
|
+
followupList: "baron_followup_list"
|
|
103
|
+
};
|
|
104
|
+
var ROLE_ENUM = [...WORKFLOW_ROLES];
|
|
105
|
+
var TYPE_ROLE_ENUM = [...WORK_ITEM_TYPE_ROLES];
|
|
106
|
+
var LINK_TYPE_ENUM = [...ISSUE_LINK_TYPES];
|
|
107
|
+
var FOLLOWUP_STATUS_ENUM = [...FOLLOWUP_STATUSES];
|
|
108
|
+
var RUN_STATUS_ENUM = [...RUN_STATUSES];
|
|
109
|
+
var DEFAULT_QUERY_LIMIT = 50;
|
|
110
|
+
var TOOL_DEFINITIONS = [
|
|
111
|
+
{
|
|
112
|
+
name: MCP_TOOL_NAMES.create,
|
|
113
|
+
description: "Create an issue from abstract terms. typeRole -> native work-item type and initialRole -> native state are translated automatically per the active policy; capability gaps (e.g. no native hierarchy) are handled by the configured gap policy.",
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: "object",
|
|
116
|
+
additionalProperties: false,
|
|
117
|
+
required: ["title", "typeRole"],
|
|
118
|
+
properties: {
|
|
119
|
+
title: { type: "string", minLength: 1 },
|
|
120
|
+
typeRole: {
|
|
121
|
+
type: "string",
|
|
122
|
+
enum: TYPE_ROLE_ENUM,
|
|
123
|
+
description: "Abstract type role; the provider maps it to a native work-item type."
|
|
124
|
+
},
|
|
125
|
+
body: { type: "string" },
|
|
126
|
+
parentId: {
|
|
127
|
+
type: "string",
|
|
128
|
+
description: "Parent issue id. On providers without native hierarchy this is emulated or degraded per the gap policy."
|
|
129
|
+
},
|
|
130
|
+
labels: { type: "array", items: { type: "string" } },
|
|
131
|
+
initialRole: {
|
|
132
|
+
type: "string",
|
|
133
|
+
enum: ROLE_ENUM,
|
|
134
|
+
description: "Optional starting workflow role; omit to use the provider default."
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: MCP_TOOL_NAMES.get,
|
|
141
|
+
description: "Fetch a normalized issue by id.",
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: "object",
|
|
144
|
+
additionalProperties: false,
|
|
145
|
+
required: ["id"],
|
|
146
|
+
properties: { id: { type: "string", minLength: 1 } }
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: MCP_TOOL_NAMES.transition,
|
|
151
|
+
description: "Transition an issue to a target workflow role (idempotent). The adapter resolves the role to the provider-native state/column/label.",
|
|
152
|
+
inputSchema: {
|
|
153
|
+
type: "object",
|
|
154
|
+
additionalProperties: false,
|
|
155
|
+
required: ["id", "role"],
|
|
156
|
+
properties: {
|
|
157
|
+
id: { type: "string", minLength: 1 },
|
|
158
|
+
role: {
|
|
159
|
+
type: "string",
|
|
160
|
+
enum: ROLE_ENUM,
|
|
161
|
+
description: "Target workflow role. Translated to the provider-native target."
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: MCP_TOOL_NAMES.comment,
|
|
168
|
+
description: "Add a comment to an issue.",
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: "object",
|
|
171
|
+
additionalProperties: false,
|
|
172
|
+
required: ["id", "body"],
|
|
173
|
+
properties: {
|
|
174
|
+
id: { type: "string", minLength: 1 },
|
|
175
|
+
body: { type: "string", minLength: 1 }
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: MCP_TOOL_NAMES.link,
|
|
181
|
+
description: "Link two issues with an abstract relationship. On providers without native typed links the link is emulated or degraded per the gap policy.",
|
|
182
|
+
inputSchema: {
|
|
183
|
+
type: "object",
|
|
184
|
+
additionalProperties: false,
|
|
185
|
+
required: ["fromId", "toId", "type"],
|
|
186
|
+
properties: {
|
|
187
|
+
fromId: { type: "string", minLength: 1 },
|
|
188
|
+
toId: { type: "string", minLength: 1 },
|
|
189
|
+
type: {
|
|
190
|
+
type: "string",
|
|
191
|
+
enum: LINK_TYPE_ENUM,
|
|
192
|
+
description: "Relationship from the source (fromId) to the target (toId) issue."
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: MCP_TOOL_NAMES.query,
|
|
199
|
+
description: "List issues filtered by workflow role and/or type role (filters are AND-combined). Returns a lightweight projection (no body); fetch an issue with get for full detail.",
|
|
200
|
+
inputSchema: {
|
|
201
|
+
type: "object",
|
|
202
|
+
additionalProperties: false,
|
|
203
|
+
properties: {
|
|
204
|
+
role: { type: "string", enum: ROLE_ENUM, description: "Filter by workflow role." },
|
|
205
|
+
typeRole: { type: "string", enum: TYPE_ROLE_ENUM, description: "Filter by type role." },
|
|
206
|
+
limit: {
|
|
207
|
+
type: "number",
|
|
208
|
+
minimum: 1,
|
|
209
|
+
description: `Maximum number of issues to return. Defaults to ${DEFAULT_QUERY_LIMIT} to keep the result within an agent's context; pass a higher value for more.`
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
];
|
|
215
|
+
var SCM_TOOL_DEFINITIONS = [
|
|
216
|
+
{
|
|
217
|
+
name: SCM_TOOL_NAMES.branchCreate,
|
|
218
|
+
description: "Create a branch from a base branch (defaults to the repository default branch).",
|
|
219
|
+
inputSchema: {
|
|
220
|
+
type: "object",
|
|
221
|
+
additionalProperties: false,
|
|
222
|
+
required: ["name"],
|
|
223
|
+
properties: {
|
|
224
|
+
name: {
|
|
225
|
+
type: "string",
|
|
226
|
+
minLength: 1,
|
|
227
|
+
description: "New branch name (without refs/heads/)."
|
|
228
|
+
},
|
|
229
|
+
fromBranch: {
|
|
230
|
+
type: "string",
|
|
231
|
+
minLength: 1,
|
|
232
|
+
description: "Branch to fork from. Defaults to the repository's default branch."
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: SCM_TOOL_NAMES.prCreate,
|
|
239
|
+
description: "Open a pull request. A requested draft may be degraded to a ready PR if the provider lacks draft support (per the gap policy); the returned `draft` reflects what was actually opened.",
|
|
240
|
+
inputSchema: {
|
|
241
|
+
type: "object",
|
|
242
|
+
additionalProperties: false,
|
|
243
|
+
required: ["title", "sourceBranch"],
|
|
244
|
+
properties: {
|
|
245
|
+
title: { type: "string", minLength: 1 },
|
|
246
|
+
body: { type: "string" },
|
|
247
|
+
sourceBranch: { type: "string", minLength: 1 },
|
|
248
|
+
targetBranch: {
|
|
249
|
+
type: "string",
|
|
250
|
+
minLength: 1,
|
|
251
|
+
description: "Branch to merge into. Defaults to the repository's default branch."
|
|
252
|
+
},
|
|
253
|
+
draft: { type: "boolean", description: "Open as a draft PR when supported." }
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: SCM_TOOL_NAMES.prThread,
|
|
259
|
+
description: "Add a discussion thread/comment to a pull request.",
|
|
260
|
+
inputSchema: {
|
|
261
|
+
type: "object",
|
|
262
|
+
additionalProperties: false,
|
|
263
|
+
required: ["pullRequestId", "body"],
|
|
264
|
+
properties: {
|
|
265
|
+
pullRequestId: { type: "string", minLength: 1 },
|
|
266
|
+
body: { type: "string", minLength: 1 }
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
name: SCM_TOOL_NAMES.prStatus,
|
|
272
|
+
description: `Read a pull request's normalized status: state, review decision, mergeability, and a checks rollup \u2014 the "is it ready to merge?" view.`,
|
|
273
|
+
inputSchema: {
|
|
274
|
+
type: "object",
|
|
275
|
+
additionalProperties: false,
|
|
276
|
+
required: ["pullRequestId"],
|
|
277
|
+
properties: { pullRequestId: { type: "string", minLength: 1 } }
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
];
|
|
281
|
+
var CI_TOOL_DEFINITIONS = [
|
|
282
|
+
{
|
|
283
|
+
name: CI_TOOL_NAMES.pipelines,
|
|
284
|
+
description: "List pipeline definitions.",
|
|
285
|
+
inputSchema: {
|
|
286
|
+
type: "object",
|
|
287
|
+
additionalProperties: false,
|
|
288
|
+
properties: {
|
|
289
|
+
limit: {
|
|
290
|
+
type: "number",
|
|
291
|
+
minimum: 1,
|
|
292
|
+
description: "Maximum number of pipelines to return."
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: CI_TOOL_NAMES.runs,
|
|
299
|
+
description: "List CI runs (filter by pipeline / branch / normalized status). Returns a lightweight projection; status is the provider-agnostic run status.",
|
|
300
|
+
inputSchema: {
|
|
301
|
+
type: "object",
|
|
302
|
+
additionalProperties: false,
|
|
303
|
+
properties: {
|
|
304
|
+
pipelineId: { type: "string", minLength: 1, description: "Restrict to one pipeline." },
|
|
305
|
+
branch: { type: "string", minLength: 1, description: "Restrict to a source branch." },
|
|
306
|
+
status: {
|
|
307
|
+
type: "string",
|
|
308
|
+
enum: RUN_STATUS_ENUM,
|
|
309
|
+
description: "Filter by normalized run status."
|
|
310
|
+
},
|
|
311
|
+
limit: {
|
|
312
|
+
type: "number",
|
|
313
|
+
minimum: 1,
|
|
314
|
+
description: `Maximum number of runs to return. Defaults to ${DEFAULT_QUERY_LIMIT} to keep the result within an agent's context.`
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: CI_TOOL_NAMES.runGet,
|
|
321
|
+
description: "Get one run, including its stages when the provider surfaces them.",
|
|
322
|
+
inputSchema: {
|
|
323
|
+
type: "object",
|
|
324
|
+
additionalProperties: false,
|
|
325
|
+
required: ["id"],
|
|
326
|
+
properties: { id: { type: "string", minLength: 1 } }
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: CI_TOOL_NAMES.runLogs,
|
|
331
|
+
description: "Fetch a run's logs. Size-aware: returns a lean tail by default (`truncated` flags omitted content); raise `tailLines` for more.",
|
|
332
|
+
inputSchema: {
|
|
333
|
+
type: "object",
|
|
334
|
+
additionalProperties: false,
|
|
335
|
+
required: ["runId"],
|
|
336
|
+
properties: {
|
|
337
|
+
runId: { type: "string", minLength: 1 },
|
|
338
|
+
tailLines: {
|
|
339
|
+
type: "number",
|
|
340
|
+
minimum: 1,
|
|
341
|
+
description: "Max lines to return from the tail."
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
name: CI_TOOL_NAMES.runTrigger,
|
|
348
|
+
description: "Queue a new run of a pipeline. Returns { accepted, run? } \u2014 `run` is present only when the provider returns it synchronously (some providers dispatch asynchronously with no run id).",
|
|
349
|
+
inputSchema: {
|
|
350
|
+
type: "object",
|
|
351
|
+
additionalProperties: false,
|
|
352
|
+
required: ["pipelineId"],
|
|
353
|
+
properties: {
|
|
354
|
+
pipelineId: { type: "string", minLength: 1 },
|
|
355
|
+
ref: {
|
|
356
|
+
type: "string",
|
|
357
|
+
minLength: 1,
|
|
358
|
+
description: "Branch/tag to run on. Defaults to the repository's default branch."
|
|
359
|
+
},
|
|
360
|
+
variables: {
|
|
361
|
+
type: "object",
|
|
362
|
+
additionalProperties: { type: "string" },
|
|
363
|
+
description: "Pipeline variables / workflow inputs."
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: CI_TOOL_NAMES.runCancel,
|
|
370
|
+
description: "Cancel a run; returns the run with its updated status.",
|
|
371
|
+
inputSchema: {
|
|
372
|
+
type: "object",
|
|
373
|
+
additionalProperties: false,
|
|
374
|
+
required: ["runId"],
|
|
375
|
+
properties: { runId: { type: "string", minLength: 1 } }
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
];
|
|
379
|
+
var NOTIFY_TOOL_DEFINITIONS = [
|
|
380
|
+
{
|
|
381
|
+
name: NOTIFY_TOOL_NAMES.send,
|
|
382
|
+
description: "Send a notification. Targeting a channel or threading a reply may be degraded/errored per the gap policy on providers that lack those capabilities.",
|
|
383
|
+
inputSchema: {
|
|
384
|
+
type: "object",
|
|
385
|
+
additionalProperties: false,
|
|
386
|
+
required: ["text"],
|
|
387
|
+
properties: {
|
|
388
|
+
text: { type: "string", minLength: 1 },
|
|
389
|
+
channel: {
|
|
390
|
+
type: "string",
|
|
391
|
+
minLength: 1,
|
|
392
|
+
description: "Target channel (requires channels)."
|
|
393
|
+
},
|
|
394
|
+
threadKey: {
|
|
395
|
+
type: "string",
|
|
396
|
+
minLength: 1,
|
|
397
|
+
description: "Thread to reply under (an opaque key from a prior send; requires threads)."
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
];
|
|
403
|
+
var DEPLOY_TOOL_DEFINITIONS = [
|
|
404
|
+
{
|
|
405
|
+
name: DEPLOY_TOOL_NAMES.environments,
|
|
406
|
+
description: "List deployment environments (e.g. dev / staging / prod).",
|
|
407
|
+
inputSchema: {
|
|
408
|
+
type: "object",
|
|
409
|
+
additionalProperties: false,
|
|
410
|
+
properties: {
|
|
411
|
+
limit: { type: "number", minimum: 1, description: "Maximum number to return." }
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
name: DEPLOY_TOOL_NAMES.deployments,
|
|
417
|
+
description: "List recent deployments with a normalized status (optionally filtered to one environment).",
|
|
418
|
+
inputSchema: {
|
|
419
|
+
type: "object",
|
|
420
|
+
additionalProperties: false,
|
|
421
|
+
properties: {
|
|
422
|
+
environment: { type: "string", minLength: 1, description: "Restrict to one environment." },
|
|
423
|
+
limit: { type: "number", minimum: 1, description: "Maximum number to return." }
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
];
|
|
428
|
+
var NATIVE_TOOL_DEFINITIONS = [
|
|
429
|
+
{
|
|
430
|
+
name: NATIVE_TOOL_NAMES.request,
|
|
431
|
+
description: "ESCAPE HATCH \u2014 a raw, authenticated, NON-PORTABLE provider REST call. Last resort for when no normalized tool (issue/scm/ci/notify) covers the need. You supply the provider-native method + path (+ query/body); Baron only attaches the base URL + auth and returns the (size-capped) response. Prefer the normalized tools \u2014 this is provider-specific and will not port to another provider. Only providers bound in the active policy are reachable.",
|
|
432
|
+
inputSchema: {
|
|
433
|
+
type: "object",
|
|
434
|
+
additionalProperties: false,
|
|
435
|
+
required: ["provider", "method", "path"],
|
|
436
|
+
properties: {
|
|
437
|
+
provider: { type: "string", minLength: 1, description: "A provider bound in the policy." },
|
|
438
|
+
method: { type: "string", minLength: 1, description: "HTTP method (GET/POST/PATCH/\u2026)." },
|
|
439
|
+
path: {
|
|
440
|
+
type: "string",
|
|
441
|
+
minLength: 1,
|
|
442
|
+
description: "Provider-relative path, including any required api-version query."
|
|
443
|
+
},
|
|
444
|
+
query: { type: "object", additionalProperties: { type: "string" } },
|
|
445
|
+
body: { description: "JSON request body (any shape)." }
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
];
|
|
450
|
+
var RECIPE_TOOL_DEFINITIONS = [
|
|
451
|
+
{
|
|
452
|
+
name: RECIPE_TOOL_NAMES.list,
|
|
453
|
+
description: "List the runnable recipes (built-ins + project recipes) with their declared inputs. Call this to discover what `baron_recipe_run` accepts before running a workflow.",
|
|
454
|
+
inputSchema: { type: "object", additionalProperties: false, properties: {} }
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
name: RECIPE_TOOL_NAMES.run,
|
|
458
|
+
description: "Run a named recipe end-to-end as ONE deterministic, rule-enforced workflow (the engine \u2014 not you \u2014 enforces the step order). Supply all required inputs (from baron_recipe_list) in `inputs`; a missing required input errors rather than prompting. Prefer this over composing the individual issue/scm/ci tools yourself for a packaged workflow.",
|
|
459
|
+
inputSchema: {
|
|
460
|
+
type: "object",
|
|
461
|
+
additionalProperties: false,
|
|
462
|
+
required: ["name"],
|
|
463
|
+
properties: {
|
|
464
|
+
name: { type: "string", minLength: 1, description: "Recipe name (e.g. task-start)." },
|
|
465
|
+
inputs: {
|
|
466
|
+
type: "object",
|
|
467
|
+
description: "Values for the recipe's `ask` inputs, keyed by input name."
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
];
|
|
473
|
+
var LOOP_TOOL_DEFINITIONS = [
|
|
474
|
+
{
|
|
475
|
+
name: LOOP_TOOL_NAMES.learningAppend,
|
|
476
|
+
description: "Record a durable learning (knowledge that should survive across runs).",
|
|
477
|
+
inputSchema: {
|
|
478
|
+
type: "object",
|
|
479
|
+
additionalProperties: false,
|
|
480
|
+
required: ["title", "body"],
|
|
481
|
+
properties: {
|
|
482
|
+
title: { type: "string", minLength: 1 },
|
|
483
|
+
body: { type: "string" },
|
|
484
|
+
tags: { type: "array", items: { type: "string" } }
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
name: LOOP_TOOL_NAMES.learningQuery,
|
|
490
|
+
description: "Query recorded learnings by tag and/or free text (newest first).",
|
|
491
|
+
inputSchema: {
|
|
492
|
+
type: "object",
|
|
493
|
+
additionalProperties: false,
|
|
494
|
+
properties: {
|
|
495
|
+
tag: { type: "string" },
|
|
496
|
+
text: { type: "string", description: "Case-insensitive substring over title + body." },
|
|
497
|
+
limit: { type: "number", minimum: 1 }
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: LOOP_TOOL_NAMES.followupAppend,
|
|
503
|
+
description: "Record an open follow-up (deferred work to revisit later).",
|
|
504
|
+
inputSchema: {
|
|
505
|
+
type: "object",
|
|
506
|
+
additionalProperties: false,
|
|
507
|
+
required: ["title"],
|
|
508
|
+
properties: {
|
|
509
|
+
title: { type: "string", minLength: 1 },
|
|
510
|
+
body: { type: "string" },
|
|
511
|
+
tags: { type: "array", items: { type: "string" } }
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
name: LOOP_TOOL_NAMES.followupList,
|
|
517
|
+
description: "List follow-ups by status and/or tag (newest first).",
|
|
518
|
+
inputSchema: {
|
|
519
|
+
type: "object",
|
|
520
|
+
additionalProperties: false,
|
|
521
|
+
properties: {
|
|
522
|
+
status: { type: "string", enum: FOLLOWUP_STATUS_ENUM },
|
|
523
|
+
tag: { type: "string" },
|
|
524
|
+
limit: { type: "number", minimum: 1 }
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
];
|
|
529
|
+
var INVALID_ARGS = "INVALID_ARGS";
|
|
530
|
+
function requireString(args, key) {
|
|
531
|
+
const value = args?.[key];
|
|
532
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
533
|
+
throw new BaronError2(`Missing or empty required string argument '${key}'.`, INVALID_ARGS);
|
|
534
|
+
}
|
|
535
|
+
return value;
|
|
536
|
+
}
|
|
537
|
+
function optionalString(args, key) {
|
|
538
|
+
const value = args?.[key];
|
|
539
|
+
if (value === void 0) return void 0;
|
|
540
|
+
if (typeof value !== "string") {
|
|
541
|
+
throw new BaronError2(`Argument '${key}' must be a string.`, INVALID_ARGS);
|
|
542
|
+
}
|
|
543
|
+
return value;
|
|
544
|
+
}
|
|
545
|
+
function optionalLabels(args) {
|
|
546
|
+
const value = args?.labels;
|
|
547
|
+
if (value === void 0) return void 0;
|
|
548
|
+
if (!Array.isArray(value) || value.some((label) => typeof label !== "string")) {
|
|
549
|
+
throw new BaronError2("Argument 'labels' must be an array of strings.", INVALID_ARGS);
|
|
550
|
+
}
|
|
551
|
+
return value;
|
|
552
|
+
}
|
|
553
|
+
function requireRole(args) {
|
|
554
|
+
const value = requireString(args, "role");
|
|
555
|
+
if (!isWorkflowRole(value)) {
|
|
556
|
+
throw new BaronError2(
|
|
557
|
+
`Invalid role '${value}'. Expected one of: ${WORKFLOW_ROLES.join(", ")}.`,
|
|
558
|
+
INVALID_ARGS
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
return value;
|
|
562
|
+
}
|
|
563
|
+
function requireLinkType(args) {
|
|
564
|
+
const value = requireString(args, "type");
|
|
565
|
+
if (!isIssueLinkType(value)) {
|
|
566
|
+
throw new BaronError2(
|
|
567
|
+
`Invalid link type '${value}'. Expected one of: ${ISSUE_LINK_TYPES.join(", ")}.`,
|
|
568
|
+
INVALID_ARGS
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
return value;
|
|
572
|
+
}
|
|
573
|
+
function toQuery(args) {
|
|
574
|
+
const roleRaw = optionalString(args, "role");
|
|
575
|
+
if (roleRaw !== void 0 && !isWorkflowRole(roleRaw)) {
|
|
576
|
+
throw new BaronError2(
|
|
577
|
+
`Invalid role '${roleRaw}'. Expected one of: ${WORKFLOW_ROLES.join(", ")}.`,
|
|
578
|
+
INVALID_ARGS
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
const typeRoleRaw = optionalString(args, "typeRole");
|
|
582
|
+
if (typeRoleRaw !== void 0 && !isWorkItemTypeRole(typeRoleRaw)) {
|
|
583
|
+
throw new BaronError2(
|
|
584
|
+
`Invalid typeRole '${typeRoleRaw}'. Expected one of: ${WORK_ITEM_TYPE_ROLES.join(", ")}.`,
|
|
585
|
+
INVALID_ARGS
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
const limit = args?.limit;
|
|
589
|
+
if (limit !== void 0 && (typeof limit !== "number" || !Number.isFinite(limit) || limit < 1)) {
|
|
590
|
+
throw new BaronError2("Argument 'limit' must be a positive number.", INVALID_ARGS);
|
|
591
|
+
}
|
|
592
|
+
return {
|
|
593
|
+
...roleRaw !== void 0 ? { role: roleRaw } : {},
|
|
594
|
+
...typeRoleRaw !== void 0 ? { typeRole: typeRoleRaw } : {},
|
|
595
|
+
limit: limit !== void 0 ? limit : DEFAULT_QUERY_LIMIT
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function toDraft(args) {
|
|
599
|
+
const title = requireString(args, "title");
|
|
600
|
+
const typeRole = requireString(args, "typeRole");
|
|
601
|
+
if (!isWorkItemTypeRole(typeRole)) {
|
|
602
|
+
throw new BaronError2(
|
|
603
|
+
`Invalid typeRole '${typeRole}'. Expected one of: ${WORK_ITEM_TYPE_ROLES.join(", ")}.`,
|
|
604
|
+
INVALID_ARGS
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
const body = optionalString(args, "body");
|
|
608
|
+
const parentId = optionalString(args, "parentId");
|
|
609
|
+
const labels = optionalLabels(args);
|
|
610
|
+
const initialRoleRaw = optionalString(args, "initialRole");
|
|
611
|
+
if (initialRoleRaw !== void 0 && !isWorkflowRole(initialRoleRaw)) {
|
|
612
|
+
throw new BaronError2(
|
|
613
|
+
`Invalid initialRole '${initialRoleRaw}'. Expected one of: ${WORKFLOW_ROLES.join(", ")}.`,
|
|
614
|
+
INVALID_ARGS
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
title,
|
|
619
|
+
typeRole,
|
|
620
|
+
...body !== void 0 ? { body } : {},
|
|
621
|
+
...parentId !== void 0 ? { parentId } : {},
|
|
622
|
+
...labels !== void 0 ? { labels } : {},
|
|
623
|
+
...initialRoleRaw !== void 0 ? { initialRole: initialRoleRaw } : {}
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
async function run(fn) {
|
|
627
|
+
try {
|
|
628
|
+
const result = await fn();
|
|
629
|
+
const text = result === void 0 ? '{"ok":true}' : JSON.stringify(result);
|
|
630
|
+
return { content: [{ type: "text", text }] };
|
|
631
|
+
} catch (error) {
|
|
632
|
+
if (error instanceof BaronError2) {
|
|
633
|
+
return {
|
|
634
|
+
isError: true,
|
|
635
|
+
content: [{ type: "text", text: `${error.code}: ${error.message}` }],
|
|
636
|
+
structuredContent: { code: error.code, message: error.message }
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
640
|
+
return {
|
|
641
|
+
isError: true,
|
|
642
|
+
content: [{ type: "text", text: `INTERNAL: ${message}` }],
|
|
643
|
+
structuredContent: { code: "INTERNAL", message }
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function callTool(port, name, args) {
|
|
648
|
+
switch (name) {
|
|
649
|
+
case MCP_TOOL_NAMES.create:
|
|
650
|
+
return run(() => port.create(toDraft(args)));
|
|
651
|
+
case MCP_TOOL_NAMES.get:
|
|
652
|
+
return run(() => port.get(requireString(args, "id")));
|
|
653
|
+
case MCP_TOOL_NAMES.transition:
|
|
654
|
+
return run(() => port.transition(requireString(args, "id"), requireRole(args)));
|
|
655
|
+
case MCP_TOOL_NAMES.comment:
|
|
656
|
+
return run(() => port.comment(requireString(args, "id"), requireString(args, "body")));
|
|
657
|
+
case MCP_TOOL_NAMES.link:
|
|
658
|
+
return run(
|
|
659
|
+
() => port.link(
|
|
660
|
+
requireString(args, "fromId"),
|
|
661
|
+
requireString(args, "toId"),
|
|
662
|
+
requireLinkType(args)
|
|
663
|
+
)
|
|
664
|
+
);
|
|
665
|
+
case MCP_TOOL_NAMES.query:
|
|
666
|
+
return run(() => port.query(toQuery(args)));
|
|
667
|
+
default:
|
|
668
|
+
return run(() => {
|
|
669
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
function optionalBoolean(args, key) {
|
|
674
|
+
const value = args?.[key];
|
|
675
|
+
if (value === void 0) return void 0;
|
|
676
|
+
if (typeof value !== "boolean") {
|
|
677
|
+
throw new BaronError2(`Argument '${key}' must be a boolean.`, INVALID_ARGS);
|
|
678
|
+
}
|
|
679
|
+
return value;
|
|
680
|
+
}
|
|
681
|
+
function callScmTool(port, name, args) {
|
|
682
|
+
switch (name) {
|
|
683
|
+
case SCM_TOOL_NAMES.branchCreate:
|
|
684
|
+
return run(() => {
|
|
685
|
+
const fromBranch = optionalString(args, "fromBranch");
|
|
686
|
+
return port.createBranch({
|
|
687
|
+
name: requireString(args, "name"),
|
|
688
|
+
...fromBranch !== void 0 ? { fromBranch } : {}
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
case SCM_TOOL_NAMES.prCreate:
|
|
692
|
+
return run(() => {
|
|
693
|
+
const draft = optionalBoolean(args, "draft");
|
|
694
|
+
const body = optionalString(args, "body");
|
|
695
|
+
const targetBranch = optionalString(args, "targetBranch");
|
|
696
|
+
return port.createPullRequest({
|
|
697
|
+
title: requireString(args, "title"),
|
|
698
|
+
sourceBranch: requireString(args, "sourceBranch"),
|
|
699
|
+
...targetBranch !== void 0 ? { targetBranch } : {},
|
|
700
|
+
...body !== void 0 ? { body } : {},
|
|
701
|
+
...draft !== void 0 ? { draft } : {}
|
|
702
|
+
});
|
|
703
|
+
});
|
|
704
|
+
case SCM_TOOL_NAMES.prStatus:
|
|
705
|
+
return run(() => port.prStatus(requireString(args, "pullRequestId")));
|
|
706
|
+
case SCM_TOOL_NAMES.prThread:
|
|
707
|
+
return run(
|
|
708
|
+
() => port.addPullRequestThread(
|
|
709
|
+
requireString(args, "pullRequestId"),
|
|
710
|
+
requireString(args, "body")
|
|
711
|
+
)
|
|
712
|
+
);
|
|
713
|
+
default:
|
|
714
|
+
return run(() => {
|
|
715
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
function optStringArray(args, key) {
|
|
720
|
+
const value = args?.[key];
|
|
721
|
+
if (value === void 0) return void 0;
|
|
722
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
723
|
+
throw new BaronError2(`Argument '${key}' must be an array of strings.`, INVALID_ARGS);
|
|
724
|
+
}
|
|
725
|
+
return value;
|
|
726
|
+
}
|
|
727
|
+
function optNumber(args, key) {
|
|
728
|
+
const value = args?.[key];
|
|
729
|
+
if (value === void 0) return void 0;
|
|
730
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
731
|
+
throw new BaronError2(`Argument '${key}' must be a number.`, INVALID_ARGS);
|
|
732
|
+
}
|
|
733
|
+
return value;
|
|
734
|
+
}
|
|
735
|
+
function optFollowupStatus(args) {
|
|
736
|
+
const value = optionalString(args, "status");
|
|
737
|
+
if (value === void 0) return void 0;
|
|
738
|
+
if (!isFollowupStatus(value)) {
|
|
739
|
+
throw new BaronError2(
|
|
740
|
+
`Invalid status '${value}'. Expected one of: ${FOLLOWUP_STATUSES.join(", ")}.`,
|
|
741
|
+
INVALID_ARGS
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
return value;
|
|
745
|
+
}
|
|
746
|
+
function callLoopTool(loop, name, args) {
|
|
747
|
+
switch (name) {
|
|
748
|
+
case LOOP_TOOL_NAMES.learningAppend:
|
|
749
|
+
return run(() => {
|
|
750
|
+
const tags = optStringArray(args, "tags");
|
|
751
|
+
return loop.learningAppend({
|
|
752
|
+
title: requireString(args, "title"),
|
|
753
|
+
body: requireString(args, "body"),
|
|
754
|
+
...tags !== void 0 ? { tags } : {}
|
|
755
|
+
});
|
|
756
|
+
});
|
|
757
|
+
case LOOP_TOOL_NAMES.learningQuery:
|
|
758
|
+
return run(() => {
|
|
759
|
+
const tag = optionalString(args, "tag");
|
|
760
|
+
const text = optionalString(args, "text");
|
|
761
|
+
const limit = optNumber(args, "limit");
|
|
762
|
+
return loop.learningQuery({
|
|
763
|
+
...tag !== void 0 ? { tag } : {},
|
|
764
|
+
...text !== void 0 ? { text } : {},
|
|
765
|
+
...limit !== void 0 ? { limit } : {}
|
|
766
|
+
});
|
|
767
|
+
});
|
|
768
|
+
case LOOP_TOOL_NAMES.followupAppend:
|
|
769
|
+
return run(() => {
|
|
770
|
+
const body = optionalString(args, "body");
|
|
771
|
+
const tags = optStringArray(args, "tags");
|
|
772
|
+
return loop.followupAppend({
|
|
773
|
+
title: requireString(args, "title"),
|
|
774
|
+
...body !== void 0 ? { body } : {},
|
|
775
|
+
...tags !== void 0 ? { tags } : {}
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
case LOOP_TOOL_NAMES.followupList:
|
|
779
|
+
return run(() => {
|
|
780
|
+
const status = optFollowupStatus(args);
|
|
781
|
+
const tag = optionalString(args, "tag");
|
|
782
|
+
const limit = optNumber(args, "limit");
|
|
783
|
+
return loop.followupList({
|
|
784
|
+
...status !== void 0 ? { status } : {},
|
|
785
|
+
...tag !== void 0 ? { tag } : {},
|
|
786
|
+
...limit !== void 0 ? { limit } : {}
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
default:
|
|
790
|
+
return run(() => {
|
|
791
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
function toRunQuery(args) {
|
|
796
|
+
const pipelineId = optionalString(args, "pipelineId");
|
|
797
|
+
const branch = optionalString(args, "branch");
|
|
798
|
+
const statusRaw = optionalString(args, "status");
|
|
799
|
+
if (statusRaw !== void 0 && !isRunStatus(statusRaw)) {
|
|
800
|
+
throw new BaronError2(
|
|
801
|
+
`Invalid status '${statusRaw}'. Expected one of: ${RUN_STATUSES.join(", ")}.`,
|
|
802
|
+
INVALID_ARGS
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
const limit = args?.limit;
|
|
806
|
+
if (limit !== void 0 && (typeof limit !== "number" || !Number.isFinite(limit) || limit < 1)) {
|
|
807
|
+
throw new BaronError2("Argument 'limit' must be a positive number.", INVALID_ARGS);
|
|
808
|
+
}
|
|
809
|
+
return {
|
|
810
|
+
...pipelineId !== void 0 ? { pipelineId } : {},
|
|
811
|
+
...branch !== void 0 ? { branch } : {},
|
|
812
|
+
...statusRaw !== void 0 ? { status: statusRaw } : {},
|
|
813
|
+
limit: limit !== void 0 ? limit : DEFAULT_QUERY_LIMIT
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function optionalStringRecord(args, key) {
|
|
817
|
+
const value = args?.[key];
|
|
818
|
+
if (value === void 0) return void 0;
|
|
819
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
820
|
+
throw new BaronError2(`Argument '${key}' must be an object of string values.`, INVALID_ARGS);
|
|
821
|
+
}
|
|
822
|
+
const out = {};
|
|
823
|
+
for (const [k, v] of Object.entries(value)) {
|
|
824
|
+
if (typeof v !== "string") {
|
|
825
|
+
throw new BaronError2(`Argument '${key}.${k}' must be a string.`, INVALID_ARGS);
|
|
826
|
+
}
|
|
827
|
+
out[k] = v;
|
|
828
|
+
}
|
|
829
|
+
return out;
|
|
830
|
+
}
|
|
831
|
+
function callCiTool(port, name, args) {
|
|
832
|
+
switch (name) {
|
|
833
|
+
case CI_TOOL_NAMES.pipelines:
|
|
834
|
+
return run(() => {
|
|
835
|
+
const limit = optNumber(args, "limit");
|
|
836
|
+
return port.pipelines(limit !== void 0 ? { limit } : {});
|
|
837
|
+
});
|
|
838
|
+
case CI_TOOL_NAMES.runs:
|
|
839
|
+
return run(() => port.runs(toRunQuery(args)));
|
|
840
|
+
case CI_TOOL_NAMES.runGet:
|
|
841
|
+
return run(() => port.run(requireString(args, "id")));
|
|
842
|
+
case CI_TOOL_NAMES.runLogs:
|
|
843
|
+
return run(() => {
|
|
844
|
+
const tailLines = optNumber(args, "tailLines");
|
|
845
|
+
return port.logs(
|
|
846
|
+
requireString(args, "runId"),
|
|
847
|
+
tailLines !== void 0 ? { tailLines } : {}
|
|
848
|
+
);
|
|
849
|
+
});
|
|
850
|
+
case CI_TOOL_NAMES.runTrigger:
|
|
851
|
+
return run(() => {
|
|
852
|
+
const ref = optionalString(args, "ref");
|
|
853
|
+
const variables = optionalStringRecord(args, "variables");
|
|
854
|
+
return port.trigger({
|
|
855
|
+
pipelineId: requireString(args, "pipelineId"),
|
|
856
|
+
...ref !== void 0 ? { ref } : {},
|
|
857
|
+
...variables !== void 0 ? { variables } : {}
|
|
858
|
+
});
|
|
859
|
+
});
|
|
860
|
+
case CI_TOOL_NAMES.runCancel:
|
|
861
|
+
return run(() => port.cancel(requireString(args, "runId")));
|
|
862
|
+
default:
|
|
863
|
+
return run(() => {
|
|
864
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
function callNotifyTool(port, name, args) {
|
|
869
|
+
switch (name) {
|
|
870
|
+
case NOTIFY_TOOL_NAMES.send:
|
|
871
|
+
return run(() => {
|
|
872
|
+
const channel = optionalString(args, "channel");
|
|
873
|
+
const threadKey = optionalString(args, "threadKey");
|
|
874
|
+
return port.send({
|
|
875
|
+
text: requireString(args, "text"),
|
|
876
|
+
...channel !== void 0 ? { channel } : {},
|
|
877
|
+
...threadKey !== void 0 ? { threadKey } : {}
|
|
878
|
+
});
|
|
879
|
+
});
|
|
880
|
+
default:
|
|
881
|
+
return run(() => {
|
|
882
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
function callDeployTool(port, name, args) {
|
|
887
|
+
switch (name) {
|
|
888
|
+
case DEPLOY_TOOL_NAMES.environments:
|
|
889
|
+
return run(() => {
|
|
890
|
+
const limit = optNumber(args, "limit");
|
|
891
|
+
return port.environments(limit !== void 0 ? { limit } : {});
|
|
892
|
+
});
|
|
893
|
+
case DEPLOY_TOOL_NAMES.deployments:
|
|
894
|
+
return run(() => {
|
|
895
|
+
const environment = optionalString(args, "environment");
|
|
896
|
+
const limit = optNumber(args, "limit");
|
|
897
|
+
return port.deployments({
|
|
898
|
+
...environment !== void 0 ? { environment } : {},
|
|
899
|
+
...limit !== void 0 ? { limit } : {}
|
|
900
|
+
});
|
|
901
|
+
});
|
|
902
|
+
default:
|
|
903
|
+
return run(() => {
|
|
904
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
function callRecipeTool(service, name, args) {
|
|
909
|
+
switch (name) {
|
|
910
|
+
case RECIPE_TOOL_NAMES.list:
|
|
911
|
+
return run(async () => service.list());
|
|
912
|
+
case RECIPE_TOOL_NAMES.run:
|
|
913
|
+
return run(() => {
|
|
914
|
+
const inputs = args?.inputs;
|
|
915
|
+
if (inputs !== void 0 && (typeof inputs !== "object" || inputs === null || Array.isArray(inputs))) {
|
|
916
|
+
throw new BaronError2("Argument 'inputs' must be an object.", INVALID_ARGS);
|
|
917
|
+
}
|
|
918
|
+
return service.run(
|
|
919
|
+
requireString(args, "name"),
|
|
920
|
+
inputs ?? {}
|
|
921
|
+
);
|
|
922
|
+
});
|
|
923
|
+
default:
|
|
924
|
+
return run(() => {
|
|
925
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
function callNativeTool(access, name, args) {
|
|
930
|
+
switch (name) {
|
|
931
|
+
case NATIVE_TOOL_NAMES.request:
|
|
932
|
+
return run(() => {
|
|
933
|
+
const query = optionalStringRecord(args, "query");
|
|
934
|
+
const body = args?.body;
|
|
935
|
+
return access(requireString(args, "provider"), {
|
|
936
|
+
method: requireString(args, "method"),
|
|
937
|
+
path: requireString(args, "path"),
|
|
938
|
+
...query !== void 0 ? { query } : {},
|
|
939
|
+
...body !== void 0 ? { body } : {}
|
|
940
|
+
});
|
|
941
|
+
});
|
|
942
|
+
default:
|
|
943
|
+
return run(() => {
|
|
944
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
function activeToolDefinitions(ports) {
|
|
949
|
+
return [
|
|
950
|
+
...ports.issues ? TOOL_DEFINITIONS : [],
|
|
951
|
+
...ports.scm ? SCM_TOOL_DEFINITIONS : [],
|
|
952
|
+
...ports.ci ? CI_TOOL_DEFINITIONS : [],
|
|
953
|
+
...ports.notify ? NOTIFY_TOOL_DEFINITIONS : [],
|
|
954
|
+
...ports.deploy ? DEPLOY_TOOL_DEFINITIONS : [],
|
|
955
|
+
...ports.recipes ? RECIPE_TOOL_DEFINITIONS : [],
|
|
956
|
+
...ports.nativeAccess ? NATIVE_TOOL_DEFINITIONS : [],
|
|
957
|
+
...ports.knowledge ? LOOP_TOOL_DEFINITIONS : []
|
|
958
|
+
];
|
|
959
|
+
}
|
|
960
|
+
function dispatchTool(ports, name, args) {
|
|
961
|
+
if (name.startsWith("baron_issue_")) {
|
|
962
|
+
if (ports.issues === void 0) {
|
|
963
|
+
return run(() => {
|
|
964
|
+
throw new BaronError2("The issues port is not configured.", "PORT_UNBOUND");
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
return callTool(ports.issues, name, args);
|
|
968
|
+
}
|
|
969
|
+
if (name.startsWith("baron_scm_")) {
|
|
970
|
+
if (ports.scm === void 0) {
|
|
971
|
+
return run(() => {
|
|
972
|
+
throw new BaronError2("The scm port is not configured.", "PORT_UNBOUND");
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
return callScmTool(ports.scm, name, args);
|
|
976
|
+
}
|
|
977
|
+
if (name.startsWith("baron_ci_")) {
|
|
978
|
+
if (ports.ci === void 0) {
|
|
979
|
+
return run(() => {
|
|
980
|
+
throw new BaronError2("The ci port is not configured.", "PORT_UNBOUND");
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
return callCiTool(ports.ci, name, args);
|
|
984
|
+
}
|
|
985
|
+
if (name.startsWith("baron_notify_")) {
|
|
986
|
+
if (ports.notify === void 0) {
|
|
987
|
+
return run(() => {
|
|
988
|
+
throw new BaronError2("The notify port is not configured.", "PORT_UNBOUND");
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
return callNotifyTool(ports.notify, name, args);
|
|
992
|
+
}
|
|
993
|
+
if (name.startsWith("baron_deploy_")) {
|
|
994
|
+
if (ports.deploy === void 0) {
|
|
995
|
+
return run(() => {
|
|
996
|
+
throw new BaronError2("The deploy port is not configured.", "PORT_UNBOUND");
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
return callDeployTool(ports.deploy, name, args);
|
|
1000
|
+
}
|
|
1001
|
+
if (name.startsWith("baron_recipe_")) {
|
|
1002
|
+
if (ports.recipes === void 0) {
|
|
1003
|
+
return run(() => {
|
|
1004
|
+
throw new BaronError2("The recipe runner is not available.", "PORT_UNBOUND");
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
return callRecipeTool(ports.recipes, name, args);
|
|
1008
|
+
}
|
|
1009
|
+
if (name.startsWith("baron_native_")) {
|
|
1010
|
+
if (ports.nativeAccess === void 0) {
|
|
1011
|
+
return run(() => {
|
|
1012
|
+
throw new BaronError2("The provider-native escape hatch is not available.", "PORT_UNBOUND");
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
return callNativeTool(ports.nativeAccess, name, args);
|
|
1016
|
+
}
|
|
1017
|
+
if (name.startsWith("baron_learning_") || name.startsWith("baron_followup_")) {
|
|
1018
|
+
if (ports.knowledge === void 0) {
|
|
1019
|
+
return run(() => {
|
|
1020
|
+
throw new BaronError2("The knowledge loop is not configured.", "PORT_UNBOUND");
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
return callLoopTool(ports.knowledge, name, args);
|
|
1024
|
+
}
|
|
1025
|
+
return run(() => {
|
|
1026
|
+
throw new BaronError2(`Unknown tool '${name}'.`, "UNKNOWN_TOOL");
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// src/server.ts
|
|
1031
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
1032
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
1033
|
+
var SERVER_INFO = { name: "baron", version: "0.0.0" };
|
|
1034
|
+
function createMcpServer(ports) {
|
|
1035
|
+
const server = new Server(SERVER_INFO, { capabilities: { tools: {} } });
|
|
1036
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
1037
|
+
tools: activeToolDefinitions(ports)
|
|
1038
|
+
}));
|
|
1039
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1040
|
+
const result = await dispatchTool(ports, request.params.name, request.params.arguments);
|
|
1041
|
+
return result;
|
|
1042
|
+
});
|
|
1043
|
+
return server;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
export {
|
|
1047
|
+
loadPorts,
|
|
1048
|
+
MCP_TOOL_NAMES,
|
|
1049
|
+
SCM_TOOL_NAMES,
|
|
1050
|
+
CI_TOOL_NAMES,
|
|
1051
|
+
NOTIFY_TOOL_NAMES,
|
|
1052
|
+
DEPLOY_TOOL_NAMES,
|
|
1053
|
+
NATIVE_TOOL_NAMES,
|
|
1054
|
+
RECIPE_TOOL_NAMES,
|
|
1055
|
+
LOOP_TOOL_NAMES,
|
|
1056
|
+
TOOL_DEFINITIONS,
|
|
1057
|
+
SCM_TOOL_DEFINITIONS,
|
|
1058
|
+
CI_TOOL_DEFINITIONS,
|
|
1059
|
+
NOTIFY_TOOL_DEFINITIONS,
|
|
1060
|
+
DEPLOY_TOOL_DEFINITIONS,
|
|
1061
|
+
NATIVE_TOOL_DEFINITIONS,
|
|
1062
|
+
RECIPE_TOOL_DEFINITIONS,
|
|
1063
|
+
LOOP_TOOL_DEFINITIONS,
|
|
1064
|
+
callTool,
|
|
1065
|
+
callScmTool,
|
|
1066
|
+
callLoopTool,
|
|
1067
|
+
callCiTool,
|
|
1068
|
+
callNotifyTool,
|
|
1069
|
+
callDeployTool,
|
|
1070
|
+
callRecipeTool,
|
|
1071
|
+
callNativeTool,
|
|
1072
|
+
activeToolDefinitions,
|
|
1073
|
+
dispatchTool,
|
|
1074
|
+
SERVER_INFO,
|
|
1075
|
+
createMcpServer
|
|
1076
|
+
};
|