Skip to content

feat: add MCP tools for legal intake CRUD#44

Open
achuth10 wants to merge 1 commit intomainfrom
feat/legal-intake-mcp-tools
Open

feat: add MCP tools for legal intake CRUD#44
achuth10 wants to merge 1 commit intomainfrom
feat/legal-intake-mcp-tools

Conversation

@achuth10
Copy link
Copy Markdown
Contributor

@achuth10 achuth10 commented Mar 27, 2026

User description

Summary

Adds five MCP tools that expose the new private public API endpoints for legal intakes (see companion PR in django-rest-api). Also extends SpotDraftClient with patch and delete methods needed to call the update and delete endpoints.

New tools

Tool name HTTP method Endpoint Write?
list_legal_intakes GET /v1/public/legal_intake/ No
get_legal_intake GET /v1/public/legal_intake/<id>/ No
create_legal_intake POST /v1/public/legal_intake/ Yes
update_legal_intake PATCH /v1/public/legal_intake/<id>/ Yes
delete_legal_intake DELETE /v1/public/legal_intake/<id>/ Yes

Read tools are available in read-only mode. Write tools are gated behind the write flag (consistent with all existing write tools).

SpotDraftClient changes

Added patch(endpoint, body) and delete(endpoint) methods following the exact same structure (fetch, error handling, logging) as the existing post method.

Files changed

File Change
src/spotdraft_client.ts Added patch and delete methods
src/tools/legal-intake/list_legal_intakes.ts New tool
src/tools/legal-intake/get_legal_intake.ts New tool
src/tools/legal-intake/create_legal_intake.ts New tool
src/tools/legal-intake/update_legal_intake.ts New tool
src/tools/legal-intake/delete_legal_intake.ts New tool
src/tools/index.ts Import + register all five tools

Testing notes

  • TypeScript type-checked locally (tsc --noEmit) — zero errors.
  • Prettier ran automatically via lint-staged on commit.
  • Tools follow the exact pattern of existing counter-parties tools.
  • Companion Django PR: SpotDraft/django-rest-api#12590

Generated description

Below is a concise technical summary of the changes proposed in this PR:
Expose legal intake CRUD through new MCP tools wired into the global registry so agents can hit the /v1/public/legal_intake/ endpoints. Extend SpotDraftClient with patch and delete methods to support the new update and delete operations via the MCP layer.

TopicDetails
Legal intake tools Provide new MCP tools for listing, retrieving, creating, updating, and deleting legal intakes, each wired into the global registry with appropriate read/write flags and documentation for the public endpoints.
Modified files (6)
  • src/tools/index.ts
  • src/tools/legal-intake/create_legal_intake.ts
  • src/tools/legal-intake/delete_legal_intake.ts
  • src/tools/legal-intake/get_legal_intake.ts
  • src/tools/legal-intake/list_legal_intakes.ts
  • src/tools/legal-intake/update_legal_intake.ts
Latest Contributors(2)
UserCommitDate
madhav@spotdraft.comfeat: Introduce write ...March 23, 2026
achuth10chore: Refactor projec...February 05, 2026
Client verbs Add patch and delete support to SpotDraftClient so MCP handlers can send the new update and delete requests with the existing error/logging patterns.
Modified files (1)
  • src/spotdraft_client.ts
Latest Contributors(2)
UserCommitDate
madhav@spotdraft.comfeat: Introduce write ...March 23, 2026
achuth10fix: Add 'Enforce-User...March 05, 2026
This pull request is reviewed by Baz. Review like a pro on (Baz).

Adds five new MCP tools that call the new private public API endpoints
exposed on the Django side (api/v1/public/legal_intake/):

  list_legal_intakes   – GET  /v1/public/legal_intake/          (read)
  get_legal_intake     – GET  /v1/public/legal_intake/<id>/     (read)
  create_legal_intake  – POST /v1/public/legal_intake/          (write)
  update_legal_intake  – PATCH /v1/public/legal_intake/<id>/    (write)
  delete_legal_intake  – DELETE /v1/public/legal_intake/<id>/   (write)

Read tools are registered without the write flag so they are available in
read-only mode. Write tools require write mode to be enabled.

SpotDraftClient gains two new methods (patch, delete) following the exact
same error-handling pattern as the existing post method.

Testing notes
-------------
* TypeScript type-checked locally (tsc --noEmit) – zero errors.
* Tools follow the same pattern as the existing counter-parties tools.
@sachin-spotdraft sachin-spotdraft added the size/m < 500 lines of changes label Mar 27, 2026
Comment on lines +37 to +41

const endpoint = `/v1/public/legal_intake/${request.legal_intake_id}/`;
logger.debug('SpotDraft MCP', `Making DELETE request to ${endpoint}`);
await spotdraftClient.delete(endpoint);
return { success: true, message: `Legal intake ${request.legal_intake_id} deleted successfully.` };
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

delete_legal_intake is documented to return null/204 but the handler returns { success: true, message: ... }, should we return null (204) or update the contract/schema to match?

Finding type: Breaking Changes | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Fix in Cursor

Prompt for AI Agents:

Before applying, verify this suggestion against the current code. In
src/tools/legal-intake/delete_legal_intake.ts around lines 35 to 41, the
deleteLegalIntake handler currently returns an object ({ success: true, message: ... })
but the tool's description documents that it returns null (204 No Content). Change the
function signature to return Promise<null> and replace the final return statement with
return null; (keep the spotdraftClient.delete call and logging). Ensure any exported
types or usage sites are updated if they expect the old object. This preserves the
documented MCP contract.

Comment on lines +172 to +176
async patch(endpoint: string, body?: any) {
const url = `${this.baseUrl}${endpoint}`;

this.logger.debug('SpotDraftClient', `PATCH ${url}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SpotDraftClient.patch duplicates get/post fetch/log/error-handling — should we extract a private request(method, endpoint, options) helper that get/post/patch/delete call?

Finding type: Code Dedup and Conventions | Severity: 🟢 Low


Want Baz to fix this for you? Activate Fixer

Comment on lines +220 to +224
async delete(endpoint: string) {
const url = `${this.baseUrl}${endpoint}`;

this.logger.debug('SpotDraftClient', `DELETE ${url}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SpotDraftClient.delete duplicates the get/post fetch/error-handling boilerplate — should we centralize all HTTP verbs into a private async request(method, endpoint, options) that handles fetch, JSON parsing, and APIError handling?

Finding type: Code Dedup and Conventions | Severity: 🟢 Low


Want Baz to fix this for you? Activate Fixer

Comment on lines +101 to +107
const updateLegalIntake = async (request: UpdateLegalIntakeRequest, spotdraftClient: SpotDraftClient): Promise<any> => {
if (!request.legal_intake_id) throw new Error('legal_intake_id is required.');

const { legal_intake_id, ...body } = request;
const endpoint = `/v1/public/legal_intake/${legal_intake_id}/`;
logger.debug('SpotDraft MCP', `Making PATCH request to ${endpoint}`);
return spotdraftClient.patch(endpoint, body);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

updateLegalIntake sends an empty PATCH when only legal_intake_id is provided despite the docstring 'At least one updatable field must be supplied' — should we enforce Object.keys(body).length > 0 and throw before calling spotdraftClient.patch?

Finding type: Logical Bugs | Severity: 🔴 High


Want Baz to fix this for you? Activate Fixer

Fix in Cursor

Prompt for AI Agents:

Before applying, verify this suggestion against the current code. In
src/tools/legal-intake/update_legal_intake.ts around lines 101-107, the
updateLegalIntake function only validates legal_intake_id and then PATCHes with body
which can be an empty object. Enforce that at least one updatable field is provided by
checking Object.keys(body).length > 0 after destructuring; if it's zero, throw an Error
with a descriptive message like 'At least one updatable field must be supplied.'
Otherwise proceed to build the endpoint, log, and call spotdraftClient.patch as before.
Make this change within the updateLegalIntake function so the runtime behavior matches
the tool docstring.

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

Labels

size/m < 500 lines of changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants