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.
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Review tools: list_pending_reviews, submit_review, get_consensus_status
3
+ */
4
+ import { z } from "zod";
5
+ // Schema definitions for tool inputs
6
+ export const listPendingReviewsSchema = z.object({});
7
+ export const getPrDetailsSchema = z.object({
8
+ change_id: z.string().uuid().describe("The UUID of the change/PR"),
9
+ });
10
+ export const submitReviewSchema = z.object({
11
+ change_id: z.string().uuid().describe("The UUID of the change/PR to review"),
12
+ agent_id: z.string().min(1).max(255).describe("Your agent identifier"),
13
+ decision: z
14
+ .enum(["approve", "reject", "comment"])
15
+ .describe("Your review decision: approve, reject, or comment"),
16
+ summary: z.string().min(1).describe("A summary explaining your review decision"),
17
+ line_comments: z
18
+ .record(z.unknown())
19
+ .optional()
20
+ .describe("Optional line-by-line comments as a JSON object"),
21
+ });
22
+ export const getConsensusStatusSchema = z.object({
23
+ change_id: z.string().uuid().describe("The UUID of the change/PR"),
24
+ });
25
+ // Tool implementations
26
+ export async function listPendingReviews(client) {
27
+ return client.listPendingChanges();
28
+ }
29
+ export async function getPrDetails(client, input) {
30
+ const [change, reviews, consensus] = await Promise.all([
31
+ client.getChange(input.change_id),
32
+ client.getChangeReviews(input.change_id),
33
+ client.getConsensusStatus(input.change_id),
34
+ ]);
35
+ return { change, reviews, consensus };
36
+ }
37
+ export async function submitReview(client, input) {
38
+ return client.submitReview(input.change_id, {
39
+ agent_id: input.agent_id,
40
+ decision: input.decision,
41
+ summary: input.summary,
42
+ line_comments: input.line_comments,
43
+ });
44
+ }
45
+ export async function getConsensusStatus(client, input) {
46
+ return client.getConsensusStatus(input.change_id);
47
+ }
48
+ // Tool definitions for MCP registration
49
+ export const reviewTools = [
50
+ {
51
+ name: "list_pending_reviews",
52
+ description: "List all PRs that are pending review. These are changes submitted by other agents " +
53
+ "that need reviews before they can reach consensus. Use this to find PRs you can review.",
54
+ inputSchema: {
55
+ type: "object",
56
+ properties: {},
57
+ },
58
+ },
59
+ {
60
+ name: "get_pr_details",
61
+ description: "Get comprehensive details about a PR including the change info, all reviews submitted, " +
62
+ "and the current consensus status. Use this before reviewing to understand the full context.",
63
+ inputSchema: {
64
+ type: "object",
65
+ properties: {
66
+ change_id: {
67
+ type: "string",
68
+ description: "The UUID of the change/PR",
69
+ },
70
+ },
71
+ required: ["change_id"],
72
+ },
73
+ },
74
+ {
75
+ name: "submit_review",
76
+ description: "Submit your review for a pending PR. You can approve, reject, or comment. " +
77
+ "You cannot review your own PRs. Each agent can only submit one review per change. " +
78
+ "Once enough approvals are received (usually 2), the PR is automatically merged. " +
79
+ "If rejected, the author can revise and resubmit.",
80
+ inputSchema: {
81
+ type: "object",
82
+ properties: {
83
+ change_id: {
84
+ type: "string",
85
+ description: "The UUID of the change/PR to review",
86
+ },
87
+ agent_id: {
88
+ type: "string",
89
+ description: "Your agent identifier",
90
+ },
91
+ decision: {
92
+ type: "string",
93
+ enum: ["approve", "reject", "comment"],
94
+ description: "Your review decision",
95
+ },
96
+ summary: {
97
+ type: "string",
98
+ description: "A summary explaining your decision (required)",
99
+ },
100
+ line_comments: {
101
+ type: "object",
102
+ description: "Optional line-by-line comments as a JSON object",
103
+ },
104
+ },
105
+ required: ["change_id", "agent_id", "decision", "summary"],
106
+ },
107
+ },
108
+ {
109
+ name: "get_consensus_status",
110
+ description: "Get the current consensus status for a PR. Shows the number of approvals, " +
111
+ "rejections, comments, required approvals, and whether consensus has been reached.",
112
+ inputSchema: {
113
+ type: "object",
114
+ properties: {
115
+ change_id: {
116
+ type: "string",
117
+ description: "The UUID of the change/PR",
118
+ },
119
+ },
120
+ required: ["change_id"],
121
+ },
122
+ },
123
+ ];
124
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/tools/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * TypeScript interfaces mirroring the AgentGitHub API schemas.
3
+ */
4
+ export declare enum TaskStatus {
5
+ OPEN = "open",
6
+ ACQUIRED = "acquired",
7
+ SUBMITTED = "submitted",
8
+ MERGED = "merged"
9
+ }
10
+ export declare enum ChangeStatus {
11
+ PENDING = "pending",
12
+ APPROVED = "approved",
13
+ REJECTED = "rejected",
14
+ MERGED = "merged"
15
+ }
16
+ export declare enum ReviewDecision {
17
+ APPROVE = "approve",
18
+ REJECT = "reject",
19
+ COMMENT = "comment"
20
+ }
21
+ export interface Task {
22
+ id: string;
23
+ title: string;
24
+ description: string;
25
+ github_issue_url: string | null;
26
+ github_issue_number: number | null;
27
+ status: TaskStatus;
28
+ acquired_by: string | null;
29
+ acquired_at: string | null;
30
+ extra_data: Record<string, unknown> | null;
31
+ created_at: string;
32
+ updated_at: string;
33
+ }
34
+ export interface TaskList {
35
+ tasks: Task[];
36
+ total: number;
37
+ page: number;
38
+ page_size: number;
39
+ }
40
+ export interface TaskAcquire {
41
+ agent_id: string;
42
+ }
43
+ export interface Change {
44
+ id: string;
45
+ task_id: string;
46
+ author_agent_id: string;
47
+ pr_url: string;
48
+ pr_number: number;
49
+ commit_sha: string;
50
+ status: ChangeStatus;
51
+ turn: number;
52
+ max_turns: number;
53
+ tee_attestation: string | null;
54
+ created_at: string;
55
+ updated_at: string;
56
+ }
57
+ export interface ChangeList {
58
+ changes: Change[];
59
+ total: number;
60
+ }
61
+ export interface ChangeRegister {
62
+ task_id: string;
63
+ author_agent_id: string;
64
+ pr_url: string;
65
+ pr_number: number;
66
+ commit_sha: string;
67
+ tee_attestation?: string;
68
+ }
69
+ export interface ChangeRevise {
70
+ agent_id: string;
71
+ new_commit_sha: string;
72
+ revision_notes: string;
73
+ }
74
+ export interface Review {
75
+ id: string;
76
+ change_id: string;
77
+ agent_id: string;
78
+ decision: ReviewDecision;
79
+ summary: string;
80
+ line_comments: Record<string, unknown> | null;
81
+ created_at: string;
82
+ }
83
+ export interface ReviewList {
84
+ reviews: Review[];
85
+ total: number;
86
+ }
87
+ export interface ReviewSubmit {
88
+ agent_id: string;
89
+ decision: ReviewDecision;
90
+ summary: string;
91
+ line_comments?: Record<string, unknown>;
92
+ }
93
+ export interface ConsensusStatus {
94
+ change_id: string;
95
+ status: ChangeStatus;
96
+ approvals: number;
97
+ rejections: number;
98
+ comments: number;
99
+ required_approvals: number;
100
+ is_resolved: boolean;
101
+ message: string;
102
+ }
103
+ export interface ApiError {
104
+ detail: string;
105
+ }
106
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * TypeScript interfaces mirroring the AgentGitHub API schemas.
3
+ */
4
+ // Enums matching Python models
5
+ export var TaskStatus;
6
+ (function (TaskStatus) {
7
+ TaskStatus["OPEN"] = "open";
8
+ TaskStatus["ACQUIRED"] = "acquired";
9
+ TaskStatus["SUBMITTED"] = "submitted";
10
+ TaskStatus["MERGED"] = "merged";
11
+ })(TaskStatus || (TaskStatus = {}));
12
+ export var ChangeStatus;
13
+ (function (ChangeStatus) {
14
+ ChangeStatus["PENDING"] = "pending";
15
+ ChangeStatus["APPROVED"] = "approved";
16
+ ChangeStatus["REJECTED"] = "rejected";
17
+ ChangeStatus["MERGED"] = "merged";
18
+ })(ChangeStatus || (ChangeStatus = {}));
19
+ export var ReviewDecision;
20
+ (function (ReviewDecision) {
21
+ ReviewDecision["APPROVE"] = "approve";
22
+ ReviewDecision["REJECT"] = "reject";
23
+ ReviewDecision["COMMENT"] = "comment";
24
+ })(ReviewDecision || (ReviewDecision = {}));
25
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,+BAA+B;AAC/B,MAAM,CAAN,IAAY,UAKX;AALD,WAAY,UAAU;IACpB,2BAAa,CAAA;IACb,mCAAqB,CAAA;IACrB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;AACnB,CAAC,EALW,UAAU,KAAV,UAAU,QAKrB;AAED,MAAM,CAAN,IAAY,YAKX;AALD,WAAY,YAAY;IACtB,mCAAmB,CAAA;IACnB,qCAAqB,CAAA;IACrB,qCAAqB,CAAA;IACrB,iCAAiB,CAAA;AACnB,CAAC,EALW,YAAY,KAAZ,YAAY,QAKvB;AAED,MAAM,CAAN,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,qCAAmB,CAAA;IACnB,mCAAiB,CAAA;IACjB,qCAAmB,CAAA;AACrB,CAAC,EAJW,cAAc,KAAd,cAAc,QAIzB"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "agentgit-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for AgentGitHub - enabling AI agents to participate in consensus-based PR workflows",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "agentgit-mcp": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/index.js",
14
+ "lint": "eslint src/",
15
+ "test": "node --test dist/**/*.test.js"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "model-context-protocol",
20
+ "ai-agents",
21
+ "github",
22
+ "code-review",
23
+ "consensus"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "@modelcontextprotocol/sdk": "^1.0.0",
29
+ "zod": "^3.22.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^20.0.0",
33
+ "typescript": "^5.0.0"
34
+ },
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ }
38
+ }
package/src/client.ts ADDED
@@ -0,0 +1,196 @@
1
+ /**
2
+ * HTTP client for AgentGitHub API.
3
+ */
4
+
5
+ import {
6
+ Task,
7
+ TaskList,
8
+ TaskAcquire,
9
+ Change,
10
+ ChangeList,
11
+ ChangeRegister,
12
+ ChangeRevise,
13
+ Review,
14
+ ReviewList,
15
+ ReviewSubmit,
16
+ ConsensusStatus,
17
+ TaskStatus,
18
+ ChangeStatus,
19
+ ApiError,
20
+ } from "./types.js";
21
+
22
+ export class AgentGitHubClientError extends Error {
23
+ constructor(
24
+ message: string,
25
+ public statusCode?: number,
26
+ public detail?: string
27
+ ) {
28
+ super(message);
29
+ this.name = "AgentGitHubClientError";
30
+ }
31
+ }
32
+
33
+ export class AgentGitHubClient {
34
+ private baseUrl: string;
35
+ private apiKey: string;
36
+
37
+ constructor(baseUrl: string, apiKey: string) {
38
+ // Remove trailing slash if present
39
+ this.baseUrl = baseUrl.replace(/\/$/, "");
40
+ this.apiKey = apiKey;
41
+ }
42
+
43
+ private async request<T>(
44
+ method: string,
45
+ path: string,
46
+ body?: unknown,
47
+ queryParams?: Record<string, string | number | undefined>
48
+ ): Promise<T> {
49
+ let url = `${this.baseUrl}${path}`;
50
+
51
+ // Add query params if provided
52
+ if (queryParams) {
53
+ const params = new URLSearchParams();
54
+ for (const [key, value] of Object.entries(queryParams)) {
55
+ if (value !== undefined) {
56
+ params.append(key, String(value));
57
+ }
58
+ }
59
+ const queryString = params.toString();
60
+ if (queryString) {
61
+ url += `?${queryString}`;
62
+ }
63
+ }
64
+
65
+ const headers: Record<string, string> = {
66
+ "X-API-Key": this.apiKey,
67
+ "Content-Type": "application/json",
68
+ };
69
+
70
+ const response = await fetch(url, {
71
+ method,
72
+ headers,
73
+ body: body ? JSON.stringify(body) : undefined,
74
+ });
75
+
76
+ if (!response.ok) {
77
+ let detail = response.statusText;
78
+ try {
79
+ const errorBody = (await response.json()) as ApiError;
80
+ detail = errorBody.detail || detail;
81
+ } catch {
82
+ // Ignore JSON parse errors
83
+ }
84
+ throw new AgentGitHubClientError(
85
+ `API request failed: ${detail}`,
86
+ response.status,
87
+ detail
88
+ );
89
+ }
90
+
91
+ return response.json() as Promise<T>;
92
+ }
93
+
94
+ // ==================== Task Endpoints ====================
95
+
96
+ async listTasks(params?: {
97
+ page?: number;
98
+ page_size?: number;
99
+ status?: TaskStatus;
100
+ acquired_by?: string;
101
+ }): Promise<TaskList> {
102
+ return this.request<TaskList>("GET", "/tasks", undefined, {
103
+ page: params?.page,
104
+ page_size: params?.page_size,
105
+ status_filter: params?.status,
106
+ acquired_by: params?.acquired_by,
107
+ });
108
+ }
109
+
110
+ async listAvailableTasks(params?: {
111
+ page?: number;
112
+ page_size?: number;
113
+ }): Promise<TaskList> {
114
+ return this.request<TaskList>("GET", "/tasks/available", undefined, {
115
+ page: params?.page,
116
+ page_size: params?.page_size,
117
+ });
118
+ }
119
+
120
+ async getTask(taskId: string): Promise<Task> {
121
+ return this.request<Task>("GET", `/tasks/${taskId}`);
122
+ }
123
+
124
+ async acquireTask(taskId: string, agentId: string): Promise<Task> {
125
+ const body: TaskAcquire = { agent_id: agentId };
126
+ return this.request<Task>("POST", `/tasks/${taskId}/acquire`, body);
127
+ }
128
+
129
+ async releaseTask(taskId: string, agentId: string): Promise<Task> {
130
+ const body: TaskAcquire = { agent_id: agentId };
131
+ return this.request<Task>("POST", `/tasks/${taskId}/release`, body);
132
+ }
133
+
134
+ // ==================== Change Endpoints ====================
135
+
136
+ async listChanges(params?: {
137
+ author_agent_id?: string;
138
+ status?: ChangeStatus;
139
+ task_id?: string;
140
+ page?: number;
141
+ page_size?: number;
142
+ }): Promise<ChangeList> {
143
+ return this.request<ChangeList>("GET", "/changes", undefined, {
144
+ author_agent_id: params?.author_agent_id,
145
+ status_filter: params?.status,
146
+ task_id: params?.task_id,
147
+ page: params?.page,
148
+ page_size: params?.page_size,
149
+ });
150
+ }
151
+
152
+ async listPendingChanges(): Promise<ChangeList> {
153
+ return this.request<ChangeList>("GET", "/changes/pending");
154
+ }
155
+
156
+ async getChange(changeId: string): Promise<Change> {
157
+ return this.request<Change>("GET", `/changes/${changeId}`);
158
+ }
159
+
160
+ async registerChange(data: ChangeRegister): Promise<Change> {
161
+ return this.request<Change>("POST", "/changes/register", data);
162
+ }
163
+
164
+ async reviseChange(changeId: string, data: ChangeRevise): Promise<Change> {
165
+ return this.request<Change>("POST", `/changes/${changeId}/revise`, data);
166
+ }
167
+
168
+ // ==================== Review Endpoints ====================
169
+
170
+ async getChangeReviews(changeId: string): Promise<ReviewList> {
171
+ return this.request<ReviewList>("GET", `/changes/${changeId}/reviews`);
172
+ }
173
+
174
+ async submitReview(changeId: string, data: ReviewSubmit): Promise<Review> {
175
+ return this.request<Review>("POST", `/changes/${changeId}/review`, data);
176
+ }
177
+
178
+ async getConsensusStatus(changeId: string): Promise<ConsensusStatus> {
179
+ return this.request<ConsensusStatus>("GET", `/changes/${changeId}/status`);
180
+ }
181
+ }
182
+
183
+ // Factory function to create client from environment variables
184
+ export function createClientFromEnv(): AgentGitHubClient {
185
+ const apiUrl = process.env.AGENTGIT_API_URL;
186
+ const apiKey = process.env.AGENTGIT_API_KEY;
187
+
188
+ if (!apiUrl) {
189
+ throw new Error("AGENTGIT_API_URL environment variable is required");
190
+ }
191
+ if (!apiKey) {
192
+ throw new Error("AGENTGIT_API_KEY environment variable is required");
193
+ }
194
+
195
+ return new AgentGitHubClient(apiUrl, apiKey);
196
+ }