huly-mcp-selfhost 1.0.0 → 2.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.
- package/.env.example +17 -9
- package/LICENSE +80 -0
- package/README.md +195 -111
- package/dist/connection.d.ts +65 -4
- package/dist/connection.js +230 -93
- package/dist/connection.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/schemas.d.ts +162 -2
- package/dist/schemas.js +65 -3
- package/dist/schemas.js.map +1 -1
- package/dist/server.js +52 -6
- package/dist/server.js.map +1 -1
- package/dist/tools/attachments.d.ts +3 -0
- package/dist/tools/attachments.js +5 -5
- package/dist/tools/attachments.js.map +1 -1
- package/dist/tools/channels.d.ts +5 -0
- package/dist/tools/channels.js +5 -5
- package/dist/tools/channels.js.map +1 -1
- package/dist/tools/comments.d.ts +3 -0
- package/dist/tools/comments.js +3 -3
- package/dist/tools/comments.js.map +1 -1
- package/dist/tools/components.d.ts +2 -0
- package/dist/tools/components.js +2 -2
- package/dist/tools/components.js.map +1 -1
- package/dist/tools/documents.d.ts +10 -1
- package/dist/tools/documents.js +16 -14
- package/dist/tools/documents.js.map +1 -1
- package/dist/tools/issues.d.ts +5 -0
- package/dist/tools/issues.js +11 -10
- package/dist/tools/issues.js.map +1 -1
- package/dist/tools/labels.d.ts +4 -0
- package/dist/tools/labels.js +4 -4
- package/dist/tools/labels.js.map +1 -1
- package/dist/tools/log-time.d.ts +1 -0
- package/dist/tools/log-time.js +1 -1
- package/dist/tools/log-time.js.map +1 -1
- package/dist/tools/members.d.ts +3 -1
- package/dist/tools/members.js +2 -2
- package/dist/tools/members.js.map +1 -1
- package/dist/tools/milestones.d.ts +2 -0
- package/dist/tools/milestones.js +2 -2
- package/dist/tools/milestones.js.map +1 -1
- package/dist/tools/organizations.d.ts +6 -1
- package/dist/tools/organizations.js +10 -9
- package/dist/tools/organizations.js.map +1 -1
- package/dist/tools/projects.d.ts +5 -1
- package/dist/tools/projects.js +4 -4
- package/dist/tools/projects.js.map +1 -1
- package/dist/tools/relations.d.ts +3 -0
- package/dist/tools/relations.js +3 -3
- package/dist/tools/relations.js.map +1 -1
- package/dist/tools/search.d.ts +1 -0
- package/dist/tools/search.js +1 -1
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/statuses.d.ts +4 -1
- package/dist/tools/statuses.js +3 -3
- package/dist/tools/statuses.js.map +1 -1
- package/dist/tools/workspaces.d.ts +6 -0
- package/dist/tools/workspaces.js +19 -0
- package/dist/tools/workspaces.js.map +1 -0
- package/package.json +4 -2
- package/scripts/cleanup-issues.js +15 -6
- package/scripts/demo.js +10 -2
- package/scripts/import-csv.js +13 -5
- package/scripts/setup.js +22 -20
package/README.md
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
# huly-mcp-
|
|
1
|
+
# huly-mcp-selfhost
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/huly-mcp-selfhost)
|
|
4
|
+
[](https://hub.docker.com/r/jokeks2023/huly-mcp)
|
|
5
|
+
[](https://hub.docker.com/r/jokeks2023/huly-mcp)
|
|
6
|
+
[](https://github.com/JoKeks2023/huly-mcp/actions/workflows/docker-publish.yml)
|
|
7
|
+
[](LICENSE)
|
|
2
8
|
|
|
3
9
|
> The most complete MCP server for [Huly](https://huly.app) — the open-source project management platform.
|
|
4
10
|
|
|
5
|
-
Connects **Claude Desktop** (and any [MCP](https://modelcontextprotocol.io)-compatible client) directly to your Huly
|
|
11
|
+
Connects **Claude Desktop** (and any [MCP](https://modelcontextprotocol.io)-compatible client) directly to your Huly workspaces — one account, as many workspaces as it can access. Manage projects, issues, milestones, components, documents, labels, chat, attachments, organizations, and more — all via natural language.
|
|
6
12
|
|
|
7
13
|
## About this fork
|
|
8
14
|
|
|
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.
|
|
15
|
+
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. Published separately as **[`huly-mcp-selfhost`](https://www.npmjs.com/package/huly-mcp-selfhost)** on npm and as a Docker image — `huly-mcp-sdk` on npm is the *original* upstream package, not this one. See [Installing this fork](#installing-this-fork) below.
|
|
10
16
|
|
|
11
17
|
**Fixed vs. upstream:**
|
|
12
18
|
- **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
19
|
- **`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
20
|
|
|
15
|
-
**
|
|
21
|
+
**Multi-workspace:** one login, all workspaces of the account — see [Workspaces](#workspaces-one-account-several-workspaces).
|
|
22
|
+
|
|
23
|
+
**New tool categories** (upstream had 33 tools across Projects/Issues/Comments/Time/Labels/Relations/Members/Milestones/Components/Documents/Search; this fork adds 15 more):
|
|
24
|
+
- **Workspaces** — `list_workspaces`
|
|
16
25
|
- **Chat** — `list_channels`, `create_channel`, `start_direct_message`, `send_message`, `list_messages`
|
|
17
26
|
- **Attachments** — `attach_file`, `list_attachments`, `delete_attachment` (generic files on issues, any content type)
|
|
18
27
|
- **Issue Statuses** — `list_issue_statuses`, `create_issue_status` (custom workflow states)
|
|
@@ -22,11 +31,14 @@ This is a fork of [varaprasadreddy9676/huly-mcp](https://github.com/varaprasadre
|
|
|
22
31
|
|
|
23
32
|
---
|
|
24
33
|
|
|
25
|
-
## Tools (
|
|
34
|
+
## Tools (48 total)
|
|
35
|
+
|
|
36
|
+
All tools except `list_workspaces` take a `workspace` argument — required for every change, optional for reads when only one workspace is available.
|
|
26
37
|
|
|
27
38
|
| Category | Tool | Description |
|
|
28
39
|
|----------|------|-------------|
|
|
29
|
-
| **
|
|
40
|
+
| **Workspaces** | `list_workspaces` | List the workspaces this account can access (name, slug, id) |
|
|
41
|
+
| **Projects** | `list_projects` | List all projects in a workspace |
|
|
30
42
|
| | `get_project` | Get project details + available statuses |
|
|
31
43
|
| | `create_project` | Create a new tracker project with a unique identifier |
|
|
32
44
|
| **Issues** | `list_issues` | List issues with optional status / priority filters |
|
|
@@ -58,7 +70,7 @@ This is a fork of [varaprasadreddy9676/huly-mcp](https://github.com/varaprasadre
|
|
|
58
70
|
| | `create_document` | Create a new document in a teamspace |
|
|
59
71
|
| | `update_document` | Write Markdown content to a document — Mermaid diagrams render natively |
|
|
60
72
|
| | `link_document` | Link a document to an issue — appears in the Relations panel |
|
|
61
|
-
| **Search** | `search_issues` | Full-text search across all issues |
|
|
73
|
+
| **Search** | `search_issues` | Full-text search across all issues of a workspace |
|
|
62
74
|
| **Chat** | `list_channels` | List all channels in the workspace |
|
|
63
75
|
| | `create_channel` | Create a new channel |
|
|
64
76
|
| | `start_direct_message` | Start (or find) a 1:1 direct message with a workspace member |
|
|
@@ -85,7 +97,18 @@ This is a fork of [varaprasadreddy9676/huly-mcp](https://github.com/varaprasadre
|
|
|
85
97
|
|
|
86
98
|
## Installing this fork
|
|
87
99
|
|
|
88
|
-
This fork
|
|
100
|
+
This fork is published separately as **[`huly-mcp-selfhost`](https://www.npmjs.com/package/huly-mcp-selfhost)** (`huly-mcp-sdk` is the upstream package). Three ways to run it:
|
|
101
|
+
|
|
102
|
+
### npm / npx
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
"command": "npx",
|
|
106
|
+
"args": ["-y", "huly-mcp-selfhost"]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Every client example below uses this form.
|
|
110
|
+
|
|
111
|
+
### Clone and build
|
|
89
112
|
|
|
90
113
|
```bash
|
|
91
114
|
git clone https://github.com/JoKeks2023/huly-mcp.git
|
|
@@ -94,28 +117,65 @@ npm install
|
|
|
94
117
|
npm run build
|
|
95
118
|
```
|
|
96
119
|
|
|
97
|
-
Then in any client config below, replace `"command": "npx", "args": ["huly-mcp-sdk"]` with:
|
|
98
|
-
|
|
99
120
|
```json
|
|
100
121
|
"command": "node",
|
|
101
122
|
"args": ["/absolute/path/to/huly-mcp/dist/index.js"]
|
|
102
123
|
```
|
|
103
124
|
|
|
104
|
-
|
|
125
|
+
### Docker (network-reachable server, not local stdio)
|
|
126
|
+
|
|
127
|
+
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`:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
docker pull jokeks2023/huly-mcp:latest
|
|
131
|
+
# also mirrored at ghcr.io/jokeks2023/huly-mcp:latest
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Or with Compose — copy `.env.example` to `.env`, fill in your credentials (no workspace needed), then:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
docker compose up -d
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
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).
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Workspaces (one account, several workspaces)
|
|
145
|
+
|
|
146
|
+
A single Huly account can belong to several workspaces — e.g. a personal one and a team one. This server logs in **once** with your account credentials and discovers every workspace that account can access via the account service (`getUserWorkspaces()`). You **don't configure a workspace** in the environment.
|
|
147
|
+
|
|
148
|
+
- **`list_workspaces`** returns name, slug and id of every available workspace.
|
|
149
|
+
- **Every other tool takes a `workspace` argument** — the slug, the name or the id (case-insensitive):
|
|
150
|
+
`list_projects(workspace="jokeks2023")`, `get_issue(workspace="avms", identifier="PROJ-1")`, `log_time(workspace="jokeks2023", identifier="WEB-12", hours=2)`.
|
|
151
|
+
- **Changes always require `workspace`.** Every tool that creates, updates, deletes, links, sends, attaches or logs something has `workspace` as a required argument — the server never falls back to an implicit, default or "last used" workspace for a write.
|
|
152
|
+
- **Reads may omit `workspace` only if exactly one workspace is available.** With several, the call fails and lists the options.
|
|
153
|
+
- **IDs are per workspace.** `PROJ-1`, a document id or a comment id identifies something only together with its workspace — the same id can exist in two workspaces. Pass the same `workspace` you got the id from.
|
|
154
|
+
- Each workspace gets its own lazily opened, cached WebSocket connection with its own workspace token (via `selectWorkspace()`), so workspaces never share state.
|
|
155
|
+
|
|
156
|
+
**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.
|
|
157
|
+
|
|
158
|
+
**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.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Configuration
|
|
163
|
+
|
|
164
|
+
| Variable | Required | Purpose |
|
|
165
|
+
|----------|----------|---------|
|
|
166
|
+
| `HULY_EMAIL` + `HULY_PASSWORD` | one auth option | Account login (needs a password set on your Huly account) |
|
|
167
|
+
| `HULY_TOKEN` | one auth option | Account token for SSO accounts (Google/GitHub) — get it with `npm run setup` |
|
|
168
|
+
| `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` |
|
|
169
|
+
| `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` |
|
|
170
|
+
| `HULY_WORKSPACE` | no (legacy) | Restrict the server to a single workspace |
|
|
105
171
|
|
|
106
172
|
---
|
|
107
173
|
|
|
108
174
|
## Compatible Clients
|
|
109
175
|
|
|
110
|
-
The same MCP server works across all major AI coding tools.
|
|
176
|
+
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"]`.
|
|
111
177
|
|
|
112
|
-
|
|
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.
|
|
178
|
+
**Self-hosted:** add `HULY_ACCOUNTS_URL` and `HULY_FRONT_URL` to every `env` block below.
|
|
119
179
|
|
|
120
180
|
---
|
|
121
181
|
|
|
@@ -129,10 +189,10 @@ The same MCP server works across all major AI coding tools. Pick your client, th
|
|
|
129
189
|
"mcpServers": {
|
|
130
190
|
"huly": {
|
|
131
191
|
"command": "npx",
|
|
132
|
-
"args": ["huly-mcp-
|
|
192
|
+
"args": ["-y", "huly-mcp-selfhost"],
|
|
133
193
|
"env": {
|
|
134
|
-
"
|
|
135
|
-
"
|
|
194
|
+
"HULY_EMAIL": "you@example.com",
|
|
195
|
+
"HULY_PASSWORD": "your-password"
|
|
136
196
|
}
|
|
137
197
|
}
|
|
138
198
|
}
|
|
@@ -146,43 +206,40 @@ Restart Claude Desktop after saving.
|
|
|
146
206
|
### Claude Code (CLI)
|
|
147
207
|
|
|
148
208
|
```bash
|
|
149
|
-
claude mcp add huly
|
|
209
|
+
claude mcp add huly \
|
|
210
|
+
-e HULY_EMAIL=you@example.com \
|
|
211
|
+
-e HULY_PASSWORD=your-password \
|
|
212
|
+
-- npx -y huly-mcp-selfhost
|
|
150
213
|
```
|
|
151
214
|
|
|
152
|
-
|
|
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`
|
|
215
|
+
Add `--scope project` (writes `.mcp.json`, shared with the repo — don't commit secrets) or `--scope user` (all your projects) after `add huly`. Verify with `claude mcp list`.
|
|
159
216
|
|
|
160
217
|
---
|
|
161
218
|
|
|
162
219
|
### Cursor
|
|
163
220
|
|
|
164
|
-
Create or edit `~/.cursor/mcp.json
|
|
221
|
+
Create or edit `~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project):
|
|
165
222
|
|
|
166
223
|
```json
|
|
167
224
|
{
|
|
168
225
|
"mcpServers": {
|
|
169
226
|
"huly": {
|
|
170
227
|
"command": "npx",
|
|
171
|
-
"args": ["huly-mcp-
|
|
228
|
+
"args": ["-y", "huly-mcp-selfhost"],
|
|
172
229
|
"env": {
|
|
173
|
-
"
|
|
174
|
-
"
|
|
230
|
+
"HULY_EMAIL": "you@example.com",
|
|
231
|
+
"HULY_PASSWORD": "your-password"
|
|
175
232
|
}
|
|
176
233
|
}
|
|
177
234
|
}
|
|
178
235
|
}
|
|
179
236
|
```
|
|
180
237
|
|
|
181
|
-
|
|
238
|
+
The tools appear in the Agent panel under MCP.
|
|
182
239
|
|
|
183
240
|
---
|
|
184
241
|
|
|
185
|
-
### Windsurf
|
|
242
|
+
### Windsurf
|
|
186
243
|
|
|
187
244
|
Create or edit `~/.codeium/windsurf/mcp_config.json`:
|
|
188
245
|
|
|
@@ -191,34 +248,35 @@ Create or edit `~/.codeium/windsurf/mcp_config.json`:
|
|
|
191
248
|
"mcpServers": {
|
|
192
249
|
"huly": {
|
|
193
250
|
"command": "npx",
|
|
194
|
-
"args": ["huly-mcp-
|
|
251
|
+
"args": ["-y", "huly-mcp-selfhost"],
|
|
195
252
|
"env": {
|
|
196
|
-
"
|
|
197
|
-
"
|
|
253
|
+
"HULY_EMAIL": "you@example.com",
|
|
254
|
+
"HULY_PASSWORD": "your-password"
|
|
198
255
|
}
|
|
199
256
|
}
|
|
200
257
|
}
|
|
201
258
|
}
|
|
202
259
|
```
|
|
203
260
|
|
|
204
|
-
|
|
261
|
+
Refresh the MCP servers in the Cascade panel.
|
|
205
262
|
|
|
206
263
|
---
|
|
207
264
|
|
|
208
|
-
### VS Code — Cline
|
|
265
|
+
### VS Code — Cline
|
|
209
266
|
|
|
210
|
-
|
|
211
|
-
2. Open Cline settings → **MCP Servers** → **Edit MCP Settings**
|
|
212
|
-
3. Add:
|
|
267
|
+
Cline → **MCP Servers** → **Installed** → **Configure MCP Servers** (opens `cline_mcp_settings.json`):
|
|
213
268
|
|
|
214
269
|
```json
|
|
215
270
|
{
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
"
|
|
221
|
-
|
|
271
|
+
"mcpServers": {
|
|
272
|
+
"huly": {
|
|
273
|
+
"command": "npx",
|
|
274
|
+
"args": ["-y", "huly-mcp-selfhost"],
|
|
275
|
+
"env": {
|
|
276
|
+
"HULY_EMAIL": "you@example.com",
|
|
277
|
+
"HULY_PASSWORD": "your-password"
|
|
278
|
+
},
|
|
279
|
+
"disabled": false
|
|
222
280
|
}
|
|
223
281
|
}
|
|
224
282
|
}
|
|
@@ -226,44 +284,36 @@ Restart Windsurf. MCP tools are available to the Cascade AI panel.
|
|
|
226
284
|
|
|
227
285
|
---
|
|
228
286
|
|
|
229
|
-
### VS Code — Continue
|
|
287
|
+
### VS Code / JetBrains — Continue
|
|
230
288
|
|
|
231
|
-
|
|
232
|
-
2. Edit `~/.continue/config.json` and add to the `mcpServers` array:
|
|
289
|
+
Add to `~/.continue/config.yaml` (MCP tools are available in Agent mode):
|
|
233
290
|
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
"HULY_TOKEN": "your-token",
|
|
243
|
-
"HULY_WORKSPACE": "your-workspace-slug"
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
]
|
|
247
|
-
}
|
|
291
|
+
```yaml
|
|
292
|
+
mcpServers:
|
|
293
|
+
- name: huly
|
|
294
|
+
command: npx
|
|
295
|
+
args: ["-y", "huly-mcp-selfhost"]
|
|
296
|
+
env:
|
|
297
|
+
HULY_EMAIL: you@example.com
|
|
298
|
+
HULY_PASSWORD: your-password
|
|
248
299
|
```
|
|
249
300
|
|
|
250
301
|
---
|
|
251
302
|
|
|
252
303
|
### Zed
|
|
253
304
|
|
|
254
|
-
|
|
305
|
+
Add to `~/.config/zed/settings.json`:
|
|
255
306
|
|
|
256
307
|
```json
|
|
257
308
|
{
|
|
258
309
|
"context_servers": {
|
|
259
310
|
"huly": {
|
|
260
|
-
"
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
311
|
+
"source": "custom",
|
|
312
|
+
"command": "npx",
|
|
313
|
+
"args": ["-y", "huly-mcp-selfhost"],
|
|
314
|
+
"env": {
|
|
315
|
+
"HULY_EMAIL": "you@example.com",
|
|
316
|
+
"HULY_PASSWORD": "your-password"
|
|
267
317
|
}
|
|
268
318
|
}
|
|
269
319
|
}
|
|
@@ -274,35 +324,27 @@ Edit `~/.config/zed/settings.json` and add a `context_servers` entry:
|
|
|
274
324
|
|
|
275
325
|
### OpenAI Codex CLI
|
|
276
326
|
|
|
277
|
-
|
|
327
|
+
Add to `~/.codex/config.toml`:
|
|
278
328
|
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
}
|
|
329
|
+
```toml
|
|
330
|
+
[mcp_servers.huly]
|
|
331
|
+
command = "npx"
|
|
332
|
+
args = ["-y", "huly-mcp-selfhost"]
|
|
333
|
+
env = { HULY_EMAIL = "you@example.com", HULY_PASSWORD = "your-password" }
|
|
293
334
|
```
|
|
294
335
|
|
|
336
|
+
or: `codex mcp add huly --env HULY_EMAIL=you@example.com --env HULY_PASSWORD=your-password -- npx -y huly-mcp-selfhost`
|
|
337
|
+
|
|
295
338
|
---
|
|
296
339
|
|
|
297
340
|
### Any other MCP-compatible client
|
|
298
341
|
|
|
299
|
-
The server uses standard **stdio transport
|
|
342
|
+
The server uses standard **stdio transport**:
|
|
300
343
|
|
|
301
|
-
- **command:** `node`
|
|
302
|
-
- **
|
|
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))
|
|
344
|
+
- **command:** `npx` with args `["-y", "huly-mcp-selfhost"]`, or `node` with `["/absolute/path/to/huly-mcp/dist/index.js"]`
|
|
345
|
+
- **env:** `HULY_EMAIL` + `HULY_PASSWORD` (or `HULY_TOKEN`); self-hosted also `HULY_ACCOUNTS_URL` + `HULY_FRONT_URL` — see [Configuration](#configuration)
|
|
304
346
|
|
|
305
|
-
|
|
347
|
+
For network access (HTTP/SSE) use the [Docker image](#docker-network-reachable-server-not-local-stdio).
|
|
306
348
|
|
|
307
349
|
---
|
|
308
350
|
|
|
@@ -310,6 +352,11 @@ Consult your tool's MCP documentation for the exact config file location.
|
|
|
310
352
|
|
|
311
353
|
## Example Prompts
|
|
312
354
|
|
|
355
|
+
**Workspaces:**
|
|
356
|
+
- *"Which Huly workspaces do I have?"*
|
|
357
|
+
- *"List the projects in my AVMS workspace"*
|
|
358
|
+
- *"In the jokeks2023 workspace, log 2 hours on WEB-12"*
|
|
359
|
+
|
|
313
360
|
**Projects & issues:**
|
|
314
361
|
- *"Create a new project called 'Mobile App' with identifier MOBILE"*
|
|
315
362
|
- *"List all in-progress issues in the PROJ project"*
|
|
@@ -352,12 +399,14 @@ Consult your tool's MCP documentation for the exact config file location.
|
|
|
352
399
|
|
|
353
400
|
```json
|
|
354
401
|
"env": {
|
|
355
|
-
"
|
|
356
|
-
"
|
|
402
|
+
"HULY_EMAIL": "...",
|
|
403
|
+
"HULY_PASSWORD": "...",
|
|
357
404
|
"HULY_FRONT_URL": "https://front.huly.app"
|
|
358
405
|
}
|
|
359
406
|
```
|
|
360
407
|
|
|
408
|
+
`HULY_FRONT_URL` only serves document/description content and file uploads — each request uses the token of the workspace named in the tool call. It plays no part in login or workspace discovery (that is `HULY_ACCOUNTS_URL`).
|
|
409
|
+
|
|
361
410
|
For **self-hosted** Huly, set `HULY_FRONT_URL` to your own front service URL (e.g. `http://localhost:8083`).
|
|
362
411
|
|
|
363
412
|
### Writing: `update_document`
|
|
@@ -413,9 +462,12 @@ The Mermaid block renders as a live interactive diagram in Huly's document edito
|
|
|
413
462
|
Import many issues at once from a CSV file — useful for migrating from other tools:
|
|
414
463
|
|
|
415
464
|
```bash
|
|
416
|
-
|
|
465
|
+
npm run build
|
|
466
|
+
node scripts/import-csv.js tasks.csv PROJ --workspace=myteam
|
|
417
467
|
```
|
|
418
468
|
|
|
469
|
+
The target workspace is required (`--workspace=<slug>`, or `HULY_WORKSPACE` as a fallback), since the script writes data. Credentials come from the environment as for the server.
|
|
470
|
+
|
|
419
471
|
**CSV format:**
|
|
420
472
|
|
|
421
473
|
```csv
|
|
@@ -429,9 +481,9 @@ Required column: `title`. Optional: `priority` (Urgent/High/Medium/Low), `status
|
|
|
429
481
|
|
|
430
482
|
---
|
|
431
483
|
|
|
432
|
-
##
|
|
484
|
+
## Authentication
|
|
433
485
|
|
|
434
|
-
Create a `.env` file in the project root (or pass via `env` in your client config)
|
|
486
|
+
Create a `.env` file in the project root (or pass via `env` in your client config). No workspace is needed in either option.
|
|
435
487
|
|
|
436
488
|
**Option A — Email + password (recommended):**
|
|
437
489
|
|
|
@@ -440,40 +492,72 @@ Works if you have a password set on your Huly account (Profile → Security →
|
|
|
440
492
|
```bash
|
|
441
493
|
HULY_EMAIL=your@email.com
|
|
442
494
|
HULY_PASSWORD=yourpassword
|
|
443
|
-
HULY_WORKSPACE=your-workspace-slug
|
|
444
495
|
```
|
|
445
496
|
|
|
446
|
-
**Option B — Token:**
|
|
497
|
+
**Option B — Token (SSO accounts: Google/GitHub):**
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
npm run setup
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
The wizard sends a one-time code to your email, saves the resulting account token as `HULY_TOKEN` in `.env`, and lists the workspaces the account can access (a discovery test).
|
|
447
504
|
|
|
448
505
|
```bash
|
|
449
|
-
HULY_WORKSPACE=your-workspace-slug
|
|
450
506
|
HULY_TOKEN=your-token-here
|
|
451
507
|
```
|
|
452
508
|
|
|
453
|
-
|
|
509
|
+
A token copied from the browser (DevTools → Application → Local Storage → `token`) also works, but may be scoped to the single workspace open in that tab. If the account service refuses to list workspaces for such a token, the server falls back to that one workspace. Use `npm run setup` for full multi-workspace discovery.
|
|
454
510
|
|
|
455
|
-
> Tokens expire after some time. If you get an auth error,
|
|
511
|
+
> Tokens expire after some time. If you get an auth error, run `npm run setup` again or switch to email + password.
|
|
456
512
|
|
|
457
513
|
**Self-hosted Huly:**
|
|
458
514
|
|
|
459
515
|
```bash
|
|
460
|
-
HULY_ACCOUNTS_URL=https://your-huly-instance.com/
|
|
461
|
-
HULY_FRONT_URL=https://your-huly-instance.com
|
|
516
|
+
HULY_ACCOUNTS_URL=https://your-huly-instance.com/_accounts # login + workspace discovery
|
|
517
|
+
HULY_FRONT_URL=https://your-huly-instance.com # document content + file uploads
|
|
462
518
|
```
|
|
463
519
|
|
|
464
520
|
---
|
|
465
521
|
|
|
466
522
|
## Architecture
|
|
467
523
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
524
|
+
```text
|
|
525
|
+
HULY_EMAIL + HULY_PASSWORD (or HULY_TOKEN)
|
|
526
|
+
↓
|
|
527
|
+
account login (once) account-level client: getUserWorkspaces(), selectWorkspace()
|
|
528
|
+
↓
|
|
529
|
+
getUserWorkspaces() → workspace discovery (cached)
|
|
530
|
+
↓
|
|
531
|
+
WorkspaceConnectionManager
|
|
532
|
+
├── workspace A: selectWorkspace(A) → endpoint + token → WebSocket (cached)
|
|
533
|
+
├── workspace B: selectWorkspace(B) → endpoint + token → WebSocket (cached)
|
|
534
|
+
└── … workspace-level client (workspace token): getWorkspaceMembers()
|
|
535
|
+
↓
|
|
536
|
+
MCP tools (each call names its workspace)
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
- **One login, many workspaces** — the account session is shared; each workspace gets its own long-lived connection via `@hcengineering/server-client` (model load takes 1–3 s, so connections are reused, not opened per call)
|
|
540
|
+
- **Lazy** — nothing connects until the first tool call, and a workspace connects only when first used, so auth errors surface clearly in the client
|
|
541
|
+
- **No current workspace** — there is no global or "last used" workspace; see [Workspaces](#workspaces-one-account-several-workspaces)
|
|
542
|
+
- **Stdio transport** — standard MCP transport; the Docker image adds HTTP/SSE via `mcp-proxy`
|
|
543
|
+
|
|
544
|
+
See [`src/connection.ts`](src/connection.ts).
|
|
472
545
|
|
|
473
546
|
---
|
|
474
547
|
|
|
475
548
|
## Changelog
|
|
476
549
|
|
|
550
|
+
### 2.0.0 — multi-workspace
|
|
551
|
+
|
|
552
|
+
Breaking: tools that change data require `workspace`; `HULY_WORKSPACE` only restricts the server to one workspace.
|
|
553
|
+
|
|
554
|
+
- **New: multi-workspace support** — one account login, workspaces discovered via `getUserWorkspaces()`, one cached connection per workspace; `HULY_WORKSPACE` is no longer required (still honoured as an optional single-workspace restriction)
|
|
555
|
+
- **New: `list_workspaces`**
|
|
556
|
+
- **Changed: every tool takes `workspace`** — required for all tools that change data; reads may omit it only when exactly one workspace is available
|
|
557
|
+
- **New: `huly-mcp-selfhost` bin alias** — `npx huly-mcp-selfhost` now starts the server directly
|
|
558
|
+
- **Changed: `npm run setup`** no longer asks for a workspace; it lists the discovered workspaces instead
|
|
559
|
+
- **Changed: `scripts/import-csv.js`, `cleanup-issues.js`, `demo.js`** need `--workspace=<slug>` (or `HULY_WORKSPACE`)
|
|
560
|
+
|
|
477
561
|
### Fork — self-hosted support, chat, attachments, statuses, organizations
|
|
478
562
|
- **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
563
|
- **New: `description` on `create_issue`/`update_issue`** — was missing entirely upstream
|
package/dist/connection.d.ts
CHANGED
|
@@ -1,9 +1,70 @@
|
|
|
1
1
|
import { type AccountClient } from '@hcengineering/account-client';
|
|
2
|
-
import { TxOperations } from '@hcengineering/core';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { TxOperations, type PersonId } from '@hcengineering/core';
|
|
3
|
+
export interface WorkspaceRef {
|
|
4
|
+
uuid: string;
|
|
5
|
+
/** Workspace slug, as in huly.app/<slug>. Passed to selectWorkspace(). */
|
|
6
|
+
url: string;
|
|
7
|
+
name: string;
|
|
8
|
+
mode?: string;
|
|
9
|
+
isDisabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface WorkspaceConnection {
|
|
12
|
+
workspace: WorkspaceRef;
|
|
13
|
+
client: TxOperations;
|
|
14
|
+
/** Workspace-scoped account client (token carries the workspace) — e.g. getWorkspaceMembers(). */
|
|
15
|
+
accountClient: AccountClient;
|
|
16
|
+
wsToken: string;
|
|
17
|
+
workspaceUuid: string;
|
|
18
|
+
}
|
|
19
|
+
interface OpenConnection {
|
|
20
|
+
client: TxOperations;
|
|
21
|
+
close: () => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export interface ConnectionManagerOptions {
|
|
24
|
+
accountsUrl: string;
|
|
25
|
+
email?: string;
|
|
26
|
+
password?: string;
|
|
27
|
+
token?: string;
|
|
28
|
+
/** Legacy HULY_WORKSPACE: restricts this server to that single workspace. */
|
|
29
|
+
restrictTo?: string;
|
|
30
|
+
createAccountClient?: (accountsUrl: string, token?: string) => AccountClient;
|
|
31
|
+
openConnection?: (endpoint: string, token: string, socialId: PersonId) => Promise<OpenConnection>;
|
|
32
|
+
}
|
|
33
|
+
export declare class WorkspaceConnectionManager {
|
|
34
|
+
private readonly opts;
|
|
35
|
+
private readonly createAccountClient;
|
|
36
|
+
private readonly openConnection;
|
|
37
|
+
private session;
|
|
38
|
+
private workspaces;
|
|
39
|
+
private generation;
|
|
40
|
+
private readonly connections;
|
|
41
|
+
constructor(opts: ConnectionManagerOptions);
|
|
42
|
+
/** All workspaces this account can use (after the optional legacy HULY_WORKSPACE restriction). */
|
|
43
|
+
listWorkspaces(): Promise<WorkspaceRef[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve user input (slug, name or UUID; case-insensitive) to a workspace.
|
|
46
|
+
* Without input, succeeds only if exactly one workspace is available.
|
|
47
|
+
*/
|
|
48
|
+
resolveWorkspace(input?: string): Promise<WorkspaceRef>;
|
|
49
|
+
/** Cached connection for the given workspace (see resolveWorkspace for the input rules). */
|
|
50
|
+
getWorkspace(input?: string): Promise<WorkspaceConnection>;
|
|
51
|
+
closeAll(): Promise<void>;
|
|
52
|
+
private match;
|
|
53
|
+
private getSession;
|
|
54
|
+
private login;
|
|
55
|
+
private discover;
|
|
56
|
+
private connect;
|
|
57
|
+
}
|
|
58
|
+
export declare function getConnectionManager(): WorkspaceConnectionManager;
|
|
59
|
+
/** Replace the process-wide manager (tests). */
|
|
60
|
+
export declare function setConnectionManager(next: WorkspaceConnectionManager | null): void;
|
|
61
|
+
export declare function listWorkspaces(): Promise<WorkspaceRef[]>;
|
|
62
|
+
export declare function getWorkspace(workspace?: string): Promise<WorkspaceConnection>;
|
|
63
|
+
export declare function getConnection(workspace?: string): Promise<TxOperations>;
|
|
64
|
+
export declare function getAccountClient(workspace?: string): Promise<AccountClient>;
|
|
65
|
+
export declare function getWorkspaceInfo(workspace?: string): Promise<{
|
|
6
66
|
wsToken: string;
|
|
7
67
|
workspaceUuid: string;
|
|
8
68
|
}>;
|
|
9
69
|
export declare function closeConnection(): Promise<void>;
|
|
70
|
+
export {};
|