specguard-mcp 0.1.7 → 0.1.9
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 +22 -13
- package/dist/src/tools/add-repository-member.d.ts +6 -5
- package/dist/src/tools/add-repository-member.js +11 -9
- package/dist/src/tools/add-repository-member.js.map +1 -1
- package/dist/src/tools/index.d.ts +6 -6
- package/dist/src/tools/index.js +6 -6
- package/dist/src/tools/list-repository-members.d.ts +15 -12
- package/dist/src/tools/list-repository-members.js +21 -16
- package/dist/src/tools/list-repository-members.js.map +1 -1
- package/dist/src/tools/remove-repository-member.js +12 -5
- package/dist/src/tools/remove-repository-member.js.map +1 -1
- package/dist/src/tools/update-repository-member-permissions.d.ts +7 -6
- package/dist/src/tools/update-repository-member-permissions.js +17 -11
- package/dist/src/tools/update-repository-member-permissions.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -541,8 +541,9 @@ It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repo
|
|
|
541
541
|
|
|
542
542
|
### `list_repository_members`
|
|
543
543
|
|
|
544
|
-
Lists who has access to a SpecGuard repository: one row per member with their `
|
|
545
|
-
|
|
544
|
+
Lists who has access to a SpecGuard repository: one row per member with their `id` (the
|
|
545
|
+
**membership id** `update_repository_member_permissions` and `remove_repository_member` name),
|
|
546
|
+
`handle`, `permissions`, `granted_by` (who last set them) and `created_at`, ordered by handle.
|
|
546
547
|
|
|
547
548
|
| argument | |
|
|
548
549
|
| --- | --- |
|
|
@@ -550,7 +551,9 @@ Lists who has access to a SpecGuard repository: one row per member with their `h
|
|
|
550
551
|
|
|
551
552
|
The list answers **memberships only** and never reports how many CI keys a member has minted
|
|
552
553
|
(`keys_minted`) — that is a separate `keys.manage` disclosure this endpoint deliberately withholds;
|
|
553
|
-
the API-keys tools are the surface for it.
|
|
554
|
+
the API-keys tools are the surface for it. Each row's `id` is the membership id — the identifier
|
|
555
|
+
`update_repository_member_permissions` and `remove_repository_member` name; ids are scoped to the
|
|
556
|
+
repository, and a foreign id is refused `404`.
|
|
554
557
|
|
|
555
558
|
Authorization is the `members.manage` capability: a caller who is not a member is refused `404`
|
|
556
559
|
(the repository's existence stays hidden), and a member without `members.manage` is refused `403`
|
|
@@ -575,9 +578,11 @@ handle is ambiguous, the handle is not a login — arrives as a **distinguishabl
|
|
|
575
578
|
naming the exact next move. The grantor recorded on the membership is always the person behind
|
|
576
579
|
`SPECGUARD_USER_API_KEY`; no argument can name a different one.
|
|
577
580
|
|
|
578
|
-
On success (`201`) the response carries a `member` block
|
|
579
|
-
`created_at`) —
|
|
580
|
-
|
|
581
|
+
On success (`201`) the response carries a `member` block whose **`id` is the membership id**
|
|
582
|
+
(alongside `handle`, `permissions`, `granted_by`, `created_at`) — the identifier
|
|
583
|
+
`update_repository_member_permissions` and `remove_repository_member` name. Authorization is the
|
|
584
|
+
`members.manage` capability; a member without it is refused `403` with SpecGuard's own sentence,
|
|
585
|
+
verbatim.
|
|
581
586
|
|
|
582
587
|
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
583
588
|
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
@@ -595,9 +600,12 @@ Replaces one member's permission set on a SpecGuard repository.
|
|
|
595
600
|
**`permissions` replaces the whole set** — name every permission the member should end with.
|
|
596
601
|
Values are validated by SpecGuard; an unknown value is refused with its own sentence, verbatim.
|
|
597
602
|
|
|
598
|
-
**
|
|
599
|
-
|
|
600
|
-
|
|
603
|
+
**The membership id:** `member_id` comes straight off the API — every member response serves it
|
|
604
|
+
as `id`: the rows `list_repository_members` returns, the `add_repository_member` 201 body, and
|
|
605
|
+
this tool's own response. The server serves that `id` as a JSON number (the column is a bigint),
|
|
606
|
+
while `member_id` is a string argument refused by name before any request is made — pass a
|
|
607
|
+
numeric-looking id such as `7` as a string, not as a number. There is no name-based lookup, and
|
|
608
|
+
ids are scoped to the repository (a foreign id is refused `404`). Authorization is the
|
|
601
609
|
`members.manage` capability; a member without it is refused `403` with SpecGuard's own sentence,
|
|
602
610
|
verbatim.
|
|
603
611
|
|
|
@@ -618,10 +626,11 @@ it is revoked.
|
|
|
618
626
|
repository keep authenticating by design; the lever for those is the API-keys surface
|
|
619
627
|
(`revoke_repository_api_key`), not this one. Self-revocation is permitted — after it, the caller's
|
|
620
628
|
next request to the member routes answers `404`, not `403`. The repository owner's membership
|
|
621
|
-
cannot be removed at all. The same
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
629
|
+
cannot be removed at all. The same source as the edit tool serves `member_id`: it is the `id`
|
|
630
|
+
field on the member rows `list_repository_members` and `add_repository_member` return — a JSON
|
|
631
|
+
number on the wire, so pass it as a string, not as a number (see the edit tool above).
|
|
632
|
+
Authorization is the `members.manage` capability; a member without it is refused `403` with
|
|
633
|
+
SpecGuard's own sentence, verbatim.
|
|
625
634
|
|
|
626
635
|
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
627
636
|
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
@@ -20,12 +20,13 @@ import type { ToolDefinition } from "./types.js";
|
|
|
20
20
|
* deliberately absent from the permitted params. The tool therefore takes no
|
|
21
21
|
* grantor argument, and no caller can name one.
|
|
22
22
|
*
|
|
23
|
-
* == The 201 body
|
|
23
|
+
* == The 201 body carries the membership id
|
|
24
24
|
*
|
|
25
|
-
* `#serialize` serves `handle`, `permissions`, `granted_by`,
|
|
26
|
-
* and
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* `#serialize` serves `id`, `handle`, `permissions`, `granted_by`,
|
|
26
|
+
* `created_at` — and the `id` is the MEMBERSHIP id, the very identifier
|
|
27
|
+
* `update_repository_member_permissions` and `remove_repository_member` name.
|
|
28
|
+
* It is not portable: lookup is scoped through the repository, so a foreign
|
|
29
|
+
* id is refused 404 server-side.
|
|
29
30
|
*/
|
|
30
31
|
declare const addRepositoryMember: ToolDefinition;
|
|
31
32
|
export default addRepositoryMember;
|
|
@@ -21,12 +21,13 @@ import { optionalStringArray, requireString } from "./args.js";
|
|
|
21
21
|
* deliberately absent from the permitted params. The tool therefore takes no
|
|
22
22
|
* grantor argument, and no caller can name one.
|
|
23
23
|
*
|
|
24
|
-
* == The 201 body
|
|
24
|
+
* == The 201 body carries the membership id
|
|
25
25
|
*
|
|
26
|
-
* `#serialize` serves `handle`, `permissions`, `granted_by`,
|
|
27
|
-
* and
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* `#serialize` serves `id`, `handle`, `permissions`, `granted_by`,
|
|
27
|
+
* `created_at` — and the `id` is the MEMBERSHIP id, the very identifier
|
|
28
|
+
* `update_repository_member_permissions` and `remove_repository_member` name.
|
|
29
|
+
* It is not portable: lookup is scoped through the repository, so a foreign
|
|
30
|
+
* id is refused 404 server-side.
|
|
30
31
|
*/
|
|
31
32
|
const addRepositoryMember = {
|
|
32
33
|
name: "add_repository_member",
|
|
@@ -39,10 +40,11 @@ const addRepositoryMember = {
|
|
|
39
40
|
"arrives as a distinguishable 400 message naming the exact next move. " +
|
|
40
41
|
"The grantor recorded on the membership is always the person behind this server's user API " +
|
|
41
42
|
"key — the server stamps it, and no argument can name a different one. " +
|
|
42
|
-
"On success (201) the response carries a `member` block
|
|
43
|
-
"`granted_by`, `created_at`)
|
|
44
|
-
"
|
|
45
|
-
"
|
|
43
|
+
"On success (201) the response carries a `member` block whose `id` is the MEMBERSHIP id " +
|
|
44
|
+
"(`handle`, `permissions`, `granted_by`, `created_at` alongside) — the very identifier " +
|
|
45
|
+
"`update_repository_member_permissions` and `remove_repository_member` name. The id is not " +
|
|
46
|
+
"portable between repositories (a foreign id is refused 404), so use it within this " +
|
|
47
|
+
"repository. " +
|
|
46
48
|
"Permissions are strings from SpecGuard's own set (`view`, `keys.manage`, `members.manage`, " +
|
|
47
49
|
"`repo.delete`); an unknown value is refused in SpecGuard's own words, and omitting the " +
|
|
48
50
|
"list grants access with no additional permissions. The repository owner cannot be added " +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-repository-member.js","sourceRoot":"","sources":["../../../src/tools/add-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/D
|
|
1
|
+
{"version":3,"file":"add-repository-member.js","sourceRoot":"","sources":["../../../src/tools/add-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,mBAAmB,GAAmB;IAC1C,IAAI,EAAE,uBAAuB;IAC7B,KAAK,EAAE,uBAAuB;IAC9B,WAAW,EACT,4FAA4F;QAC5F,uBAAuB;QACvB,0FAA0F;QAC1F,4FAA4F;QAC5F,8FAA8F;QAC9F,uEAAuE;QACvE,4FAA4F;QAC5F,wEAAwE;QACxE,yFAAyF;QACzF,wFAAwF;QACxF,4FAA4F;QAC5F,qFAAqF;QACrF,cAAc;QACd,6FAA6F;QAC7F,yFAAyF;QACzF,0FAA0F;QAC1F,0CAA0C;QAC1C,2FAA2F;QAC3F,yBAAyB;QACzB,yFAAyF;QACzF,UAAU;QACV,oFAAoF;QACpF,+FAA+F;IACjG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,0EAA0E;oBAC1E,qEAAqE;aACxE;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,sFAAsF;oBACtF,mFAAmF;oBACnF,uCAAuC;aAC1C;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,WAAW,EACT,2EAA2E;oBAC3E,mFAAmF;oBACnF,oFAAoF;oBACpF,mBAAmB;aACtB;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC;QACrC,4EAA4E;QAC5E,wEAAwE;QACxE,oCAAoC;QACpC,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC;QAC3E,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC;QAE5E,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,wEAAwE;QACxE,yEAAyE;QACzE,0EAA0E;QAC1E,0EAA0E;QAC1E,uEAAuE;QACvE,MAAM,OAAO,GAAG,MAAM,cAAc,CAClC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,UAAU,EAClE,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAChE,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,yDAAyD;QACzD,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,UAAU,EAAE,OAAO;SACpB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -124,12 +124,12 @@ import type { ToolDefinition } from "./types.js";
|
|
|
124
124
|
* routes through `requestJson` like `postJson` rather than `deleteJson`'s
|
|
125
125
|
* raw-body handling.
|
|
126
126
|
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* name-based lookup.
|
|
127
|
+
* PATCH and DELETE name a membership by id, and the platform serves that id on
|
|
128
|
+
* every member response (SPGD-894): the list, the add 201 and the edit 200 all
|
|
129
|
+
* carry it, so an agent that listed or added a member already holds it — the
|
|
130
|
+
* edit/revoke tool descriptions say so rather than leaving it implicit. Lookup
|
|
131
|
+
* stays scoped to the repository (a foreign id is refused 404), and there is
|
|
132
|
+
* no name-based lookup.
|
|
133
133
|
*
|
|
134
134
|
* == The thirteenth: rename
|
|
135
135
|
*
|
package/dist/src/tools/index.js
CHANGED
|
@@ -137,12 +137,12 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
137
137
|
* routes through `requestJson` like `postJson` rather than `deleteJson`'s
|
|
138
138
|
* raw-body handling.
|
|
139
139
|
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* name-based lookup.
|
|
140
|
+
* PATCH and DELETE name a membership by id, and the platform serves that id on
|
|
141
|
+
* every member response (SPGD-894): the list, the add 201 and the edit 200 all
|
|
142
|
+
* carry it, so an agent that listed or added a member already holds it — the
|
|
143
|
+
* edit/revoke tool descriptions say so rather than leaving it implicit. Lookup
|
|
144
|
+
* stays scoped to the repository (a foreign id is refused 404), and there is
|
|
145
|
+
* no name-based lookup.
|
|
146
146
|
*
|
|
147
147
|
* == The thirteenth: rename
|
|
148
148
|
*
|
|
@@ -6,20 +6,23 @@ import type { ToolDefinition } from "./types.js";
|
|
|
6
6
|
*
|
|
7
7
|
* == Memberships only, never `keys_minted`
|
|
8
8
|
*
|
|
9
|
-
* The endpoint answers
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* The endpoint answers five fields per row — `id`, `handle`, `permissions`,
|
|
10
|
+
* `granted_by`, `created_at`, ordered by handle — and deliberately NOTHING
|
|
11
|
+
* else. Four of the five are the rows the web members page renders
|
|
12
|
+
* (`handle`, `permissions`, `granted_by`, `created_at`, under the same
|
|
13
|
+
* names); `id` is served to the API caller alone — that page has no id
|
|
14
|
+
* column, the id appears there only inside edit and revoke links.
|
|
15
|
+
* `keys_minted` is a `keys.manage` disclosure
|
|
16
|
+
* that page gates separately; this read answers memberships to a
|
|
17
|
+
* `members.manage` holder and no more. A tool that promised counts here would
|
|
18
|
+
* be promising something the endpoint refuses to say.
|
|
15
19
|
*
|
|
16
|
-
* ==
|
|
20
|
+
* == The membership `id` is served
|
|
17
21
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* where the id comes from today.
|
|
22
|
+
* Each row's `id` is the MEMBERSHIP id — the very identifier
|
|
23
|
+
* `update_repository_member_permissions` and `remove_repository_member` name.
|
|
24
|
+
* The id is not portable: lookup is scoped through the repository, so a
|
|
25
|
+
* foreign id is refused 404 server-side, and there is no name-based lookup.
|
|
23
26
|
*
|
|
24
27
|
* == No client-side capability probing
|
|
25
28
|
*
|
|
@@ -7,20 +7,23 @@ import { requireString } from "./args.js";
|
|
|
7
7
|
*
|
|
8
8
|
* == Memberships only, never `keys_minted`
|
|
9
9
|
*
|
|
10
|
-
* The endpoint answers
|
|
11
|
-
* `
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* The endpoint answers five fields per row — `id`, `handle`, `permissions`,
|
|
11
|
+
* `granted_by`, `created_at`, ordered by handle — and deliberately NOTHING
|
|
12
|
+
* else. Four of the five are the rows the web members page renders
|
|
13
|
+
* (`handle`, `permissions`, `granted_by`, `created_at`, under the same
|
|
14
|
+
* names); `id` is served to the API caller alone — that page has no id
|
|
15
|
+
* column, the id appears there only inside edit and revoke links.
|
|
16
|
+
* `keys_minted` is a `keys.manage` disclosure
|
|
17
|
+
* that page gates separately; this read answers memberships to a
|
|
18
|
+
* `members.manage` holder and no more. A tool that promised counts here would
|
|
19
|
+
* be promising something the endpoint refuses to say.
|
|
16
20
|
*
|
|
17
|
-
* ==
|
|
21
|
+
* == The membership `id` is served
|
|
18
22
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* where the id comes from today.
|
|
23
|
+
* Each row's `id` is the MEMBERSHIP id — the very identifier
|
|
24
|
+
* `update_repository_member_permissions` and `remove_repository_member` name.
|
|
25
|
+
* The id is not portable: lookup is scoped through the repository, so a
|
|
26
|
+
* foreign id is refused 404 server-side, and there is no name-based lookup.
|
|
24
27
|
*
|
|
25
28
|
* == No client-side capability probing
|
|
26
29
|
*
|
|
@@ -32,8 +35,9 @@ import { requireString } from "./args.js";
|
|
|
32
35
|
const listRepositoryMembers = {
|
|
33
36
|
name: "list_repository_members",
|
|
34
37
|
title: "List repository members",
|
|
35
|
-
description: "Lists who has access to a SpecGuard repository: one row per member with their `
|
|
36
|
-
"
|
|
38
|
+
description: "Lists who has access to a SpecGuard repository: one row per member with their `id` (the " +
|
|
39
|
+
"MEMBERSHIP id `update_repository_member_permissions` and `remove_repository_member` name), " +
|
|
40
|
+
"`handle`, `permissions`, `granted_by` (who last set them) and `created_at`, ordered by handle. " +
|
|
37
41
|
"The list answers MEMBERSHIPS only and never reports how many CI keys a member has minted " +
|
|
38
42
|
"(`keys_minted`) — that is a separate `keys.manage` disclosure this endpoint deliberately " +
|
|
39
43
|
"withholds, and the API-keys tools are the surface for it. " +
|
|
@@ -64,8 +68,9 @@ const listRepositoryMembers = {
|
|
|
64
68
|
const api = requireUserApiConfig(context.config);
|
|
65
69
|
const members = await getJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/members`, {}, context.fetch);
|
|
66
70
|
// Passed through unreshaped, the standing rule (`types.ts`: "A thin client
|
|
67
|
-
// that reshapes its upstream is not thin") —
|
|
68
|
-
//
|
|
71
|
+
// that reshapes its upstream is not thin") — five fields per row, four of
|
|
72
|
+
// them the same columns the web members page renders; `id` is served to
|
|
73
|
+
// the API caller alone, that page has no id column.
|
|
69
74
|
return {
|
|
70
75
|
text: JSON.stringify(members, null, 2),
|
|
71
76
|
structured: members,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-repository-members.js","sourceRoot":"","sources":["../../../src/tools/list-repository-members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C
|
|
1
|
+
{"version":3,"file":"list-repository-members.js","sourceRoot":"","sources":["../../../src/tools/list-repository-members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,qBAAqB,GAAmB;IAC5C,IAAI,EAAE,yBAAyB;IAC/B,KAAK,EAAE,yBAAyB;IAChC,WAAW,EACT,0FAA0F;QAC1F,6FAA6F;QAC7F,iGAAiG;QACjG,2FAA2F;QAC3F,2FAA2F;QAC3F,4DAA4D;QAC5D,wFAAwF;QACxF,4FAA4F;QAC5F,4DAA4D;QAC5D,yFAAyF;QACzF,UAAU;QACV,uFAAuF;QACvF,yFAAyF;IAC3F,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,6EAA6E;oBAC7E,qEAAqE;aACxE;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,qEAAqE;QACrE,6EAA6E;QAC7E,uBAAuB;QACvB,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC;QAE3E,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,UAAU,EAClE,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,0EAA0E;QAC1E,wEAAwE;QACxE,oDAAoD;QACpD,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,UAAU,EAAE,OAAO;SACpB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -41,9 +41,13 @@ const removeRepositoryMember = {
|
|
|
41
41
|
"request to the member routes answers 404 — a former member is a non-member, so this tool " +
|
|
42
42
|
"cannot read the repository's members afterwards. The repository owner's membership cannot " +
|
|
43
43
|
"be removed at all (an owner holds everything by construction). " +
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
44
|
+
"The membership id comes straight off the API: every member response carries it as `id` — " +
|
|
45
|
+
"the rows `list_repository_members` serves, the `add_repository_member` 201 body, and " +
|
|
46
|
+
"`update_repository_member_permissions`'s response — so a member you listed or added has " +
|
|
47
|
+
"already handed you the id. The server serves that `id` as a JSON number (a bigint column) " +
|
|
48
|
+
"while `member_id` is a string argument refused by name (\"`member_id` must be a string.\") " +
|
|
49
|
+
"before any request is made — so pass a numeric-looking id such as `7` as a string, not as " +
|
|
50
|
+
"a number. " +
|
|
47
51
|
"Authorization is the `members.manage` capability — a member without it is refused 403 in " +
|
|
48
52
|
"SpecGuard's own words. A 204 means the membership is revoked. " +
|
|
49
53
|
"Takes `repository_id` — the numeric id `list_repositories` reports, not the `org/repo` " +
|
|
@@ -61,8 +65,11 @@ const removeRepositoryMember = {
|
|
|
61
65
|
member_id: {
|
|
62
66
|
type: "string",
|
|
63
67
|
description: "The id of the MEMBERSHIP row to revoke — not a user id, and not the handle. " +
|
|
64
|
-
"Scoped to `repository_id`: a foreign membership id is refused 404.
|
|
65
|
-
"
|
|
68
|
+
"Scoped to `repository_id`: a foreign membership id is refused 404. Take it from " +
|
|
69
|
+
"the `id` field of a member row served by `list_repository_members`, " +
|
|
70
|
+
"`add_repository_member` or `update_repository_member_permissions` — the server " +
|
|
71
|
+
"serves that id as a JSON number, so pass it on as a string, not as a number " +
|
|
72
|
+
"(\"7\", not 7).",
|
|
66
73
|
},
|
|
67
74
|
},
|
|
68
75
|
required: ["repository_id", "member_id"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-repository-member.js","sourceRoot":"","sources":["../../../src/tools/remove-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,sBAAsB,GAAmB;IAC7C,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,WAAW,EACT,sFAAsF;QACtF,kFAAkF;QAClF,uFAAuF;QACvF,mCAAmC;QACnC,yFAAyF;QACzF,uFAAuF;QACvF,uDAAuD;QACvD,yFAAyF;QACzF,2FAA2F;QAC3F,4FAA4F;QAC5F,iEAAiE;QACjE,uFAAuF;QACvF,
|
|
1
|
+
{"version":3,"file":"remove-repository-member.js","sourceRoot":"","sources":["../../../src/tools/remove-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,sBAAsB,GAAmB;IAC7C,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,WAAW,EACT,sFAAsF;QACtF,kFAAkF;QAClF,uFAAuF;QACvF,mCAAmC;QACnC,yFAAyF;QACzF,uFAAuF;QACvF,uDAAuD;QACvD,yFAAyF;QACzF,2FAA2F;QAC3F,4FAA4F;QAC5F,iEAAiE;QACjE,2FAA2F;QAC3F,uFAAuF;QACvF,0FAA0F;QAC1F,4FAA4F;QAC5F,6FAA6F;QAC7F,4FAA4F;QAC5F,YAAY;QACZ,2FAA2F;QAC3F,gEAAgE;QAChE,yFAAyF;QACzF,UAAU;QACV,oFAAoF;QACpF,+FAA+F;IACjG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,iFAAiF;oBACjF,qEAAqE;aACxE;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,8EAA8E;oBAC9E,kFAAkF;oBAClF,sEAAsE;oBACtE,iFAAiF;oBACjF,8EAA8E;oBAC9E,iBAAiB;aACpB;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,WAAW,CAAC;QACxC,4EAA4E;QAC5E,uEAAuE;QACvE,gEAAgE;QAChE,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC;QAE/D,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,YAAY,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAClG,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,0EAA0E;QAC1E,2EAA2E;QAC3E,+DAA+D;QAC/D,OAAO;YACL,IAAI,EACF,IAAI,KAAK,EAAE;gBACT,CAAC,CAAC,cAAc,QAAQ,uDAAuD;oBAC7E,gEAAgE;oBAChE,kDAAkD;gBACpD,CAAC,CAAC,IAAI;YACV,UAAU,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;SAChF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -18,13 +18,14 @@ import type { ToolDefinition } from "./types.js";
|
|
|
18
18
|
* write. The bridge adds no client-side check of that scoping: the server is
|
|
19
19
|
* the gate.
|
|
20
20
|
*
|
|
21
|
-
* ==
|
|
21
|
+
* == Where the id comes from
|
|
22
22
|
*
|
|
23
|
-
* `#serialize`
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
23
|
+
* `#serialize` serves the membership id on every member response — the list
|
|
24
|
+
* (`list_repository_members`), the 201 body (`add_repository_member`) and
|
|
25
|
+
* this tool's own 200 body — so an agent that listed or added a member
|
|
26
|
+
* already holds the id this call names. There is no name-based lookup: the
|
|
27
|
+
* id comes off those responses, and lookup is scoped through the repository
|
|
28
|
+
* (a foreign id is refused 404).
|
|
28
29
|
*/
|
|
29
30
|
declare const updateRepositoryMemberPermissions: ToolDefinition;
|
|
30
31
|
export default updateRepositoryMemberPermissions;
|
|
@@ -19,13 +19,14 @@ import { requireString, requireStringArray } from "./args.js";
|
|
|
19
19
|
* write. The bridge adds no client-side check of that scoping: the server is
|
|
20
20
|
* the gate.
|
|
21
21
|
*
|
|
22
|
-
* ==
|
|
22
|
+
* == Where the id comes from
|
|
23
23
|
*
|
|
24
|
-
* `#serialize`
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* `#serialize` serves the membership id on every member response — the list
|
|
25
|
+
* (`list_repository_members`), the 201 body (`add_repository_member`) and
|
|
26
|
+
* this tool's own 200 body — so an agent that listed or added a member
|
|
27
|
+
* already holds the id this call names. There is no name-based lookup: the
|
|
28
|
+
* id comes off those responses, and lookup is scoped through the repository
|
|
29
|
+
* (a foreign id is refused 404).
|
|
29
30
|
*/
|
|
30
31
|
const updateRepositoryMemberPermissions = {
|
|
31
32
|
name: "update_repository_member_permissions",
|
|
@@ -38,9 +39,12 @@ const updateRepositoryMemberPermissions = {
|
|
|
38
39
|
"today, so name every permission the member should end with. Values are strings from " +
|
|
39
40
|
"SpecGuard's own set (`view`, `keys.manage`, `members.manage`, `repo.delete`); an unknown " +
|
|
40
41
|
"value is refused in SpecGuard's own words. " +
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
42
|
+
"The membership id comes straight off the API: every member response carries it as `id` — " +
|
|
43
|
+
"the rows `list_repository_members` serves, the `add_repository_member` 201 body, and this " +
|
|
44
|
+
"tool's own response — so a member you listed or added has already handed you the id. The " +
|
|
45
|
+
"server serves that `id` as a JSON number (a bigint column) while `member_id` is a string " +
|
|
46
|
+
"argument refused by name (\"`member_id` must be a string.\") before any request is made — " +
|
|
47
|
+
"so pass a numeric-looking id such as `7` as a string, not as a number. " +
|
|
44
48
|
"Authorization is the `members.manage` capability — a member without it is refused 403 in " +
|
|
45
49
|
"SpecGuard's own words. " +
|
|
46
50
|
"Takes `repository_id` — the numeric id `list_repositories` reports, not the `org/repo` " +
|
|
@@ -58,8 +62,10 @@ const updateRepositoryMemberPermissions = {
|
|
|
58
62
|
member_id: {
|
|
59
63
|
type: "string",
|
|
60
64
|
description: "The id of the MEMBERSHIP row to edit — not a user id, and not the handle. Scoped " +
|
|
61
|
-
"to `repository_id`: a foreign membership id is refused 404.
|
|
62
|
-
"
|
|
65
|
+
"to `repository_id`: a foreign membership id is refused 404. Take it from the `id` " +
|
|
66
|
+
"field of a member row served by `list_repository_members`, `add_repository_member` " +
|
|
67
|
+
"or this tool's own response — the server serves that id as a JSON number, so pass " +
|
|
68
|
+
"it on as a string, not as a number (\"7\", not 7).",
|
|
63
69
|
},
|
|
64
70
|
permissions: {
|
|
65
71
|
type: "array",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-repository-member-permissions.js","sourceRoot":"","sources":["../../../src/tools/update-repository-member-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAG9D
|
|
1
|
+
{"version":3,"file":"update-repository-member-permissions.js","sourceRoot":"","sources":["../../../src/tools/update-repository-member-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAG9D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,iCAAiC,GAAmB;IACxD,IAAI,EAAE,sCAAsC;IAC5C,KAAK,EAAE,sCAAsC;IAC7C,WAAW,EACT,yFAAyF;QACzF,0FAA0F;QAC1F,8EAA8E;QAC9E,0BAA0B;QAC1B,wFAAwF;QACxF,sFAAsF;QACtF,2FAA2F;QAC3F,6CAA6C;QAC7C,2FAA2F;QAC3F,4FAA4F;QAC5F,2FAA2F;QAC3F,2FAA2F;QAC3F,4FAA4F;QAC5F,yEAAyE;QACzE,2FAA2F;QAC3F,yBAAyB;QACzB,yFAAyF;QACzF,UAAU;QACV,oFAAoF;QACpF,+FAA+F;IACjG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,iFAAiF;oBACjF,qEAAqE;aACxE;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,mFAAmF;oBACnF,oFAAoF;oBACpF,qFAAqF;oBACrF,oFAAoF;oBACpF,oDAAoD;aACvD;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,WAAW,EACT,kFAAkF;oBAClF,mFAAmF;oBACnF,0CAA0C;aAC7C;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,WAAW,EAAE,aAAa,CAAC;QACvD,qEAAqE;QACrE,yEAAyE;QACzE,uEAAuE;QACvE,sBAAsB;QACtB,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC;QAC/D,0EAA0E;QAC1E,4EAA4E;QAC5E,2EAA2E;QAC3E,WAAW;QACX,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC;QAE3E,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAG,MAAM,eAAe,CACnC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,YAAY,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAClG,EAAE,WAAW,EAAE,EACf,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,4EAA4E;QAC5E,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,UAAU,EAAE,OAAO;SACpB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,iCAAiC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specguard-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "MCP server exposing SpecGuard suite intelligence to AI coding agents",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^20.19.0",
|
|
31
|
-
"specguard
|
|
31
|
+
"@yatfa/specguard": "^0.1.1",
|
|
32
32
|
"typescript": "^5.6.0"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|