@bgx4k3p/huly-mcp-server 2.0.0 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,24 +3,23 @@
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4
4
  [![Node.js](https://img.shields.io/badge/Node.js-22+-339933?logo=node.js&logoColor=white)](https://nodejs.org)
5
5
  [![MCP](https://img.shields.io/badge/MCP-compatible-blue)](https://modelcontextprotocol.io)
6
- [![Tests](https://img.shields.io/badge/tests-162%20passing-brightgreen)](test/integration.test.mjs)
7
- [![Coverage](https://img.shields.io/badge/coverage-100%25%20methods-brightgreen)](test/integration.test.mjs)
8
- [![npm](https://img.shields.io/npm/v/@bgx4k3p/huly-mcp-server)](https://www.npmjs.com/package/@bgx4k3p/huly-mcp-server)
9
6
  [![Huly SDK](https://img.shields.io/badge/Huly%20SDK-0.7.x-purple)](https://huly.io)
10
7
  [![Docker](https://img.shields.io/badge/Docker-ready-2496ED?logo=docker&logoColor=white)](Dockerfile)
11
8
 
12
- MCP and HTTP REST server providing full coverage of the
13
- [Huly](https://huly.io) SDK — issues, projects, workspaces, members,
14
- and account management. Tested against self-hosted Huly.
9
+ MCP server providing full coverage of the [Huly](https://huly.io) SDK —
10
+ issues, projects, workspaces, members, and account management.
11
+ Two transports: **stdio** for local tools and **Streamable HTTP** for
12
+ remote clients. Tested against self-hosted Huly.
15
13
  May also work with [Huly Cloud](https://app.huly.io) (not yet tested).
16
14
 
17
15
  ## Why This Exists
18
16
 
19
- Huly has no REST API. The only programmatic access is through their JavaScript SDK,
17
+ Huly has no public API. The only programmatic access is through their JavaScript SDK,
20
18
  which connects via WebSocket. This server wraps that SDK and exposes **MCP tools**
21
- and a **full HTTP REST API** with OpenAPI spec, authentication, rate limiting, and SSE events.
19
+ over both stdio and **Streamable HTTP** transports compatible with Claude Code,
20
+ VS Code, n8n, and any MCP client.
22
21
 
23
- ## Quick Start
22
+ ## Install
24
23
 
25
24
  ```bash
26
25
  git clone https://github.com/bgx4k3p/huly-mcp-server.git
@@ -28,6 +27,14 @@ cd huly-mcp-server
28
27
  npm install
29
28
  ```
30
29
 
30
+ > **Note:** The Huly SDK publishes packages with pnpm `workspace:`
31
+ > protocol in transitive dependencies, which prevents `npx` and
32
+ > global npm installs from working. Clone from source is required.
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
31
38
  ### Authentication
32
39
 
33
40
  You can authenticate with either **email/password** or a **token**.
@@ -57,23 +64,51 @@ export HULY_TOKEN=<paste-token-from-above>
57
64
  export HULY_WORKSPACE=your-workspace
58
65
  ```
59
66
 
60
- The token does not expire. You can store it in a secrets manager or
61
- `~/.secrets` file and stop exposing your password in environment variables.
67
+ The token does not expire. You can store it in a secrets manager
68
+ and stop exposing your password in environment variables.
62
69
 
63
70
  ---
64
71
 
65
72
  ## Integrations
66
73
 
67
- ### Claude Code (MCP)
74
+ ### Claude Code (stdio)
75
+
76
+ After cloning and running `npm install`, register the server:
77
+
78
+ ```bash
79
+ claude mcp add huly \
80
+ -e HULY_URL=https://your-huly-instance.com \
81
+ -e HULY_TOKEN=your-token \
82
+ -e HULY_WORKSPACE=your-workspace \
83
+ -- node /absolute/path/to/huly-mcp-server/src/index.mjs
84
+ ```
85
+
86
+ Or add to your `.mcp.json` manually (token auth — recommended):
87
+
88
+ ```json
89
+ {
90
+ "mcpServers": {
91
+ "huly": {
92
+ "command": "node",
93
+ "args": ["/path/to/huly-mcp-server/src/index.mjs"],
94
+ "env": {
95
+ "HULY_URL": "https://your-huly-instance.com",
96
+ "HULY_TOKEN": "${HULY_TOKEN}",
97
+ "HULY_WORKSPACE": "${HULY_WORKSPACE}"
98
+ }
99
+ }
100
+ }
101
+ }
102
+ ```
68
103
 
69
- Add to your `.mcp.json`:
104
+ Or with email/password:
70
105
 
71
106
  ```json
72
107
  {
73
108
  "mcpServers": {
74
109
  "huly": {
75
110
  "command": "node",
76
- "args": ["path/to/huly-mcp-server/src/index.mjs"],
111
+ "args": ["/path/to/huly-mcp-server/src/index.mjs"],
77
112
  "env": {
78
113
  "HULY_URL": "https://your-huly-instance.com",
79
114
  "HULY_EMAIL": "${HULY_EMAIL}",
@@ -95,53 +130,45 @@ Then ask Claude things like:
95
130
  All tools have detailed descriptions optimized for AI agents.
96
131
  MCP Resources are also available at `huly://projects/{id}` and `huly://issues/{id}`.
97
132
 
98
- ### n8n / Automation Workflows
133
+ ### Streamable HTTP (n8n, VS Code, remote clients)
99
134
 
100
- Start the HTTP server:
135
+ Start the HTTP MCP server:
101
136
 
102
137
  ```bash
103
138
  npm run start:server
104
- # Listening on port 3001
139
+ # MCP endpoint: http://localhost:3001/mcp
140
+ # Health check: http://localhost:3001/health
105
141
  ```
106
142
 
107
- Use HTTP Request nodes pointing to `http://localhost:3001/api/...`:
108
-
109
- ```bash
110
- # List projects
111
- curl http://localhost:3001/api/projects
143
+ Any MCP client that supports Streamable HTTP can connect to
144
+ `http://localhost:3001/mcp`. This includes n8n (v1.88+),
145
+ VS Code, and other MCP-compatible tools.
112
146
 
113
- # Create an issue
114
- curl -X POST http://localhost:3001/api/projects/OPS/issues \
115
- -H "Content-Type: application/json" \
116
- -d '{"title": "New issue", "priority": "high"}'
147
+ To secure the endpoint, set a bearer token:
117
148
 
118
- # Get project summary
119
- curl http://localhost:3001/api/projects/OPS/summary
149
+ ```bash
150
+ MCP_AUTH_TOKEN=your-secret npm run start:server
120
151
  ```
121
152
 
122
- OpenAPI spec available at `GET /api/openapi.json` for auto-discovery in n8n and other tools.
153
+ Clients must then include `Authorization: Bearer your-secret` in requests.
123
154
 
124
155
  ### Docker
125
156
 
126
157
  ```bash
127
158
  docker build -t huly-mcp-server .
128
159
 
160
+ # Streamable HTTP server (recommended)
129
161
  docker run -d \
130
162
  -p 3001:3001 \
131
163
  -e HULY_URL=https://your-huly-instance.com \
132
- -e HULY_EMAIL=admin@example.com \
133
- -e HULY_PASSWORD=secret \
164
+ -e HULY_TOKEN=your-token \
134
165
  -e HULY_WORKSPACE=my-workspace \
135
166
  huly-mcp-server
136
- ```
137
-
138
- For MCP stdio mode in Docker:
139
167
 
140
- ```bash
168
+ # MCP stdio mode
141
169
  docker run -i \
142
170
  -e HULY_URL=https://your-huly-instance.com \
143
- -e HULY_EMAIL=admin@example.com \
144
- -e HULY_PASSWORD=secret \
171
+ -e HULY_TOKEN=your-token \
145
172
  -e HULY_WORKSPACE=my-workspace \
146
173
  huly-mcp-server node src/mcp.mjs
147
174
  ```
@@ -150,9 +177,6 @@ docker run -i \
150
177
 
151
178
  ## Server Configuration
152
179
 
153
- These settings control the MCP server itself — authentication, rate limiting,
154
- connection pooling. They are separate from the Huly credentials above.
155
-
156
180
  ### Environment Variables
157
181
 
158
182
  | Variable | Required | Default | Description |
@@ -163,14 +187,16 @@ connection pooling. They are separate from the Huly credentials above.
163
187
  | `HULY_EMAIL` | No | - | Huly login email (required if no token) |
164
188
  | `HULY_PASSWORD` | No | - | Huly login password (required if no token) |
165
189
  | `HULY_WORKSPACE` | Yes* | - | Default workspace slug |
166
- | **Server Settings** | | | |
167
- | `PORT` | No | `3001` | HTTP server port |
168
- | `MCP_AUTH_TOKEN` | No | - | Bearer token for HTTP server auth (disabled if unset) |
169
- | `HULY_RATE_LIMIT` | No | `100` | Max requests per minute per IP |
190
+ | `HULY_TRANSPORT` | No | `ws` | SDK transport: `ws` (WebSocket) or `rest` (REST API) |
170
191
  | `HULY_POOL_TTL_MS` | No | `1800000` | Connection pool TTL in ms (30 min) |
192
+ | **HTTP Server** | | | |
193
+ | `PORT` | No | `3001` | HTTP server port (auto-assigns if taken) |
194
+ | `MCP_AUTH_TOKEN` | No | - | Bearer token for HTTP auth (disabled if unset) |
195
+ | `HULY_RATE_LIMIT` | No | `200` | Max requests per minute per IP |
196
+ | `ALLOWED_ORIGINS` | No | `*` | CORS allowed origins (comma-separated) |
171
197
 
172
- *`HULY_WORKSPACE` is required for MCP mode. For HTTP mode it can be
173
- omitted if every request specifies a workspace via header or query param.
198
+ *`HULY_WORKSPACE` is required for MCP stdio mode. For HTTP mode it can
199
+ be omitted if every request specifies a workspace via the tool arguments.
174
200
 
175
201
  ### HTTP Server Authentication
176
202
 
@@ -183,71 +209,49 @@ openssl rand -hex 32
183
209
 
184
210
  # Start with auth enabled
185
211
  MCP_AUTH_TOKEN=your-token-here npm run start:server
186
-
187
- # Clients must include it in requests
188
- curl -H "Authorization: Bearer your-token-here" http://localhost:3001/api/projects
189
212
  ```
190
213
 
191
214
  If `MCP_AUTH_TOKEN` is not set, auth is disabled (fine for local-only usage).
192
215
 
193
216
  MCP stdio mode (Claude Code) does not use this token — stdio is inherently local.
194
217
 
195
- ### Rate Limiting
196
-
197
- Per-IP rate limiting is always active. Response headers show current state:
198
-
199
- ```text
200
- X-RateLimit-Limit: 100
201
- X-RateLimit-Remaining: 97
202
- X-RateLimit-Reset: 1710000000
203
- ```
204
-
205
- Returns `429 Too Many Requests` when exceeded.
206
-
207
- ### SSE Event Stream
208
-
209
- Subscribe to real-time mutation events:
210
-
211
- ```bash
212
- curl -N http://localhost:3001/api/events
213
- ```
214
-
215
- Events: `issue.created`, `issue.updated`, `issue.moved`, `issue.assigned`,
216
- `issue.comment_added`, `issue.label_added`, `issues.batch_created`,
217
- `issues.template_created`, and more.
218
-
219
218
  ### Multi-Workspace
220
219
 
221
- All tools/endpoints accept an optional workspace parameter. The connection pool caches clients by workspace slug:
220
+ All tools accept an optional `workspace` parameter. The connection pool
221
+ caches clients by workspace slug with configurable TTL:
222
222
 
223
- ```bash
224
- # MCP: pass workspace in tool arguments
223
+ ```json
225
224
  {"tool": "list_projects", "arguments": {"workspace": "workspace-a"}}
226
-
227
- # HTTP: via header or query param
228
- curl -H "X-Huly-Workspace: workspace-a" http://localhost:3001/api/projects
229
- curl "http://localhost:3001/api/projects?workspace=workspace-b"
230
225
  ```
231
226
 
227
+ If omitted, the `HULY_WORKSPACE` env var is used as the default.
228
+
232
229
  ---
233
230
 
234
231
  ## Testing
235
232
 
236
233
  Uses Node.js built-in `node:test` and `node:assert` — no test framework dependencies.
234
+ Tests run twice: once with WebSocket transport, once with REST transport.
237
235
 
238
236
  ```bash
239
- npm test
237
+ npm test # Both transports (ws + rest)
238
+ npm run test:ws # WebSocket only
239
+ npm run test:rest # REST only
240
240
  ```
241
241
 
242
- | Section | Tests | Description |
242
+ 194 tests across 101 suites:
243
+
244
+ | Suite | Tests | Description |
243
245
  | --- | --- | --- |
244
- | **Unit** | 28 | Constants, ID parsing, route matching, rate limiting, auth |
245
- | **Integration** | 43 | Full CRUD lifecycle against live Huly |
246
- | **Account-Level** | 11 | Workspaces, profile, social IDs |
247
- | **Mock** | 28 | Destructive ops, token auth via mocks |
248
- | **HTTP Server** | 52 | Every REST endpoint via real HTTP requests |
246
+ | **Unit** | 28 | Constants, ID parsing, rate limiting, auth logic |
247
+ | **Integration** | 55 | Full CRUD lifecycle against live Huly |
248
+ | **Dispatch** | 45 | Schema to dispatch to client param forwarding for all tools |
249
+ | **Account-level** | 11 | Workspaces, profile, social IDs |
250
+ | **Mock** | 44 | Destructive ops, token auth via mocks |
251
+ | **Streamable HTTP** | 11 | MCP protocol over HTTP: init, tools, resources, auth, rate limiting |
249
252
 
250
- **100% method coverage.** All test issues are prefixed with `[TEST]` and cleaned up after each run.
253
+ **100% dispatch coverage** every tool's params are traced end-to-end
254
+ through the dispatch table to the client method.
251
255
 
252
256
  ---
253
257
 
@@ -274,27 +278,63 @@ bypass Application for `/_*` or these individual paths:
274
278
 
275
279
  ```text
276
280
  src/
277
- client.mjs # HulyClient class - all business logic
278
- pool.mjs # Connection pool - caches clients by workspace with TTL
279
- mcp.mjs # MCP stdio entry point - MCP tools + resources
280
- server.mjs # HTTP REST entry point - auth, rate limiting, SSE, OpenAPI
281
- index.mjs # Backwards compat - re-exports mcp.mjs
281
+ client.mjs # HulyClient all business logic and SDK calls
282
+ helpers.mjs # Shared constants, markup conversion, JSDOM polyfills
283
+ dispatch.mjs # Tool-to-method dispatch table
284
+ pool.mjs # Connection pool caches clients by workspace with TTL
285
+ mcpShared.mjs # Shared MCP server factory — tool definitions + resources
286
+ mcp.mjs # MCP stdio entry point (Claude Code)
287
+ server.mjs # MCP Streamable HTTP entry point (n8n, VS Code, remote)
288
+ index.mjs # CLI entry point — --get-token mode + MCP re-export
282
289
  ```
283
290
 
284
291
  ```text
285
- Claude Code -> stdio -> mcp.mjs -> pool.mjs -> client.mjs -> REST -> Huly
286
- n8n / curl -> HTTP -> server.mjs -> pool.mjs -> client.mjs -> REST -> Huly
292
+ Claude Code -> stdio -> mcp.mjs -> mcpShared.mjs -> pool -> client -> Huly SDK
293
+ n8n / remote -> Streamable HTTP -> server.mjs -> mcpShared.mjs -> pool -> client -> Huly SDK
287
294
  ```
288
295
 
289
296
  ---
290
297
 
291
- ## API Reference
298
+ ## Response Format
299
+
300
+ All read operations return **known fields** at the top level with
301
+ resolved, human-readable values (e.g., status names instead of IDs,
302
+ formatted dates). Any additional fields from the Huly SDK that aren't
303
+ explicitly mapped appear in an `extra` object — this future-proofs
304
+ the API so new SDK fields are visible without a code update.
305
+
306
+ ```json
307
+ {
308
+ "id": "PROJ-42",
309
+ "title": "Fix the bug",
310
+ "status": "In Progress",
311
+ "priority": "High",
312
+ "type": "Task",
313
+ "parent": "PROJ-10",
314
+ "childCount": 3,
315
+ "createdOn": 1719700000000,
316
+ "completedAt": null,
317
+ "extra": {
318
+ "_id": "69bab168...",
319
+ "_class": "tracker:class:Issue",
320
+ "space": "69b819b7...",
321
+ "kind": "tracker:taskTypes:Issue"
322
+ }
323
+ }
324
+ ```
325
+
326
+ Text fields (`description`, `comment`) support three input formats
327
+ via `descriptionFormat` / `format` parameter:
292
328
 
293
- Full list of all MCP tools and HTTP endpoints available through this server.
329
+ - **markdown** (default) rendered as rich text in the Huly UI
330
+ - **html** — raw HTML, converted to rich text
331
+ - **plain** — stored as unformatted text
294
332
 
295
- ### MCP Tools
333
+ ## API Reference
296
334
 
297
- #### Account & Workspace Management
335
+ Full list of all MCP tools available through this server.
336
+
337
+ ### Account and Workspace Management
298
338
 
299
339
  | Tool | Description |
300
340
  | --- | --- |
@@ -311,7 +351,7 @@ Full list of all MCP tools and HTTP endpoints available through this server.
311
351
  | `change_password` | Change password |
312
352
  | `change_username` | Change username |
313
353
 
314
- #### Invites
354
+ ### Invites
315
355
 
316
356
  | Tool | Description |
317
357
  | --- | --- |
@@ -319,7 +359,7 @@ Full list of all MCP tools and HTTP endpoints available through this server.
319
359
  | `resend_invite` | Resend pending invite |
320
360
  | `create_invite_link` | Generate shareable invite link |
321
361
 
322
- #### Integrations, Mailboxes, Social IDs, Subscriptions
362
+ ### Integrations, Mailboxes, Social IDs, Subscriptions
323
363
 
324
364
  | Tool | Description |
325
365
  | --- | --- |
@@ -328,118 +368,155 @@ Full list of all MCP tools and HTTP endpoints available through this server.
328
368
  | `find_person_by_social_key` / `get_social_ids` / `add_email_social_id` | Person/social ID management |
329
369
  | `list_subscriptions` | List account subscriptions |
330
370
 
331
- #### Projects & Issues
371
+ ### Projects
372
+
373
+ | Tool | Description | Text Format |
374
+ | --- | --- | --- |
375
+ | `list_projects` | List all projects (supports `include_details`) | -- |
376
+ | `get_project` | Get project by identifier (supports `include_details`) | -- |
377
+ | `create_project` | Create a new project | `descriptionFormat`: md/html/plain |
378
+ | `update_project` | Update project name, description, privacy, default assignee | `descriptionFormat`: md/html/plain |
379
+ | `archive_project` | Archive or unarchive a project | -- |
380
+ | `delete_project` | Permanently delete a project | -- |
381
+ | `summarize_project` | Aggregated project metrics and health | -- |
382
+
383
+ ### Issues
384
+
385
+ | Tool | Description | Text Format |
386
+ | --- | --- | --- |
387
+ | `list_issues` | List issues with filters (supports `include_details`) | -- |
388
+ | `get_issue` | Get full issue details (supports `include_details`) | -- |
389
+ | `create_issue` | Create a new issue | `descriptionFormat`: md/html/plain |
390
+ | `update_issue` | Update issue fields | `descriptionFormat`: md/html/plain |
391
+ | `delete_issue` | Permanently delete an issue | -- |
392
+ | `search_issues` | Full-text search across projects | -- |
393
+ | `get_my_issues` | Issues assigned to current user | -- |
394
+ | `batch_create_issues` | Create multiple issues at once | `descriptionFormat` per item |
395
+ | `move_issue` | Move issue between projects | -- |
396
+ | `create_issues_from_template` | Create from predefined templates | -- |
397
+
398
+ ### Labels
332
399
 
333
400
  | Tool | Description |
334
401
  | --- | --- |
335
- | `list_projects` / `get_project` | Browse projects |
336
- | `list_issues` / `get_issue` / `create_issue` / `update_issue` | Full issue CRUD with filtering |
337
- | `search_issues` | Full-text search across projects |
338
- | `get_my_issues` | Issues assigned to current user |
339
- | `batch_create_issues` | Create multiple issues at once |
340
- | `move_issue` | Move issue between projects |
341
- | `summarize_project` | Aggregated project metrics |
342
- | `get_issue_history` | Activity timeline for an issue |
343
- | `create_issues_from_template` | Create from feature/bug/sprint/release templates |
344
-
345
- #### Labels, Relations, Milestones, Members, Comments, Time Tracking
402
+ | `list_labels` | List all labels in the workspace |
403
+ | `get_label` | Find a label by name |
404
+ | `create_label` | Create a new label with optional color |
405
+ | `update_label` | Update label name, color, or description |
406
+ | `add_label` | Add a label to an issue |
407
+ | `remove_label` | Remove a label from an issue |
408
+
409
+ ### Relations
346
410
 
347
411
  | Tool | Description |
348
412
  | --- | --- |
349
- | `list_labels` / `create_label` / `add_label` / `remove_label` | Label management |
350
- | `add_relation` / `add_blocked_by` / `set_parent` | Issue relationships |
351
- | `list_milestones` / `get_milestone` / `create_milestone` / `set_milestone` | Milestone management |
352
- | `list_members` / `assign_issue` | Member management |
353
- | `add_comment` / `list_comments` | Comments |
354
- | `set_due_date` / `set_estimation` / `log_time` | Time tracking |
355
- | `list_task_types` / `list_statuses` | Metadata |
356
-
357
- ### HTTP REST Endpoints
413
+ | `add_relation` | Add bidirectional "related to" link |
414
+ | `add_blocked_by` | Add "blocked by" dependency |
415
+ | `set_parent` | Set parent issue (epic/task hierarchy) |
358
416
 
359
- #### System Routes
417
+ ### Components
360
418
 
361
- | Method | Path | Description |
419
+ | Tool | Description | Text Format |
362
420
  | --- | --- | --- |
363
- | GET | `/health` | Health check |
364
- | GET | `/api/openapi.json` | OpenAPI 3.0.3 spec |
365
- | GET | `/api/events` | SSE event stream |
421
+ | `list_components` | List components in a project | -- |
422
+ | `get_component` | Find a component by name | -- |
423
+ | `create_component` | Create a new component | `descriptionFormat`: md/html/plain |
424
+ | `update_component` | Update component fields | `descriptionFormat`: md/html/plain |
425
+ | `delete_component` | Delete a component | -- |
366
426
 
367
- #### Account & Workspace Routes
427
+ ### Milestones
368
428
 
369
- | Method | Path | Description |
429
+ | Tool | Description | Text Format |
370
430
  | --- | --- | --- |
371
- | GET | `/api/workspaces` | List workspaces |
372
- | GET | `/api/workspaces/:slug/info` | Get workspace info |
373
- | POST | `/api/workspaces` | Create workspace |
374
- | PATCH | `/api/workspaces/:slug/name` | Rename workspace |
375
- | DELETE | `/api/workspaces/:slug` | Delete workspace |
376
- | GET | `/api/workspaces/:slug/members` | List members |
377
- | PATCH | `/api/workspaces/:slug/role` | Update member role |
378
- | POST | `/api/workspaces/:slug/invites` | Send invite |
379
- | POST | `/api/workspaces/:slug/invite-link` | Create invite link |
380
- | GET | `/api/account` | Get account info |
381
- | GET | `/api/profile` | Get user profile |
382
- | PATCH | `/api/profile` | Update profile |
383
- | GET | `/api/integrations` | List integrations |
384
- | POST | `/api/integrations` | Create integration |
385
- | DELETE | `/api/integrations/:id` | Delete integration |
386
- | GET | `/api/mailboxes` | List mailboxes |
387
- | GET | `/api/social-ids` | List social IDs |
388
- | GET | `/api/subscriptions` | List subscriptions |
389
-
390
- #### Project & Issue Routes
391
-
392
- | Method | Path | Description |
431
+ | `list_milestones` | List milestones (supports `include_details`) | -- |
432
+ | `get_milestone` | Get milestone details (supports `include_details`) | -- |
433
+ | `create_milestone` | Create a new milestone | `descriptionFormat`: md/html/plain |
434
+ | `update_milestone` | Update milestone fields | `descriptionFormat`: md/html/plain |
435
+ | `delete_milestone` | Delete a milestone | -- |
436
+ | `set_milestone` | Set or clear milestone on an issue | -- |
437
+
438
+ ### Members
439
+
440
+ | Tool | Description |
441
+ | --- | --- |
442
+ | `list_members` | List all active workspace members |
443
+ | `get_member` | Find a member by name (fuzzy match) |
444
+
445
+ ### Comments
446
+
447
+ | Tool | Description | Text Format |
393
448
  | --- | --- | --- |
394
- | GET | `/api/projects` | List all projects |
395
- | GET | `/api/projects/:identifier` | Get project by identifier |
396
- | GET | `/api/projects/:project/summary` | Project summary with metrics |
397
- | GET | `/api/projects/:project/issues` | List issues (query: status, priority, label, milestone, limit) |
398
- | GET | `/api/projects/:project/issues/:number` | Get issue |
399
- | POST | `/api/projects/:project/issues` | Create issue |
400
- | PATCH | `/api/issues/:issueId` | Update issue |
401
- | POST | `/api/issues/:issueId/move` | Move to different project |
402
- | GET | `/api/issues/:issueId/history` | Get activity history |
403
- | GET | `/api/my-issues` | Issues assigned to current user |
404
- | POST | `/api/projects/:project/batch-issues` | Batch create issues |
405
- | POST | `/api/projects/:project/template` | Create from template |
406
- | GET | `/api/search?query=...&project=...&limit=...` | Search issues |
407
-
408
- #### Other Resource Routes
409
-
410
- | Method | Path | Description |
449
+ | `list_comments` | List all comments on an issue | -- |
450
+ | `get_comment` | Get a specific comment by ID | -- |
451
+ | `add_comment` | Add a comment to an issue | `format`: md/html/plain |
452
+ | `update_comment` | Update comment text | `format`: md/html/plain |
453
+ | `delete_comment` | Delete a comment | -- |
454
+
455
+ ### Time Tracking
456
+
457
+ | Tool | Description | Text Format |
411
458
  | --- | --- | --- |
412
- | GET | `/api/labels` | List all labels |
413
- | POST | `/api/labels` | Create label |
414
- | POST | `/api/issues/:issueId/labels` | Add label to issue |
415
- | DELETE | `/api/issues/:issueId/labels/:label` | Remove label |
416
- | POST | `/api/issues/:issueId/relations` | Add relation |
417
- | POST | `/api/issues/:issueId/blocked-by` | Add blocked-by |
418
- | POST | `/api/issues/:issueId/parent` | Set parent |
419
- | GET | `/api/projects/:project/task-types` | List task types |
420
- | GET | `/api/statuses` | List all statuses |
421
- | GET | `/api/projects/:project/milestones` | List milestones |
422
- | GET | `/api/projects/:project/milestones/:name` | Get milestone |
423
- | POST | `/api/projects/:project/milestones` | Create milestone |
424
- | PATCH | `/api/issues/:issueId/milestone` | Set/clear milestone |
425
- | GET | `/api/members` | List workspace members |
426
- | PATCH | `/api/issues/:issueId/assignee` | Assign/unassign issue |
427
- | GET | `/api/issues/:issueId/comments` | List comments |
428
- | POST | `/api/issues/:issueId/comments` | Add comment |
429
- | PATCH | `/api/issues/:issueId/due-date` | Set/clear due date |
430
- | PATCH | `/api/issues/:issueId/estimation` | Set estimation |
431
- | POST | `/api/issues/:issueId/time-logs` | Log time |
459
+ | `log_time` | Log actual time spent | `descriptionFormat`: md/html/plain |
460
+ | `list_time_reports` | List time reports for an issue | -- |
461
+ | `get_time_report` | Get a specific time report by ID | -- |
462
+ | `delete_time_report` | Delete a time report | -- |
463
+
464
+ ### Metadata
465
+
466
+ | Tool | Description |
467
+ | --- | --- |
468
+ | `list_task_types` | List task types for a project |
469
+ | `get_task_type` | Find a task type by name |
470
+ | `list_statuses` | List issue statuses |
471
+ | `get_status` | Find a status by name |
472
+
473
+ > **Text format**: All text fields default to `markdown`.
474
+ > Set `descriptionFormat` (or `format` for comments) to
475
+ > `"markdown"`, `"html"`, or `"plain"`. Content is passed
476
+ > through unmodified -- the format tells Huly how to render it.
477
+
478
+ ### include\_details Flag
479
+
480
+ Several read tools support an `include_details` boolean parameter that
481
+ fetches related data in a single call:
482
+
483
+ | Tool | Extra data when `include_details=true` |
484
+ | --- | --- |
485
+ | `get_issue` | Comments, time reports, relations, children |
486
+ | `list_issues` | Descriptions, comments, time reports, relations, children (limit reduced to 50) |
487
+ | `get_project` | Milestones, components, labels, members |
488
+ | `list_projects` | Milestones, components, labels, members per project (limit 20) |
489
+ | `get_milestone` | Full list of issues in the milestone |
490
+ | `list_milestones` | Issues list per milestone |
491
+
492
+ ### CRUD Coverage
493
+
494
+ | Entity | Create | Read | List | Update | Delete |
495
+ | --- | --- | --- | --- | --- | --- |
496
+ | Project | `create_project` | `get_project` | `list_projects` | `update_project` | `delete_project` |
497
+ | Issue | `create_issue` | `get_issue` | `list_issues` | `update_issue` | `delete_issue` |
498
+ | Label | `create_label` | `get_label` | `list_labels` | `update_label` | `remove_label` |
499
+ | Component | `create_component` | `get_component` | `list_components` | `update_component` | `delete_component` |
500
+ | Milestone | `create_milestone` | `get_milestone` | `list_milestones` | `update_milestone` | `delete_milestone` |
501
+ | Comment | `add_comment` | `get_comment` | `list_comments` | `update_comment` | `delete_comment` |
502
+ | Time Report | `log_time` | `get_time_report` | `list_time_reports` | -- | `delete_time_report` |
503
+ | Member | -- | `get_member` | `list_members` | -- | -- |
504
+ | Status | -- | `get_status` | `list_statuses` | -- | -- |
505
+ | Task Type | -- | `get_task_type` | `list_task_types` | -- | -- |
432
506
 
433
507
  ### Issue Templates
434
508
 
435
- Use `create_issues_from_template` (MCP) or `POST /api/projects/:project/template` (HTTP):
509
+ Use `create_issues_from_template`:
436
510
 
437
511
  | Template | Creates |
438
512
  | --- | --- |
439
- | `feature` | Epic + design/implement/test/docs/review sub-issues |
440
- | `bug` | Bug + reproduce/root-cause/fix/regression-test sub-issues |
513
+ | `feature` | Parent + design/implement/test/docs/review sub-issues |
514
+ | `bug` | Parent + reproduce/root-cause/fix/regression-test sub-issues |
441
515
  | `sprint` | Planning/standup/review/retro ceremony issues |
442
- | `release` | Epic + freeze/QA/changelog/staging/prod/verify sub-issues |
516
+ | `release` | Parent + freeze/QA/changelog/staging/prod/verify sub-issues |
517
+
518
+ Templates use task types like Epic/Bug when available, falling back
519
+ to the workspace default type otherwise.
443
520
 
444
521
  ---
445
522
 
@@ -447,7 +524,7 @@ Use `create_issues_from_template` (MCP) or `POST /api/projects/:project/template
447
524
 
448
525
  `npm audit` reports moderate vulnerabilities in Svelte (SSR XSS).
449
526
  These come from Huly SDK transitive dependencies — the SDK shares packages
450
- with Huly's web frontend. This server never renders HTML or uses Svelte.
527
+ with Huly's web frontend. MCP server never renders HTML or uses Svelte.
451
528
  The vulnerabilities are **not exploitable** in this context.
452
529
 
453
530
  ---