Skip to main content
Glama
project-manager

project-manager

by samrullo

What is this project

This project implements stdio MCP server, so that Claude can search data by sending requests to an API backend running on localhost:8000

Documentation: docs/ — implementation overview and full pm_* tool reference.

This is the entry point for your MCP server. Breaking it down:

@click.command() + @click.option — CLI interface with two flags:

  • --base-url: override the API URL without changing env vars (e.g. --base-url http://staging:8000)

  • --transport: how Claude communicates with the server — stdio (default, used by Claude Desktop via stdin/stdout pipes), sse or streamable-http for network-based transports

def main(...):

  1. Creates a ProjectManagerClient — your HTTP client that talks to the FastAPI backend

  2. Calls build_mcp(client) — registers all the pm_* tools with the MCP framework, wrapping the client's methods as Claude-callable tools

  3. mcp.run(transport=transport) — starts the server loop, listening for tool calls from Claude

  4. client.close() in finally — cleanly shuts down the HTTP client when the process exits

Why stdio is the default: Claude Desktop launches this as a subprocess and communicates via stdin/stdout pipes — no network port needed. The sse/streamable-http options would be for remote deployments where Claude connects over HTTP instead.

In short: this boots the bridge between Claude and your project manager API, using whichever communication channel fits the deployment context.

How to register this local MCP server with Claude Desktop

You add below into mcpServers section of %APPDATA%\Claude\claude_desktop_config.json

What does this achieve in %APPDATA%\Claude\claude_desktop_config.json

 "project-manager": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "c:\\Users\\amrusub\\programming\\pet_projects\\project_manager_mcp",
        "project-manager-mcp"
      ],
      "env": {
        "PROJECT_MANAGER_API_BASE": "http://127.0.0.1:8000"
      }
    }
  },

This registers a local MCP server called "project-manager" with Claude Desktop. Here's what each part does:

command: "uv" — uses uv (the fast Python package manager) to run the server

args — tells uv to run the project-manager-mcp entry point from your local project directory at c:\Users\amrusub\programming\pet_projects\project_manager_mcp

env — sets an environment variable so the MCP server knows to talk to your locally running API at http://127.0.0.1:8000

Net effect: When Claude Desktop starts, it spins up your local project-manager-mcp Python process in the background. Claude then gets access to whatever tools that server exposes (in your case, the project-manager:pm_* tools visible in this conversation — create tasks, list projects, manage users, etc.), all backed by your local FastAPI server on port 8000.

So it's essentially a bridge: Claude ↔ MCP server process ↔ your local REST API.

Available Tools

46 tools
pm_create_commentD

POST /comments — TaskCommentCreate.

Inputs: payload (required), x_user_id. Returns: result

pm_create_organizationD

POST /organizations — OrganizationCreate {name}.

Inputs: payload (required), x_user_id. Returns: result

pm_create_projectC

POST /projects — body matches ProjectCreate (name, description_md, owner, optional slug, color_key, sort_order, settings_json, owner_user_id).

Inputs: payload (required), x_user_id. Returns: result

pm_create_tagB

POST /tags — TagCreate (name, optional project_id).

Inputs: payload (required), x_user_id. Returns: result

pm_create_taskC

POST /tasks — TaskCreate (project_id, title, short_name, plus optional fields).

Inputs: payload (required), x_user_id. Returns: result

pm_create_teamB

POST /teams — TeamCreate {name, optional organization_id}.

Inputs: payload (required), x_user_id. Returns: result

pm_create_userB

POST /users — admin only. UserCreate: display_name; optional email, phone, avatar_url, presence, role (admin|member), user_kind (internal|client), organization_id, team_id.

Inputs: payload (required), x_user_id. Returns: result

pm_create_user_labelC

POST /user-labels — UserLabelCreate {name}.

Inputs: payload (required), x_user_id. Returns: result

pm_delete_commentC

DELETE /comments/{comment_id}.

Inputs: comment_id (required), x_user_id. Returns: result

pm_delete_projectD

DELETE /projects/{project_id}.

Inputs: project_id (required), x_user_id. Returns: result

pm_delete_project_fileD

DELETE /projects/{project_id}/files/{file_id}.

Inputs: file_id (required), project_id (required), x_user_id. Returns: result

pm_delete_tagD

DELETE /tags/{tag_id}.

Inputs: tag_id (required), x_user_id. Returns: result

pm_delete_taskC

DELETE /tasks/{task_id}.

Inputs: task_id (required), x_user_id. Returns: result

pm_delete_userC

DELETE /users/{user_id} — admin only.

Inputs: user_id (required), x_user_id. Returns: result

pm_delete_user_labelD

DELETE /user-labels/{label_id}.

Inputs: label_id (required), x_user_id. Returns: result

pm_download_project_fileA

GET /projects/{project_id}/files/{file_id}/download — returns JSON with content_base64, content_type, size_bytes.

Inputs: file_id (required), project_id (required), x_user_id. Returns: result

pm_export_users_csvC

GET /users/export.csv — CSV export; fields is comma-separated column names; same filters as pm_list_users.

Inputs: fields, team_id, label_id, label_ids, +3 more. Returns: result

pm_export_users_joinedA

GET /users/export/joined — plain text; field: display_name|email|phone; separator: comma|semicolon; same filters as pm_list_users.

Inputs: field, team_id, label_id, label_ids, +4 more. Returns: result

pm_get_organizationD

GET /organizations/{organization_id}.

Inputs: organization_id (required), x_user_id. Returns: result

pm_get_projectD

GET /projects/{project_id}.

Inputs: project_id (required), x_user_id. Returns: result

pm_get_tagD

GET /tags/{tag_id}.

Inputs: tag_id (required), x_user_id. Returns: result

pm_get_taskC

GET /tasks/{task_id}.

Inputs: task_id (required), x_user_id. Returns: result

pm_get_teamC

GET /teams/{team_id}.

Inputs: team_id (required), x_user_id. Returns: result

pm_get_userC

GET /users/{user_id}.

Inputs: user_id (required), x_user_id. Returns: result

pm_get_user_labelD

GET /user-labels/{label_id}.

Inputs: label_id (required), x_user_id. Returns: result

pm_healthB

GET /health — API liveness.

Inputs: no named parameters. Returns: result

pm_list_commentsC

GET /comments?task_id=...

Inputs: task_id (required), x_user_id. Returns: result

pm_list_organizationsD

GET /organizations.

Inputs: x_user_id. Returns: result

pm_list_project_filesC

GET /projects/{project_id}/files.

Inputs: project_id (required), x_user_id. Returns: result

pm_list_projectsB

GET /projects — list projects (optional include_archived).

Inputs: x_user_id, include_archived. Returns: result

pm_list_tagsC

GET /tags — optional project_id or global_only.

Inputs: x_user_id, project_id, global_only. Returns: result

pm_list_tasksC

GET /tasks — filters optional. task_status: todo|in_progress|blocked|done|cancelled; priority: low|medium|high|urgent.

Inputs: tag_id, priority, x_user_id, project_id, +5 more. Returns: result

pm_list_teamsB

GET /teams — optional organization_id filter.

Inputs: x_user_id, organization_id. Returns: result

pm_list_user_labelsA

GET /user-labels — list global contact labels (not task tags).

Inputs: x_user_id. Returns: result

pm_list_usersA

GET /users — optional filters. user_kind: internal|client; label_ids: comma-separated UUIDs (OR); do not combine label_id and label_ids.

Inputs: team_id, label_id, label_ids, user_kind, +2 more. Returns: result

pm_task_attach_tagC

POST /tasks/{task_id}/tags — body {tag_id: ...}; tag_id also accepted as top-level arg for convenience.

Inputs: tag_id (required), task_id (required), x_user_id. Returns: result

pm_task_detach_tagC

DELETE /tasks/{task_id}/tags/{tag_id}.

Inputs: tag_id (required), task_id (required), x_user_id. Returns: result

pm_update_commentD

PATCH /comments/{comment_id}.

Inputs: payload (required), comment_id (required), x_user_id. Returns: result

pm_update_projectC

PATCH /projects/{project_id} — partial ProjectUpdate fields.

Inputs: payload (required), project_id (required), x_user_id. Returns: result

pm_update_project_fileB

PATCH /projects/{project_id}/files/{file_id} — partial ProjectFileUpdate (name, description_md, kind).

Inputs: file_id (required), payload (required), project_id (required), x_user_id. Returns: result

pm_update_tagD

PATCH /tags/{tag_id}.

Inputs: tag_id (required), payload (required), x_user_id. Returns: result

pm_update_taskC

PATCH /tasks/{task_id} — partial TaskUpdate.

Inputs: payload (required), task_id (required), x_user_id. Returns: result

pm_update_userA

PATCH /users/{user_id} — partial UserUpdate; requires X-User-Id (self or admin). Fields: display_name, email, phone, avatar_url, presence, role, user_kind, organization_id, team_id.

Inputs: payload (required), user_id (required), x_user_id. Returns: result

pm_upload_project_fileD

POST /projects/{project_id}/files — multipart upload; file bytes as standard base64.

Inputs: filename (required), project_id (required), file_content_base64 (required), kind, +3 more. Returns: result

pm_user_attach_labelC

POST /users/{user_id}/labels — admin only; attach a contact label to a user.

Inputs: user_id (required), label_id (required), x_user_id. Returns: result

pm_user_detach_labelC

DELETE /users/{user_id}/labels/{label_id} — admin only.

Inputs: user_id (required), label_id (required), x_user_id. Returns: result

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    C2.5/5.0

    Scored across 46 tools

    Disambiguation5/5

    Each tool targets a distinct resource and action (e.g., pm_create_comment vs pm_create_task). The names and descriptions make it clear which entity is being operated on, with no overlapping functionality. The distinction between pm_list_tags and pm_list_user_labels is explicit.

    Naming Consistency5/5

    All tools follow the consistent pattern `pm_verb_noun`. Verbs are standard (create, get, list, update, delete, upload, download, export, attach, detach) and nouns correspond to resources. No mixed conventions or vague names.

    Tool Count2/5

    46 tools is well above the typical well-scoped range (3-15). Even for a comprehensive project manager, this number is high and may overwhelm agents. It borders on excessive, as per calibration (25+ is too many).

    Completeness3/5

    The server covers CRUD for many entities (projects, tasks, comments, tags, users, files) but lacks update operations for organizations, teams, and user labels. Also team and organization deletion are missing. These are notable gaps that agents may encounter.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers