Skip to content

Conversation

sarahyun02
Copy link

@sarahyun02 sarahyun02 commented Sep 17, 2025

Description

  • Added search_issues tool in src/tools/search-issues.ts
  • Updated src/tools/index.ts to register the new tool

Usage

The tool can be used to search issues by text query.

Summary by CodeRabbit

  • New Features

    • Added an issue search tool that lets you find issues by a required search term, with optional limit, project filter, and workspace-wide toggle.
    • Returns results in a readable JSON format.
    • Automatically enabled alongside existing tools.
  • Bug Fixes

    • None.
  • Documentation

    • None.
  • Chores

    • Integrated the issue search capability into the default server tooling initialization for immediate availability.

Copy link

coderabbitai bot commented Sep 17, 2025

Walkthrough

Adds a new search_issues tool and registers it in the server initialization. The tool builds a query from provided parameters and issues a GET request to Plane’s issues search endpoint using the workspace slug from an environment variable, returning pretty-printed JSON as text content.

Changes

Cohort / File(s) Summary
Tool registration update
src/tools/index.ts
Imports registerSearchIssueTools and invokes registerSearchIssueTools(server) after project tools registration.
Search issues tool
src/tools/search-issues.ts
New module exporting registerSearchIssueTools(server). Registers search_issues tool with params: search (required), limit?, project_id?, workspace_search?. Constructs query via URLSearchParams, calls makePlaneRequest GET workspaces/${process.env.PLANE_WORKSPACE_SLUG}/issues/search/?…, returns pretty-printed JSON text.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as Client
  participant S as MCP Server
  participant T as search_issues Tool
  participant API as Plane API

  U->>S: invoke tool "search_issues"(search, limit?, project_id?, workspace_search?)
  S->>T: execute
  T->>T: Build URLSearchParams (search, limit?, project_id?, workspace_search?)
  T->>API: GET /workspaces/{PLANE_WORKSPACE_SLUG}/issues/search/?query
  API-->>T: JSON response
  T-->>S: Pretty-printed JSON (text)
  S-->>U: content: [{ type: "text", text }]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I twitch my ears at search so new,
A hop, a query—results in view!
With slug in paw and params tight,
I nose the API for data bright.
Thump-thump! The JSON’s crisp and clear—
Carrots for code, and bugs to fear. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "feat: add search issues tools" is concise, directly describes the primary change (adding the search-issues tool and registering it), and matches the files modified in the changeset, so it accurately summarizes the pull request's main purpose.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

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: 2

🧹 Nitpick comments (2)
src/tools/search-issues.ts (2)

8-10: Polish tool description for clarity.

Minor grammar tweak improves readability.

-    "Use this to search issues by text query. This requests project_id as uuid parameter. If you have a readable identifier for project, you can use the get_projects tool to get the project_id from it",
+    "Search issues by text query. The project_id parameter is a UUID. If you have a readable project identifier, use the get_projects tool to resolve its project_id.",

11-15: Tighten input validation (UUID, non-empty search, integer/positive limit, boolean coercion).

Prevents silent drops (e.g., limit=0), empty searches, and invalid IDs.

-      limit: z.number().describe("The number of issues to return").optional(),
-      project_id: z.string().describe("The uuid identifier of the project to search issues for").optional(),
-      search: z.string().describe("The search query"),
-      workspace_search: z.boolean().describe("Whether to search across all projects in the workspace").optional(),
+      limit: z.coerce.number().int().min(1).describe("Max issues to return (positive integer)").optional(),
+      project_id: z.string().uuid().describe("The UUID of the project to search within").optional(),
+      search: z.string().trim().min(1).describe("The search query (non-empty)"),
+      workspace_search: z.coerce.boolean().describe("Whether to search across all projects in the workspace").optional(),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1a199cd and d2841de.

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

10-10: Import looks correct and consistent with ESM .js extension.


19-19: Registration order LGTM — "search_issues" is registered only once.
Single registration found at src/tools/search-issues.ts:7-8 (server.tool("search_issues", ...)).

src/tools/search-issues.ts (1)

11-22: Confirm mutual-exclusivity of project_id vs workspace_search (or enforce XOR)

Repo tool currently sends both params (src/tools/search-issues.ts:11–22). Plane docs list standard issue endpoints but do not document an /issues/search endpoint, and there is a GH feature request for a search API — confirm the server semantics and either validate/reject when both project_id and workspace_search are provided or document which param wins when both are present. (docs.plane.so)

Comment on lines +19 to +22
if (limit) queryParams.set("limit", limit.toString());
if (project_id) queryParams.set("project_id", project_id);
if (workspace_search) queryParams.set("workspace_search", workspace_search.toString());
if (search) queryParams.set("search", search);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Don’t gate on truthiness; include false/0 and avoid dropping valid values.

Using truthy checks drops limit=0 and workspace_search=false. Prefer explicit undefined checks and always send the required search param.

-      if (limit) queryParams.set("limit", limit.toString());
+      if (limit !== undefined) queryParams.set("limit", String(limit));
       if (project_id) queryParams.set("project_id", project_id);
-      if (workspace_search) queryParams.set("workspace_search", workspace_search.toString());
-      if (search) queryParams.set("search", search);
+      if (workspace_search !== undefined) queryParams.set("workspace_search", String(workspace_search));
+      queryParams.set("search", search);
📝 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
if (limit) queryParams.set("limit", limit.toString());
if (project_id) queryParams.set("project_id", project_id);
if (workspace_search) queryParams.set("workspace_search", workspace_search.toString());
if (search) queryParams.set("search", search);
if (limit !== undefined) queryParams.set("limit", String(limit));
if (project_id) queryParams.set("project_id", project_id);
if (workspace_search !== undefined) queryParams.set("workspace_search", String(workspace_search));
queryParams.set("search", search);
🤖 Prompt for AI Agents
In src/tools/search-issues.ts around lines 19 to 22, the current truthy checks
drop valid falsy values like limit=0 and workspace_search=false and may omit the
required search param; change the guards to explicit undefined/null checks
(e.g., check for !== undefined && !== null) so limit and workspace_search are
set even when falsy, and always set the search query parameter (without gating
on truthiness) to ensure it is sent.

Comment on lines +24 to +27
const response = await makePlaneRequest(
"GET",
`workspaces/${process.env.PLANE_WORKSPACE_SLUG}/issues/search/?${queryParams.toString()}`
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Guard missing workspace slug and URL-encode it.

Without PLANE_WORKSPACE_SLUG this hits workspaces/undefined/…, yielding confusing failures. Also encode the slug for safety.

-      const response = await makePlaneRequest(
-        "GET",
-        `workspaces/${process.env.PLANE_WORKSPACE_SLUG}/issues/search/?${queryParams.toString()}`
-      );
+      const slug = process.env.PLANE_WORKSPACE_SLUG;
+      if (!slug) {
+        throw new Error("Environment variable PLANE_WORKSPACE_SLUG is required for search_issues.");
+      }
+      const path = `workspaces/${encodeURIComponent(slug)}/issues/search/?${queryParams.toString()}`;
+      const response = await makePlaneRequest("GET", path);
📝 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
const response = await makePlaneRequest(
"GET",
`workspaces/${process.env.PLANE_WORKSPACE_SLUG}/issues/search/?${queryParams.toString()}`
);
const slug = process.env.PLANE_WORKSPACE_SLUG;
if (!slug) {
throw new Error("Environment variable PLANE_WORKSPACE_SLUG is required for search_issues.");
}
const path = `workspaces/${encodeURIComponent(slug)}/issues/search/?${queryParams.toString()}`;
const response = await makePlaneRequest("GET", path);
🤖 Prompt for AI Agents
In src/tools/search-issues.ts around lines 24 to 27, the code uses
process.env.PLANE_WORKSPACE_SLUG directly when building the request path which
can produce confusing failures if the env var is missing and is unsafe for
special characters; add a guard that checks for the presence of
PLANE_WORKSPACE_SLUG and either throw a clear Error or return a rejected promise
if it's undefined/empty, and use
encodeURIComponent(process.env.PLANE_WORKSPACE_SLUG) when interpolating the slug
into the URL so the workspace slug is URL-encoded.

@sarahyun02 sarahyun02 marked this pull request as draft September 17, 2025 21:22
@sarahyun02
Copy link
Author

sarahyun02 commented Sep 17, 2025

In the example provided (pasted below), the endpoint did not include project_id in the path parameter and only had it as a query param.

   async ({ limit, project_id, search, workspace_search }) => {
      // send the params if not null as query string
      const queryParams = new URLSearchParams();
      if (limit) queryParams.set("limit", limit.toString());
      if (project_id) queryParams.set("project_id", project_id);
      if (workspace_search) queryParams.set("workspace_search", workspace_search.toString());
      if (search) queryParams.set("search", search);

      const response = await mcp.makePlaneRequest(
        "GET",
        `workspaces/${mcp.props.workspaceDetail.slug}/issues/search/?${queryParams.toString()}`,
      );
      return {
        content: [

When I follow the example implementation and test the workspace wide issue search, I get a 404 error.

curl -H 'X-API-Key: '\$PLANE_API_KEY 'http://plane-api:8000/api/v1/workspaces/'\$PLANE_WORKSPACE_SLUG'/issues/?search=test&limit=5'"

However, I find that using project_id in the path param correctly returns issues.

curl -H 'X-API-Key: '\$PLANE_API_KEY 'http://plane-api:8000/api/v1/workspaces/'\$PLANE_WORKSPACE_SLUG'/projects/74022669-4ec9-492d-852e-1738580ece65/issues/?search=test&limit=5'"

Is project_id is a required path parameter for the search? Any guidance is extremely appreciated. Thanks in advance.

@Prashant-Surya
Copy link
Member

@sarahyun02 looks like you missed search suffix to the workspace search endpoint

Example curl

curl -H 'X-API-Key: PLANE_API_KEY' http://plane-api:8000/api/v1/workspaces/<slug>/issues/search/?search=test&limit=5

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