Skip to main content
Glama

huly-mcp-selfhost

npm CI Docker Pulls MCP Registry License: EPL-2.0

Huly for AI agents. An MCP server for Huly — self-hosted or Huly Cloud — that lets Claude and other agents work in your workspaces: issues, epics, milestones, documents, chat, inbox, planner, test management and more. 227 tools, built for agent workflows and to spend as few tokens as possible.

Website · Quick start · Tools · Claude Code plugin · Changelog

Highlights

  • Everything in Huly: tracker, documents, chat, inbox, activity, planner, calendar, GitHub PRs, contacts, drive, cards, templates, test management, recruiting, CRM, HR and more — plus read access to any Huly class.

  • Made for agents: one-call overviews (my_day, standup, project_report, get_issue_context), start_work → finish_work, plans → epics with sub-issues, specs and meeting notes → issues, claims for parallel agents, and huly-mcp watch to hand issues to Claude from Huly.

  • Few tokens: tools come in toolsets (default ≈11k tokens, everything ≈24k), optionally loaded on demand; pin a workspace for −10 %; compact outputs; wrong parameters are rejected with the valid list instead of silently ignored.

  • Safe by default: every change names its workspace, risky tools ask first, writes can be limited to projects, optional audit log — and undo_changes reverses your last changes.

  • Small and quick to install: one self-contained package of ~4 MB (900 kB download) — no 180 dependencies to fetch on the first npx.

  • No telemetry. The server talks to your Huly server and nothing else: no analytics, no usage tracking, nothing to opt out of. (The only other request, the npm version check, runs when you call check_setup.)

  • Claude Code plugin: /huly:setup asks once per repo how Huly is used there and writes the rules; skill, hooks and /huly:* commands. Guides and a setup prompt for every other MCP client too.

  • Self-hosted first: document and description content, file uploads and internal URLs work on huly-selfhost; one account, all its workspaces.

Related MCP server: huly-mcp

Tokens, measured

What the model reads — measured on a real self-hosted project (≈60 issues):

Characters

≈ Tokens

Tool list, default toolsets (99 tools, each callable directly)

38,259

10.9k

Tool list, pinned workspace

34,567

9.9k

Open issues of a project (one call, ≈30 issues)

2,768

0.8k

One issue with description

318

0.1k

Project report (done, in progress, blocked, milestones, PRs, time)

~2,700

0.8k

My day (calendar, to-dos, my issues, PRs, inbox)

~1,200

0.3k

Lists default to open items, empty fields are left out, and one call answers what would otherwise take four or five. Per call and question: costs.md.

Same self-hosted Huly, same questions, the best parameters on both sides, measured 2026-11-11. For the other server only the text content is counted, not the duplicate JSON copy it also returns. Where we return more (components), it is because we include each component's description and code paths.

Question

huly-mcp-selfhost

Other server

Ratio

Open issues of a project

2,768 (1 call)

11,601 (3 calls)

4.2× less

Issues in progress

211 (1 call)

790 (1 call)

3.7× less

One issue

318 (1 call)

585 (1 call)

1.8× less

Everything about an issue (fields, sub-issues, comments, relations)

1,246 (1 call)

3,585 (4 calls)

2.9× less

Search

406 (1 call)

1,405 (1 call)

3.5× less

Projects

550 (1 call)

1,041 (1 call)

1.9× less

Milestones

208 (1 call)

503 (1 call)

2.4× less

Components

1,302 (1 call)

692 (1 call)

2.0× more

Documents of a teamspace

106 (1 call)

305 (1 call)

2.9× less

Tool definitions (49 tools with the same name)

15,728

216,890

13.8× less

Quick start

You need Node.js 20+ and a Huly account — Huly Cloud or self-hosted.

Claude Code — install the plugin, then fill in its settings when asked:

/plugin marketplace add JoKeks2023/huly-mcp
/plugin install huly@huly-mcp

Then run /huly:setup in a repository. Details: Claude Code plugin.

Claude Desktop, Cursor, VS Code, Windsurf, Zed, … — add the server to your client's MCP config:

{
  "mcpServers": {
    "huly": {
      "command": "npx",
      "args": ["-y", "huly-mcp-selfhost"],
      "env": {
        "HULY_EMAIL": "you@example.com",
        "HULY_PASSWORD": "your-password"
      }
    }
  }
}
  • Self-hosted Huly: add "HULY_ACCOUNTS_URL": "https://huly.example.com/_accounts" and "HULY_FRONT_URL": "https://huly.example.com".

  • Google/GitHub login (no password): run npx huly-mcp-selfhost setup and use HULY_TOKEN instead — see Authentication.

  • One workspace? Add "HULY_WORKSPACE": "<slug>" — fewer tokens.

Config file locations and examples for each client: Compatible clients.

Server for a team or remote clients — huly-mcp-selfhost http or the Docker image; everyone logs in with their own Huly account in the browser (OAuth): see Team server over HTTP.

Then ask: "What's on my plate today?", "Plan the login redesign as an epic in WEB", "Write release notes for v1.2". More in Example prompts.


Claude Code plugin

The repo is also a Claude Code plugin marketplace. The plugin bundles the MCP server with a workflow skill, hooks and commands:

/plugin marketplace add JoKeks2023/huly-mcp
/plugin install huly@huly-mcp

Note: the plugin starts the npm package at exactly its own version (e.g. huly-mcp-selfhost@3.5.1; the plugin directory does not accept version ranges), so a plugin update brings the matching server. To try a local checkout instead: npm run build, then point plugin/.mcp.json at dist/index.js and start claude --plugin-dir ./plugin.

Claude Code then asks for your Huly settings (e-mail + password or token, and for self-hosted Huly the accounts and front URL; passwords and tokens go to the OS keychain).

Part

What it does

MCP server

huly-mcp-selfhost via npx, configured from the plugin settings (toolsets, on-demand loading, pinned workspace and writable projects included); tool annotations on (HULY_ANNOTATIONS=1)

Skill huly

How to use Huly while coding at the lowest token cost: the repo's ## Huly rules first, find the project for the repo, pick up/hand back issues, status flow, duplicate check, component + milestone, epics for plans, cheapest call per question. Reference files are read only when needed: costs.md (measured output size per call), onboarding.md (bringing a project into Huly) and features.md (all of Huly for a software project — labels, templates, test management incl. CI import, documents, drive, custom fields, cards — with the toolsets each needs)

Hook on session start

Reports the GitHub repo and branch; a branch like proj-12-login points Claude to issue PROJ-12; points to the repo's ## Huly rules or offers /huly:setup (no network, no credentials)

Hook after gh pr create / gh pr merge

Reminds Claude to link the new PR to its issue (finish_work) or to check the status after a merge

/huly:setup [workspace]

Set up Huly for this repo: asks how Huly is used here (role, where new issues go, initiative, how token-saving), writes the answers as a ## Huly section to CLAUDE.md, CLAUDE.local.md (only you) or split between both, then optionally imports the project (status set, components, milestones, TODO/FIXME proposals, architecture document). The session-start hook offers it once while a repo has no such section

/huly:start [PROJ-12]

Pick up an issue (from the argument or the branch), load the context, plan

/huly:finish [PROJ-12] [PR]

Honest summary, PR link, status to review

/huly:plan <goal>

Plan → epic + sub-issues (dry run first)

/huly:day, /huly:standup [since], /huly:triage

My day, stand-up, inbox triage — one call each (my_day, standup, triage_inbox)

/huly:report <PROJECT> [7d]

Project status: progress, milestones, blockers (project_report)

Without the plugin, the same server works in Claude Code as a plain MCP server (see below); the MCP prompts (setup, start, finish, plan, triage, standup) and guide resources are available there too.


Command line

Every tool also works from the terminal — for scripts, CI and quick looks without a chat. Same login (HULY_* environment or --env-file), same safety rules (write scope, audit log, confirmation for hard-to-undo changes).

npm install -g huly-mcp-selfhost          # or: npx huly-mcp-selfhost <command>

huly-mcp tools issue                      # find tools
huly-mcp help list_issues                 # parameters, types, allowed values, defaults
huly-mcp get_issue PROJ-12                # one required parameter can be given directly
huly-mcp list_issues --project PROJ --due overdue --assignee null
huly-mcp create_issue -w acme --project PROJ --title "Fix login" --description-file notes.md
huly-mcp bulk_update_issues --identifiers PROJ-1 --identifiers PROJ-2 --status-name Done --yes
huly-mcp my_day --format json | jq -r .text
  • Parameters come from the same schemas the MCP server sends to Claude, so help is always current. Names work as --project-identifier or --projectIdentifier; common short forms (--project, --status, --milestone, …) too. Values are read by type: numbers, true/false, null to clear, repeat a flag for lists, JSON for nested values. --json '{…}' or --input file.json (- = stdin) pass everything at once; --<text-param>-file reads a text value from a file.

  • Hard-to-undo tools (deletes, bulk changes, moves) ask in a terminal; in scripts they run only with --yes.

  • Exit codes: 0 ok · 1 the tool failed or was cancelled · 2 wrong usage (unknown tool or option — with a "did you mean …").

  • Output: the tool's Markdown; --format json gives {"ok", "tool", "text"} (errors too). The Huly SDK's own logging is silenced; HULY_DEBUG=1 shows it on stderr.

  • Shell completion for tools, options and allowed values: eval "$(huly-mcp completion zsh)" (or bash) in your shell profile.


Tools (227 total, grouped in toolsets)

All tools except list_workspaces take a workspace argument — required for every change, optional for reads when only one workspace is available.

Toolsets

Every tool schema is sent to the model in each session (Claude Desktop loads all of them up front), so tools are grouped and only the default toolsets are enabled unless you choose otherwise:

HULY_TOOLSETS=all                       # everything
HULY_TOOLSETS=tracker,documents,planner # just these ('core' = list_workspaces, check_setup and undo_changes, always on)

Load on demand (HULY_DYNAMIC_TOOLSETS=1): HULY_TOOLSETS becomes the starting set, and Claude loads more toolsets itself via enable_toolsets. Called without arguments, it lists every toolset with its tools; called with names, it loads them and tells the client that the tool list changed. With HULY_TOOLSETS=agent,inbox a session starts at ≈1.8k tokens instead of ≈9–11k. This needs a client that reloads the tool list on notifications/tools/list_changed: it is tested with the MCP SDK client, but not yet verified in Claude Desktop. Without the variable, nothing changes.

Toolset

Default

Tools

Contents

agent

✓

14

agent workflow: my day at a glance, standup, project report, release notes, issue context in one call, start/finish work, plan → issue tree, spec document → issues, meeting notes → issues, changes since, claims, repo → project — plus resources and prompts

tracker

✓

37

projects, issues, comments, time, labels, relations, milestones, components, statuses, attachments, search

documents

✓

8

teamspaces and documents (tree, move, rename)

chat

✓

12

channels, DMs, threads, edit/delete, reactions, pins

contacts

✓

11

members, organizations, persons, contact channels

inbox

✓

4

notifications, triage (what changed since last read), mark read/archive; pin, hide, mark unread, follow/unfollow per object

activity

✓

1

change history of an issue/object

planner

✓

5

to-dos, time blocking

generic

✓

4

fulltext search across everything, read any Huly class

tracker-admin

12

rarely needed admin: create/update project, create status, update/delete label, label categories, delete milestone/component, repair parent links, project types and workflows

calendar

4

calendar events

github

2

pull requests synced by Huly's GitHub integration (read-only)

generic-write

3

create/update/delete any class — dry run by default, deletes need confirm

collaboration

8

followers (collaborators) of issues/documents, public guest links, document comments

cards

8

cards: types and tags, create/edit/move/delete, nesting, field values

fields

3

custom fields on issues, project types, card types or any class; set values

drive

10

drives, folders, versioned files: upload, download, move, restore versions

templates

11

issue templates with sub-issues, new issue from template; message templates

testing

23

test management: projects, suites, cases, plans, runs, results; JUnit import, report, bugs from failed tests

products

2

products and versions (read-only)

members

4

workspace settings, invite links and e-mails, member roles

recruiting

9

vacancies, candidates, applications

crm

5

leads, customers

hr

7

departments, staff, vacation/sick/remote days

inventory

5

categories, products, variants (SKU)

meetings

2

office rooms, meeting minutes and transcripts (read-only)

qms

4

controlled documents and trainings (read-only)

process

4

process definitions and executions; start and cancel

surveys

2

surveys and aggregated poll answers (read-only)

Context cost of tools/list (≈3.5 chars/token):

default (99 tools)

all (227 tools)

several workspaces

~38.3k chars ≈ 10.9k tokens

~83.5k chars ≈ 23.9k tokens

pinned with HULY_WORKSPACE

~34.6k chars ≈ 9.9k tokens

~75.0k chars ≈ 21.4k tokens

For comparison, 2.2.0 needed ≈12.8k tokens for 64 tools. Using one workspace? Set HULY_WORKSPACE — the workspace argument then disappears from every tool (−10%). Claude Code loads MCP tools on demand, so there even HULY_TOOLSETS=all costs little up front.

Agent workflow

Tools, resources and prompts for AI agents working on Huly issues (toolset agent):

Tool

What it does

my_day

Today (or date) in one call: own calendar events and work slots, open to-dos (overdue and due first), open issues assigned to me (in progress first), PRs waiting for my review and my own open PRs, unread inbox grouped by object. Times in UTC

standup

What I did since the last working day (Monday → Friday, or since): status changes, new issues, comments, time, finished to-dos; then today (calendar, to-dos, my issues) and my issues blocked by open ones

release_notes

Release notes from a milestone: done issues as "New and changed" and "Fixes" (by title or label, English and German), merged PR numbers, epics left out; open issues listed separately

project_report

Weekly (or since: 14d, ISO date) report of a project: done in the period (status changed to done — not just touched by sync), new, in progress (flagged when untouched), blocked by open issues, overdue, PRs merged and open, open milestones with progress and target, time logged per person. To keep it in Huly, pass the text to create_document + update_document

get_issue_context

Everything about an issue in one call: fields, description, parent chain, sub-issues, blocked by / blocks, related, PRs, comments, suggested branch name

start_work

Status → In Progress, assign to me, optionally claim — returns the full context

finish_work

Work summary as comment, PR (#12, URL or Huly id) linked as sub-issue, status → Review in progress, claim released. Validates the PR before changing anything

create_issue_tree

Plan → epic + sub-issues with priorities, components, milestones, assignees, labels and blockers ("#2" = second child). Same-title issues are reused, dry run by default

issues_from_document

Spec → issues: the open checklist items of a Huly document (without a checklist: its sections) become sub-issues of an epic, checked items are skipped, the document is linked to the epic. Dry run by default; one call instead of reading the document and repeating every task

issues_from_meeting

Meeting notes → issues: open checkboxes, lines starting with TODO:/Action:/Aufgabe: and list items under a heading like "Action items" or "Next steps" become issues. @Name (or a Huly mention) becomes the assignee, a date (2026-11-10, 10.11.2026, "due …"/"bis …") the due date. Unknown people are flagged and left unassigned; same-title issues are skipped; each new issue is linked to the document. Dry run by default

changes_since

Issues/PRs changed since 24h, 7d or an ISO time — which fields changed, new comments, by whom

find_project_for_repo

Workspace + project linked to a GitHub repo (owner/name, URL or git remote) via Huly's GitHub integration

claim_issue / release_issue

Lease an issue to an agent (label agent:working + comment marker) so parallel agents skip it; expires after minutes

Resources — huly://<workspace>/issue/<PROJ-12> and huly://<workspace>/document/<id>. Your open assigned issues are listed, so in Claude Code you can @-mention them. Guides for agents in any client: huly://guide/workflow (how to work with Huly), huly://guide/costs (cheapest call per question) and huly://guide/onboarding (bringing a project into Huly) and huly://guide/features (which Huly feature to use for what, and which toolset it needs) — the same text as the plugin skill.

Prompts — setup (ask how Huly is used for a project and write the rules for your project instructions), start, finish, plan, triage, standup (in Claude Code: /mcp__huly__start …).

Guard rails (environment):

Variable

Effect

HULY_WRITE_PROJECTS=TSK,WEB

Changes are only allowed when every project they touch (project keys and PROJ-12 ids in the arguments) is listed. Reads are never blocked. Tools without a project (chat, documents, planner) are not affected

HULY_AUDIT_LOG=/path/audit.jsonl

Every change is appended as one JSON line (time, tool, shortened arguments, success, first line of the result)

HULY_AGENT_NAME=claude-2

Default agent name for claims

HULY_CONFIRM=auto

Deletes and other hard-to-undo tools (delete_*, bulk_update_issues, move_issue, generic_update/generic_delete, revoke_public_link, restore_file_version) ask you first via MCP elicitation when the client can show a form (Claude Code in an interactive session). auto (default): ask when possible, otherwise run as before. strict: refuse when the client cannot ask (unattended agents). off: never ask. Dry runs never ask

Huly hands work to Claude: huly-mcp watch

huly-mcp watch turns Huly into the place where you give Claude work. It polls for open issues that carry a label (--label claude) or are assigned to the account it runs as (--assigned, the default), and for each one:

  1. claims the issue (claim_issue), so a second watcher or agent skips it,

  2. runs a command for it — by default claude -p in the current directory, with this MCP server attached and a prompt that says: read the issue, do the work, hand back with finish_work,

  3. releases the claim if the run did not (finish_work releases it), and comments on the issue if the run failed or timed out.

cd ~/code/my-repo
npx huly-mcp-selfhost watch --workspace acme --project WEB --label claude --dry-run   # what would run
npx huly-mcp-selfhost watch --workspace acme --project WEB --label claude             # poll every 60 s
  • Each issue runs once. A state file (~/.huly-mcp/watch-<workspace>.json) remembers it. To run it again, remove the label and add it again.

  • The command is yours. --command takes any program; the placeholders {prompt} {issue} {title} {workspace} {agent} {trigger} {mcpConfig} are filled in per argument — no shell is involved, so issue titles cannot inject shell commands. The run also gets HULY_ISSUE, HULY_ISSUE_TITLE and HULY_WORKSPACE in its environment. Examples: a GitHub Action (--command "gh workflow run agent.yml -f issue={issue}"), or Claude with more tools (--command "claude -p {prompt} --mcp-config {mcpConfig} --allowedTools mcp__huly,Bash(npm test),Edit").

  • Default command: claude -p {prompt} --mcp-config {mcpConfig} --strict-mcp-config --allowedTools mcp__huly --permission-mode acceptEdits. {mcpConfig} is a temporary MCP config that starts this server limited to the watched workspace; the credentials are passed through the environment, not written to the file.

  • Unattended means careful. Runs get HULY_CONFIRM=strict unless you set it: deletes and other risky tools are refused, because nobody is there to confirm them. HULY_WRITE_PROJECTS limits which projects are watched and changed. Issue text reaches the agent as instructions — only watch projects whose writers you trust.

  • Its own identity. Give the agent its own Huly account (invite e.g. claude@your-domain to the workspace) and start the watcher with that account's credentials (--env-file agent.env with HULY_EMAIL/HULY_PASSWORD or HULY_TOKEN). Then you hand work to Claude by assigning an issue to that user, and every comment, status change and claim shows up under its name instead of yours. --agent <name> (or HULY_AGENT_NAME) names it in claims.

  • Other options: --interval <sec>, --timeout <min> (default 60), --once, --cwd <dir>, --prompt <template>, --state <file>. huly-mcp watch --help lists them all.

CI test results into Huly: huly-mcp junit

huly-mcp junit report.xml --project "App" imports a JUnit XML report as a test run in Huly's test management. Almost every test runner writes JUnit XML (Jest/Vitest with a JUnit reporter, pytest --junitxml, go-junit-report, Gradle, Maven Surefire, xcpretty). Suites and cases that do not exist yet are created; failed tests keep their message and stack trace. Then ask Claude "What is flaky in App?" (get_test_report) or "File bugs for today's failures in PROJ" (create_issue_from_test_result).

# .github/workflows/test.yml (after the test step)
- name: Report to Huly
  if: always()
  run: npx -y huly-mcp-selfhost junit reports/junit.xml --project "App" --run "CI ${{ github.ref_name }} #${{ github.run_number }}"
  env:
    HULY_URL: ${{ secrets.HULY_URL }}
    HULY_TOKEN: ${{ secrets.HULY_TOKEN }}
    HULY_WORKSPACE: my-workspace

Options: --run <name>, --parent-suite <suite>, --no-create (only existing cases), --fail-on-failures (exit code 1 when tests failed), --dry-run, --workspace. huly-mcp junit --help lists them.

Tool reference

Category

Tool

Description

Workspaces

list_workspaces

List the workspaces this account can access (name, slug, id)

undo_changes

Undo your last changes made through this server, newest first: what was created is removed, changed fields get their old values, deleted objects come back with the same id and data. Dry run by default; skips (and says so) when someone changed the object since — force overrides. Covers every write tool; history per process (stdio) or per session (HTTP), last 50 changes

check_setup

Diagnose the setup in one call: version and whether a newer one exists, login (incl. API-token expiry), workspaces, front URL reachable, active settings — never prints secrets

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 (tracker-admin)

update_project

Change name, description, default assignee or default status (tracker-admin)

Issues

list_issues

List issues — open ones by default (status: "all" or a status name for others), filterable by priority, milestone, component, label, assignee, parent (null = none for each), text in the title and due date (overdue, set, none); offset pages through long lists ("51–100 of 118")

get_issue

Full details of an issue (e.g. PROJ-42): assignee, milestone, component, labels, parent, links

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

bulk_update_issues

Same change on many issues at once — validates all before writing

move_issue

Move an issue (with sub-issues, comments, attachments, labels, time) to another project

list_sub_issues

Sub-issue tree of an epic with status and progress

Comments

add_comment

Add a comment to an issue

list_comments

Newest comments on an issue, oldest first (includes IDs for delete_comment); comments over 1,500 chars are shortened with a marker unless full: true

update_comment

Edit a comment

delete_comment

Delete a specific comment by ID

Time Tracking

log_time

Log hours spent on an issue

list_time_reports

Logged time per issue or project, totals per member, member/date filters

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

update_label

Rename or recolor a label (updated on every issue) (tracker-admin)

delete_label

Delete a label and remove it from every issue (tracker-admin)

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

remove_relation

Remove a "related" link

remove_blocked_by

Remove a "blocked by" link

repair_parent_links

Fix sub-issues linked by huly-mcp ≤ 2.1 that don't show under their parent (dry run by default) (tracker-admin)

Members

list_members

List workspace members with names and roles

Persons (contacts)

list_persons

Contact persons with their channels

get_person

Person details, contact channels, organizations

create_person

Create a contact person (with optional channels)

update_person

Change name or city

add_contact_channel

Add email, phone, LinkedIn, …

remove_contact_channel

Remove a contact channel

Milestones

list_milestones

List milestones for a project

create_milestone

Create a milestone with a target date and status

get_milestone

Milestone details with progress (done/open/canceled issues) and the open issues

update_milestone

Change name, target date, status or description

delete_milestone

Delete a milestone; its issues are unassigned or moved (moveIssuesTo) (tracker-admin)

Components

list_components

List components (sub-areas) in a project

create_component

Create a new component with optional lead

update_component

Change name, description or lead

delete_component

Delete a component; its issues are unassigned or moved (moveIssuesTo) (tracker-admin)

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

list_documents

Shows the full document tree; update_document also renames and moves (incl. to another teamspace, with sub-documents)

Search

search_issues

Full-text search across all issues of a workspace

search

Full-text search across everything — issues, documents, messages, cards, files, persons … (kinds filter) (generic)

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 with authors, ids, replies, reactions, pins

list_thread

A message with its thread replies

reply_to_message

Reply in a thread (channel messages and issue comments)

update_message

Edit a message or reply

delete_message

Delete a message or reply

add_reaction / remove_reaction

Emoji reactions

pin_message

Pin or unpin a 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 (tracker-admin)

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

Inbox (inbox)

list_notifications

Your notifications, grouped by issue/PR/document

triage_inbox

Work through the inbox in one call: per unread item its status and assignee, which fields changed and the new comments (plain text, shortened) since you last read it

mark_notifications_read

Mark read by object, ids or all; optionally archive

manage_notifications

For one object: pin/unpin, hide/unhide, unread, unarchive, follow/unfollow (follow = its changes reach your inbox)

Activity (activity)

get_activity

Who changed what, plus comments, for an issue or object

Planner (planner)

list_todos

Your to-dos (open/done, due date filter)

create_todo

Create a to-do, optionally attached to an issue

update_todo

Change title, due date, priority; mark done/reopen

delete_todo

Delete a to-do

schedule_todo

Block time for a to-do in your calendar

Calendar (calendar)

list_events

Events and work slots in a date range

create_event / update_event / delete_event

Manage events in your calendar

GitHub (github)

list_pull_requests

PRs by project, issue, state

get_pull_request

State, branches, reviews, review comments, linked issue

Generic (generic)

list_classes

All data classes of the workspace (filter by module, optional counts)

describe_class

Attributes and types of a class

query_documents

Read documents of any class; secrets are redacted

Generic write (generic-write)

generic_create / generic_update / generic_delete

Any class; dry run by default, deletes also need confirm: true; system classes, spaces and credentials are blocked

Collaboration (collaboration)

list_collaborators / add_collaborator / remove_collaborator

Who follows an issue/document (and gets its notifications)

create_public_link / list_public_links / revoke_public_link

Read-only guest links for issues and documents

list_document_comments / add_document_comment

Comments on documents

Cards (cards)

list_card_types / create_card_type / delete_card_type

Card types (MasterTags) and tags

list_cards / get_card

Cards by type, parent or title; one card with fields, tags, children, content

create_card / update_card / delete_card

With content (Markdown), parent, tags and field values

Custom fields (fields)

list_custom_fields

Fields of issues, a project type, card type or class — or the values on one object

create_custom_field

string, number, boolean, date, markup, enum (with values) or ref

set_custom_fields

Set values on an issue, card or document (validated against the type)

Drive (drive)

list_drives / create_drive / list_drive_files

Drives and their folder tree

create_folder / update_drive_item / delete_drive_item

Folders; rename/move files and folders (across drives too)

upload_file / download_file

Base64 or local files under HULY_FILE_ROOT; same name → new version

list_file_versions / restore_file_version

File history

Issue templates (templates)

list_issue_templates / get_issue_template

Templates with their sub-issues

create_issue_template / update_issue_template / delete_issue_template

Priority, assignee, component, milestone, estimation, labels, sub-issues

create_issue_from_template

New issue plus sub-issues from a template

Test management (testing)

list_test_projects / create_test_project

Test projects

list_test_cases / create_test_suite / get_test_case / create_test_case / update_test_case / delete_test_case

Suites (nested) and cases

list_test_plans / create_test_plan

Plans from suites and/or cases

create_test_run / list_test_runs / get_test_run / set_test_result

Runs with Passed/Failed/Blocked results; results can be assigned

create_test_cases

Many cases in one call (e.g. drafted from a spec or an issue); existing names are skipped

update_test_suite / delete_test_suite / update_test_run / delete_test_run / delete_test_plan

Rename/move suites (no cycles), delete with recursive, run due dates

import_test_results

JUnit XML from CI (Jest, Vitest, pytest, Go, Gradle, Maven, xcpretty …) as a run; missing suites/cases are created, failures keep message and stack trace

get_test_report

Over the latest runs: failing now, flaky (flipped ≥ 2×), blocked, never run, per-suite table

create_issue_from_test_result

Bug from a failed result: steps + failure in the description, related to the test case, comment on the result

Products (products)

list_products / get_product

Products and their versions (read-only)

Labels (tracker-admin)

list_label_categories / create_label_category / set_label_category

Group issue labels

Project types (tracker-admin)

list_project_types

Project types, their task types and status workflows, and which projects use them

Workspace (members)

get_workspace_settings

Your role, members per role, invite defaults, integrations

create_invite_link / send_invite / set_member_role

Invite links (personal or with use limit and e-mail mask; nothing is sent), invitation e-mails, roles. send_invite and set_member_role ask for confirmation

Recruiting (recruiting)

list_vacancies / create_vacancy / update_vacancy

Vacancies with applications per status; archive via update_vacancy

list_candidates / create_candidate

Candidates (person + title, e-mail, onsite/remote)

list_applications / create_application / update_application / delete_application

Applications APP-n through the vacancy's workflow, one per candidate and vacancy

CRM (crm)

list_leads / create_lead / update_lead / delete_lead / list_customers

Leads LEAD-n in funnels; a new customer (person or organization) can be created with the lead

HR (hr)

list_departments / create_department / delete_department / set_department

Department tree, team leads, members

list_time_off / create_time_off / delete_time_off

Vacation, sick days, PTO, overtime, remote days

Inventory (inventory)

list_inventory / create_inventory_category / create_inventory_product / update_inventory_item / delete_inventory_item

Categories, products, variants with SKU (Huly beta module)

Message templates (templates)

list_message_templates / get_message_template / create_message_template / update_message_template / delete_message_template

Reusable texts with ${field} placeholders

Meetings (meetings)

list_meetings / get_meeting

Rooms, meeting minutes, action items and transcripts (read-only)

QMS (qms)

list_controlled_documents / get_controlled_document

Controlled documents: version, state, reviewers/approvers, requests, content (read-only)

list_trainings / get_training

Trainings, questions (answers optional) and trainee results (read-only)

Processes (process)

list_processes / list_executions / start_process / cancel_execution

Process states and transitions; running executions; run a process on a card like Huly's "Run process" menu (processes that ask for input in the app are refused); cancel asks first

Surveys (surveys)

list_surveys / get_survey

Surveys and aggregated poll answers (read-only)


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_workspaces returns name, slug and id of every available workspace.

  • Every other tool takes a workspace argument — the slug, the name or the id (case-insensitive): list_projects(workspace="jokeks2023"), get_issue(workspace="acme", 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 has workspace as a required argument — the server never falls back to an implicit, default or "last used" workspace for a write.

  • Reads may omit workspace only 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 same workspace you 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 npx huly-mcp-selfhost setup) prints it.

HULY_WORKSPACE: pins the server to that one workspace. Tools then have no workspace argument at all, which saves ~10% of the tool-list tokens. Leave it unset to use all workspaces of the account.


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 npx huly-mcp-selfhost 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_TRANSACTOR_URL

no

Self-hosted, server next to Huly: connect to the transactor directly instead of the public address the account service returns, e.g. ws://huly/_transactor (via nginx) or ws://transactor:3333. Saves the detour through your uplink/tunnel. HULY_ACCOUNTS_URL can be internal too (http://huly/_accounts); an internal HULY_FRONT_URL also works but then invite links show the internal address

HULY_WORKSPACE

no

Pin the server to one workspace; tools then take no workspace argument (fewer tokens)

HULY_ANNOTATIONS

no

1: every tool carries MCP annotations — a title, readOnlyHint for reads, destructiveHint for deletes/removals/bulk changes. Clients can use them to allow reads without asking. Costs ~16% more tool-list tokens, so it is off by default; the Claude Code plugin turns it on

HULY_DYNAMIC_TOOLSETS

no

1: start with HULY_TOOLSETS and load more on demand via enable_toolsets (see Toolsets)

HULY_TOOLSETS

no

Comma-separated toolsets to enable, or all (see Toolsets). Default: agent,tracker,documents,chat,contacts,inbox,activity,planner,generic

HULY_WRITE_PROJECTS

no

Only allow changes in these projects, e.g. TSK,WEB (see Agent workflow)

HULY_AUDIT_LOG

no

Append every change as JSON line to this file

HULY_AGENT_NAME

no

Default agent name for claim_issue (default claude)

HULY_CONFIRM

no

auto (default), strict or off — ask before deletes and other risky tools (see Agent workflow)

HULY_FILE_ROOT

no

Directory for local files: upload_file (localPath) and download_file (savePath) only work inside it. Off when unset — the server may run remotely

MCP_TRANSPORT

no

Docker only: http = the server's own HTTP endpoint (/mcp, per-user logins) instead of mcp-proxy (see Team server over HTTP)

MCP_OAUTH_SECRET

no

HTTP mode: turns on "log in with Huly" (OAuth); at least 32 characters, e.g. openssl rand -hex 32 (see Team server over HTTP)

MCP_PUBLIC_URL

with OAuth

The HTTPS address clients reach the server at (issuer and login page), e.g. https://huly-mcp.example.com

MCP_AUTH_TOKEN

no

HTTP mode: bearer token every client must send; required before the server's own HULY_* login is used over HTTP

HULY_PREWARM

no

0 turns off connecting at start-up. By default the server logs in (and opens the workspace when there is only one) right after it starts, so the first tool call answers in well under a second instead of 4–12 s

HULY_SUBSCRIBE_POLL_MS

no

How often subscribed huly:// resources are checked for changes (default 30000, minimum 5000)


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).

HULY_EMAIL=your@email.com
HULY_PASSWORD=yourpassword

Option B — Token (SSO accounts: Google/GitHub):

npx huly-mcp-selfhost setup                                  # Huly Cloud
npx huly-mcp-selfhost setup --url https://huly.example.com   # self-hosted

The wizard asks for your Huly address (unless --url or HULY_ACCOUNTS_URL is set), sends a one-time code to your email and lists the workspaces the account can access (a discovery test). It then prints the token and the URLs to paste into your client — for the Claude Code plugin: /plugin → huly → configure. In a checkout of this repo, npm run setup does the same and saves the token as HULY_TOKEN in .env.

HULY_TOKEN=your-token-here

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 npx huly-mcp-selfhost setup for full multi-workspace discovery.

Tokens expire after some time. If you get an auth error, run npx huly-mcp-selfhost setup again or switch to email + password.

Option C — API token (Huly → Settings → API tokens; in Huly's development branch since 2026-08, not yet in every release or self-hosted install): bound to one workspace, with an expiry date, revocable without changing your password — the best choice for agents and CI. Use it as HULY_TOKEN. The server keeps it to its own workspace (even where Huly itself would allow switching), checks the expiry up front, and check_setup warns two weeks before it runs out. Tested against Huly's token format, not yet against a live server that issues such tokens.

Something not working? Ask Claude to run check_setup: version (and whether a newer one exists), login, workspaces, whether the front URL is reachable and which settings are active — without printing secrets.

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 uploads

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": "you@example.com",
        "HULY_PASSWORD": "your-password"
      }
    }
  }
}

Restart Claude Desktop after saving.


Claude Code (CLI)

claude mcp add huly \
  -e HULY_EMAIL=you@example.com \
  -e HULY_PASSWORD=your-password \
  -- npx -y huly-mcp-selfhost

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.


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": "you@example.com",
        "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": "you@example.com",
        "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": "you@example.com",
        "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: you@example.com
      HULY_PASSWORD: your-password

Zed

Add to ~/.config/zed/settings.json:

{
  "context_servers": {
    "huly": {
      "source": "custom",
      "command": "npx",
      "args": ["-y", "huly-mcp-selfhost"],
      "env": {
        "HULY_EMAIL": "you@example.com",
        "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 = "you@example.com", HULY_PASSWORD = "your-password" }

or: codex mcp add huly --env HULY_EMAIL=you@example.com --env HULY_PASSWORD=your-password -- npx -y huly-mcp-selfhost


Any other MCP-compatible client

The server uses standard stdio transport:

  • command: npx with args ["-y", "huly-mcp-selfhost"], or node with ["/absolute/path/to/huly-mcp/dist/index.js"]

  • env: HULY_EMAIL + HULY_PASSWORD (or HULY_TOKEN); self-hosted also HULY_ACCOUNTS_URL + HULY_FRONT_URL — see Configuration

For network access (HTTP/SSE) use the Docker image.



Running the server

Every client example uses "command": "npx", "args": ["-y", "huly-mcp-selfhost"]. Pin a version (huly-mcp-selfhost@3.5.1) if you want updates only when you choose.

From source

git clone https://github.com/JoKeks2023/huly-mcp.git
cd huly-mcp
npm ci && npm run build

Then use "command": "node", "args": ["/absolute/path/to/huly-mcp/dist/index.js"].

Docker

For deployments where the MCP server needs to be reachable over the network (behind a reverse proxy, remote MCP clients, etc.) rather than launched locally per-client, a prebuilt image is published to Docker Hub and GHCR for every release, for linux/amd64 and linux/arm64:

docker pull jokeks2023/huly-mcp:latest   # latest release; also :3, :3.1, :3.1.0
# also mirrored at ghcr.io/jokeks2023/huly-mcp:latest
# :edge = latest build from main

Or with Compose — copy .env.example to .env, fill in your credentials (no workspace needed), then:

docker compose up -d

The 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. Behind a reverse proxy or on a public hostname, set MCP_ALLOWED_HOSTS to the host name(s) clients use, e.g. MCP_ALLOWED_HOSTS=huly-mcp.example.com. Otherwise mcp-proxy only accepts localhost and answers 421 Invalid Host header. See Dockerfile / docker-compose.yml.

Team server over HTTP

huly-mcp-selfhost http serves MCP over Streamable HTTP at /mcp (health check /healthz) — no proxy, one long-lived session per client, so logins and connections are reused (the first call of a session takes ~0.2 s). In Docker: MCP_TRANSPORT=http.

npx huly-mcp-selfhost http --host 0.0.0.0 --port 8000

Everyone with their own Huly account. A client sends its own login as headers; the session then acts as that person:

claude mcp add --transport http huly https://huly-mcp.example.com/mcp \
  --header "X-Huly-Token: <your token>"            # or X-Huly-Email + X-Huly-Password
  # optional: --header "X-Huly-Workspace: acme"    # pin one workspace (fewer tokens)

Log in with Huly (OAuth). Set MCP_OAUTH_SECRET (openssl rand -hex 32) and MCP_PUBLIC_URL (the HTTPS address clients reach, e.g. https://huly-mcp.example.com). Then people simply add https://huly-mcp.example.com/mcp in their AI app — Claude Code (claude mcp add --transport http huly …), Claude's custom connectors and other OAuth-capable MCP clients — and log in in the browser with their own Huly account: e-mail + password, or a one-time code by e-mail for Google/GitHub accounts. One server, as many people as you like, nobody handles tokens.

  • Stateless: registrations, codes and tokens are sealed with AES-256-GCM under MCP_OAUTH_SECRET — no database, logins survive restarts. Changing the secret logs everyone out.

  • The Huly password goes only to your Huly server; the server keeps just the resulting Huly token, inside the sealed tokens. Access tokens last 1 hour, refresh tokens 30 days and work once (rotation). Login attempts are throttled per address.

  • The protocol parts (client registration, PKCE, token endpoint, metadata) are the MCP SDK's own; this server adds the login page and the tokens.

  • X-Huly-Workspace still pins a workspace. In OAuth mode /mcp needs the OAuth token; MCP_AUTH_TOKEN and the X-Huly-* login headers are for the other mode.

One shared account. The server's own HULY_* login is only used behind a bearer token — set MCP_AUTH_TOKEN and give clients Authorization: Bearer <token>. Without it an open port would act as that account, so the server refuses and asks for per-user headers instead. With MCP_AUTH_TOKEN set, every request needs the bearer token, also when it brings its own login.

Set MCP_ALLOWED_HOSTS to the host names clients use (DNS-rebinding protection). Use HTTPS (reverse proxy) as soon as logins travel over a network. Idle sessions close after 30 minutes.


Example prompts

Workspaces:

  • "Which Huly workspaces do I have?"

  • "List the projects in my Acme 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"

  • "How far along is milestone v2.0 Launch in PROJ?"

  • "Move the v2.0 Launch milestone to 2026-07-15 and set it to In Progress"

  • "Delete milestone 'Beta' in PROJ and move its issues to 'v2.0 Launch'"

Planning & bulk work:

  • "Which issues in milestone v2.0 Launch carry the label 'bug' and are still unassigned?"

  • "Set PROJ-12, PROJ-13 and PROJ-20 to In Progress and put them into milestone v2.0 Launch"

  • "Show me the sub-issue tree of PROJ-1 and how far along it is"

  • "How many hours did we log on PROJ in October, per person?"

  • "Move PROJ-42 to the OPS project"

Inbox, planner, calendar:

  • "What's new in my inbox? Mark everything about PROJ-12 as read"

  • "Create a to-do 'Review PR' on PROJ-7 due Friday and block 45 minutes tomorrow at 9"

  • "What's on my calendar this week?"

  • "Show the history of PROJ-12 — who moved it to Done?"

  • "Which pull requests are waiting for review 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 MarkupBlobRef blob. 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 through front's own, older /files endpoint instead. If HULY_FRONT_URL is 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_URL doubles 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=myteam

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.

CSV format:

title,priority,status,dueDate
Fix login bug,High,In Progress,2025-04-01
Add dark mode,Medium,,
Improve performance,Urgent,,2025-05-01

Required column: title. Optional: priority (Urgent/High/Medium/Low), status (must match a status name in the project), dueDate (YYYY-MM-DD).


Architecture

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.


Development and CI

npm ci && npm run build && npm test

npm run build type-checks (tsc --noEmit) and bundles src/ with all dependencies into one readable file, dist/index.js (esbuild, not minified), plus dist/guides/. The published package therefore has no runtime dependencies; everything in package.json is a dev dependency. Tests run on the TypeScript sources (tsx).

GitHub Actions check every pull request:

Workflow

What it checks

ci.yml

build and tests on Node 20/22/24 (Linux), macOS and Windows; the built server answers tools/list over stdio; npm pack contents; gitleaks and a personal-data check; the Docker image (build, stdio smoke, Trivy); actionlint; a token report comment with the tools/list size before and after the PR

codeql.yml

CodeQL security analysis (also weekly)

links.yml

broken links in Markdown and the site (on PRs that touch them, and weekly → issue)

dependabot-automerge.yml

Dependabot patch/minor updates merge by themselves once checks are green; majors and Huly packages wait for review

scheduled.yml

nightly live smoke test against a sandbox workspace; weekly: the latest @hcengineering/* packages, and Huly modules that have no tools yet (see .github/huly-modules-ignore.txt). Failures open or update an issue

release.yml

on a vX.Y.Z tag: version and changelog check, tests, personal-data check, npm publish --provenance (Trusted Publishing), GitHub release from the changelog section, MCP registry entry

Security reports: see SECURITY.md.

test/repo.test.ts keeps the docs honest: tool counts in this README, the site and DOCKERHUB.md must match the registry, the version must match everywhere, and the plugin must be well-formed.

Releasing:

  1. Move the Unreleased entries in CHANGELOG.md under ### X.Y.Z — date.

  2. Bump the version in package.json, server.json, plugin/.claude-plugin/plugin.json, plugin/.mcp.json (exact npx version) and src/server.ts. The tests check that they agree.

  3. Merge, then tag vX.Y.Z on main. The rest runs by itself.

Environments and secrets:

  • Environment release (tags v* only): used by release.yml. npm Trusted Publishing names this environment.

  • Environment sandbox: used by the nightly live jobs.

Secrets:

  • PERSONAL_DATA_PATTERNS: private terms that must never appear in the repo, one regex per line.

  • NPM_TOKEN: fallback only, until Trusted Publishing is set up on npmjs.com.

  • In the environment sandbox: HULY_SMOKE_WORKSPACE, HULY_SMOKE_PROJECT, HULY_SMOKE_EMAIL + HULY_SMOKE_PASSWORD (or HULY_SMOKE_TOKEN), HULY_SMOKE_ACCOUNTS_URL, HULY_SMOKE_FRONT_URL: a throwaway workspace for the nightly live test. Without them the live jobs skip.


Changelog

See CHANGELOG.md.


Credits

Started as a fork of varaprasadreddy9676/huly-mcp (npm huly-mcp-sdk) by SaiVaraprasad Medapati and grown from its 33 tools to 227, with self-hosted support, toolsets, agent workflow and the Claude Code plugin. Published separately as huly-mcp-selfhost. Not affiliated with Huly Labs.

License

Eclipse Public License 2.0

Available Tools

99 tools
add_blocked_byC

Mark an issue as blocked by another issue

Inputs: blockedBy (required), workspace (required), identifier (required).

add_commentC

Add a comment to an issue

Inputs: message (required), workspace (required), identifier (required).

add_contact_channelC

Add email/phone/… to a person

Inputs: value (required), person (required), provider (required), workspace (required).

add_labelC

Add label to issue (auto-creates label)

Inputs: labelName (required), workspace (required), identifier (required).

add_reactionC

React to a message/comment with an emoji

Inputs: emoji (required), messageId (required), workspace (required).

add_relationB

Mark two issues as related to each other (bidirectional)

Inputs: relatedTo (required), workspace (required), identifier (required).

attach_fileB

Attach a file to an issue (base64-encoded content)

Inputs: filename (required), workspace (required), identifier (required), contentBase64 (required), +1 more.

bulk_update_issuesB
Destructive

Apply one change to many issues; validates all first

Inputs: workspace (required), identifiers (required), dueDate, assignee, +4 more.

changes_sinceC
Read-only

Issues/PRs changed since a time: fields, comments, who

Inputs: since (required), limit, workspace, projectIdentifiers.

check_setupB
Read-only

Diagnose the setup: version and updates, login, workspaces, front URL, settings (no secrets)

Inputs: workspace, skipVersionCheck.

claim_issueB

Lease an issue so parallel agents skip it

Inputs: workspace (required), identifier (required), agent, force, +1 more.

create_channelD

Create a new channel

Inputs: name (required), workspace (required), topic, isPrivate.

create_componentC

Create a new component in a project

Inputs: label (required), workspace (required), projectIdentifier (required), lead, +1 more.

create_documentC

Create a new document in a teamspace

Inputs: title (required), workspace (required), teamspaceId (required), parentId.

create_issueC

Create a new issue in a project

Inputs: title (required), workspace (required), projectIdentifier (required), dueDate, +6 more.

create_issue_treeB

Plan → epic + sub-issues with blockers; skips duplicates; dry run first

Inputs: children (required), workspace (required), projectIdentifier (required), epic, +5 more.

create_labelC

Create a new label with an optional hex color

Inputs: title (required), workspace (required), color.

create_milestoneC

Create a new milestone in a project with a target date

Inputs: label (required), workspace (required), targetDate (required), projectIdentifier (required), +1 more.

create_organizationC

Create a new organization (company contact)

Inputs: name (required), workspace (required), city.

create_personC

Create a contact person

Inputs: firstName (required), workspace (required), city, channels, +1 more.

create_teamspaceC

Create a document teamspace

Inputs: name (required), workspace (required), isPrivate, description.

create_todoC

Create a to-do, optionally on an issue

Inputs: title (required), workspace (required), issue, dueDate, +2 more.

delete_attachmentC
Destructive

Delete a file attachment from an issue

Inputs: workspace (required), identifier (required), attachmentId (required).

delete_commentC
Destructive

Delete a comment by id

Inputs: commentId (required), workspace (required), identifier (required).

delete_documentA
Destructive

Permanently delete a document by its ID

Inputs: workspace (required), documentId (required).

delete_issueB
Destructive

Permanently delete an issue by identifier (e.g. "PROJ-123")

Inputs: workspace (required), identifier (required).

delete_messageC
Destructive

Delete a message or thread reply

Inputs: messageId (required), workspace (required).

delete_todoC
Destructive

Delete a to-do

Inputs: todoId (required), workspace (required).

describe_classC
Read-only

Attributes and types of a class

Inputs: className (required), workspace.

find_project_for_repoC
Read-only

Huly workspace + project linked to a GitHub repo

Inputs: repository (required), workspace.

finish_workC

Hand back: summary comment, link PR, status to review

Inputs: summary (required), workspace (required), identifier (required), statusName, +1 more.

get_activityC
Read-only

Change history and comments of an issue or object

Inputs: object (required), limit, workspace.

get_documentC
Read-only

Document metadata and content

Inputs: documentId (required), workspace.

get_issueB
Read-only

Get full details of an issue by identifier (e.g. "PROJ-123")

Inputs: identifier (required), workspace.

get_issue_contextC
Read-only

Issue with description, sub-issues, blockers, PRs, comments, branch name

Inputs: identifier (required), workspace, commentLimit.

get_milestoneD
Read-only

Milestone with progress and open issues

Inputs: label (required), projectIdentifier (required), workspace.

get_organizationB
Read-only

Get details of an organization, including description

Inputs: organizationId (required), workspace.

get_personD
Read-only

Person details, channels, organizations

Inputs: person (required), workspace.

get_projectB
Read-only

Get a project by its identifier (e.g. "PROJ")

Inputs: identifier (required), workspace.

issues_from_documentB

Spec → epic + sub-issues from a document's open checklist items (else its sections); links the doc. Dry run first

Inputs: document (required), workspace (required), projectIdentifier (required), dryRun, +5 more.

issues_from_meetingB

Meeting notes → issues: action items with @assignee and due date; links the doc. Dry run first

Inputs: document (required), workspace (required), projectIdentifier (required), dryRun, +3 more.

list_attachmentsC
Read-only

List files attached to an issue

Inputs: identifier (required), workspace.

list_channelsC
Read-only

List all channels in the workspace

Inputs: workspace, includeArchived.

list_classesB
Read-only

Huly data classes (for modules without dedicated tools)

Inputs: module, workspace, withCounts.

list_commentsC
Read-only

List comments of an issue (with ids)

Inputs: identifier (required), full, limit, workspace.

list_componentsC
Read-only

List components (sub-areas) in a project

Inputs: projectIdentifier (required), workspace.

list_documentsC
Read-only

List documents in a teamspace

Inputs: teamspaceId (required), workspace.

list_issuesC
Read-only

List issues of a project; filters: status, priority, milestone, component, label, assignee, parent

Inputs: projectIdentifier (required), due, limit, title, +9 more.

list_issue_statusesB
Read-only

List all issue statuses (workflow states), grouped by phase

Inputs: workspace.

list_labelsB
Read-only

List all labels in the workspace

Inputs: workspace, projectIdentifier.

list_membersC
Read-only

List all members in the workspace

Inputs: workspace.

list_messagesC
Read-only

List messages in a channel or direct message

Inputs: spaceId (required), limit, workspace.

list_milestonesC
Read-only

List milestones for a project

Inputs: projectIdentifier (required), workspace.

list_notificationsC
Read-only

Your inbox notifications, grouped by issue/PR/document

Inputs: ids, limit, workspace, unreadOnly.

list_organizationsB
Read-only

List all organizations (companies) in the workspace

Inputs: workspace.

list_personsC
Read-only

Contact persons with their channels

Inputs: limit, query, workspace, employeesOnly.

list_projectsC
Read-only

List all projects in a Huly workspace

Inputs: workspace.

list_sub_issuesC
Read-only

Sub-issue tree of an issue with progress

Inputs: identifier (required), depth, workspace.

list_teamspacesC
Read-only

List all document teamspaces in the workspace

Inputs: workspace.

list_threadC
Read-only

Message with its thread replies

Inputs: messageId (required), limit, workspace.

list_time_reportsB
Read-only

Logged time for an issue or project, totals per person; person/date filters

Inputs: to, from, limit, member, +3 more.

list_todosD
Read-only

Your planner to-dos

Inputs: limit, status, dueBefore, workspace.

list_workspacesA
Read-only

List accessible workspaces (name, slug, id)

Inputs: no named parameters.

log_timeC

Log hours spent on an issue

Inputs: hours (required), workspace (required), identifier (required), description.

manage_notificationsC

Inbox for one object: pin, hide, mark unread, unarchive, follow/unfollow (and the undo of each)

Inputs: action (required), object (required), workspace (required).

mark_notifications_readA

Mark notifications read (by object, ids or all); optionally archive

Inputs: workspace (required), all, object, archive, +1 more.

move_issueA
Destructive

Move issue (incl. sub-issues, comments, files, time) to another project; gets a new id, component/milestone cleared

Inputs: workspace (required), identifier (required), targetProjectIdentifier (required), statusName.

my_dayB
Read-only

Today at a glance: calendar, to-dos, my issues, reviews, unread inbox

Inputs: date, limit, workspace.

pin_messageB

Pin or unpin a message

Inputs: messageId (required), workspace (required), pinned.

project_reportC
Read-only

Weekly report: done, new, blocked, overdue, PRs, milestones, time

Inputs: projectIdentifier (required), since, workspace.

query_documentsC
Read-only

Read documents of any class (secrets redacted)

Inputs: className (required), limit, query, fields, +1 more.

release_issueC

Release an agent claim

Inputs: workspace (required), identifier (required), agent.

release_notesB
Read-only

Release notes from a milestone: features, fixes, PRs, still open

Inputs: milestoneLabel (required), projectIdentifier (required), workspace.

remove_blocked_byC
Destructive

Remove a "blocked by" link from an issue

Inputs: blockedBy (required), workspace (required), identifier (required).

remove_contact_channelC
Destructive

Remove email/phone/… from a person

Inputs: value (required), person (required), provider (required), workspace (required).

remove_labelB
Destructive

Remove a label from an issue

Inputs: labelName (required), workspace (required), identifier (required).

remove_reactionB
Destructive

Remove your emoji reaction

Inputs: emoji (required), messageId (required), workspace (required).

remove_relationB
Destructive

Remove the "related" link between two issues

Inputs: relatedTo (required), workspace (required), identifier (required).

reply_to_messageC

Reply in the thread of a message or comment

Inputs: message (required), messageId (required), workspace (required).

schedule_todoC

Block time for a to-do in your calendar

Inputs: start (required), todoId (required), workspace (required), durationMinutes.

search_issuesC
Read-only

Full-text search across all issues

Inputs: query (required), limit, workspace.

send_messageC

Send a message to a channel or direct message

Inputs: message (required), spaceId (required), workspace (required).

set_parentC

Set or clear the parent (epic) of an issue

Inputs: workspace (required), identifier (required), parentIdentifier.

standupC
Read-only

Standup: what I did since the last working day, today, blockers

Inputs: since, workspace.

start_direct_messageB

Start or find a 1:1 DM with a person

Inputs: member (required), workspace (required).

start_workC

Pick up issue: In Progress, assign me, return context

Inputs: workspace (required), identifier (required), claimAs, assignToMe, +1 more.

triage_inboxB
Read-only

Unread items with what changed since last read: new comments, fields, status

Inputs: limit, workspace.

undo_changesA
Destructive

Undo your last changes made through this server: created → removed, changed → old values, deleted → restored. Dry run first

Inputs: workspace (required), count, force, dryRun.

update_commentC

Edit a comment by id

Inputs: message (required), commentId (required), workspace (required), identifier (required).

update_componentC

Update a component (name, description, lead)

Inputs: label (required), workspace (required), projectIdentifier (required), lead, +2 more.

update_documentA

Replace content (Markdown), rename or move a document

Inputs: workspace (required), documentId (required), title, markdown, +2 more.

update_issueC

Update issue fields

Inputs: workspace (required), identifier (required), title, dueDate, +6 more.

update_messageC

Edit a message or thread reply

Inputs: message (required), messageId (required), workspace (required).

update_milestoneC

Update a milestone (name, target date, status, description)

Inputs: label (required), workspace (required), projectIdentifier (required), status, +3 more.

update_organizationC

Set the description of an organization from Markdown

Inputs: workspace (required), description (required), organizationId (required).

update_personC

Update a contact person

Inputs: person (required), workspace (required), city, lastName, +1 more.

update_todoC

Update a to-do or mark it done

Inputs: todoId (required), workspace (required), done, title, +3 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.6/5.0

    Scored across 99 tools

    Disambiguation3/5

    Most tools target a distinct resource+action, but several clusters blur together: get_issue vs get_issue_context vs get_activity vs list_sub_issues, search vs search_issues vs query_documents, and the notification group (list_notifications, triage_inbox, manage_notifications, mark_notifications_read). Issue-creation also overlaps across create_issue, create_issue_tree, issues_from_document and issues_from_meeting, and the agent-workflow helpers (claim_issue/release_issue vs start_work/finish_work) describe closely related states. Descriptions do help, but an agent must read carefully to pick correctly.

    Naming Consistency4/5

    Names are uniformly snake_case with a strong verb_noun bias (create_issue, update_milestone, remove_reaction, list_attachments), which is highly predictable. Deviations are limited to a handful of noun-first or verb-less labels like my_day, standup, project_report, release_notes and changes_since, which are readable but break the pattern.

    Tool Count2/5

    99 tools is far beyond what an agent can comfortably select from, even though Huly genuinely spans issues, documents, chat, contacts and notifications. Several tools are near-duplicates or convenience wrappers (my_day, standup, triage_inbox, check_setup) that could be folded into broader calls. The surface would benefit from consolidation into per-domain entry points.

    Completeness4/5

    Coverage is unusually deep: full CRUD for issues, documents, todos, comments, messages, attachments and relations, plus reporting, time tracking, workflow helpers and generic class queries. Gaps are mostly delete/create operations for secondary entities (no delete for projects, milestones, components, persons, organizations, labels or channels, and no create_project), but agents can work around these.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Complete MCP server for Huly project management with 209 tools across 23 categories — issues, projects, tasks, comments, documents, cards, channels, calendar, time tracking, test management, processes, custom fields, attachments, leads and more. Includes custom task type support (Ticket, Bug, Feature) with project-scoped status workflows and read-side Process plugin tools.
      24 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      An MCP server that enables AI assistants to interact with Huly's project and document management platform, providing search and write actions for issues, milestones, and more.
      7 npm
      MIT