@arii/boomtick-mcp 0.6.2 → 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 (93) 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_pull_request.json +16 -3
  6. package/.mcp/schemas/github.get_pr.json +12 -3
  7. package/.mcp/schemas/github.get_pr_commits.json +12 -3
  8. package/.mcp/schemas/github.get_pr_reviews.json +24 -3
  9. package/.mcp/schemas/github.issue_comment.json +19 -3
  10. package/.mcp/schemas/github.issue_view.json +17 -3
  11. package/.mcp/schemas/github.open_replacement_pr.json +16 -3
  12. package/.mcp/schemas/github_checkout_branch.json +16 -3
  13. package/.mcp/schemas/github_comment_triage_summary.json +16 -3
  14. package/.mcp/schemas/github_create_pull_request.json +16 -3
  15. package/.mcp/schemas/github_get_pr.json +12 -3
  16. package/.mcp/schemas/github_get_pr_commits.json +12 -3
  17. package/.mcp/schemas/github_get_pr_reviews.json +24 -3
  18. package/.mcp/schemas/github_issue_comment.json +19 -3
  19. package/.mcp/schemas/github_issue_view.json +17 -3
  20. package/.mcp/schemas/github_open_replacement_pr.json +16 -3
  21. package/.mcp/schemas/jules.cancel_session.json +38 -3
  22. package/.mcp/schemas/jules.create_session.json +52 -3
  23. package/.mcp/schemas/jules.get_messages.json +19 -3
  24. package/.mcp/schemas/jules.get_pr.json +23 -3
  25. package/.mcp/schemas/jules.get_session.json +38 -3
  26. package/.mcp/schemas/jules.list_sessions.json +53 -3
  27. package/.mcp/schemas/jules.send_message.json +31 -3
  28. package/.mcp/schemas/jules.trigger_feedback.json +28 -3
  29. package/.mcp/schemas/jules_cancel_session.json +38 -3
  30. package/.mcp/schemas/jules_create_session.json +52 -3
  31. package/.mcp/schemas/jules_get_messages.json +19 -3
  32. package/.mcp/schemas/jules_get_pr.json +23 -3
  33. package/.mcp/schemas/jules_get_session.json +38 -3
  34. package/.mcp/schemas/jules_list_sessions.json +53 -3
  35. package/.mcp/schemas/jules_send_message.json +31 -3
  36. package/.mcp/schemas/jules_trigger_feedback.json +28 -3
  37. package/.mcp/schemas/repo.check_jules_status.json +93 -3
  38. package/.mcp/schemas/repo.commit_patch.json +23 -3
  39. package/.mcp/schemas/repo.create_branch.json +28 -3
  40. package/.mcp/schemas/repo.create_repair_branch.json +31 -3
  41. package/.mcp/schemas/repo.get_changed_files.json +11 -3
  42. package/.mcp/schemas/repo.get_command_schema.json +29 -3
  43. package/.mcp/schemas/repo.get_package_scripts.json +11 -3
  44. package/.mcp/schemas/repo.get_workflow_runs.json +12 -3
  45. package/.mcp/schemas/repo.logs.json +14 -3
  46. package/.mcp/schemas/repo.multi_exec.json +89 -0
  47. package/.mcp/schemas/repo.read_agent_context.json +117 -5
  48. package/.mcp/schemas/repo.read_ci_logs.json +46 -3
  49. package/.mcp/schemas/repo_check_jules_status.json +93 -3
  50. package/.mcp/schemas/repo_commit_patch.json +23 -3
  51. package/.mcp/schemas/repo_create_branch.json +28 -3
  52. package/.mcp/schemas/repo_create_repair_branch.json +31 -3
  53. package/.mcp/schemas/repo_get_changed_files.json +11 -3
  54. package/.mcp/schemas/repo_get_command_schema.json +29 -3
  55. package/.mcp/schemas/repo_get_package_scripts.json +11 -3
  56. package/.mcp/schemas/repo_get_workflow_runs.json +12 -3
  57. package/.mcp/schemas/repo_logs.json +14 -3
  58. package/.mcp/schemas/repo_multi_exec.json +89 -0
  59. package/.mcp/schemas/repo_read_agent_context.json +117 -5
  60. package/.mcp/schemas/repo_read_ci_logs.json +46 -3
  61. package/CHANGELOG.md +14 -0
  62. package/README.md +7 -5
  63. package/dist/config/dynamic.js +3 -2
  64. package/dist/config/repo.js +5 -5
  65. package/dist/config.test.js +10 -3
  66. package/dist/mcp/definitions.js +49 -36
  67. package/dist/mcp/http.js +15 -0
  68. package/dist/mcp/http.test.js +8 -0
  69. package/dist/mcp/server.js +34 -0
  70. package/dist/mcp/server.test.js +31 -0
  71. package/dist/tools/contract.js +960 -3
  72. package/dist/tools/jules/create-session.js +12 -2
  73. package/dist/tools/jules/create-session.test.js +7 -0
  74. package/dist/tools/repo.multi_exec.js +21 -0
  75. package/dist/tools/repo.multi_exec.test.js +13 -0
  76. package/dist/tools/repo.read_agent_context.js +65 -3
  77. package/dist/tools/repo.read_agent_context.test.js +30 -1
  78. package/package.json +1 -1
  79. package/src/config/dynamic.ts +3 -2
  80. package/src/config/repo.ts +6 -6
  81. package/src/config.test.ts +11 -3
  82. package/src/mcp/definitions.ts +77 -36
  83. package/src/mcp/http.test.ts +10 -0
  84. package/src/mcp/http.ts +20 -0
  85. package/src/mcp/server.test.ts +38 -0
  86. package/src/mcp/server.ts +36 -0
  87. package/src/tools/contract.ts +1089 -16
  88. package/src/tools/jules/create-session.test.ts +9 -0
  89. package/src/tools/jules/create-session.ts +13 -2
  90. package/src/tools/repo.multi_exec.test.ts +15 -0
  91. package/src/tools/repo.multi_exec.ts +23 -0
  92. package/src/tools/repo.read_agent_context.test.ts +35 -1
  93. package/src/tools/repo.read_agent_context.ts +68 -3
package/src/mcp/http.ts CHANGED
@@ -32,6 +32,13 @@ export function createMcpHttpServer(options: HttpServerOptions) {
32
32
 
33
33
  const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
34
34
 
35
+ // Endpoint 0: Health check endpoint for readiness probes / load balancers
36
+ if (url.pathname === "/health" && req.method === "GET") {
37
+ res.writeHead(200, { "Content-Type": "application/json" });
38
+ res.end(JSON.stringify({ status: "ok", transport: "http" }));
39
+ return;
40
+ }
41
+
35
42
  // Endpoint 1: RFC 9728 OAuth Protected Resource Metadata Discovery
36
43
  if (url.pathname === "/.well-known/oauth-protected-resource" && (req.method === "GET" || req.method === "HEAD")) {
37
44
  const metadata = {
@@ -82,11 +89,24 @@ export function createMcpHttpServer(options: HttpServerOptions) {
82
89
 
83
90
  // Endpoint 2: SSE stream setup
84
91
  if (url.pathname === "/sse" && req.method === "GET") {
92
+ res.setHeader("Cache-Control", "no-cache");
93
+ res.setHeader("Content-Type", "text/event-stream");
94
+ res.setHeader("Connection", "keep-alive");
95
+
85
96
  const transport = new SSEServerTransport("/messages", res);
86
97
  transports.set(transport.sessionId, transport);
98
+
99
+ const keepAliveInterval = setInterval(() => {
100
+ if (!res.writableEnded) {
101
+ res.write(": keep-alive\n\n");
102
+ }
103
+ }, 15000);
104
+
87
105
  transport.onclose = () => {
106
+ clearInterval(keepAliveInterval);
88
107
  transports.delete(transport.sessionId);
89
108
  };
109
+
90
110
  await mcpServer.connect(transport);
91
111
  return;
92
112
  }
@@ -207,6 +207,33 @@ describe("BoomtickMCPServer", () => {
207
207
  expect(JSON.parse(result.contents[0].text)).toEqual({ files: ["src/index.ts"] });
208
208
  });
209
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
+
210
237
  it("should handle mcp://ci/latest-run", async () => {
211
238
  const handler = requestHandlers.get("resources/read");
212
239
  vi.spyOn(workflowRunsModule, "getWorkflowRunsHandler").mockResolvedValue({ workflowRuns: [{ id: 1, status: "completed", conclusion: "success" }] } as any);
@@ -241,6 +268,17 @@ describe("BoomtickMCPServer", () => {
241
268
  expect(result.tools).toBeDefined();
242
269
  expect(Array.isArray(result.tools)).toBe(true);
243
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
+ });
244
282
  });
245
283
 
246
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";
@@ -142,6 +143,22 @@ export class BoomtickMCPServer {
142
143
  contents: [{ uri, mimeType: "text/markdown", text: content }],
143
144
  };
144
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
+ }
145
162
  if (
146
163
  uri === "mcp://git/changed-files" ||
147
164
  uri === "repo://changed-files"
@@ -151,6 +168,22 @@ export class BoomtickMCPServer {
151
168
  contents: [{ uri, mimeType: "application/json", text: JSON.stringify(changedFiles, null, 2) }],
152
169
  };
153
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
+ }
154
187
  if (
155
188
  uri === "mcp://ci/latest-run" ||
156
189
  uri === "repo://ci/latest-run" ||
@@ -213,6 +246,9 @@ export class BoomtickMCPServer {
213
246
  case "repo.read.agent.context":
214
247
  case "repo.read_agent_context":
215
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)));
216
252
  case "github.get.pr.diff":
217
253
  case "github.get_pr_diff":
218
254
  return createSuccessResult(await getPrDiffHandler(GetPrDiffInputSchema.parse(normArgs)));