huly-mcp-selfhost
v2.0.0
Published
MCP server for Huly (self-hosted + cloud) — connect Claude Desktop to your Huly workspace via the native WebSocket SDK. Fork of huly-mcp-sdk with self-hosted document/description support, chat, attachments, custom issue statuses, and organizations.
Maintainers
Readme
huly-mcp-selfhost
The most complete MCP server for Huly — the open-source project management platform.
Connects Claude Desktop (and any MCP-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.
About this fork
This is a fork of 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 on npm and as a Docker image — huly-mcp-sdk on npm is the original upstream package, not this one. See Installing this fork below.
Fixed vs. upstream:
- Self-hosted document/description writes. Upstream's
update_document(and, by extension, any issue description) is hardcoded against Huly Cloud's "datalake" microservice atdl-eu.huly.app, whichhuly-selfhostdoesn't run. This fork auto-detects self-hosted deployments viaHULY_FRONT_URLand uploads throughfront's own/filescontract instead — falls back to the original Cloud behavior whenHULY_FRONT_URLis unset. Seesrc/utils/storage.ts. descriptiononcreate_issue/update_issue. Missing entirely upstream — issue descriptions areMarkupBlobRefs, same storage mechanism as document content, so this needed the same fix.
Multi-workspace: one login, all workspaces of the account — see Workspaces.
New tool categories (upstream had 33 tools across Projects/Issues/Comments/Time/Labels/Relations/Members/Milestones/Components/Documents/Search; this fork adds 15 more):
- Workspaces —
list_workspaces - Chat —
list_channels,create_channel,start_direct_message,send_message,list_messages - Attachments —
attach_file,list_attachments,delete_attachment(generic files on issues, any content type) - Issue Statuses —
list_issue_statuses,create_issue_status(custom workflow states) - Organizations —
list_organizations,get_organization,create_organization,update_organization
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 — @hcengineering/* packages published 0.7.411+ ship without their types/ directory, and these modules have no earlier version to pin around it).
Tools (48 total)
All tools except list_workspaces take a workspace argument — required for every change, optional for reads when only one workspace is available.
| Category | Tool | Description |
|----------|------|-------------|
| Workspaces | list_workspaces | List the workspaces this account can access (name, slug, id) |
| Projects | list_projects | List all projects in a workspace |
| | get_project | Get project details + available statuses |
| | create_project | Create a new tracker project with a unique identifier |
| Issues | list_issues | List issues with optional status / priority filters |
| | get_issue | Get full details of an issue (e.g. PROJ-42) |
| | create_issue | Create a new issue (with optional Markdown description) |
| | update_issue | Update title, description, status, priority, assignee, due date, component, milestone |
| | delete_issue | Permanently delete an issue by identifier |
| Comments | add_comment | Add a comment to an issue |
| | list_comments | List all comments on an issue (includes IDs for delete_comment) |
| | delete_comment | Delete a specific comment by ID |
| Time Tracking | log_time | Log hours spent on an issue |
| Labels | list_labels | List all labels with color + usage count |
| | create_label | Create a new label with an optional hex color |
| | add_label | Add a label to an issue (auto-creates if it doesn't exist) |
| | remove_label | Remove a label from an issue |
| Relations | add_relation | Mark two issues as related (bidirectional) |
| | add_blocked_by | Mark an issue as blocked by another issue |
| | set_parent | Set or clear the parent epic of an issue |
| Members | list_members | List workspace members |
| Milestones | list_milestones | List milestones for a project |
| | create_milestone | Create a milestone with a target date and status |
| Components | list_components | List components (sub-areas) in a project |
| | create_component | Create a new component with optional lead |
| Documents | list_teamspaces | List document teamspaces |
| | create_teamspace | Create a new teamspace (top-level document folder) |
| | list_documents | List documents in a teamspace |
| | delete_document | Permanently delete a document by ID |
| | get_document | Get document metadata + content |
| | create_document | Create a new document in a teamspace |
| | update_document | Write Markdown content to a document — Mermaid diagrams render natively |
| | link_document | Link a document to an issue — appears in the Relations panel |
| Search | search_issues | Full-text search across all issues of a workspace |
| Chat | list_channels | List all channels in the workspace |
| | create_channel | Create a new channel |
| | start_direct_message | Start (or find) a 1:1 direct message with a workspace member |
| | send_message | Send a message to a channel or direct message |
| | list_messages | List messages in a channel or direct message |
| Attachments | attach_file | Attach a file to an issue (base64-encoded content) |
| | list_attachments | List files attached to an issue |
| | delete_attachment | Delete a file attachment from an issue |
| Issue Statuses | list_issue_statuses | List all issue statuses (workflow states), grouped by phase |
| | create_issue_status | Create a new issue status — available in every project immediately |
| Organizations | list_organizations | List all organizations (companies) in the workspace |
| | get_organization | Get details of an organization, including description |
| | create_organization | Create a new organization (company contact) |
| | update_organization | Set the description of an organization from Markdown |
Requirements
- Node.js >= 20
- A Huly account — huly.app (cloud) or self-hosted
Installing this fork
This fork is published separately as huly-mcp-selfhost (huly-mcp-sdk is the upstream package). Three ways to run it:
npm / npx
"command": "npx",
"args": ["-y", "huly-mcp-selfhost"]Every client example below uses this form.
Clone and build
git clone https://github.com/JoKeks2023/huly-mcp.git
cd huly-mcp
npm install
npm run build"command": "node",
"args": ["/absolute/path/to/huly-mcp/dist/index.js"]Docker (network-reachable server, not local stdio)
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:
docker pull jokeks2023/huly-mcp:latest
# also mirrored at ghcr.io/jokeks2023/huly-mcp:latestOr with Compose — copy .env.example to .env, fill in your credentials (no workspace needed), then:
docker compose up -dThe container wraps the server with 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 / docker-compose.yml.
Workspaces (one account, several workspaces)
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.
list_workspacesreturns name, slug and id of every available workspace.- Every other tool takes a
workspaceargument — the slug, the name or the id (case-insensitive):list_projects(workspace="jokeks2023"),get_issue(workspace="avms", identifier="PROJ-1"),log_time(workspace="jokeks2023", identifier="WEB-12", hours=2). - Changes always require
workspace. Every tool that creates, updates, deletes, links, sends, attaches or logs something hasworkspaceas a required argument — the server never falls back to an implicit, default or "last used" workspace for a write. - Reads may omit
workspaceonly if exactly one workspace is available. With several, the call fails and lists the options. - 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 sameworkspaceyou got the id from. - Each workspace gets its own lazily opened, cached WebSocket connection with its own workspace token (via
selectWorkspace()), so workspaces never share state.
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.
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.
Configuration
| Variable | Required | Purpose |
|----------|----------|---------|
| HULY_EMAIL + HULY_PASSWORD | one auth option | Account login (needs a password set on your Huly account) |
| HULY_TOKEN | one auth option | Account token for SSO accounts (Google/GitHub) — get it with npm run setup |
| 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 |
| 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 |
| HULY_WORKSPACE | no (legacy) | Restrict the server to a single workspace |
Compatible Clients
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). To run a local build instead, replace npx + args with node + ["/absolute/path/to/huly-mcp/dist/index.js"].
Self-hosted: add HULY_ACCOUNTS_URL and HULY_FRONT_URL to every env block below.
Claude Desktop
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"huly": {
"command": "npx",
"args": ["-y", "huly-mcp-selfhost"],
"env": {
"HULY_EMAIL": "[email protected]",
"HULY_PASSWORD": "your-password"
}
}
}
}Restart Claude Desktop after saving.
Claude Code (CLI)
claude mcp add huly \
-e [email protected] \
-e HULY_PASSWORD=your-password \
-- npx -y huly-mcp-selfhostAdd --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.
Cursor
Create or edit ~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{
"mcpServers": {
"huly": {
"command": "npx",
"args": ["-y", "huly-mcp-selfhost"],
"env": {
"HULY_EMAIL": "[email protected]",
"HULY_PASSWORD": "your-password"
}
}
}
}The tools appear in the Agent panel under MCP.
Windsurf
Create or edit ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"huly": {
"command": "npx",
"args": ["-y", "huly-mcp-selfhost"],
"env": {
"HULY_EMAIL": "[email protected]",
"HULY_PASSWORD": "your-password"
}
}
}
}Refresh the MCP servers in the Cascade panel.
VS Code — Cline
Cline → MCP Servers → Installed → Configure MCP Servers (opens cline_mcp_settings.json):
{
"mcpServers": {
"huly": {
"command": "npx",
"args": ["-y", "huly-mcp-selfhost"],
"env": {
"HULY_EMAIL": "[email protected]",
"HULY_PASSWORD": "your-password"
},
"disabled": false
}
}
}VS Code / JetBrains — Continue
Add to ~/.continue/config.yaml (MCP tools are available in Agent mode):
mcpServers:
- name: huly
command: npx
args: ["-y", "huly-mcp-selfhost"]
env:
HULY_EMAIL: [email protected]
HULY_PASSWORD: your-passwordZed
Add to ~/.config/zed/settings.json:
{
"context_servers": {
"huly": {
"source": "custom",
"command": "npx",
"args": ["-y", "huly-mcp-selfhost"],
"env": {
"HULY_EMAIL": "[email protected]",
"HULY_PASSWORD": "your-password"
}
}
}
}OpenAI Codex CLI
Add to ~/.codex/config.toml:
[mcp_servers.huly]
command = "npx"
args = ["-y", "huly-mcp-selfhost"]
env = { HULY_EMAIL = "[email protected]", HULY_PASSWORD = "your-password" }or: codex mcp add huly --env [email protected] --env HULY_PASSWORD=your-password -- npx -y huly-mcp-selfhost
Any other MCP-compatible client
The server uses standard stdio transport:
- command:
npxwith args["-y", "huly-mcp-selfhost"], ornodewith["/absolute/path/to/huly-mcp/dist/index.js"] - env:
HULY_EMAIL+HULY_PASSWORD(orHULY_TOKEN); self-hosted alsoHULY_ACCOUNTS_URL+HULY_FRONT_URL— see Configuration
For network access (HTTP/SSE) use the Docker image.
Example Prompts
Workspaces:
- "Which Huly workspaces do I have?"
- "List the projects in my AVMS workspace"
- "In the jokeks2023 workspace, log 2 hours on WEB-12"
Projects & issues:
- "Create a new project called 'Mobile App' with identifier MOBILE"
- "List all in-progress issues in the PROJ project"
- "Create a high-priority issue in PROJ titled 'Fix login timeout'"
- "Update PROJ-42 status to Done, assign it to Sarah, and move it to the Auth component"
- "Search for issues related to authentication"
- "Add a comment to PROJ-15 saying the fix is deployed"
- "List all comments on PROJ-42 to see the discussion"
Milestones & components:
- "Create a milestone 'v2.0 Launch' in PROJ with target date 2026-06-01"
- "List milestones for the PROJ project"
- "Create a component called 'Auth' in PROJ"
- "List all components in PROJ"
Labels & relations:
- "Add the label 'bug' to PROJ-42"
- "Create a label called 'backend' with color #3b82f6"
- "Mark PROJ-55 as blocked by PROJ-12"
- "Set PROJ-42 as a subtask of PROJ-5"
Time tracking:
- "Log 2.5 hours on PROJ-42 for the database refactor"
Documents:
- "List all documents in the Engineering teamspace"
- "Create a document called 'API Design' in the Engineering teamspace"
- "Update the API Design document with this Markdown: ..."
- "Add a Mermaid architecture diagram to the EP1 document"
- "Link document abc123 to issue PROJ-42"
- "Delete the second comment on PROJ-15"
Document Content
Reading: get_document
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:
"env": {
"HULY_EMAIL": "...",
"HULY_PASSWORD": "...",
"HULY_FRONT_URL": "https://front.huly.app"
}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).
For self-hosted Huly, set HULY_FRONT_URL to your own front service URL (e.g. http://localhost:8083).
Writing: update_document
update_document accepts a documentId and a markdown string and writes rich structured content directly to the document — no manual editing required.
Self-hosted note: Document content (and, as of this fork, issue descriptions — see below) is stored as a
MarkupBlobRefblob. Huly Cloud uploads these through a dedicated "datalake" microservice at a fixed URL;huly-selfhost(v0.7.x) does not run that service — blob storage goes throughfront's own, older/filesendpoint instead. IfHULY_FRONT_URLis set, this fork uploads through that self-hosted contract automatically; if it's unset, it falls back to Huly Cloud's datalake (the original, upstream behavior). No separate flag needed —HULY_FRONT_URLdoubles as the self-host/cloud switch for both reading and writing.
Supported Markdown:
| Element | Syntax |
|---------|--------|
| Headings | #, ##, ### |
| Bold / inline code | **bold**, `code` |
| Paragraphs | plain text |
| Bullet lists | - item |
| Pipe tables | \| col \| col \| |
| Code blocks | ```lang |
| Mermaid diagrams | ```mermaid — stored as Huly's native mermaid node type so diagrams render as interactive visuals in the editor |
Example:
update_document({
documentId: "abc123",
markdown: `# Service Flow\n\n` +
`## Architecture\n\n` +
"```mermaid\n" +
"flowchart TD\n" +
" A([User]) --> B[Browse Catalogue]\n" +
" B --> C[Pay via Razorpay]\n" +
" C --> D[Order Confirmed]\n" +
"```\n\n" +
"## Business Rules\n\n" +
"- Payment required before confirmation\n" +
"- All orders synced to HIS\n"
})The Mermaid block renders as a live interactive diagram in Huly's document editor — not as a code block.
Bulk CSV Import
Import many issues at once from a CSV file — useful for migrating from other tools:
npm run build
node scripts/import-csv.js tasks.csv PROJ --workspace=myteamThe 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.
CSV format:
title,priority,status,dueDate
Fix login bug,High,In Progress,2025-04-01
Add dark mode,Medium,,
Improve performance,Urgent,,2025-05-01Required column: title. Optional: priority (Urgent/High/Medium/Low), status (must match a status name in the project), dueDate (YYYY-MM-DD).
Authentication
Create a .env file in the project root (or pass via env in your client config). No workspace is needed in either option.
Option A — Email + password (recommended):
Works if you have a password set on your Huly account (Profile → Security → Change password).
[email protected]
HULY_PASSWORD=yourpasswordOption B — Token (SSO accounts: Google/GitHub):
npm run setupThe 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).
HULY_TOKEN=your-token-hereA 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.
Tokens expire after some time. If you get an auth error, run
npm run setupagain or switch to email + password.
Self-hosted Huly:
HULY_ACCOUNTS_URL=https://your-huly-instance.com/_accounts # login + workspace discovery
HULY_FRONT_URL=https://your-huly-instance.com # document content + file uploadsArchitecture
HULY_EMAIL + HULY_PASSWORD (or HULY_TOKEN)
↓
account login (once) account-level client: getUserWorkspaces(), selectWorkspace()
↓
getUserWorkspaces() → workspace discovery (cached)
↓
WorkspaceConnectionManager
├── workspace A: selectWorkspace(A) → endpoint + token → WebSocket (cached)
├── workspace B: selectWorkspace(B) → endpoint + token → WebSocket (cached)
└── … workspace-level client (workspace token): getWorkspaceMembers()
↓
MCP tools (each call names its workspace)- 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) - Lazy — nothing connects until the first tool call, and a workspace connects only when first used, so auth errors surface clearly in the client
- No current workspace — there is no global or "last used" workspace; see Workspaces
- Stdio transport — standard MCP transport; the Docker image adds HTTP/SSE via
mcp-proxy
See src/connection.ts.
Changelog
2.0.0 — multi-workspace
Breaking: tools that change data require workspace; HULY_WORKSPACE only restricts the server to one workspace.
- New: multi-workspace support — one account login, workspaces discovered via
getUserWorkspaces(), one cached connection per workspace;HULY_WORKSPACEis no longer required (still honoured as an optional single-workspace restriction) - New:
list_workspaces - Changed: every tool takes
workspace— required for all tools that change data; reads may omit it only when exactly one workspace is available - New:
huly-mcp-selfhostbin alias —npx huly-mcp-selfhostnow starts the server directly - Changed:
npm run setupno longer asks for a workspace; it lists the discovered workspaces instead - Changed:
scripts/import-csv.js,cleanup-issues.js,demo.jsneed--workspace=<slug>(orHULY_WORKSPACE)
Fork — self-hosted support, chat, attachments, statuses, organizations
- Fix: self-hosted document/description writes — auto-detects
huly-selfhostviaHULY_FRONT_URLand uploads throughfront's/filescontract instead of Huly Cloud's datalake, which self-hosted doesn't run - New:
descriptiononcreate_issue/update_issue— was missing entirely upstream - New: Chat —
list_channels,create_channel,start_direct_message,send_message,list_messages - New: Attachments —
attach_file,list_attachments,delete_attachment - New: Issue Statuses —
list_issue_statuses,create_issue_status - New: Organizations —
list_organizations,get_organization,create_organization,update_organization - See About this fork for details and what was investigated but not built
v0.5.6 — delete_document
- New:
delete_document— permanently delete a document by ID
v0.5.5 — create_teamspace
- New:
create_teamspace— create a new document teamspace (top-level folder for organising documents by project or team)
v0.5.2 — delete_comment + link_document
- New:
delete_comment— delete a specific comment from an issue by ID;list_commentsnow includes comment IDs in its output - New:
link_document— link a Huly document to an issue; the document appears in the Relations panel on the issue
v0.5.0 — Document Writing + Bug Fixes
- New:
update_document— write Markdown to any Huly document programmatically;\``mermaid` blocks use Huly's native node type and render as interactive diagrams - Fix:
IssueStatusqueries — statuses are stored globally in Huly (core:space:Model), not per-project; removed incorrect space filter that caused "no statuses found" errors oncreate_issue,update_issue, andlist_issues - Fix:
create_project— setsmembers: [currentUser]so newly created projects are immediately visible in the Huly UI
v0.4.0
log_time,list_comments, component/milestone assignment onupdate_issue
v0.3.1
get_document,create_document
v0.3.0
create_project,create_milestone, assignee support on issues
Links
- This fork: https://github.com/JoKeks2023/huly-mcp
- Upstream: https://github.com/varaprasadreddy9676/huly-mcp (npm, MCP Registry — neither reflects this fork's changes)
- Missing
.d.tsin@hcengineering/*0.7.411+: https://github.com/hcengineering/platform/issues/10881
