@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.
- package/.mcp/schemas/boomtick.health.json +22 -3
- package/.mcp/schemas/boomtick_health.json +22 -3
- package/.mcp/schemas/github.checkout_branch.json +16 -3
- package/.mcp/schemas/github.comment_triage_summary.json +16 -3
- package/.mcp/schemas/github.create_pull_request.json +16 -3
- package/.mcp/schemas/github.get_pr.json +12 -3
- package/.mcp/schemas/github.get_pr_commits.json +12 -3
- package/.mcp/schemas/github.get_pr_reviews.json +24 -3
- package/.mcp/schemas/github.issue_comment.json +19 -3
- package/.mcp/schemas/github.issue_view.json +17 -3
- package/.mcp/schemas/github.open_replacement_pr.json +16 -3
- package/.mcp/schemas/github_checkout_branch.json +16 -3
- package/.mcp/schemas/github_comment_triage_summary.json +16 -3
- package/.mcp/schemas/github_create_pull_request.json +16 -3
- package/.mcp/schemas/github_get_pr.json +12 -3
- package/.mcp/schemas/github_get_pr_commits.json +12 -3
- package/.mcp/schemas/github_get_pr_reviews.json +24 -3
- package/.mcp/schemas/github_issue_comment.json +19 -3
- package/.mcp/schemas/github_issue_view.json +17 -3
- package/.mcp/schemas/github_open_replacement_pr.json +16 -3
- package/.mcp/schemas/jules.cancel_session.json +38 -3
- package/.mcp/schemas/jules.create_session.json +52 -3
- package/.mcp/schemas/jules.get_messages.json +19 -3
- package/.mcp/schemas/jules.get_pr.json +23 -3
- package/.mcp/schemas/jules.get_session.json +38 -3
- package/.mcp/schemas/jules.list_sessions.json +53 -3
- package/.mcp/schemas/jules.send_message.json +31 -3
- package/.mcp/schemas/jules.trigger_feedback.json +28 -3
- package/.mcp/schemas/jules_cancel_session.json +38 -3
- package/.mcp/schemas/jules_create_session.json +52 -3
- package/.mcp/schemas/jules_get_messages.json +19 -3
- package/.mcp/schemas/jules_get_pr.json +23 -3
- package/.mcp/schemas/jules_get_session.json +38 -3
- package/.mcp/schemas/jules_list_sessions.json +53 -3
- package/.mcp/schemas/jules_send_message.json +31 -3
- package/.mcp/schemas/jules_trigger_feedback.json +28 -3
- package/.mcp/schemas/repo.check_jules_status.json +93 -3
- package/.mcp/schemas/repo.commit_patch.json +23 -3
- package/.mcp/schemas/repo.create_branch.json +28 -3
- package/.mcp/schemas/repo.create_repair_branch.json +31 -3
- package/.mcp/schemas/repo.get_changed_files.json +11 -3
- package/.mcp/schemas/repo.get_command_schema.json +29 -3
- package/.mcp/schemas/repo.get_package_scripts.json +11 -3
- package/.mcp/schemas/repo.get_workflow_runs.json +12 -3
- package/.mcp/schemas/repo.logs.json +14 -3
- package/.mcp/schemas/repo.multi_exec.json +89 -0
- package/.mcp/schemas/repo.read_agent_context.json +117 -5
- package/.mcp/schemas/repo.read_ci_logs.json +46 -3
- package/.mcp/schemas/repo_check_jules_status.json +93 -3
- package/.mcp/schemas/repo_commit_patch.json +23 -3
- package/.mcp/schemas/repo_create_branch.json +28 -3
- package/.mcp/schemas/repo_create_repair_branch.json +31 -3
- package/.mcp/schemas/repo_get_changed_files.json +11 -3
- package/.mcp/schemas/repo_get_command_schema.json +29 -3
- package/.mcp/schemas/repo_get_package_scripts.json +11 -3
- package/.mcp/schemas/repo_get_workflow_runs.json +12 -3
- package/.mcp/schemas/repo_logs.json +14 -3
- package/.mcp/schemas/repo_multi_exec.json +89 -0
- package/.mcp/schemas/repo_read_agent_context.json +117 -5
- package/.mcp/schemas/repo_read_ci_logs.json +46 -3
- package/CHANGELOG.md +14 -0
- package/README.md +7 -5
- package/dist/config/dynamic.js +3 -2
- package/dist/config/repo.js +5 -5
- package/dist/config.test.js +10 -3
- package/dist/mcp/definitions.js +49 -36
- package/dist/mcp/http.js +15 -0
- package/dist/mcp/http.test.js +8 -0
- package/dist/mcp/server.js +34 -0
- package/dist/mcp/server.test.js +31 -0
- package/dist/tools/contract.js +960 -3
- package/dist/tools/jules/create-session.js +12 -2
- package/dist/tools/jules/create-session.test.js +7 -0
- package/dist/tools/repo.multi_exec.js +21 -0
- package/dist/tools/repo.multi_exec.test.js +13 -0
- package/dist/tools/repo.read_agent_context.js +65 -3
- package/dist/tools/repo.read_agent_context.test.js +30 -1
- package/package.json +1 -1
- package/src/config/dynamic.ts +3 -2
- package/src/config/repo.ts +6 -6
- package/src/config.test.ts +11 -3
- package/src/mcp/definitions.ts +77 -36
- package/src/mcp/http.test.ts +10 -0
- package/src/mcp/http.ts +20 -0
- package/src/mcp/server.test.ts +38 -0
- package/src/mcp/server.ts +36 -0
- package/src/tools/contract.ts +1089 -16
- package/src/tools/jules/create-session.test.ts +9 -0
- package/src/tools/jules/create-session.ts +13 -2
- package/src/tools/repo.multi_exec.test.ts +15 -0
- package/src/tools/repo.multi_exec.ts +23 -0
- package/src/tools/repo.read_agent_context.test.ts +35 -1
- package/src/tools/repo.read_agent_context.ts +68 -3
|
@@ -4,16 +4,26 @@ export const CreateJulesSessionInputSchema = z.object({
|
|
|
4
4
|
task: z.string(),
|
|
5
5
|
branch: z.string().optional(),
|
|
6
6
|
pr: z.number().optional(),
|
|
7
|
+
repo: z.string().optional(),
|
|
7
8
|
});
|
|
8
9
|
export async function createJulesSessionHandler(input) {
|
|
9
10
|
let branch = input.branch;
|
|
10
11
|
if (!branch && input.pr) {
|
|
11
|
-
const
|
|
12
|
+
const ghArgs = ["gh", "view", input.pr.toString()];
|
|
13
|
+
if (input.repo) {
|
|
14
|
+
ghArgs.push("--repo", input.repo);
|
|
15
|
+
}
|
|
16
|
+
const prData = await runTDCli(ghArgs);
|
|
12
17
|
branch = prData.pr.headRefName;
|
|
13
18
|
}
|
|
14
19
|
if (!branch) {
|
|
15
20
|
branch = process.env.DEFAULT_BASE_BRANCH || "main";
|
|
16
21
|
}
|
|
17
|
-
const
|
|
22
|
+
const dispatchArgs = ["agent", "dispatch"];
|
|
23
|
+
if (input.repo) {
|
|
24
|
+
dispatchArgs.push("--repo", input.repo);
|
|
25
|
+
}
|
|
26
|
+
dispatchArgs.push(branch, input.task);
|
|
27
|
+
const output = await runTDCli(dispatchArgs);
|
|
18
28
|
return parseJulesSession(output.session || output);
|
|
19
29
|
}
|
|
@@ -41,6 +41,13 @@ describe("createJulesSessionHandler", () => {
|
|
|
41
41
|
"agent", "dispatch", "feature-x", "do work"
|
|
42
42
|
]);
|
|
43
43
|
});
|
|
44
|
+
it("should create a session with repo parameter", async () => {
|
|
45
|
+
const result = await createJulesSessionHandler({ task: "do work", branch: "main", repo: "arii/portfolio" });
|
|
46
|
+
expect(result.id).toBe("1234567890");
|
|
47
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
48
|
+
"agent", "dispatch", "--repo", "arii/portfolio", "main", "do work"
|
|
49
|
+
]);
|
|
50
|
+
});
|
|
44
51
|
it("should create a session with PR number", async () => {
|
|
45
52
|
vi.mocked(shell.runCommand).mockImplementation(async (cmd, args) => {
|
|
46
53
|
if (args[1] === "view") {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { runTDCli } from "./jules/shared.js";
|
|
3
|
+
export const MultiExecInputSchema = z.object({
|
|
4
|
+
command: z.string().describe("Shell command to execute sequentially across repositories"),
|
|
5
|
+
repos: z.array(z.string()).optional().describe("Optional list of repository names to target"),
|
|
6
|
+
continueOnError: z.boolean().optional().default(true).describe("Whether to continue execution if a repo command fails"),
|
|
7
|
+
});
|
|
8
|
+
export async function multiExecHandler(input) {
|
|
9
|
+
const args = MultiExecInputSchema.parse(input);
|
|
10
|
+
const cliArgs = ["multi-repo", "exec", args.command];
|
|
11
|
+
if (args.repos) {
|
|
12
|
+
for (const r of args.repos) {
|
|
13
|
+
cliArgs.push("-r", r);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (args.continueOnError === false) {
|
|
17
|
+
cliArgs.push("--fail-fast");
|
|
18
|
+
}
|
|
19
|
+
const output = await runTDCli(cliArgs, "execute command across ecosystem repositories");
|
|
20
|
+
return output;
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { multiExecHandler } from "./repo.multi_exec.js";
|
|
3
|
+
describe("MultiExec Tool", () => {
|
|
4
|
+
it("should execute a command sequentially across repositories", async () => {
|
|
5
|
+
const res = await multiExecHandler({
|
|
6
|
+
command: "echo test-vitest-exec",
|
|
7
|
+
repos: ["arii/boomtick"],
|
|
8
|
+
});
|
|
9
|
+
expect(res.status).toBe("success");
|
|
10
|
+
expect(res.total_repos).toBe(1);
|
|
11
|
+
expect(res.results[0].stdout).toContain("test-vitest-exec");
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -3,6 +3,7 @@ import { config } from "../config.js";
|
|
|
3
3
|
import { execSync } from "child_process";
|
|
4
4
|
import * as fs from "fs";
|
|
5
5
|
import * as path from "path";
|
|
6
|
+
import { runTDCli } from "./jules/shared.js";
|
|
6
7
|
export const loadStandaloneAgentContext = (repoRoot = process.cwd()) => {
|
|
7
8
|
const configPath = path.join(repoRoot, "project_config.json");
|
|
8
9
|
let projectConfig = {};
|
|
@@ -27,13 +28,74 @@ export const loadStandaloneAgentContext = (repoRoot = process.cwd()) => {
|
|
|
27
28
|
config: projectConfig,
|
|
28
29
|
};
|
|
29
30
|
};
|
|
30
|
-
export const ReadAgentContextInputSchema = z.object({
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
export const ReadAgentContextInputSchema = z.object({
|
|
32
|
+
path: z.string().optional().describe("Local filesystem path to target repository root"),
|
|
33
|
+
repoPath: z.string().optional().describe("Alias for path to target repository root"),
|
|
34
|
+
repo: z.string().optional().describe("Repository name override (e.g. arii/portfolio or portfolio)"),
|
|
35
|
+
repos: z.array(z.string()).optional().describe("List of repository names to fetch context for"),
|
|
36
|
+
all: z.boolean().optional().describe("Whether to fetch context across all discovered ecosystem repositories"),
|
|
37
|
+
});
|
|
38
|
+
export async function readAgentContextHandler(args) {
|
|
39
|
+
// 1. Ecosystem / Multi-repo request
|
|
40
|
+
if (args.all || (args.repos && args.repos.length > 0)) {
|
|
41
|
+
const cliArgs = ["multi-repo", "status"];
|
|
42
|
+
if (args.repos) {
|
|
43
|
+
for (const r of args.repos) {
|
|
44
|
+
cliArgs.push("-r", r);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const output = await runTDCli(cliArgs, "fetch multi-repo context");
|
|
48
|
+
return {
|
|
49
|
+
status: "success",
|
|
50
|
+
ecosystem: true,
|
|
51
|
+
repos: output.repos ?? [],
|
|
52
|
+
total: output.total ?? (output.repos?.length ?? 0)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// 2. Specific repository name override
|
|
56
|
+
if (args.repo) {
|
|
57
|
+
let matchedPath;
|
|
58
|
+
try {
|
|
59
|
+
const output = await runTDCli(["multi-repo", "status", "-r", args.repo], "find target repository");
|
|
60
|
+
const matched = output.repos?.[0];
|
|
61
|
+
if (matched?.path) {
|
|
62
|
+
matchedPath = matched.path;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Fallback to directory inspection if CLI is unavailable or not in TD workspace
|
|
67
|
+
}
|
|
68
|
+
if (!matchedPath) {
|
|
69
|
+
const repoName = args.repo.includes("/") ? args.repo.split("/")[1] : args.repo;
|
|
70
|
+
const cwdParent = path.resolve(process.cwd(), "..", repoName);
|
|
71
|
+
const configParent = path.resolve(config.repoPath, "..", repoName);
|
|
72
|
+
if (fs.existsSync(cwdParent)) {
|
|
73
|
+
matchedPath = cwdParent;
|
|
74
|
+
}
|
|
75
|
+
else if (fs.existsSync(configParent)) {
|
|
76
|
+
matchedPath = configParent;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (matchedPath) {
|
|
80
|
+
const context = loadStandaloneAgentContext(matchedPath);
|
|
81
|
+
return {
|
|
82
|
+
status: "success",
|
|
83
|
+
repo: args.repo,
|
|
84
|
+
path: matchedPath,
|
|
85
|
+
...context
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// 3. Specific filesystem path
|
|
90
|
+
const targetPath = (args.path || args.repoPath) ? path.resolve(args.path || args.repoPath) : config.repoPath;
|
|
91
|
+
const context = loadStandaloneAgentContext(targetPath);
|
|
33
92
|
const result = {
|
|
34
93
|
status: "success",
|
|
35
94
|
...context
|
|
36
95
|
};
|
|
96
|
+
if (args?.repo) {
|
|
97
|
+
result.repo = args.repo;
|
|
98
|
+
}
|
|
37
99
|
delete result.submodules;
|
|
38
100
|
if (result.config) {
|
|
39
101
|
delete result.config.submodules;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { loadStandaloneAgentContext } from "./repo.read_agent_context.js";
|
|
2
|
+
import { loadStandaloneAgentContext, readAgentContextHandler } from "./repo.read_agent_context.js";
|
|
3
3
|
describe("Standalone Agent Context Loader", () => {
|
|
4
4
|
it("should load agent context without submodule references", () => {
|
|
5
5
|
const context = loadStandaloneAgentContext(process.cwd());
|
|
@@ -7,4 +7,33 @@ describe("Standalone Agent Context Loader", () => {
|
|
|
7
7
|
expect(context).toHaveProperty("gitCommit");
|
|
8
8
|
expect(context).not.toHaveProperty("submodules");
|
|
9
9
|
});
|
|
10
|
+
it("should handle readAgentContextHandler with default workspace", async () => {
|
|
11
|
+
const res = await readAgentContextHandler({});
|
|
12
|
+
expect(res.status).toBe("success");
|
|
13
|
+
expect(res).toHaveProperty("packageName");
|
|
14
|
+
expect(res).toHaveProperty("gitCommit");
|
|
15
|
+
});
|
|
16
|
+
it("readAgentContextHandler should accept optional repoPath argument", async () => {
|
|
17
|
+
const res = await readAgentContextHandler({ repoPath: process.cwd() });
|
|
18
|
+
expect(res).toHaveProperty("status", "success");
|
|
19
|
+
expect(res).toHaveProperty("packageName");
|
|
20
|
+
expect(res).toHaveProperty("gitCommit");
|
|
21
|
+
});
|
|
22
|
+
it("readAgentContextHandler should accept path argument", async () => {
|
|
23
|
+
const res = await readAgentContextHandler({ path: process.cwd() });
|
|
24
|
+
expect(res).toHaveProperty("status", "success");
|
|
25
|
+
expect(res).toHaveProperty("packageName");
|
|
26
|
+
});
|
|
27
|
+
it("readAgentContextHandler should accept repo argument", async () => {
|
|
28
|
+
const res = await readAgentContextHandler({ repo: "arii/tech-dancer" });
|
|
29
|
+
expect(res).toHaveProperty("status", "success");
|
|
30
|
+
expect(res).toHaveProperty("repo", "arii/tech-dancer");
|
|
31
|
+
});
|
|
32
|
+
it("should handle multi-repo context querying when all: true is passed", async () => {
|
|
33
|
+
const res = await readAgentContextHandler({ all: true });
|
|
34
|
+
expect(res.status).toBe("success");
|
|
35
|
+
expect(res.ecosystem).toBe(true);
|
|
36
|
+
expect(Array.isArray(res.repos)).toBe(true);
|
|
37
|
+
expect(res.repos.length).toBeGreaterThan(0);
|
|
38
|
+
});
|
|
10
39
|
});
|
package/package.json
CHANGED
package/src/config/dynamic.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { execSync } from "child_process";
|
|
2
|
+
import { findRepoRoot } from "./repo.js";
|
|
2
3
|
|
|
3
4
|
let cachedDynamicConfig: any = null;
|
|
4
5
|
|
|
5
|
-
export function initializeConfig() {
|
|
6
|
+
export function initializeConfig(targetCwd?: string) {
|
|
6
7
|
if (cachedDynamicConfig !== null) {
|
|
7
8
|
return cachedDynamicConfig;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
try {
|
|
11
|
-
const cwd =
|
|
12
|
+
const cwd = findRepoRoot(targetCwd);
|
|
12
13
|
const cmd = `td config view`;
|
|
13
14
|
const output = execSync(cmd, {
|
|
14
15
|
cwd,
|
package/src/config/repo.ts
CHANGED
|
@@ -4,12 +4,8 @@ import { fileURLToPath } from "url";
|
|
|
4
4
|
|
|
5
5
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
6
|
|
|
7
|
-
export function findRepoRoot(): string {
|
|
8
|
-
|
|
9
|
-
return process.env.BOOMTICK_REPO_PATH;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
let current = process.cwd();
|
|
7
|
+
export function findRepoRoot(startDir?: string): string {
|
|
8
|
+
let current = startDir || process.cwd();
|
|
13
9
|
while (current !== path.parse(current).root) {
|
|
14
10
|
if (
|
|
15
11
|
fs.existsSync(path.join(current, "project_config.json")) ||
|
|
@@ -21,6 +17,10 @@ export function findRepoRoot(): string {
|
|
|
21
17
|
current = path.dirname(current);
|
|
22
18
|
}
|
|
23
19
|
|
|
20
|
+
if (process.env.BOOMTICK_REPO_PATH) {
|
|
21
|
+
return process.env.BOOMTICK_REPO_PATH;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
24
|
current = __dirname;
|
|
25
25
|
while (current !== path.parse(current).root) {
|
|
26
26
|
if (
|
package/src/config.test.ts
CHANGED
|
@@ -25,10 +25,11 @@ describe("config", () => {
|
|
|
25
25
|
vi.mocked(execSync).mockReturnValue(JSON.stringify(mockConfig));
|
|
26
26
|
|
|
27
27
|
const { initializeConfig } = await import("./config.js");
|
|
28
|
+
const { findRepoRoot } = await import("./config/repo.js");
|
|
28
29
|
const result = initializeConfig();
|
|
29
30
|
|
|
30
31
|
expect(execSync).toHaveBeenCalledWith("td config view", expect.objectContaining({
|
|
31
|
-
cwd:
|
|
32
|
+
cwd: findRepoRoot()
|
|
32
33
|
}));
|
|
33
34
|
expect(result).toEqual(mockConfig);
|
|
34
35
|
});
|
|
@@ -133,10 +134,17 @@ describe("config", () => {
|
|
|
133
134
|
expect(() => config.githubRepo).toThrow("GITHUB_REPO must be set via environment variable or project_config.json");
|
|
134
135
|
});
|
|
135
136
|
|
|
136
|
-
it("should resolve
|
|
137
|
+
it("should resolve active workspace from process.cwd() over BOOMTICK_REPO_PATH when inside a repo", async () => {
|
|
137
138
|
process.env.BOOMTICK_REPO_PATH = "/custom/repo/path";
|
|
138
139
|
const { config } = await import("./config.js");
|
|
139
|
-
expect(config.repoPath).toBe("
|
|
140
|
+
expect(config.repoPath).toBe(process.cwd().replace(/\/mcp$/, ""));
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should fallback to BOOMTICK_REPO_PATH when process.cwd() is outside any repo", async () => {
|
|
144
|
+
process.env.BOOMTICK_REPO_PATH = "/custom/repo/path";
|
|
145
|
+
const { findRepoRoot } = await import("./config/repo.js");
|
|
146
|
+
const rootDir = process.platform === "win32" ? "C:\\" : "/";
|
|
147
|
+
expect(findRepoRoot(rootDir)).toBe("/custom/repo/path");
|
|
140
148
|
});
|
|
141
149
|
|
|
142
150
|
it("should resolve defaultBaseBranch, viteBasePath, and ghPath", async () => {
|
package/src/mcp/definitions.ts
CHANGED
|
@@ -1,41 +1,70 @@
|
|
|
1
1
|
import { Tool, Prompt, Resource, ResourceTemplate } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import {
|
|
3
3
|
HealthCheckInputJsonSchema,
|
|
4
|
+
HealthCheckResponseJsonSchema,
|
|
4
5
|
SearchPRsInputJsonSchema,
|
|
5
6
|
SearchPRsResponseJsonSchema,
|
|
6
7
|
GetPrDiffInputJsonSchema,
|
|
7
8
|
PrDiffResponseJsonSchema,
|
|
8
9
|
CheckoutBranchInputJsonSchema,
|
|
10
|
+
CheckoutBranchResponseJsonSchema,
|
|
9
11
|
GetMergeConflictFilesInputJsonSchema,
|
|
10
12
|
GetMergeConflictFilesResponseJsonSchema,
|
|
11
13
|
GetChangedFilesInputJsonSchema,
|
|
14
|
+
GetChangedFilesResponseJsonSchema,
|
|
12
15
|
GetPackageScriptsInputJsonSchema,
|
|
16
|
+
GetPackageScriptsResponseJsonSchema,
|
|
13
17
|
ReadCiLogsInputJsonSchema,
|
|
18
|
+
ReadCiLogsResponseJsonSchema,
|
|
14
19
|
RepoLogsInputJsonSchema,
|
|
20
|
+
RepoLogsResponseJsonSchema,
|
|
15
21
|
CreateBranchInputJsonSchema,
|
|
22
|
+
CreateBranchResponseJsonSchema,
|
|
16
23
|
CreateRepairBranchInputJsonSchema,
|
|
24
|
+
CreateRepairBranchResponseJsonSchema,
|
|
25
|
+
CheckJulesStatusResponseJsonSchema,
|
|
17
26
|
RunTestsInputJsonSchema,
|
|
18
27
|
RunTestsResponseJsonSchema,
|
|
19
28
|
CommitPatchInputJsonSchema,
|
|
29
|
+
CommitPatchResponseJsonSchema,
|
|
20
30
|
OpenReplacementPrInputJsonSchema,
|
|
31
|
+
OpenReplacementPrResponseJsonSchema,
|
|
21
32
|
CreatePullRequestInputJsonSchema,
|
|
33
|
+
CreatePullRequestResponseJsonSchema,
|
|
22
34
|
CommentTriageSummaryInputJsonSchema,
|
|
35
|
+
CommentTriageSummaryResponseJsonSchema,
|
|
23
36
|
GetPrInputJsonSchema,
|
|
37
|
+
GetPrResponseJsonSchema,
|
|
24
38
|
IssueViewInputJsonSchema,
|
|
39
|
+
IssueViewResponseJsonSchema,
|
|
25
40
|
IssueUpdateInputJsonSchema,
|
|
26
41
|
IssueUpdateResponseJsonSchema,
|
|
27
42
|
IssueCommentInputJsonSchema,
|
|
43
|
+
IssueCommentResponseJsonSchema,
|
|
28
44
|
CreateIssueInputJsonSchema,
|
|
29
45
|
CreateIssueResponseJsonSchema,
|
|
30
46
|
GetCommandSchemaInputJsonSchema,
|
|
47
|
+
GetCommandSchemaResponseJsonSchema,
|
|
31
48
|
ReadAgentContextInputJsonSchema as ReadAgentContextSchema,
|
|
49
|
+
ReadAgentContextResponseJsonSchema,
|
|
50
|
+
MultiExecInputJsonSchema,
|
|
51
|
+
MultiExecResponseJsonSchema,
|
|
32
52
|
CreateJulesSessionInputJsonSchema,
|
|
33
53
|
JulesSessionIdInputJsonSchema,
|
|
34
54
|
JulesSendMessageInputJsonSchema,
|
|
55
|
+
JulesSendMessageResponseJsonSchema,
|
|
56
|
+
JulesGetMessagesResponseJsonSchema,
|
|
35
57
|
JulesListSessionsInputJsonSchema,
|
|
58
|
+
JulesListSessionsResponseJsonSchema,
|
|
59
|
+
JulesSessionResponseJsonSchema,
|
|
60
|
+
JulesGetPrResponseJsonSchema,
|
|
61
|
+
JulesTriggerFeedbackResponseJsonSchema,
|
|
36
62
|
GetPrReviewsInputJsonSchema,
|
|
63
|
+
GetPrReviewsResponseJsonSchema,
|
|
37
64
|
GetPrCommitsInputJsonSchema,
|
|
65
|
+
GetPrCommitsResponseJsonSchema,
|
|
38
66
|
GetWorkflowRunsInputJsonSchema,
|
|
67
|
+
GetWorkflowRunsResponseJsonSchema,
|
|
39
68
|
} from "../tools/contract.js";
|
|
40
69
|
|
|
41
70
|
export const MCP_PROMPTS: Prompt[] = [
|
|
@@ -78,12 +107,24 @@ export const MCP_RESOURCES: Resource[] = [
|
|
|
78
107
|
mimeType: "text/markdown",
|
|
79
108
|
description: "The agent contract specification file (.agents/AGENT_CONTRACT.md).",
|
|
80
109
|
},
|
|
110
|
+
{
|
|
111
|
+
uri: "mcp://workspace/project-config",
|
|
112
|
+
name: "Project Configuration",
|
|
113
|
+
mimeType: "application/json",
|
|
114
|
+
description: "The project configuration (project_config.json).",
|
|
115
|
+
},
|
|
81
116
|
{
|
|
82
117
|
uri: "mcp://git/changed-files",
|
|
83
118
|
name: "Git Changed Files",
|
|
84
119
|
mimeType: "application/json",
|
|
85
120
|
description: "List of changed files in the repository.",
|
|
86
121
|
},
|
|
122
|
+
{
|
|
123
|
+
uri: "mcp://git/status",
|
|
124
|
+
name: "Git Status",
|
|
125
|
+
mimeType: "application/json",
|
|
126
|
+
description: "Current working directory git status.",
|
|
127
|
+
},
|
|
87
128
|
{
|
|
88
129
|
uri: "mcp://ci/latest-run",
|
|
89
130
|
name: "Latest CI Run",
|
|
@@ -125,18 +166,12 @@ export const MCP_RESOURCE_TEMPLATES: ResourceTemplate[] = [
|
|
|
125
166
|
},
|
|
126
167
|
];
|
|
127
168
|
|
|
128
|
-
const DEFAULT_OUTPUT_SCHEMA = {
|
|
129
|
-
type: "object",
|
|
130
|
-
properties: {},
|
|
131
|
-
additionalProperties: true,
|
|
132
|
-
} as const;
|
|
133
|
-
|
|
134
169
|
const BASE_MCP_TOOLS: Tool[] = [
|
|
135
170
|
{
|
|
136
171
|
name: "boomtick.health",
|
|
137
172
|
description: "Check the health and configuration of the MCP server.",
|
|
138
173
|
inputSchema: HealthCheckInputJsonSchema as any,
|
|
139
|
-
outputSchema:
|
|
174
|
+
outputSchema: HealthCheckResponseJsonSchema as any,
|
|
140
175
|
},
|
|
141
176
|
{
|
|
142
177
|
name: "github.search_open_prs",
|
|
@@ -146,9 +181,15 @@ const BASE_MCP_TOOLS: Tool[] = [
|
|
|
146
181
|
},
|
|
147
182
|
{
|
|
148
183
|
name: "repo.read_agent_context",
|
|
149
|
-
description: "Read the
|
|
184
|
+
description: "Read the repository index including metadata, model review chains, or multi-repo ecosystem status.",
|
|
150
185
|
inputSchema: ReadAgentContextSchema as any,
|
|
151
|
-
outputSchema:
|
|
186
|
+
outputSchema: ReadAgentContextResponseJsonSchema as any,
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: "repo.multi_exec",
|
|
190
|
+
description: "Execute a shell command sequentially across ecosystem repositories (or a filtered subset).",
|
|
191
|
+
inputSchema: MultiExecInputJsonSchema as any,
|
|
192
|
+
outputSchema: MultiExecResponseJsonSchema as any,
|
|
152
193
|
},
|
|
153
194
|
{
|
|
154
195
|
name: "github.get_pr_diff",
|
|
@@ -160,7 +201,7 @@ const BASE_MCP_TOOLS: Tool[] = [
|
|
|
160
201
|
name: "github.checkout_branch",
|
|
161
202
|
description: "Checkout a specific branch in the repository or worktree.",
|
|
162
203
|
inputSchema: CheckoutBranchInputJsonSchema as any,
|
|
163
|
-
outputSchema:
|
|
204
|
+
outputSchema: CheckoutBranchResponseJsonSchema as any,
|
|
164
205
|
},
|
|
165
206
|
{
|
|
166
207
|
name: "github.get_merge_conflict_files",
|
|
@@ -172,43 +213,43 @@ const BASE_MCP_TOOLS: Tool[] = [
|
|
|
172
213
|
name: "repo.get_changed_files",
|
|
173
214
|
description: "Get the list of changed files between two refs.",
|
|
174
215
|
inputSchema: GetChangedFilesInputJsonSchema as any,
|
|
175
|
-
outputSchema:
|
|
216
|
+
outputSchema: GetChangedFilesResponseJsonSchema as any,
|
|
176
217
|
},
|
|
177
218
|
{
|
|
178
219
|
name: "repo.get_command_schema",
|
|
179
220
|
description: "Retrieve a lightweight, targeted schema for a specific td subcommand. Use this instead of reading the entire cli-schema.json to save tokens.",
|
|
180
221
|
inputSchema: GetCommandSchemaInputJsonSchema as any,
|
|
181
|
-
outputSchema:
|
|
222
|
+
outputSchema: GetCommandSchemaResponseJsonSchema as any,
|
|
182
223
|
},
|
|
183
224
|
{
|
|
184
225
|
name: "repo.get_package_scripts",
|
|
185
226
|
description: "Get the scripts defined in package.json.",
|
|
186
227
|
inputSchema: GetPackageScriptsInputJsonSchema as any,
|
|
187
|
-
outputSchema:
|
|
228
|
+
outputSchema: GetPackageScriptsResponseJsonSchema as any,
|
|
188
229
|
},
|
|
189
230
|
{
|
|
190
231
|
name: "repo.read_ci_logs",
|
|
191
232
|
description: "Read CI logs for a given pull request.",
|
|
192
233
|
inputSchema: ReadCiLogsInputJsonSchema as any,
|
|
193
|
-
outputSchema:
|
|
234
|
+
outputSchema: ReadCiLogsResponseJsonSchema as any,
|
|
194
235
|
},
|
|
195
236
|
{
|
|
196
237
|
name: "repo.logs",
|
|
197
238
|
description: "Stream or grep combined CI logs for all jobs in a pull request.",
|
|
198
239
|
inputSchema: RepoLogsInputJsonSchema as any,
|
|
199
|
-
outputSchema:
|
|
240
|
+
outputSchema: RepoLogsResponseJsonSchema as any,
|
|
200
241
|
},
|
|
201
242
|
{
|
|
202
243
|
name: "repo.create_branch",
|
|
203
244
|
description: "Creates a new clean git branch from a target base branch.",
|
|
204
245
|
inputSchema: CreateBranchInputJsonSchema as any,
|
|
205
|
-
outputSchema:
|
|
246
|
+
outputSchema: CreateBranchResponseJsonSchema as any,
|
|
206
247
|
},
|
|
207
248
|
{
|
|
208
249
|
name: "repo.create_repair_branch",
|
|
209
250
|
description: "Creates a fresh worktree and a new repair branch for an existing PR. This isolates the repair work from the main codebase.",
|
|
210
251
|
inputSchema: CreateRepairBranchInputJsonSchema as any,
|
|
211
|
-
outputSchema:
|
|
252
|
+
outputSchema: CreateRepairBranchResponseJsonSchema as any,
|
|
212
253
|
},
|
|
213
254
|
{
|
|
214
255
|
name: "repo.check_jules_status",
|
|
@@ -224,7 +265,7 @@ const BASE_MCP_TOOLS: Tool[] = [
|
|
|
224
265
|
intervalMs: { type: "integer", description: "Polling interval in milliseconds." },
|
|
225
266
|
},
|
|
226
267
|
} as any,
|
|
227
|
-
outputSchema:
|
|
268
|
+
outputSchema: CheckJulesStatusResponseJsonSchema as any,
|
|
228
269
|
},
|
|
229
270
|
{
|
|
230
271
|
name: "repo.run_tests",
|
|
@@ -236,55 +277,55 @@ const BASE_MCP_TOOLS: Tool[] = [
|
|
|
236
277
|
name: "repo.commit_patch",
|
|
237
278
|
description: "Commit verified repair changes in a worktree.",
|
|
238
279
|
inputSchema: CommitPatchInputJsonSchema as any,
|
|
239
|
-
outputSchema:
|
|
280
|
+
outputSchema: CommitPatchResponseJsonSchema as any,
|
|
240
281
|
},
|
|
241
282
|
{
|
|
242
283
|
name: "github.open_replacement_pr",
|
|
243
284
|
description: "Open a new PR that replaces or repairs the original PR.",
|
|
244
285
|
inputSchema: OpenReplacementPrInputJsonSchema as any,
|
|
245
|
-
outputSchema:
|
|
286
|
+
outputSchema: OpenReplacementPrResponseJsonSchema as any,
|
|
246
287
|
},
|
|
247
288
|
{
|
|
248
289
|
name: "github.create_pull_request",
|
|
249
290
|
description: "Creates a pull request on GitHub using the MCP server's integrated credentials. Bypasses terminal CLI constraints.",
|
|
250
291
|
inputSchema: CreatePullRequestInputJsonSchema as any,
|
|
251
|
-
outputSchema:
|
|
292
|
+
outputSchema: CreatePullRequestResponseJsonSchema as any,
|
|
252
293
|
},
|
|
253
294
|
{
|
|
254
295
|
name: "github.comment_triage_summary",
|
|
255
296
|
description: "Comment on the original PR with a diagnosis and replacement link.",
|
|
256
297
|
inputSchema: CommentTriageSummaryInputJsonSchema as any,
|
|
257
|
-
outputSchema:
|
|
298
|
+
outputSchema: CommentTriageSummaryResponseJsonSchema as any,
|
|
258
299
|
},
|
|
259
300
|
{
|
|
260
301
|
name: "github.get_pr",
|
|
261
302
|
description: "Get details of a GitHub PR including title, state, and URLs.",
|
|
262
303
|
inputSchema: GetPrInputJsonSchema as any,
|
|
263
|
-
outputSchema:
|
|
304
|
+
outputSchema: GetPrResponseJsonSchema as any,
|
|
264
305
|
},
|
|
265
306
|
{
|
|
266
307
|
name: "github.get_pr_reviews",
|
|
267
308
|
description: "Get top-level reviews, verdicts, states, and bodies for a GitHub PR.",
|
|
268
309
|
inputSchema: GetPrReviewsInputJsonSchema as any,
|
|
269
|
-
outputSchema:
|
|
310
|
+
outputSchema: GetPrReviewsResponseJsonSchema as any,
|
|
270
311
|
},
|
|
271
312
|
{
|
|
272
313
|
name: "github.get_pr_commits",
|
|
273
314
|
description: "List commits and commit metadata (SHAs, authors, messages) for a GitHub PR.",
|
|
274
315
|
inputSchema: GetPrCommitsInputJsonSchema as any,
|
|
275
|
-
outputSchema:
|
|
316
|
+
outputSchema: GetPrCommitsResponseJsonSchema as any,
|
|
276
317
|
},
|
|
277
318
|
{
|
|
278
319
|
name: "repo.get_workflow_runs",
|
|
279
320
|
description: "List recent GitHub Actions workflow runs for the repository.",
|
|
280
321
|
inputSchema: GetWorkflowRunsInputJsonSchema as any,
|
|
281
|
-
outputSchema:
|
|
322
|
+
outputSchema: GetWorkflowRunsResponseJsonSchema as any,
|
|
282
323
|
},
|
|
283
324
|
{
|
|
284
325
|
name: "github.issue_view",
|
|
285
326
|
description: "View details of a GitHub issue including title, body, and state.",
|
|
286
327
|
inputSchema: IssueViewInputJsonSchema as any,
|
|
287
|
-
outputSchema:
|
|
328
|
+
outputSchema: IssueViewResponseJsonSchema as any,
|
|
288
329
|
},
|
|
289
330
|
{
|
|
290
331
|
name: "github.issue_update",
|
|
@@ -296,7 +337,7 @@ const BASE_MCP_TOOLS: Tool[] = [
|
|
|
296
337
|
name: "github.issue_comment",
|
|
297
338
|
description: "Add a new comment to a GitHub issue.",
|
|
298
339
|
inputSchema: IssueCommentInputJsonSchema as any,
|
|
299
|
-
outputSchema:
|
|
340
|
+
outputSchema: IssueCommentResponseJsonSchema as any,
|
|
300
341
|
},
|
|
301
342
|
{
|
|
302
343
|
name: "github.create_issue",
|
|
@@ -308,49 +349,49 @@ const BASE_MCP_TOOLS: Tool[] = [
|
|
|
308
349
|
name: "jules.create_session",
|
|
309
350
|
description: "Create a Jules session that performs work externally and may generate a GitHub pull request.",
|
|
310
351
|
inputSchema: CreateJulesSessionInputJsonSchema as any,
|
|
311
|
-
outputSchema:
|
|
352
|
+
outputSchema: JulesSessionResponseJsonSchema as any,
|
|
312
353
|
},
|
|
313
354
|
{
|
|
314
355
|
name: "jules.get_session",
|
|
315
356
|
description: "Get the status and details of a Jules session.",
|
|
316
357
|
inputSchema: JulesSessionIdInputJsonSchema as any,
|
|
317
|
-
outputSchema:
|
|
358
|
+
outputSchema: JulesSessionResponseJsonSchema as any,
|
|
318
359
|
},
|
|
319
360
|
{
|
|
320
361
|
name: "jules.send_message",
|
|
321
362
|
description: "Send a message to an active Jules session.",
|
|
322
363
|
inputSchema: JulesSendMessageInputJsonSchema as any,
|
|
323
|
-
outputSchema:
|
|
364
|
+
outputSchema: JulesSendMessageResponseJsonSchema as any,
|
|
324
365
|
},
|
|
325
366
|
{
|
|
326
367
|
name: "jules.get_messages",
|
|
327
368
|
description: "Get the message history of a Jules session.",
|
|
328
369
|
inputSchema: JulesSessionIdInputJsonSchema as any,
|
|
329
|
-
outputSchema:
|
|
370
|
+
outputSchema: JulesGetMessagesResponseJsonSchema as any,
|
|
330
371
|
},
|
|
331
372
|
{
|
|
332
373
|
name: "jules.list_sessions",
|
|
333
374
|
description: "List all Jules sessions.",
|
|
334
375
|
inputSchema: JulesListSessionsInputJsonSchema as any,
|
|
335
|
-
outputSchema:
|
|
376
|
+
outputSchema: JulesListSessionsResponseJsonSchema as any,
|
|
336
377
|
},
|
|
337
378
|
{
|
|
338
379
|
name: "jules.cancel_session",
|
|
339
380
|
description: "Cancel an ongoing Jules session.",
|
|
340
381
|
inputSchema: JulesSessionIdInputJsonSchema as any,
|
|
341
|
-
outputSchema:
|
|
382
|
+
outputSchema: JulesSessionResponseJsonSchema as any,
|
|
342
383
|
},
|
|
343
384
|
{
|
|
344
385
|
name: "jules.get_pr",
|
|
345
386
|
description: "Get the generated pull request url associated with an active Jules agent session.",
|
|
346
387
|
inputSchema: JulesSessionIdInputJsonSchema as any,
|
|
347
|
-
outputSchema:
|
|
388
|
+
outputSchema: JulesGetPrResponseJsonSchema as any,
|
|
348
389
|
},
|
|
349
390
|
{
|
|
350
391
|
name: "jules.trigger_feedback",
|
|
351
392
|
description: "Automatically collect CI status/logs for the PR associated with a Jules session and send them back as feedback.",
|
|
352
393
|
inputSchema: JulesSessionIdInputJsonSchema as any,
|
|
353
|
-
outputSchema:
|
|
394
|
+
outputSchema: JulesTriggerFeedbackResponseJsonSchema as any,
|
|
354
395
|
},
|
|
355
396
|
];
|
|
356
397
|
|
package/src/mcp/http.test.ts
CHANGED
|
@@ -18,6 +18,16 @@ describe("createMcpHttpServer", () => {
|
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
it("should respond with 200 on GET /health endpoint", async () => {
|
|
22
|
+
httpServerObj = createMcpHttpServer({ port: 0, mcpServer });
|
|
23
|
+
port = await httpServerObj.listen(0);
|
|
24
|
+
|
|
25
|
+
const res = await fetch(`http://localhost:${port}/health`);
|
|
26
|
+
expect(res.status).toBe(200);
|
|
27
|
+
const body = await res.json();
|
|
28
|
+
expect(body).toEqual({ status: "ok", transport: "http" });
|
|
29
|
+
});
|
|
30
|
+
|
|
21
31
|
it("should respond with RFC 9728 OAuth protected resource metadata on /.well-known/oauth-protected-resource", async () => {
|
|
22
32
|
httpServerObj = createMcpHttpServer({ port: 0, mcpServer });
|
|
23
33
|
port = await httpServerObj.listen(0);
|