@rallycry/conveyor-mcp 5.0.1 → 5.0.3

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 ADDED
@@ -0,0 +1,102 @@
1
+ # @rallycry/conveyor-mcp
2
+
3
+ The Conveyor MCP server. It gives a coding agent — Claude Code, Codex, Cursor,
4
+ Windsurf, VS Code, Claude Desktop — direct access to your Conveyor cards,
5
+ plans, chat, tags, and pull requests.
6
+
7
+ ## Get your values
8
+
9
+ Open **User Settings → Connect your coding agent (MCP)** in the Conveyor web
10
+ app. It generates a token and copies a pre-filled command or config block that
11
+ already carries your API URL, token, and project id. Use that if you can.
12
+
13
+ To register the server by hand, replace the three placeholders below:
14
+
15
+ - `<api-url>` — your Conveyor API host.
16
+ - `<user-token>` — your personal token from User Settings. Treat it as a secret.
17
+ - `<project-id>` — the project to work in. Omit this variable for multi-project
18
+ mode, then pass `projectId` per tool call after calling `list_projects`.
19
+
20
+ ## Install
21
+
22
+ ### Claude Code (CLI)
23
+
24
+ ```bash
25
+ claude mcp remove conveyor -s local 2>/dev/null;
26
+ claude mcp add conveyor -s local \
27
+ -e CONVEYOR_API_URL=<api-url> \
28
+ -e CONVEYOR_USER_TOKEN=<user-token> \
29
+ -e CONVEYOR_PROJECT_ID=<project-id> \
30
+ -- npx -y @rallycry/conveyor-mcp@latest
31
+ ```
32
+
33
+ The `claude mcp remove` prefix makes the command idempotent. A bare
34
+ `claude mcp add` exits 1 with "already exists in local config" when a `conveyor`
35
+ server is already registered, which blocks a re-paste after a token rotation.
36
+
37
+ ### JSON config (Cursor, Windsurf, VS Code, Claude Desktop)
38
+
39
+ Merge this into your `mcpServers` block:
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "conveyor": {
45
+ "command": "npx",
46
+ "args": ["-y", "@rallycry/conveyor-mcp@latest"],
47
+ "env": {
48
+ "CONVEYOR_API_URL": "<api-url>",
49
+ "CONVEYOR_USER_TOKEN": "<user-token>",
50
+ "CONVEYOR_PROJECT_ID": "<project-id>"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### TOML config (Codex CLI, `~/.codex/config.toml`)
58
+
59
+ ```toml
60
+ [mcp_servers.conveyor]
61
+ command = "npx"
62
+ args = ["-y", "@rallycry/conveyor-mcp@latest"]
63
+
64
+ [mcp_servers.conveyor.env]
65
+ CONVEYOR_API_URL = "<api-url>"
66
+ CONVEYOR_USER_TOKEN = "<user-token>"
67
+ CONVEYOR_PROJECT_ID = "<project-id>"
68
+ ```
69
+
70
+ ## Environment variables
71
+
72
+ | Variable | Required | Purpose |
73
+ | ------------------------ | -------- | ------------------------------------------------------------------------------------ |
74
+ | `CONVEYOR_API_URL` | yes | Conveyor API host. |
75
+ | `CONVEYOR_USER_TOKEN` | yes | Your personal token. `CONVEYOR_PROJECT_TOKEN` is a backwards-compatible alias. |
76
+ | `CONVEYOR_PROJECT_ID` | no | Default project for unqualified tools. Omit it for multi-project mode. |
77
+ | `CONVEYOR_SUBPROJECT_ID` | no | Default board. Unqualified `create_task`/`list_tasks`/`search_tasks` target it. |
78
+
79
+ ## Why `npx -y …@latest`
80
+
81
+ Every form above launches the server through
82
+ `npx -y @rallycry/conveyor-mcp@latest`, so each start re-resolves the `@latest`
83
+ tag from the registry. Restarting the MCP server picks up newly published
84
+ versions, and there is no upgrade step to remember. The trade-off is a slightly
85
+ slower launch, because npx checks the registry each time.
86
+
87
+ The `@latest` tag is load-bearing. npx resolves a bare package name against the
88
+ local workspace first, so a bare `npx @rallycry/conveyor-mcp` inside a repo that
89
+ vendors a package of that name execs the unbuilt local copy and the server fails
90
+ to start. A version or tag spec forces registry resolution regardless of cwd.
91
+ Never shorten the command.
92
+
93
+ ## Verify
94
+
95
+ After you reload MCP servers, call `verify_connection`. It returns a plain
96
+ pass/fail plus, on failure, the failing layer and one next action. Then call
97
+ `get_connection_context` to confirm the account, project, and board are the ones
98
+ you intended.
99
+
100
+ ## License
101
+
102
+ MIT
@@ -208,14 +208,13 @@ var ConveyorConnection = class {
208
208
  const { projectId, subProjectId, tags, ...rest } = params;
209
209
  const resolvedProjectId = this.resolveProjectId(projectId);
210
210
  const resolvedSubProjectId = this.resolveSubProjectId(subProjectId);
211
+ const tagIds = await this.resolveTagIds(resolvedProjectId, tags ?? []);
211
212
  const result = await this.call("createProjectTask", {
212
213
  projectId: resolvedProjectId,
213
214
  subProjectId: resolvedSubProjectId,
214
215
  ...rest
215
216
  });
216
- if (tags && tags.length > 0) {
217
- await this.assignTagsToTask(result.id, resolvedProjectId, tags);
218
- }
217
+ await this.assignResolvedTags(result.id, tagIds);
219
218
  return {
220
219
  ...result,
221
220
  effectiveScope: {
@@ -230,12 +229,10 @@ var ConveyorConnection = class {
230
229
  const hasCoreUpdate = rest.title !== void 0 || rest.description !== void 0 || rest.plan !== void 0 || rest.status !== void 0 || rest.risk !== void 0 || rest.storyPointValue !== void 0 || rest.assignedUserId !== void 0 || rest.subProjectId !== void 0 || rest.githubBranch !== void 0;
231
230
  const removedTags = removeTags ?? [];
232
231
  const addedTags = addTags ?? [];
233
- if (removedTags.length > 0) {
234
- await this.removeTagsFromTask(rest.taskId, resolvedProjectId, removedTags);
235
- }
236
- if (addedTags.length > 0) {
237
- await this.assignTagsToTask(rest.taskId, resolvedProjectId, addedTags);
238
- }
232
+ const removeIds = await this.resolveTagIds(resolvedProjectId, removedTags);
233
+ const addIds = await this.resolveTagIds(resolvedProjectId, addedTags);
234
+ await this.removeResolvedTags(rest.taskId, removeIds);
235
+ await this.assignResolvedTags(rest.taskId, addIds);
239
236
  if (hasCoreUpdate) {
240
237
  const result = await this.call("updateProjectTask", { projectId: resolvedProjectId, ...rest });
241
238
  return { ...result, addedTags, removedTags };
@@ -270,13 +267,11 @@ var ConveyorConnection = class {
270
267
  }
271
268
  return [...new Set(ids)];
272
269
  }
273
- async assignTagsToTask(taskId, projectId, names) {
274
- const tagIds = await this.resolveTagIds(projectId, names);
270
+ async assignResolvedTags(taskId, tagIds) {
275
271
  if (tagIds.length === 0) return;
276
272
  await this.callService("tagService", "assignToTask", { taskId, tagIds });
277
273
  }
278
- async removeTagsFromTask(taskId, projectId, names) {
279
- const tagIds = await this.resolveTagIds(projectId, names);
274
+ async removeResolvedTags(taskId, tagIds) {
280
275
  if (tagIds.length === 0) return;
281
276
  await this.callService("tagService", "removeFromTask", { taskId, tagIds });
282
277
  }
@@ -552,7 +547,7 @@ var ConveyorConnection = class {
552
547
  ...rest
553
548
  });
554
549
  }
555
- // ── Meetings (read-only) ────────────────────────────────────────────
550
+ // ── Meetings ────────────────────────────────────────────────────────
556
551
  listMeetings(params) {
557
552
  const { projectId, ...rest } = params;
558
553
  return this.call("listMeetings", { projectId: this.resolveProjectId(projectId), ...rest });
@@ -568,6 +563,48 @@ var ConveyorConnection = class {
568
563
  ...rest
569
564
  });
570
565
  }
566
+ createMeeting(params) {
567
+ const { projectId, ...rest } = params;
568
+ return this.call("createProjectMeeting", {
569
+ projectId: this.resolveProjectId(projectId),
570
+ ...rest
571
+ });
572
+ }
573
+ updateMeeting(params) {
574
+ const { projectId, ...rest } = params;
575
+ return this.call("updateProjectMeeting", {
576
+ projectId: this.resolveProjectId(projectId),
577
+ ...rest
578
+ });
579
+ }
580
+ addMeetingChecklistItems(params) {
581
+ const { projectId, ...rest } = params;
582
+ return this.call("addProjectMeetingChecklistItems", {
583
+ projectId: this.resolveProjectId(projectId),
584
+ ...rest
585
+ });
586
+ }
587
+ checkMeetingChecklistItem(params) {
588
+ const { projectId, ...rest } = params;
589
+ return this.call("checkProjectMeetingChecklistItem", {
590
+ projectId: this.resolveProjectId(projectId),
591
+ ...rest
592
+ });
593
+ }
594
+ editMeetingChecklistItem(params) {
595
+ const { projectId, ...rest } = params;
596
+ return this.call("editProjectMeetingChecklistItem", {
597
+ projectId: this.resolveProjectId(projectId),
598
+ ...rest
599
+ });
600
+ }
601
+ removeMeetingChecklistItem(params) {
602
+ const { projectId, ...rest } = params;
603
+ return this.call("removeProjectMeetingChecklistItem", {
604
+ projectId: this.resolveProjectId(projectId),
605
+ ...rest
606
+ });
607
+ }
571
608
  /** Effective account/project/board identity + capabilities for this token. */
572
609
  getConnectionContext(projectId) {
573
610
  return this.call("getConnectionContext", {
@@ -707,13 +744,12 @@ var ConveyorConnection = class {
707
744
  async createSubtask(params) {
708
745
  const { projectId, tags, ...rest } = params;
709
746
  const resolvedProjectId = this.resolveProjectId(projectId);
747
+ const tagIds = await this.resolveTagIds(resolvedProjectId, tags ?? []);
710
748
  const result = await this.call("createProjectSubtask", {
711
749
  projectId: resolvedProjectId,
712
750
  ...rest
713
751
  });
714
- if (tags && tags.length > 0) {
715
- await this.assignTagsToTask(result.id, resolvedProjectId, tags);
716
- }
752
+ await this.assignResolvedTags(result.id, tagIds);
717
753
  return result;
718
754
  }
719
755
  /**