Skip to main content
Glama

worksection-mcp

A Model Context Protocol (MCP) server for the Worksection project-management API. It speaks MCP over stdio, so any MCP-capable client can drive Worksection projects, tasks, subtasks, comments, tags, people, time tracking, files, search and reporting through a consistent set of tools.

Requirements

  • Python 3.11+

  • uv

  • A Worksection account, with either an admin API key or an OAuth2 application

Related MCP server: weeek-mcp

Install

git clone https://github.com/atlantdak/worksection-mcp.git
cd worksection-mcp
uv sync
uv run worksection-mcp

Configuration

All settings are read from environment variables (or a local .env file — see .env.example). None have a prefix.

Variable

Default

Purpose

AUTH_MODE

admin_key

admin_key (no browser flow) or oauth (per-user browser login)

WORKSECTION_ACCOUNT

(empty)

Bare account slug from https://<slug>.worksection.com (admin_key mode)

WORKSECTION_API_KEY

(empty)

Admin API key (admin_key mode)

OAUTH_CLIENT_ID

(unset)

OAuth2 application client id (oauth mode)

OAUTH_CLIENT_SECRET

(unset)

OAuth2 application client secret (oauth mode)

OAUTH_REDIRECT_PORT

18030

Loopback port the login listener binds to; 0 picks a free ephemeral port

FERNET_KEY

(unset)

Key used to encrypt stored OAuth tokens (oauth mode)

ALLOW_DESTRUCTIVE_OPERATIONS

false

Registers delete_task, delete_comment and delete_costs when true

FILE_WORKSPACE_DIR

(unset)

Absolute path to the only directory upload_file may read from

STATE_DIR

~/.worksection-mcp

Where tokens, certificates, cache and offloaded responses are stored

REQUEST_TIMEOUT_SECONDS

30

HTTP request timeout

MAX_RETRIES

3

Retry attempts for retryable HTTP failures

RATE_LIMIT_RPS

3

Outbound request rate limit

CACHE_ENABLED

true

Enables the in-process response cache

CACHE_TTL_SECONDS

60

Cache entry lifetime

OFFLOAD_THRESHOLD_BYTES

50000

Responses larger than this are written to disk instead of returned inline

LOG_LEVEL

INFO

Standard Python logging level

Authentication — two modes

Find your admin API key in Worksection under account settings, then set:

AUTH_MODE=admin_key
WORKSECTION_ACCOUNT=your-account
WORKSECTION_API_KEY=your-key

There is no browser step at all in this mode. The server authenticates every request directly with the key.

OAuth2 (per-user)

Register an OAuth2 application in Worksection, then set:

AUTH_MODE=oauth
OAUTH_CLIENT_ID=your-client-id
OAUTH_CLIENT_SECRET=your-client-secret
FERNET_KEY=your-generated-key

Generate the Fernet key with:

uv run python -m worksection_mcp.auth.token_store

Then call the worksection_login tool from your MCP client to complete the one-time login. A short-lived HTTPS listener starts on 127.0.0.1:18030 (configurable via OAUTH_REDIRECT_PORT) to receive the OAuth2 redirect. Its certificate is self-signed, so your browser will show a one-time warning before you can continue. Once authenticated, tokens are stored Fernet-encrypted with 0600 permissions under ~/.worksection-mcp/ (or STATE_DIR), and refreshed automatically as needed — no further browser interaction is required.

Two-factor authentication: if your Worksection account has two-factor authentication enabled, it affects only the one-time browser login step of OAuth2 mode — you complete the 2FA prompt in the browser exactly as you normally would. Nothing in this server touches, stores or bypasses your second factor. For a fully non-interactive setup, use admin API key mode, which needs no browser login at all.

Safety: destructive operations

ALLOW_DESTRUCTIVE_OPERATIONS defaults to false. While it is false, the destructive tools — delete_task, delete_comment and delete_costs — are not even listed to the connected client; they simply don't exist as far as the client can see. When it is set to true, they become available, and each additionally requires the caller to pass confirm: true before it will run. This two-layer guard exists specifically to protect against prompt-injection-driven data loss: a client has to be deliberately configured to allow destructive actions, and every individual call has to opt in explicitly.

Safety: file access

No tool accepts an arbitrary filesystem path. upload_file takes either inline base64 content or the name of a file inside the configured FILE_WORKSPACE_DIR — any path outside that directory, including via traversal or symlinks, is rejected. download_file returns attachment content inline as base64, capped at a maximum size, and never writes anything to disk.

Large responses

Responses larger than OFFLOAD_THRESHOLD_BYTES are written to disk instead of returned inline. The tool call instead gets back a summary containing a worksection://offload/... resource URI. The full content can be read back in bounded chunks with the read_offloaded_response tool, or fetched directly as an MCP resource.

Client configuration

Example configuration for an MCP client, using admin API key mode:

{
  "mcpServers": {
    "worksection": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/worksection-mcp", "run", "worksection-mcp"],
      "env": {
        "AUTH_MODE": "admin_key",
        "WORKSECTION_ACCOUNT": "your-account",
        "WORKSECTION_API_KEY": "your-key"
      }
    }
  }
}

Tools

Tool

Description

activate_project

Restore an archived project to active status.

add_costs

Log time (and optionally money) against a task.

add_task_tags

Add tags to a task, keeping the tags it already has.

archive_project

Close a project and move it to the archive. Reversible with activate_project.

auth_status

Report the active authentication mode and, in oauth mode, whether the server has stored login credentials. This reflects whether credentials are on file, not whether the access token happens to be fresh right now - an expired token is refreshed automatically as long as a refresh token is stored. Never returns token values.

complete_task

Mark a task as done, closing it in Worksection.

create_project

Create a project, optionally with a manager, description and dates.

create_subtask

Create a subtask under an existing task.

create_task

Create a task in a project, optionally assigned, dated and prioritised.

delete_comment (destructive)

Permanently delete a comment. Only available when ALLOW_DESTRUCTIVE_OPERATIONS=true, and requires confirm=true.

delete_costs (destructive)

Permanently delete a time entry. Only available when ALLOW_DESTRUCTIVE_OPERATIONS=true, and requires confirm=true.

delete_task (destructive)

Permanently delete a task. Only available when ALLOW_DESTRUCTIVE_OPERATIONS=true, and requires confirm=true.

download_file

Fetch one attachment and return it inline as base64. Refuses files larger than max_bytes instead of writing anywhere on disk.

get_activity_log

List recent account or project activity events over a date range.

get_all_tasks

List tasks across every project the account can see. Status and assignee filters are re-applied locally because the API's own filtering is unreliable for some combinations.

get_comments

List the comments on a task, oldest first.

get_contacts

List external contacts (clients) registered in the account.

get_costs

List logged time and cost entries, optionally scoped to a project or task, a date range, or one person.

get_member

Find one account member by email or id.

get_member_groups

List the member groups (teams) configured for the account.

get_members

List the people in the account with their ids, emails and roles.

get_overdue_tasks

List open tasks whose due date has passed, most overdue first.

get_project

Fetch a single project by id, including its status and dates.

get_project_groups

List the task groups (folders) configured inside a project.

get_project_members

List the people who have access to one project.

get_project_stats

Count a project's tasks by status and priority bucket.

get_projects

List projects visible to the authenticated account.

get_running_timers

List every timer currently running in the account.

get_subtasks

List the subtasks of a task.

get_tags

List the tag groups and tags configured for the account.

get_task

Fetch one task, optionally with its description text, files and subtasks.

get_task_files

List the files attached to a task, with their ids, names and sizes.

get_task_tags

List the tag names currently applied to a task.

get_tasks

List tasks inside one project, with local status and assignee filtering.

get_tasks_by_priority

Group tasks into high, normal and low priority buckets.

get_tasks_by_status

Group tasks by status, with counts and the tasks in each group.

get_team_workload

Group open and completed tasks by assignee across the account or one project.

get_time_report

Summarise logged time and money for an account, project or task over a date range, totalled per person.

health_check

Verify that the configured credentials can reach the Worksection API. Returns a status report instead of raising when the call fails.

list_workspace_files

List the files available in the configured workspace directory. Returns an empty list when FILE_WORKSPACE_DIR is not set.

post_comment

Add a comment to a task.

read_offloaded_response

Read one bounded chunk of a response that was too large to return inline. Use the resource_uri and total_chunks from the offload summary.

reopen_task

Reopen a previously completed task.

search_tasks

Search tasks by text, status, assignee, priority and due date, across the account or inside one project. Filtering is applied locally for reliability.

set_task_tags

Replace every tag on a task with the given list.

start_timer

Start a running timer on a task.

stop_timer

Stop the running timer on a task and store the elapsed time.

update_comment

Replace the text of an existing comment.

update_costs

Change the hours, comment, date or amount of an existing time entry.

update_project

Change a project's title, description, manager or dates.

update_subtask

Change the title, description, assignee, due date or priority of a subtask.

update_task

Change the title, description, assignee, dates or priority of a task.

upload_file

Attach a file to a task. Provide the content inline as base64, or name a file inside the configured workspace directory. Arbitrary filesystem paths are rejected.

validate_configuration

Report the server's effective configuration and the result of every local startup check. Contacts no external service and never returns secret values.

worksection_login

Start the OAuth2 browser login. Opens the authorization page, waits for the loopback redirect, and stores the resulting tokens encrypted on disk. Has nothing to do in admin_key mode and reports that instead of failing.

worksection_logout

Delete the stored OAuth tokens from disk. Only local credentials are removed; nothing in Worksection itself is affected.

Development

uv sync
uv run pytest
uv run ruff check .
uv run mypy
uv run python scripts/import_sweep.py
uv run python scripts/preflight.py

API limitations

Known quirks and undocumented behaviour of the upstream Worksection API, and how each was verified, are tracked in docs/API-LIMITATIONS.md.

Security

See SECURITY.md for the project's security posture and how to report a vulnerability.

Acknowledgments

This project's design was informed by ideas from a few existing community Worksection MCP servers, including novgorodskii/worksection-mcp-server, PavloPopravkin/worksection-mcp, and pbv7/worksection-mcp. Thanks to their authors for publishing their work. This codebase is an independent, from-scratch implementation, not a fork of any of them.

Licence

MIT

Available Tools

53 tools
activate_projectB

Restore an archived project to active status.

Inputs: project_id (required).

add_costsC

Log time (and optionally money) against a task.

Inputs: hours (required), task_id (required), project_id (required), date, +3 more.

add_task_tagsA

Add tags to a task, keeping the tags it already has.

Inputs: tags (required), task_id (required), project_id (required).

archive_projectA

Close a project and move it to the archive. Reversible with activate_project.

Inputs: project_id (required).

auth_statusA

Report the active authentication mode and, in oauth mode, whether the server has stored login credentials. This reflects whether credentials are on file, not whether the access token happens to be fresh right now - an expired token is refreshed automatically as long as a refresh token is stored. Never returns token values.

Inputs: no named parameters.

complete_taskB

Mark a task as done, closing it in Worksection.

Inputs: task_id (required), project_id (required).

create_projectB

Create a project, optionally with a manager, description and dates.

Inputs: title (required), text, due_date, start_date, +2 more.

create_subtaskB

Create a subtask under an existing task.

Inputs: title (required), task_id (required), project_id (required), text, +3 more.

create_taskC

Create a task in a project, optionally assigned, dated and prioritised.

Inputs: title (required), project_id (required), text, due_date, +5 more.

download_fileA

Fetch one attachment and return it inline as base64. Refuses files larger than max_bytes instead of writing anywhere on disk.

Inputs: file_id (required), task_id (required), project_id (required), max_bytes.

get_activity_logA

List recent account or project activity events over a date range.

Inputs: date_to, date_from, project_id.

get_all_tasksA

List tasks across every project the account can see. Status and assignee filters are re-applied locally because the API's own filtering is unreliable for some combinations.

Inputs: status, assignee_email.

get_commentsA

List the comments on a task, oldest first.

Inputs: task_id (required), project_id (required).

get_contactsA

List external contacts (clients) registered in the account.

Inputs: no named parameters.

get_costsB

List logged time and cost entries, optionally scoped to a project or task, a date range, or one person.

Inputs: date_to, task_id, date_from, project_id, +1 more.

get_memberA

Find one account member by email or id.

Inputs: email, member_id.

get_member_groupsB

List the member groups (teams) configured for the account.

Inputs: no named parameters.

get_membersA

List the people in the account with their ids, emails and roles.

Inputs: no named parameters.

get_overdue_tasksA

List open tasks whose due date has passed, most overdue first.

Inputs: project_id.

get_projectA

Fetch a single project by id, including its status and dates.

Inputs: project_id (required), include_extra.

get_project_groupsA

List the task groups (folders) configured inside a project.

Inputs: project_id (required).

get_project_membersA

List the people who have access to one project.

Inputs: project_id (required).

get_projectsC

List projects visible to the authenticated account.

Inputs: status, include_extra.

get_project_statsA

Count a project's tasks by status and priority bucket.

Inputs: project_id (required).

get_running_timersA

List every timer currently running in the account.

Inputs: no named parameters.

get_subtasksC

List the subtasks of a task.

Inputs: task_id (required), project_id (required).

get_tagsA

List the tag groups and tags configured for the account.

Inputs: no named parameters.

get_taskB

Fetch one task, optionally with its description text, files and subtasks.

Inputs: task_id (required), project_id (required), include_extra.

get_task_filesA

List the files attached to a task, with their ids, names and sizes.

Inputs: task_id (required), project_id (required).

get_tasksA

List tasks inside one project, with local status and assignee filtering.

Inputs: project_id (required), status, assignee_email.

get_tasks_by_priorityC

Group tasks into high, normal and low priority buckets.

Inputs: project_id.

get_tasks_by_statusB

Group tasks by status, with counts and the tasks in each group.

Inputs: project_id.

get_task_tagsA

List the tag names currently applied to a task.

Inputs: task_id (required), project_id (required).

get_team_workloadA

Group open and completed tasks by assignee across the account or one project.

Inputs: project_id.

get_time_reportA

Summarise logged time and money for an account, project or task over a date range, totalled per person.

Inputs: date_to, task_id, date_from, project_id, +2 more.

health_checkB

Verify that the configured credentials can reach the Worksection API. Returns a status report instead of raising when the call fails.

Inputs: no named parameters.

list_workspace_filesB

List the files available in the configured workspace directory. Returns an empty list when FILE_WORKSPACE_DIR is not set.

Inputs: no named parameters.

post_commentA

Add a comment to a task.

Inputs: text (required), task_id (required), project_id (required), hidden, +1 more.

read_offloaded_responseA

Read one bounded chunk of a response that was too large to return inline. Use the resource_uri and total_chunks from the offload summary.

Inputs: resource_uri (required), chunk_index.

reopen_taskC

Reopen a previously completed task.

Inputs: task_id (required), project_id (required).

search_tasksA

Search tasks by text, status, assignee, priority and due date, across the account or inside one project. Filtering is applied locally for reliability.

Inputs: text, limit, status, due_after, +4 more.

set_task_tagsA

Replace every tag on a task with the given list.

Inputs: tags (required), task_id (required), project_id (required).

start_timerC

Start a running timer on a task.

Inputs: task_id (required), project_id (required), user_email.

stop_timerA

Stop the running timer on a task and store the elapsed time.

Inputs: task_id (required), project_id (required), comment, user_email.

update_commentA

Replace the text of an existing comment.

Inputs: text (required), task_id (required), comment_id (required), project_id (required).

update_costsB

Change the hours, comment, date or amount of an existing time entry.

Inputs: cost_id (required), task_id (required), project_id (required), date, +3 more.

update_projectC

Change a project's title, description, manager or dates.

Inputs: project_id (required), text, title, due_date, +2 more.

update_subtaskB

Change the title, description, assignee, due date or priority of a subtask.

Inputs: task_id (required), project_id (required), subtask_id (required), text, +4 more.

update_taskB

Change the title, description, assignee, dates or priority of a task.

Inputs: task_id (required), project_id (required), text, title, +4 more.

upload_fileB

Attach a file to a task. Provide the content inline as base64, or name a file inside the configured workspace directory. Arbitrary filesystem paths are rejected.

Inputs: task_id (required), project_id (required), filename, content_base64, +1 more.

validate_configurationA

Report the server's effective configuration and the result of every local startup check. Contacts no external service and never returns secret values.

Inputs: no named parameters.

worksection_loginA

Start the OAuth2 browser login. Opens the authorization page, waits for the loopback redirect, and stores the resulting tokens encrypted on disk. Has nothing to do in admin_key mode and reports that instead of failing.

Inputs: timeout_seconds.

worksection_logoutA

Delete the stored OAuth tokens from disk. Only local credentials are removed; nothing in Worksection itself is affected.

Inputs: no named parameters.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    B3.1/5.0

    Scored across 53 tools

    Disambiguation3/5

    The read surface is dense: get_tasks, get_all_tasks, get_tasks_by_status, get_tasks_by_priority, get_overdue_tasks, and search_tasks all return task lists with overlapping filters/grouping, and get_costs/get_time_report plus auth_status/health_check/validate_configuration occupy similar niches. Descriptions are detailed enough to separate them, but an agent can easily pick the wrong variant.

    Naming Consistency4/5

    The vast majority use a clear verb_noun pattern (get_*, create_*, update_*), with state changes as verb_noun (complete_task, reopen_task, archive_project). Minor deviations like post_comment instead of create_comment, add_costs instead of create_cost, and noun-style auth_status/health_check keep it from a perfect 5.

    Tool Count1/5

    53 tools is far above the 3-15 well-scoped range and even above the 25+ 'too many' threshold; it is an extreme count for an MCP server. Many variants could be consolidated (e.g., task listing/grouping/search).

    Completeness4/5

    The surface covers the main Worksection workflow: projects, tasks, subtasks, comments, tags, files, time/costs, timers, members, and activity. The main gap is the lack of delete operations (tasks, projects, comments, files) and no ability to move a task between projects, but these are workable rather than blocking.

    Maintenance

    ActivitySlowing
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Local, read-only-by-default MCP server for Weeek that connects AI clients to your workspace over stdio, enabling listing projects, tasks, boards, members, and tags with opt-in write tools for task management.
      10
      66 npm
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables MCP clients to interact with the Crewmeister API over local stdio, covering operations for members, teams, time tracking, salary exports, and related platform resources.
      Apache 2.0