@brightbeamai/chap-coordinator-mcp 0.3.3 → 0.3.5

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/dist/tools.d.cts CHANGED
@@ -48,5 +48,21 @@ interface ToolAnnotations {
48
48
  }
49
49
  /** Annotations for every tool, derived from the sets above. */
50
50
  declare const TOOL_ANNOTATIONS: Record<string, ToolAnnotations>;
51
+ /**
52
+ * The tools an agent's own connection offers: what its work needs, and
53
+ * nothing that chooses who reviews that work or passes its review on. The
54
+ * decision tools and review.acknowledge stay for work the agent is asked to
55
+ * review; on its own work the coordinator refuses them and records the
56
+ * attempt. Left out are workspace and membership changes, review.request
57
+ * (an explicit review may name its own author), escalate.raise (it passes
58
+ * the open review on to a successor task), and every other tool.
59
+ * task.update stays, and can take a task under review back to in_progress,
60
+ * which withdraws the draft; the next completion opens the review again, so
61
+ * a task that holds a review completes only through a decision.
62
+ *
63
+ * The stdio server offers this set by default. A server that gives an agent
64
+ * its own MCP connection, as the templates' /mcp does, imports it from here.
65
+ */
66
+ declare const AGENT_MCP_TOOLS: ReadonlySet<string>;
51
67
 
52
- export { TOOL_ANNOTATIONS, TOOL_DESCRIPTIONS, type ToolAnnotations };
68
+ export { AGENT_MCP_TOOLS, TOOL_ANNOTATIONS, TOOL_DESCRIPTIONS, type ToolAnnotations };
package/dist/tools.d.ts CHANGED
@@ -48,5 +48,21 @@ interface ToolAnnotations {
48
48
  }
49
49
  /** Annotations for every tool, derived from the sets above. */
50
50
  declare const TOOL_ANNOTATIONS: Record<string, ToolAnnotations>;
51
+ /**
52
+ * The tools an agent's own connection offers: what its work needs, and
53
+ * nothing that chooses who reviews that work or passes its review on. The
54
+ * decision tools and review.acknowledge stay for work the agent is asked to
55
+ * review; on its own work the coordinator refuses them and records the
56
+ * attempt. Left out are workspace and membership changes, review.request
57
+ * (an explicit review may name its own author), escalate.raise (it passes
58
+ * the open review on to a successor task), and every other tool.
59
+ * task.update stays, and can take a task under review back to in_progress,
60
+ * which withdraws the draft; the next completion opens the review again, so
61
+ * a task that holds a review completes only through a decision.
62
+ *
63
+ * The stdio server offers this set by default. A server that gives an agent
64
+ * its own MCP connection, as the templates' /mcp does, imports it from here.
65
+ */
66
+ declare const AGENT_MCP_TOOLS: ReadonlySet<string>;
51
67
 
52
- export { TOOL_ANNOTATIONS, TOOL_DESCRIPTIONS, type ToolAnnotations };
68
+ export { AGENT_MCP_TOOLS, TOOL_ANNOTATIONS, TOOL_DESCRIPTIONS, type ToolAnnotations };
package/dist/tools.js CHANGED
@@ -4,19 +4,21 @@ var TOOL_DESCRIPTIONS = {
4
4
  "chap.workspace.create": "Create a workspace: the container for the participants, tasks and audit log of one piece of collaborative work. Returns the workspace id, which every later call carries.",
5
5
  "chap.workspace.describe": "Report the current state of a workspace: its members, enabled profiles, audit length, and task and override counts.",
6
6
  "chap.workspace.set_profiles": "Replace the whole set of profiles enabled on a workspace. The list is not merged: any profile absent from it is dropped, so send the complete set you want. Enabling audit-scitt/1.0 on a workspace that already has entries starts the chain from that point and leaves the earlier entries permanently outside it, which chap.audit.verify_chain then reports as not_evaluated. Prefer setting profiles at chap.workspace.create, where no entries exist yet to strand.",
7
+ "chap.workspace.invite": "Invite a participant to a workspace, as its admin. The invitation names the type and role the member takes when it joins, and may pin its keys and its OIDC subject. A workspace whose join policy is 'invite' admits nobody else. For a member that holds no key in force, the call registers the keys it names at once, so a member whose keys were all revoked can sign again. Where a token or credential verifier is configured, an invitation names no keys for a person: their keys arrive with the token they join with (-32602).",
7
8
  "chap.participant.join": "Add a participant to a workspace. The type given, human, agent, service, group or workspace, decides whether they are eligible to review work that requires it.",
8
9
  "chap.participant.leave": "Remove a participant from a workspace. Entries they have already written stay in the audit log and their past signatures still verify, so leaving is not a way to withdraw a decision. They can no longer be assigned tasks or act as a reviewer, and returning means a fresh chap.participant.join.",
9
10
  "chap.task.create": "Create a task: a unit of work assigned to one participant. Set review_required to make completion depend on a reviewer decision rather than on the assignee. Returns a task_id that the rest of the lifecycle takes. Supplying idempotency_key is what makes a retry safe: a repeat carrying a key already seen returns the original task, while a repeat without one creates a second task. Assigning to a paused member is refused.",
10
- "chap.task.update": "Move a task to a new state. Only the transitions in the specification's lifecycle table are accepted, and a task that requires review cannot be completed here.",
11
+ "chap.task.update": "Move a task to a new state. Only the transitions in the specification's lifecycle table are accepted, and a task that requires review cannot be completed here. A task whose review no decision has closed, or a successor that carries one on, is not declined (-32602).",
11
12
  "chap.task.complete": "Submit a task's output. A task that requires review does not complete: the output is held as the artefact under review, the task moves to review_requested, and a reviewer decision completes it. Any other task completes immediately.",
12
13
  "chap.audit.read": "Read entries from a workspace's audit log, optionally within a sequence range and filtered by method, sender, task or outcome. This is the query surface for everything the workspace has recorded, decisions and overrides included. An accepted call is under 'envelope'. A refused attempt the coordinator recorded, such as a decision by someone the review was not addressed to, is under 'request' with an 'outcome' giving the error code, and it did not take effect. Reads only: it records nothing, so it never appears in its own output. Entries come back as recorded, without aggregation, so grouping them, by tag for instance, is the reader's job.",
13
14
  // review/1.0
14
- "chap.review.request": "Open a review on a task and address it to one or more reviewers. They then call chap.decide.approve, chap.decide.reject, chap.decide.override or chap.abstain.declare. Repeating the request with the same artefact adds reviewers to the open review.",
15
+ "chap.review.request": "Open a review on a task and address it to one or more reviewers. They then call chap.decide.approve, chap.decide.reject, chap.decide.override or chap.abstain.declare, and may first say they have begun with chap.review.acknowledge. Repeating the request with the same artefact adds reviewers to the open review. A task marked review_required is reviewed through chap.task.complete, which opens its review under the workspace's rule; on such a task this tool only adds people to a review already open, and before it opens is refused with -32011.",
16
+ "chap.review.acknowledge": "Say that this reviewer has begun the open review on a task, before deciding it. The call is recorded, so the audit log shows when each reviewer took the review up as well as when they decided. It decides nothing: the review stays open and the acknowledgement counts towards no rule. Only someone who may decide the review may send it, and anyone else is refused with -32011. A task with no open review is refused with -32010, and a second acknowledgement from the same reviewer in the same round with -32602. Returns requested_at, the time the round opened, which names it.",
15
17
  "chap.decide.approve": "Approve the artefact under review as it stands. Only a reviewer the review was addressed to may decide, and anyone else is refused with -32011. The task completes once the review's rule is satisfied, so under all_approve or quorum:N an approval may leave the review open awaiting others. Use chap.decide.override instead to accept a corrected version.",
16
18
  "chap.decide.reject": "Reject the artefact under review. The task is declined, or returns to in_progress when request_revision is set, which is the choice between ending the work and sending it back. Only a reviewer the review was addressed to may decide. Use chap.decide.override instead to correct the artefact and accept it rather than refuse it.",
17
19
  "chap.decide.override": "Correct the artefact under review with an RFC 6902 JSON Patch and accept the result. The patch, the rationale and any tags are recorded together, so the audit log holds what was changed and why, rather than only that the work was not accepted as written.",
18
20
  "chap.abstain.declare": "Stand aside from a review this participant cannot decide, for example on a conflict of interest or for want of context. Use it in place of chap.decide.reject, which judges the work; abstaining judges nothing and leaves the artefact intact. It requires an open review addressed to the caller and answers -32010 otherwise. The task moves to abstained, which is not terminal: chap.escalate.raise or a fresh chap.review.request can still carry it forward.",
19
- "chap.escalate.raise": "Hand a task upwards, where the current holder can act but should not decide alone. The original moves to escalated and is linked to a new task for whoever takes it on. Use chap.handoff.propose to pass work sideways without that link, and chap.control.supersede to replace a task outright. The successor starts with an empty input unless one is supplied, so restate whatever the new assignee needs. A completed, cancelled or superseded task cannot be escalated. The successor takes the mode new_task.mode names, or else the original's, and requires review when the original did, or when it is a trial task under modes/1.0. A paused assignee is refused with -32063, and a mode above the workspace's current ceiling with -32040; after the ceiling is lowered, name a mode within it.",
21
+ "chap.escalate.raise": "Hand a task upwards, where the current holder can act but should not decide alone. The original moves to escalated and is linked to a new task for whoever takes it on. Use chap.handoff.propose to pass work sideways without that link, and chap.control.supersede to replace a task outright. The successor starts with an empty input unless one is supplied, so restate whatever the new assignee needs. A completed, cancelled or superseded task cannot be escalated. The successor takes the mode new_task.mode names, or else the original's, and requires review when the original did or held a review, or when it is a trial task under modes/1.0. Whoever made the original's work counts as an author of the successor's review. A paused assignee is refused with -32063, and a mode above the workspace's current ceiling with -32040; after the ceiling is lowered, name a mode within it.",
20
22
  // whisper/1.0
21
23
  "chap.whisper.ask": "Put one question to one or more participants, with a deadline and a default. If the deadline passes unanswered the default applies, so a task is never blocked waiting on a reply.",
22
24
  "chap.whisper.answer": "Answer an open whisper. Where the question carried options, the answer must name one of their ids and any other value is refused with -32022. A whisper already answered is refused with -32020 and one past its deadline with -32021, in which case the default supplied at chap.whisper.ask has already been applied.",
@@ -32,10 +34,10 @@ var TOOL_DESCRIPTIONS = {
32
34
  // control/1.0
33
35
  "chap.control.pause": "Pause work. Scoped to a task it moves that task to paused; to a participant it stops new tasks being assigned to them; to the workspace it refuses every method except describing, reading the audit log, joining, leaving and resuming.",
34
36
  "chap.control.resume": "Resume work paused at the same scope: a task returns to the state it held at the pause, a participant can be assigned tasks again, a workspace returns to active.",
35
- "chap.control.cancel": "Cancel a task. Cancelled is terminal, and a task that has already settled cannot be cancelled.",
37
+ "chap.control.cancel": "Cancel a task. Cancelled is terminal, and a task that has already settled cannot be cancelled. From the moment a review the task requires opens until a reviewer rejects the work, the authors of the work cannot cancel it, even once they take the work back, nor a successor that carries its review (-32011).",
36
38
  "chap.control.snapshot": "Capture the workspace state as an artefact before a change you may want to undo. Returns a snapshot artefact id, which is the only thing chap.control.rollback accepts as a target; the label is for a human reading the log and cannot be used to select it. Taking a snapshot changes nothing. Note that a rollback restores only the mode ceiling and member roles, so a snapshot is a narrow safety net rather than a general undo.",
37
39
  "chap.control.rollback": "Restore workspace state from a snapshot. The mode ceiling and member roles are restored; the rollback is appended to the audit log rather than rewriting it.",
38
- "chap.control.supersede": "Replace a task with a successor in one call. The original moves to superseded and stays linked to its replacement. The successor requires review when the original did, whatever its own review_required says, and a paused assignee is refused with -32063.",
40
+ "chap.control.supersede": "Replace a task with a successor in one call. The original moves to superseded and stays linked to its replacement. The successor requires review when the original did, whatever its own review_required says, and whoever made the original's work counts as an author of the successor's review. A paused assignee is refused with -32063, and from the moment a review the original requires opens until a reviewer rejects the work, the authors of the work cannot supersede it, nor a successor that carries its review (-32011).",
39
41
  "chap.control.set_mode_ceiling": "Set the highest operating mode tasks in this workspace may request. A task above the ceiling is refused.",
40
42
  // routing/1.0
41
43
  "chap.task.route": "Choose an assignee for a task from a list of candidates and reassign the task to the one selected. Use it where the choice itself belongs on the record: it writes a route_decision artefact naming the policy, the candidate chosen and the alternatives passed over, none of which is captured by setting assignee directly on chap.task.create. The default policy takes the first candidate that is a workspace member and is not paused. An operator-supplied policy may choose on any basis, and the call is refused with -32510 when its choice is not a member, or with -32063 when its choice is paused.",
@@ -86,8 +88,10 @@ var IDEMPOTENT = /* @__PURE__ */ new Set([
86
88
  // pausing an already paused target changes nothing
87
89
  "chap.control.set_mode_ceiling",
88
90
  // setting the ceiling it already has changes nothing
89
- "chap.deliberate.close"
91
+ "chap.deliberate.close",
90
92
  // returns the same outcome, recomputing nothing
93
+ "chap.review.acknowledge"
94
+ // a second acknowledgement in the round is refused and records nothing
91
95
  ]);
92
96
  var OPEN_WORLD = /* @__PURE__ */ new Set([
93
97
  "chap.audit.submit_to_scitt",
@@ -97,6 +101,7 @@ var TITLES = {
97
101
  "chap.workspace.create": "Create workspace",
98
102
  "chap.workspace.describe": "Describe workspace",
99
103
  "chap.workspace.set_profiles": "Replace workspace profiles",
104
+ "chap.workspace.invite": "Invite participant",
100
105
  "chap.participant.join": "Add participant",
101
106
  "chap.participant.leave": "Remove participant",
102
107
  "chap.task.create": "Create task",
@@ -104,6 +109,7 @@ var TITLES = {
104
109
  "chap.task.complete": "Submit task output",
105
110
  "chap.audit.read": "Read audit log",
106
111
  "chap.review.request": "Request review",
112
+ "chap.review.acknowledge": "Acknowledge review",
107
113
  "chap.decide.approve": "Approve",
108
114
  "chap.decide.reject": "Reject",
109
115
  "chap.decide.override": "Override with a correction",
@@ -144,7 +150,21 @@ var TOOL_ANNOTATIONS = Object.fromEntries(
144
150
  openWorldHint: OPEN_WORLD.has(name)
145
151
  }])
146
152
  );
153
+ var AGENT_MCP_TOOLS = /* @__PURE__ */ new Set([
154
+ "chap.task.create",
155
+ "chap.task.update",
156
+ "chap.task.complete",
157
+ "chap.whisper.ask",
158
+ "chap.decide.approve",
159
+ "chap.decide.reject",
160
+ "chap.decide.override",
161
+ "chap.review.acknowledge",
162
+ "chap.workspace.describe",
163
+ "chap.audit.read",
164
+ "chap.audit.verify_chain"
165
+ ]);
147
166
  export {
167
+ AGENT_MCP_TOOLS,
148
168
  TOOL_ANNOTATIONS,
149
169
  TOOL_DESCRIPTIONS
150
170
  };
package/dist/tools.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tools.ts"],"sourcesContent":["/**\n * @brightbeamai/chap-coordinator-mcp/tools\n *\n * Tool-level descriptions and behavioural annotations for each CHAP\n * method exposed over MCP. A client shows these in its UI and reads\n * them when choosing a tool.\n *\n * A description says what the method does, how it differs from its\n * nearest sibling, and the consequence a caller most needs to know\n * before calling. It does not restate the parameter schema: every\n * parameter is already described in schemas.ts, and repeating that\n * here costs length and adds no meaning.\n *\n * The annotations carry what prose states poorly.\n *\n * `readOnlyHint` is not a judgement. It is exactly the coordinator's\n * own READ_ONLY_METHODS set, the list that decides whether an envelope\n * is recorded on the audit chain, and a test holds the two together.\n * Anything absent from that set appends an entry, which is a change of\n * state whatever else it does.\n *\n * `idempotentHint` was derived by calling each method twice with\n * identical arguments and comparing workspace state, and is claimed\n * only where the second call both succeeds and leaves that state\n * untouched. Where a repeat is refused rather than absorbed, the hint\n * is absent: an agent must not read an error as a safe retry. It is\n * also absent from `task.create`, which is idempotent only when the\n * caller supplies `idempotency_key` and creates a second task when\n * they do not.\n *\n * `destructiveHint` marks the methods that overwrite or remove state\n * that was there before, or settle it somewhere it cannot come back\n * from. Most of CHAP is additive and carries `false`.\n */\n\nexport const TOOL_DESCRIPTIONS: Record<string, string> = {\n // Core\n \"chap.workspace.create\":\n \"Create a workspace: the container for the participants, tasks and audit log of one piece of \" +\n \"collaborative work. Returns the workspace id, which every later call carries.\",\n\n \"chap.workspace.describe\":\n \"Report the current state of a workspace: its members, enabled profiles, audit length, and task and \" +\n \"override counts.\",\n\n \"chap.workspace.set_profiles\":\n \"Replace the whole set of profiles enabled on a workspace. The list is not merged: any profile absent \" +\n \"from it is dropped, so send the complete set you want. Enabling audit-scitt/1.0 on a workspace that \" +\n \"already has entries starts the chain from that point and leaves the earlier entries permanently outside \" +\n \"it, which chap.audit.verify_chain then reports as not_evaluated. Prefer setting profiles at \" +\n \"chap.workspace.create, where no entries exist yet to strand.\",\n\n \"chap.participant.join\":\n \"Add a participant to a workspace. The type given, human, agent, service, group or workspace, decides \" +\n \"whether they are eligible to review work that requires it.\",\n\n \"chap.participant.leave\":\n \"Remove a participant from a workspace. Entries they have already written stay in the audit log and their \" +\n \"past signatures still verify, so leaving is not a way to withdraw a decision. They can no longer be \" +\n \"assigned tasks or act as a reviewer, and returning means a fresh chap.participant.join.\",\n\n \"chap.task.create\":\n \"Create a task: a unit of work assigned to one participant. Set review_required to make completion depend \" +\n \"on a reviewer decision rather than on the assignee. Returns a task_id that the rest of the lifecycle \" +\n \"takes. Supplying idempotency_key is what makes a retry safe: a repeat carrying a key already seen \" +\n \"returns the original task, while a repeat without one creates a second task. Assigning to a paused \" +\n \"member is refused.\",\n\n \"chap.task.update\":\n \"Move a task to a new state. Only the transitions in the specification's lifecycle table are accepted, \" +\n \"and a task that requires review cannot be completed here.\",\n\n \"chap.task.complete\":\n \"Submit a task's output. A task that requires review does not complete: the output is held as the \" +\n \"artefact under review, the task moves to review_requested, and a reviewer decision completes it. Any \" +\n \"other task completes immediately.\",\n\n \"chap.audit.read\":\n \"Read entries from a workspace's audit log, optionally within a sequence range and filtered by method, \" +\n \"sender, task or outcome. This is the query surface for everything the workspace has recorded, decisions \" +\n \"and overrides included. An accepted call is under 'envelope'. A refused attempt the coordinator recorded, \" +\n \"such as a decision by someone the review was not addressed to, is under 'request' with an 'outcome' \" +\n \"giving the error code, and it did not take effect. Reads only: it records nothing, so it never appears in \" +\n \"its own output. Entries come back as recorded, without aggregation, so grouping them, by tag for \" +\n \"instance, is the reader's job.\",\n\n // review/1.0\n \"chap.review.request\":\n \"Open a review on a task and address it to one or more reviewers. They then call chap.decide.approve, \" +\n \"chap.decide.reject, chap.decide.override or chap.abstain.declare. Repeating the request with the same \" +\n \"artefact adds reviewers to the open review.\",\n\n \"chap.decide.approve\":\n \"Approve the artefact under review as it stands. Only a reviewer the review was addressed to may decide, \" +\n \"and anyone else is refused with -32011. The task completes once the review's rule is satisfied, so under \" +\n \"all_approve or quorum:N an approval may leave the review open awaiting others. Use chap.decide.override \" +\n \"instead to accept a corrected version.\",\n\n \"chap.decide.reject\":\n \"Reject the artefact under review. The task is declined, or returns to in_progress when request_revision \" +\n \"is set, which is the choice between ending the work and sending it back. Only a reviewer the review was \" +\n \"addressed to may decide. Use chap.decide.override instead to correct the artefact and accept it rather \" +\n \"than refuse it.\",\n\n \"chap.decide.override\":\n \"Correct the artefact under review with an RFC 6902 JSON Patch and accept the result. The patch, the \" +\n \"rationale and any tags are recorded together, so the audit log holds what was changed and why, rather \" +\n \"than only that the work was not accepted as written.\",\n\n \"chap.abstain.declare\":\n \"Stand aside from a review this participant cannot decide, for example on a conflict of interest or for \" +\n \"want of context. Use it in place of chap.decide.reject, which judges the work; abstaining judges nothing \" +\n \"and leaves the artefact intact. It requires an open review addressed to the caller and answers -32010 \" +\n \"otherwise. The task moves to abstained, which is not terminal: chap.escalate.raise or a fresh \" +\n \"chap.review.request can still carry it forward.\",\n\n \"chap.escalate.raise\":\n \"Hand a task upwards, where the current holder can act but should not decide alone. The original moves to \" +\n \"escalated and is linked to a new task for whoever takes it on. Use chap.handoff.propose to pass work \" +\n \"sideways without that link, and chap.control.supersede to replace a task outright. The successor starts \" +\n \"with an empty input unless one is supplied, so restate whatever the new assignee needs. A completed, \" +\n \"cancelled or superseded task cannot be escalated. The successor takes the mode new_task.mode names, or \" +\n \"else the original's, and requires review when the original did, or when it is a trial task under \" +\n \"modes/1.0. A paused assignee is refused with -32063, and a mode above the workspace's current ceiling \" +\n \"with -32040; after the ceiling is lowered, name a mode within it.\",\n\n // whisper/1.0\n \"chap.whisper.ask\":\n \"Put one question to one or more participants, with a deadline and a default. If the deadline passes \" +\n \"unanswered the default applies, so a task is never blocked waiting on a reply.\",\n\n \"chap.whisper.answer\":\n \"Answer an open whisper. Where the question carried options, the answer must name one of their ids and \" +\n \"any other value is refused with -32022. A whisper already answered is refused with -32020 and one past \" +\n \"its deadline with -32021, in which case the default supplied at chap.whisper.ask has already been \" +\n \"applied.\",\n\n // deliberation/1.0\n \"chap.deliberate.open\":\n \"Open a group decision among several participants under a stated voting rule: any_one_approves, \" +\n \"all_approve, quorum:N, weighted_vote:T or weighted_vote_with_veto:T. Use it where several people must \" +\n \"weigh in on one question; chap.review.request is the tool for judging one participant's output. Returns \" +\n \"a deliberation_id that the comment, vote and close tools all take. The participant list, rule, weights \" +\n \"and veto map are fixed at open, so the terms are settled before anyone votes. No outcome exists until \" +\n \"chap.deliberate.close computes one.\",\n\n \"chap.deliberate.comment\":\n \"Record a comment on an open deliberation, so the reasoning behind a vote survives alongside the tally. \" +\n \"Comments carry no weight in the outcome and may be added by any participant at any point before \" +\n \"chap.deliberate.close.\",\n\n \"chap.deliberate.vote\":\n \"Cast a yea, nay or abstain in an open deliberation. Each participant votes once and a second attempt \" +\n \"answers -32031, so a vote cannot be revised. An abstention is recorded but counts as neither side, which \" +\n \"under all_approve or quorum:N withholds the approval those rules need. The tally is computed later, by \" +\n \"chap.deliberate.close.\",\n\n \"chap.deliberate.close\":\n \"Close a deliberation and compute its outcome from the votes cast under its rule. Closing is final: \" +\n \"further comments and votes are refused with -32032. Calling it again on a closed deliberation returns \" +\n \"the same outcome and changes nothing, so a retry is safe. Votes never cast are simply absent from the \" +\n \"tally rather than counted as abstentions.\",\n\n // handoff/1.0\n \"chap.handoff.propose\":\n \"Propose handing one or more tasks to another participant or a group, with the context needed to pick \" +\n \"them up. Every task must currently be assigned to the proposer.\",\n\n \"chap.handoff.accept\":\n \"Accept a proposed handoff. The accepted tasks are reassigned to the accepting participant, which is the \" +\n \"point at which responsibility actually moves. Omitting accepted_task_ids accepts all of them. Accepting \" +\n \"resolves the proposal for good: a later accept or decline on the same handoff answers -32051. A paused \" +\n \"participant cannot accept and is refused with -32063.\",\n\n \"chap.handoff.decline\":\n \"Decline a proposed handoff. The tasks stay with the proposer and nothing is reassigned, which is the \" +\n \"difference from chap.handoff.accept. Declining resolves the proposal for good: a later accept or decline \" +\n \"on the same handoff answers -32051, and trying again means a fresh proposal. The reason is recorded so \" +\n \"the proposer can route the work elsewhere.\",\n\n // control/1.0\n \"chap.control.pause\":\n \"Pause work. Scoped to a task it moves that task to paused; to a participant it stops new tasks being \" +\n \"assigned to them; to the workspace it refuses every method except describing, reading the audit log, \" +\n \"joining, leaving and resuming.\",\n\n \"chap.control.resume\":\n \"Resume work paused at the same scope: a task returns to the state it held at the pause, a participant \" +\n \"can be assigned tasks again, a workspace returns to active.\",\n\n \"chap.control.cancel\":\n \"Cancel a task. Cancelled is terminal, and a task that has already settled cannot be cancelled.\",\n\n \"chap.control.snapshot\":\n \"Capture the workspace state as an artefact before a change you may want to undo. Returns a snapshot \" +\n \"artefact id, which is the only thing chap.control.rollback accepts as a target; the label is for a human \" +\n \"reading the log and cannot be used to select it. Taking a snapshot changes nothing. Note that a rollback \" +\n \"restores only the mode ceiling and member roles, so a snapshot is a narrow safety net rather than a \" +\n \"general undo.\",\n\n \"chap.control.rollback\":\n \"Restore workspace state from a snapshot. The mode ceiling and member roles are restored; the rollback is \" +\n \"appended to the audit log rather than rewriting it.\",\n\n \"chap.control.supersede\":\n \"Replace a task with a successor in one call. The original moves to superseded and stays linked to its \" +\n \"replacement. The successor requires review when the original did, whatever its own review_required \" +\n \"says, and a paused assignee is refused with -32063.\",\n\n \"chap.control.set_mode_ceiling\":\n \"Set the highest operating mode tasks in this workspace may request. A task above the ceiling is refused.\",\n\n // routing/1.0\n \"chap.task.route\":\n \"Choose an assignee for a task from a list of candidates and reassign the task to the one selected. Use \" +\n \"it where the choice itself belongs on the record: it writes a route_decision artefact naming the policy, \" +\n \"the candidate chosen and the alternatives passed over, none of which is captured by setting assignee \" +\n \"directly on chap.task.create. The default policy takes the first candidate that is a workspace member \" +\n \"and is not paused. An operator-supplied policy may choose on any basis, and the call is refused with \" +\n \"-32510 when its choice is not a member, or with -32063 when its choice is paused.\",\n\n \"chap.review.depth\":\n \"Decide how much review a task warrants, skip, spot_check or full, from its routing hints. Records a \" +\n \"route_decision artefact giving the rule that produced the answer.\",\n\n \"chap.escalate.auto\":\n \"Evaluate a task's routing hints against the escalation policy and report whether it should be escalated, \" +\n \"and to whom. It decides only: a route_decision artefact is recorded but the task does not move, so act \" +\n \"on the answer with chap.escalate.raise. The default policy escalates on criticality critical, or high \" +\n \"with confidence below 0.6.\",\n\n // security-signed/1.0\n \"chap.participant.rotate_key\":\n \"Retire a participant's signing key and register its replacement. The old key stays in the key history \" +\n \"with a valid_until timestamp, so envelopes it signed still verify.\",\n\n \"chap.participant.revoke_key\":\n \"Revoke a signing key, for example after a device is lost. Signatures presented with it are refused from \" +\n \"then on. Revoking another participant's key requires the admin role.\",\n\n // audit-scitt/1.0\n \"chap.audit.submit_to_scitt\":\n \"Build COSE_Sign1-shaped statements for a range of audit entries and submit them to the configured SCITT \" +\n \"transparency service. Where none is configured the statements are returned for submission out of band.\",\n\n \"chap.audit.verify_receipt\":\n \"Check a receipt returned by an external SCITT transparency service, confirming that service logged the \" +\n \"statement. This is the external half of verification; chap.audit.verify_chain checks the local prev-hash \" +\n \"chain instead, and the two answer different questions. Verification is delegated to a hook the \" +\n \"deployment supplies and fails closed with -32082 when none is configured, so a missing verifier can \" +\n \"never read as a pass. Reads only: nothing is recorded.\",\n\n \"chap.audit.verify_chain\":\n \"Replay a workspace's prev-hash chain. Only status verified with ok true means the log was checked and is \" +\n \"intact. Status not_evaluated with ok false means part of the log was never checked, so its integrity is \" +\n \"unknown and must not be reported as verified; entries_unchecked says how much. An error means the chain \" +\n \"is broken or absent.\",\n};\n\n/** MCP tool annotations (2025-03-26 onwards). Every field is a hint. */\nexport interface ToolAnnotations {\n /** Human-readable title, shown by a client instead of the raw tool name. */\n title: string;\n /** Does not modify state. Mirrors the coordinator's own read-only set. */\n readOnlyHint: boolean;\n /** May overwrite or remove existing state, or settle it irreversibly. */\n destructiveHint: boolean;\n /** A repeat with identical arguments succeeds and changes nothing further. */\n idempotentHint: boolean;\n /** Reaches a system outside this coordinator. */\n openWorldHint: boolean;\n}\n\n/**\n * Read-only, and so never recorded on the chain. This is the coordinator's own\n * READ_ONLY_METHODS set, the list that decides whether an envelope is\n * recorded. It is repeated here rather than imported so the adapter does not\n * depend on a coordinator export at runtime, and annotations.test.ts reads\n * that source and fails if the two ever diverge.\n */\nconst READ_ONLY = new Set([\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\", \"chap.audit.verify_receipt\",\n // Submitting reads the chain and sends it onward. It changes nothing here,\n // which is what readOnlyHint claims; openWorldHint carries the fact that it\n // reaches a service outside this coordinator.\n \"chap.audit.submit_to_scitt\",\n]);\n\n/** Overwrites, removes, or settles state irreversibly. */\nconst DESTRUCTIVE = new Set([\n \"chap.workspace.set_profiles\", // replaces the profile set; can strand entries outside the chain\n \"chap.participant.leave\", // removes a member\n \"chap.participant.revoke_key\", // invalidates a key from then on\n \"chap.control.cancel\", // cancelled is terminal\n \"chap.control.supersede\", // superseded is terminal\n \"chap.control.rollback\", // overwrites the mode ceiling and member roles\n]);\n\n/** Verified by calling twice with identical arguments and diffing workspace state. */\nconst IDEMPOTENT = new Set([\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\", \"chap.audit.verify_receipt\",\n \"chap.participant.join\", // a re-join is additive and adds no duplicate member\n \"chap.participant.leave\", // leaving twice leaves the same absence\n \"chap.control.pause\", // pausing an already paused target changes nothing\n \"chap.control.set_mode_ceiling\", // setting the ceiling it already has changes nothing\n \"chap.deliberate.close\", // returns the same outcome, recomputing nothing\n]);\n\n/** Reaches a transparency service outside this coordinator. */\nconst OPEN_WORLD = new Set([\n \"chap.audit.submit_to_scitt\", \"chap.audit.verify_receipt\",\n]);\n\n/**\n * Human-readable titles. A client that shows a title instead of the tool\n * name should still show something a person can read at a glance.\n */\nconst TITLES: Record<string, string> = {\n \"chap.workspace.create\": \"Create workspace\",\n \"chap.workspace.describe\": \"Describe workspace\",\n \"chap.workspace.set_profiles\": \"Replace workspace profiles\",\n \"chap.participant.join\": \"Add participant\",\n \"chap.participant.leave\": \"Remove participant\",\n \"chap.task.create\": \"Create task\",\n \"chap.task.update\": \"Change task state\",\n \"chap.task.complete\": \"Submit task output\",\n \"chap.audit.read\": \"Read audit log\",\n \"chap.review.request\": \"Request review\",\n \"chap.decide.approve\": \"Approve\",\n \"chap.decide.reject\": \"Reject\",\n \"chap.decide.override\": \"Override with a correction\",\n \"chap.abstain.declare\": \"Abstain from review\",\n \"chap.escalate.raise\": \"Escalate task\",\n \"chap.whisper.ask\": \"Ask a whisper\",\n \"chap.whisper.answer\": \"Answer a whisper\",\n \"chap.deliberate.open\": \"Open deliberation\",\n \"chap.deliberate.comment\": \"Comment on deliberation\",\n \"chap.deliberate.vote\": \"Vote in deliberation\",\n \"chap.deliberate.close\": \"Close deliberation\",\n \"chap.handoff.propose\": \"Propose handoff\",\n \"chap.handoff.accept\": \"Accept handoff\",\n \"chap.handoff.decline\": \"Decline handoff\",\n \"chap.control.pause\": \"Pause work\",\n \"chap.control.resume\": \"Resume work\",\n \"chap.control.cancel\": \"Cancel task\",\n \"chap.control.snapshot\": \"Snapshot workspace\",\n \"chap.control.rollback\": \"Roll back to snapshot\",\n \"chap.control.supersede\": \"Supersede task\",\n \"chap.control.set_mode_ceiling\": \"Set mode ceiling\",\n \"chap.task.route\": \"Route task to an assignee\",\n \"chap.review.depth\": \"Decide review depth\",\n \"chap.escalate.auto\": \"Evaluate auto-escalation\",\n \"chap.participant.rotate_key\": \"Rotate signing key\",\n \"chap.participant.revoke_key\": \"Revoke signing key\",\n \"chap.audit.submit_to_scitt\": \"Anchor audit log in SCITT\",\n \"chap.audit.verify_receipt\": \"Verify SCITT receipt\",\n \"chap.audit.verify_chain\": \"Verify audit chain\",\n};\n\n/** Annotations for every tool, derived from the sets above. */\nexport const TOOL_ANNOTATIONS: Record<string, ToolAnnotations> = Object.fromEntries(\n Object.keys(TOOL_DESCRIPTIONS).map((name) => [name, {\n title: TITLES[name] ?? name,\n readOnlyHint: READ_ONLY.has(name),\n // Meaningful only when readOnlyHint is false, per the specification.\n destructiveHint: DESTRUCTIVE.has(name),\n idempotentHint: IDEMPOTENT.has(name),\n openWorldHint: OPEN_WORLD.has(name),\n }]),\n);\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/tools.ts"],"sourcesContent":["/**\n * @brightbeamai/chap-coordinator-mcp/tools\n *\n * Tool-level descriptions and behavioural annotations for each CHAP\n * method exposed over MCP. A client shows these in its UI and reads\n * them when choosing a tool.\n *\n * A description says what the method does, how it differs from its\n * nearest sibling, and the consequence a caller most needs to know\n * before calling. It does not restate the parameter schema: every\n * parameter is already described in schemas.ts, and repeating that\n * here costs length and adds no meaning.\n *\n * The annotations carry what prose states poorly.\n *\n * `readOnlyHint` is not a judgement. It is exactly the coordinator's\n * own READ_ONLY_METHODS set, the list that decides whether an envelope\n * is recorded on the audit chain, and a test holds the two together.\n * Anything absent from that set appends an entry, which is a change of\n * state whatever else it does.\n *\n * `idempotentHint` was derived by calling each method twice with\n * identical arguments and comparing workspace state, and is claimed\n * only where the second call both succeeds and leaves that state\n * untouched. Where a repeat is refused rather than absorbed, the hint\n * is absent: an agent must not read an error as a safe retry. It is\n * also absent from `task.create`, which is idempotent only when the\n * caller supplies `idempotency_key` and creates a second task when\n * they do not.\n *\n * `destructiveHint` marks the methods that overwrite or remove state\n * that was there before, or settle it somewhere it cannot come back\n * from. Most of CHAP is additive and carries `false`.\n */\n\nexport const TOOL_DESCRIPTIONS: Record<string, string> = {\n // Core\n \"chap.workspace.create\":\n \"Create a workspace: the container for the participants, tasks and audit log of one piece of \" +\n \"collaborative work. Returns the workspace id, which every later call carries.\",\n\n \"chap.workspace.describe\":\n \"Report the current state of a workspace: its members, enabled profiles, audit length, and task and \" +\n \"override counts.\",\n\n \"chap.workspace.set_profiles\":\n \"Replace the whole set of profiles enabled on a workspace. The list is not merged: any profile absent \" +\n \"from it is dropped, so send the complete set you want. Enabling audit-scitt/1.0 on a workspace that \" +\n \"already has entries starts the chain from that point and leaves the earlier entries permanently outside \" +\n \"it, which chap.audit.verify_chain then reports as not_evaluated. Prefer setting profiles at \" +\n \"chap.workspace.create, where no entries exist yet to strand.\",\n\n \"chap.workspace.invite\":\n \"Invite a participant to a workspace, as its admin. The invitation names the type and role the member \" +\n \"takes when it joins, and may pin its keys and its OIDC subject. A workspace whose join policy is \" +\n \"'invite' admits nobody else. For a member that holds no key in force, the call registers the keys it \" +\n \"names at once, so a member whose keys were all revoked can sign again. Where a token or credential \" +\n \"verifier is configured, an invitation names no keys for a person: their keys arrive with the token they \" +\n \"join with (-32602).\",\n\n \"chap.participant.join\":\n \"Add a participant to a workspace. The type given, human, agent, service, group or workspace, decides \" +\n \"whether they are eligible to review work that requires it.\",\n\n \"chap.participant.leave\":\n \"Remove a participant from a workspace. Entries they have already written stay in the audit log and their \" +\n \"past signatures still verify, so leaving is not a way to withdraw a decision. They can no longer be \" +\n \"assigned tasks or act as a reviewer, and returning means a fresh chap.participant.join.\",\n\n \"chap.task.create\":\n \"Create a task: a unit of work assigned to one participant. Set review_required to make completion depend \" +\n \"on a reviewer decision rather than on the assignee. Returns a task_id that the rest of the lifecycle \" +\n \"takes. Supplying idempotency_key is what makes a retry safe: a repeat carrying a key already seen \" +\n \"returns the original task, while a repeat without one creates a second task. Assigning to a paused \" +\n \"member is refused.\",\n\n \"chap.task.update\":\n \"Move a task to a new state. Only the transitions in the specification's lifecycle table are accepted, \" +\n \"and a task that requires review cannot be completed here. A task whose review no decision has closed, or \" +\n \"a successor that carries one on, is not declined (-32602).\",\n\n \"chap.task.complete\":\n \"Submit a task's output. A task that requires review does not complete: the output is held as the \" +\n \"artefact under review, the task moves to review_requested, and a reviewer decision completes it. Any \" +\n \"other task completes immediately.\",\n\n \"chap.audit.read\":\n \"Read entries from a workspace's audit log, optionally within a sequence range and filtered by method, \" +\n \"sender, task or outcome. This is the query surface for everything the workspace has recorded, decisions \" +\n \"and overrides included. An accepted call is under 'envelope'. A refused attempt the coordinator recorded, \" +\n \"such as a decision by someone the review was not addressed to, is under 'request' with an 'outcome' \" +\n \"giving the error code, and it did not take effect. Reads only: it records nothing, so it never appears in \" +\n \"its own output. Entries come back as recorded, without aggregation, so grouping them, by tag for \" +\n \"instance, is the reader's job.\",\n\n // review/1.0\n \"chap.review.request\":\n \"Open a review on a task and address it to one or more reviewers. They then call chap.decide.approve, \" +\n \"chap.decide.reject, chap.decide.override or chap.abstain.declare, and may first say they have begun with \" +\n \"chap.review.acknowledge. Repeating the request with the same artefact adds reviewers to the open review. \" +\n \"A task marked review_required is reviewed through chap.task.complete, which opens its review under the \" +\n \"workspace's rule; on such a task this tool only adds people to a review already open, and before it \" +\n \"opens is refused with -32011.\",\n\n \"chap.review.acknowledge\":\n \"Say that this reviewer has begun the open review on a task, before deciding it. The call is recorded, so \" +\n \"the audit log shows when each reviewer took the review up as well as when they decided. It decides \" +\n \"nothing: the review stays open and the acknowledgement counts towards no rule. Only someone who may \" +\n \"decide the review may send it, and anyone else is refused with -32011. A task with no open review is \" +\n \"refused with -32010, and a second acknowledgement from the same reviewer in the same round with -32602. \" +\n \"Returns requested_at, the time the round opened, which names it.\",\n\n \"chap.decide.approve\":\n \"Approve the artefact under review as it stands. Only a reviewer the review was addressed to may decide, \" +\n \"and anyone else is refused with -32011. The task completes once the review's rule is satisfied, so under \" +\n \"all_approve or quorum:N an approval may leave the review open awaiting others. Use chap.decide.override \" +\n \"instead to accept a corrected version.\",\n\n \"chap.decide.reject\":\n \"Reject the artefact under review. The task is declined, or returns to in_progress when request_revision \" +\n \"is set, which is the choice between ending the work and sending it back. Only a reviewer the review was \" +\n \"addressed to may decide. Use chap.decide.override instead to correct the artefact and accept it rather \" +\n \"than refuse it.\",\n\n \"chap.decide.override\":\n \"Correct the artefact under review with an RFC 6902 JSON Patch and accept the result. The patch, the \" +\n \"rationale and any tags are recorded together, so the audit log holds what was changed and why, rather \" +\n \"than only that the work was not accepted as written.\",\n\n \"chap.abstain.declare\":\n \"Stand aside from a review this participant cannot decide, for example on a conflict of interest or for \" +\n \"want of context. Use it in place of chap.decide.reject, which judges the work; abstaining judges nothing \" +\n \"and leaves the artefact intact. It requires an open review addressed to the caller and answers -32010 \" +\n \"otherwise. The task moves to abstained, which is not terminal: chap.escalate.raise or a fresh \" +\n \"chap.review.request can still carry it forward.\",\n\n \"chap.escalate.raise\":\n \"Hand a task upwards, where the current holder can act but should not decide alone. The original moves to \" +\n \"escalated and is linked to a new task for whoever takes it on. Use chap.handoff.propose to pass work \" +\n \"sideways without that link, and chap.control.supersede to replace a task outright. The successor starts \" +\n \"with an empty input unless one is supplied, so restate whatever the new assignee needs. A completed, \" +\n \"cancelled or superseded task cannot be escalated. The successor takes the mode new_task.mode names, or \" +\n \"else the original's, and requires review when the original did or held a review, or when it is a trial \" +\n \"task under modes/1.0. Whoever made the original's work counts as an author of the successor's review. A \" +\n \"paused assignee is refused with -32063, and a mode above the workspace's current ceiling with -32040; \" +\n \"after the ceiling is lowered, name a mode within it.\",\n\n // whisper/1.0\n \"chap.whisper.ask\":\n \"Put one question to one or more participants, with a deadline and a default. If the deadline passes \" +\n \"unanswered the default applies, so a task is never blocked waiting on a reply.\",\n\n \"chap.whisper.answer\":\n \"Answer an open whisper. Where the question carried options, the answer must name one of their ids and \" +\n \"any other value is refused with -32022. A whisper already answered is refused with -32020 and one past \" +\n \"its deadline with -32021, in which case the default supplied at chap.whisper.ask has already been \" +\n \"applied.\",\n\n // deliberation/1.0\n \"chap.deliberate.open\":\n \"Open a group decision among several participants under a stated voting rule: any_one_approves, \" +\n \"all_approve, quorum:N, weighted_vote:T or weighted_vote_with_veto:T. Use it where several people must \" +\n \"weigh in on one question; chap.review.request is the tool for judging one participant's output. Returns \" +\n \"a deliberation_id that the comment, vote and close tools all take. The participant list, rule, weights \" +\n \"and veto map are fixed at open, so the terms are settled before anyone votes. No outcome exists until \" +\n \"chap.deliberate.close computes one.\",\n\n \"chap.deliberate.comment\":\n \"Record a comment on an open deliberation, so the reasoning behind a vote survives alongside the tally. \" +\n \"Comments carry no weight in the outcome and may be added by any participant at any point before \" +\n \"chap.deliberate.close.\",\n\n \"chap.deliberate.vote\":\n \"Cast a yea, nay or abstain in an open deliberation. Each participant votes once and a second attempt \" +\n \"answers -32031, so a vote cannot be revised. An abstention is recorded but counts as neither side, which \" +\n \"under all_approve or quorum:N withholds the approval those rules need. The tally is computed later, by \" +\n \"chap.deliberate.close.\",\n\n \"chap.deliberate.close\":\n \"Close a deliberation and compute its outcome from the votes cast under its rule. Closing is final: \" +\n \"further comments and votes are refused with -32032. Calling it again on a closed deliberation returns \" +\n \"the same outcome and changes nothing, so a retry is safe. Votes never cast are simply absent from the \" +\n \"tally rather than counted as abstentions.\",\n\n // handoff/1.0\n \"chap.handoff.propose\":\n \"Propose handing one or more tasks to another participant or a group, with the context needed to pick \" +\n \"them up. Every task must currently be assigned to the proposer.\",\n\n \"chap.handoff.accept\":\n \"Accept a proposed handoff. The accepted tasks are reassigned to the accepting participant, which is the \" +\n \"point at which responsibility actually moves. Omitting accepted_task_ids accepts all of them. Accepting \" +\n \"resolves the proposal for good: a later accept or decline on the same handoff answers -32051. A paused \" +\n \"participant cannot accept and is refused with -32063.\",\n\n \"chap.handoff.decline\":\n \"Decline a proposed handoff. The tasks stay with the proposer and nothing is reassigned, which is the \" +\n \"difference from chap.handoff.accept. Declining resolves the proposal for good: a later accept or decline \" +\n \"on the same handoff answers -32051, and trying again means a fresh proposal. The reason is recorded so \" +\n \"the proposer can route the work elsewhere.\",\n\n // control/1.0\n \"chap.control.pause\":\n \"Pause work. Scoped to a task it moves that task to paused; to a participant it stops new tasks being \" +\n \"assigned to them; to the workspace it refuses every method except describing, reading the audit log, \" +\n \"joining, leaving and resuming.\",\n\n \"chap.control.resume\":\n \"Resume work paused at the same scope: a task returns to the state it held at the pause, a participant \" +\n \"can be assigned tasks again, a workspace returns to active.\",\n\n \"chap.control.cancel\":\n \"Cancel a task. Cancelled is terminal, and a task that has already settled cannot be cancelled. From the \" +\n \"moment a review the task requires opens until a reviewer rejects the work, the authors of the work cannot \" +\n \"cancel it, even once they take the work back, nor a successor that carries its review (-32011).\",\n\n \"chap.control.snapshot\":\n \"Capture the workspace state as an artefact before a change you may want to undo. Returns a snapshot \" +\n \"artefact id, which is the only thing chap.control.rollback accepts as a target; the label is for a human \" +\n \"reading the log and cannot be used to select it. Taking a snapshot changes nothing. Note that a rollback \" +\n \"restores only the mode ceiling and member roles, so a snapshot is a narrow safety net rather than a \" +\n \"general undo.\",\n\n \"chap.control.rollback\":\n \"Restore workspace state from a snapshot. The mode ceiling and member roles are restored; the rollback is \" +\n \"appended to the audit log rather than rewriting it.\",\n\n \"chap.control.supersede\":\n \"Replace a task with a successor in one call. The original moves to superseded and stays linked to its \" +\n \"replacement. The successor requires review when the original did, whatever its own review_required \" +\n \"says, and whoever made the original's work counts as an author of the successor's review. A paused \" +\n \"assignee is refused with -32063, and from the moment a review the original requires opens until a \" +\n \"reviewer rejects the work, the authors of the work cannot supersede it, nor a successor that carries its \" +\n \"review (-32011).\",\n\n \"chap.control.set_mode_ceiling\":\n \"Set the highest operating mode tasks in this workspace may request. A task above the ceiling is refused.\",\n\n // routing/1.0\n \"chap.task.route\":\n \"Choose an assignee for a task from a list of candidates and reassign the task to the one selected. Use \" +\n \"it where the choice itself belongs on the record: it writes a route_decision artefact naming the policy, \" +\n \"the candidate chosen and the alternatives passed over, none of which is captured by setting assignee \" +\n \"directly on chap.task.create. The default policy takes the first candidate that is a workspace member \" +\n \"and is not paused. An operator-supplied policy may choose on any basis, and the call is refused with \" +\n \"-32510 when its choice is not a member, or with -32063 when its choice is paused.\",\n\n \"chap.review.depth\":\n \"Decide how much review a task warrants, skip, spot_check or full, from its routing hints. Records a \" +\n \"route_decision artefact giving the rule that produced the answer.\",\n\n \"chap.escalate.auto\":\n \"Evaluate a task's routing hints against the escalation policy and report whether it should be escalated, \" +\n \"and to whom. It decides only: a route_decision artefact is recorded but the task does not move, so act \" +\n \"on the answer with chap.escalate.raise. The default policy escalates on criticality critical, or high \" +\n \"with confidence below 0.6.\",\n\n // security-signed/1.0\n \"chap.participant.rotate_key\":\n \"Retire a participant's signing key and register its replacement. The old key stays in the key history \" +\n \"with a valid_until timestamp, so envelopes it signed still verify.\",\n\n \"chap.participant.revoke_key\":\n \"Revoke a signing key, for example after a device is lost. Signatures presented with it are refused from \" +\n \"then on. Revoking another participant's key requires the admin role.\",\n\n // audit-scitt/1.0\n \"chap.audit.submit_to_scitt\":\n \"Build COSE_Sign1-shaped statements for a range of audit entries and submit them to the configured SCITT \" +\n \"transparency service. Where none is configured the statements are returned for submission out of band.\",\n\n \"chap.audit.verify_receipt\":\n \"Check a receipt returned by an external SCITT transparency service, confirming that service logged the \" +\n \"statement. This is the external half of verification; chap.audit.verify_chain checks the local prev-hash \" +\n \"chain instead, and the two answer different questions. Verification is delegated to a hook the \" +\n \"deployment supplies and fails closed with -32082 when none is configured, so a missing verifier can \" +\n \"never read as a pass. Reads only: nothing is recorded.\",\n\n \"chap.audit.verify_chain\":\n \"Replay a workspace's prev-hash chain. Only status verified with ok true means the log was checked and is \" +\n \"intact. Status not_evaluated with ok false means part of the log was never checked, so its integrity is \" +\n \"unknown and must not be reported as verified; entries_unchecked says how much. An error means the chain \" +\n \"is broken or absent.\",\n};\n\n/** MCP tool annotations (2025-03-26 onwards). Every field is a hint. */\nexport interface ToolAnnotations {\n /** Human-readable title, shown by a client instead of the raw tool name. */\n title: string;\n /** Does not modify state. Mirrors the coordinator's own read-only set. */\n readOnlyHint: boolean;\n /** May overwrite or remove existing state, or settle it irreversibly. */\n destructiveHint: boolean;\n /** A repeat with identical arguments succeeds and changes nothing further. */\n idempotentHint: boolean;\n /** Reaches a system outside this coordinator. */\n openWorldHint: boolean;\n}\n\n/**\n * Read-only, and so never recorded on the chain. This is the coordinator's own\n * READ_ONLY_METHODS set, the list that decides whether an envelope is\n * recorded. It is repeated here rather than imported so the adapter does not\n * depend on a coordinator export at runtime, and annotations.test.ts reads\n * that source and fails if the two ever diverge.\n */\nconst READ_ONLY = new Set([\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\", \"chap.audit.verify_receipt\",\n // Submitting reads the chain and sends it onward. It changes nothing here,\n // which is what readOnlyHint claims; openWorldHint carries the fact that it\n // reaches a service outside this coordinator.\n \"chap.audit.submit_to_scitt\",\n]);\n\n/** Overwrites, removes, or settles state irreversibly. */\nconst DESTRUCTIVE = new Set([\n \"chap.workspace.set_profiles\", // replaces the profile set; can strand entries outside the chain\n \"chap.participant.leave\", // removes a member\n \"chap.participant.revoke_key\", // invalidates a key from then on\n \"chap.control.cancel\", // cancelled is terminal\n \"chap.control.supersede\", // superseded is terminal\n \"chap.control.rollback\", // overwrites the mode ceiling and member roles\n]);\n\n/** Verified by calling twice with identical arguments and diffing workspace state. */\nconst IDEMPOTENT = new Set([\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\", \"chap.audit.verify_receipt\",\n \"chap.participant.join\", // a re-join is additive and adds no duplicate member\n \"chap.participant.leave\", // leaving twice leaves the same absence\n \"chap.control.pause\", // pausing an already paused target changes nothing\n \"chap.control.set_mode_ceiling\", // setting the ceiling it already has changes nothing\n \"chap.deliberate.close\", // returns the same outcome, recomputing nothing\n \"chap.review.acknowledge\", // a second acknowledgement in the round is refused and records nothing\n]);\n\n/** Reaches a transparency service outside this coordinator. */\nconst OPEN_WORLD = new Set([\n \"chap.audit.submit_to_scitt\", \"chap.audit.verify_receipt\",\n]);\n\n/**\n * Human-readable titles. A client that shows a title instead of the tool\n * name should still show something a person can read at a glance.\n */\nconst TITLES: Record<string, string> = {\n \"chap.workspace.create\": \"Create workspace\",\n \"chap.workspace.describe\": \"Describe workspace\",\n \"chap.workspace.set_profiles\": \"Replace workspace profiles\",\n \"chap.workspace.invite\": \"Invite participant\",\n \"chap.participant.join\": \"Add participant\",\n \"chap.participant.leave\": \"Remove participant\",\n \"chap.task.create\": \"Create task\",\n \"chap.task.update\": \"Change task state\",\n \"chap.task.complete\": \"Submit task output\",\n \"chap.audit.read\": \"Read audit log\",\n \"chap.review.request\": \"Request review\",\n \"chap.review.acknowledge\": \"Acknowledge review\",\n \"chap.decide.approve\": \"Approve\",\n \"chap.decide.reject\": \"Reject\",\n \"chap.decide.override\": \"Override with a correction\",\n \"chap.abstain.declare\": \"Abstain from review\",\n \"chap.escalate.raise\": \"Escalate task\",\n \"chap.whisper.ask\": \"Ask a whisper\",\n \"chap.whisper.answer\": \"Answer a whisper\",\n \"chap.deliberate.open\": \"Open deliberation\",\n \"chap.deliberate.comment\": \"Comment on deliberation\",\n \"chap.deliberate.vote\": \"Vote in deliberation\",\n \"chap.deliberate.close\": \"Close deliberation\",\n \"chap.handoff.propose\": \"Propose handoff\",\n \"chap.handoff.accept\": \"Accept handoff\",\n \"chap.handoff.decline\": \"Decline handoff\",\n \"chap.control.pause\": \"Pause work\",\n \"chap.control.resume\": \"Resume work\",\n \"chap.control.cancel\": \"Cancel task\",\n \"chap.control.snapshot\": \"Snapshot workspace\",\n \"chap.control.rollback\": \"Roll back to snapshot\",\n \"chap.control.supersede\": \"Supersede task\",\n \"chap.control.set_mode_ceiling\": \"Set mode ceiling\",\n \"chap.task.route\": \"Route task to an assignee\",\n \"chap.review.depth\": \"Decide review depth\",\n \"chap.escalate.auto\": \"Evaluate auto-escalation\",\n \"chap.participant.rotate_key\": \"Rotate signing key\",\n \"chap.participant.revoke_key\": \"Revoke signing key\",\n \"chap.audit.submit_to_scitt\": \"Anchor audit log in SCITT\",\n \"chap.audit.verify_receipt\": \"Verify SCITT receipt\",\n \"chap.audit.verify_chain\": \"Verify audit chain\",\n};\n\n/** Annotations for every tool, derived from the sets above. */\nexport const TOOL_ANNOTATIONS: Record<string, ToolAnnotations> = Object.fromEntries(\n Object.keys(TOOL_DESCRIPTIONS).map((name) => [name, {\n title: TITLES[name] ?? name,\n readOnlyHint: READ_ONLY.has(name),\n // Meaningful only when readOnlyHint is false, per the specification.\n destructiveHint: DESTRUCTIVE.has(name),\n idempotentHint: IDEMPOTENT.has(name),\n openWorldHint: OPEN_WORLD.has(name),\n }]),\n);\n\n/**\n * The tools an agent's own connection offers: what its work needs, and\n * nothing that chooses who reviews that work or passes its review on. The\n * decision tools and review.acknowledge stay for work the agent is asked to\n * review; on its own work the coordinator refuses them and records the\n * attempt. Left out are workspace and membership changes, review.request\n * (an explicit review may name its own author), escalate.raise (it passes\n * the open review on to a successor task), and every other tool.\n * task.update stays, and can take a task under review back to in_progress,\n * which withdraws the draft; the next completion opens the review again, so\n * a task that holds a review completes only through a decision.\n *\n * The stdio server offers this set by default. A server that gives an agent\n * its own MCP connection, as the templates' /mcp does, imports it from here.\n */\nexport const AGENT_MCP_TOOLS: ReadonlySet<string> = new Set([\n \"chap.task.create\", \"chap.task.update\", \"chap.task.complete\", \"chap.whisper.ask\",\n \"chap.decide.approve\", \"chap.decide.reject\", \"chap.decide.override\", \"chap.review.acknowledge\",\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\",\n]);\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightbeamai/chap-coordinator-mcp",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "MCP server adapter for the CHAP Coordinator. Exposes every CHAP method as an MCP tool.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Brightbeam AI <oss@brightbeam.com>",
@@ -24,7 +24,7 @@
24
24
  "mcpName": "io.github.BrightbeamAI/chap",
25
25
  "type": "module",
26
26
  "engines": {
27
- "node": ">=20"
27
+ "node": ">=22"
28
28
  },
29
29
  "bin": {
30
30
  "chap-mcp-server": "dist/cli.js"
@@ -65,7 +65,7 @@
65
65
  "prepublishOnly": "npm run typecheck && npm run test && npm run build"
66
66
  },
67
67
  "dependencies": {
68
- "@brightbeamai/chap-coordinator": "^0.3.3",
68
+ "@brightbeamai/chap-coordinator": "^0.3.5",
69
69
  "@modelcontextprotocol/sdk": "^1.32.1",
70
70
  "zod": "^3.25 || ^4.0"
71
71
  },