Skip to content

Conversation

@KurodaKayn
Copy link

@KurodaKayn KurodaKayn commented Oct 23, 2025

Description

This PR adds a new MCP tool list_project_issues to retrieve all issues for a specific project.

Background:
The current MCP server only provides tools to list issues within modules (list_module_issues) or cycles (list_cycle_issues), but lacks a general tool to list all issues in a project. This makes it difficult for LLM agents to:

  • Get an overview of all project issues
  • Filter issues by state (e.g., fetch all TODO/Backlog items)
  • Perform project-wide issue analysis

Changes:

  • Added list_project_issues tool in src/tools/issues.ts
  • Added IssuesResponse type definition matching Plane API response structure
  • Implemented field simplification (returns only id, name, sequence_id, state, priority, timestamps) to reduce token usage for LLM processing
  • Added explicit return types to comply with project ESLint rules (registerIssueTools(): void)
  • Improved tool description for get_issue_using_readable_identifier for clarity

API Usage Example:

// Get all issues for a project
await plane_list_project_issues({ 
  project_id: "d114da0c-2653-44d7-be88-d4aa78404388" 
})

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

After: New list_project_issues tool available

// Example: Fetch all TODO items in a project
// Step 1: Get project
const projects = await plane_get_projects();
const project = projects.find(p => p.name === "PM Bot");

// Step 2: Get states to find TODO state_id
const states = await plane_list_states({ project_id: project.id });
const todoState = states.find(s => s.name === "Todo");

// Step 3: Get all issues (NEW TOOL!)
const issues = await plane_list_project_issues({ project_id: project.id });

// Step 4: Filter by state
const todoIssues = issues.results.filter(issue => issue.state === todoState.id);
// Result: [{ name: "Todo list CRUD", sequence_id: 1, ... }, { name: "Todo list table design", sequence_id: 2, ... }]

Test Scenarios

Manual Testing:

  1. ✅ Built the project successfully (npm run build)
  2. ✅ Passed ESLint checks (npm run lint)
  3. ✅ Passed Prettier formatting (npm run format:check)
  4. ✅ Tested with Mastra AI agent to fetch TODO items from a real Plane project
  5. ✅ Verified the tool returns correct data structure matching IssuesResponse type
  6. ✅ Confirmed simplified issue fields reduce token usage while maintaining necessary information

Integration Testing:

  • Tested with an LLM agent (Qwen/Qwen2.5-7B-Instruct) via Mastra framework
  • Agent successfully called plane_list_project_issues with correct parameters
  • Agent successfully filtered issues by state to identify TODO items
  • Agent successfully presented results to user in a readable format

Code Quality:

# All checks passed
npm run lint      # ✅ No errors (only pre-existing warnings)
npm run format:check  # ✅ All files formatted correctly
npm run build     # ✅ TypeScript compilation successful

References

  • Related to common user requests for project-wide issue visibility
  • Complements existing list_module_issues and list_cycle_issues tools
  • Follows the same pattern as get_projects tool implementation (see src/tools/projects.ts)

Summary by CodeRabbit

  • New Features

    • Added a tool to list project issues with key details (ID, name, state, priority, counts, timestamps).
  • Documentation

    • Clarified descriptions and parameter text for issue identification and retrieval tools.
  • Chores / Style

    • Minor formatting tweaks and updated type annotations for internal tool registrations.

@coderabbitai
Copy link

coderabbitai bot commented Oct 23, 2025

Walkthrough

Added a new tool to list project issues with a compact response, introduced internal paginated/summary types, and applied explicit : void return type annotations to two public tool registration functions; also changed two string literals' quote style in a request helper.

Changes

Cohort / File(s) Summary
Formatting
src/common/request-helper.ts
Replaced single-quoted string literals with double-quoted literals in two GET-request conditionals. No behavioral change.
Issue tools & types
src/tools/issues.ts
Added type-only import for Issue; introduced internal types (IssueStateSummary, IssuePrioritySummary, IssueWithDetails, IssuesResponse); implemented list_project_issues tool returning { total_count, count, results } with simplified issue objects; clarified get_issue_using_readable_identifier descriptions; changed registerIssueTools signature to : void.
Module tools signature
src/tools/modules.ts
Added explicit : void return type to registerModuleTools function signature.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant MCP as MCP Server
    participant Tool as list_project_issues
    participant API as Project API

    Client->>MCP: Request list_project_issues (project_id, pagination)
    MCP->>Tool: Invoke tool with params
    Tool->>API: Fetch issues for project (paginated)
    API-->>Tool: Return paginated issue data
    Tool->>Tool: Map to compact issue shape (id, name, sequence_id, state, priority, created_at, updated_at)
    Tool-->>MCP: Return summary payload (total_count, count, results)
    MCP-->>Client: Respond with compacted issues
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Review attention: src/tools/issues.ts (mapping logic and types), registerIssueTools/registerModuleTools signature changes for exported API clarity.

Poem

🐇 I hopped through code, a tidy spree,
Fresh tools to fetch each issue tree,
Quotes aligned and types declared,
Slim results returned with care,
A rabbit's wink — the patch is free!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat: Add list_project_issues tool to fetch all issues in a project" directly and accurately describes the primary objective of the changeset. The title clearly identifies the main feature being introduced (a new list_project_issues tool) and its purpose (fetching all issues in a project). While the PR includes secondary changes such as formatting updates in request-helper.ts and explicit return type annotations, the title correctly focuses on the primary contribution. The title is concise, specific, and uses conventional commit format (feat:), making it immediately clear to teammates reviewing the commit history what the change accomplishes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@KurodaKayn KurodaKayn closed this Oct 23, 2025
@cursor
Copy link

cursor bot commented Oct 23, 2025

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: UUID References Hinder LLM Processing

The simplified issues object includes state and priority fields, but these are UUID references in the Issue type. According to the PR description's test scenario example, the code filters issues by comparing issue.state === todoState.id, which suggests these UUID values are being returned. However, this makes the returned data less useful for LLM processing (the stated goal of simplification) since the LLM would need to make additional calls to resolve what these UUIDs mean. The description and priority values (human-readable names/labels) would be more useful than their UUID references for the stated purpose of "reducing token usage and improving LLM processing."

Fix in Cursor Fix in Web

@KurodaKayn KurodaKayn reopened this Oct 23, 2025
@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Inconsistent Issue Data Mapping

The list_project_issues tool's simplifiedIssues mapping explicitly includes fields like state and priority that can be null or undefined from the API. This results in inconsistent data for the LLM, as these fields will always be present, potentially with null values, differing from other tools that return full issue objects.

Fix in Cursor Fix in Web

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/tools/issues.ts (1)

23-63: Consider exposing pagination information.

The implementation correctly fetches issues and simplifies the response to reduce token usage. However, the Plane API returns pagination fields (next_page_results, prev_page_results, next_cursor, prev_cursor) that are not exposed in the simplified response. For projects with many issues, this tool will only return the first page without indicating that more results exist.

Consider including pagination metadata in the response:

       return {
         content: [
           {
             type: "text",
             text: JSON.stringify(
               {
                 total_count: issuesResponse.total_count,
                 count: issuesResponse.count,
+                total_pages: issuesResponse.total_pages,
+                next_page_results: issuesResponse.next_page_results,
+                prev_page_results: issuesResponse.prev_page_results,
                 results: simplifiedIssues,
               },
               null,
               2
             ),
           },
         ],
       };

Additionally, you might want to add optional cursor or page parameters to the tool in a follow-up to enable paginated access for large result sets.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44c90b9 and 02145b5.

📒 Files selected for processing (3)
  • src/common/request-helper.ts (2 hunks)
  • src/tools/issues.ts (1 hunks)
  • src/tools/modules.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/tools/issues.ts (2)
src/schemas.ts (2)
  • Issue (38-68)
  • Issue (69-69)
src/common/request-helper.ts (1)
  • makePlaneRequest (3-36)
🔇 Additional comments (5)
src/common/request-helper.ts (1)

12-12: LGTM! Formatting consistency improvement.

The change from single quotes to double quotes for string literals improves consistency across the codebase.

Also applies to: 24-24

src/tools/modules.ts (1)

7-7: LGTM! Explicit return type annotation.

Adding the explicit void return type improves type safety and satisfies linting requirements.

src/tools/issues.ts (3)

5-5: LGTM! Type-only import pattern.

Using the type keyword for the Issue import is a good practice that helps with tree-shaking and clearly distinguishes type imports from value imports.


22-22: LGTM! Explicit return type annotation.

Adding the explicit void return type improves type safety and satisfies linting requirements, consistent with the change in src/tools/modules.ts.


67-70: LGTM! Improved parameter descriptions.

The enhanced descriptions clearly explain the readable identifier format (e.g., FIRST-123) and how to split it into project_identifier and issue_identifier, which will help LLM agents use this tool correctly.

Comment on lines 7 to 20
type IssuesResponse = {
grouped_by: null;
sub_grouped_by: null;
total_count: number;
next_cursor: string;
prev_cursor: string;
next_page_results: boolean;
prev_page_results: boolean;
count: number;
total_pages: number;
total_results: number;
extra_stats: null;
results: Issue[];
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Consider more flexible typing for nullable fields.

The IssuesResponse type definition hardcodes several fields as null (lines 8, 9, 18). If the Plane API can return non-null values for grouped_by, sub_grouped_by, or extra_stats in different contexts (e.g., when grouping is applied), the current typing will cause runtime type mismatches.

Consider using union types for these fields if they can have values:

 type IssuesResponse = {
-  grouped_by: null;
-  sub_grouped_by: null;
+  grouped_by: string | null;
+  sub_grouped_by: string | null;
   total_count: number;
   next_cursor: string;
   prev_cursor: string;
   next_page_results: boolean;
   prev_page_results: boolean;
   count: number;
   total_pages: number;
   total_results: number;
-  extra_stats: null;
+  extra_stats: Record<string, any> | null;
   results: Issue[];
 };

Please verify the Plane API documentation to confirm whether these fields can have non-null values.


🌐 Web query:

What are the possible values for grouped_by, sub_grouped_by, and extra_stats fields in Plane API issues endpoint response?

💡 Result:

Do you mean Plane (plane.so) API? I can look up the official docs and list the exact permitted values — want me to fetch that now?



---

🏁 Script executed:

```shell
#!/bin/bash
# Search for API response examples, fixtures, or references to grouped_by, sub_grouped_by, extra_stats
rg -nC5 "grouped_by|sub_grouped_by|extra_stats" --type=ts --type=js --type=json

Length of output: 2088



---

🏁 Script executed:

```shell
#!/bin/bash
# Check how IssuesResponse is used in the codebase
echo "=== Searching for IssuesResponse usage ==="
rg -nC3 "IssuesResponse" --type=ts --type=js

echo -e "\n=== Checking for makePlaneRequest calls to issues endpoint ==="
rg -nC5 "makePlaneRequest.*issues|/issues" --type=ts --type=js

echo -e "\n=== Looking for test files or mock data ==="
fd -e "test\|spec\|mock\|fixture" --type f

echo -e "\n=== Searching for any Plane API version info or documentation references ==="
rg -nC2 "plane\.so|developers\.plane|API.*version" --type=ts --type=js --type=md

Length of output: 9275



---

🏁 Script executed:

```shell
#!/bin/bash
# Check Plane source code for API response schemas
# Try to find issues API response definition
rg -nC5 "grouped_by|sub_grouped_by" --type=py --type=json -g "*.py" -g "*.json"

# Also check if there are any import statements or API schema definitions
echo -e "\n=== Checking for schema or serializer files ==="
fd -e "schema" -e "serializer" -e "response" | head -20

Length of output: 48



---

🌐 Web query:

```web
Plane API list issues endpoint response schema grouped_by sub_grouped_by

💡 Result:

The List Issues response includes top-level keys grouped_by and sub_grouped_by. Type: string | null — they contain the field name used to group results (or null when not grouped). Example (from Plane dummy response): "grouped_by": null, "sub_grouped_by": null. [1][2]

Sources:

  • Plane API — List issues (response/pagination description). [1]
  • Example/dummy JSON showing grouped_by and sub_grouped_by. [2]

Update field types to match Plane API schema.

The IssuesResponse type (lines 8, 9, 18) has types that are too narrow and don't match the documented Plane API response schema:

  • grouped_by and sub_grouped_by should be string | null per Plane API docs—they contain the grouping field name when grouping is applied, or null when not grouped
  • extra_stats should be Record<string, any> | null per API documentation (shown as {} in responses, not null)

The same issue exists in src/tools/projects.ts with the identical ProjectsResponse type definition.

Update both files:

 type IssuesResponse = {
-  grouped_by: null;
-  sub_grouped_by: null;
+  grouped_by: string | null;
+  sub_grouped_by: string | null;
   total_count: number;
   next_cursor: string;
   prev_cursor: string;
   next_page_results: boolean;
   prev_page_results: boolean;
   count: number;
   total_pages: number;
   total_results: number;
-  extra_stats: null;
+  extra_stats: Record<string, any> | null;
   results: Issue[];
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type IssuesResponse = {
grouped_by: null;
sub_grouped_by: null;
total_count: number;
next_cursor: string;
prev_cursor: string;
next_page_results: boolean;
prev_page_results: boolean;
count: number;
total_pages: number;
total_results: number;
extra_stats: null;
results: Issue[];
};
type IssuesResponse = {
grouped_by: string | null;
sub_grouped_by: string | null;
total_count: number;
next_cursor: string;
prev_cursor: string;
next_page_results: boolean;
prev_page_results: boolean;
count: number;
total_pages: number;
total_results: number;
extra_stats: Record<string, any> | null;
results: Issue[];
};
🤖 Prompt for AI Agents
In src/tools/issues.ts around lines 7 to 20, update the IssuesResponse type so
that grouped_by and sub_grouped_by are typed as string | null (they hold the
grouping field name or null) and change extra_stats to Record<string, any> |
null (API returns an object or null); apply the same changes to the identical
ProjectsResponse type in src/tools/projects.ts so both response types match the
Plane API schema.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/tools/issues.ts (1)

26-39: Update IssuesResponse type to match Plane API schema.

As noted in the previous review, the grouped_by, sub_grouped_by, and extra_stats fields are typed too narrowly:

  • grouped_by and sub_grouped_by should be string | null (they contain the grouping field name or null)
  • extra_stats should be Record<string, any> | null (API returns an object or null)
🧹 Nitpick comments (1)
src/tools/issues.ts (1)

42-100: Well-implemented token usage optimization.

The new list_project_issues tool effectively reduces token usage by mapping to a simplified structure with only essential fields. The fallback logic for state and priority details handles various API response shapes defensively.

Consider adding a brief comment explaining the priority fallback logic (lines 57-61), as the handling of both object and string priority values may not be immediately obvious:

      const simplifiedIssues = issuesResponse.results.map((issue) => {
        const stateDetail = issue.state_detail ?? null;
+       // Priority can be either a UUID string or an object with details
        const priorityDetail =
          issue.priority_detail ??
          (typeof issue.priority === "object" && issue.priority !== null
            ? (issue.priority as IssuePrioritySummary)
            : null);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02145b5 and 82d747c.

📒 Files selected for processing (1)
  • src/tools/issues.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/tools/issues.ts (2)
src/schemas.ts (2)
  • Issue (38-68)
  • Issue (69-69)
src/common/request-helper.ts (1)
  • makePlaneRequest (3-36)
🔇 Additional comments (3)
src/tools/issues.ts (3)

5-5: LGTM: Clean type/schema separation.

The type-only import and renaming convention clearly distinguishes the runtime schema from the type definition.


41-41: LGTM: Explicit return type improves clarity.

The explicit : void return type improves type safety and is consistent with similar tool registration functions in the codebase.


104-107: LGTM: Improved documentation clarity.

The enhanced descriptions with concrete examples (e.g., FIRST-123) make the readable identifier pattern immediately clear to users.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no bugs!


@Prashant-Surya Prashant-Surya self-requested a review October 27, 2025 07:26
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