
List every calendar appointment on one case by internal case ID. Not paginated — returns the case's full appointment history. Use search_appointments for a firm-wide or date-filtered view.
List every calendar appointment on one case by its human-readable case number. Use listcaseappointments when you already have the internal case ID.
Search appointments across cases for firm-wide calendars and deadline reports. The modified-date window is required; narrow further by the dates the appointments fall on, by case number, or by owning staff user.
Schedule an appointment on a case — a hearing, deposition, meeting, or reminder. Call listappointmenttypes, listappointmentactivitytypes, and listappointment_statuses first; those IDs are per-firm configuration.
List the firm's appointment types, e.g. Deposition or Trial. Call this before create_appointment — type IDs are per-firm configuration.
List the firm's appointment activity types — the secondary classification on an appointment. Call this before create_appointment.
List the firm's appointment statuses, e.g. Scheduled or Cancelled. Call this before create_appointment.
List the calls logged on one case — remote party, number, direction, date, and summary. Page with pageinfo.nextpage.
Log a phone call on a case. direction is true for outbound and false for inbound. Use listcasecontacts or lookup_contacts to find the remote party's contact ID. summary accepts HTML.
Replace a logged call in full. Every field you want kept must be supplied — omitted fields are cleared. Use patch_call to change one field.
Change selected fields on a logged call, leaving the others untouched. Pass fields as a mapping of API field name to new value, e.g. summary. Use update_call to replace the whole record.
Delete a logged call from a case permanently. This cannot be undone.
Get one case by its internal case ID, including parties, staff, tags, and incident summary. Use getcaseinfo instead when you only have the human-readable case number. Find case IDs with searchcases or listactive_cases.
Get a case by its human-readable case number, e.g. 9000002. Use get_case instead when you already have the internal case ID. Optionally include full contact details and referral source information.
Search cases modified within a date range, optionally narrowed by case number, case type, case group, or tag. The date window is required. Use listcasegroups, listcasetypes, and listtags to resolve filter IDs. Page with pageinfo.next_page.
List open cases assigned to one staff member, for workload or dashboard views. Use listcasestaff on a known case to find staff contact IDs. Set primary_only to return only cases where they are the primary assignee.
Open a new case from intake details. Call listcasegroups and listcasetypes first — group and type IDs are per-firm configuration and cannot be guessed. At least one of email or phone is required. Pass plaintiffcontactid to attach an existing contact, or omit it to have SmartAdvocate create one from the name fields.
Change a case's human-readable case number. The firm must have case-number editing enabled in SmartAdvocate and the new number must be unused, or the call is rejected. Documents already stored keep their existing folder paths.
List every contact linked to a case with the role each one holds — plaintiff, defendant, witness, adjuster, and so on. Also the way to see which role names this firm uses before calling addcasecontact.
Link an existing contact to a case in a role. Find the contact ID with lookupcontacts or searchcontacts, or create one with createcontact. Role names are per-firm; call listcase_contacts on a similar case to see the ones in use.
Replace a case-contact link's role and comments. This is a full replacement — any field left unset is cleared. Use patchcasecontact to change one field and leave the rest alone.
Change selected fields on a case-contact link, leaving the others untouched. Pass fields as a mapping of field name to new value. Use updatecasecontact to replace the whole link instead.
Unlink a contact from a case. This removes the case-contact relationship only; the contact record itself is left in place.
List cases linked to this one as related matters — consolidated cases, companion cases, or other cases involving the same parties.
List the firm's case groups — the top-level case classification, e.g. Personal Injury. Call this before createcase or searchcases: group IDs are per-firm configuration. Feed a group ID to listcasetypes.
List the case types inside one case group — the second-level classification. Get the group ID from listcasegroups. Feed a type ID to listcasesubtypes or create_case.
List the subtypes inside one case type — the third-level classification. Get the case type ID from listcasetypes. Returns an empty list when the type defines no subtypes.
Get a contact's core details by contact ID — name, primary address, phone, and email. Use getcontactfull for the complete record with every address, email, and phone.
Get a contact's complete record, including all addresses, emails, phones, and classification fields. Heavier than get_contact — use that one when the core fields are enough.
Search contacts by modified-date window, optionally restricted to those linked to given case numbers. The date window is required. Use lookup_contacts to search by name or phone instead.
Find contacts by name or phone number — the way to resolve a person to a contact ID before addcasecontact, addplaintiff, or createcall. With no filters it returns a full paginated contact list. Note first_page is one-based.
Create a contact. Call listcontacttypes first — category and type IDs are per-firm configuration. Give firstname and lastname for a person, or other_name for an organization. Addresses, emails, and phones can be included inline.
Change selected fields on a contact, leaving the others untouched. Pass fields as a mapping of API field name to new value. Addresses, emails, and phones have their own tools — this route does not reach them.
List contacts related to a given contact, with the relationship each one holds — family members, employers, and similar links.
List a contact's postal addresses. Returns the address IDs patchcontactaddress and deletecontactaddress take.
Add one or more postal addresses to a contact. Pass a list even for a single address. Use listincidentstates for valid two-letter state codes.
Change selected fields on one of a contact's addresses. Get the address ID from listcontactaddresses. Pass fields as a mapping of API field name to new value.
Delete one address from a contact permanently. This cannot be undone.
List a contact's email addresses. The address itself is in the name field. Returns the email IDs patchcontactemail and deletecontactemail take.
Add one or more email addresses to a contact. Pass a list even for a single address. Set preventautocontact to stop automated messages going to it.
Change selected fields on one of a contact's email addresses. The address itself is the name field. Get the email ID from listcontactemails.
Delete one email address from a contact permanently. This cannot be undone.
List a contact's phone numbers with their labels and texting flags. Returns the phone IDs patchcontactphone and deletecontactphone take.
Add one or more phone numbers to a contact. Pass a list even for a single number. Use listphonetypes for the labels this firm uses, e.g. Mobile Phone.
Change selected fields on one of a contact's phone numbers. Get the phone ID from listcontactphones. Pass fields as a mapping of API field name to new value.
Delete one phone number from a contact permanently. This cannot be undone.
List the firm's contact types for a contact category. Call this before create_contact — the category and type IDs are per-firm configuration.
List the firm's address types for a contact category, for labelling addresses on a contact.
List the firm's phone types, e.g. Mobile Phone or Work Phone. Use one of these as the name when calling addcontactphones.
List the firm's contact subcategories. Feeds contactsubcategoryid on createcontact.
List document metadata for one case, filtered server-side by category, subcategory, or originating/destination contact. Returns metadata only — use downloaddocument for file content. Use listdocument_categories to resolve IDs.
List document metadata for one case by its human-readable case number, with the same category and contact filters. Use listcasedocuments when you already have the internal case ID.
Get one document's metadata by document ID — name, category, dates, and review state. Returns no file content; use download_document for that.
Search document metadata across cases by modified-date window, narrowed by case number, category, subcategory, or contact. The date window is required. Returns metadata only — use download_document for content.
Create a document metadata record on a case. This moves no bytes — call uploaddocumentcontent with the returned document ID to attach the file. Call listdocumentcategories first; category IDs are per-firm configuration.
Replace a document's metadata in full. Every field you want kept must be supplied — omitted fields are cleared. Use patch_document to change one field. Neither tool touches the file content.
Change selected metadata fields on a document, leaving the others untouched. Pass fields as a mapping of API field name to new value. Use update_document to replace the whole record.
Download a document's file content by document ID. Returns UTF-8 text as text and anything else as base64 — check the 'encoding' field before use. Files over maxbytes (10 MB default) come back flagged truncated with no content; set returndownload_url=true for a download link instead, which handles larger files.
Attach file content to an existing document record. Pass the bytes as base64 in contentbase64, or a filereference from the file upload API (POST /api/v1/files/) for large files, which never enter the model's context. Create the record first with create_document. If this fails, retry against the same document ID rather than creating another record.
List the firm's document categories with their subcategories, one row per category/subcategory pair. Call this before create_document or the document list filters — these IDs are per-firm configuration.
List the document folders configured on one case. Use a folder name as documentfolder on createdocument to file a document into it.
List the firm's document tags. Call this before createdocument to pass valid tagids.
Get a case's incident record — the facts of what happened plus structured details like date, state, and county. Returns the incident ID that updateincident and patchincident need.
Get a case's incident record by its human-readable case number. Use getcaseincident when you already have the internal case ID.
Search incident records across cases by modified-date window, optionally restricted to specific case numbers. The date window is required.
Replace a case's incident facts and structured details. Get the incident ID from getcaseincident. Supplying incidentdetails replaces the existing detail rows, so include every one you want kept; use patchincident to change just the facts.
Change selected fields on a case's incident record, leaving the others untouched. Pass fields as a mapping of API field name to new value, e.g. incidentFacts.
List the states available on incident records. Call this before update_incident to get a valid state ID, or to resolve a two-letter state code.
List the counties available on incident records. This is a large reference list covering every state; call it before update_incident to get a valid county ID.
List the firm's liability codes for incident records. Call this before update_incident — these IDs are per-firm configuration.
List the injury records on a case, one per injured plaintiff. Returns the injury IDs the injury-detail tools take. Use listinjurydetails for the individual body-part and treatment rows under an injury.
Get one injury record on a case, including its summaries and confinement details. Use listcaseinjuries to find injury IDs.
Search injury records across cases by modified-date window, optionally restricted to specific case numbers. The date window is required.
Create an injury record for one plaintiff on a case. plaintiffid is the plaintiff RECORD id from listplaintiffs, not the contact ID. Add body parts and treatments afterwards with createinjurydetail.
Replace an injury record's summaries, confinement details, and comments. Fields left unset are cleared, so supply everything you want kept.
Delete an injury record from a case permanently, along with its detail rows. This cannot be undone.
List the detail rows under one injury — each a body part with its treatments and sequelae. Returns the detail row IDs the update and delete tools take.
Get one injury detail row by its ID. Use listinjurydetails to find row IDs.
Add a body-part detail row to an injury. Call listbodyparts first, then listtreatments and listsequelae with that body part ID — all three are per-firm reference data.
Replace an injury detail row. Fields left unset are cleared, so supply everything you want kept. Use patchinjurydetail to change one field.
Change selected fields on an injury detail row, leaving the others untouched. Pass fields as a mapping of API field name to new value.
Delete one injury detail row permanently. This cannot be undone.
Add injury detail rows from ICD diagnosis codes, letting SmartAdvocate map each code to the right body part and injury. Faster than createinjurydetail when you already have coded diagnoses.
Add procedure detail rows to an injury from CPT procedure codes, letting SmartAdvocate map each code to the right treatment.
List the body parts available on injury detail rows. Call this first when building a detail row, then feed the ID to listtreatments and listsequelae.
List the sequelae — follow-on conditions — recorded for one body part. Feeds sequelaeids on createinjurydetail. Use listbody_parts to get the body part ID.
List the treatments available for one body part. Feeds treatmentids on createinjurydetail. Use listbody_parts to get the body part ID.
List the firm's catalogue of injury names. This is a large reference list; use it to resolve an injury description to a known name.
List the insurance policies on a case for one side. party is required: 'P' for plaintiff-side coverage, 'D' for defendant-side — they are separate lists, so check both to see all policies.
List insurance policies for one side of a case by its human-readable case number. Use listcaseinsurance when you already have the internal case ID.
Get one insurance policy on a case by its insurance record ID, including carrier, adjuster, limits, and claim number.
Record an insurance policy on a case. Set party to 'P' or 'D' and pass the matching plaintiffid or defendantid from listplaintiffs / listdefendants. Use listinsurancetypes and lookup_contacts for the type and carrier IDs.
Replace an insurance policy in full. Fields left unset are cleared, so supply everything you want kept, including party and the matching party ID. Use patch_insurance to change one field.
Change selected fields on an insurance policy, leaving the others untouched. Pass fields as a mapping of API field name to new value, e.g. policyNo. party is still required so SmartAdvocate scopes the record correctly.
Delete an insurance policy from a case permanently. This cannot be undone.
List the firm's insurance types, e.g. auto liability or health. Call this before create_insurance — these IDs are per-firm configuration.
List the notes on one case by internal case ID, newest first. Use listnotesbycasenumber when you only have the case number, or searchnotes to look across cases by date. Page with pageinfo.next_page.
List the notes on one case by its human-readable case number. Use listcasenotes when you already have the internal case ID.
Get one case note by its note ID, including full body text and sharing settings.
Search notes across cases by modified-date window, optionally restricted to specific case numbers. The date window is required. Use listcasenotes for the notes on one known case.
Add a note to a case. Call listnotetypes first — note type IDs are per-firm configuration. note_text accepts HTML. Returns the new note ID.
Replace a note in full — type, body, date, subject, contact, priority and sharing. Every field left unset is cleared, so read the current note with getnote first. Use patchnote to change one field and leave the rest alone.
Change selected fields on a note, leaving the others untouched. Pass fields as a mapping of API field name to new value, e.g. noteText or isSharedinCP. Use update_note to replace the whole note.
List the firm's note types. Call this before createnote or updatenote — note type IDs are per-firm configuration and cannot be guessed.
List the plaintiffs on a case with their roles and contact IDs. Set addcontactinfo to include full contact details, or table_type to read the Other or Non-Party tables instead of the main one.
List the defendants on a case with their roles and contact IDs.
Add a plaintiff to a case. Call listplaintiffroles first with the case's type ID — role IDs are per-firm configuration. The contact must already exist; use lookupcontacts or createcontact.
Change selected fields on a plaintiff record, leaving the others untouched. Pass fields as a mapping of API field name to new value. Use list_plaintiffs to find the plaintiff record ID.
List the plaintiff roles available for a case type, e.g. Passenger or Driver. Call this before add_plaintiff — role IDs are per-firm configuration. Pass 0 for roles across all case types.
Look up cases by a single criterion, e.g. every case with a given status. Pass the value as criteria and what it refers to as searchtype, such as CASESTATUS. Use searchcases for date-window and multi-filter searches.
List the staff assigned to one case with their roles. This is the discovery tool for staff IDs: it returns the contact ID listactivecases takes and the user ID task and appointment writes take.
List staff assignments by case number. Accepts % as a wildcard, so '1%' returns assignments for every case whose number starts with 1. Use listcasestaff for a single known case ID.
Search staff assignments across cases by modified-date window, optionally restricted to specific case numbers. The date window is required. Useful for finding reassignments in a period.
List a case's status history by internal case ID — each record with its type, value, and effective dates. A record with no to_date is still active.
List a case's status history by its human-readable case number. Use listcasestatuses when you already have the internal case ID.
Get one case status record by its status record ID, with dates and comments.
Search case status records across cases by modified-date window, optionally restricted to specific case numbers. The date window is required.
Add a status record to a case. Call liststatustypes first — both the status type ID and the status value ID within it are per-firm configuration. Use terminatecasestatus to close out an active status instead of replacing it.
Change the comment on an existing case status record. Only the comment can be edited; use createcasestatus to record a new status.
Close out the active status of a given type on a case by stamping its end date. Nothing is deleted — the record stays in the case's status history. Use listcasestatuses to see which types are currently active.
List the firm's case status types and the status values inside each one. Call this before createcasestatus or terminatecasestatus — both IDs are per-firm configuration. Narrow with statustypeid to see one type's values.
List every tag defined in the firm, with its active state and any case-group or case-type restrictions. Use listavailablecase_tags instead to see which tags may be applied to one specific case.
Get one tag definition by ID, including its group and case-type restrictions.
Define a new tag that can be applied to cases. Set limitgroups true and pass groups to restrict it to certain case groups — use listcasegroups and listcase_types for those IDs.
Update a tag definition's name, active state, or group restrictions. This replaces the tag's properties, so supply every value you want kept.
Delete a tag definition permanently. This also removes the tag from every case it was applied to and cannot be undone. To take a tag off one case only, use removecasetags.
List the tags that can still be applied to one case — those allowed for its case group and type and not already assigned. Call this before addcasetags.
Apply one or more existing tags to a case. Call listavailablecase_tags first — a tag not permitted for the case's group or type, or already applied, is rejected.
Take one or more tags off a case. The tag definitions themselves are left intact — use delete_tag to remove a definition entirely.
List the tasks on one case by internal case ID. Use listtasksbycasenumber when you only have the case number, or search_tasks to look across cases and filter by type, status, assignee, or due date.
List the tasks on one case by its human-readable case number. Use listcasetasks when you already have the internal case ID.
Get one task by its task ID, including assignee, dates, and attached documents.
Search tasks across cases, filtering by modified window, due-date range, type, status, assignee, or template. All filters are optional. Use listtasktypes and listtaskstatuses to resolve IDs. Due-date filters need SmartAdvocate API 2026-07+.
Create a task on a case. Call listtasktypes, listtaskstatuses, and listtaskpriorities first — these IDs are per-firm configuration. Pass IDs rather than labels where you have them. Returns the new task ID.
Replace a task in full. Every field you want kept must be supplied — omitted fields are cleared. Use patch_task to change one field and leave the rest alone.
Change selected fields on a task, leaving the others untouched. Pass fields as a mapping of API field name to new value, e.g. description or summary. Use update_task to replace the whole task.
Delete a task permanently by its task ID. This cannot be undone.
List the firm's task types. Call this before createtask, updatetask, or search_tasks — task type IDs are per-firm configuration.
List the firm's task statuses, e.g. Not Started or Completed. Call this before createtask, updatetask, or search_tasks.
List the firm's task priority levels, e.g. Normal or High. Call this before createtask or updatetask.
List a case's user-defined fields and their current values — SmartAdvocate's custom fields. This is the discovery tool for UDF writes: it returns the udfid, screenname, and relatedPK that updateudf and the grid tools need.
List a case's user-defined fields by its human-readable case number. Use listcaseudfs when you already have the internal case ID.
Get one user-defined field's value on a case by its UDF definition ID. Use listcaseudfs to find UDF IDs.
Search user-defined field values across cases by modified-date window, optionally restricted to specific case numbers. The date window is required.
Set one user-defined field's value on a case. Call listcaseudfs first for the udfid, and pass its relatedPK as subrelatedid for plaintiff- or defendant-level fields. Use bulkupdateudfs to set several at once.
Set several user-defined field values on one case in a single transaction — if any entry is invalid nothing is written. Call listcaseudfs first for the udfids. Grid-type UDFs are rejected here; use createudfgrid_row for those.
List the rows of a UDF grid on a case. Get the screen name from the screenname of a grid-type field returned by listcaseudfs. Row IDs from here feed getudfgridrow, updateudfgridrow, and deleteudfgridrow.
Get one row of a UDF grid by row ID, returning each cell's column definition ID and value. Use listudfgrid_rows to find row IDs.
Add a row to a UDF grid on a case. Read the column definition IDs from an existing row with listudfgrid_rows first — they are per-firm configuration and cannot be guessed.
Replace a UDF grid row's cells. This is a full replacement — include every column you want kept, with each cell's udfvalueid so existing values are updated rather than duplicated.
Delete a row from a UDF grid on a case. This cannot be undone.
Check that the SmartAdvocate connection works by signing in and reading the firm's case groups.

In an mcp.json file, add the configuration below, and restart Cursor.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "url": "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
5 "headers": {
6 "Authorization": "Bearer yMt*****"
7 }
8 }
9 }
10}
11Open your Claude Desktop configuration file and add the server configuration below. You'll also need to restart the application for the changes to take effect.
Make sure Claude is using the Node v20+.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "yMt*****"
14 }
15 }
16 }
17}Open your Windsurf MCP configuration file and add the server configuration below.
Click on the refresh button in the top right of the Manage MCP server page or in the top right of the chat box in the box icon.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api.merge.dev/api/v1/tool-packs/<tool-pack-id>/registered-users/<registered-user-id>/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "<ah-production-access-key>"
14 }
15 }
16 }
17 }In Command Palette (Cmd+Shift+P on macOS, Ctrl+Shift+P on Windows), run "MCP: Open User Configuration".
You can then add the configuration below and press "start" right under servers. Enter the auth token when prompted.
Learn more in the official documentation ↗
1{
2 "inputs": [
3 {
4 "type": "promptString",
5 "id": "agent-handler-auth",
6 "description": "Agent Handler AUTH_TOKEN", // "yMt*****" when prompt
7 "password": true
8 }
9 ],
10 "servers": {
11 "agent-handler": {
12 "type": "stdio",
13 "command": "npx",
14 "args": [
15 "-y",
16 "mcp-remote@latest",
17 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
18 "--header",
19 "Authorization: Bearer ${input:agent-handler-auth}"
20 ]
21 }
22 }
23}Whether you're an engineer experimenting with agents or a product manager looking to add tools, you can get started for free now