huly-mcp-selfhost 2.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/.env.example +39 -2
  2. package/README.md +462 -16
  3. package/dist/connection.d.ts +8 -0
  4. package/dist/connection.js +13 -1
  5. package/dist/connection.js.map +1 -1
  6. package/dist/env.d.ts +1 -0
  7. package/dist/env.js +17 -0
  8. package/dist/env.js.map +1 -0
  9. package/dist/guard.d.ts +28 -0
  10. package/dist/guard.js +152 -0
  11. package/dist/guard.js.map +1 -0
  12. package/dist/guides/costs.md +48 -0
  13. package/dist/guides/features.md +49 -0
  14. package/dist/guides/onboarding.md +56 -0
  15. package/dist/guides/workflow.md +57 -0
  16. package/dist/index.js +18 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/junit-cli.d.ts +8 -0
  19. package/dist/junit-cli.js +106 -0
  20. package/dist/junit-cli.js.map +1 -0
  21. package/dist/registry.d.ts +18 -0
  22. package/dist/registry.js +318 -0
  23. package/dist/registry.js.map +1 -0
  24. package/dist/resources.d.ts +12 -0
  25. package/dist/resources.js +212 -0
  26. package/dist/resources.js.map +1 -0
  27. package/dist/schemas.d.ts +1269 -17
  28. package/dist/schemas.js +890 -97
  29. package/dist/schemas.js.map +1 -1
  30. package/dist/server.d.ts +27 -1
  31. package/dist/server.js +197 -128
  32. package/dist/server.js.map +1 -1
  33. package/dist/tools/activity.d.ts +10 -0
  34. package/dist/tools/activity.js +62 -0
  35. package/dist/tools/activity.js.map +1 -0
  36. package/dist/tools/agent.d.ts +156 -0
  37. package/dist/tools/agent.js +523 -0
  38. package/dist/tools/agent.js.map +1 -0
  39. package/dist/tools/attachments.d.ts +4 -4
  40. package/dist/tools/calendar.d.ts +49 -0
  41. package/dist/tools/calendar.js +116 -0
  42. package/dist/tools/calendar.js.map +1 -0
  43. package/dist/tools/cards.d.ts +87 -0
  44. package/dist/tools/cards.js +246 -0
  45. package/dist/tools/cards.js.map +1 -0
  46. package/dist/tools/channels.d.ts +76 -7
  47. package/dist/tools/channels.js +86 -5
  48. package/dist/tools/channels.js.map +1 -1
  49. package/dist/tools/comments.d.ts +16 -4
  50. package/dist/tools/comments.js +26 -9
  51. package/dist/tools/comments.js.map +1 -1
  52. package/dist/tools/components.d.ts +5 -5
  53. package/dist/tools/components.js +4 -22
  54. package/dist/tools/components.js.map +1 -1
  55. package/dist/tools/contacts.d.ts +69 -0
  56. package/dist/tools/contacts.js +130 -0
  57. package/dist/tools/contacts.js.map +1 -0
  58. package/dist/tools/crm.d.ts +61 -0
  59. package/dist/tools/crm.js +117 -0
  60. package/dist/tools/crm.js.map +1 -0
  61. package/dist/tools/documents.d.ts +35 -12
  62. package/dist/tools/documents.js +107 -22
  63. package/dist/tools/documents.js.map +1 -1
  64. package/dist/tools/drive.d.ts +107 -0
  65. package/dist/tools/drive.js +277 -0
  66. package/dist/tools/drive.js.map +1 -0
  67. package/dist/tools/fields.d.ts +33 -0
  68. package/dist/tools/fields.js +124 -0
  69. package/dist/tools/fields.js.map +1 -0
  70. package/dist/tools/generic.d.ts +72 -0
  71. package/dist/tools/generic.js +242 -0
  72. package/dist/tools/generic.js.map +1 -0
  73. package/dist/tools/github.d.ts +21 -0
  74. package/dist/tools/github.js +80 -0
  75. package/dist/tools/github.js.map +1 -0
  76. package/dist/tools/hr.d.ts +97 -0
  77. package/dist/tools/hr.js +150 -0
  78. package/dist/tools/hr.js.map +1 -0
  79. package/dist/tools/inbox.d.ts +23 -0
  80. package/dist/tools/inbox.js +76 -0
  81. package/dist/tools/inbox.js.map +1 -0
  82. package/dist/tools/inventory.d.ts +61 -0
  83. package/dist/tools/inventory.js +103 -0
  84. package/dist/tools/inventory.js.map +1 -0
  85. package/dist/tools/issues.d.ts +63 -12
  86. package/dist/tools/issues.js +259 -48
  87. package/dist/tools/issues.js.map +1 -1
  88. package/dist/tools/labels.d.ts +52 -4
  89. package/dist/tools/labels.js +86 -4
  90. package/dist/tools/labels.js.map +1 -1
  91. package/dist/tools/log-time.d.ts +15 -1
  92. package/dist/tools/log-time.js +70 -6
  93. package/dist/tools/log-time.js.map +1 -1
  94. package/dist/tools/meetings.d.ts +30 -0
  95. package/dist/tools/meetings.js +78 -0
  96. package/dist/tools/meetings.js.map +1 -0
  97. package/dist/tools/members.d.ts +1 -1
  98. package/dist/tools/members.js +17 -1
  99. package/dist/tools/members.js.map +1 -1
  100. package/dist/tools/message-templates.d.ts +54 -0
  101. package/dist/tools/message-templates.js +88 -0
  102. package/dist/tools/message-templates.js.map +1 -0
  103. package/dist/tools/milestones.d.ts +9 -9
  104. package/dist/tools/organizations.d.ts +5 -5
  105. package/dist/tools/organizations.js +2 -1
  106. package/dist/tools/organizations.js.map +1 -1
  107. package/dist/tools/overview.d.ts +55 -0
  108. package/dist/tools/overview.js +395 -0
  109. package/dist/tools/overview.js.map +1 -0
  110. package/dist/tools/planner.d.ts +60 -0
  111. package/dist/tools/planner.js +145 -0
  112. package/dist/tools/planner.js.map +1 -0
  113. package/dist/tools/process.d.ts +50 -0
  114. package/dist/tools/process.js +137 -0
  115. package/dist/tools/process.js.map +1 -0
  116. package/dist/tools/products.d.ts +17 -0
  117. package/dist/tools/products.js +45 -0
  118. package/dist/tools/products.js.map +1 -0
  119. package/dist/tools/projects.d.ts +17 -4
  120. package/dist/tools/projects.js +31 -2
  121. package/dist/tools/projects.js.map +1 -1
  122. package/dist/tools/qms.d.ts +57 -0
  123. package/dist/tools/qms.js +171 -0
  124. package/dist/tools/qms.js.map +1 -0
  125. package/dist/tools/recruiting.d.ts +112 -0
  126. package/dist/tools/recruiting.js +203 -0
  127. package/dist/tools/recruiting.js.map +1 -0
  128. package/dist/tools/relations.d.ts +45 -3
  129. package/dist/tools/relations.js +128 -39
  130. package/dist/tools/relations.js.map +1 -1
  131. package/dist/tools/search.d.ts +14 -1
  132. package/dist/tools/search.js +29 -1
  133. package/dist/tools/search.js.map +1 -1
  134. package/dist/tools/sharing.d.ts +62 -0
  135. package/dist/tools/sharing.js +149 -0
  136. package/dist/tools/sharing.js.map +1 -0
  137. package/dist/tools/statuses.d.ts +3 -3
  138. package/dist/tools/surveys.d.ts +22 -0
  139. package/dist/tools/surveys.js +53 -0
  140. package/dist/tools/surveys.js.map +1 -0
  141. package/dist/tools/templates.d.ts +95 -0
  142. package/dist/tools/templates.js +260 -0
  143. package/dist/tools/templates.js.map +1 -0
  144. package/dist/tools/test-automation.d.ts +81 -0
  145. package/dist/tools/test-automation.js +225 -0
  146. package/dist/tools/test-automation.js.map +1 -0
  147. package/dist/tools/testing.d.ts +234 -0
  148. package/dist/tools/testing.js +401 -0
  149. package/dist/tools/testing.js.map +1 -0
  150. package/dist/tools/workspace-admin.d.ts +55 -0
  151. package/dist/tools/workspace-admin.js +117 -0
  152. package/dist/tools/workspace-admin.js.map +1 -0
  153. package/dist/tools/workspaces.d.ts +1 -1
  154. package/dist/utils/attributes.d.ts +37 -0
  155. package/dist/utils/attributes.js +188 -0
  156. package/dist/utils/attributes.js.map +1 -0
  157. package/dist/utils/classes.d.ts +51 -0
  158. package/dist/utils/classes.js +73 -0
  159. package/dist/utils/classes.js.map +1 -0
  160. package/dist/utils/content.d.ts +11 -0
  161. package/dist/utils/content.js +86 -0
  162. package/dist/utils/content.js.map +1 -0
  163. package/dist/utils/errors.js +1 -1
  164. package/dist/utils/errors.js.map +1 -1
  165. package/dist/utils/files.d.ts +5 -0
  166. package/dist/utils/files.js +50 -0
  167. package/dist/utils/files.js.map +1 -0
  168. package/dist/utils/format.d.ts +2 -0
  169. package/dist/utils/format.js +7 -13
  170. package/dist/utils/format.js.map +1 -1
  171. package/dist/utils/junit.d.ts +13 -0
  172. package/dist/utils/junit.js +81 -0
  173. package/dist/utils/junit.js.map +1 -0
  174. package/dist/utils/markdown.js +9 -4
  175. package/dist/utils/markdown.js.map +1 -1
  176. package/dist/utils/meeting.d.ts +13 -0
  177. package/dist/utils/meeting.js +118 -0
  178. package/dist/utils/meeting.js.map +1 -0
  179. package/dist/utils/people.d.ts +25 -0
  180. package/dist/utils/people.js +80 -0
  181. package/dist/utils/people.js.map +1 -0
  182. package/dist/utils/redact.d.ts +3 -0
  183. package/dist/utils/redact.js +26 -0
  184. package/dist/utils/redact.js.map +1 -0
  185. package/dist/utils/resolve.d.ts +17 -0
  186. package/dist/utils/resolve.js +54 -0
  187. package/dist/utils/resolve.js.map +1 -0
  188. package/dist/utils/spec.d.ts +10 -0
  189. package/dist/utils/spec.js +90 -0
  190. package/dist/utils/spec.js.map +1 -0
  191. package/dist/utils/storage.js +7 -3
  192. package/dist/utils/storage.js.map +1 -1
  193. package/dist/utils/tasks.d.ts +22 -0
  194. package/dist/utils/tasks.js +81 -0
  195. package/dist/utils/tasks.js.map +1 -0
  196. package/dist/watch.d.ts +62 -0
  197. package/dist/watch.js +405 -0
  198. package/dist/watch.js.map +1 -0
  199. package/package.json +4 -3
  200. package/scripts/setup.js +3 -1
package/README.md CHANGED
@@ -27,46 +27,190 @@ This is a fork of [varaprasadreddy9676/huly-mcp](https://github.com/varaprasadre
27
27
  - **Issue Statuses** — `list_issue_statuses`, `create_issue_status` (custom workflow states)
28
28
  - **Organizations** — `list_organizations`, `get_organization`, `create_organization`, `update_organization`
29
29
 
30
- **Investigated and deliberately not built:** Calendar (not a native event system in Huly — it's a Google Calendar sync bridge requiring infra this fork doesn't assume you're running) and Drive/HR/Recruiting/CRM-Leads/Board (blocked by an [upstream npm packaging bug](https://github.com/hcengineering/platform/issues/10881) — `@hcengineering/*` packages published `0.7.411`+ ship without their `types/` directory, and these modules have no earlier version to pin around it).
30
+ **Beyond the tracker (3.0):** inbox, activity history, planner to-dos and time blocking, calendar events, chat threads/reactions/pins, GitHub pull requests, contact persons — plus generic read access to *every* Huly class (`list_classes`, `describe_class`, `query_documents`) and optional guarded writes (`generic_*`). Modules without a published npm type package (Recruiting, CRM, HR, Board, Drive, …) are reachable through the generic tools; dedicated tools for them follow in 3.1/3.2.
31
+
32
+ **Deliberately not built:** Love (live video office), Gmail/Telegram/Bitrix bridges (need their own service setup), analytics and UI preferences.
31
33
 
32
34
  ---
33
35
 
34
- ## Tools (53 total)
36
+ ## Tools (224 total, grouped in toolsets)
35
37
 
36
38
  All tools except `list_workspaces` take a `workspace` argument — required for every change, optional for reads when only one workspace is available.
37
39
 
40
+ ### Toolsets
41
+
42
+ Every tool schema is sent to the model in each session (Claude Desktop loads all of them up front), so tools are grouped and only the default toolsets are enabled unless you choose otherwise:
43
+
44
+ ```bash
45
+ HULY_TOOLSETS=all # everything
46
+ HULY_TOOLSETS=tracker,documents,planner # just these ('core' = list_workspaces is always on)
47
+ ```
48
+
49
+ **Load on demand** (`HULY_DYNAMIC_TOOLSETS=1`): `HULY_TOOLSETS` becomes the starting set, and Claude loads more toolsets itself via `enable_toolsets`. Called without arguments, it lists every toolset with its tools; called with names, it loads them and tells the client that the tool list changed. With `HULY_TOOLSETS=agent,inbox` a session starts at ≈1.8k tokens instead of ≈9–11k. This needs a client that reloads the tool list on `notifications/tools/list_changed`: it is tested with the MCP SDK client, but **not yet verified in Claude Desktop**. Without the variable, nothing changes.
50
+
51
+ | Toolset | Default | Tools | Contents |
52
+ |---------|:-:|--:|----------|
53
+ | `agent` | ✓ | 14 | agent workflow: my day at a glance, standup, project report, release notes, issue context in one call, start/finish work, plan → issue tree, spec document → issues, meeting notes → issues, changes since, claims, repo → project — plus [resources and prompts](#agent-workflow) |
54
+ | `tracker` | ✓ | 37 | projects, issues, comments, time, labels, relations, milestones, components, statuses, attachments, search |
55
+ | `documents` | ✓ | 8 | teamspaces and documents (tree, move, rename) |
56
+ | `chat` | ✓ | 12 | channels, DMs, threads, edit/delete, reactions, pins |
57
+ | `contacts` | ✓ | 11 | members, organizations, persons, contact channels |
58
+ | `inbox` | ✓ | 3 | notifications, triage (what changed since last read), mark read/archive |
59
+ | `activity` | ✓ | 1 | change history of an issue/object |
60
+ | `planner` | ✓ | 5 | to-dos, time blocking |
61
+ | `generic` | ✓ | 4 | fulltext search across everything, read any Huly class |
62
+ | `tracker-admin` | | 12 | rarely needed admin: create/update project, create status, update/delete label, label categories, delete milestone/component, repair parent links, project types and workflows |
63
+ | `calendar` | | 4 | calendar events |
64
+ | `github` | | 2 | pull requests synced by Huly's GitHub integration (read-only) |
65
+ | `generic-write` | | 3 | create/update/delete any class — dry run by default, deletes need `confirm` |
66
+ | `collaboration` | | 8 | followers (collaborators) of issues/documents, public guest links, document comments |
67
+ | `cards` | | 8 | cards: types and tags, create/edit/move/delete, nesting, field values |
68
+ | `fields` | | 3 | custom fields on issues, project types, card types or any class; set values |
69
+ | `drive` | | 10 | drives, folders, versioned files: upload, download, move, restore versions |
70
+ | `templates` | | 11 | issue templates with sub-issues, new issue from template; message templates |
71
+ | `testing` | | 23 | test management: projects, suites, cases, plans, runs, results; JUnit import, report, bugs from failed tests |
72
+ | `products` | | 2 | products and versions (read-only) |
73
+ | `members` | | 4 | workspace settings, invite links and e-mails, member roles |
74
+ | `recruiting` | | 9 | vacancies, candidates, applications |
75
+ | `crm` | | 5 | leads, customers |
76
+ | `hr` | | 7 | departments, staff, vacation/sick/remote days |
77
+ | `inventory` | | 5 | categories, products, variants (SKU) |
78
+ | `meetings` | | 2 | office rooms, meeting minutes and transcripts (read-only) |
79
+ | `qms` | | 4 | controlled documents and trainings (read-only) |
80
+ | `process` | | 4 | process definitions and executions; start and cancel |
81
+ | `surveys` | | 2 | surveys and aggregated poll answers (read-only) |
82
+
83
+ Context cost of `tools/list` (≈3.5 chars/token):
84
+
85
+ | | default (96 tools) | `all` (224 tools) |
86
+ |---|--:|--:|
87
+ | several workspaces | ~36.5k chars ≈ **10.4k tokens** | ~81.6k chars ≈ **23.3k tokens** |
88
+ | pinned with `HULY_WORKSPACE` | ~33k chars ≈ **9.4k tokens** | ~73.3k chars ≈ **20.9k tokens** |
89
+
90
+ For comparison, 2.2.0 needed ≈12.8k tokens for 64 tools. **Using one workspace? Set `HULY_WORKSPACE`** — the `workspace` argument then disappears from every tool (−10%). **Claude Code** loads MCP tools on demand, so there even `HULY_TOOLSETS=all` costs little up front.
91
+
92
+ ### Agent workflow
93
+
94
+ Tools, resources and prompts for AI agents working on Huly issues (toolset `agent`):
95
+
96
+ | Tool | What it does |
97
+ |------|--------------|
98
+ | `my_day` | Today (or `date`) in one call: own calendar events and work slots, open to-dos (overdue and due first), open issues assigned to me (in progress first), PRs waiting for my review and my own open PRs, unread inbox grouped by object. Times in UTC |
99
+ | `standup` | What I did since the last working day (Monday → Friday, or `since`): status changes, new issues, comments, time, finished to-dos; then today (calendar, to-dos, my issues) and my issues blocked by open ones |
100
+ | `release_notes` | Release notes from a milestone: done issues as "New and changed" and "Fixes" (by title or label, English and German), merged PR numbers, epics left out; open issues listed separately |
101
+ | `project_report` | Weekly (or `since`: `14d`, ISO date) report of a project: done in the period (status changed to done — not just touched by sync), new, in progress (flagged when untouched), blocked by open issues, overdue, PRs merged and open, open milestones with progress and target, time logged per person. To keep it in Huly, pass the text to `create_document` + `update_document` |
102
+ | `get_issue_context` | Everything about an issue in one call: fields, description, parent chain, sub-issues, blocked by / blocks, related, PRs, comments, suggested branch name |
103
+ | `start_work` | Status → In Progress, assign to me, optionally claim — returns the full context |
104
+ | `finish_work` | Work summary as comment, PR (`#12`, URL or Huly id) linked as sub-issue, status → Review in progress, claim released. Validates the PR before changing anything |
105
+ | `create_issue_tree` | Plan → epic + sub-issues with priorities, components, milestones, assignees, labels and blockers (`"#2"` = second child). Same-title issues are reused, dry run by default |
106
+ | `issues_from_document` | Spec → issues: the open checklist items of a Huly document (without a checklist: its sections) become sub-issues of an epic, checked items are skipped, the document is linked to the epic. Dry run by default; one call instead of reading the document and repeating every task |
107
+ | `issues_from_meeting` | Meeting notes → issues: open checkboxes, lines starting with `TODO:`/`Action:`/`Aufgabe:` and list items under a heading like "Action items" or "Next steps" become issues. `@Name` (or a Huly mention) becomes the assignee, a date (`2026-11-10`, `10.11.2026`, "due …"/"bis …") the due date. Unknown people are flagged and left unassigned; same-title issues are skipped; each new issue is linked to the document. Dry run by default |
108
+ | `changes_since` | Issues/PRs changed since `24h`, `7d` or an ISO time — which fields changed, new comments, by whom |
109
+ | `find_project_for_repo` | Workspace + project linked to a GitHub repo (`owner/name`, URL or git remote) via Huly's GitHub integration |
110
+ | `claim_issue` / `release_issue` | Lease an issue to an agent (label `agent:working` + comment marker) so parallel agents skip it; expires after `minutes` |
111
+
112
+ **Resources** — `huly://<workspace>/issue/<PROJ-12>` and `huly://<workspace>/document/<id>`. Your open assigned issues are listed, so in Claude Code you can `@`-mention them.
113
+
114
+ **Prompts** — `start`, `finish`, `plan`, `triage`, `standup` (in Claude Code: `/mcp__huly__start` …).
115
+
116
+ **Guard rails** (environment):
117
+
118
+ | Variable | Effect |
119
+ |----------|--------|
120
+ | `HULY_WRITE_PROJECTS=TSK,WEB` | Changes are only allowed when every project they touch (project keys and `PROJ-12` ids in the arguments) is listed. Reads are never blocked. Tools without a project (chat, documents, planner) are not affected |
121
+ | `HULY_AUDIT_LOG=/path/audit.jsonl` | Every change is appended as one JSON line (time, tool, shortened arguments, success, first line of the result) |
122
+ | `HULY_AGENT_NAME=claude-2` | Default agent name for claims |
123
+ | `HULY_CONFIRM=auto` | Deletes and other hard-to-undo tools (`delete_*`, `bulk_update_issues`, `move_issue`, `generic_update`/`generic_delete`, `revoke_public_link`, `restore_file_version`) ask you first via MCP elicitation when the client can show a form (Claude Code in an interactive session). `auto` (default): ask when possible, otherwise run as before. `strict`: refuse when the client cannot ask (unattended agents). `off`: never ask. Dry runs never ask |
124
+
125
+ ### Huly hands work to Claude: `huly-mcp watch`
126
+
127
+ `huly-mcp watch` turns Huly into the place where you give Claude work. It polls for open issues that carry a label (`--label claude`) or are assigned to the account it runs as (`--assigned`, the default), and for each one:
128
+
129
+ 1. claims the issue (`claim_issue`), so a second watcher or agent skips it,
130
+ 2. runs a command for it — by default `claude -p` in the current directory, with this MCP server attached and a prompt that says: read the issue, do the work, hand back with `finish_work`,
131
+ 3. releases the claim if the run did not (`finish_work` releases it), and comments on the issue if the run failed or timed out.
132
+
133
+ ```bash
134
+ cd ~/code/my-repo
135
+ npx huly-mcp-selfhost watch --workspace acme --project WEB --label claude --dry-run # what would run
136
+ npx huly-mcp-selfhost watch --workspace acme --project WEB --label claude # poll every 60 s
137
+ ```
138
+
139
+ - **Each issue runs once.** A state file (`~/.huly-mcp/watch-<workspace>.json`) remembers it. To run it again, remove the label and add it again.
140
+ - **The command is yours.** `--command` takes any program; the placeholders `{prompt}` `{issue}` `{title}` `{workspace}` `{agent}` `{trigger}` `{mcpConfig}` are filled in per argument — no shell is involved, so issue titles cannot inject shell commands. The run also gets `HULY_ISSUE`, `HULY_ISSUE_TITLE` and `HULY_WORKSPACE` in its environment. Examples: a GitHub Action (`--command "gh workflow run agent.yml -f issue={issue}"`), or Claude with more tools (`--command "claude -p {prompt} --mcp-config {mcpConfig} --allowedTools mcp__huly,Bash(npm test),Edit"`).
141
+ - **Default command:** `claude -p {prompt} --mcp-config {mcpConfig} --strict-mcp-config --allowedTools mcp__huly --permission-mode acceptEdits`. `{mcpConfig}` is a temporary MCP config that starts this server limited to the watched workspace; the credentials are passed through the environment, not written to the file.
142
+ - **Unattended means careful.** Runs get `HULY_CONFIRM=strict` unless you set it: deletes and other risky tools are refused, because nobody is there to confirm them. `HULY_WRITE_PROJECTS` limits which projects are watched and changed. Issue text reaches the agent as instructions — only watch projects whose writers you trust.
143
+ - **Its own identity.** Give the agent its own Huly account (invite e.g. `claude@your-domain` to the workspace) and start the watcher with that account's credentials (`--env-file agent.env` with `HULY_EMAIL`/`HULY_PASSWORD` or `HULY_TOKEN`). Then you hand work to Claude by assigning an issue to that user, and every comment, status change and claim shows up under its name instead of yours. `--agent <name>` (or `HULY_AGENT_NAME`) names it in claims.
144
+ - Other options: `--interval <sec>`, `--timeout <min>` (default 60), `--once`, `--cwd <dir>`, `--prompt <template>`, `--state <file>`. `huly-mcp watch --help` lists them all.
145
+
146
+ ### CI test results into Huly: `huly-mcp junit`
147
+
148
+ `huly-mcp junit report.xml --project "App"` imports a JUnit XML report as a test run in Huly's test management. Almost every test runner writes JUnit XML (Jest/Vitest with a JUnit reporter, `pytest --junitxml`, `go-junit-report`, Gradle, Maven Surefire, xcpretty). Suites and cases that do not exist yet are created; failed tests keep their message and stack trace. Then ask Claude *"What is flaky in App?"* (`get_test_report`) or *"File bugs for today's failures in PROJ"* (`create_issue_from_test_result`).
149
+
150
+ ```yaml
151
+ # .github/workflows/test.yml (after the test step)
152
+ - name: Report to Huly
153
+ if: always()
154
+ run: npx -y huly-mcp-selfhost junit reports/junit.xml --project "App" --run "CI ${{ github.ref_name }} #${{ github.run_number }}"
155
+ env:
156
+ HULY_URL: ${{ secrets.HULY_URL }}
157
+ HULY_TOKEN: ${{ secrets.HULY_TOKEN }}
158
+ HULY_WORKSPACE: my-workspace
159
+ ```
160
+
161
+ Options: `--run <name>`, `--parent-suite <suite>`, `--no-create` (only existing cases), `--fail-on-failures` (exit code 1 when tests failed), `--dry-run`, `--workspace`. `huly-mcp junit --help` lists them.
162
+
163
+ ### Tool reference
164
+
38
165
  | Category | Tool | Description |
39
166
  |----------|------|-------------|
40
167
  | **Workspaces** | `list_workspaces` | List the workspaces this account can access (name, slug, id) |
41
168
  | **Projects** | `list_projects` | List all projects in a workspace |
42
169
  | | `get_project` | Get project details + available statuses |
43
- | | `create_project` | Create a new tracker project with a unique identifier |
44
- | **Issues** | `list_issues` | List issues with optional status / priority filters |
45
- | | `get_issue` | Get full details of an issue (e.g. `PROJ-42`) |
170
+ | | `create_project` | Create a new tracker project with a unique identifier *(tracker-admin)* |
171
+ | | `update_project` | Change name, description, default assignee or default status *(tracker-admin)* |
172
+ | **Issues** | `list_issues` | List issues — open ones by default (`status: "all"` or a status name for others), filterable by priority, milestone, component, label, assignee, parent; `offset` pages through long lists ("51–100 of 118") |
173
+ | | `get_issue` | Full details of an issue (e.g. `PROJ-42`): assignee, milestone, component, labels, parent, links |
46
174
  | | `create_issue` | Create a new issue (with optional Markdown description) |
47
175
  | | `update_issue` | Update title, description, status, priority, assignee, due date, component, milestone |
48
176
  | | `delete_issue` | Permanently delete an issue by identifier |
177
+ | | `bulk_update_issues` | Same change on many issues at once — validates all before writing |
178
+ | | `move_issue` | Move an issue (with sub-issues, comments, attachments, labels, time) to another project |
179
+ | | `list_sub_issues` | Sub-issue tree of an epic with status and progress |
49
180
  | **Comments** | `add_comment` | Add a comment to an issue |
50
- | | `list_comments` | List all comments on an issue (includes IDs for `delete_comment`) |
181
+ | | `list_comments` | Newest comments on an issue, oldest first (includes IDs for `delete_comment`); comments over 1,500 chars are shortened with a marker unless `full: true` |
182
+ | | `update_comment` | Edit a comment |
51
183
  | | `delete_comment` | Delete a specific comment by ID |
52
184
  | **Time Tracking** | `log_time` | Log hours spent on an issue |
185
+ | | `list_time_reports` | Logged time per issue or project, totals per member, member/date filters |
53
186
  | **Labels** | `list_labels` | List all labels with color + usage count |
54
187
  | | `create_label` | Create a new label with an optional hex color |
55
188
  | | `add_label` | Add a label to an issue (auto-creates if it doesn't exist) |
56
189
  | | `remove_label` | Remove a label from an issue |
190
+ | | `update_label` | Rename or recolor a label (updated on every issue) *(tracker-admin)* |
191
+ | | `delete_label` | Delete a label and remove it from every issue *(tracker-admin)* |
57
192
  | **Relations** | `add_relation` | Mark two issues as related (bidirectional) |
58
193
  | | `add_blocked_by` | Mark an issue as blocked by another issue |
59
194
  | | `set_parent` | Set or clear the parent epic of an issue |
60
- | **Members** | `list_members` | List workspace members |
195
+ | | `remove_relation` | Remove a "related" link |
196
+ | | `remove_blocked_by` | Remove a "blocked by" link |
197
+ | | `repair_parent_links` | Fix sub-issues linked by huly-mcp ≤ 2.1 that don't show under their parent (dry run by default) *(tracker-admin)* |
198
+ | **Members** | `list_members` | List workspace members with names and roles |
199
+ | **Persons** (`contacts`) | `list_persons` | Contact persons with their channels |
200
+ | | `get_person` | Person details, contact channels, organizations |
201
+ | | `create_person` | Create a contact person (with optional channels) |
202
+ | | `update_person` | Change name or city |
203
+ | | `add_contact_channel` | Add email, phone, LinkedIn, … |
204
+ | | `remove_contact_channel` | Remove a contact channel |
61
205
  | **Milestones** | `list_milestones` | List milestones for a project |
62
206
  | | `create_milestone` | Create a milestone with a target date and status |
63
207
  | | `get_milestone` | Milestone details with progress (done/open/canceled issues) and the open issues |
64
208
  | | `update_milestone` | Change name, target date, status or description |
65
- | | `delete_milestone` | Delete a milestone; its issues are unassigned or moved (`moveIssuesTo`) |
209
+ | | `delete_milestone` | Delete a milestone; its issues are unassigned or moved (`moveIssuesTo`) *(tracker-admin)* |
66
210
  | **Components** | `list_components` | List components (sub-areas) in a project |
67
211
  | | `create_component` | Create a new component with optional lead |
68
212
  | | `update_component` | Change name, description or lead |
69
- | | `delete_component` | Delete a component; its issues are unassigned or moved (`moveIssuesTo`) |
213
+ | | `delete_component` | Delete a component; its issues are unassigned or moved (`moveIssuesTo`) *(tracker-admin)* |
70
214
  | **Documents** | `list_teamspaces` | List document teamspaces |
71
215
  | | `create_teamspace` | Create a new teamspace (top-level document folder) |
72
216
  | | `list_documents` | List documents in a teamspace |
@@ -75,21 +219,89 @@ All tools except `list_workspaces` take a `workspace` argument — required for
75
219
  | | `create_document` | Create a new document in a teamspace |
76
220
  | | `update_document` | Write Markdown content to a document — Mermaid diagrams render natively |
77
221
  | | `link_document` | Link a document to an issue — appears in the Relations panel |
222
+ | | `list_documents` | Shows the full document tree; `update_document` also renames and moves (incl. to another teamspace, with sub-documents) |
78
223
  | **Search** | `search_issues` | Full-text search across all issues of a workspace |
224
+ | | `search` | Full-text search across everything — issues, documents, messages, cards, files, persons … (`kinds` filter) *(generic)* |
79
225
  | **Chat** | `list_channels` | List all channels in the workspace |
80
226
  | | `create_channel` | Create a new channel |
81
227
  | | `start_direct_message` | Start (or find) a 1:1 direct message with a workspace member |
82
228
  | | `send_message` | Send a message to a channel or direct message |
83
- | | `list_messages` | List messages in a channel or direct message |
229
+ | | `list_messages` | List messages with authors, ids, replies, reactions, pins |
230
+ | | `list_thread` | A message with its thread replies |
231
+ | | `reply_to_message` | Reply in a thread (channel messages and issue comments) |
232
+ | | `update_message` | Edit a message or reply |
233
+ | | `delete_message` | Delete a message or reply |
234
+ | | `add_reaction` / `remove_reaction` | Emoji reactions |
235
+ | | `pin_message` | Pin or unpin a message |
84
236
  | **Attachments** | `attach_file` | Attach a file to an issue (base64-encoded content) |
85
237
  | | `list_attachments` | List files attached to an issue |
86
238
  | | `delete_attachment` | Delete a file attachment from an issue |
87
239
  | **Issue Statuses** | `list_issue_statuses` | List all issue statuses (workflow states), grouped by phase |
88
- | | `create_issue_status` | Create a new issue status — available in every project immediately |
240
+ | | `create_issue_status` | Create a new issue status — available in every project immediately *(tracker-admin)* |
89
241
  | **Organizations** | `list_organizations` | List all organizations (companies) in the workspace |
90
242
  | | `get_organization` | Get details of an organization, including description |
91
243
  | | `create_organization` | Create a new organization (company contact) |
92
244
  | | `update_organization` | Set the description of an organization from Markdown |
245
+ | **Inbox** (`inbox`) | `list_notifications` | Your notifications, grouped by issue/PR/document |
246
+ | | `triage_inbox` | Work through the inbox in one call: per unread item its status and assignee, which fields changed and the new comments (plain text, shortened) since you last read it |
247
+ | | `mark_notifications_read` | Mark read by object, ids or all; optionally archive |
248
+ | **Activity** (`activity`) | `get_activity` | Who changed what, plus comments, for an issue or object |
249
+ | **Planner** (`planner`) | `list_todos` | Your to-dos (open/done, due date filter) |
250
+ | | `create_todo` | Create a to-do, optionally attached to an issue |
251
+ | | `update_todo` | Change title, due date, priority; mark done/reopen |
252
+ | | `delete_todo` | Delete a to-do |
253
+ | | `schedule_todo` | Block time for a to-do in your calendar |
254
+ | **Calendar** (`calendar`) | `list_events` | Events and work slots in a date range |
255
+ | | `create_event` / `update_event` / `delete_event` | Manage events in your calendar |
256
+ | **GitHub** (`github`) | `list_pull_requests` | PRs by project, issue, state |
257
+ | | `get_pull_request` | State, branches, reviews, review comments, linked issue |
258
+ | **Generic** (`generic`) | `list_classes` | All data classes of the workspace (filter by module, optional counts) |
259
+ | | `describe_class` | Attributes and types of a class |
260
+ | | `query_documents` | Read documents of any class; secrets are redacted |
261
+ | **Generic write** (`generic-write`) | `generic_create` / `generic_update` / `generic_delete` | Any class; dry run by default, deletes also need `confirm: true`; system classes, spaces and credentials are blocked |
262
+ | **Collaboration** (`collaboration`) | `list_collaborators` / `add_collaborator` / `remove_collaborator` | Who follows an issue/document (and gets its notifications) |
263
+ | | `create_public_link` / `list_public_links` / `revoke_public_link` | Read-only guest links for issues and documents |
264
+ | | `list_document_comments` / `add_document_comment` | Comments on documents |
265
+ | **Cards** (`cards`) | `list_card_types` / `create_card_type` / `delete_card_type` | Card types (MasterTags) and tags |
266
+ | | `list_cards` / `get_card` | Cards by type, parent or title; one card with fields, tags, children, content |
267
+ | | `create_card` / `update_card` / `delete_card` | With content (Markdown), parent, tags and field values |
268
+ | **Custom fields** (`fields`) | `list_custom_fields` | Fields of issues, a project type, card type or class — or the values on one object |
269
+ | | `create_custom_field` | string, number, boolean, date, markup, enum (with values) or ref |
270
+ | | `set_custom_fields` | Set values on an issue, card or document (validated against the type) |
271
+ | **Drive** (`drive`) | `list_drives` / `create_drive` / `list_drive_files` | Drives and their folder tree |
272
+ | | `create_folder` / `update_drive_item` / `delete_drive_item` | Folders; rename/move files and folders (across drives too) |
273
+ | | `upload_file` / `download_file` | Base64 or local files under `HULY_FILE_ROOT`; same name → new version |
274
+ | | `list_file_versions` / `restore_file_version` | File history |
275
+ | **Issue templates** (`templates`) | `list_issue_templates` / `get_issue_template` | Templates with their sub-issues |
276
+ | | `create_issue_template` / `update_issue_template` / `delete_issue_template` | Priority, assignee, component, milestone, estimation, labels, sub-issues |
277
+ | | `create_issue_from_template` | New issue plus sub-issues from a template |
278
+ | **Test management** (`testing`) | `list_test_projects` / `create_test_project` | Test projects |
279
+ | | `list_test_cases` / `create_test_suite` / `get_test_case` / `create_test_case` / `update_test_case` / `delete_test_case` | Suites (nested) and cases |
280
+ | | `list_test_plans` / `create_test_plan` | Plans from suites and/or cases |
281
+ | | `create_test_run` / `list_test_runs` / `get_test_run` / `set_test_result` | Runs with Passed/Failed/Blocked results; results can be assigned |
282
+ | | `create_test_cases` | Many cases in one call (e.g. drafted from a spec or an issue); existing names are skipped |
283
+ | | `update_test_suite` / `delete_test_suite` / `update_test_run` / `delete_test_run` / `delete_test_plan` | Rename/move suites (no cycles), delete with `recursive`, run due dates |
284
+ | | `import_test_results` | JUnit XML from CI (Jest, Vitest, pytest, Go, Gradle, Maven, xcpretty …) as a run; missing suites/cases are created, failures keep message and stack trace |
285
+ | | `get_test_report` | Over the latest runs: failing now, flaky (flipped ≥ 2×), blocked, never run, per-suite table |
286
+ | | `create_issue_from_test_result` | Bug from a failed result: steps + failure in the description, related to the test case, comment on the result |
287
+ | **Products** (`products`) | `list_products` / `get_product` | Products and their versions (read-only) |
288
+ | **Labels** (`tracker-admin`) | `list_label_categories` / `create_label_category` / `set_label_category` | Group issue labels |
289
+ | **Project types** (`tracker-admin`) | `list_project_types` | Project types, their task types and status workflows, and which projects use them |
290
+ | **Workspace** (`members`) | `get_workspace_settings` | Your role, members per role, invite defaults, integrations |
291
+ | | `create_invite_link` / `send_invite` / `set_member_role` | Invite links (personal or with use limit and e-mail mask; nothing is sent), invitation e-mails, roles. `send_invite` and `set_member_role` ask for confirmation |
292
+ | **Recruiting** (`recruiting`) | `list_vacancies` / `create_vacancy` / `update_vacancy` | Vacancies with applications per status; archive via `update_vacancy` |
293
+ | | `list_candidates` / `create_candidate` | Candidates (person + title, e-mail, onsite/remote) |
294
+ | | `list_applications` / `create_application` / `update_application` / `delete_application` | Applications `APP-n` through the vacancy's workflow, one per candidate and vacancy |
295
+ | **CRM** (`crm`) | `list_leads` / `create_lead` / `update_lead` / `delete_lead` / `list_customers` | Leads `LEAD-n` in funnels; a new customer (person or organization) can be created with the lead |
296
+ | **HR** (`hr`) | `list_departments` / `create_department` / `delete_department` / `set_department` | Department tree, team leads, members |
297
+ | | `list_time_off` / `create_time_off` / `delete_time_off` | Vacation, sick days, PTO, overtime, remote days |
298
+ | **Inventory** (`inventory`) | `list_inventory` / `create_inventory_category` / `create_inventory_product` / `update_inventory_item` / `delete_inventory_item` | Categories, products, variants with SKU (Huly beta module) |
299
+ | **Message templates** (`templates`) | `list_message_templates` / `get_message_template` / `create_message_template` / `update_message_template` / `delete_message_template` | Reusable texts with `${field}` placeholders |
300
+ | **Meetings** (`meetings`) | `list_meetings` / `get_meeting` | Rooms, meeting minutes, action items and transcripts (read-only) |
301
+ | **QMS** (`qms`) | `list_controlled_documents` / `get_controlled_document` | Controlled documents: version, state, reviewers/approvers, requests, content (read-only) |
302
+ | | `list_trainings` / `get_training` | Trainings, questions (answers optional) and trainee results (read-only) |
303
+ | **Processes** (`process`) | `list_processes` / `list_executions` / `start_process` / `cancel_execution` | Process states and transitions; running executions; run a process on a card like Huly's "Run process" menu (processes that ask for input in the app are refused); cancel asks first |
304
+ | **Surveys** (`surveys`) | `list_surveys` / `get_survey` | Surveys and aggregated poll answers (read-only) |
93
305
 
94
306
  ---
95
307
 
@@ -129,11 +341,12 @@ npm run build
129
341
 
130
342
  ### Docker (network-reachable server, not local stdio)
131
343
 
132
- For deployments where the MCP server needs to be reachable over the network (behind a reverse proxy, remote MCP clients, etc.) rather than launched locally per-client, a prebuilt image is published to GHCR on every push to `main`:
344
+ For deployments where the MCP server needs to be reachable over the network (behind a reverse proxy, remote MCP clients, etc.) rather than launched locally per-client, a prebuilt image is published to Docker Hub and GHCR for every release, for `linux/amd64` and `linux/arm64`:
133
345
 
134
346
  ```bash
135
- docker pull jokeks2023/huly-mcp:latest
347
+ docker pull jokeks2023/huly-mcp:latest # latest release; also :3, :3.1, :3.1.0
136
348
  # also mirrored at ghcr.io/jokeks2023/huly-mcp:latest
349
+ # :edge = latest build from main
137
350
  ```
138
351
 
139
352
  Or with Compose — copy `.env.example` to `.env`, fill in your credentials (no workspace needed), then:
@@ -142,7 +355,7 @@ Or with Compose — copy `.env.example` to `.env`, fill in your credentials (no
142
355
  docker compose up -d
143
356
  ```
144
357
 
145
- The container wraps the server with [`mcp-proxy`](https://github.com/sparfenyuk/mcp-proxy) to expose it over HTTP/SSE at `:8000/sse`, since standard MCP stdio transport can't be reached over a network directly. See [`Dockerfile`](Dockerfile) / [`docker-compose.yml`](docker-compose.yml).
358
+ The container wraps the server with [`mcp-proxy`](https://github.com/sparfenyuk/mcp-proxy) to expose it over HTTP/SSE at `:8000/sse`, since standard MCP stdio transport can't be reached over a network directly. **Behind a reverse proxy or on a public hostname, set `MCP_ALLOWED_HOSTS`** to the host name(s) clients use, e.g. `MCP_ALLOWED_HOSTS=huly-mcp.example.com`. Otherwise mcp-proxy only accepts `localhost` and answers `421 Invalid Host header`. See [`Dockerfile`](Dockerfile) / [`docker-compose.yml`](docker-compose.yml).
146
359
 
147
360
  ---
148
361
 
@@ -160,7 +373,7 @@ A single Huly account can belong to several workspaces — e.g. a personal one a
160
373
 
161
374
  **Workspace slug:** the part of the Huly URL after the domain: `huly.app/workbench/`**`myteam`** → `myteam`. You don't need to look it up — `list_workspaces` (or `npm run setup`) prints it.
162
375
 
163
- **Legacy `HULY_WORKSPACE`:** still honoured, but only as an optional *restriction*: if set, this server exposes just that one workspace (as before). Leave it unset to use all workspaces.
376
+ **`HULY_WORKSPACE`:** pins the server to that one workspace. Tools then have no `workspace` argument at all, which saves ~20% of the tool-list tokens. Leave it unset to use all workspaces of the account.
164
377
 
165
378
  ---
166
379
 
@@ -172,10 +385,47 @@ A single Huly account can belong to several workspaces — e.g. a personal one a
172
385
  | `HULY_TOKEN` | one auth option | Account token for SSO accounts (Google/GitHub) — get it with `npm run setup` |
173
386
  | `HULY_ACCOUNTS_URL` | self-hosted only | Account service — login and workspace discovery. Default `https://account.huly.app`. Self-hosted: your instance's accounts URL, e.g. `https://huly.example.com/_accounts` |
174
387
  | `HULY_FRONT_URL` | self-hosted (optional on Cloud) | Front service — document/description content and file uploads. Not involved in login or workspace discovery. Self-hosted: e.g. `https://huly.example.com` |
175
- | `HULY_WORKSPACE` | no (legacy) | Restrict the server to a single workspace |
388
+ | `HULY_TRANSACTOR_URL` | no | Self-hosted, server next to Huly: connect to the transactor directly instead of the public address the account service returns, e.g. `ws://huly/_transactor` (via nginx) or `ws://transactor:3333`. Saves the detour through your uplink/tunnel. `HULY_ACCOUNTS_URL` can be internal too (`http://huly/_accounts`); an internal `HULY_FRONT_URL` also works but then invite links show the internal address |
389
+ | `HULY_WORKSPACE` | no | Pin the server to one workspace; tools then take no `workspace` argument (fewer tokens) |
390
+ | `HULY_DYNAMIC_TOOLSETS` | no | `1`: start with `HULY_TOOLSETS` and load more on demand via `enable_toolsets` (see [Toolsets](#toolsets)) |
391
+ | `HULY_TOOLSETS` | no | Comma-separated toolsets to enable, or `all` (see [Toolsets](#toolsets)). Default: `agent,tracker,documents,chat,contacts,inbox,activity,planner,generic` |
392
+ | `HULY_WRITE_PROJECTS` | no | Only allow changes in these projects, e.g. `TSK,WEB` (see [Agent workflow](#agent-workflow)) |
393
+ | `HULY_AUDIT_LOG` | no | Append every change as JSON line to this file |
394
+ | `HULY_AGENT_NAME` | no | Default agent name for `claim_issue` (default `claude`) |
395
+ | `HULY_CONFIRM` | no | `auto` (default), `strict` or `off` — ask before deletes and other risky tools (see [Agent workflow](#agent-workflow)) |
396
+ | `HULY_FILE_ROOT` | no | Directory for local files: `upload_file` (`localPath`) and `download_file` (`savePath`) only work inside it. Off when unset — the server may run remotely |
397
+ | `HULY_SUBSCRIBE_POLL_MS` | no | How often subscribed `huly://` resources are checked for changes (default 30000, minimum 5000) |
176
398
 
177
399
  ---
178
400
 
401
+ ## Claude Code plugin
402
+
403
+ The repo is also a Claude Code plugin marketplace. The plugin bundles the MCP server with a workflow skill, hooks and commands:
404
+
405
+ ```
406
+ /plugin marketplace add JoKeks2023/huly-mcp
407
+ /plugin install huly@huly-mcp
408
+ ```
409
+
410
+ > **Note:** the plugin starts `huly-mcp-selfhost@^3.0.0` from npm. To try a local checkout instead: `npm run build`, then point `plugin/.mcp.json` at `dist/index.js` and start `claude --plugin-dir ./plugin`.
411
+
412
+ Claude Code then asks for your Huly settings (e-mail + password or token, and for self-hosted Huly the accounts and front URL; passwords and tokens go to the OS keychain).
413
+
414
+ | Part | What it does |
415
+ |------|--------------|
416
+ | MCP server | `huly-mcp-selfhost` via `npx`, configured from the plugin settings (toolsets, on-demand loading, pinned workspace and writable projects included) |
417
+ | Skill `huly-workflow` | When and how to use Huly while coding: find the project for the repo, duplicate check before new issues, component + milestone, status flow, PR → issue links, epics for plans |
418
+ | Skill `huly-efficient` | Cheapest call for each question and change, with measured output sizes: one-call overviews, filters instead of full lists, one write instead of create-then-update, no pre-checks the tools already do |
419
+ | Hook on session start | Reports the GitHub repo and branch; a branch like `proj-12-login` points Claude to issue `PROJ-12` (no network, no credentials) |
420
+ | Hook after `gh pr create` / `gh pr merge` | Reminds Claude to link the new PR to its issue (`finish_work`) or to check the status after a merge |
421
+ | `/huly:start [PROJ-12]` | Pick up an issue (from the argument or the branch), load the context, plan |
422
+ | `/huly:finish [PROJ-12] [PR]` | Honest summary, PR link, status to review |
423
+ | `/huly:plan <goal>` | Plan → epic + sub-issues (dry run first) |
424
+ | `/huly:day`, `/huly:standup [since]`, `/huly:triage` | My day, stand-up, inbox triage — one call each (`my_day`, `standup`, `triage_inbox`) |
425
+ | `/huly:report <PROJECT> [7d]` | Project status: progress, milestones, blockers (`project_report`) |
426
+
427
+ Without the plugin, the same server works in Claude Code as a plain MCP server (see below); the MCP prompts `start`, `finish`, `plan`, `triage`, `standup` are available there too.
428
+
179
429
  ## Compatible Clients
180
430
 
181
431
  The same MCP server works across all major AI coding tools. All examples use **email + password** and the npm package via `npx`; for SSO accounts replace the two credentials with `"HULY_TOKEN": "your-token"` (see [Authentication](#authentication)). To run a local build instead, replace `npx` + args with `node` + `["/absolute/path/to/huly-mcp/dist/index.js"]`.
@@ -380,6 +630,20 @@ For network access (HTTP/SSE) use the [Docker image](#docker-network-reachable-s
380
630
  - *"Move the v2.0 Launch milestone to 2026-07-15 and set it to In Progress"*
381
631
  - *"Delete milestone 'Beta' in PROJ and move its issues to 'v2.0 Launch'"*
382
632
 
633
+ **Planning & bulk work:**
634
+ - *"Which issues in milestone v2.0 Launch carry the label 'bug' and are still unassigned?"*
635
+ - *"Set PROJ-12, PROJ-13 and PROJ-20 to In Progress and put them into milestone v2.0 Launch"*
636
+ - *"Show me the sub-issue tree of PROJ-1 and how far along it is"*
637
+ - *"How many hours did we log on PROJ in October, per person?"*
638
+ - *"Move PROJ-42 to the OPS project"*
639
+
640
+ **Inbox, planner, calendar:**
641
+ - *"What's new in my inbox? Mark everything about PROJ-12 as read"*
642
+ - *"Create a to-do 'Review PR' on PROJ-7 due Friday and block 45 minutes tomorrow at 9"*
643
+ - *"What's on my calendar this week?"*
644
+ - *"Show the history of PROJ-12 — who moved it to Done?"*
645
+ - *"Which pull requests are waiting for review in PROJ?"*
646
+
383
647
  **Labels & relations:**
384
648
  - *"Add the label 'bug' to PROJ-42"*
385
649
  - *"Create a label called 'backend' with color #3b82f6"*
@@ -553,8 +817,190 @@ See [`src/connection.ts`](src/connection.ts).
553
817
 
554
818
  ---
555
819
 
820
+ ## Development and CI
821
+
822
+ ```bash
823
+ npm ci && npm run build && npm test
824
+ ```
825
+
826
+ GitHub Actions check every pull request:
827
+
828
+ | Workflow | What it checks |
829
+ |---|---|
830
+ | `ci.yml` | build and tests on Node 20/22/24 (Linux), macOS and Windows; the built server answers `tools/list` over stdio; `npm pack` contents; gitleaks and a personal-data check; the Docker image (build, stdio smoke, Trivy); actionlint; a **token report** comment with the `tools/list` size before and after the PR |
831
+ | `codeql.yml` | CodeQL security analysis (also weekly) |
832
+ | `links.yml` | broken links in Markdown and the site (on PRs that touch them, and weekly → issue) |
833
+ | `dependabot-automerge.yml` | Dependabot patch/minor updates merge by themselves once checks are green; majors and Huly packages wait for review |
834
+ | `scheduled.yml` | nightly live smoke test against a sandbox workspace; weekly: the latest `@hcengineering/*` packages, and Huly modules that have no tools yet (see `.github/huly-modules-ignore.txt`). Failures open or update an issue |
835
+ | `release.yml` | on a `vX.Y.Z` tag: version and changelog check, tests, personal-data check, `npm publish --provenance` (Trusted Publishing), GitHub release from the changelog section, MCP registry entry |
836
+
837
+ Security reports: see [SECURITY.md](SECURITY.md).
838
+
839
+ `test/repo.test.ts` keeps the docs honest: tool counts in this README, the site and `DOCKERHUB.md` must match the registry, the version must match everywhere, and the plugin must be well-formed.
840
+
841
+ **Releasing:**
842
+ 1. Move the `Unreleased` changelog entries under `### X.Y.Z — date`.
843
+ 2. Bump the version in `package.json`, `server.json`, `plugin/.claude-plugin/plugin.json` and `src/server.ts`. The tests check that they agree.
844
+ 3. Merge, then tag `vX.Y.Z` on `main`. The rest runs by itself.
845
+
846
+ **Environments and secrets:**
847
+ - Environment `release` (tags `v*` only): used by `release.yml`. npm Trusted Publishing names this environment.
848
+ - Environment `sandbox`: used by the nightly live jobs.
849
+
850
+ Secrets:
851
+ - `PERSONAL_DATA_PATTERNS`: private terms that must never appear in the repo, one regex per line.
852
+ - `NPM_TOKEN`: fallback only, until Trusted Publishing is set up on npmjs.com.
853
+ - In the environment `sandbox`: `HULY_SMOKE_WORKSPACE`, `HULY_SMOKE_PROJECT`, `HULY_SMOKE_EMAIL` + `HULY_SMOKE_PASSWORD` (or `HULY_SMOKE_TOKEN`), `HULY_SMOKE_ACCOUNTS_URL`, `HULY_SMOKE_FRONT_URL`: a **throwaway** workspace for the nightly live test. Without them the live jobs skip.
854
+
855
+ ---
856
+
556
857
  ## Changelog
557
858
 
859
+ ### 3.2.0 — 2026-11-11
860
+
861
+ - **New: `issues_from_document`** — spec → issues in one call: open checklist items of a Huly document (or, without a checklist, its sections) become sub-issues of an epic; checked items are skipped; the document is linked to the epic. Dry run by default.
862
+ - **New: `issues_from_meeting`** — meeting notes → issues in one call: action items (open checkboxes, `TODO:`/`Action:` lines, lists under "Action items"/"Next steps") with `@assignee` and due date taken from the line; dry run first, each new issue linked to the document.
863
+ - **`create_issue` takes `assignee`, `componentLabel` and `milestoneLabel`**, so a new issue no longer needs a second `update_issue` call. An unknown `statusName` is now an error (it used to fall back to the first status). Everything is checked before anything is written.
864
+ - **Unknown tool parameters are rejected instead of silently dropped.** Before, `update_issue {status: "Done"}` answered "No changes made". Now the call fails with the list of valid parameters and nothing is done. Common mix-ups are mapped automatically: `status`→`statusName`, `project`/`projectId`→`projectIdentifier`, `issue`/`issueId`/`id`→`identifier`, `component`→`componentLabel`, `milestone`→`milestoneLabel`.
865
+ - **`get_issue` is shorter:** empty fields (no milestone, 0 comments, …) are left out and the fields share one line.
866
+ - **Smaller tool list:** the `workspace` parameter no longer repeats its description in every tool (the server instructions explain it once). Default set 38.7k → 35.2k characters, all toolsets 88.8k → 80.3k.
867
+ - **New `HULY_TRANSACTOR_URL`:** a server running next to Huly (same Docker network) can reach the transactor internally, e.g. `ws://huly/_transactor`, instead of the public address — no detour through the uplink or a tunnel.
868
+ - **Claude Code plugin: new skill `huly-efficient`** — which Huly call answers which question with the least output (sizes measured on a real project), which writes need only one call, and which checks the tools already do. The `huly-workflow` skill points to it.
869
+ - **Claude Code plugin:** `/huly:standup` and `/huly:triage` (and the MCP prompts) now use the one-call tools `standup` and `triage_inbox`; new commands `/huly:day` (`my_day`) and `/huly:report` (`project_report`); new settings for a pinned workspace (`HULY_WORKSPACE`) and on-demand toolsets (`HULY_DYNAMIC_TOOLSETS`). The skill points to the overview tools and to `create_issue` with component/milestone.
870
+ - **Fixed: Huly client log lines on stdout.** `Client: onConnect 1` landed in the JSON-RPC stream; mcp-proxy logged "Failed to parse JSONRPC message". Such logs now go to stderr.
871
+ - **Fixed: session tokens in logs.** Huly's client logs its websocket URL including the workspace token (`client websocket error: … /_transactor/<token>`), which ended up in `docker compose logs`. Tokens in log output are now masked as `***`.
872
+ - **Fixed: `create_issue_tree` (and `issues_from_document`) left reused issues outside the epic.** A same-title issue that is reused now moves under the epic when it has no parent; one under another parent stays there, and the plan and result say so.
873
+ - **Fixed: blob requests without a timeout.** Reading document/description content and uploads could hang a tool call when the front service stalled. Reads now stop after 30 s, uploads after 2 min, with a clear error naming `HULY_FRONT_URL`.
874
+ - `create_issue_tree` passes component, milestone and assignee straight to `create_issue`, so a wrong name fails before the issue exists (before: the issue was created, then the update failed).
875
+ - Unknown-parameter error of tools without own parameters (e.g. `list_issue_statuses`) said "Valid: ."; it now says the tool takes no parameters besides `workspace`.
876
+ - README: context-cost table re-measured (the pinned saving is now ~10%, not 20%, since the `workspace` description was already shortened).
877
+ - CI: CodeQL Action v4; runs on `main` are no longer cancelled by the next push.
878
+
879
+ ### 3.1.1 — 2026-11-04
880
+
881
+ - **Fixed: Docker image behind a reverse proxy.** The `mcp-proxy` update in 3.1.0 made the server reject every Host name except `localhost` (`421 Invalid Host header`). New variable `MCP_ALLOWED_HOSTS` (comma-separated) lists the host names clients use, e.g. `MCP_ALLOWED_HOSTS=huly-mcp.example.com`. Without it the container logs a warning. CI now tests allowed and rejected Host headers.
882
+ - Release workflow: when `npm publish` fails, the OIDC/auth lines of npm's debug log are shown (3.1.0 had to be published to npm by hand).
883
+
884
+ ### 3.1.0 — 2026-11-04
885
+
886
+ First 3.x release on npm. 3.0.0 was only released on GitHub; everything from it is included here.
887
+
888
+ **One call instead of several**
889
+ - **New: `my_day`** (toolset `agent`, on by default) — "what's on today?" in one call: calendar, to-dos, my issues, reviews, unread inbox.
890
+ - **New: `standup`, `triage_inbox`, `release_notes`** — one call each instead of several: yesterday/today/blockers, the inbox with what changed since last read, and release notes from a milestone.
891
+ - **New: `project_report`** (toolset `agent`) — weekly report of a project: done, new, in progress, blocked, overdue, PRs, milestones, time logged.
892
+
893
+ **More of Huly**
894
+ - **New: test management, much more of it** — `import_test_results` and the CLI `huly-mcp junit` bring CI results (JUnit XML) into Huly as test runs; `get_test_report` shows failing, flaky, blocked and never-run cases over the latest runs; `create_issue_from_test_result` turns a failed test into a bug (steps and failure included, related to the test case); `create_test_cases` creates many cases at once; suites can be renamed, moved and deleted, runs renamed, dated and deleted, plans deleted, results assigned.
895
+ - **New: `start_process` / `cancel_execution`** — run a process on a card and cancel a running one. Starting works like Huly's "Run process" menu; Huly's process service then moves the execution on. Processes whose start asks for input in the app are refused, and so is a second run where the process forbids parallel runs. Cancelling asks first.
896
+ - `get_issue` names related non-issue documents (e.g. a test case) instead of showing a bare id.
897
+
898
+ **Changed behaviour**
899
+ - **Changed: `list_issues` lists open issues by default.** Pass `status: "all"` for every issue, or a status name. Long lists show `51–100 of 118` and page with `offset`. In a mature project this cuts the answer by ~80%.
900
+ - **Changed: `list_comments` returns the newest comments** (before: the oldest), still in chronological order. Comments over 1,500 characters are shortened with a visible marker; `full: true` shows them whole. Issue descriptions are never shortened, because `update_issue` replaces them.
901
+ - **Changed: Docker tags.** `latest` now means the latest *release* (before: the latest commit on `main`), and `main` builds are tagged `edge`. There are new tags `3` and `3.1` for release lines, and images are built for `linux/arm64` as well, with an SBOM and provenance.
902
+ - `list_labels`: dead code for the ignored `projectIdentifier` removed. No behaviour change.
903
+
904
+ **Fewer tokens**
905
+ - **Fewer tokens:**
906
+ - With `HULY_WORKSPACE` set, tools take no `workspace` argument (−20% tool-list size). Changes still go to exactly that workspace.
907
+ - Validation limits (`minLength`, `maximum` …) are no longer sent in tool schemas. They are still enforced, with a clear error.
908
+ - `list_issues` uses one line per issue and leaves out "No priority".
909
+ - `list_notifications` shows notification ids only with `ids: true`. Marking read by object (`PROJ-12`) does not need them.
910
+ - **New: load toolsets on demand** (`HULY_DYNAMIC_TOOLSETS=1`, opt-in): start small and let Claude load toolsets with `enable_toolsets`. With `agent,inbox` a session starts at ≈1.8k tokens. Not yet verified in Claude Desktop.
911
+ - Server instructions are 41 % shorter (1,463 → 858 chars). They now point to the one-call overviews (`my_day`, `standup`, `triage_inbox` …); hints that the tool descriptions already carry were dropped.
912
+ - Read tools describe `workspace` more briefly (the rule for omitting it is in the server instructions), which keeps the default set within its context budget.
913
+
914
+ **Security**
915
+ - **Security fixes from code scanning:**
916
+ - Docker image: `mcp-proxy` 0.14.0 with `mcp` 1.30.0 (fixes 5 CVEs); npm is removed from the runtime image (23 alerts in npm's bundled packages); Debian security updates are applied at build time.
917
+ - `uuid` is pinned to 11.1.1 via an npm override (a CVE in 8.3.2, pulled in by Huly's server client).
918
+ - Code: entity decoding in `triage_inbox` no longer double-unescapes (`&amp;lt;` stays `&lt;`); JUnit comment removal is repeated until nothing is left; a check-then-read race in `huly-mcp-setup` is gone.
919
+
920
+ **CI and releases**
921
+ - **CI and automation:**
922
+ - every PR is checked on three platforms, with a token report, a personal-data check, a Docker scan and CodeQL
923
+ - releases publish themselves from a tag
924
+ - a nightly live test runs against a sandbox workspace
925
+ - weekly checks cover new Huly packages and Huly modules without tools
926
+ - see [Development and CI](#development-and-ci)
927
+
928
+ ### 3.0.0 — 2026-11-04
929
+
930
+ One large release instead of several small ones, built in stages (see [#11](https://github.com/JoKeks2023/huly-mcp/issues/11)).
931
+
932
+ Breaking:
933
+ - Tools are grouped into toolsets.
934
+ - `calendar`, `github`, `generic-write` and `tracker-admin` are not enabled by default.
935
+ - `HULY_TOOLSETS=all` enables everything.
936
+
937
+ **Toolsets and the core modules**
938
+ - **New: toolsets** (`HULY_TOOLSETS`) and slimmer tool schemas. The 64 tools of 2.2.0 now cost about 36 % fewer tokens.
939
+ - **New: inbox** — `list_notifications`, `mark_notifications_read`
940
+ - **New: activity** — `get_activity`
941
+ - **New: planner** — `list_todos`, `create_todo`, `update_todo`, `delete_todo`, `schedule_todo`
942
+ - **New: calendar** — `list_events`, `create_event`, `update_event`, `delete_event`
943
+ - **New: chat** — `list_thread`, `reply_to_message`, `update_message`, `delete_message`, `add_reaction`, `remove_reaction`, `pin_message`. `list_messages` now shows authors and message ids.
944
+ - **New: GitHub** — `list_pull_requests`, `get_pull_request`
945
+ - **New: persons** — `list_persons`, `get_person`, `create_person`, `update_person`, `add_contact_channel`, `remove_contact_channel`
946
+ - **New: generic access** — `list_classes`, `describe_class` and `query_documents` (secrets redacted). `generic_create`, `generic_update` and `generic_delete` are opt-in and run as a dry run by default.
947
+
948
+ **Agent workflow**
949
+ - **New: agent workflow** (toolset `agent`, on by default) — `get_issue_context`, `start_work`, `finish_work`, `create_issue_tree`, `changes_since`, `claim_issue`, `release_issue`, `find_project_for_repo`
950
+ - **New: MCP resources** (`huly://…/issue/…`, `huly://…/document/…`)
951
+ - **New: MCP prompts** (`start`, `finish`, `plan`, `triage`, `standup`)
952
+ - **New: guard rails** — `HULY_WRITE_PROJECTS` limits changes to the listed projects, and `HULY_AUDIT_LOG` records every change.
953
+ - **Changed: toolset `tracker-admin`.** These tools are no longer in the default set: `create_project`, `update_project`, `create_issue_status`, `update_label`, `delete_label`, `delete_milestone`, `delete_component`, `repair_parent_links`. Enable them with `HULY_TOOLSETS=…,tracker-admin` or `all`.
954
+
955
+ **Claude Code plugin**
956
+ - **New: Claude Code plugin** (`/plugin marketplace add JoKeks2023/huly-mcp`, `/plugin install huly@huly-mcp`). It bundles:
957
+ - the MCP server with its settings
958
+ - the `huly-workflow` skill
959
+ - session-start and PR hooks
960
+ - the commands `/huly:start`, `/huly:finish`, `/huly:plan`, `/huly:triage`, `/huly:standup`
961
+
962
+ **More of Huly**
963
+ - **New: fulltext search across everything** — `search` (issues, documents, messages, cards, files, persons …)
964
+ - **New: toolset `collaboration`** — followers of issues/documents, public guest links, document comments
965
+ - **New: toolset `cards`** — card types and tags, cards with content, nesting and field values
966
+ - **New: toolset `fields`** — custom fields on issues, project types, card types or any class, and their values
967
+ - **New: toolset `drive`** — drives, folders, versioned files (upload, download, move, restore)
968
+ - **New: toolset `templates`** — issue templates; new issue with sub-issues from a template
969
+ - **New: toolset `testing`** — test projects, suites, cases, plans, runs and results
970
+ - **New: toolset `products`** — products and versions (read-only)
971
+ - **New: label categories** (`tracker-admin`)
972
+ - **New: documents** — `list_documents` shows the whole tree; `update_document` renames and moves (also to another teamspace); new documents are placed after their siblings
973
+ - **New: MCP argument completions** for prompts and `huly://` resources (workspaces, projects, issue ids) and **resource subscriptions** (`notifications/resources/updated` when a subscribed issue or document changes)
974
+
975
+ **Business modules**
976
+ - **New: toolsets `members`, `recruiting`, `crm`, `hr`, `inventory`** — invitations and roles, vacancies/candidates/applications, leads/customers, departments and time off, inventory
977
+ - **New: message templates** (`templates`) and **project types with workflows** (`tracker-admin`)
978
+ - **New, read-only: `meetings`** (minutes, transcripts), **`qms`** (controlled documents, trainings), **`process`**, **`surveys`**
979
+ - Not included: Huly's Board module (hidden and off by default in Huly itself).
980
+
981
+ **Agents**
982
+ - **New: confirmation for risky tools** — deletes, bulk updates, moves, generic writes, revoking links and restoring file versions ask the user via MCP elicitation when the client supports it (`HULY_CONFIRM`). Declining changes nothing.
983
+ - **New: `huly-mcp watch`** — Huly hands work to an agent: issues with a label or assigned to the agent's own account are claimed, passed to `claude -p` (or any command) and released afterwards. Runs are unattended, so they default to `HULY_CONFIRM=strict`.
984
+
985
+ **Fixes**
986
+ - `create_teamspace`, `create_channel`, `start_direct_message` and `create_project` stored the user's social id as member/owner; Huly 0.7 expects the account id. Spaces created with earlier versions may list you twice as member and have no proper owner.
987
+ - Public links created on servers whose `FRONT_URL` is `localhost` are shown with `HULY_FRONT_URL` instead.
988
+ - Empty or unresolved `HULY_*` variables (for example plugin settings left blank) now count as not set.
989
+ - Nested tool errors no longer repeat the "Huly MCP:" prefix.
990
+
991
+ ### 2.2.0 — planning, bulk edits, fixes for Huly 0.7
992
+
993
+ - **New: filters in `list_issues`** — milestone, component, label, assignee, parent (null = without / top-level)
994
+ - **New: `bulk_update_issues`, `move_issue`, `list_sub_issues`, `list_time_reports`**
995
+ - **New: `update_project`, `update_comment`, `update_label`, `delete_label`, `remove_relation`, `remove_blocked_by`**
996
+ - **New: `repair_parent_links`** — re-links sub-issues created by earlier versions (dry run by default)
997
+ - **More detail in `get_issue`** — assignee, milestone, component, labels, parent, blocked by, related
998
+ - **`list_members`** shows names
999
+ - **Fix: `set_parent`** now links like Huly itself (`attachedTo`). Before, sub-issues did not appear under their parent in Huly. Existing links: `repair_parent_links` or `set_parent` again
1000
+ - **Fix: people lookup on Huly 0.7** — `log_time` failed ("Could not identify current user"), assigning by name (`assignee`, `lead`) never matched and comment authors showed as "Unknown". People are now resolved via the Employee mixin; names are shown as "First Last" and ambiguous names are rejected
1001
+ - **Fix: bold/italic text** in issue, document and organization descriptions no longer breaks into separate lines
1002
+ - **Fix: `update_issue`** accepts `componentLabel: null` (as documented) and rejects invalid due dates
1003
+
558
1004
  ### 2.1.0 — milestones & components, security updates
559
1005
 
560
1006
  - **New: `get_milestone`, `update_milestone`, `delete_milestone`** — progress overview, edit name/date/status/description, delete with issues unassigned or moved via `moveIssuesTo`