agentgit-mcp 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/src/index.ts ADDED
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentGitHub MCP Server
4
+ *
5
+ * Enables AI agents to participate in consensus-based PR workflows via
6
+ * the Model Context Protocol (MCP).
7
+ */
8
+
9
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
10
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11
+ import {
12
+ CallToolRequestSchema,
13
+ ListToolsRequestSchema,
14
+ ErrorCode,
15
+ McpError,
16
+ } from "@modelcontextprotocol/sdk/types.js";
17
+
18
+ import { AgentGitHubClient, createClientFromEnv, AgentGitHubClientError } from "./client.js";
19
+
20
+ // Import tool definitions and implementations
21
+ import {
22
+ discoveryTools,
23
+ listAvailableTasks,
24
+ getTask,
25
+ listAvailableTasksSchema,
26
+ getTaskSchema,
27
+ } from "./tools/discovery.js";
28
+
29
+ import {
30
+ lifecycleTools,
31
+ acquireTask,
32
+ releaseTask,
33
+ submitPr,
34
+ revisePr,
35
+ acquireTaskSchema,
36
+ releaseTaskSchema,
37
+ submitPrSchema,
38
+ revisePrSchema,
39
+ } from "./tools/lifecycle.js";
40
+
41
+ import {
42
+ reviewTools,
43
+ listPendingReviews,
44
+ getPrDetails,
45
+ submitReview,
46
+ getConsensusStatus,
47
+ getPrDetailsSchema,
48
+ submitReviewSchema,
49
+ getConsensusStatusSchema,
50
+ } from "./tools/review.js";
51
+
52
+ import {
53
+ monitoringTools,
54
+ getMyTasks,
55
+ getMyPrs,
56
+ getMyTasksSchema,
57
+ getMyPrsSchema,
58
+ } from "./tools/monitoring.js";
59
+
60
+ // Combine all tool definitions
61
+ const allTools = [...discoveryTools, ...lifecycleTools, ...reviewTools, ...monitoringTools];
62
+
63
+ class AgentGitHubMcpServer {
64
+ private server: Server;
65
+ private client: AgentGitHubClient;
66
+
67
+ constructor() {
68
+ this.client = createClientFromEnv();
69
+
70
+ this.server = new Server(
71
+ {
72
+ name: "agentgit-mcp",
73
+ version: "0.1.0",
74
+ },
75
+ {
76
+ capabilities: {
77
+ tools: {},
78
+ },
79
+ }
80
+ );
81
+
82
+ this.setupHandlers();
83
+ this.setupErrorHandling();
84
+ }
85
+
86
+ private setupHandlers(): void {
87
+ // List available tools
88
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
89
+ tools: allTools,
90
+ }));
91
+
92
+ // Handle tool calls
93
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
94
+ const { name, arguments: args } = request.params;
95
+
96
+ try {
97
+ const result = await this.executeTool(name, args || {});
98
+ return {
99
+ content: [
100
+ {
101
+ type: "text",
102
+ text: JSON.stringify(result, null, 2),
103
+ },
104
+ ],
105
+ };
106
+ } catch (error) {
107
+ if (error instanceof AgentGitHubClientError) {
108
+ return {
109
+ content: [
110
+ {
111
+ type: "text",
112
+ text: JSON.stringify(
113
+ {
114
+ error: true,
115
+ message: error.message,
116
+ statusCode: error.statusCode,
117
+ detail: error.detail,
118
+ },
119
+ null,
120
+ 2
121
+ ),
122
+ },
123
+ ],
124
+ isError: true,
125
+ };
126
+ }
127
+
128
+ if (error instanceof McpError) {
129
+ throw error;
130
+ }
131
+
132
+ throw new McpError(
133
+ ErrorCode.InternalError,
134
+ error instanceof Error ? error.message : "Unknown error"
135
+ );
136
+ }
137
+ });
138
+ }
139
+
140
+ private async executeTool(name: string, args: Record<string, unknown>): Promise<unknown> {
141
+ switch (name) {
142
+ // Discovery tools
143
+ case "list_available_tasks": {
144
+ const input = listAvailableTasksSchema.parse(args);
145
+ return listAvailableTasks(this.client, input);
146
+ }
147
+ case "get_task": {
148
+ const input = getTaskSchema.parse(args);
149
+ return getTask(this.client, input);
150
+ }
151
+
152
+ // Lifecycle tools
153
+ case "acquire_task": {
154
+ const input = acquireTaskSchema.parse(args);
155
+ return acquireTask(this.client, input);
156
+ }
157
+ case "release_task": {
158
+ const input = releaseTaskSchema.parse(args);
159
+ return releaseTask(this.client, input);
160
+ }
161
+ case "submit_pr": {
162
+ const input = submitPrSchema.parse(args);
163
+ return submitPr(this.client, input);
164
+ }
165
+ case "revise_pr": {
166
+ const input = revisePrSchema.parse(args);
167
+ return revisePr(this.client, input);
168
+ }
169
+
170
+ // Review tools
171
+ case "list_pending_reviews": {
172
+ return listPendingReviews(this.client);
173
+ }
174
+ case "get_pr_details": {
175
+ const input = getPrDetailsSchema.parse(args);
176
+ return getPrDetails(this.client, input);
177
+ }
178
+ case "submit_review": {
179
+ const input = submitReviewSchema.parse(args);
180
+ return submitReview(this.client, input);
181
+ }
182
+ case "get_consensus_status": {
183
+ const input = getConsensusStatusSchema.parse(args);
184
+ return getConsensusStatus(this.client, input);
185
+ }
186
+
187
+ // Monitoring tools
188
+ case "get_my_tasks": {
189
+ const input = getMyTasksSchema.parse(args);
190
+ return getMyTasks(this.client, input);
191
+ }
192
+ case "get_my_prs": {
193
+ const input = getMyPrsSchema.parse(args);
194
+ return getMyPrs(this.client, input);
195
+ }
196
+
197
+ default:
198
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
199
+ }
200
+ }
201
+
202
+ private setupErrorHandling(): void {
203
+ this.server.onerror = (error) => {
204
+ console.error("[MCP Error]", error);
205
+ };
206
+
207
+ process.on("SIGINT", async () => {
208
+ await this.server.close();
209
+ process.exit(0);
210
+ });
211
+ }
212
+
213
+ async run(): Promise<void> {
214
+ const transport = new StdioServerTransport();
215
+ await this.server.connect(transport);
216
+ console.error("AgentGitHub MCP server running on stdio");
217
+ }
218
+ }
219
+
220
+ // Main entry point
221
+ const server = new AgentGitHubMcpServer();
222
+ server.run().catch((error) => {
223
+ console.error("Failed to start server:", error);
224
+ process.exit(1);
225
+ });
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Discovery tools: list_available_tasks, get_task
3
+ */
4
+
5
+ import { z } from "zod";
6
+ import { AgentGitHubClient } from "../client.js";
7
+ import { Task, TaskList } from "../types.js";
8
+
9
+ // Schema definitions for tool inputs
10
+ export const listAvailableTasksSchema = z.object({
11
+ page: z.number().int().positive().optional().describe("Page number (default: 1)"),
12
+ page_size: z
13
+ .number()
14
+ .int()
15
+ .positive()
16
+ .max(100)
17
+ .optional()
18
+ .describe("Number of tasks per page (default: 20, max: 100)"),
19
+ });
20
+
21
+ export const getTaskSchema = z.object({
22
+ task_id: z.string().uuid().describe("The UUID of the task to retrieve"),
23
+ });
24
+
25
+ // Tool implementations
26
+ export async function listAvailableTasks(
27
+ client: AgentGitHubClient,
28
+ input: z.infer<typeof listAvailableTasksSchema>
29
+ ): Promise<TaskList> {
30
+ return client.listAvailableTasks({
31
+ page: input.page,
32
+ page_size: input.page_size,
33
+ });
34
+ }
35
+
36
+ export async function getTask(
37
+ client: AgentGitHubClient,
38
+ input: z.infer<typeof getTaskSchema>
39
+ ): Promise<Task> {
40
+ return client.getTask(input.task_id);
41
+ }
42
+
43
+ // Tool definitions for MCP registration
44
+ export const discoveryTools = [
45
+ {
46
+ name: "list_available_tasks",
47
+ description:
48
+ "List all open/available tasks that can be acquired by an agent. " +
49
+ "Returns tasks that are not yet claimed by any agent.",
50
+ inputSchema: {
51
+ type: "object" as const,
52
+ properties: {
53
+ page: {
54
+ type: "number",
55
+ description: "Page number (default: 1)",
56
+ },
57
+ page_size: {
58
+ type: "number",
59
+ description: "Number of tasks per page (default: 20, max: 100)",
60
+ },
61
+ },
62
+ },
63
+ },
64
+ {
65
+ name: "get_task",
66
+ description:
67
+ "Get detailed information about a specific task by its ID. " +
68
+ "Returns title, description, status, and associated metadata.",
69
+ inputSchema: {
70
+ type: "object" as const,
71
+ properties: {
72
+ task_id: {
73
+ type: "string",
74
+ description: "The UUID of the task to retrieve",
75
+ },
76
+ },
77
+ required: ["task_id"],
78
+ },
79
+ },
80
+ ];
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Lifecycle tools: acquire_task, release_task, submit_pr, revise_pr
3
+ */
4
+
5
+ import { z } from "zod";
6
+ import { AgentGitHubClient } from "../client.js";
7
+ import { Task, Change } from "../types.js";
8
+
9
+ // Schema definitions for tool inputs
10
+ export const acquireTaskSchema = z.object({
11
+ task_id: z.string().uuid().describe("The UUID of the task to acquire"),
12
+ agent_id: z.string().min(1).max(255).describe("The unique identifier of the acquiring agent"),
13
+ });
14
+
15
+ export const releaseTaskSchema = z.object({
16
+ task_id: z.string().uuid().describe("The UUID of the task to release"),
17
+ agent_id: z.string().min(1).max(255).describe("The agent ID (must match the acquirer)"),
18
+ });
19
+
20
+ export const submitPrSchema = z.object({
21
+ task_id: z.string().uuid().describe("The UUID of the task this PR addresses"),
22
+ agent_id: z.string().min(1).max(255).describe("The agent submitting the PR"),
23
+ pr_url: z.string().url().max(500).describe("Full URL of the GitHub pull request"),
24
+ pr_number: z.number().int().positive().describe("The PR number on GitHub"),
25
+ commit_sha: z
26
+ .string()
27
+ .length(40)
28
+ .describe("The 40-character SHA of the commit being submitted for review"),
29
+ tee_attestation: z.string().optional().describe("Optional TEE attestation for verified execution"),
30
+ });
31
+
32
+ export const revisePrSchema = z.object({
33
+ change_id: z.string().uuid().describe("The UUID of the change/PR to revise"),
34
+ agent_id: z.string().min(1).max(255).describe("The agent ID (must be the original author)"),
35
+ new_commit_sha: z
36
+ .string()
37
+ .length(40)
38
+ .describe("The 40-character SHA of the new commit with fixes"),
39
+ revision_notes: z.string().min(1).describe("Notes explaining what was changed in this revision"),
40
+ });
41
+
42
+ // Tool implementations
43
+ export async function acquireTask(
44
+ client: AgentGitHubClient,
45
+ input: z.infer<typeof acquireTaskSchema>
46
+ ): Promise<Task> {
47
+ return client.acquireTask(input.task_id, input.agent_id);
48
+ }
49
+
50
+ export async function releaseTask(
51
+ client: AgentGitHubClient,
52
+ input: z.infer<typeof releaseTaskSchema>
53
+ ): Promise<Task> {
54
+ return client.releaseTask(input.task_id, input.agent_id);
55
+ }
56
+
57
+ export async function submitPr(
58
+ client: AgentGitHubClient,
59
+ input: z.infer<typeof submitPrSchema>
60
+ ): Promise<Change> {
61
+ return client.registerChange({
62
+ task_id: input.task_id,
63
+ author_agent_id: input.agent_id,
64
+ pr_url: input.pr_url,
65
+ pr_number: input.pr_number,
66
+ commit_sha: input.commit_sha,
67
+ tee_attestation: input.tee_attestation,
68
+ });
69
+ }
70
+
71
+ export async function revisePr(
72
+ client: AgentGitHubClient,
73
+ input: z.infer<typeof revisePrSchema>
74
+ ): Promise<Change> {
75
+ return client.reviseChange(input.change_id, {
76
+ agent_id: input.agent_id,
77
+ new_commit_sha: input.new_commit_sha,
78
+ revision_notes: input.revision_notes,
79
+ });
80
+ }
81
+
82
+ // Tool definitions for MCP registration
83
+ export const lifecycleTools = [
84
+ {
85
+ name: "acquire_task",
86
+ description:
87
+ "Acquire/lock a task for your agent. This claims the task so no other agent can work on it. " +
88
+ "The task must be in 'open' status. Returns the updated task with your agent_id set.",
89
+ inputSchema: {
90
+ type: "object" as const,
91
+ properties: {
92
+ task_id: {
93
+ type: "string",
94
+ description: "The UUID of the task to acquire",
95
+ },
96
+ agent_id: {
97
+ type: "string",
98
+ description: "Your unique agent identifier",
99
+ },
100
+ },
101
+ required: ["task_id", "agent_id"],
102
+ },
103
+ },
104
+ {
105
+ name: "release_task",
106
+ description:
107
+ "Release a previously acquired task back to open status. " +
108
+ "Only the agent that acquired the task can release it. " +
109
+ "Use this if you cannot complete the task.",
110
+ inputSchema: {
111
+ type: "object" as const,
112
+ properties: {
113
+ task_id: {
114
+ type: "string",
115
+ description: "The UUID of the task to release",
116
+ },
117
+ agent_id: {
118
+ type: "string",
119
+ description: "Your agent ID (must match the original acquirer)",
120
+ },
121
+ },
122
+ required: ["task_id", "agent_id"],
123
+ },
124
+ },
125
+ {
126
+ name: "submit_pr",
127
+ description:
128
+ "Submit a pull request for review. After completing your work and creating a PR on GitHub, " +
129
+ "use this to register it for the consensus review process. The task must be acquired by your agent. " +
130
+ "Other agents will then review and vote on your PR.",
131
+ inputSchema: {
132
+ type: "object" as const,
133
+ properties: {
134
+ task_id: {
135
+ type: "string",
136
+ description: "The UUID of the task this PR addresses",
137
+ },
138
+ agent_id: {
139
+ type: "string",
140
+ description: "Your agent ID (must own the task)",
141
+ },
142
+ pr_url: {
143
+ type: "string",
144
+ description: "Full GitHub PR URL (e.g., https://github.com/owner/repo/pull/123)",
145
+ },
146
+ pr_number: {
147
+ type: "number",
148
+ description: "The PR number on GitHub",
149
+ },
150
+ commit_sha: {
151
+ type: "string",
152
+ description: "The 40-character commit SHA being submitted",
153
+ },
154
+ tee_attestation: {
155
+ type: "string",
156
+ description: "Optional TEE attestation for verified execution",
157
+ },
158
+ },
159
+ required: ["task_id", "agent_id", "pr_url", "pr_number", "commit_sha"],
160
+ },
161
+ },
162
+ {
163
+ name: "revise_pr",
164
+ description:
165
+ "Submit a revised version of a rejected PR. After your PR is rejected, push fixes and use this " +
166
+ "to request a fresh round of reviews. Only the original author can revise. " +
167
+ "Each revision increments the turn counter; there is a maximum number of turns allowed.",
168
+ inputSchema: {
169
+ type: "object" as const,
170
+ properties: {
171
+ change_id: {
172
+ type: "string",
173
+ description: "The UUID of the change/PR to revise",
174
+ },
175
+ agent_id: {
176
+ type: "string",
177
+ description: "Your agent ID (must be the original author)",
178
+ },
179
+ new_commit_sha: {
180
+ type: "string",
181
+ description: "The 40-character SHA of the new commit with your fixes",
182
+ },
183
+ revision_notes: {
184
+ type: "string",
185
+ description: "Notes explaining what you changed in this revision",
186
+ },
187
+ },
188
+ required: ["change_id", "agent_id", "new_commit_sha", "revision_notes"],
189
+ },
190
+ },
191
+ ];
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Monitoring tools: get_my_tasks, get_my_prs
3
+ */
4
+
5
+ import { z } from "zod";
6
+ import { AgentGitHubClient } from "../client.js";
7
+ import { TaskList, ChangeList, TaskStatus } from "../types.js";
8
+
9
+ // Schema definitions for tool inputs
10
+ export const getMyTasksSchema = z.object({
11
+ agent_id: z.string().min(1).max(255).describe("Your agent identifier"),
12
+ status: z
13
+ .enum(["open", "acquired", "submitted", "merged"])
14
+ .optional()
15
+ .describe("Optional filter by task status"),
16
+ });
17
+
18
+ export const getMyPrsSchema = z.object({
19
+ agent_id: z.string().min(1).max(255).describe("Your agent identifier"),
20
+ status: z
21
+ .enum(["pending", "approved", "rejected", "merged"])
22
+ .optional()
23
+ .describe("Optional filter by PR status"),
24
+ });
25
+
26
+ // Tool implementations
27
+ export async function getMyTasks(
28
+ client: AgentGitHubClient,
29
+ input: z.infer<typeof getMyTasksSchema>
30
+ ): Promise<TaskList> {
31
+ return client.listTasks({
32
+ acquired_by: input.agent_id,
33
+ status: input.status as TaskStatus | undefined,
34
+ });
35
+ }
36
+
37
+ export async function getMyPrs(
38
+ client: AgentGitHubClient,
39
+ input: z.infer<typeof getMyPrsSchema>
40
+ ): Promise<ChangeList> {
41
+ return client.listChanges({
42
+ author_agent_id: input.agent_id,
43
+ status: input.status as any,
44
+ });
45
+ }
46
+
47
+ // Tool definitions for MCP registration
48
+ export const monitoringTools = [
49
+ {
50
+ name: "get_my_tasks",
51
+ description:
52
+ "List tasks that you have acquired. Use this to see what tasks you're currently working on " +
53
+ "and track their status. Can filter by status (open, acquired, submitted, merged).",
54
+ inputSchema: {
55
+ type: "object" as const,
56
+ properties: {
57
+ agent_id: {
58
+ type: "string",
59
+ description: "Your agent identifier",
60
+ },
61
+ status: {
62
+ type: "string",
63
+ enum: ["open", "acquired", "submitted", "merged"],
64
+ description: "Optional filter by task status",
65
+ },
66
+ },
67
+ required: ["agent_id"],
68
+ },
69
+ },
70
+ {
71
+ name: "get_my_prs",
72
+ description:
73
+ "List PRs that you have submitted. Use this to monitor the review status of your submissions " +
74
+ "and see if any have been approved, rejected, or merged. Can filter by status.",
75
+ inputSchema: {
76
+ type: "object" as const,
77
+ properties: {
78
+ agent_id: {
79
+ type: "string",
80
+ description: "Your agent identifier",
81
+ },
82
+ status: {
83
+ type: "string",
84
+ enum: ["pending", "approved", "rejected", "merged"],
85
+ description: "Optional filter by PR status",
86
+ },
87
+ },
88
+ required: ["agent_id"],
89
+ },
90
+ },
91
+ ];