huly-mcp-selfhost 1.0.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 (77) hide show
  1. package/.env.example +16 -0
  2. package/README.md +522 -0
  3. package/dist/connection.d.ts +9 -0
  4. package/dist/connection.js +122 -0
  5. package/dist/connection.js.map +1 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +25 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/schemas.d.ts +459 -0
  10. package/dist/schemas.js +196 -0
  11. package/dist/schemas.js.map +1 -0
  12. package/dist/server.d.ts +2 -0
  13. package/dist/server.js +87 -0
  14. package/dist/server.js.map +1 -0
  15. package/dist/tools/attachments.d.ts +28 -0
  16. package/dist/tools/attachments.js +61 -0
  17. package/dist/tools/attachments.js.map +1 -0
  18. package/dist/tools/channels.d.ts +44 -0
  19. package/dist/tools/channels.js +130 -0
  20. package/dist/tools/channels.js.map +1 -0
  21. package/dist/tools/comments.d.ts +27 -0
  22. package/dist/tools/comments.js +60 -0
  23. package/dist/tools/comments.js.map +1 -0
  24. package/dist/tools/components.d.ts +19 -0
  25. package/dist/tools/components.js +57 -0
  26. package/dist/tools/components.js.map +1 -0
  27. package/dist/tools/documents.d.ts +68 -0
  28. package/dist/tools/documents.js +207 -0
  29. package/dist/tools/documents.js.map +1 -0
  30. package/dist/tools/issues.d.ts +56 -0
  31. package/dist/tools/issues.js +262 -0
  32. package/dist/tools/issues.js.map +1 -0
  33. package/dist/tools/labels.d.ts +35 -0
  34. package/dist/tools/labels.js +150 -0
  35. package/dist/tools/labels.js.map +1 -0
  36. package/dist/tools/log-time.d.ts +10 -0
  37. package/dist/tools/log-time.js +31 -0
  38. package/dist/tools/log-time.js.map +1 -0
  39. package/dist/tools/members.d.ts +6 -0
  40. package/dist/tools/members.js +17 -0
  41. package/dist/tools/members.js.map +1 -0
  42. package/dist/tools/milestones.d.ts +19 -0
  43. package/dist/tools/milestones.js +80 -0
  44. package/dist/tools/milestones.js.map +1 -0
  45. package/dist/tools/organizations.d.ts +32 -0
  46. package/dist/tools/organizations.js +86 -0
  47. package/dist/tools/organizations.js.map +1 -0
  48. package/dist/tools/projects.d.ts +24 -0
  49. package/dist/tools/projects.js +64 -0
  50. package/dist/tools/projects.js.map +1 -0
  51. package/dist/tools/relations.d.ts +27 -0
  52. package/dist/tools/relations.js +103 -0
  53. package/dist/tools/relations.js.map +1 -0
  54. package/dist/tools/search.d.ts +9 -0
  55. package/dist/tools/search.js +32 -0
  56. package/dist/tools/search.js.map +1 -0
  57. package/dist/tools/statuses.d.ts +16 -0
  58. package/dist/tools/statuses.js +93 -0
  59. package/dist/tools/statuses.js.map +1 -0
  60. package/dist/utils/errors.d.ts +11 -0
  61. package/dist/utils/errors.js +24 -0
  62. package/dist/utils/errors.js.map +1 -0
  63. package/dist/utils/format.d.ts +4 -0
  64. package/dist/utils/format.js +28 -0
  65. package/dist/utils/format.js.map +1 -0
  66. package/dist/utils/markdown.d.ts +14 -0
  67. package/dist/utils/markdown.js +144 -0
  68. package/dist/utils/markdown.js.map +1 -0
  69. package/dist/utils/storage.d.ts +7 -0
  70. package/dist/utils/storage.js +82 -0
  71. package/dist/utils/storage.js.map +1 -0
  72. package/package.json +68 -0
  73. package/scripts/cleanup-issues.js +132 -0
  74. package/scripts/demo.js +193 -0
  75. package/scripts/import-csv.js +242 -0
  76. package/scripts/sample-tasks.csv +11 -0
  77. package/scripts/setup.js +103 -0
package/.env.example ADDED
@@ -0,0 +1,16 @@
1
+ # ─── Required ────────────────────────────────────────────────────────────────
2
+ HULY_WORKSPACE=your-workspace-slug # e.g. "myteam" from huly.app/myteam
3
+
4
+ # ─── Authentication (choose ONE option) ──────────────────────────────────────
5
+
6
+ # Option A — Token auth (recommended for SSO / Google / GitHub accounts)
7
+ # Run the interactive setup wizard to get a token via email OTP:
8
+ # npm run setup
9
+ # HULY_TOKEN=your-token-here
10
+
11
+ # Option B — Email + password auth (only works if you set a password on huly.app)
12
+ # HULY_EMAIL=your-email@example.com
13
+ # HULY_PASSWORD=your-password
14
+
15
+ # ─── Optional ────────────────────────────────────────────────────────────────
16
+ # HULY_ACCOUNTS_URL=https://account.huly.app # default shown; change for self-hosted
package/README.md ADDED
@@ -0,0 +1,522 @@
1
+ # huly-mcp-sdk (self-hosted fork)
2
+
3
+ > The most complete MCP server for [Huly](https://huly.app) — the open-source project management platform.
4
+
5
+ Connects **Claude Desktop** (and any [MCP](https://modelcontextprotocol.io)-compatible client) directly to your Huly workspace. Manage projects, issues, milestones, components, documents, labels, chat, attachments, organizations, and more — all via natural language.
6
+
7
+ ## About this fork
8
+
9
+ This is a fork of [varaprasadreddy9676/huly-mcp](https://github.com/varaprasadreddy9676/huly-mcp), built out for a **self-hosted** (`huly-selfhost`) deployment and extended well past the upstream tool set. **Not published to npm** — see [Installing this fork](#installing-this-fork) below.
10
+
11
+ **Fixed vs. upstream:**
12
+ - **Self-hosted document/description writes.** Upstream's `update_document` (and, by extension, any issue description) is hardcoded against Huly Cloud's "datalake" microservice at `dl-eu.huly.app`, which `huly-selfhost` doesn't run. This fork auto-detects self-hosted deployments via `HULY_FRONT_URL` and uploads through `front`'s own `/files` contract instead — falls back to the original Cloud behavior when `HULY_FRONT_URL` is unset. See [`src/utils/storage.ts`](src/utils/storage.ts).
13
+ - **`description` on `create_issue`/`update_issue`.** Missing entirely upstream — issue descriptions are `MarkupBlobRef`s, same storage mechanism as document content, so this needed the same fix.
14
+
15
+ **New tool categories** (upstream had 36 tools across Projects/Issues/Comments/Time/Labels/Relations/Members/Milestones/Components/Documents/Search; this fork adds 14 more):
16
+ - **Chat** — `list_channels`, `create_channel`, `start_direct_message`, `send_message`, `list_messages`
17
+ - **Attachments** — `attach_file`, `list_attachments`, `delete_attachment` (generic files on issues, any content type)
18
+ - **Issue Statuses** — `list_issue_statuses`, `create_issue_status` (custom workflow states)
19
+ - **Organizations** — `list_organizations`, `get_organization`, `create_organization`, `update_organization`
20
+
21
+ **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).
22
+
23
+ ---
24
+
25
+ ## Tools (50 total)
26
+
27
+ | Category | Tool | Description |
28
+ |----------|------|-------------|
29
+ | **Projects** | `list_projects` | List all projects in the workspace |
30
+ | | `get_project` | Get project details + available statuses |
31
+ | | `create_project` | Create a new tracker project with a unique identifier |
32
+ | **Issues** | `list_issues` | List issues with optional status / priority filters |
33
+ | | `get_issue` | Get full details of an issue (e.g. `PROJ-42`) |
34
+ | | `create_issue` | Create a new issue (with optional Markdown description) |
35
+ | | `update_issue` | Update title, description, status, priority, assignee, due date, component, milestone |
36
+ | | `delete_issue` | Permanently delete an issue by identifier |
37
+ | **Comments** | `add_comment` | Add a comment to an issue |
38
+ | | `list_comments` | List all comments on an issue (includes IDs for `delete_comment`) |
39
+ | | `delete_comment` | Delete a specific comment by ID |
40
+ | **Time Tracking** | `log_time` | Log hours spent on an issue |
41
+ | **Labels** | `list_labels` | List all labels with color + usage count |
42
+ | | `create_label` | Create a new label with an optional hex color |
43
+ | | `add_label` | Add a label to an issue (auto-creates if it doesn't exist) |
44
+ | | `remove_label` | Remove a label from an issue |
45
+ | **Relations** | `add_relation` | Mark two issues as related (bidirectional) |
46
+ | | `add_blocked_by` | Mark an issue as blocked by another issue |
47
+ | | `set_parent` | Set or clear the parent epic of an issue |
48
+ | **Members** | `list_members` | List workspace members |
49
+ | **Milestones** | `list_milestones` | List milestones for a project |
50
+ | | `create_milestone` | Create a milestone with a target date and status |
51
+ | **Components** | `list_components` | List components (sub-areas) in a project |
52
+ | | `create_component` | Create a new component with optional lead |
53
+ | **Documents** | `list_teamspaces` | List document teamspaces |
54
+ | | `create_teamspace` | Create a new teamspace (top-level document folder) |
55
+ | | `list_documents` | List documents in a teamspace |
56
+ | | `delete_document` | Permanently delete a document by ID |
57
+ | | `get_document` | Get document metadata + content |
58
+ | | `create_document` | Create a new document in a teamspace |
59
+ | | `update_document` | Write Markdown content to a document — Mermaid diagrams render natively |
60
+ | | `link_document` | Link a document to an issue — appears in the Relations panel |
61
+ | **Search** | `search_issues` | Full-text search across all issues |
62
+ | **Chat** | `list_channels` | List all channels in the workspace |
63
+ | | `create_channel` | Create a new channel |
64
+ | | `start_direct_message` | Start (or find) a 1:1 direct message with a workspace member |
65
+ | | `send_message` | Send a message to a channel or direct message |
66
+ | | `list_messages` | List messages in a channel or direct message |
67
+ | **Attachments** | `attach_file` | Attach a file to an issue (base64-encoded content) |
68
+ | | `list_attachments` | List files attached to an issue |
69
+ | | `delete_attachment` | Delete a file attachment from an issue |
70
+ | **Issue Statuses** | `list_issue_statuses` | List all issue statuses (workflow states), grouped by phase |
71
+ | | `create_issue_status` | Create a new issue status — available in every project immediately |
72
+ | **Organizations** | `list_organizations` | List all organizations (companies) in the workspace |
73
+ | | `get_organization` | Get details of an organization, including description |
74
+ | | `create_organization` | Create a new organization (company contact) |
75
+ | | `update_organization` | Set the description of an organization from Markdown |
76
+
77
+ ---
78
+
79
+ ## Requirements
80
+
81
+ - Node.js >= 20
82
+ - A Huly account — [huly.app](https://huly.app) (cloud) or self-hosted
83
+
84
+ ---
85
+
86
+ ## Installing this fork
87
+
88
+ This fork isn't published to npm — `npx huly-mcp-sdk` (the upstream package) will **not** include anything in this README past "About this fork". Clone and build instead:
89
+
90
+ ```bash
91
+ git clone https://github.com/JoKeks2023/huly-mcp.git
92
+ cd huly-mcp
93
+ npm install
94
+ npm run build
95
+ ```
96
+
97
+ Then in any client config below, replace `"command": "npx", "args": ["huly-mcp-sdk"]` with:
98
+
99
+ ```json
100
+ "command": "node",
101
+ "args": ["/absolute/path/to/huly-mcp/dist/index.js"]
102
+ ```
103
+
104
+ **Your workspace slug** is the part of your Huly URL after the domain: `huly.app/`**`myteam`** → slug is `myteam` (self-hosted: the `url` field of your workspace, e.g. `https://your-instance.com/workbench/`**`myteam`**).
105
+
106
+ ---
107
+
108
+ ## Compatible Clients
109
+
110
+ The same MCP server works across all major AI coding tools. Pick your client, then swap the `npx`/`args` for the local build per [Installing this fork](#installing-this-fork) above.
111
+
112
+ > **Auth note:** All config examples below use `HULY_TOKEN`. If you have issues with token expiry, use email + password instead — just replace the `env` block with:
113
+ > ```json
114
+ > "HULY_EMAIL": "your@email.com",
115
+ > "HULY_PASSWORD": "yourpassword",
116
+ > "HULY_WORKSPACE": "your-workspace-slug"
117
+ > ```
118
+ > See [Manual Auth](#manual-auth) for details on both options.
119
+
120
+ ---
121
+
122
+ ### Claude Desktop
123
+
124
+ - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
125
+ - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
126
+
127
+ ```json
128
+ {
129
+ "mcpServers": {
130
+ "huly": {
131
+ "command": "npx",
132
+ "args": ["huly-mcp-sdk"],
133
+ "env": {
134
+ "HULY_TOKEN": "your-token",
135
+ "HULY_WORKSPACE": "your-workspace-slug"
136
+ }
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ Restart Claude Desktop after saving.
143
+
144
+ ---
145
+
146
+ ### Claude Code (CLI)
147
+
148
+ ```bash
149
+ claude mcp add huly -e HULY_TOKEN=your-token -e HULY_WORKSPACE=your-slug -- npx huly-mcp-sdk
150
+ ```
151
+
152
+ Or scope it to a single project only:
153
+
154
+ ```bash
155
+ claude mcp add huly --scope project -e HULY_TOKEN=your-token -e HULY_WORKSPACE=your-slug -- npx huly-mcp-sdk
156
+ ```
157
+
158
+ Verify it's connected: `claude mcp list`
159
+
160
+ ---
161
+
162
+ ### Cursor
163
+
164
+ Create or edit `~/.cursor/mcp.json`:
165
+
166
+ ```json
167
+ {
168
+ "mcpServers": {
169
+ "huly": {
170
+ "command": "npx",
171
+ "args": ["huly-mcp-sdk"],
172
+ "env": {
173
+ "HULY_TOKEN": "your-token",
174
+ "HULY_WORKSPACE": "your-workspace-slug"
175
+ }
176
+ }
177
+ }
178
+ }
179
+ ```
180
+
181
+ Restart Cursor. The tools appear in the Agent panel under MCP.
182
+
183
+ ---
184
+
185
+ ### Windsurf (Codeium)
186
+
187
+ Create or edit `~/.codeium/windsurf/mcp_config.json`:
188
+
189
+ ```json
190
+ {
191
+ "mcpServers": {
192
+ "huly": {
193
+ "command": "npx",
194
+ "args": ["huly-mcp-sdk"],
195
+ "env": {
196
+ "HULY_TOKEN": "your-token",
197
+ "HULY_WORKSPACE": "your-workspace-slug"
198
+ }
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ Restart Windsurf. MCP tools are available to the Cascade AI panel.
205
+
206
+ ---
207
+
208
+ ### VS Code — Cline extension
209
+
210
+ 1. Install the [Cline extension](https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev)
211
+ 2. Open Cline settings → **MCP Servers** → **Edit MCP Settings**
212
+ 3. Add:
213
+
214
+ ```json
215
+ {
216
+ "huly": {
217
+ "command": "npx",
218
+ "args": ["huly-mcp-sdk"],
219
+ "env": {
220
+ "HULY_TOKEN": "your-token",
221
+ "HULY_WORKSPACE": "your-workspace-slug"
222
+ }
223
+ }
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ### VS Code — Continue extension
230
+
231
+ 1. Install the [Continue extension](https://marketplace.visualstudio.com/items?itemName=Continue.continue)
232
+ 2. Edit `~/.continue/config.json` and add to the `mcpServers` array:
233
+
234
+ ```json
235
+ {
236
+ "mcpServers": [
237
+ {
238
+ "name": "huly",
239
+ "command": "npx",
240
+ "args": ["huly-mcp-sdk"],
241
+ "env": {
242
+ "HULY_TOKEN": "your-token",
243
+ "HULY_WORKSPACE": "your-workspace-slug"
244
+ }
245
+ }
246
+ ]
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ### Zed
253
+
254
+ Edit `~/.config/zed/settings.json` and add a `context_servers` entry:
255
+
256
+ ```json
257
+ {
258
+ "context_servers": {
259
+ "huly": {
260
+ "command": {
261
+ "path": "npx",
262
+ "args": ["huly-mcp-sdk"],
263
+ "env": {
264
+ "HULY_TOKEN": "your-token",
265
+ "HULY_WORKSPACE": "your-workspace-slug"
266
+ }
267
+ }
268
+ }
269
+ }
270
+ }
271
+ ```
272
+
273
+ ---
274
+
275
+ ### OpenAI Codex CLI
276
+
277
+ Edit `~/.codex/config.json` and add to `mcpServers`:
278
+
279
+ ```json
280
+ {
281
+ "mcpServers": {
282
+ "huly": {
283
+ "type": "stdio",
284
+ "command": "npx",
285
+ "args": ["huly-mcp-sdk"],
286
+ "env": {
287
+ "HULY_TOKEN": "your-token",
288
+ "HULY_WORKSPACE": "your-workspace-slug"
289
+ }
290
+ }
291
+ }
292
+ }
293
+ ```
294
+
295
+ ---
296
+
297
+ ### Any other MCP-compatible client
298
+
299
+ The server uses standard **stdio transport**. If your tool supports MCP, the config pattern is always the same:
300
+
301
+ - **command:** `node`
302
+ - **args:** `["/absolute/path/to/huly-mcp/dist/index.js"]` (see [Installing this fork](#installing-this-fork))
303
+ - **env:** `HULY_TOKEN` + `HULY_WORKSPACE` (or `HULY_EMAIL`/`HULY_PASSWORD`; self-hosted also needs `HULY_ACCOUNTS_URL` + `HULY_FRONT_URL`, see [Manual Auth](#manual-auth))
304
+
305
+ Consult your tool's MCP documentation for the exact config file location.
306
+
307
+ ---
308
+
309
+ <img width="932" height="401" alt="image" src="https://github.com/user-attachments/assets/0f9d9a74-ca1e-4884-bd6a-918c0fb8ddbd" />
310
+
311
+ ## Example Prompts
312
+
313
+ **Projects & issues:**
314
+ - *"Create a new project called 'Mobile App' with identifier MOBILE"*
315
+ - *"List all in-progress issues in the PROJ project"*
316
+ - *"Create a high-priority issue in PROJ titled 'Fix login timeout'"*
317
+ - *"Update PROJ-42 status to Done, assign it to Sarah, and move it to the Auth component"*
318
+ - *"Search for issues related to authentication"*
319
+ - *"Add a comment to PROJ-15 saying the fix is deployed"*
320
+ - *"List all comments on PROJ-42 to see the discussion"*
321
+
322
+ **Milestones & components:**
323
+ - *"Create a milestone 'v2.0 Launch' in PROJ with target date 2026-06-01"*
324
+ - *"List milestones for the PROJ project"*
325
+ - *"Create a component called 'Auth' in PROJ"*
326
+ - *"List all components in PROJ"*
327
+
328
+ **Labels & relations:**
329
+ - *"Add the label 'bug' to PROJ-42"*
330
+ - *"Create a label called 'backend' with color #3b82f6"*
331
+ - *"Mark PROJ-55 as blocked by PROJ-12"*
332
+ - *"Set PROJ-42 as a subtask of PROJ-5"*
333
+
334
+ **Time tracking:**
335
+ - *"Log 2.5 hours on PROJ-42 for the database refactor"*
336
+
337
+ **Documents:**
338
+ - *"List all documents in the Engineering teamspace"*
339
+ - *"Create a document called 'API Design' in the Engineering teamspace"*
340
+ - *"Update the API Design document with this Markdown: ..."*
341
+ - *"Add a Mermaid architecture diagram to the EP1 document"*
342
+ - *"Link document abc123 to issue PROJ-42"*
343
+ - *"Delete the second comment on PROJ-15"*
344
+
345
+ ---
346
+
347
+ ## Document Content
348
+
349
+ ### Reading: `get_document`
350
+
351
+ `get_document` always returns full metadata (title, teamspace, comments, snapshots). To also fetch and display the **text content**, set the optional `HULY_FRONT_URL` env var:
352
+
353
+ ```json
354
+ "env": {
355
+ "HULY_TOKEN": "...",
356
+ "HULY_WORKSPACE": "myteam",
357
+ "HULY_FRONT_URL": "https://front.huly.app"
358
+ }
359
+ ```
360
+
361
+ For **self-hosted** Huly, set `HULY_FRONT_URL` to your own front service URL (e.g. `http://localhost:8083`).
362
+
363
+ ### Writing: `update_document`
364
+
365
+ `update_document` accepts a `documentId` and a `markdown` string and writes rich structured content directly to the document — no manual editing required.
366
+
367
+ > **Self-hosted note:** Document content (and, as of this fork, issue descriptions —
368
+ > see below) is stored as a `MarkupBlobRef` blob. Huly Cloud uploads these through a
369
+ > dedicated "datalake" microservice at a fixed URL; `huly-selfhost` (v0.7.x) does not
370
+ > run that service — blob storage goes through `front`'s own, older `/files` endpoint
371
+ > instead. **If `HULY_FRONT_URL` is set, this fork uploads through that self-hosted
372
+ > contract automatically; if it's unset, it falls back to Huly Cloud's datalake** (the
373
+ > original, upstream behavior). No separate flag needed — `HULY_FRONT_URL` doubles as
374
+ > the self-host/cloud switch for both reading and writing.
375
+
376
+ **Supported Markdown:**
377
+
378
+ | Element | Syntax |
379
+ |---------|--------|
380
+ | Headings | `#`, `##`, `###` |
381
+ | Bold / inline code | `**bold**`, `` `code` `` |
382
+ | Paragraphs | plain text |
383
+ | Bullet lists | `- item` |
384
+ | Pipe tables | `\| col \| col \|` |
385
+ | Code blocks | ` ```lang ` |
386
+ | **Mermaid diagrams** | ` ```mermaid ` — stored as Huly's native `mermaid` node type so diagrams render as interactive visuals in the editor |
387
+
388
+ **Example:**
389
+
390
+ ```
391
+ update_document({
392
+ documentId: "abc123",
393
+ markdown: `# Service Flow\n\n` +
394
+ `## Architecture\n\n` +
395
+ "```mermaid\n" +
396
+ "flowchart TD\n" +
397
+ " A([User]) --> B[Browse Catalogue]\n" +
398
+ " B --> C[Pay via Razorpay]\n" +
399
+ " C --> D[Order Confirmed]\n" +
400
+ "```\n\n" +
401
+ "## Business Rules\n\n" +
402
+ "- Payment required before confirmation\n" +
403
+ "- All orders synced to HIS\n"
404
+ })
405
+ ```
406
+
407
+ The Mermaid block renders as a live interactive diagram in Huly's document editor — not as a code block.
408
+
409
+ ---
410
+
411
+ ## Bulk CSV Import
412
+
413
+ Import many issues at once from a CSV file — useful for migrating from other tools:
414
+
415
+ ```bash
416
+ node scripts/import-csv.js tasks.csv PROJ
417
+ ```
418
+
419
+ **CSV format:**
420
+
421
+ ```csv
422
+ title,priority,status,dueDate
423
+ Fix login bug,High,In Progress,2025-04-01
424
+ Add dark mode,Medium,,
425
+ Improve performance,Urgent,,2025-05-01
426
+ ```
427
+
428
+ Required column: `title`. Optional: `priority` (Urgent/High/Medium/Low), `status` (must match a status name in the project), `dueDate` (YYYY-MM-DD).
429
+
430
+ ---
431
+
432
+ ## Manual Auth
433
+
434
+ Create a `.env` file in the project root (or pass via `env` in your client config):
435
+
436
+ **Option A — Email + password (recommended):**
437
+
438
+ Works if you have a password set on your Huly account (Profile → Security → Change password).
439
+
440
+ ```bash
441
+ HULY_EMAIL=your@email.com
442
+ HULY_PASSWORD=yourpassword
443
+ HULY_WORKSPACE=your-workspace-slug
444
+ ```
445
+
446
+ **Option B — Token:**
447
+
448
+ ```bash
449
+ HULY_WORKSPACE=your-workspace-slug
450
+ HULY_TOKEN=your-token-here
451
+ ```
452
+
453
+ To get a token: go to [huly.app](https://huly.app) → open browser DevTools → Application → Local Storage → `https://huly.app` → copy the `token` value.
454
+
455
+ > Tokens expire after some time. If you get an auth error, switch to email + password auth or refresh the token from DevTools.
456
+
457
+ **Self-hosted Huly:**
458
+
459
+ ```bash
460
+ HULY_ACCOUNTS_URL=https://your-huly-instance.com/account
461
+ HULY_FRONT_URL=https://your-huly-instance.com
462
+ ```
463
+
464
+ ---
465
+
466
+ ## Architecture
467
+
468
+ - **Single long-lived WebSocket connection** — connects once per process via `@hcengineering/server-client`, not per tool call (model load takes 1–3 s, so this keeps tools fast)
469
+ - **Lazy init** — connects on the first tool call so auth errors surface clearly in Claude
470
+ - **Dual auth** — OTP token (works for Google/GitHub SSO) or email + password
471
+ - **Stdio transport** — standard MCP transport compatible with Claude Desktop and any MCP client
472
+
473
+ ---
474
+
475
+ ## Changelog
476
+
477
+ ### Fork — self-hosted support, chat, attachments, statuses, organizations
478
+ - **Fix: self-hosted document/description writes** — auto-detects `huly-selfhost` via `HULY_FRONT_URL` and uploads through `front`'s `/files` contract instead of Huly Cloud's datalake, which self-hosted doesn't run
479
+ - **New: `description` on `create_issue`/`update_issue`** — was missing entirely upstream
480
+ - **New: Chat** — `list_channels`, `create_channel`, `start_direct_message`, `send_message`, `list_messages`
481
+ - **New: Attachments** — `attach_file`, `list_attachments`, `delete_attachment`
482
+ - **New: Issue Statuses** — `list_issue_statuses`, `create_issue_status`
483
+ - **New: Organizations** — `list_organizations`, `get_organization`, `create_organization`, `update_organization`
484
+ - See [About this fork](#about-this-fork) for details and what was investigated but not built
485
+
486
+ ### v0.5.6 — delete_document
487
+ - **New: `delete_document`** — permanently delete a document by ID
488
+
489
+ ### v0.5.5 — create_teamspace
490
+ - **New: `create_teamspace`** — create a new document teamspace (top-level folder for organising documents by project or team)
491
+
492
+ ### v0.5.2 — delete_comment + link_document
493
+ - **New: `delete_comment`** — delete a specific comment from an issue by ID; `list_comments` now includes comment IDs in its output
494
+ - **New: `link_document`** — link a Huly document to an issue; the document appears in the Relations panel on the issue
495
+
496
+ ### v0.5.0 — Document Writing + Bug Fixes
497
+ - **New: `update_document`** — write Markdown to any Huly document programmatically; `\`\`\`mermaid` blocks use Huly's native node type and render as interactive diagrams
498
+ - **Fix: `IssueStatus` queries** — statuses are stored globally in Huly (`core:space:Model`), not per-project; removed incorrect space filter that caused *"no statuses found"* errors on `create_issue`, `update_issue`, and `list_issues`
499
+ - **Fix: `create_project`** — sets `members: [currentUser]` so newly created projects are immediately visible in the Huly UI
500
+
501
+ ### v0.4.0
502
+ - `log_time`, `list_comments`, component/milestone assignment on `update_issue`
503
+
504
+ ### v0.3.1
505
+ - `get_document`, `create_document`
506
+
507
+ ### v0.3.0
508
+ - `create_project`, `create_milestone`, assignee support on issues
509
+
510
+ ---
511
+
512
+ ## Links
513
+
514
+ - This fork: https://github.com/JoKeks2023/huly-mcp
515
+ - Upstream: https://github.com/varaprasadreddy9676/huly-mcp ([npm](https://www.npmjs.com/package/huly-mcp-sdk), [MCP Registry](https://registry.modelcontextprotocol.io) — neither reflects this fork's changes)
516
+ - Missing `.d.ts` in `@hcengineering/*` 0.7.411+: https://github.com/hcengineering/platform/issues/10881
517
+
518
+ ---
519
+
520
+ ## License
521
+
522
+ [Eclipse Public License 2.0](https://www.eclipse.org/legal/epl-2.0/)
@@ -0,0 +1,9 @@
1
+ import { type AccountClient } from '@hcengineering/account-client';
2
+ import { TxOperations } from '@hcengineering/core';
3
+ export declare function getConnection(): Promise<TxOperations>;
4
+ export declare function getAccountClient(): Promise<AccountClient>;
5
+ export declare function getWorkspaceInfo(): Promise<{
6
+ wsToken: string;
7
+ workspaceUuid: string;
8
+ }>;
9
+ export declare function closeConnection(): Promise<void>;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getConnection = getConnection;
4
+ exports.getAccountClient = getAccountClient;
5
+ exports.getWorkspaceInfo = getWorkspaceInfo;
6
+ exports.closeConnection = closeConnection;
7
+ const account_client_1 = require("@hcengineering/account-client");
8
+ const core_1 = require("@hcengineering/core");
9
+ const server_client_1 = require("@hcengineering/server-client");
10
+ let state = null;
11
+ let connectPromise = null;
12
+ async function getConnection() {
13
+ if (state !== null)
14
+ return state.txClient;
15
+ if (connectPromise !== null)
16
+ return (await connectPromise).txClient;
17
+ connectPromise = connect();
18
+ state = await connectPromise;
19
+ connectPromise = null;
20
+ return state.txClient;
21
+ }
22
+ async function getAccountClient() {
23
+ if (state !== null)
24
+ return state.accountClient;
25
+ await getConnection();
26
+ return state.accountClient;
27
+ }
28
+ async function getWorkspaceInfo() {
29
+ if (state !== null)
30
+ return { wsToken: state.wsToken, workspaceUuid: state.workspaceUuid };
31
+ await getConnection();
32
+ return { wsToken: state.wsToken, workspaceUuid: state.workspaceUuid };
33
+ }
34
+ async function connect() {
35
+ const email = process.env.HULY_EMAIL;
36
+ const password = process.env.HULY_PASSWORD;
37
+ const workspaceUrl = process.env.HULY_WORKSPACE;
38
+ const hulyToken = process.env.HULY_TOKEN;
39
+ const accountsUrl = process.env.HULY_ACCOUNTS_URL ?? 'https://account.huly.app';
40
+ if (workspaceUrl == null) {
41
+ throw new Error('Missing required env var: HULY_WORKSPACE');
42
+ }
43
+ let socialId;
44
+ let endpoint;
45
+ let wsToken;
46
+ let workspaceUuid = '';
47
+ if (hulyToken != null) {
48
+ // Token-based auth — for SSO accounts (Google/GitHub login on huly.app)
49
+ // Get the token from your browser: huly.app → DevTools → Application →
50
+ // Local Storage → huly.app → look for the key "token"
51
+ const authedClient = (0, account_client_1.getClient)(accountsUrl, hulyToken);
52
+ const info = await authedClient.getLoginInfoByToken();
53
+ if (info == null) {
54
+ throw new Error('HULY_TOKEN is invalid or expired. Please get a fresh token from huly.app DevTools.');
55
+ }
56
+ if ('endpoint' in info && info.endpoint != null) {
57
+ // It's a WorkspaceLoginInfo — already has endpoint + workspace token
58
+ if (info.socialId == null) {
59
+ throw new Error('Token auth: no socialId in token. Try a workspace-scoped token.');
60
+ }
61
+ socialId = info.socialId;
62
+ endpoint = info.endpoint;
63
+ wsToken = info.token;
64
+ workspaceUuid = String(info.workspace ?? '');
65
+ }
66
+ else if ('token' in info && info.token != null) {
67
+ // It's a plain LoginInfo (account-level token) — still need selectWorkspace
68
+ if (info.socialId == null) {
69
+ throw new Error('Token auth: no socialId returned.');
70
+ }
71
+ socialId = info.socialId;
72
+ const wsInfo = await authedClient.selectWorkspace(workspaceUrl, 'external');
73
+ if (wsInfo.endpoint == null || wsInfo.token == null) {
74
+ throw new Error(`Workspace '${workspaceUrl}' not found or not accessible.`);
75
+ }
76
+ endpoint = wsInfo.endpoint;
77
+ wsToken = wsInfo.token;
78
+ workspaceUuid = String(wsInfo.workspace ?? '');
79
+ }
80
+ else {
81
+ throw new Error('Token auth: unexpected response from getLoginInfoByToken. Token may be incomplete.');
82
+ }
83
+ }
84
+ else {
85
+ // Email + password auth — for accounts with a password set on huly.app
86
+ if (email == null || password == null) {
87
+ throw new Error('Missing credentials. Provide HULY_TOKEN (for SSO accounts) or both HULY_EMAIL and HULY_PASSWORD.');
88
+ }
89
+ // Step 1: login → get account token + socialId
90
+ const unauthClient = (0, account_client_1.getClient)(accountsUrl);
91
+ const loginInfo = await unauthClient.login(email, password);
92
+ if (loginInfo.token == null) {
93
+ throw new Error('Login failed: no token returned. Check credentials.');
94
+ }
95
+ if (loginInfo.socialId == null) {
96
+ throw new Error('Login failed: no socialId returned.');
97
+ }
98
+ // Step 2: select workspace → get WS endpoint + workspace token
99
+ const authedAccountClient = (0, account_client_1.getClient)(accountsUrl, loginInfo.token);
100
+ const wsInfo = await authedAccountClient.selectWorkspace(workspaceUrl, 'external');
101
+ if (wsInfo.endpoint == null || wsInfo.token == null) {
102
+ throw new Error(`Workspace '${workspaceUrl}' not found or not accessible.`);
103
+ }
104
+ socialId = loginInfo.socialId;
105
+ endpoint = wsInfo.endpoint;
106
+ workspaceUuid = String(wsInfo.workspace ?? '');
107
+ wsToken = wsInfo.token;
108
+ }
109
+ // Step 3: open WebSocket connection
110
+ const rawConnection = await (0, server_client_1.createClient)(endpoint, wsToken);
111
+ const txClient = new core_1.TxOperations(rawConnection, socialId);
112
+ // Build workspace-scoped account client for member lookups
113
+ const accountClient = (0, account_client_1.getClient)(accountsUrl, wsToken);
114
+ return { txClient, rawConnection, accountClient, wsToken, workspaceUuid };
115
+ }
116
+ async function closeConnection() {
117
+ if (state !== null) {
118
+ await state.rawConnection.close();
119
+ state = null;
120
+ }
121
+ }
122
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};