Skip to content

feat: MCP write tools -- add_repository, index, directories, delete (OPE-165)#287

Merged
DevanshuNEU merged 3 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:feat/mcp-write-tools
Mar 7, 2026
Merged

feat: MCP write tools -- add_repository, index, directories, delete (OPE-165)#287
DevanshuNEU merged 3 commits into
OpenCodeIntel:mainfrom
DevanshuNEU:feat/mcp-write-tools

Conversation

@DevanshuNEU

@DevanshuNEU DevanshuNEU commented Mar 7, 2026

Copy link
Copy Markdown
Collaborator

What

4 new MCP tools for managing repositories directly from Claude conversations:

Tool Backend Endpoint Purpose
add_repository POST /repos Clone and register a repo
get_repo_directories GET /repos/{id}/directories List dirs for subset selection
index_repository POST /repos/{id}/index Trigger indexing (with optional include_paths)
delete_repository DELETE /repos/{id} Remove repo and all indexed data

Why

MCP only had read tools. To add/index a repo, you had to go to the dashboard. Now we can do everything from Claude -- true dogfooding.

Changes

  • api_client.py: Added api_delete method
  • tools.py: 4 new tool schemas with LLM-friendly descriptions
  • handlers.py: 4 new handler functions with formatted responses
  • tests/test_tools.py: Updated EXPECTED_TOOLS set

Testing

45 tests pass, flake8 clean.

Workflow after merge

> Use codeintel to add https://github.com/OpenCodeIntel/opencodeintel
> Use codeintel to list directories for repo <id>
> Use codeintel to index repo <id> with include_paths backend, frontend
> Use codeintel to search for 'auth middleware' in repo <id>

Summary by CodeRabbit

  • New Features
    • Added repository management: add repositories (Git URL, branch), list repository directories, index repositories (optional path filtering, sync/async), and delete repositories.
  • Tests
    • Updated tests to include the new repository tools and validate repo-related tool behaviors.

…OPE-165)

4 new MCP tools so we can manage repos without leaving the conversation:

- add_repository: POST /repos (name, git_url, branch)
- get_repo_directories: GET /repos/{repo_id}/directories
- index_repository: POST /repos/{repo_id}/index (with optional include_paths)
- delete_repository: DELETE /repos/{repo_id}

Also adds api_delete to the HTTP client.
All 45 tests pass, lint clean.
@vercel

vercel Bot commented Mar 7, 2026

Copy link
Copy Markdown

@DevanshuNEU is attempting to deploy a commit to the Dev's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Mar 7, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@DevanshuNEU has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 46 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bb1100e7-159f-4911-bbc3-652eff16a824

📥 Commits

Reviewing files that changed from the base of the PR and between 2e48561 and 429a7ba.

📒 Files selected for processing (1)
  • mcp-server/handlers.py
📝 Walkthrough

Walkthrough

Added repository-management tools and handlers plus an API client DELETE helper: new tool schemas and tests for add/get directories/index/delete repository operations; handlers wired into the dispatch map call the API client (including new api_delete) to interact with backend repo and indexing endpoints.

Changes

Cohort / File(s) Summary
API Enhancement
mcp-server/api_client.py
Added api_delete(path: str, **kwargs) -> dict to send DELETE requests using the shared HTTP client; improved close_client() to lock, close, and clear the global client safely.
Handlers
mcp-server/handlers.py
Added four async handlers: _handle_add_repository, _handle_get_repo_directories, _handle_index_repository, _handle_delete_repository; wired them into the _HANDLERS dispatch mapping and imported api_delete.
Tools / Schemas
mcp-server/tools.py
Added four write-oriented tool schemas: add_repository, get_repo_directories, index_repository, delete_repository with input validation (git_url, name, branch, repo_id, include_paths).
Tests
mcp-server/tests/test_tools.py
Updated EXPECTED_TOOLS and repo-requirement checks to include the new tool identifiers: add_repository, get_repo_directories, index_repository, delete_repository.

Sequence Diagram(s)

sequenceDiagram
  participant User as Client
  participant Handler as MCP Handler
  participant APIClient as api_client.get_client()/api_delete
  participant Backend as Repo Backend
  User->>Handler: invoke tool (e.g., delete_repository repo_id)
  Handler->>APIClient: DELETE /repos/{repo_id}
  APIClient->>Backend: HTTP DELETE /repos/{repo_id}
  Backend-->>APIClient: 200 OK / 204 No Content (JSON or empty)
  APIClient-->>Handler: parsed JSON or {}
  Handler-->>User: formatted status string/result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit pads through lines of code,
I add, I list, I index, I unload.
Delete with care, clone with glee,
Repositories hop back to me. 🐇

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: four new MCP write tools for repository management (add, index, directories, delete).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 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.

@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: 3

🧹 Nitpick comments (1)
mcp-server/api_client.py (1)

61-66: Consider handling DELETE responses that return no body.

The backend currently returns JSON, but DELETE endpoints sometimes return 204 No Content with an empty body. Calling response.json() on an empty response would raise an exception.

🛡️ Defensive fix for empty responses
 async def api_delete(path: str, **kwargs: Any) -> dict:
     """Make a DELETE request to the backend API."""
     client = await get_client()
     response = await client.delete(path, **kwargs)
     response.raise_for_status()
-    return response.json()
+    if response.status_code == 204 or not response.content:
+        return {}
+    return response.json()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mcp-server/api_client.py` around lines 61 - 66, The api_delete function
currently calls response.json() which will raise if the DELETE returns 204 No
Content or an empty body; update api_delete (and keep using get_client and
response.raise_for_status) to defensively handle empty responses by checking
response.status_code (or response.content/response.text) and returning an empty
dict (or None per contract) when there's no body, otherwise parse and return
response.json(); ensure the behavior is consistent with other API helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@mcp-server/handlers.py`:
- Around line 84-110: The handler _handle_add_repository reads the wrong
response key for the repository identifier: it uses result.get("id", ...) which
the backend returns as "repo_id"; update the code to read repo_id =
result.get("repo_id", "unknown") (and ensure any other references to
result.get("id") in that function are replaced) so the returned guidance string
(including the index_repository(repo_id='...') hint) contains the real repo id.
- Around line 130-156: The handler _handle_index_repository is reading the wrong
response field and is sending an unsupported include_paths body to the sync
index endpoint; change the response mapping to use result.get("functions",
result.get("functions_indexed", 0)) for fn_count (and keep file_count fallback
as-is), and stop sending include_paths to POST /repos/{repo_id}/index (remove
include_paths from params) — if include_paths support is required, call the
async endpoint "/repos/{repo_id}/index/async" instead and pass include_paths
inside the JSON payload (e.g. use api_post(f"/repos/{repo_id}/index/async",
json={ "include_paths": include_paths }) when include_paths is present).

In `@mcp-server/tests/test_tools.py`:
- Around line 18-21: The test test_repo_tools_require_repo_id is missing the new
tools in its repo_tools list; update the repo_tools variable inside
test_repo_tools_require_repo_id to include "get_repo_directories",
"index_repository", and "delete_repository" alongside the existing
"add_repository" so the schema validation covers these tools that require
repo_id.

---

Nitpick comments:
In `@mcp-server/api_client.py`:
- Around line 61-66: The api_delete function currently calls response.json()
which will raise if the DELETE returns 204 No Content or an empty body; update
api_delete (and keep using get_client and response.raise_for_status) to
defensively handle empty responses by checking response.status_code (or
response.content/response.text) and returning an empty dict (or None per
contract) when there's no body, otherwise parse and return response.json();
ensure the behavior is consistent with other API helpers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 45ca7132-f732-485c-baf8-d4f78c3ed173

📥 Commits

Reviewing files that changed from the base of the PR and between c20384e and fc281f7.

📒 Files selected for processing (4)
  • mcp-server/api_client.py
  • mcp-server/handlers.py
  • mcp-server/tests/test_tools.py
  • mcp-server/tools.py

Comment thread mcp-server/handlers.py
Comment thread mcp-server/handlers.py
Comment thread mcp-server/tests/test_tools.py
…defensive delete

- handlers.py: add_repository reads result.get('repo_id') not 'id'
  (backend returns 'repo_id')
- handlers.py: index_repository uses /index/async when include_paths
  set (sync endpoint doesn't accept include_paths), reads 'functions'
  not 'function_count'
- api_client.py: api_delete handles 204/empty body gracefully
- test_tools.py: repo_tools list includes new write tools

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@mcp-server/handlers.py`:
- Around line 132-150: The code currently treats an explicit empty include_paths
list as omitted and falls through to the full-repo sync index; change the check
so we distinguish None (omitted) from an explicit empty list: use a presence
check (e.g. if "include_paths" in args or if include_paths is not None) and if
include_paths == [] return/reject with a BadRequest-style response indicating
empty include_paths is invalid; otherwise proceed to call the async subset
endpoint via api_post(f"/repos/{repo_id}/index/async", json={"include_paths":
include_paths}) and keep the existing status/response handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2d98e752-14e9-4614-b054-5ad6fc078060

📥 Commits

Reviewing files that changed from the base of the PR and between fc281f7 and 2e48561.

📒 Files selected for processing (3)
  • mcp-server/api_client.py
  • mcp-server/handlers.py
  • mcp-server/tests/test_tools.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • mcp-server/tests/test_tools.py
  • mcp-server/api_client.py

Comment thread mcp-server/handlers.py
[] is falsy in Python, so 'if include_paths:' treated an explicit
empty list the same as None (omitted). Now returns a clear error
for empty list, preserving the distinction between 'index everything'
(omit include_paths) and 'index nothing' (empty list).
@vercel

vercel Bot commented Mar 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
opencodeintel Ignored Ignored Preview Mar 7, 2026 9:06pm

@DevanshuNEU DevanshuNEU merged commit 5ae2eba into OpenCodeIntel:main Mar 7, 2026
8 checks passed
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.

1 participant