Skip to content

Overhaul all API routes and tools against the current ClickUp API (v6.0.0) - #37

Closed
PiotrKrzyzek wants to merge 7 commits into
mainfrom
claude/clickup-api-routes-overhaul-t29gt0
Closed

PiotrKrzyzek wants to merge 7 commits into
mainfrom
claude/clickup-api-routes-overhaul-t29gt0

Conversation

@PiotrKrzyzek

@PiotrKrzyzek PiotrKrzyzek commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Description

Full audit and overhaul of the core server's HTTP layer, MCP tool schemas, and zod schemas against the current ClickUp REST API (v2 + v3). Every area was audited against the current OpenAPI specs (api-evangelist mirror, May 2026) plus current SDK/docs research, every finding was adversarially verified by an independent second pass, and only confirmed findings were applied (186 confirmed / 6 refuted out of ~192 reported).

Critical fixes

  • Task descriptions were silently lost: create/update sent markdown_content, but the API field is markdown_description (single + bulk paths).
  • Chat module rewritten for API v3 — previous v2-style paths (/team/{id}/chat/...) never existed; now /api/v3/workspaces/{workspace_id}/chat/... with correct bodies ({type, content}), {data, next_cursor} envelopes, and cursor pagination.
  • List-from-template paths fixed (/list/template/ → /list_template/, both variants always 404'd).
  • Goals key results: correct endpoints (POST /goal/{id}/key_result, PUT/DELETE /key_result/{id}), fields (steps_start/steps_end/steps_current/task_ids, note), {key_result} envelope, real type enum (percentage/automatic).
  • Webhooks: real 27-event enum + *, location scoping, full-body updates, real delivery payload schema ({webhook_id, event, history_items}), raw-body HMAC verification; removed fabricated get-by-id/events/ping/stats/retry endpoints.
  • Views: real filter grammar ({field, op, values} with EQ/ANY/ALL…), full-object PUT semantics, real settings/divide/columns fields, 0-indexed required page, Everything-level (team) views.
  • Attachments rebuilt around the two real endpoints: multipart POST /task/{id}/attachment (was sending JSON with base64) and v3 parent-entity listing; removed 13 tools calling invented endpoints.
  • Custom fields: removed field-definition create/update/delete tools (no such API exists), real type vocabulary, value_options (date time flag), workspace-level field listing.
  • Dependencies: correct depends_on vs dependency_of semantics (direction was inverted), query-param delete, reads via the task's dependencies/linked_tasks arrays; removed 11 fabricated endpoints.
  • Docs v3: create-doc body (parent{id,type}, visibility, create_page), next_cursor pagination (was silently restarting at page 1), real content_format values, content_edit_mode append/prepend, pageListing; removed unsupported update/delete/sharing/template tools.
  • Time tracking: single-object running-timer response (validation crashed before), end field on update, tag_action, required duration, start-timer body params.
  • Client/auth: OAuth Bearer vs raw pk_ token handling, Retry-After honored as a minimum wait, ECODE in errors, 429 retry.
  • Systemic: custom_task_ids/team_id support across task-scoped endpoints; several pagination fixes.

New tools (documented endpoints previously missing): workspace-wide task search, native task merge, task tag add/remove, task-from-template, get folder, folder-from-template, list members, space create/update/delete + space tag CRUD, team views, workspace custom fields, single time entry + time-entry tags, doc pageListing, whoami, user groups, workspace plan, custom roles.

~40 tools that could never succeed (fabricated endpoints) were removed rather than left to 404. The server now registers 157 tools, all backed by documented ClickUp endpoints. Versions bumped to 5.1.0; release notes and README counts updated.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected) — tools backed by nonexistent endpoints were removed, and several tool input shapes changed to match the real API

How Has This Been Tested?

  • npx jest in packages/core: 150/150 tests pass (10 suites, including updated assignee/merge/markdown/time tests)
  • Strict tsc --noEmit over src/clickup-client, src/schemas, src/utils: clean
  • Syntax parse of all 77 core source files: clean
  • Live MCP smoke test: server boots via stdio, completes initialize, and tools/list returns all 157 registered tools
  • Note: a full-project tsc including the tool files hits a pre-existing TypeScript type-instantiation blowup in the MCP SDK + zod generics (present on main; the intelligence package fails to build on main for the same reason) — unchanged by this PR

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have updated the RELEASE_NOTES.md file with details of changes
  • New and existing unit tests pass locally with my changes

🤖 Generated with Claude Code

https://claude.ai/code/session_01M18XtDQugWqcmBQLjhyjRo


Generated by Claude Code


Summary by cubic

Overhauled all API routes, tools, and schemas to match the current ClickUp REST API (v2/v3) in @chykalophia/clickup-mcp-server 6.0.0. Removed ~40 nonexistent endpoints, added missing features, fixed critical mismatches, standardized auth/pagination, and now register 157 tools; all 178 tests pass and team_id is enforced when custom_task_ids is used.

  • New Features

    • Chat v3: workspace-scoped routes, messages/replies/reactions, cursor pagination; channel listing supports description_format.
    • Tasks: native merge, tag add/remove, task-from-template, workspace task search.
    • Spaces: create/update/delete + space tag CRUD; lists/folders-from-template (with options.return_immediately), list members; team-level views.
    • Docs v3: parent{id,type} create, pageListing, content_format/content_edit_mode, cursor pagination.
    • Time tracking: running timer, single time entry CRUD, time-entry tags (updates accept start+duration and derive end).
  • Migration

    • Use task markdown_description; markdown_content is accepted (including empty strings to clear descriptions).
    • Chat: require post_data.subtype when sending posts (schema-enforced).
    • Webhooks: documented events/scoping; raw-body HMAC verification; fail-closed when validate_signature is true or signature/secret are missing; status filter uses health states.
    • Attachments: multipart task upload + v3 listing only; exactly one upload source; base64 size pre-check; URL downloads stream with a byte limit; file_path limited to canonical CLICKUP_UPLOAD_DIR; SSRF guard on file_url.
    • custom_task_ids: always provide team_id on task-scoped tools; bulk dependency ops accept per-item custom_task_ids/team_id (max 100).
    • Time tracking: tag_action is replace; create requires exactly one of end/duration; updates may send start+duration (end is derived); stop > start enforced.
    • Comments: create requires content (comment_text or structured blocks); blocks take precedence and empty arrays are rejected; updates allow resolve-only or assign-only and must include at least one update field.
    • Views: real filter grammar and full-object PUT semantics; duplicate-view guard for types the API cannot create.
    • Dependencies: direction semantics fixed; delete via query params; reads via dependencies/linked_tasks.
    • Dependencies: packages/intelligence peer range widened to ^5.0.0 || ^6.0.0.

Written for commit dbeee36. Summary will update on new commits.

Review in cubic

…(v5.1.0)

Audit of every route/tool against the current ClickUp REST API (v2 + v3
OpenAPI specs, May 2026), with independent adversarial verification of
each finding (186 confirmed). Fixes all confirmed request/response
mismatches, removes ~40 tools that called nonexistent endpoints, and
adds missing documented endpoints. Highlights:

- fix markdown_description on task create/update (descriptions were
  silently dropped), custom_fields JSON query filter, subtask pagination
- rewrite Chat for API v3 (workspaces-scoped paths, cursor pagination)
- fix list_template paths, goals key_result endpoints/fields/envelope,
  webhook events/scoping/payload schema, view filter grammar and
  full-object updates, dependency direction semantics
- rebuild attachments on the two real endpoints (multipart upload + v3
  listing); remove fabricated attachment/webhook/dependency/docs tools
- docs v3: parent-body create, next_cursor pagination, content_edit_mode
- custom_task_ids/team_id support across task-scoped endpoints
- OAuth Bearer vs personal token handling, Retry-After floor, ECODE
- new tools: filtered team tasks, task merge, task tags, space CRUD +
  space tags, team views, workspace fields, time-entry tags, doc
  pageListing, whoami, user groups, plan, custom roles

150/150 jest tests pass; server registers 157 tools via live MCP
handshake.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M18XtDQugWqcmBQLjhyjRo
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

This release aligns ClickUp schemas, clients, and MCP tools with revised v2/v3 API routes and response contracts. It adds resource operations, workspace-scoped requests, cursor pagination, custom task ID support, security and retry handling, and updates the project to version 6.0.0 with 157 registered tools.

Changes

API contracts and resource integrations
packages/core/src/schemas/*, packages/core/src/clickup-client/*|Schemas and clients now use revised ClickUp payloads, routes, response envelopes, authentication formatting, rate-limit handling, and resource-specific operations.|

|---|---|
|MCP tool wiring
packages/core/src/tools/*|Tool schemas and handlers expose revised chat, task, document, attachment, dependency, goal, view, webhook, time-entry, workspace, space, list, folder, and comment operations.|
|Validation and project metadata
packages/core/src/tests/*, README.md, RELEASE_NOTES.md, package.json, packages/core/package.json, packages/core/src/utils/*, jest.config.js, packages/core/jest.config.js|Merge tests, release notes, package versions, tool counts, markdown field naming, endpoint usage, error/retry behavior, and Jest transform settings are updated.|

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main change: a broad API/tool/schema overhaul for the current ClickUp API and version bump.
Description check ✅ Passed The description matches the changeset and objectives, covering the API audit, removed tools, added endpoints, tests, and version bump.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/clickup-api-routes-overhaul-t29gt0
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/clickup-api-routes-overhaul-t29gt0

Comment @coderabbitai help to get the list of available commands.

@amazon-q-developer amazon-q-developer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

I've reviewed this large API overhaul PR (57 files, 186 confirmed fixes). The changes correctly address critical issues including:

Critical Fixes Verified:

  • Task description field fix (markdown_content → markdown_description) - prevents silent data loss
  • Retry-After header handling now treats it as a minimum wait per RFC 9110, not a cap
  • ECODE preservation in error messages for debugging
  • Webhook signature validation uses timing-safe comparison
  • Custom fields JSON serialization for ClickUp API compatibility

Security & Error Handling:
The security implementations look solid:

  • HMAC signature validation with crypto.timingSafeEqual
  • Rate limiting with token-based buckets
  • Comprehensive error handling with retry logic
  • Input validation throughout

Test Coverage:
150/150 tests pass, including updated assignee/merge/markdown/time tests. The PR has been thoroughly validated.

The implementation follows documented ClickUp API patterns and removes ~40 fabricated endpoints that would have returned 404s. Overall, this is a well-executed API alignment effort that significantly improves reliability and correctness.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.


⚠️ This PR contains more than 30 files. Amazon Q is better at reviewing smaller PRs, and may miss issues in larger changesets.

Copy link
Copy Markdown
Contributor Author

Note on the CI failures (build 18.x / 20.x): both fail in packages/intelligence during npm install's prepare step — DetailedHealthMetrics missing properties, unresolved @chykalophia/clickup-mcp-shared, and MCP SDK zod overload errors — before packages/core is built. This is the same failure as the last 8+ CI runs on main (runs 45–52, all red); no error in the logs references packages/core. Core verification for this PR: 150/150 jest tests pass, strict typecheck of the client/schema/util layers is clean, and a live MCP stdio handshake registers all 157 tools. Fixing the intelligence package build is a separate work item.


Generated by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/tests/delete-merge-operations.test.ts (1)

91-96: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the merge tests exercise the production contract.

These assertions only validate local literals; they do not prove that the merge tool sends source_task_ids or emits the new confirmation text. Invoke the production request/tool path with a mocked client and assert the URL, body, and formatted response.

Also applies to: 121-127, 265-272

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/tests/delete-merge-operations.test.ts` around lines 91 -
96, Update the merge tests around the valid merge fixtures and the corresponding
cases at the other referenced sections to invoke the production merge
request/tool path with a mocked client instead of asserting local literals.
Verify the mocked call uses the expected URL and a body containing
source_task_ids, and assert the response includes the new confirmation text and
formatting.
🧹 Nitpick comments (2)
packages/core/src/schemas/attachments-schemas.ts (1)

9-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Schema does not enforce the documented "exactly one of file_data/file_path/file_url".

All three are optional(), so both "none" and "multiple" pass Zod. At-least-one is only caught later in resolveFileBytes (generic Error), and when several are supplied one is silently ignored by priority. A .refine() would surface a clear validation error at the boundary and match the comment.

♻️ Optional: enforce exactly-one
   team_id: z
     .string()
     .optional()
     .describe('Workspace ID (required when custom_task_ids is true)'),
-});
+}).refine(
+  d => [d.file_data, d.file_path, d.file_url].filter(v => v !== undefined).length === 1,
+  { message: 'Provide exactly one of file_data, file_path, or file_url' }
+);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/schemas/attachments-schemas.ts` around lines 9 - 27, Update
UploadAttachmentSchema to validate that exactly one of file_data, file_path, or
file_url is provided, rejecting both missing and multiple sources with a clear
validation error. Keep the existing field-level validations and descriptions
unchanged, and retain resolveFileBytes only for resolving the already-validated
source.
packages/core/src/clickup-client/secure-client.ts (1)

120-124: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Unbounded wait can stall requests indefinitely. waitForRateLimit polls every second with no ceiling, and the axios timeout only governs the HTTP round-trip — not this pre-request interceptor. Under sustained throttling, callers can block far longer than the configured timeout and queued requests accumulate with no signal. Consider a max total wait (then reject) plus small jitter to avoid synchronized polling.

♻️ Suggested cap
-  private async waitForRateLimit(): Promise<void> {
-    while (!rateLimiter.isAllowed(this.rateLimitKey, CLICKUP_TOKEN_RATE_LIMIT)) {
-      await new Promise(resolve => setTimeout(resolve, 1000));
-    }
-  }
+  private async waitForRateLimit(maxWaitMs = 60000): Promise<void> {
+    const deadline = Date.now() + maxWaitMs;
+    while (!rateLimiter.isAllowed(this.rateLimitKey, CLICKUP_TOKEN_RATE_LIMIT)) {
+      if (Date.now() >= deadline) {
+        throw new Error('Rate limit wait exceeded maximum duration');
+      }
+      await new Promise(resolve => setTimeout(resolve, 1000 + Math.random() * 250));
+    }
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/clickup-client/secure-client.ts` around lines 120 - 124,
Update waitForRateLimit to enforce a bounded total wait and reject once that
limit is exceeded, rather than polling indefinitely. Preserve the existing
rateLimiter.isAllowed check, and add small randomized jitter to the polling
delay to reduce synchronized retries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/clickup-client/attachments-enhanced.ts`:
- Around line 32-55: Update the headers configuration in uploadAttachment so the
Content-Type override uses false instead of undefined, clearing the Axios
instance-level application/json default and allowing FormData to set the
multipart boundary automatically.

In `@packages/core/src/clickup-client/views-enhanced.ts`:
- Line 286: Rename the unused parameter in the makeOverrides callback type from
current to _current, preserving the existing callback signature and return type
so it complies with the repository’s unused-argument convention.

In `@packages/core/src/clickup-client/webhooks-enhanced.ts`:
- Around line 80-82: Align the status filtering in the webhook retrieval flow
with ClickUp’s health states by updating WebhookFilter.status to use the active,
failing, and suspended values, or explicitly mapping inactive to the intended
non-active states before comparing with webhook.health?.status. Ensure filtering
no longer attempts to match inactive directly against ClickUp health statuses.
- Around line 112-121: Update updateWebhook so updateData.status falls back to
the fetched webhook’s current health?.status instead of the hardcoded 'active'
value when request.status is omitted, preserving inactive status during partial
updates.

In `@packages/core/src/schemas/webhook-schemas.ts`:
- Around line 105-113: Update ProcessWebhookSchema so validate_signature=true
requires both signature and secret, preventing requests from reaching
processWebhook with verification enabled but missing credentials. Preserve
optional signature and secret only when validation is explicitly disabled, and
ensure invalid combinations are rejected during schema validation.

In `@packages/core/src/tools/comment-tools.ts`:
- Around line 285-291: Require at least one of comment_text or comment in the
create_chat_view_comment, create_list_comment, and create_threaded_comment
validation/handler flows, rejecting requests where both are absent before
calling the API. Apply the checks at packages/core/src/tools/comment-tools.ts
lines 285-291, 342-348, and 453-459 respectively; leave clickup_update_comment
unchanged.

In `@README.md`:
- Around line 15-20: Replace every advertised “157+” tool count with the exact
registered count “157” to establish one source of truth. Update README.md at
lines 15-20, 47, 106, and 124, plus the descriptions in package.json lines 3-4
and packages/core/package.json lines 3-4; keep all surrounding descriptions
unchanged.

---

Outside diff comments:
In `@packages/core/src/tests/delete-merge-operations.test.ts`:
- Around line 91-96: Update the merge tests around the valid merge fixtures and
the corresponding cases at the other referenced sections to invoke the
production merge request/tool path with a mocked client instead of asserting
local literals. Verify the mocked call uses the expected URL and a body
containing source_task_ids, and assert the response includes the new
confirmation text and formatting.

---

Nitpick comments:
In `@packages/core/src/clickup-client/secure-client.ts`:
- Around line 120-124: Update waitForRateLimit to enforce a bounded total wait
and reject once that limit is exceeded, rather than polling indefinitely.
Preserve the existing rateLimiter.isAllowed check, and add small randomized
jitter to the polling delay to reduce synchronized retries.

In `@packages/core/src/schemas/attachments-schemas.ts`:
- Around line 9-27: Update UploadAttachmentSchema to validate that exactly one
of file_data, file_path, or file_url is provided, rejecting both missing and
multiple sources with a clear validation error. Keep the existing field-level
validations and descriptions unchanged, and retain resolveFileBytes only for
resolving the already-validated source.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6e27c92f-0a22-4131-bd29-aa6b679ee509

📥 Commits

Reviewing files that changed from the base of the PR and between 26f0db5 and c9b6323.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (56)
  • README.md
  • RELEASE_NOTES.md
  • package.json
  • packages/core/package.json
  • packages/core/src/clickup-client/attachments-enhanced.ts
  • packages/core/src/clickup-client/auth.ts
  • packages/core/src/clickup-client/chat-enhanced.ts
  • packages/core/src/clickup-client/checklists.ts
  • packages/core/src/clickup-client/comments-enhanced.ts
  • packages/core/src/clickup-client/comments.ts
  • packages/core/src/clickup-client/custom-fields-enhanced.ts
  • packages/core/src/clickup-client/dependencies-enhanced.ts
  • packages/core/src/clickup-client/docs-enhanced.ts
  • packages/core/src/clickup-client/docs.ts
  • packages/core/src/clickup-client/folders.ts
  • packages/core/src/clickup-client/goals-enhanced.ts
  • packages/core/src/clickup-client/index.ts
  • packages/core/src/clickup-client/lists.ts
  • packages/core/src/clickup-client/secure-client.ts
  • packages/core/src/clickup-client/spaces.ts
  • packages/core/src/clickup-client/tasks.ts
  • packages/core/src/clickup-client/time-tracking-enhanced.ts
  • packages/core/src/clickup-client/views-enhanced.ts
  • packages/core/src/clickup-client/webhooks-enhanced.ts
  • packages/core/src/index-efficiency-simple.ts
  • packages/core/src/schemas/attachments-schemas.ts
  • packages/core/src/schemas/chat-schemas.ts
  • packages/core/src/schemas/custom-field-schemas.ts
  • packages/core/src/schemas/dependencies-schemas.ts
  • packages/core/src/schemas/document-schemas.ts
  • packages/core/src/schemas/goals-schemas.ts
  • packages/core/src/schemas/response-schemas.ts
  • packages/core/src/schemas/task-schemas.ts
  • packages/core/src/schemas/time-tracking-schemas.ts
  • packages/core/src/schemas/views-schemas.ts
  • packages/core/src/schemas/webhook-schemas.ts
  • packages/core/src/tests/delete-merge-operations.test.ts
  • packages/core/src/tools/attachments-tools-setup.ts
  • packages/core/src/tools/bulk-task-tools.ts
  • packages/core/src/tools/chat-tools.ts
  • packages/core/src/tools/checklist-tools.ts
  • packages/core/src/tools/comment-tools.ts
  • packages/core/src/tools/custom-field-tools.ts
  • packages/core/src/tools/dependencies-tools-setup.ts
  • packages/core/src/tools/doc-tools-enhanced.ts
  • packages/core/src/tools/doc-tools.ts
  • packages/core/src/tools/goals-tools.ts
  • packages/core/src/tools/list-folder-tools.ts
  • packages/core/src/tools/space-tools.ts
  • packages/core/src/tools/task-tools.ts
  • packages/core/src/tools/time-tracking-tools.ts
  • packages/core/src/tools/views-tools-setup.ts
  • packages/core/src/tools/webhook-tools-setup.ts
  • packages/core/src/tools/workspace-tools.ts
  • packages/core/src/utils/error-handling.ts
  • packages/core/src/utils/markdown.ts
💤 Files with no reviewable changes (1)
  • packages/core/src/schemas/task-schemas.ts

Comment thread packages/core/src/clickup-client/attachments-enhanced.ts
Comment thread packages/core/src/clickup-client/views-enhanced.ts Outdated
Comment on lines 80 to 82
if (filter.status) {
params.append('status', filter.status);
webhooks = webhooks.filter(webhook => webhook.health?.status === filter.status);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

ClickUp webhook health status values active failing

💡 Result:

ClickUp monitors the health of webhooks to ensure reliable event delivery [1]. The health status of a webhook, which can be retrieved via the API, indicates its current operational state [1][2][3]. The primary health status values are: Active A webhook is considered active when it is healthy and successfully receiving events [1][4][5]. This status is maintained as long as your endpoint responds with a successful HTTP status code in a timely manner (under 7 seconds) [1][4]. Failing A webhook is marked as failing if it returns an unsuccessful HTTP status code or if a request takes longer than 7 seconds to complete [1][4][5]. ClickUp will retry delivery up to five times for each event before stopping delivery for that specific event [1]. If the endpoint recovers and begins sending successful responses, the webhook will automatically return to the active state, and the fail count will reset [1]. Suspended If a webhook continues to fail and its fail count reaches 100, it is marked as suspended [1][4][5]. Once suspended, ClickUp stops sending events to the endpoint [1]. Additionally, returning a 401 status code or receiving a 410 status code will cause the webhook to be immediately marked as suspended [1]. To reactivate a suspended webhook, you must update its status back to active using the PUT /api/v2/webhook/{webhook_id} request [1]. You can monitor the health status and the associated fail_count via the webhook object in the ClickUp API [1][2][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the target file around the reported lines.
sed -n '1,180p' packages/core/src/clickup-client/webhooks-enhanced.ts | cat -n

printf '\n---\n'

# Find the filter type definition and any related webhook health typing/usages.
rg -n "filter\.status|status:\s*'active'|'inactive'|health\?\.(status|state)|webhook health|WebhookHealth|health status" packages/core/src -S

printf '\n---\n'

# Locate the ClickUp webhook response types if they exist in the repo.
rg -n "interface .*Webhook|type .*Webhook|health" packages/core/src -S

Repository: Chykalophia/ClickUp-MCP-Server---Enhanced

Length of output: 11931


Align filter.status with ClickUp webhook health states
webhook.health?.status uses ClickUp’s health values (active, failing, suspended), so inactive will never match here. Either change WebhookFilter.status to the real health enum or map inactive explicitly to the intended non-active states.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/clickup-client/webhooks-enhanced.ts` around lines 80 - 82,
Align the status filtering in the webhook retrieval flow with ClickUp’s health
states by updating WebhookFilter.status to use the active, failing, and
suspended values, or explicitly mapping inactive to the intended non-active
states before comparing with webhook.health?.status. Ensure filtering no longer
attempts to match inactive directly against ClickUp health statuses.

Comment on lines 112 to +121
async updateWebhook(request: UpdateWebhookRequest): Promise<WebhookResponse> {
const updateData: Record<string, any> = {};

if (request.endpoint !== undefined) updateData.endpoint = request.endpoint;
if (request.events !== undefined) updateData.events = request.events;
if (request.health_check_url !== undefined) updateData.health_check_url = request.health_check_url;
if (request.secret !== undefined) updateData.secret = request.secret;
if (request.status !== undefined) updateData.status = request.status;
const current = await this.getWebhook(request.workspace_id, request.webhook_id);

const updateData = {
endpoint: request.endpoint ?? current.endpoint,
events: request.events ?? current.events,
// The list response does not include a status field; default to 'active'
// when the caller does not specify one.
status: request.status ?? 'active'
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

ClickUp API Update Webhook endpoint required status field behavior

💡 Result:

The ClickUp API Update Webhook endpoint (PUT /api/v2/webhook/{webhook_id}) supports the status field to manage the state of a webhook [1][2][3]. When updating a webhook, the status field allows you to explicitly set the webhook to active or inactive [1][2]. This is particularly useful for reactivating a webhook that has been automatically suspended by ClickUp due to health issues (e.g., if the webhook's fail_count reaches 100) [4]. Regarding its requirement behavior: - The status field is typically optional during a PUT update request [2][3]. You only need to include it in the JSON request body if you intend to change the current status [2]. - The API is designed to accept updates to specific fields (endpoint, events, or status) without requiring the entire object to be re-submitted [2]. To reactivate a suspended webhook, you must send a request with the status field set to "active" [4]. Failing to include the field or providing an invalid value while attempting to modify other properties will not affect the webhook's enabled state unless the field is explicitly provided [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== file outline ==\n'
ast-grep outline packages/core/src/clickup-client/webhooks-enhanced.ts --view expanded || true

printf '\n== relevant slices ==\n'
sed -n '1,220p' packages/core/src/clickup-client/webhooks-enhanced.ts | cat -n

printf '\n== status references ==\n'
rg -n "health\.status|status:|inactive|failing|active" packages/core/src/clickup-client -g '*.ts' -g '*.tsx' || true

Repository: Chykalophia/ClickUp-MCP-Server---Enhanced

Length of output: 11715


🌐 Web query:

ClickUp webhook health status values active failing inactive paused suspended list API

💡 Result:

According to ClickUp's official technical documentation regarding webhook health, webhooks primarily exist in the following states [1]: Active: The webhook is healthy, and ClickUp continues to send events to your endpoint as long as it responds with successful HTTP status codes in a timely manner [1]. Failing: A webhook is marked as failing if it returns an unsuccessful HTTP status code or if a request takes longer than 7 seconds to complete [1]. ClickUp will retry delivery up to five times for each event [1]. If the endpoint recovers and begins sending successful responses, the webhook automatically returns to the active state [1]. Suspended: A webhook is marked as suspended if the failure count reaches 100 or if the endpoint returns a 401 (Unauthorized) or 410 (Gone) HTTP status code [1]. Once suspended, ClickUp stops sending events [1]. To restore a suspended webhook, you must manually update its status back to active using the PUT /api/v2/webhook/{webhook_id} API endpoint [1]. While your query mentioned "inactive" and "paused," these specific status values are not listed in the official ClickUp webhook health documentation [1]. Official documentation focuses on the lifecycle of active, failing, and suspended states [1].

Citations:


🌐 Web query:

site:developer.clickup.com webhook health status active failing paused

💡 Result:

Webhook health statuses, such as active, failing, and paused (or suspended), are used by platforms to monitor the reliability and performance of webhook endpoints. While specific terminology and thresholds can vary by service, common definitions include: Active: The webhook is functioning correctly. The endpoint is responding to delivery attempts with successful HTTP status codes in a timely manner [1]. Failing: The endpoint is returning unsuccessful HTTP status codes or exceeding latency thresholds (e.g., timing out) [1]. Platforms typically implement retry logic for these events to account for temporary issues [1]. If the number of failures reaches a predefined limit, the status may transition to a more restrictive state, such as suspended or paused [1]. Paused or Suspended: The platform has stopped sending events to the endpoint [1]. This state is often triggered automatically if an endpoint consistently fails or returns specific error codes (e.g., 401 Unauthorized or 410 Gone) [1]. In many systems, a webhook must be manually reactivated by the user via an API call once the underlying issue is resolved [1]. Always consult the specific API documentation of the service you are using, as they may define their own unique thresholds and recovery processes for these statuses [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== webhook schema definitions ==\n'
sed -n '1,240p' packages/core/src/schemas/webhook-schemas.ts | cat -n

printf '\n== any status enums/usages in webhook schemas ==\n'
rg -n "status|WebhookFilter|UpdateWebhookRequest" packages/core/src/schemas/webhook-schemas.ts packages/core/src/schemas -g '*.ts' || true

Repository: Chykalophia/ClickUp-MCP-Server---Enhanced

Length of output: 8619


updateWebhook should preserve the current status on partial updates. status: request.status ?? 'active' will reactivate an inactive webhook when only endpoint or events changes. Use the fetched webhook’s current health?.status as the fallback, or require status explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/clickup-client/webhooks-enhanced.ts` around lines 112 -
121, Update updateWebhook so updateData.status falls back to the fetched
webhook’s current health?.status instead of the hardcoded 'active' value when
request.status is omitted, preserving inactive status during partial updates.

Comment thread packages/core/src/schemas/webhook-schemas.ts Outdated
Comment thread packages/core/src/tools/comment-tools.ts
Comment thread README.md Outdated
Comment on lines +15 to +20
A comprehensive Model Context Protocol (MCP) server suite providing AI assistants with complete ClickUp integration. Features **157+ core tools**, **AI-powered project intelligence**, **production-grade security**, and **full GitHub Flavored Markdown support**.

## 📦 Package Suite

### Core Server: `@chykalophia/clickup-mcp-server`
Complete ClickUp API integration with **177+ tools** covering all major functionality:
Complete ClickUp API integration with **157+ tools** covering all major functionality:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use one exact tool-count source of truth.

The PR states that the MCP server registers exactly 157 tools, but the README and both package manifests advertise 157+. Replace these claims with 157 or generate them from the registry.

  • README.md#L15-L20: update the core-server and package-suite descriptions.
  • README.md#L47-L47: update the architecture-tree count.
  • README.md#L106-L106: update the API-coverage count.
  • README.md#L124-L124: update the inventory heading.
  • package.json#L3-L4: update the root package description.
  • packages/core/package.json#L3-L4: update the core package description.
📍 Affects 3 files
  • README.md#L15-L20 (this comment)
  • README.md#L47-L47
  • README.md#L106-L106
  • README.md#L124-L124
  • package.json#L3-L4
  • packages/core/package.json#L3-L4
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 15 - 20, Replace every advertised “157+” tool count
with the exact registered count “157” to establish one source of truth. Update
README.md at lines 15-20, 47, 106, and 124, plus the descriptions in
package.json lines 3-4 and packages/core/package.json lines 3-4; keep all
surrounding descriptions unchanged.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

14 issues found across 57 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/src/schemas/chat-schemas.ts">

<violation number="1" location="packages/core/src/schemas/chat-schemas.ts:98">
P1: Sending a message or reply with initial reactions produces a request body with strings where ClickUp expects reaction objects, causing those requests to be rejected. Model `reactions` as the documented ChatReaction input shape in both schemas and tool signatures.</violation>
</file>

<file name="packages/core/src/clickup-client/docs-enhanced.ts">

<violation number="1" location="packages/core/src/clickup-client/docs-enhanced.ts:455">
P2: HTML page create/update/read requests fail because `text/html` is not a supported v3 Docs `content_format`. Remove the HTML alias/value from the Docs input schemas/types, or convert HTML to a supported representation before this request.</violation>
</file>

<file name="packages/core/src/clickup-client/docs.ts">

<violation number="1" location="packages/core/src/clickup-client/docs.ts:153">
P2: Doc-name searches miss matches beyond the first API page, and callers cannot continue because `clickup_search_docs` drops `next_cursor`. Fetch all pages before applying the client-side filter, or expose the returned cursor in the tool response.</violation>
</file>

<file name="packages/core/src/tools/checklist-tools.ts">

<violation number="1" location="packages/core/src/tools/checklist-tools.ts:144">
P2: Concurrent creates with the same name can resolve the wrong checklist item because this lookup is not an item identity. Determine the newly created ID from a pre-create snapshot (or remove the unsupported `resolved` create option) before sending the follow-up update.</violation>
</file>

<file name="packages/core/src/clickup-client/dependencies-enhanced.ts">

<violation number="1" location="packages/core/src/clickup-client/dependencies-enhanced.ts:152">
P2: Graph and conflict-check calls can report an empty/partial result as successful during auth, rate-limit, or server failures. Restrict this suppression to intended missing/inaccessible-neighbor responses and propagate other request errors.</violation>

<violation number="2" location="packages/core/src/clickup-client/dependencies-enhanced.ts:199">
P2: Long dependency chains can bypass circular-conflict detection because this call only loads ten levels before validating. Traverse until the relevant component is exhausted, or expose/document an explicit incomplete-result state instead of returning a definitive no-conflict result.</violation>
</file>

<file name="packages/core/src/schemas/views-schemas.ts">

<violation number="1" location="packages/core/src/schemas/views-schemas.ts:108">
P1: `clickup_create_view` can send only `name` and `type`, which the Create View API rejects because its configuration objects are required. Supply defaults for all required view sections in `createView` (or require them in this schema) before posting.</violation>
</file>

<file name="packages/core/src/tools/views-tools-setup.ts">

<violation number="1" location="packages/core/src/tools/views-tools-setup.ts:37">
P2: `clickup_create_view` advertises unsupported view types, and its input schema accepts them; calls such as `type: "table"` will be sent to the Create View endpoint and rejected. Limit this tool's create types to ClickUp's documented four values (or remove the unsupported types from its description and schema).</violation>

<violation number="2" location="packages/core/src/tools/views-tools-setup.ts:324">
P2: Duplicating an existing Form/Embed view now fails because `duplicateView` re-posts its unsupported source type to Create View. Validate the fetched type before creating, and return a clear unsupported-duplicate error (or implement a supported conversion).</violation>
</file>

<file name="packages/core/src/schemas/webhook-schemas.ts">

<violation number="1" location="packages/core/src/schemas/webhook-schemas.ts:62">
P2: Processing non-task webhooks drops the resource ID, so callers cannot identify the List, Goal, or key result that fired the event. Model and return resource IDs for all supported event families (or return the parsed payload/resource ID generically).</violation>
</file>

<file name="packages/core/src/tools/workspace-tools.ts">

<violation number="1" location="packages/core/src/tools/workspace-tools.ts:86">
P2: A malformed `workspace_id` can alter the authenticated request URL because this value is interpolated into a path without segment validation. Restrict path IDs (and apply the same schema to `clickup_get_custom_roles`) so `/`, `?`, and `#` cannot turn the fixed suffix into a query or traverse endpoint segments.</violation>
</file>

<file name="packages/core/src/tools/dependencies-tools-setup.ts">

<violation number="1" location="packages/core/src/tools/dependencies-tools-setup.ts:23">
P2: Custom-ID relationship calls accept `custom_task_ids: true` without `team_id`, then issue requests the API cannot resolve. Add conditional validation so these tools fail locally with the required workspace ID instead of sending an invalid relationship request.</violation>
</file>

<file name="packages/core/src/tools/attachments-tools-setup.ts">

<violation number="1" location="packages/core/src/tools/attachments-tools-setup.ts:30">
P2: Custom task-ID uploads fail at ClickUp when callers set `custom_task_ids: true` without `team_id`. Add cross-field validation requiring `team_id` for that mode so invalid tool calls fail before the HTTP request.</violation>
</file>

<file name="packages/core/src/clickup-client/attachments-enhanced.ts">

<violation number="1" location="packages/core/src/clickup-client/attachments-enhanced.ts:32">
P2: This public upload path has no 10/min upload limit, so callers can repeatedly trigger file reads/downloads and ClickUp uploads. Apply the existing upload rate limiter before resolving the file.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/core/src/clickup-client/attachments-enhanced.ts Outdated
Comment thread packages/core/src/clickup-client/attachments-enhanced.ts
Comment thread packages/core/src/clickup-client/attachments-enhanced.ts
Comment thread packages/core/src/schemas/webhook-schemas.ts
access: ViewAccessSchema.default('private'),
filters: z.array(ViewFilterSchema).optional(),
grouping: z.array(ViewGroupingSchema).optional(),
grouping: ViewGroupingSchema.optional(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: clickup_create_view can send only name and type, which the Create View API rejects because its configuration objects are required. Supply defaults for all required view sections in createView (or require them in this schema) before posting.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/schemas/views-schemas.ts, line 108:

<comment>`clickup_create_view` can send only `name` and `type`, which the Create View API rejects because its configuration objects are required. Supply defaults for all required view sections in `createView` (or require them in this schema) before posting.</comment>

<file context>
@@ -1,159 +1,137 @@
-  access: ViewAccessSchema.default('private'),
   filters: z.array(ViewFilterSchema).optional(),
-  grouping: z.array(ViewGroupingSchema).optional(),
+  grouping: ViewGroupingSchema.optional(),
+  divide: ViewDivideSchema.optional(),
   sorting: z.array(ViewSortingSchema).optional(),
</file context>

Comment thread packages/core/src/tools/doc-tools-enhanced.ts
Comment thread packages/core/src/clickup-client/time-tracking-enhanced.ts Outdated
Comment thread packages/core/src/clickup-client/folders.ts Outdated
Comment thread packages/core/src/tools/space-tools.ts
async checkDependencyConflicts(
check: DependencyConflictCheck
): Promise<DependencyConflictResponse> {
const graph = await this.getDependencyGraph({ task_id: check.task_id, depth: 10 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Long dependency chains can bypass circular-conflict detection because this call only loads ten levels before validating. Traverse until the relevant component is exhausted, or expose/document an explicit incomplete-result state instead of returning a definitive no-conflict result.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/clickup-client/dependencies-enhanced.ts, line 199:

<comment>Long dependency chains can bypass circular-conflict detection because this call only loads ten levels before validating. Traverse until the relevant component is exhausted, or expose/document an explicit incomplete-result state instead of returning a definitive no-conflict result.</comment>

<file context>
@@ -1,350 +1,272 @@
+  async checkDependencyConflicts(
+    check: DependencyConflictCheck
+  ): Promise<DependencyConflictResponse> {
+    const graph = await this.getDependencyGraph({ task_id: check.task_id, depth: 10 });
+    const existingKeys = new Set(graph.edges.map(edge => `${edge.task_id}->${edge.depends_on}`));
 
</file context>

Apply confirmed findings from CodeRabbit and cubic reviews:
- fail-closed webhook signature validation (signature+secret required
  when validate_signature is true); status filter uses ClickUp health
  states; partial webhook updates preserve suspended state
- multipart upload: Content-Type: false to clear the JSON default;
  upload size cap; SSRF guard on file_url; optional CLICKUP_UPLOAD_DIR
  root for file_path; exactly-one-source schema validation
- team_id required whenever custom_task_ids is true (tasks client,
  dependencies/attachments schemas, custom-field/checklist tools)
- time tracking: tag_action 'replace'; start/end sent as a pair on
  partial updates; stop>start and end/duration-exclusivity refinements
- comment create tools require comment_text or comment blocks
- Retry-After: HTTP-date parsing, no early retry beyond server delay
- manual_progress {current} and required location formatted_address
  custom-field value shapes; chat initial-reactions input removed
  (shape undocumented; dedicated reaction tool covers it)
- user-group filter sent as repeated group_ids params; per-instance
  rate-limit reset; encoded path segments on new routes; goal at_risk
  heuristic based on days remaining; doc parent_id/parent_type pairing;
  duplicate-view guard for non-creatable view types; exact 157 tool
  count in docs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M18XtDQugWqcmBQLjhyjRo

Copy link
Copy Markdown
Contributor Author

Review findings addressed in 47c6561.

Fixed (CodeRabbit + cubic): fail-closed webhook signature validation; webhook status filtering now uses ClickUp health states (active/failing/suspended); partial webhook updates no longer reactivate suspended webhooks; multipart upload uses Content-Type: false to clear the axios JSON default; upload size cap + SSRF guard on file_url + optional CLICKUP_UPLOAD_DIR root for file_path + exactly-one-source validation; team_id is now required whenever custom_task_ids is true (tasks client, dependency/attachment schemas, custom-field/checklist tools); time tracking gained tag_action: replace, start/end pairing on partial updates, and stop>start / end-vs-duration refinements; comment create tools require comment_text or comment blocks; Retry-After now parses HTTP-dates and never retries earlier than the server delay; manual_progress uses {current} and location values require formatted_address; user-group filters are sent as repeated group_ids params; per-instance rate-limit reset; encoded path segments on the new routes; _current lint fix; bounded rate-limit wait with jitter; doc parent_id/parent_type pairing; duplicate-view guard for non-creatable types; docs and manifests now state the exact 157 tool count.

Skipped, with reasons:

  • Create View requires config objects / only four types (cubic): contradicts the spec — Create View requires only name and type, and the endpoint accepts list, board, calendar, table, timeline, workload, activity, map, chat, and gantt per the current reference; verified during the audit.
  • text/html not a valid Docs content_format (cubic): text/html is listed in the v3 Get Page/Get Pages content_format values; kept.
  • v3 attachments entity_type should be tasks: independently verified the live values are attachments (tasks) and custom_fields — the code is correct as written.
  • Chat initial reactions shape: the documented shape is ambiguous, so the create/update-message reactions input was removed instead of guessing; the dedicated reaction endpoint/tool covers the use case.
  • Webhook processing should surface non-task resource IDs: the parsed history_items (with parent_id) are returned verbatim, so the resource ID is available to callers.
  • Dependency graph depth cap / error suppression, checklist create+resolved race, upload client-side rate limiter, docstring coverage: acknowledged as documented best-effort/design choices for this MCP surface rather than API-correctness issues.

Verification after fixes: full jest suite green (10 suites, 0 failures) and strict typecheck of the client/schema/util layers clean.


Generated by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/core/src/clickup-client/views-enhanced.ts (1)

132-135: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Translate numeric response view types before filtering or duplicating.

ViewResponse.type is numeric, but normalizeViewType() and the duplicate allowlist use string API tokens. Consequently, type-filtered getViews calls always return no views, and every duplicateView call rejects its source type before creating anything.

  • packages/core/src/clickup-client/views-enhanced.ts#L132-L135: map the requested token to its response type code, or map each response code to a token before comparison.
  • packages/core/src/clickup-client/views-enhanced.ts#L244-L263: map source.type to the documented create-view token before allowlist validation and assigning payload.type.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/clickup-client/views-enhanced.ts` around lines 132 - 135,
Translate numeric response view types to the string API tokens expected by
filtering and duplication. In
packages/core/src/clickup-client/views-enhanced.ts:132-135, compare requested
types against response type codes or normalize each response type before
filtering; in packages/core/src/clickup-client/views-enhanced.ts:244-263,
convert source.type to the documented create-view token before duplicate
allowlist validation and payload assignment.
packages/core/src/schemas/time-tracking-schemas.ts (1)

62-72: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate the interval when both start and stop are updated.

UpdateTimeEntrySchema accepts an input such as start: 2000, stop: 1000; mirror the create schema’s stop > start check when both fields are supplied, while preserving partial-update behavior when either is omitted.

Proposed validation adjustment
-}).refine((data) => data.duration === undefined || data.stop === undefined, {
-  message: 'Provide either duration or stop on update, not both',
-});
+}).superRefine((data, ctx) => {
+  if (data.duration !== undefined && data.stop !== undefined) {
+    ctx.addIssue({
+      code: z.ZodIssueCode.custom,
+      message: 'Provide either duration or stop on update, not both',
+    });
+  }
+  if (
+    data.start !== undefined &&
+    data.stop !== undefined &&
+    data.stop <= data.start
+  ) {
+    ctx.addIssue({
+      code: z.ZodIssueCode.custom,
+      message: 'Stop time must be after start time',
+    });
+  }
+});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/schemas/time-tracking-schemas.ts` around lines 62 - 72,
Update UpdateTimeEntrySchema’s existing refinement to validate that stop is
greater than start when both fields are provided, matching the create schema’s
interval validation. Preserve partial-update behavior by allowing either start
or stop to be omitted, while retaining the existing duration/stop exclusivity
check.
packages/core/src/tools/comment-tools.ts (1)

290-293: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Drop comment_text when structured blocks are supplied for updates.

clickup_update_comment forwards both fields, and CommentsEnhancedClient.updateComment prefers comment_text, so the structured comment payload is ignored when both are present. Remove comment_text in this path to match the documented precedence.

  • packages/core/src/tools/comment-tools.ts#L389-L392
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/tools/comment-tools.ts` around lines 290 - 293, Update the
comment parameter construction in packages/core/src/tools/comment-tools.ts at
lines 290-293, 350-353, 389-392, and 464-467 to remove comment_text whenever
structured comment blocks are supplied, ensuring
CommentsEnhancedClient.updateComment receives only the structured comment
payload and applies the documented precedence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/tools/comment-tools.ts`:
- Around line 386-388: Update the validation in clickup_update_comment so
requests that change only resolved or assignee proceed without comment_text or
comment blocks. Remove the unconditional body requirement, or apply it only when
neither non-body update field is supplied, while preserving validation for
requests with no update fields at all.

---

Outside diff comments:
In `@packages/core/src/clickup-client/views-enhanced.ts`:
- Around line 132-135: Translate numeric response view types to the string API
tokens expected by filtering and duplication. In
packages/core/src/clickup-client/views-enhanced.ts:132-135, compare requested
types against response type codes or normalize each response type before
filtering; in packages/core/src/clickup-client/views-enhanced.ts:244-263,
convert source.type to the documented create-view token before duplicate
allowlist validation and payload assignment.

In `@packages/core/src/schemas/time-tracking-schemas.ts`:
- Around line 62-72: Update UpdateTimeEntrySchema’s existing refinement to
validate that stop is greater than start when both fields are provided, matching
the create schema’s interval validation. Preserve partial-update behavior by
allowing either start or stop to be omitted, while retaining the existing
duration/stop exclusivity check.

In `@packages/core/src/tools/comment-tools.ts`:
- Around line 290-293: Update the comment parameter construction in
packages/core/src/tools/comment-tools.ts at lines 290-293, 350-353, 389-392, and
464-467 to remove comment_text whenever structured comment blocks are supplied,
ensuring CommentsEnhancedClient.updateComment receives only the structured
comment payload and applies the documented precedence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 61cfc791-19e0-4009-b7a2-929e250303df

📥 Commits

Reviewing files that changed from the base of the PR and between c9b6323 and 47c6561.

📒 Files selected for processing (27)
  • README.md
  • package.json
  • packages/core/package.json
  • packages/core/src/clickup-client/attachments-enhanced.ts
  • packages/core/src/clickup-client/auth.ts
  • packages/core/src/clickup-client/folders.ts
  • packages/core/src/clickup-client/index.ts
  • packages/core/src/clickup-client/lists.ts
  • packages/core/src/clickup-client/secure-client.ts
  • packages/core/src/clickup-client/tasks.ts
  • packages/core/src/clickup-client/time-tracking-enhanced.ts
  • packages/core/src/clickup-client/views-enhanced.ts
  • packages/core/src/clickup-client/webhooks-enhanced.ts
  • packages/core/src/schemas/attachments-schemas.ts
  • packages/core/src/schemas/chat-schemas.ts
  • packages/core/src/schemas/custom-field-schemas.ts
  • packages/core/src/schemas/dependencies-schemas.ts
  • packages/core/src/schemas/goals-schemas.ts
  • packages/core/src/schemas/time-tracking-schemas.ts
  • packages/core/src/schemas/webhook-schemas.ts
  • packages/core/src/tools/chat-tools.ts
  • packages/core/src/tools/checklist-tools.ts
  • packages/core/src/tools/comment-tools.ts
  • packages/core/src/tools/custom-field-tools.ts
  • packages/core/src/tools/doc-tools-enhanced.ts
  • packages/core/src/tools/space-tools.ts
  • packages/core/src/tools/time-tracking-tools.ts
💤 Files with no reviewable changes (2)
  • packages/core/src/schemas/chat-schemas.ts
  • packages/core/src/tools/chat-tools.ts
🚧 Files skipped from review as they are similar to previous changes (20)
  • package.json
  • packages/core/package.json
  • packages/core/src/tools/space-tools.ts
  • packages/core/src/tools/checklist-tools.ts
  • packages/core/src/clickup-client/index.ts
  • packages/core/src/schemas/attachments-schemas.ts
  • packages/core/src/clickup-client/secure-client.ts
  • packages/core/src/clickup-client/auth.ts
  • README.md
  • packages/core/src/clickup-client/lists.ts
  • packages/core/src/clickup-client/attachments-enhanced.ts
  • packages/core/src/tools/time-tracking-tools.ts
  • packages/core/src/clickup-client/webhooks-enhanced.ts
  • packages/core/src/schemas/webhook-schemas.ts
  • packages/core/src/schemas/dependencies-schemas.ts
  • packages/core/src/clickup-client/folders.ts
  • packages/core/src/tools/doc-tools-enhanced.ts
  • packages/core/src/tools/custom-field-tools.ts
  • packages/core/src/clickup-client/time-tracking-enhanced.ts
  • packages/core/src/clickup-client/tasks.ts

Comment thread packages/core/src/tools/comment-tools.ts Outdated
- clickup_update_comment: allow resolve-only/assign-only updates (the
  at-least-one-body guard had landed in the update handler by mistake);
  instead require at least one update field
- add the missing comment_text-or-blocks guard to
  clickup_create_threaded_comment, and drop comment_text whenever
  structured blocks are supplied so blocks take documented precedence
- UpdateTimeEntrySchema: validate stop > start when both are supplied

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M18XtDQugWqcmBQLjhyjRo

Copy link
Copy Markdown
Contributor Author

Second-pass findings addressed in fb00372: clickup_update_comment now accepts resolve-only/assign-only updates (the earlier guard had been misapplied to the update handler — good catch) and requires at least one update field; the missing guard was added to clickup_create_threaded_comment; comment_text is dropped whenever structured blocks are supplied so blocks take the documented precedence; and UpdateTimeEntrySchema validates stop > start when both are present.

One finding declined: "ViewResponse.type is numeric" — the view object's type is a string token (list, board, …) per the v2 spec and the code's ViewResponse interface; the numeric field is parent.type. The type filter and duplicate allowlist both compare string tokens consistently.

Comment-formatter tests (41/41) and the strict client/schema/util typecheck remain green.


Generated by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/core/src/tools/comment-tools.ts (2)

21-104: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject empty structured comment arrays.

The truthiness checks treat comment: [] as supplied. Unless commentBlocksSchema already uses .min(1), this can send an empty body or discard a valid comment_text because structured comments take precedence. Enforce a non-empty array in the shared schema and/or use comment?.length > 0 in these branches.

Proposed fix
-        if (!comment && !commentParams.comment_text) {
+        if (!comment?.length && !commentParams.comment_text) {
           throw new Error('Provide comment_text or comment blocks');
         }

-          ...(comment ? { comment: processCommentBlocks(comment), comment_text: undefined } : {}),
+          ...(comment?.length
+            ? { comment: processCommentBlocks(comment), comment_text: undefined }
+            : {}),

Also add .min(1) to commentBlocksSchema so task-comment creation cannot submit [].

Also applies to: 200-202, 231-234, 287-292, 347-352, 386-400, 473-478

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/tools/comment-tools.ts` around lines 21 - 104, Reject empty
structured comment arrays by adding a minimum length of one to the shared
commentBlocksSchema, and update every structured-comment precedence check in the
affected comment creation/update paths to require comment?.length > 0. Preserve
comment_text handling when comment is empty, while ensuring task-comment
requests cannot submit an empty array.

21-104: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject custom_task_ids=true without team_id.
buildTaskQueryString still serializes the invalid combination, and both task-comment read/create paths pass it through unchanged. Add a guard or shared refine so these requests fail fast before reaching ClickUp.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/tools/comment-tools.ts` around lines 21 - 104, The
buildTaskQueryString path must reject custom_task_ids=true when team_id is
absent instead of serializing the invalid combination. Add a shared validation
guard in buildTaskQueryString (or its common caller) that fails fast for this
combination, while preserving existing query generation for valid
custom_task_ids/team_id inputs and both task-comment read/create paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/tools/comment-tools.ts`:
- Around line 21-104: Reject empty structured comment arrays by adding a minimum
length of one to the shared commentBlocksSchema, and update every
structured-comment precedence check in the affected comment creation/update
paths to require comment?.length > 0. Preserve comment_text handling when
comment is empty, while ensuring task-comment requests cannot submit an empty
array.
- Around line 21-104: The buildTaskQueryString path must reject
custom_task_ids=true when team_id is absent instead of serializing the invalid
combination. Add a shared validation guard in buildTaskQueryString (or its
common caller) that fails fast for this combination, while preserving existing
query generation for valid custom_task_ids/team_id inputs and both task-comment
read/create paths.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ff113b9d-9367-45e9-a252-cd51a6c83b0c

📥 Commits

Reviewing files that changed from the base of the PR and between 47c6561 and fb00372.

📒 Files selected for processing (2)
  • packages/core/src/schemas/time-tracking-schemas.ts
  • packages/core/src/tools/comment-tools.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/schemas/time-tracking-schemas.ts

…n comment tools

- commentBlocksSchema requires at least one block; precedence checks use
  comment?.length so an empty array cannot discard comment_text
- buildTaskQueryString fails fast when custom_task_ids is set without
  team_id, matching the other task-scoped clients

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M18XtDQugWqcmBQLjhyjRo

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

14 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/src/tools/doc-tools-enhanced.ts">

<violation number="1" location="packages/core/src/tools/doc-tools-enhanced.ts:17">
P3: The tool now maintains local copies of document validation enums already exported by `document-schemas.ts`. Reuse `ContentFormatSchema` and `DocParentTypeFilterSchema` so future API-format changes cannot make tool validation diverge from the shared schemas.</violation>

<violation number="2" location="packages/core/src/tools/doc-tools-enhanced.ts:263">
P2: A failed initial-page request is reported as a failed document creation even though the document was already created. Preserve/return the created doc ID with a partial-success warning, or add compensating cleanup, so retries do not duplicate docs.</violation>

<violation number="3" location="packages/core/src/tools/doc-tools-enhanced.ts:267">
P2: Supplying both placement fields silently creates the doc in `space_id`, ignoring `folder_id`. Reject mutually exclusive placement inputs (and placement fields combined with explicit `parent`) so callers cannot create docs in an unintended location.</violation>
</file>

<file name="packages/core/src/schemas/webhook-schemas.ts">

<violation number="1" location="packages/core/src/schemas/webhook-schemas.ts:94">
P2: `clickup_get_webhooks` now rejects its advertised `inactive` filter, while callers cannot request `failing` or `suspended`. Align the MCP tool enum with this changed schema and the documented ClickUp health states.</violation>
</file>

<file name="packages/core/src/clickup-client/secure-client.ts">

<violation number="1" location="packages/core/src/clickup-client/secure-client.ts:407">
P2: Destroying one client clears rate-limit history for every live client using the same token, allowing another client to immediately exceed ClickUp's per-token limit. Keep shared bucket state until its normal expiry, or add ownership/reference tracking before resetting it.</violation>
</file>

<file name="packages/core/src/tools/checklist-tools.ts">

<violation number="1" location="packages/core/src/tools/checklist-tools.ts:139">
P2: Concurrent same-name creates can resolve the wrong checklist item: the follow-up selects by name and highest `orderindex`, not an ID returned for this request. Use an unambiguous created-item identifier (or a uniquely tagged temporary name) before issuing the resolve update.</violation>
</file>

<file name="packages/core/src/schemas/attachments-schemas.ts">

<violation number="1" location="packages/core/src/schemas/attachments-schemas.ts:13">
P1: Local uploads can exfiltrate arbitrary files readable by the MCP process, including traversal paths when `CLICKUP_UPLOAD_DIR` is unset. Enforce a mandatory upload root and validate a realpath against that root before reading `file_path`.</violation>
</file>

<file name="packages/core/src/tools/comment-tools.ts">

<violation number="1" location="packages/core/src/tools/comment-tools.ts:25">
P2: Empty `comment: []` passes tool validation but cannot create a body: task creation posts it, chat/list/thread creation fails, and update can silently do nothing. Require at least one block, or treat an empty array as absent before choosing it over `comment_text`.</violation>

<violation number="2" location="packages/core/src/tools/comment-tools.ts:93">
P3: Task-comment query serialization now has two independent implementations, so fixes to parameter semantics can drift between structured and text comment paths. Share one helper or route structured task-comment creation through the client.</violation>

<violation number="3" location="packages/core/src/tools/comment-tools.ts:172">
P2: Custom-ID task comment calls without `team_id` pass MCP validation and only fail after reaching ClickUp. Add an object-level refinement requiring `team_id` whenever `custom_task_ids` is true.</violation>
</file>

<file name="packages/core/src/schemas/chat-schemas.ts">

<violation number="1" location="packages/core/src/schemas/chat-schemas.ts:98">
P3: Message and reply creation drops triage metadata and initial reactions because these documented fields are absent from both request schemas. Add them to schemas and MCP tool parameter definitions so parsed requests retain and send them.</violation>
</file>

<file name="packages/core/src/schemas/goals-schemas.ts">

<violation number="1" location="packages/core/src/schemas/goals-schemas.ts:74">
P2: Create-key-result validation accepts requests ClickUp rejects when either step bound is omitted (and permits fractional values). Require both integer bounds so callers fail locally rather than after the API request.</violation>
</file>

<file name="packages/core/src/clickup-client/auth.ts">

<violation number="1" location="packages/core/src/clickup-client/auth.ts:301">
P2: Seat consumers will be typed to read `filled_member_seats`, but ClickUp returns `filled_members_seats`, so that property is undefined at runtime. Match the documented response key.</violation>
</file>

<file name="packages/core/src/clickup-client/attachments-enhanced.ts">

<violation number="1" location="packages/core/src/clickup-client/attachments-enhanced.ts:47">
P2: `clickup_upload_attachment` now has no local upload-rate limit, so callers can issue unlimited expensive file uploads. Apply the existing `DEFAULT_RATE_LIMITS.upload`/`rateLimiter` gate before the file is read or fetched.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

task_id: z.string().min(1).describe('The ID of the task to attach the file to'),
filename: z.string().min(1).describe('The name of the file, including its extension'),
file_data: z.string().optional().describe('Base64 encoded file contents for direct upload'),
file_path: z.string().optional().describe('Path to a local file to upload'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Local uploads can exfiltrate arbitrary files readable by the MCP process, including traversal paths when CLICKUP_UPLOAD_DIR is unset. Enforce a mandatory upload root and validate a realpath against that root before reading file_path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/schemas/attachments-schemas.ts, line 13:

<comment>Local uploads can exfiltrate arbitrary files readable by the MCP process, including traversal paths when `CLICKUP_UPLOAD_DIR` is unset. Enforce a mandatory upload root and validate a realpath against that root before reading `file_path`.</comment>

<file context>
@@ -1,382 +1,76 @@
+  task_id: z.string().min(1).describe('The ID of the task to attach the file to'),
+  filename: z.string().min(1).describe('The name of the file, including its extension'),
+  file_data: z.string().optional().describe('Base64 encoded file contents for direct upload'),
+  file_path: z.string().optional().describe('Path to a local file to upload'),
+  file_url: z
+    .string()
</file context>

Comment thread packages/core/src/clickup-client/attachments-enhanced.ts Outdated
Comment thread packages/core/src/clickup-client/attachments-enhanced.ts
async ({ workspace_id, doc_id }) => {
try {
const doc = await enhancedDocsClient.getDoc(workspace_id, doc_id);
const doc = await enhancedDocsClient.createDoc({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: A failed initial-page request is reported as a failed document creation even though the document was already created. Preserve/return the created doc ID with a partial-success warning, or add compensating cleanup, so retries do not duplicate docs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/tools/doc-tools-enhanced.ts, line 263:

<comment>A failed initial-page request is reported as a failed document creation even though the document was already created. Preserve/return the created doc ID with a partial-success warning, or add compensating cleanup, so retries do not duplicate docs.</comment>

<file context>
@@ -129,216 +160,159 @@ export function setupEnhancedDocTools(server: McpServer): void {
-    async ({ workspace_id, doc_id }) => {
-      try {
-        const doc = await enhancedDocsClient.getDoc(workspace_id, doc_id);
+        const doc = await enhancedDocsClient.createDoc({
+          workspace_id,
+          name,
</file context>

workspace_id,
name,
parent,
space_id,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Supplying both placement fields silently creates the doc in space_id, ignoring folder_id. Reject mutually exclusive placement inputs (and placement fields combined with explicit parent) so callers cannot create docs in an unintended location.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/tools/doc-tools-enhanced.ts, line 267:

<comment>Supplying both placement fields silently creates the doc in `space_id`, ignoring `folder_id`. Reject mutually exclusive placement inputs (and placement fields combined with explicit `parent`) so callers cannot create docs in an unintended location.</comment>

<file context>
@@ -129,216 +160,159 @@ export function setupEnhancedDocTools(server: McpServer): void {
+          workspace_id,
+          name,
+          parent,
+          space_id,
+          folder_id,
+          content,
</file context>

Comment thread packages/core/src/schemas/custom-field-schemas.ts Outdated
Comment thread packages/core/src/tools/time-tracking-tools.ts Outdated
* Build the query string for task-comment endpoints that support
* custom task IDs (custom_task_ids + team_id).
*/
function buildTaskQueryString(params: { custom_task_ids?: boolean; team_id?: number }): string {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Task-comment query serialization now has two independent implementations, so fixes to parameter semantics can drift between structured and text comment paths. Share one helper or route structured task-comment creation through the client.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/tools/comment-tools.ts, line 93:

<comment>Task-comment query serialization now has two independent implementations, so fixes to parameter semantics can drift between structured and text comment paths. Share one helper or route structured task-comment creation through the client.</comment>

<file context>
@@ -18,6 +18,90 @@ import { mcpError } from '../utils/error-handling.js';
+ * Build the query string for task-comment endpoints that support
+ * custom task IDs (custom_task_ids + team_id).
+ */
+function buildTaskQueryString(params: { custom_task_ids?: boolean; team_id?: number }): string {
+  const query = new URLSearchParams();
+  if (params.custom_task_ids) {
</file context>

assignee: z.string().optional(),
group_assignee: z.string().optional(),
followers: z.array(z.string()).optional(),
post_data: z.record(z.any()).optional(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Message and reply creation drops triage metadata and initial reactions because these documented fields are absent from both request schemas. Add them to schemas and MCP tool parameter definitions so parsed requests retain and send them.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/schemas/chat-schemas.ts, line 98:

<comment>Message and reply creation drops triage metadata and initial reactions because these documented fields are absent from both request schemas. Add them to schemas and MCP tool parameter definitions so parsed requests retain and send them.</comment>

<file context>
@@ -1,243 +1,257 @@
+  assignee: z.string().optional(),
+  group_assignee: z.string().optional(),
+  followers: z.array(z.string()).optional(),
+  post_data: z.record(z.any()).optional(),
 });
 
</file context>

Comment thread packages/core/src/schemas/chat-schemas.ts
Breaking-change semver: the overhaul removes ~40 nonfunctional tools and
changes tool input shapes, so the version is now 6.0.0 (was wrongly a
minor bump).

Review fixes:
- webhook tool status filter enum aligned with health states; scope IDs
  typed as strings
- markdown_content alias honored for empty strings (clearing descriptions)
- attachments: base64 size estimated before decoding; URL downloads
  streamed with a running byte limit; CLICKUP_UPLOAD_DIR checks use
  canonical realpaths (symlink-safe)
- docs: mutually exclusive placement inputs rejected; a failed initial
  page no longer masks successful doc creation (returns doc + warning)
- time tracking: start+duration updates derive the paired end;
  time-summary assignee validated as numeric ID list
- chat: post_data validated as {title, subtype{id}}; channel listing
  exposes description_format
- list-from-template exposes options.return_immediately
- bulk dependencies: per-item custom_task_ids/team_id support, capped at
  100 items
- custom fields: emoji rating capped at 5; set-value schema requires
  team_id with custom_task_ids
- seats guest fields typed for 'Infinity' on unlimited plans

Tests: ts-jest now runs transpile-only (diagnostics off) because
type-checking MCP tool files trips the pre-existing SDK+zod TS2589
instantiation-depth limit (same root cause as the main-branch build
failure); the earlier green runs were riding the ts-jest cache. With
tests actually executing, all 10 suites / 178 tests pass. Strict tsc
over client/schema/util layers remains the type gate (clean).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M18XtDQugWqcmBQLjhyjRo
@PiotrKrzyzek PiotrKrzyzek changed the title Overhaul all API routes and tools against the current ClickUp API (v5.1.0) Overhaul all API routes and tools against the current ClickUp API (v6.0.0) Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Cubic's second-round findings addressed in 5c3cbc3.

Fixed: semver corrected to 6.0.0 (the tool removals and input-shape changes are breaking — good catch); webhook tool status enum aligned with health states + scope IDs typed as strings; markdown_content: '' now clears descriptions; attachments harden further (base64 size estimated pre-decode, URL downloads streamed with a running byte cap, CLICKUP_UPLOAD_DIR compared via canonical realpaths); docs reject ambiguous placement inputs and report doc-created-but-page-failed as partial success with the doc ID; time tracking derives the paired end for start+duration updates and validates assignee ID lists; chat post_data validated as {title, subtype{id}} and channel listing exposes description_format; list-from-template exposes options.return_immediately; bulk dependencies gain per-item custom-ID support and a 100-item cap; emoji rating capped at 5; set-custom-field-value schema requires team_id with custom IDs; guest seat fields typed for 'Infinity'.

Also fixed along the way: the jest suite was silently riding the ts-jest cache past the pre-existing SDK+zod TS2589 instantiation-depth failure (the same root cause as the main build break). ts-jest now runs transpile-only, so all 10 suites actually execute: 178/178 tests pass (21 tests that never ran before now run). The strict tsc pass over the client/schema/util layers remains the type gate and is clean.

Declined, with reasons: empty comment: [] (already rejected by .min(1) since e7ea731); custom-ID task comments without team_id (fail-fast guard added in e7ea731's buildTaskQueryString); upload rate limiter and mandatory upload root (the MCP stdio server runs with the caller's own privileges — the caller already has this filesystem access; CLICKUP_UPLOAD_DIR remains available for shared deployments); required integer steps_start/steps_end (the spec marks both optional and fractional values are valid for currency key results); filled_members_seats spelling (the OpenAPI spec documents filled_member_seats; the tool passes the raw response through either way); checklist same-name race and dependency graph depth/error-suppression bounds (documented best-effort semantics); chat triage metadata (niche; can be added on request); local doc-tools content-format enum (intentionally wider than the shared schema to accept markdown/html aliases that are normalized before sending).


Generated by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
RELEASE_NOTES.md (1)

60-61: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Align the reported Jest count with the verified PR result.

The release notes say 150/150 tests pass, while the PR objectives state that 178 Jest tests pass. Update this to the actual verified count or clarify that 150 is only a subset.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@RELEASE_NOTES.md` around lines 60 - 61, Update the Jest test-count statement
in the release notes to reflect the verified 178/178 passing result, or
explicitly label 150 as a subset while preserving the other verification
details.
packages/core/src/clickup-client/webhooks-enhanced.ts (1)

173-174: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Fail closed when signature credentials are missing.

When validate_signature is true but signature or secret is absent, this condition skips validation and continues parsing the payload. Enforce the required fields inside processWebhook as well as in the MCP schema, returning an invalid result or throwing before parsing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/clickup-client/webhooks-enhanced.ts` around lines 173 -
174, Update processWebhook around the signature-validation branch to fail
closed: when validate_signature is true, require both signature and secret
before parsing the raw body, returning an invalid result or throwing if either
is missing. Ensure the MCP schema enforces these fields as required under the
same condition, while preserving normal parsing when validation is disabled.
🧹 Nitpick comments (1)
jest.config.js (1)

21-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Keep the transpile-only exception from masking tool-file type errors.

Both Jest configurations disable TypeScript diagnostics globally, while the documented separate typecheck does not clearly cover all changed tool files.

  • jest.config.js#L21-L27: scope the exception to the affected MCP files or add an explicit tool-file typecheck.
  • packages/core/jest.config.js#L16-L23: ensure the core tool files are included in CI typechecking rather than relying only on client/schema/utility checks.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jest.config.js` around lines 21 - 27, Limit the diagnostics:false exception
in jest.config.js to the affected MCP tool files, or add an explicit typecheck
covering those files. In packages/core/jest.config.js, update the CI
typechecking configuration to include the core tool files, not only clients,
schemas, and utilities; apply the corresponding changes at jest.config.js lines
21-27 and packages/core/jest.config.js lines 16-23.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/clickup-client/webhooks-enhanced.ts`:
- Around line 173-174: Update processWebhook around the signature-validation
branch to fail closed: when validate_signature is true, require both signature
and secret before parsing the raw body, returning an invalid result or throwing
if either is missing. Ensure the MCP schema enforces these fields as required
under the same condition, while preserving normal parsing when validation is
disabled.

In `@RELEASE_NOTES.md`:
- Around line 60-61: Update the Jest test-count statement in the release notes
to reflect the verified 178/178 passing result, or explicitly label 150 as a
subset while preserving the other verification details.

---

Nitpick comments:
In `@jest.config.js`:
- Around line 21-27: Limit the diagnostics:false exception in jest.config.js to
the affected MCP tool files, or add an explicit typecheck covering those files.
In packages/core/jest.config.js, update the CI typechecking configuration to
include the core tool files, not only clients, schemas, and utilities; apply the
corresponding changes at jest.config.js lines 21-27 and
packages/core/jest.config.js lines 16-23.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3beca62c-fd36-4de2-b0d0-45829ff59a74

📥 Commits

Reviewing files that changed from the base of the PR and between e7ea731 and 5c3cbc3.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (19)
  • RELEASE_NOTES.md
  • jest.config.js
  • package.json
  • packages/core/jest.config.js
  • packages/core/package.json
  • packages/core/src/clickup-client/attachments-enhanced.ts
  • packages/core/src/clickup-client/auth.ts
  • packages/core/src/clickup-client/docs-enhanced.ts
  • packages/core/src/clickup-client/lists.ts
  • packages/core/src/clickup-client/tasks.ts
  • packages/core/src/clickup-client/time-tracking-enhanced.ts
  • packages/core/src/clickup-client/webhooks-enhanced.ts
  • packages/core/src/schemas/chat-schemas.ts
  • packages/core/src/schemas/custom-field-schemas.ts
  • packages/core/src/schemas/dependencies-schemas.ts
  • packages/core/src/tools/chat-tools.ts
  • packages/core/src/tools/list-folder-tools.ts
  • packages/core/src/tools/time-tracking-tools.ts
  • packages/core/src/tools/webhook-tools-setup.ts
🚧 Files skipped from review as they are similar to previous changes (13)
  • packages/core/src/clickup-client/lists.ts
  • packages/core/src/clickup-client/auth.ts
  • packages/core/src/tools/webhook-tools-setup.ts
  • packages/core/src/schemas/chat-schemas.ts
  • packages/core/src/tools/list-folder-tools.ts
  • packages/core/src/tools/time-tracking-tools.ts
  • packages/core/src/clickup-client/attachments-enhanced.ts
  • packages/core/src/clickup-client/docs-enhanced.ts
  • packages/core/src/schemas/dependencies-schemas.ts
  • packages/core/src/clickup-client/time-tracking-enhanced.ts
  • packages/core/src/tools/chat-tools.ts
  • packages/core/src/clickup-client/tasks.ts
  • packages/core/src/schemas/custom-field-schemas.ts

…sing webhook signature credentials

The 6.0.0 bump broke npm install in CI: packages/intelligence pinned a
^5.0.0 peer on @chykalophia/clickup-mcp-server. Widen to ^5.0.0 || ^6.0.0.

Also from CodeRabbit review: processWebhook now throws when
validate_signature is true but signature/secret are missing (fail closed,
matching the schema-level refine), and RELEASE_NOTES reflects the actual
178/178 jest result.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M18XtDQugWqcmBQLjhyjRo

Copy link
Copy Markdown
Contributor Author

Addressed in 5d3cae0:

CI fix (new failure introduced by the 6.0.0 bump): the two build failures on 5c3cbc3 were not the pre-existing packages/intelligence tsc break — the 6.0.0 version bump made npm install itself fail with ERESOLVE, because packages/intelligence pins a ^5.0.0 peer on @chykalophia/clickup-mcp-server. Widened the peer range to ^5.0.0 || ^6.0.0 and updated the lockfile. With install unblocked, CI is expected to progress to the pre-existing intelligence build failure documented earlier (identical on main).

CodeRabbit round 4:

  • ✅ processWebhook now fails closed: requesting validate_signature without both signature and secret throws instead of silently skipping validation (matching the schema-level refine).
  • ✅ RELEASE_NOTES corrected to the verified 178/178 jest result.
  • ⏭️ Jest diagnostics: false scoping (nitpick): declined for now — the TS2589 instantiation-depth blowup comes from the SDK+zod generics used by every tool file, so a per-file exception list would cover essentially all of them. Type enforcement for the layers that can be checked (clients/schemas/utils) runs via the separate strict tsc pass, as documented in the config comment.

178/178 tests still pass after these changes.


Generated by Claude Code

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 21 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="jest.config.js">

<violation number="1" location="jest.config.js:27">
P3: Disabling ts-jest diagnostics (`diagnostics: false`) silences real type errors in test files, not just the pre-existing instantiation-depth issue. This makes it possible to merge code that breaks type correctness in tests without CI catching it. The comment explains the rationale for the pre-existing issue, but this is still a trade-off worth noting: if any test introduces a real type violation, it will pass silently.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/core/src/schemas/chat-schemas.ts Outdated
Comment thread jest.config.js
// Transpile-only: type-checking the MCP tool files trips a TypeScript
// instantiation-depth limit in the SDK+zod generics (same pre-existing
// issue as the full tsc build). Types are enforced separately via tsc.
diagnostics: false,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Disabling ts-jest diagnostics (diagnostics: false) silences real type errors in test files, not just the pre-existing instantiation-depth issue. This makes it possible to merge code that breaks type correctness in tests without CI catching it. The comment explains the rationale for the pre-existing issue, but this is still a trade-off worth noting: if any test introduces a real type violation, it will pass silently.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At jest.config.js, line 27:

<comment>Disabling ts-jest diagnostics (`diagnostics: false`) silences real type errors in test files, not just the pre-existing instantiation-depth issue. This makes it possible to merge code that breaks type correctness in tests without CI catching it. The comment explains the rationale for the pre-existing issue, but this is still a trade-off worth noting: if any test introduces a real type violation, it will pass silently.</comment>

<file context>
@@ -21,6 +21,10 @@ const config = {
+      // Transpile-only: type-checking the MCP tool files trips a TypeScript
+      // instantiation-depth limit in the SDK+zod generics (same pre-existing
+      // issue as the full tsc build). Types are enforced separately via tsc.
+      diagnostics: false,
       tsconfig: {
         module: 'esnext',
</file context>

ClickUp's PostDataCreate requires a subtype (its id comes from the Get
Post Subtype IDs endpoint), so an omitted subtype passed local validation
only to be rejected by the API. subtype is now required whenever post_data
is supplied, in both the request schemas and the MCP tool schemas; the
message *response* schema stays lenient since it validates ClickUp output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M18XtDQugWqcmBQLjhyjRo

Copy link
Copy Markdown
Contributor Author

cubic round 3, addressed in dbeee36:

  • ✅ post_data.subtype is now required (with its id from Get Post Subtype IDs) whenever post_data is supplied — applied to all three request schemas in chat-schemas.ts and the three matching MCP tool schemas in chat-tools.ts. The message response schema keeps subtype lenient since it validates ClickUp's output rather than ours.
  • ⏭️ diagnostics: false in jest configs: acknowledged trade-off, declined for now — same rationale as the previous round. The SDK+zod TS2589 instantiation-depth blowup affects the tool files that every test suite imports, so per-file scoping wouldn't meaningfully narrow the exception; the layers that can be strictly checked (clients/schemas/utils) are covered by the separate tsc pass.

178/178 tests still pass.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Superseded by #41. All of this branch's commits (c9b6323…dbeee36) are merged into dev and ship as part of the consolidated v6.0.0 release PR #41 (dev → main), which also carries issue #35, the intelligence + core build fixes, and all Dependabot security bumps. Closing here so the release goes through the single dev → main PR. The bot-review history from this PR was all addressed and is reflected in #41.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants