@geeks.ltd/geeks-amp-mcp 1.0.3 → 1.0.4
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/README.md +5 -2
- package/dist/index.js +150 -2
- package/dist/tools.js +90 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Local MCP server for Cursor that authenticates to your AMP backend via OAuth 2.0
|
|
|
6
6
|
|
|
7
7
|
1. **First use** – When you call an AMP tool, the server opens your browser to AMP’s login. After you sign in, AMP redirects to `http://127.0.0.1:5005/callback`. The server exchanges the code for access and refresh tokens and stores them (e.g. in `~/.amp-mcp/credentials.json`).
|
|
8
8
|
2. **Later uses** – The server reuses the stored access token. When it expires, it uses the refresh token; if refresh fails, it runs the browser flow again.
|
|
9
|
-
3. **Tools** – `get_projects`, `get_amp_item_with_test_cases`, `submit_amp_progress_update`, `add_amp_test_case_references`, `submit_pen_test_review`, `get_auth_status`, `audit_tdd_amp`, `audit_pen_test_amp` are forwarded to AMP with `Authorization: Bearer <token>`.
|
|
9
|
+
3. **Tools** – `get_user_projects`, `get_projects`, `create_amp`, `get_amp_item_with_test_cases`, `add_amp_update`, `submit_amp_progress_update`, `add_amp_test_case_references`, `submit_pen_test_review`, `get_auth_status`, `audit_tdd_amp`, `audit_pen_test_amp` are forwarded to AMP with `Authorization: Bearer <token>`.
|
|
10
10
|
|
|
11
11
|
## Prerequisites
|
|
12
12
|
|
|
@@ -64,8 +64,11 @@ In `.cursor/mcp.json` (project or global), use the **local server** via npx (no
|
|
|
64
64
|
## Tools
|
|
65
65
|
|
|
66
66
|
- **get_auth_status** – Returns `Authenticated: YES` or `Authenticated: NO` (no browser).
|
|
67
|
-
- **
|
|
67
|
+
- **get_user_projects** – Non-archived projects the authenticated user belongs to: `{ projects: [{ id, key, name }] }`, ordered by key. Use this before `create_amp`.
|
|
68
|
+
- **get_projects** – Legacy global project search (optional `searchTerm`, `limit`); returns id + name only, not user-scoped. Do not use for create flows.
|
|
69
|
+
- **create_amp** – Create a new work item (status New). Required: `project` (key or GUID from `get_user_projects`), `subject`, `type`, `priority`. Optional: `description`, `url`, `note`, `visualSpecLink`, `linkedWorkItems`, `parentAmpReference`. Response includes `reference`, `projectId`, `projectKey`, `projectName`, `url`, etc.
|
|
68
70
|
- **get_amp_item_with_test_cases** – AMP item + test case refs by `ampReference` (e.g. `12345` or `AMP-12345`). Response JSON includes `ampItem.teamPercentageDone` (team board % done) alongside `progress` (workflow stage), and pen test review fields: `hasPenTestReview`, `penTestReviewCompleted`, `penTestReviewCompletedBy`, `penTestReviewCommentId`.
|
|
71
|
+
- **add_amp_update** – Team-column update (mirrors Form_EnterComment team fields except assignees/attachments). Required: `ampReference` plus at least one of `message`, `teamPercentageDone` (0–100, step 10), `teamProgress` (Not started, TDD, Developing, Testing, Done, Blocked), or `stage` (Test, Local, UAT, Live, Pre-Live). Stage changes post a separate `"Done on: {stage}"` comment.
|
|
69
72
|
- **submit_amp_progress_update** – Team board: optional `teamPercentageDone` (0, 10, …, 100) and/or `message`; at least one required. Omits `message` when only updating % so AMP can default the comment to `"{n}% completed"`.
|
|
70
73
|
- **add_amp_test_case_references** – `ampReference`, required `testCaseReferences` (array of strings), optional `message` after refs; same as AMP “Update test cases” (`[#+REF#]` markers).
|
|
71
74
|
- **submit_pen_test_review** – Record a completed Cursor AI pen test review: required `ampReference` and `scope` (branch, commits, files, or PR reviewed); optional `findings` (one per line, or `"None"`), `falsePositives` (`"N/A"` if none), `knownRisks` (`"N/A"` if none), `summary`. Posts a team comment with `[#PENTEST:COMPLETE#]` and sets review metadata on the work item.
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,69 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { ensureAccessToken, getAuthStatus } from "./auth.js";
|
|
10
10
|
import { callAmpTool } from "./tools.js";
|
|
11
|
+
const teamProgressValues = [
|
|
12
|
+
"Not started",
|
|
13
|
+
"TDD",
|
|
14
|
+
"Developing",
|
|
15
|
+
"Testing",
|
|
16
|
+
"Done",
|
|
17
|
+
"Blocked",
|
|
18
|
+
];
|
|
19
|
+
const stageValues = ["Test", "Local", "UAT", "Live", "Pre-Live"];
|
|
20
|
+
const createAmpSchema = z.object({
|
|
21
|
+
project: z
|
|
22
|
+
.string()
|
|
23
|
+
.min(1)
|
|
24
|
+
.describe("Project key (preferred) or GUID from get_user_projects"),
|
|
25
|
+
subject: z.string().min(1).describe("Work item subject/title"),
|
|
26
|
+
type: z.string().min(1).describe("Work item type (AMP-defined value)"),
|
|
27
|
+
priority: z.string().min(1).describe("Priority (AMP-defined value)"),
|
|
28
|
+
description: z.string().optional().describe("Optional description"),
|
|
29
|
+
url: z.string().optional().describe("Optional URL"),
|
|
30
|
+
note: z.string().optional().describe("Optional note"),
|
|
31
|
+
visualSpecLink: z.string().optional().describe("Optional visual spec link"),
|
|
32
|
+
linkedWorkItems: z
|
|
33
|
+
.array(z.string().min(1))
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Optional linked AMP references"),
|
|
36
|
+
parentAmpReference: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Optional parent AMP reference, e.g. '12345' or 'AMP-12345'"),
|
|
40
|
+
});
|
|
41
|
+
const addAmpUpdateSchema = z
|
|
42
|
+
.object({
|
|
43
|
+
ampReference: z.string().min(1).describe("e.g. '12345' or 'AMP-12345'"),
|
|
44
|
+
message: z.string().optional().describe("Team comment text"),
|
|
45
|
+
teamPercentageDone: z
|
|
46
|
+
.number()
|
|
47
|
+
.int()
|
|
48
|
+
.min(0)
|
|
49
|
+
.max(100)
|
|
50
|
+
.refine((n) => n % 10 === 0, "Must be a multiple of 10 (0, 10, …, 100)")
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("Team % done (0–100, step 10)"),
|
|
53
|
+
teamProgress: z
|
|
54
|
+
.enum(teamProgressValues)
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("Team progress: Not started, TDD, Developing, Testing, Done, Blocked"),
|
|
57
|
+
stage: z
|
|
58
|
+
.enum(stageValues)
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('Workflow stage; posts separate "Done on: {stage}" comment when changed'),
|
|
61
|
+
})
|
|
62
|
+
.superRefine((val, ctx) => {
|
|
63
|
+
const hasUpdate = (val.message !== undefined && val.message.trim().length > 0) ||
|
|
64
|
+
val.teamPercentageDone !== undefined ||
|
|
65
|
+
val.teamProgress !== undefined ||
|
|
66
|
+
val.stage !== undefined;
|
|
67
|
+
if (!hasUpdate) {
|
|
68
|
+
ctx.addIssue({
|
|
69
|
+
code: z.ZodIssueCode.custom,
|
|
70
|
+
message: "Provide at least one of message, teamPercentageDone, teamProgress, or stage.",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
11
74
|
const submitAmpProgressUpdateSchema = z
|
|
12
75
|
.object({
|
|
13
76
|
ampReference: z.string().min(1).describe("e.g. '12345' or 'AMP-12345'"),
|
|
@@ -51,8 +114,8 @@ async function main() {
|
|
|
51
114
|
],
|
|
52
115
|
};
|
|
53
116
|
});
|
|
54
|
-
// get_projects –
|
|
55
|
-
server.tool("get_projects", "
|
|
117
|
+
// get_projects – legacy global project search (not user-scoped)
|
|
118
|
+
server.tool("get_projects", "Legacy: global search of non-archived AMP projects (id + name only, not scoped to the current user). Prefer get_user_projects for create_amp flows.", {
|
|
56
119
|
searchTerm: z.string().optional().describe("Optional search term to filter projects by name or ID"),
|
|
57
120
|
limit: z.number().optional().describe("Maximum number of projects to return (default: 100)"),
|
|
58
121
|
}, async ({ searchTerm, limit, }) => {
|
|
@@ -64,6 +127,11 @@ async function main() {
|
|
|
64
127
|
args.limit = limit;
|
|
65
128
|
return callAmpTool("get_projects", args, token);
|
|
66
129
|
});
|
|
130
|
+
// get_user_projects – projects the authenticated user can use
|
|
131
|
+
server.tool("get_user_projects", "List non-archived projects the authenticated user belongs to (id, key, name), ordered by key. Use before create_amp to pick a valid project key or GUID.", {}, async () => {
|
|
132
|
+
const token = await ensureAccessToken();
|
|
133
|
+
return callAmpTool("get_user_projects", {}, token);
|
|
134
|
+
});
|
|
67
135
|
// get_amp_item_with_test_cases – ensure token, then call AMP
|
|
68
136
|
server.tool("get_amp_item_with_test_cases", "Get AMP (work item) details and all its test case references for a given AMP item. Use the reference number (e.g. 12345) or AMP-12345 format. Returns subject, note, status, progress (workflow stage), teamPercentageDone (team board % done, 0–100 in steps of 10), project, pen test review status (hasPenTestReview, penTestReviewCompleted, penTestReviewCompletedBy, penTestReviewCommentId), and a list of test case references (e.g. +AVFD) with the comment they appear in.", {
|
|
69
137
|
ampReference: z.string().describe("AMP item reference number, e.g. '12345' or 'AMP-12345'"),
|
|
@@ -71,6 +139,86 @@ async function main() {
|
|
|
71
139
|
const token = await ensureAccessToken();
|
|
72
140
|
return callAmpTool("get_amp_item_with_test_cases", { ampReference }, token);
|
|
73
141
|
});
|
|
142
|
+
// create_amp – new work item (status New)
|
|
143
|
+
server.tool("create_amp", "Create a new AMP work item with status New. Required project is a project key (preferred) or GUID from get_user_projects. User must belong to the project. Extension items add Team + Client column comments automatically.", {
|
|
144
|
+
project: z
|
|
145
|
+
.string()
|
|
146
|
+
.min(1)
|
|
147
|
+
.describe("Project key (preferred) or GUID from get_user_projects"),
|
|
148
|
+
subject: z.string().min(1).describe("Work item subject/title"),
|
|
149
|
+
type: z.string().min(1).describe("Work item type (AMP-defined value)"),
|
|
150
|
+
priority: z.string().min(1).describe("Priority (AMP-defined value)"),
|
|
151
|
+
description: z.string().optional().describe("Optional description"),
|
|
152
|
+
url: z.string().optional().describe("Optional URL"),
|
|
153
|
+
note: z.string().optional().describe("Optional note"),
|
|
154
|
+
visualSpecLink: z
|
|
155
|
+
.string()
|
|
156
|
+
.optional()
|
|
157
|
+
.describe("Optional visual spec link"),
|
|
158
|
+
linkedWorkItems: z
|
|
159
|
+
.array(z.string().min(1))
|
|
160
|
+
.optional()
|
|
161
|
+
.describe("Optional linked AMP references"),
|
|
162
|
+
parentAmpReference: z
|
|
163
|
+
.string()
|
|
164
|
+
.optional()
|
|
165
|
+
.describe("Optional parent AMP reference, e.g. '12345' or 'AMP-12345'"),
|
|
166
|
+
}, async (raw) => {
|
|
167
|
+
const parsed = createAmpSchema.parse(raw);
|
|
168
|
+
const token = await ensureAccessToken();
|
|
169
|
+
const args = {
|
|
170
|
+
project: parsed.project,
|
|
171
|
+
subject: parsed.subject,
|
|
172
|
+
type: parsed.type,
|
|
173
|
+
priority: parsed.priority,
|
|
174
|
+
};
|
|
175
|
+
if (parsed.description !== undefined)
|
|
176
|
+
args.description = parsed.description;
|
|
177
|
+
if (parsed.url !== undefined)
|
|
178
|
+
args.url = parsed.url;
|
|
179
|
+
if (parsed.note !== undefined)
|
|
180
|
+
args.note = parsed.note;
|
|
181
|
+
if (parsed.visualSpecLink !== undefined)
|
|
182
|
+
args.visualSpecLink = parsed.visualSpecLink;
|
|
183
|
+
if (parsed.linkedWorkItems !== undefined)
|
|
184
|
+
args.linkedWorkItems = parsed.linkedWorkItems;
|
|
185
|
+
if (parsed.parentAmpReference !== undefined)
|
|
186
|
+
args.parentAmpReference = parsed.parentAmpReference;
|
|
187
|
+
return callAmpTool("create_amp", args, token);
|
|
188
|
+
});
|
|
189
|
+
// add_amp_update – team-column update (Form_EnterComment team fields)
|
|
190
|
+
server.tool("add_amp_update", 'Post a team-column update on an AMP item (mirrors Form_EnterComment team fields except assignees and attachments). At least one of message, teamPercentageDone, teamProgress, or stage required. Changing stage posts a separate "Done on: {stage}" comment.', {
|
|
191
|
+
ampReference: z.string().min(1).describe("e.g. '12345' or 'AMP-12345'"),
|
|
192
|
+
message: z.string().optional().describe("Team comment text"),
|
|
193
|
+
teamPercentageDone: z
|
|
194
|
+
.number()
|
|
195
|
+
.int()
|
|
196
|
+
.min(0)
|
|
197
|
+
.max(100)
|
|
198
|
+
.optional()
|
|
199
|
+
.describe("Team % done (0–100, step 10)"),
|
|
200
|
+
teamProgress: z
|
|
201
|
+
.enum(teamProgressValues)
|
|
202
|
+
.optional()
|
|
203
|
+
.describe("Team progress: Not started, TDD, Developing, Testing, Done, Blocked"),
|
|
204
|
+
stage: z
|
|
205
|
+
.enum(stageValues)
|
|
206
|
+
.optional()
|
|
207
|
+
.describe('Workflow stage; posts separate "Done on: {stage}" comment when changed'),
|
|
208
|
+
}, async (raw) => {
|
|
209
|
+
const parsed = addAmpUpdateSchema.parse(raw);
|
|
210
|
+
const token = await ensureAccessToken();
|
|
211
|
+
const args = { ampReference: parsed.ampReference };
|
|
212
|
+
if (parsed.message !== undefined && parsed.message.trim() !== "")
|
|
213
|
+
args.message = parsed.message.trim();
|
|
214
|
+
if (parsed.teamPercentageDone !== undefined)
|
|
215
|
+
args.teamPercentageDone = parsed.teamPercentageDone;
|
|
216
|
+
if (parsed.teamProgress !== undefined)
|
|
217
|
+
args.teamProgress = parsed.teamProgress;
|
|
218
|
+
if (parsed.stage !== undefined)
|
|
219
|
+
args.stage = parsed.stage;
|
|
220
|
+
return callAmpTool("add_amp_update", args, token);
|
|
221
|
+
});
|
|
74
222
|
// submit_amp_progress_update – team board % done and/or team comment (AMP MCPServer parity)
|
|
75
223
|
server.tool("submit_amp_progress_update", "Update the AMP team board: set team % done (0, 10, …, 100) and/or append a team-column comment. Not the same as workflow progress. At least one of teamPercentageDone or a non-empty message is required.", {
|
|
76
224
|
ampReference: z.string().min(1).describe("e.g. '12345' or 'AMP-12345'"),
|
package/dist/tools.js
CHANGED
|
@@ -6,7 +6,7 @@ import { getAmpBaseUrl } from "./auth.js";
|
|
|
6
6
|
export const TOOL_DEFINITIONS = [
|
|
7
7
|
{
|
|
8
8
|
name: "get_projects",
|
|
9
|
-
description: "
|
|
9
|
+
description: "Legacy: global search of non-archived AMP projects (id + name only, not scoped to the current user). Prefer get_user_projects for create_amp flows.",
|
|
10
10
|
inputSchema: {
|
|
11
11
|
type: "object",
|
|
12
12
|
properties: {
|
|
@@ -35,6 +35,95 @@ export const TOOL_DEFINITIONS = [
|
|
|
35
35
|
required: ["ampReference"],
|
|
36
36
|
},
|
|
37
37
|
},
|
|
38
|
+
{
|
|
39
|
+
name: "get_user_projects",
|
|
40
|
+
description: "List non-archived projects the authenticated user belongs to (id, key, name), ordered by key. Use before create_amp to pick a valid project key or GUID.",
|
|
41
|
+
inputSchema: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "create_amp",
|
|
48
|
+
description: "Create a new AMP work item with status New. Required project is a project key (preferred) or GUID from get_user_projects. User must belong to the project. Extension items add Team + Client column comments automatically.",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
project: {
|
|
53
|
+
type: "string",
|
|
54
|
+
description: "Project key (preferred) or GUID from get_user_projects",
|
|
55
|
+
},
|
|
56
|
+
subject: {
|
|
57
|
+
type: "string",
|
|
58
|
+
description: "Work item subject/title",
|
|
59
|
+
},
|
|
60
|
+
type: {
|
|
61
|
+
type: "string",
|
|
62
|
+
description: "Work item type (AMP-defined value)",
|
|
63
|
+
},
|
|
64
|
+
priority: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: "Priority (AMP-defined value)",
|
|
67
|
+
},
|
|
68
|
+
description: {
|
|
69
|
+
type: "string",
|
|
70
|
+
description: "Optional description",
|
|
71
|
+
},
|
|
72
|
+
url: {
|
|
73
|
+
type: "string",
|
|
74
|
+
description: "Optional URL",
|
|
75
|
+
},
|
|
76
|
+
note: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "Optional note",
|
|
79
|
+
},
|
|
80
|
+
visualSpecLink: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "Optional visual spec link",
|
|
83
|
+
},
|
|
84
|
+
linkedWorkItems: {
|
|
85
|
+
type: "array",
|
|
86
|
+
items: { type: "string" },
|
|
87
|
+
description: "Optional linked AMP references",
|
|
88
|
+
},
|
|
89
|
+
parentAmpReference: {
|
|
90
|
+
type: "string",
|
|
91
|
+
description: "Optional parent AMP reference, e.g. '12345' or 'AMP-12345'",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
required: ["project", "subject", "type", "priority"],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "add_amp_update",
|
|
99
|
+
description: "Post a team-column update on an AMP item (mirrors Form_EnterComment team fields except assignees and attachments). At least one of message, teamPercentageDone, teamProgress, or stage required. Changing stage posts a separate \"Done on: {stage}\" comment.",
|
|
100
|
+
inputSchema: {
|
|
101
|
+
type: "object",
|
|
102
|
+
properties: {
|
|
103
|
+
ampReference: {
|
|
104
|
+
type: "string",
|
|
105
|
+
description: "e.g. '12345' or 'AMP-12345'",
|
|
106
|
+
},
|
|
107
|
+
message: {
|
|
108
|
+
type: "string",
|
|
109
|
+
description: "Team comment text",
|
|
110
|
+
},
|
|
111
|
+
teamPercentageDone: {
|
|
112
|
+
type: "number",
|
|
113
|
+
description: "Team % done; integer 0–100, multiple of 10",
|
|
114
|
+
},
|
|
115
|
+
teamProgress: {
|
|
116
|
+
type: "string",
|
|
117
|
+
description: "Team progress: Not started, TDD, Developing, Testing, Done, or Blocked",
|
|
118
|
+
},
|
|
119
|
+
stage: {
|
|
120
|
+
type: "string",
|
|
121
|
+
description: "Workflow stage: Test, Local, UAT, Live, or Pre-Live",
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
required: ["ampReference"],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
38
127
|
{
|
|
39
128
|
name: "submit_amp_progress_update",
|
|
40
129
|
description: "Set team board % done (0–100, multiple of 10) and/or append a team-column comment. At least one of teamPercentageDone or non-empty message required. If only teamPercentageDone is sent, AMP sets comment text to \"{n}% completed\".",
|