Skip to content

Add create_entity and delete_entity MCP tools#35

Merged
visahak merged 6 commits into
AgentToolkit:mainfrom
visahak:feature/add-create-delete-entity-mcp-tools
Jan 29, 2026
Merged

Add create_entity and delete_entity MCP tools#35
visahak merged 6 commits into
AgentToolkit:mainfrom
visahak:feature/add-create-delete-entity-mcp-tools

Conversation

@visahak

@visahak visahak commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

Description

Implements create and delete entity MCP tools as requested in #34.

Changes

  • New MCP Tools (kaizen/frontend/mcp/mcp_server.py):

    • create_entity: Creates single entities using existing client.update_entities() method
    • delete_entity: Deletes entities by ID using existing client.delete_entity_by_id() method
  • Tests (tests/e2e/test_mcp.py):

    • Added 7 comprehensive test cases covering all scenarios
    • All tests passing (172/172 including Phoenix tests)
  • Documentation (README.md):

    • Updated to include new MCP tools

Features

✅ Uses existing KaizenClient API methods
✅ Supports optional conflict resolution
✅ Proper error handling
✅ Metadata support
✅ Comprehensive test coverage
✅ All tests passing (172/172)

Testing

# Run all tests
KAIZEN_BACKEND=filesystem uv run pytest

# Run MCP tests only
KAIZEN_BACKEND=filesystem uv run pytest tests/e2e/test_mcp.py -v -m e2e

Fixes #34


Files Changed

  • kaizen/frontend/mcp/mcp_server.py - Added 2 new MCP tools (80 lines)
  • tests/e2e/test_mcp.py - Added 7 test cases (157 lines)
  • README.md - Updated documentation (2 lines)

Test Results

✅ All 172 tests passing (including Phoenix tests)
✅ All new MCP tools fully tested
✅ No breaking changes to existing functionality

Summary by CodeRabbit

  • New Features
    • Added create-entity and delete-entity actions with structured JSON responses and optional metadata/conflict-resolution.
  • Bug Fixes
    • Clear error responses for invalid metadata, non-numeric IDs, and when creations produce no result.
  • Tests
    • Expanded end-to-end coverage for create/delete flows, conflict resolution, invalid metadata, multi-entity scenarios with isolated test environments.
  • Chores
    • Improved client/backend initialization and cleanup for more reliable runtime and tests.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 26, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds two MCP tools—create_entity(content, entity_type, metadata=None, enable_conflict_resolution=False) and delete_entity(entity_id)—introduces lazy Kaizen client initialization in the MCP server, normalizes metadata and lifecycle handling in the Milvus backend (per-instance client and close()), and adds extensive end-to-end tests plus README entries.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added create_entity(...) and delete_entity(...) to the Available tools list.
MCP Server Implementation
kaizen/frontend/mcp/mcp_server.py
Introduced get_client() lazy-initialized singleton, replaced direct client usage across MCP operations, added create_entity(...) and delete_entity(...) tool functions, JSON metadata parsing with structured error responses, and KaizenException handling.
Backend: Milvus
kaizen/backend/milvus.py
Moved Milvus client and embedding model to instance attributes via __init__, added close() method, normalized metadata to {} for inserts/updates, and added numeric ID validation and pre-delete existence checks in delete_entity_by_id.
End-to-End Tests
tests/e2e/test_mcp.py
Added multiple e2e tests for create/delete workflows (including conflict-resolution and invalid metadata), introduced per-test Milvus Lite DB isolation and teardown, reset MCP client between tests, and expanded fixture cleanup.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant MCP as MCP_Server
    participant NS as NamespaceManager
    participant KC as KaizenClient
    participant MB as MilvusBackend

    Client->>MCP: create_entity(content, type, metadata?, enable_conflict_resolution)
    MCP->>NS: ensure_namespace()
    NS-->>MCP: namespace_ok
    MCP->>MCP: parse metadata JSON or return error
    MCP->>KC: update_entities([Entity], enable_conflict_resolution)
    KC->>MB: insert/update vectors & metadata
    MB-->>KC: updates_result or error
    KC-->>MCP: updates_result
    MCP-->>Client: JSON response with event/id/type/content/metadata or error

    Client->>MCP: delete_entity(entity_id)
    MCP->>NS: ensure_namespace()
    NS-->>MCP: namespace_ok
    MCP->>KC: delete_entity_by_id(entity_id)
    KC->>MB: check existence -> delete by id
    MB-->>KC: success or error
    KC-->>MCP: success or KaizenException
    MCP-->>Client: JSON success/error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I nibble bytes and hop through code,
I plant new tools along the road.
Create a friend, or send it away,
Metadata tidy, then off they play.
Small hops, big MCP cheer! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the main change: adding two new MCP tools (create_entity and delete_entity).
Linked Issues check ✅ Passed The PR successfully implements both objectives from issue #34: create and delete entity MCP tools using existing KaizenClient backend operations.
Out of Scope Changes check ✅ Passed All changes are directly related to the issue objectives. Supporting changes include test isolation improvements in Milvus backend and E2E test additions.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

🤖 Fix all issues with AI agents
In `@kaizen/frontend/mcp/mcp_server.py`:
- Around line 141-149: The code currently calls json.loads(metadata) and will
crash on malformed JSON; wrap the parse in a try/except that catches
json.JSONDecodeError (or Exception) when building metadata_dict and return a
structured error response instead of proceeding to create the Entity; update the
logic around metadata_dict and Entity(...) so on parse failure you return or
raise a clear, structured error (including the invalid metadata/error message)
rather than letting the server crash.
- Around line 186-198: The except block around client.delete_entity_by_id(...)
should catch the specific KaizenException rather than Exception and should call
logger.exception(...) to preserve the traceback: replace "except Exception as
e:" with "except KaizenException as e:" (import KaizenException where needed)
and change logger.error(...) to logger.exception(...) while keeping the same
logged message about deleting entity {entity_id}; leave other behavior
(returning the JSON error response) unchanged.
🧹 Nitpick comments (1)
tests/e2e/test_mcp.py (1)

67-90: Add skipif guard to prevent test failure when LLM credentials are unavailable.

The conflict resolution feature uses LLM (via litellm with gpt-4o model), which requires OPENAI_API_KEY or equivalent credentials. The test will fail without them.

Suggested guard
 `@pytest.mark.e2e`
+@pytest.mark.skipif(
+    not os.getenv("OPENAI_API_KEY"),
+    reason="Conflict resolution requires LLM credentials"
+)
 async def test_create_entity_with_conflict_resolution(mcp):

Comment thread kaizen/frontend/mcp/mcp_server.py
Comment thread kaizen/frontend/mcp/mcp_server.py
@visahak visahak force-pushed the feature/add-create-delete-entity-mcp-tools branch from 8902fec to 0fb2968 Compare January 29, 2026 01:33

@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

🤖 Fix all issues with AI agents
In `@tests/e2e/test_mcp.py`:
- Around line 200-212: The test test_delete_nonexistent_entity is wrong to
expect an error because delete_entity_by_id calls milvus.delete (which is
idempotent) and the MCP handler therefore returns success: True; either change
the test to assert result['success'] is True and remove the error expectation,
or change the implementation in delete_entity_by_id to first check existence
(e.g., via a get/query method) and raise/return an error when the entity_id does
not exist so the MCP handler returns success: False—update the test accordingly
to match the chosen behavior; reference test_delete_nonexistent_entity,
delete_entity_by_id, and milvus.delete when making the change.
🧹 Nitpick comments (2)
kaizen/backend/milvus.py (1)

200-206: Consider setting self.milvus = None after closing to prevent potential double-close.

The SQLiteManager.close() pattern (from kaizen/db/sqlite_manager.py lines 125-128) sets the resource to None after closing, which guards against double-close issues and makes the closed state inspectable. Consider applying the same pattern here.

♻️ Suggested improvement
     def close(self):
         """Close Milvus connection."""
         try:
             if hasattr(self, 'milvus'):
                 self.milvus.close()
+                self.milvus = None
         except Exception as e:
             logger.warning(f"Error closing Milvus client: {e}")

Regarding the static analysis hint about catching broad Exception (BLE001): this is acceptable in cleanup code where we want best-effort teardown without propagating errors.

tests/e2e/test_mcp.py (1)

14-82: Good test isolation pattern with per-test DB files.

The fixture properly:

  • Creates unique DB files to avoid socket/locking conflicts between tests
  • Resets the MCP server's singleton client
  • Performs thorough multi-stage cleanup

Regarding the static analysis hints about try-except-pass (S110, BLE001): in test fixture cleanup, broad exception handling with pass is generally acceptable since cleanup should be best-effort and not mask test failures. However, consider adding minimal logging for easier debugging when cleanup fails:

♻️ Optional: Add logging for cleanup debugging
+import logging
+logger = logging.getLogger(__name__)
+
 # In cleanup blocks, e.g.:
     try:
         kaizen_client.backend.close()
-    except Exception:
-        pass
+    except Exception as e:
+        logger.debug(f"Cleanup: backend.close() failed: {e}")

Comment thread tests/e2e/test_mcp.py
@visahak visahak force-pushed the feature/add-create-delete-entity-mcp-tools branch from 00ad2fd to 40c4a4b Compare January 29, 2026 02:30

@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

🤖 Fix all issues with AI agents
In `@kaizen/backend/milvus.py`:
- Around line 196-201: The except block that converts entity_id to int should
chain the original ValueError when raising KaizenException to preserve the
traceback; modify the except ValueError handler in the method that calls
int(entity_id) so it captures the original exception (e.g., except ValueError as
e) and raises KaizenException(f"Invalid entity ID: {entity_id}. Entity IDs must
be numeric.") from e; keep the subsequent calls to
self.validate_namespace(namespace_id) and self.milvus.delete(...) unchanged.
🧹 Nitpick comments (1)
tests/e2e/test_mcp.py (1)

14-82: Good isolation strategy; bare exceptions acceptable for test teardown.

The per-test unique DB file approach (test_{uuid}.db) effectively addresses Milvus Lite socket/locking issues. The comprehensive cleanup sequence (close backend → disconnect pymilvus → release servers → reset client → restore URI → remove files) is thorough.

While Ruff flags the try-except-pass blocks (S110, BLE001), these are acceptable in test teardown code where resilience takes priority—failures during cleanup should not mask test results. Consider adding minimal logging if debugging becomes necessary in the future.

One concern: line 36-37 silently swallows namespace creation failures. If create_namespace fails for reasons other than "already exists" (e.g., connection issues), tests may proceed with an invalid state.

♻️ Optional: handle specific exception for namespace creation
-    try:
-        kaizen_client.create_namespace('test')
-    except Exception:
-        pass
+    from kaizen.schema.exceptions import NamespaceAlreadyExistsException
+    try:
+        kaizen_client.create_namespace('test')
+    except NamespaceAlreadyExistsException:
+        pass  # Expected if namespace already exists

Comment thread kaizen/backend/milvus.py
Comment on lines +196 to +201
try:
entity_id_int = int(entity_id)
except ValueError:
raise KaizenException(f"Invalid entity ID: {entity_id}. Entity IDs must be numeric.")
self.validate_namespace(namespace_id)
self.milvus.delete(collection_name=namespace_id, ids=[entity_id])
self.milvus.delete(collection_name=namespace_id, ids=[entity_id_int])

@coderabbitai coderabbitai Bot Jan 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Chain the exception for better traceability.

The validation logic is correct, but per Ruff B904, exceptions raised within except blocks should use raise ... from to preserve the original traceback.

🔧 Proposed fix
     def delete_entity_by_id(self, namespace_id: str, entity_id: str):
         try:
             entity_id_int = int(entity_id)
         except ValueError:
-            raise KaizenException(f"Invalid entity ID: {entity_id}. Entity IDs must be numeric.")
+            raise KaizenException(f"Invalid entity ID: {entity_id}. Entity IDs must be numeric.") from None
         self.validate_namespace(namespace_id)
         self.milvus.delete(collection_name=namespace_id, ids=[entity_id_int])
🧰 Tools
🪛 Ruff (0.14.14)

199-199: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


199-199: Avoid specifying long messages outside the exception class

(TRY003)

🤖 Prompt for AI Agents
In `@kaizen/backend/milvus.py` around lines 196 - 201, The except block that
converts entity_id to int should chain the original ValueError when raising
KaizenException to preserve the traceback; modify the except ValueError handler
in the method that calls int(entity_id) so it captures the original exception
(e.g., except ValueError as e) and raises KaizenException(f"Invalid entity ID:
{entity_id}. Entity IDs must be numeric.") from e; keep the subsequent calls to
self.validate_namespace(namespace_id) and self.milvus.delete(...) unchanged.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@visahak did you run ruff check before that? we have the ruff pre-commit hook setup

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@gaodan-fang not really but the tests passed. did I miss something?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I just ran it, no issues in the committed files.

- Add create_entity tool to create single entities with optional conflict resolution
- Add delete_entity tool to delete entities by ID
- Add 7 comprehensive test cases for new tools
- Update README.md to document new MCP tools
- All 172 tests passing

Fixes AgentToolkit#34
@visahak visahak force-pushed the feature/add-create-delete-entity-mcp-tools branch from 8bb6594 to e37cd6b Compare January 29, 2026 02:37
@gaodan-fang

Copy link
Copy Markdown
Collaborator

@visahak you need to update the branch with the base branch before merge

@visahak visahak merged commit e7ea693 into AgentToolkit:main Jan 29, 2026
11 checks passed
@visahak visahak deleted the feature/add-create-delete-entity-mcp-tools branch February 16, 2026 20:17
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.

mcp tools to create and remove entities.

2 participants