Skip to main content
Glama
ProjectHub MCP Server

ProjectHub MCP Server

by compagnt

ProjectHub MCP Server

An MCP (Model Context Protocol) server that connects AI assistants like Claude Desktop to ProjectHub, a collaborative project management tool.

Features

56 tools covering the full ProjectHub API:

Category

Tools

User

get_user_info

Workspaces

list_workspaces, list_projects, create_project

Projects

get_project, list_project_members, search_project, get_activity

Tasks

list_tasks, get_task, create_task, update_task, delete_task, toggle_task (create/update accept attachment_uuids; update accepts comment)

Task comments

list_task_comments, add_task_comment, update_task_comment, delete_task_comment

Time Tracking

start_timer, stop_timer

Notes

list_notes, get_note, create_note, update_note, delete_note

Tags

list_tags, create_tag, update_tag, delete_tag

Canvas

list_canvas_items, place_on_canvas, move_canvas_item, remove_from_canvas

Discussions

list_discussions, create_discussion, get_discussion_messages

Reminders

list_reminders, create_reminder, dismiss_reminder

Notifications

list_notifications, mark_notification_read

Links

list_links, create_link, delete_link

Files

list_files, get_file, upload_file, delete_file, attach_file_to_task, detach_file_from_task

Memories

list_memories, get_memory, create_memory, update_memory, delete_memory, list_workspace_memories

Related MCP server: OpenProject MCP Server

Task keys

Every task has a human-readable key such as PR14 — the project's key prefix plus a per-project number that is assigned at creation and never reused. Task objects return key and number; project objects return key. Anywhere a tool takes a task_uuid (get/update/delete/toggle, timers, attachments, parent_uuid, list_tasks parent, upload_file task_uuid) you can pass the key instead, case-insensitively (pr14, PR-14). list_tasks q and search_project match keys too. create_project accepts an optional key (1–5 letters); otherwise it's derived from the name.

Uploading files

upload_file takes the file body from exactly one of four sources:

Source

Where it works

Use for

path

Local stdio server only (Claude Code, Claude Desktop launching dist/index.js)

Anything on your disk, up to the 50 MB server limit — the bytes go straight from the MCP process to ProjectHub, never through the model

url

Everywhere, including the hosted connector

Files reachable over https. Private/loopback addresses are refused, redirects are re-checked, 30 s timeout

content

Everywhere

Small text the assistant generates (reports, CSV, Markdown)

content_base64

Everywhere

Small binary the assistant generates

Inline content / content_base64 travel inside the tool call, so they are practically limited to tens of KB. The hosted connector cannot read your disk; for local files there, use the ProjectHub UI or a url.

filename is required with inline content and defaults to the source's name for path/url. task_uuid attaches the file to a task in the same call. PROJECTHUB_MAX_UPLOAD_BYTES overrides the 50 MB client-side cap (the server enforces its own).

Prerequisites

  • Node.js 20+

  • A running ProjectHub instance

  • A ProjectHub Personal Access Token

Creating an API Token

  1. Log in to ProjectHub

  2. Click your avatar (top-right) → Settings (gear icon)

  3. Scroll to API Tokens → click +

  4. Name the token (e.g. "Claude Desktop MCP") and click Create

  5. Copy the token immediately — it is only shown once

Setup

git clone <repo-url>
cd projecthub-mcp
npm install
npm run build

Configuration

The server reads two environment variables:

Variable

Required

Default

Description

PROJECTHUB_API_TOKEN

Yes

—

Personal access token (ph_...)

PROJECTHUB_URL

No

http://localhost:8000

ProjectHub base URL

Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "projecthub": {
      "command": "node",
      "args": ["/absolute/path/to/projecthub-mcp/dist/index.js"],
      "env": {
        "PROJECTHUB_URL": "http://localhost:8000",
        "PROJECTHUB_API_TOKEN": "ph_your_token_here"
      }
    }
  }
}

Claude Code

Add to your Claude Code settings or project config:

{
  "mcpServers": {
    "projecthub": {
      "command": "node",
      "args": ["/absolute/path/to/projecthub-mcp/dist/index.js"],
      "env": {
        "PROJECTHUB_URL": "http://localhost:8000",
        "PROJECTHUB_API_TOKEN": "ph_your_token_here"
      }
    }
  }
}

Hosted mode — Claude Desktop / claude.ai custom connector

The stdio setup above runs one local process per machine with a pasted token. For a custom connector (Claude Desktop → Settings → Connectors → Add custom connector, also usable from claude.ai web and mobile) the server must be hosted over HTTPS and use OAuth. That is what dist/http.js is:

  • Transport: Streamable HTTP at /mcp, stateless (scales horizontally).

  • Auth: ProjectHub itself is the OAuth 2.1 authorization server (PKCE, dynamic client registration, consent page). This service is only a resource server: it 401s with a WWW-Authenticate challenge pointing at its /.well-known/oauth-protected-resource document, which names ProjectHub as the authorization server. Claude follows that, the user approves on ProjectHub's consent page, and every subsequent tool call forwards that user's access token to /api/v1. Personal tokens (ph_…) are accepted too.

  • Verification: each presented token is checked against GET /api/v1/me and cached for MCP_VERIFY_TTL_SECONDS (default 60).

ProjectHub prerequisites

The ProjectHub deployment must be on a build that includes the OAuth provider (oauth2_provider in INSTALLED_APPS, /oauth/* routes) with these set:

Variable

Example

Purpose

APP_BASE_URL

https://projecthub.example.com

Advertised as the OAuth issuer; every OAuth endpoint URL in the metadata is anchored to it (must be https://)

MCP_PUBLIC_URL

https://projecthub-mcp.up.railway.app/mcp

RFC 9728 resource identifier

ProjectHub must also run with DEBUG off in production. Without APP_BASE_URL, the metadata URLs are derived from the request scheme, and a misread proxy header makes them http://, which Claude refuses at the registration step.

Environment (this service)

Variable

Required

Default

Description

PROJECTHUB_URL

Yes

http://localhost:8000

Public ProjectHub base URL (also the OAuth issuer)

MCP_PUBLIC_URL

Recommended

derived from request

This service's public /mcp URL

PORT

No

3000

Listen port (Railway sets it)

MCP_ALLOWED_HOSTS

No

unset

Comma-separated Host allowlist (DNS-rebinding protection); unset = off

MCP_VERIFY_TTL_SECONDS

No

60

How long a verified token is trusted before re-checking

PROJECTHUB_API_TOKEN is not used in hosted mode.

Deploy on Railway

Add a new service in the ProjectHub Railway project from this repo. The Dockerfile builds and runs node dist/http.js. Generate a public domain for the service, then set MCP_PUBLIC_URL=https://<that domain>/mcp here and MCP_PUBLIC_URL / APP_BASE_URL on the ProjectHub web service. Health check: GET /healthz.

Connect from Claude

Claude Desktop → Settings → Connectors → Add custom connector → URL https://<mcp domain>/mcp. Leave client ID / secret blank (Claude registers itself). Sign in to ProjectHub when prompted and click Allow.

Run hosted mode locally

npm run build
PROJECTHUB_URL=http://localhost:8000 npm run start:http
# Inspector: URL http://localhost:3000/mcp, header Authorization: Bearer ph_...

Note that ProjectHub only allows https redirect URIs, so the full OAuth browser flow needs a public HTTPS deployment; locally, test with a personal token as above.

Tests

npm test   # builds, then runs an end-to-end test against a mock ProjectHub

Development

# Watch mode — recompiles on file changes
npm run dev

# Test interactively with the MCP Inspector
npm run inspect

Project Structure

src/
  index.ts           stdio entrypoint (local Claude Desktop config, one token per process)
  http.ts            Hosted entrypoint — Streamable HTTP + OAuth resource-server gate
  server.ts          createServer(): builds the McpServer with every tool registered
  api-client.ts      HTTP client (per-request token context), error handling, response helpers
  test/              node:test end-to-end tests for the hosted entrypoint
  tools/
    user.ts          get_user_info
    workspaces.ts    list_workspaces, list_projects
    projects.ts      get_project, list_project_members, search_project, get_activity
    tasks.ts         list_tasks, get_task, create_task, update_task, delete_task, toggle_task
    timers.ts        start_timer, stop_timer
    notes.ts         list_notes, get_note, create_note, update_note, delete_note
    discussions.ts   list_discussions, get_discussion_messages
    reminders.ts     list_reminders, create_reminder, dismiss_reminder

Common Workflows

Task triage — List open tasks, review priorities, update or complete them:

"Show me all open high-priority tasks in the Website Redesign project"

Standup summary — Combine your assigned tasks with recent activity:

"Give me a standup summary for my project"

Find context — Search across notes, discussions, and messages:

"Search for anything about the auth bug in this project"

Quick capture — Create tasks, notes, or reminders from conversation:

"Create a task to review the API documentation, due next Friday"

Project overview — Get project details, members, tasks, and notes at a glance:

"Give me an overview of what's happening in this project"

Notes

  • Auth: The API token inherits the user's full permissions — no separate scopes

  • Discussions: Read-only via the API (messages are sent through the ProjectHub UI)

  • HTML content: Note and message text is returned as HTML

  • IDs: All resource IDs are UUIDs except user_id and assignee_id (integers)

Available Tools

47 tools
create_discussionB

Create a new discussion (chat room) in a project

Inputs: title (required), project_uuid (required).

create_memoryA

Create a new memory in a project. Memories are AI-generated knowledge items — decisions, preferences, context, references, or lessons — that persist across conversations. Humans can view them in the platform.

Inputs: title (required), content (required), category (required), project_uuid (required), +4 more.

create_noteC

Create a new note in a project. Only title is required.

Inputs: title (required), project_uuid (required), tags, text, +1 more.

create_projectB

Create a new project in a workspace. Requires add_project permission.

Inputs: name (required), workspace_uuid (required), icon, color, +1 more.

create_reminderB

Create a reminder. Title and remind_at are required. remind_at must include timezone.

Inputs: title (required), remind_at (required), project_uuid (required), notes, +4 more.

create_tagA

Create a tag in a project. Names are unique per project (case-insensitive). Note: you usually don't need this — passing tags: ["July Release"] to create_task/update_task/create_note/update_note auto-creates any tag that doesn't exist yet. Use this when you want to control the colour.

Inputs: name (required), project_uuid (required), color.

create_taskB

Create a new task in a project. Only title is required.

Inputs: title (required), project_uuid (required), tags, status, +6 more.

delete_memoryA

Delete a memory from a project

Inputs: memory_uuid (required), project_uuid (required).

delete_noteA

Delete a note. Requires being the creator or having delete permission.

Inputs: note_uuid (required), project_uuid (required).

delete_tagA

Delete a tag from a project. It is removed from every task and note it was attached to. The tagged items themselves are NOT deleted.

Inputs: tag_uuid (required), project_uuid (required).

delete_taskB

Delete a task. Requires Project Owner role.

Inputs: task_uuid (required), project_uuid (required).

dismiss_reminderA

Dismiss a reminder (sets its status to dismissed)

Inputs: project_uuid (required), reminder_uuid (required).

get_activityC

Get the recent activity feed for a project

Inputs: project_uuid (required), limit.

get_discussion_messagesB

Get messages from a discussion in chronological order. Messages are read-only via the API.

Inputs: project_uuid (required), discussion_uuid (required), limit, before.

get_memoryB

Get a single memory with its full content

Inputs: memory_uuid (required), project_uuid (required).

get_noteA

Get a single note with its full content

Inputs: note_uuid (required), project_uuid (required).

get_projectB

Get details of a specific project

Inputs: project_uuid (required).

get_taskB

Get details of a specific task

Inputs: task_uuid (required), project_uuid (required).

get_user_infoA

Get the authenticated user's profile information (name, email, username)

Inputs: no named parameters.

list_canvas_itemsA

List the notes placed on the project's shared canvas, with their positions (x, y), sizes (width, height), and stacking order (z). Use this to understand how the board is spatially organized before placing or arranging notes.

Inputs: project_uuid (required).

list_discussionsB

List all discussions (chat rooms) in a project

Inputs: project_uuid (required).

list_filesA

List all files in a project. Requires files_enabled plan feature.

Inputs: project_uuid (required).

list_memoriesA

List memories (AI-generated knowledge items) in a project. Memories capture decisions, preferences, context, references, and lessons that persist across conversations.

Inputs: project_uuid (required), source, category, is_pinned.

list_notesA

List all notes in a project, ordered by pinned first then newest. Pass tag to only return notes carrying that tag.

Inputs: project_uuid (required), tag.

list_notificationsA

List notifications for the current user. Returns unread only by default.

Inputs: limit, unread_only.

list_project_membersA

List members of a project with their roles

Inputs: project_uuid (required).

list_projectsA

List projects in a workspace that the user is a member of

Inputs: workspace_uuid (required), include_archived.

list_remindersA

List pending reminders for the current user in a project

Inputs: project_uuid (required).

list_tagsA

List the tags defined in a project, with how many things each tag is attached to. Use this to discover existing tags before tagging something, so you reuse a tag instead of creating a near-duplicate.

Inputs: project_uuid (required), q.

list_tasksA

List tasks in a project with optional filters. Results are paginated (default 50). Use q to keyword-search titles/descriptions, and limit/offset to page through large projects instead of fetching everything.

Inputs: project_uuid (required), q, tag, limit, +4 more.

list_workspace_memoriesB

List memories across all projects in a workspace. Useful for retrieving workspace-wide knowledge and context.

Inputs: workspace_uuid (required), source, category.

list_workspacesA

List all workspaces the authenticated user belongs to

Inputs: no named parameters.

mark_notification_readB

Mark a notification as read

Inputs: notification_id (required).

move_canvas_itemA

Move and/or resize a placed canvas item. Pass the placement's item id (from list_canvas_items or place_on_canvas), not the note id. Only provided fields change. Use z to restack (higher = front). Width/height are clamped to a minimum.

Inputs: item_uuid (required), project_uuid (required), x, y, +3 more.

place_on_canvasA

Place a note on the shared canvas at an (x, y) world coordinate. Idempotent — if the note is already on the canvas, returns its existing placement. Returns the placement (including its item id used by move/remove). Coordinates are in pixels; new notes default near the top-left. Place related notes near each other.

Inputs: note_uuid (required), project_uuid (required), x, y.

remove_from_canvasA

Remove a note's placement from the canvas. The underlying note is NOT deleted — it just leaves the board. Pass the placement's item id, not the note id.

Inputs: item_uuid (required), project_uuid (required).

search_projectA

Search across notes, tasks, discussions, messages, and memories in a project. Strong multi-term keyword matching (every word must match; order-independent); semantic search is also used for embedded types on Pro plans. Returns up to 4 results per type. Pass type to restrict to one entity type (e.g. 'task').

Inputs: q (required), project_uuid (required), type.

start_timerA

Start a time tracking timer on a task. Automatically stops any other running timer.

Inputs: task_uuid (required), project_uuid (required).

stop_timerA

Stop the running time tracking timer on a task

Inputs: task_uuid (required), project_uuid (required).

toggle_taskB

Toggle a task between open and done status

Inputs: task_uuid (required), project_uuid (required).

update_memoryB

Update a memory. Only provided fields are changed (partial update).

Inputs: memory_uuid (required), project_uuid (required), tags, title, +5 more.

update_noteB

Update a note. Only provided fields are changed.

Inputs: note_uuid (required), project_uuid (required), tags, text, +2 more.

update_tagA

Rename or recolour a tag. Renaming updates it everywhere it's used. Only provided fields change.

Inputs: tag_uuid (required), project_uuid (required), name, color.

update_taskA

Update a task. Only provided fields are changed. Set assignee_id to 0 to unassign.

Inputs: task_uuid (required), project_uuid (required), tags, title, +6 more.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 47 tools

    Disambiguation4/5

    Each tool targets a specific resource or action, but some overlap exists such as search_project vs dedicated list tools, and list_workspace_memories vs list_memories, which could cause minor confusion.

    Naming Consistency5/5

    All tools consistently use snake_case and follow a verb_noun pattern (e.g., list_projects, create_task, toggle_task), making the naming highly predictable and clear.

    Tool Count2/5

    With 47 tools, the count is very high, exceeding the typical well-scoped range. While each tool serves a distinct purpose, the sheer number may overwhelm agents and makes it harder to navigate the surface.

    Completeness4/5

    The tool set provides extensive coverage of project management operations (CRUD for tasks, notes, memories, tags, etc.) with only minor gaps such as missing update/delete for discussions and file uploads.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to interact with OpenProject's API v3 for comprehensive project management operations including work packages, projects, time tracking, users, and all other OpenProject features through natural language.
      4
      MIT
    • A
      license
      B
      quality
      C
      maintenance
      Enables AI assistants to manage OpenProject work packages, projects, and time tracking. It provides comprehensive tools for creating, updating, and querying tasks and project metadata through the OpenProject API.
      11
      59 npm
      1
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI assistants to manage Todocko application data, including tasks, projects, worklogs, and attachments. It supports comprehensive project management operations such as tracking activity, managing Kanban boards, and handling shared project synchronization.
      1
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      Enables AI assistants to interact with the Worksection project management platform to manage projects, tasks, comments, and members through natural language. It provides a comprehensive suite of tools for task execution and project oversight while automatically handling API rate limits.
      21
      9 npm
      MIT