@arii/boomtick-mcp 0.6.1 → 0.7.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.
Files changed (141) hide show
  1. package/.mcp/schemas/boomtick.health.json +22 -3
  2. package/.mcp/schemas/boomtick_health.json +22 -3
  3. package/.mcp/schemas/github.checkout_branch.json +16 -3
  4. package/.mcp/schemas/github.comment_triage_summary.json +16 -3
  5. package/.mcp/schemas/github.create_issue.json +72 -3
  6. package/.mcp/schemas/github.create_pull_request.json +16 -3
  7. package/.mcp/schemas/github.get_merge_conflict_files.json +40 -3
  8. package/.mcp/schemas/github.get_pr.json +12 -3
  9. package/.mcp/schemas/github.get_pr_commits.json +12 -3
  10. package/.mcp/schemas/github.get_pr_diff.json +30 -3
  11. package/.mcp/schemas/github.get_pr_reviews.json +24 -3
  12. package/.mcp/schemas/github.issue_comment.json +19 -3
  13. package/.mcp/schemas/github.issue_update.json +72 -3
  14. package/.mcp/schemas/github.issue_view.json +17 -3
  15. package/.mcp/schemas/github.open_replacement_pr.json +16 -3
  16. package/.mcp/schemas/github.search_open_prs.json +130 -3
  17. package/.mcp/schemas/github_checkout_branch.json +16 -3
  18. package/.mcp/schemas/github_comment_triage_summary.json +16 -3
  19. package/.mcp/schemas/github_create_issue.json +72 -3
  20. package/.mcp/schemas/github_create_pull_request.json +16 -3
  21. package/.mcp/schemas/github_get_merge_conflict_files.json +40 -3
  22. package/.mcp/schemas/github_get_pr.json +12 -3
  23. package/.mcp/schemas/github_get_pr_commits.json +12 -3
  24. package/.mcp/schemas/github_get_pr_diff.json +30 -3
  25. package/.mcp/schemas/github_get_pr_reviews.json +24 -3
  26. package/.mcp/schemas/github_issue_comment.json +19 -3
  27. package/.mcp/schemas/github_issue_update.json +72 -3
  28. package/.mcp/schemas/github_issue_view.json +17 -3
  29. package/.mcp/schemas/github_open_replacement_pr.json +16 -3
  30. package/.mcp/schemas/github_search_open_prs.json +130 -3
  31. package/.mcp/schemas/jules.cancel_session.json +38 -3
  32. package/.mcp/schemas/jules.create_session.json +52 -3
  33. package/.mcp/schemas/jules.get_messages.json +19 -3
  34. package/.mcp/schemas/jules.get_pr.json +23 -3
  35. package/.mcp/schemas/jules.get_session.json +38 -3
  36. package/.mcp/schemas/jules.list_sessions.json +53 -3
  37. package/.mcp/schemas/jules.send_message.json +31 -3
  38. package/.mcp/schemas/jules.trigger_feedback.json +28 -3
  39. package/.mcp/schemas/jules_cancel_session.json +38 -3
  40. package/.mcp/schemas/jules_create_session.json +52 -3
  41. package/.mcp/schemas/jules_get_messages.json +19 -3
  42. package/.mcp/schemas/jules_get_pr.json +23 -3
  43. package/.mcp/schemas/jules_get_session.json +38 -3
  44. package/.mcp/schemas/jules_list_sessions.json +53 -3
  45. package/.mcp/schemas/jules_send_message.json +31 -3
  46. package/.mcp/schemas/jules_trigger_feedback.json +28 -3
  47. package/.mcp/schemas/repo.check_jules_status.json +128 -0
  48. package/.mcp/schemas/repo.commit_patch.json +23 -3
  49. package/.mcp/schemas/repo.create_branch.json +28 -3
  50. package/.mcp/schemas/repo.create_repair_branch.json +31 -3
  51. package/.mcp/schemas/repo.get_changed_files.json +11 -3
  52. package/.mcp/schemas/repo.get_command_schema.json +29 -3
  53. package/.mcp/schemas/repo.get_package_scripts.json +11 -3
  54. package/.mcp/schemas/repo.get_workflow_runs.json +12 -3
  55. package/.mcp/schemas/repo.logs.json +14 -3
  56. package/.mcp/schemas/repo.multi_exec.json +89 -0
  57. package/.mcp/schemas/repo.read_agent_context.json +117 -5
  58. package/.mcp/schemas/repo.read_ci_logs.json +46 -3
  59. package/.mcp/schemas/repo.run_tests.json +31 -3
  60. package/.mcp/schemas/repo_check_jules_status.json +128 -0
  61. package/.mcp/schemas/repo_commit_patch.json +23 -3
  62. package/.mcp/schemas/repo_create_branch.json +28 -3
  63. package/.mcp/schemas/repo_create_repair_branch.json +31 -3
  64. package/.mcp/schemas/repo_get_changed_files.json +11 -3
  65. package/.mcp/schemas/repo_get_command_schema.json +29 -3
  66. package/.mcp/schemas/repo_get_package_scripts.json +11 -3
  67. package/.mcp/schemas/repo_get_workflow_runs.json +12 -3
  68. package/.mcp/schemas/repo_logs.json +14 -3
  69. package/.mcp/schemas/repo_multi_exec.json +89 -0
  70. package/.mcp/schemas/repo_read_agent_context.json +117 -5
  71. package/.mcp/schemas/repo_read_ci_logs.json +46 -3
  72. package/.mcp/schemas/repo_run_tests.json +31 -3
  73. package/CHANGELOG.md +22 -0
  74. package/README.md +29 -6
  75. package/actions/run-project-gate/action.yml +1 -1
  76. package/dist/config/dynamic.js +34 -0
  77. package/dist/config/github.js +16 -0
  78. package/dist/config/repo.js +28 -0
  79. package/dist/config.js +16 -81
  80. package/dist/config.test.js +10 -3
  81. package/dist/http.js +10 -0
  82. package/dist/mcp/definitions.js +76 -41
  83. package/dist/mcp/http.js +32 -9
  84. package/dist/mcp/http.test.js +62 -4
  85. package/dist/mcp/server.js +69 -10
  86. package/dist/mcp/server.test.js +59 -1
  87. package/dist/tools/contract.js +1079 -45
  88. package/dist/tools/github.comment_triage_summary.js +3 -10
  89. package/dist/tools/github.get_merge_conflict_files.js +4 -2
  90. package/dist/tools/github.get_pr_diff.js +3 -11
  91. package/dist/tools/jules/cancel-session.js +2 -9
  92. package/dist/tools/jules/cli.js +31 -0
  93. package/dist/tools/jules/create-session.js +12 -2
  94. package/dist/tools/jules/create-session.test.js +7 -0
  95. package/dist/tools/jules/get-messages.js +2 -9
  96. package/dist/tools/jules/list-sessions.js +4 -35
  97. package/dist/tools/jules/send-message.js +2 -9
  98. package/dist/tools/jules/session.js +26 -0
  99. package/dist/tools/jules/shared.js +2 -50
  100. package/dist/tools/jules/trigger-feedback.js +2 -10
  101. package/dist/tools/repo.check_jules_status.js +148 -0
  102. package/dist/tools/repo.check_jules_status.test.js +47 -0
  103. package/dist/tools/repo.multi_exec.js +21 -0
  104. package/dist/tools/repo.multi_exec.test.js +13 -0
  105. package/dist/tools/repo.read_agent_context.js +65 -3
  106. package/dist/tools/repo.read_agent_context.test.js +30 -1
  107. package/dist/tools/repo.run_tests.js +13 -1
  108. package/package.json +3 -2
  109. package/scripts/sync-contracts.ts +11 -2
  110. package/src/config/dynamic.ts +37 -0
  111. package/src/config/github.ts +16 -0
  112. package/src/config/repo.ts +36 -0
  113. package/src/config.test.ts +11 -3
  114. package/src/config.ts +16 -89
  115. package/src/http.ts +13 -0
  116. package/src/mcp/definitions.ts +110 -41
  117. package/src/mcp/http.test.ts +75 -5
  118. package/src/mcp/http.ts +40 -14
  119. package/src/mcp/server.test.ts +72 -1
  120. package/src/mcp/server.ts +72 -11
  121. package/src/tools/contract.ts +1194 -36
  122. package/src/tools/github.comment_triage_summary.ts +3 -12
  123. package/src/tools/github.get_merge_conflict_files.ts +5 -2
  124. package/src/tools/github.get_pr_diff.ts +3 -13
  125. package/src/tools/jules/cancel-session.ts +2 -11
  126. package/src/tools/jules/cli.ts +42 -0
  127. package/src/tools/jules/create-session.test.ts +9 -0
  128. package/src/tools/jules/create-session.ts +13 -2
  129. package/src/tools/jules/get-messages.ts +2 -11
  130. package/src/tools/jules/list-sessions.ts +5 -39
  131. package/src/tools/jules/send-message.ts +2 -11
  132. package/src/tools/jules/session.ts +28 -0
  133. package/src/tools/jules/shared.ts +2 -63
  134. package/src/tools/jules/trigger-feedback.ts +2 -13
  135. package/src/tools/repo.check_jules_status.test.ts +55 -0
  136. package/src/tools/repo.check_jules_status.ts +176 -0
  137. package/src/tools/repo.multi_exec.test.ts +15 -0
  138. package/src/tools/repo.multi_exec.ts +23 -0
  139. package/src/tools/repo.read_agent_context.test.ts +35 -1
  140. package/src/tools/repo.read_agent_context.ts +68 -3
  141. package/src/tools/repo.run_tests.ts +14 -1
@@ -100,12 +100,16 @@ describe("BoomtickMCPServer", () => {
100
100
  });
101
101
 
102
102
  describe("ListResources", () => {
103
- it("should return resources list", async () => {
103
+ it("should return resources list containing workspace resources", async () => {
104
104
  const handler = requestHandlers.get("resources/list");
105
105
  expect(handler).toBeDefined();
106
106
  const result = await handler!({ method: "resources/list" });
107
107
  expect(result.resources).toBeDefined();
108
108
  expect(Array.isArray(result.resources)).toBe(true);
109
+ const uris = result.resources.map((r: any) => r.uri);
110
+ expect(uris).toContain("mcp://workspace/agent-contract");
111
+ expect(uris).toContain("mcp://git/changed-files");
112
+ expect(uris).toContain("mcp://ci/latest-run");
109
113
  });
110
114
 
111
115
  it("should return resource templates list", async () => {
@@ -188,6 +192,62 @@ describe("BoomtickMCPServer", () => {
188
192
  expect(JSON.parse(result.contents[0].text)).toEqual({ status: "success" });
189
193
  });
190
194
 
195
+ it("should handle mcp://git/changed-files", async () => {
196
+ const handler = requestHandlers.get("resources/read");
197
+ const changedFilesModule = await import("../tools/repo.get_changed_files.js");
198
+ vi.spyOn(changedFilesModule, "getChangedFilesHandler").mockResolvedValue({ files: ["src/index.ts"] } as any);
199
+
200
+ const result = await handler!({
201
+ method: "resources/read",
202
+ params: { uri: "mcp://git/changed-files" },
203
+ });
204
+
205
+ expect(result.contents[0].uri).toBe("mcp://git/changed-files");
206
+ expect(result.contents[0].mimeType).toBe("application/json");
207
+ expect(JSON.parse(result.contents[0].text)).toEqual({ files: ["src/index.ts"] });
208
+ });
209
+
210
+ it("should handle mcp://workspace/project-config", async () => {
211
+ const handler = requestHandlers.get("resources/read");
212
+ vi.mocked(fs.readFile).mockResolvedValue('{"packageName": "boomtick"}');
213
+
214
+ const result = await handler!({
215
+ method: "resources/read",
216
+ params: { uri: "mcp://workspace/project-config" },
217
+ });
218
+
219
+ expect(result.contents[0].uri).toBe("mcp://workspace/project-config");
220
+ expect(result.contents[0].mimeType).toBe("application/json");
221
+ expect(JSON.parse(result.contents[0].text)).toEqual({ packageName: "boomtick" });
222
+ });
223
+
224
+ it("should handle mcp://git/status", async () => {
225
+ const handler = requestHandlers.get("resources/read");
226
+
227
+ const result = await handler!({
228
+ method: "resources/read",
229
+ params: { uri: "mcp://git/status" },
230
+ });
231
+
232
+ expect(result.contents[0].uri).toBe("mcp://git/status");
233
+ expect(result.contents[0].mimeType).toBe("application/json");
234
+ expect(JSON.parse(result.contents[0].text)).toHaveProperty("status");
235
+ });
236
+
237
+ it("should handle mcp://ci/latest-run", async () => {
238
+ const handler = requestHandlers.get("resources/read");
239
+ vi.spyOn(workflowRunsModule, "getWorkflowRunsHandler").mockResolvedValue({ workflowRuns: [{ id: 1, status: "completed", conclusion: "success" }] } as any);
240
+
241
+ const result = await handler!({
242
+ method: "resources/read",
243
+ params: { uri: "mcp://ci/latest-run" },
244
+ });
245
+
246
+ expect(result.contents[0].uri).toBe("mcp://ci/latest-run");
247
+ expect(result.contents[0].mimeType).toBe("application/json");
248
+ expect(JSON.parse(result.contents[0].text)).toEqual({ workflowRuns: [{ id: 1, status: "completed", conclusion: "success" }] });
249
+ });
250
+
191
251
  it("should throw when resource is unknown", async () => {
192
252
  const handler = requestHandlers.get("resources/read");
193
253
 
@@ -208,6 +268,17 @@ describe("BoomtickMCPServer", () => {
208
268
  expect(result.tools).toBeDefined();
209
269
  expect(Array.isArray(result.tools)).toBe(true);
210
270
  });
271
+
272
+ it("should ensure all tools have typed outputSchema and none are empty or untyped DEFAULT_OUTPUT_SCHEMA", async () => {
273
+ const handler = requestHandlers.get("tools/list");
274
+ const result = await handler!({ method: "tools/list" });
275
+ for (const tool of result.tools) {
276
+ expect(tool.outputSchema).toBeDefined();
277
+ expect(tool.outputSchema.type).toBe("object");
278
+ expect(tool.outputSchema.properties).toBeDefined();
279
+ expect(Object.keys(tool.outputSchema.properties).length).toBeGreaterThan(0);
280
+ }
281
+ });
211
282
  });
212
283
 
213
284
  describe("CallTool", () => {
package/src/mcp/server.ts CHANGED
@@ -20,6 +20,7 @@ import { getMergeConflictFilesHandler, GetMergeConflictFilesInputSchema } from "
20
20
  import { checkoutBranchHandler, CheckoutBranchInputSchema } from "../tools/github.checkout_branch.js";
21
21
  import { getChangedFilesHandler, GetChangedFilesInputSchema } from "../tools/repo.get_changed_files.js";
22
22
  import { readAgentContextHandler, ReadAgentContextInputSchema } from "../tools/repo.read_agent_context.js";
23
+ import { multiExecHandler, MultiExecInputSchema } from "../tools/repo.multi_exec.js";
23
24
  import { getCommandSchemaHandler, GetCommandSchemaInputSchema } from "../tools/repo.get_command_schema.js";
24
25
  import { getPackageScriptsHandler, GetPackageScriptsInputSchema } from "../tools/repo.get_package_scripts.js";
25
26
  import { readCiLogsHandler, ReadCiLogsInputSchema } from "../tools/repo.read_ci_logs.js";
@@ -28,6 +29,7 @@ import { getWorkflowRunsHandler, GetWorkflowRunsInputSchema } from "../tools/rep
28
29
  import { createRepairBranchHandler, CreateRepairBranchInputSchema } from "../tools/repo.create_repair_branch.js";
29
30
  import { createBranchHandler, CreateBranchInputSchema } from "../tools/repo.create_branch.js";
30
31
  import { runTestsHandler, RunTestsInputSchema } from "../tools/repo.run_tests.js";
32
+ import { checkJulesStatusHandler, CheckJulesStatusInputSchema } from "../tools/repo.check_jules_status.js";
31
33
  import { commitPatchHandler, CommitPatchInputSchema } from "../tools/repo.commit_patch.js";
32
34
  import { openReplacementPrHandler, OpenReplacementPrInputSchema } from "../tools/github.open_replacement_pr.js";
33
35
  import { commentTriageSummaryHandler, CommentTriageSummaryInputSchema } from "../tools/github.comment_triage_summary.js";
@@ -141,6 +143,22 @@ export class BoomtickMCPServer {
141
143
  contents: [{ uri, mimeType: "text/markdown", text: content }],
142
144
  };
143
145
  }
146
+ if (
147
+ uri === "mcp://workspace/project-config" ||
148
+ uri === "mcp://workspace/project_config" ||
149
+ uri === "repo://project-config"
150
+ ) {
151
+ const configPath = path.join(config.repoPath, "project_config.json");
152
+ let content = "{}";
153
+ try {
154
+ content = await fs.readFile(configPath, "utf-8");
155
+ } catch {
156
+ // Fallback if file doesn't exist
157
+ }
158
+ return {
159
+ contents: [{ uri, mimeType: "application/json", text: content }],
160
+ };
161
+ }
144
162
  if (
145
163
  uri === "mcp://git/changed-files" ||
146
164
  uri === "repo://changed-files"
@@ -150,6 +168,32 @@ export class BoomtickMCPServer {
150
168
  contents: [{ uri, mimeType: "application/json", text: JSON.stringify(changedFiles, null, 2) }],
151
169
  };
152
170
  }
171
+ if (
172
+ uri === "mcp://git/status" ||
173
+ uri === "repo://git-status" ||
174
+ uri === "repo://status"
175
+ ) {
176
+ let statusText = "";
177
+ try {
178
+ const res = spawnSync("git", ["status", "--porcelain"], { cwd: config.repoPath, encoding: "utf-8" });
179
+ statusText = res.stdout || "";
180
+ } catch {
181
+ // Fallback if git fails
182
+ }
183
+ return {
184
+ contents: [{ uri, mimeType: "application/json", text: JSON.stringify({ status: statusText.trim() }, null, 2) }],
185
+ };
186
+ }
187
+ if (
188
+ uri === "mcp://ci/latest-run" ||
189
+ uri === "repo://ci/latest-run" ||
190
+ uri === "repo://ci-latest-run"
191
+ ) {
192
+ const workflowRuns = await getWorkflowRunsHandler(GetWorkflowRunsInputSchema.parse({}));
193
+ return {
194
+ contents: [{ uri, mimeType: "application/json", text: JSON.stringify(workflowRuns, null, 2) }],
195
+ };
196
+ }
153
197
  if (uri === "repo://package-json" || uri === "mcp://workspace/package-json") {
154
198
  const content = await fs.readFile(path.join(config.repoPath, "package.json"), "utf-8");
155
199
  return {
@@ -202,6 +246,9 @@ export class BoomtickMCPServer {
202
246
  case "repo.read.agent.context":
203
247
  case "repo.read_agent_context":
204
248
  return createSuccessResult(await readAgentContextHandler(ReadAgentContextInputSchema.parse(normArgs)));
249
+ case "repo.multi.exec":
250
+ case "repo.multi_exec":
251
+ return createSuccessResult(await multiExecHandler(MultiExecInputSchema.parse(normArgs)));
205
252
  case "github.get.pr.diff":
206
253
  case "github.get_pr_diff":
207
254
  return createSuccessResult(await getPrDiffHandler(GetPrDiffInputSchema.parse(normArgs)));
@@ -234,6 +281,9 @@ export class BoomtickMCPServer {
234
281
  case "repo.create.repair.branch":
235
282
  case "repo.create_repair_branch":
236
283
  return createSuccessResult(await createRepairBranchHandler(CreateRepairBranchInputSchema.parse(normArgs)));
284
+ case "repo.check.jules.status":
285
+ case "repo.check_jules_status":
286
+ return createSuccessResult(await checkJulesStatusHandler(CheckJulesStatusInputSchema.parse(normArgs)));
237
287
  case "repo.run.tests":
238
288
  case "repo.run_tests":
239
289
  return createSuccessResult(await runTestsHandler(RunTestsInputSchema.parse(normArgs)));
@@ -383,24 +433,35 @@ export class BoomtickMCPServer {
383
433
  }
384
434
  }
385
435
 
386
- async startHttp(port = parseInt(process.env.PORT || process.env.HTTP_PORT || "3000", 10), bearerToken?: string) {
387
- this.prepareEnvironmentAndPreflight();
388
- const mcpHttp = createMcpHttpServer({ port, bearerToken, mcpServer: this.server });
389
- return await mcpHttp.listen(port);
390
- }
391
-
392
436
  async run() {
393
437
  this.prepareEnvironmentAndPreflight();
394
438
 
439
+ const args = process.argv.slice(2);
440
+ let port = parseInt(process.env.PORT || process.env.HTTP_PORT || "3000", 10);
441
+ let bearerToken = process.env.BOOMTICK_MCP_BEARER_TOKEN || process.env.MCP_BEARER_TOKEN || process.env.AUTH_TOKEN;
442
+
443
+ for (let i = 0; i < args.length; i++) {
444
+ if (args[i] === "--port" && i + 1 < args.length) {
445
+ port = parseInt(args[i + 1], 10);
446
+ i++;
447
+ } else if (args[i].startsWith("--port=")) {
448
+ port = parseInt(args[i].split("=")[1], 10);
449
+ } else if (args[i] === "--bearer-token" && i + 1 < args.length) {
450
+ bearerToken = args[i + 1];
451
+ i++;
452
+ } else if (args[i].startsWith("--bearer-token=")) {
453
+ bearerToken = args[i].split("=")[1];
454
+ }
455
+ }
456
+
395
457
  const isHttp =
396
458
  process.env.MCP_TRANSPORT === "http" ||
397
- process.argv.includes("--http") ||
398
- (process.env.PORT !== undefined && !process.argv.includes("--stdio")) ||
399
- (process.env.HTTP_PORT !== undefined && !process.argv.includes("--stdio"));
459
+ args.includes("--http") ||
460
+ (process.env.PORT !== undefined && !args.includes("--stdio")) ||
461
+ (process.env.HTTP_PORT !== undefined && !args.includes("--stdio"));
400
462
 
401
463
  if (isHttp) {
402
- const port = parseInt(process.env.PORT || process.env.HTTP_PORT || "3000", 10);
403
- const mcpHttp = createMcpHttpServer({ port, mcpServer: this.server });
464
+ const mcpHttp = createMcpHttpServer({ port, bearerToken, mcpServer: this.server });
404
465
  await mcpHttp.listen(port);
405
466
  return;
406
467
  }