@mjquinlan2000/practicepanther-mcp 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -1,12 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getAccessToken
4
- } from "./chunk-36GM5B5H.js";
5
-
6
- // src/server.ts
7
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
- import { z as z2 } from "zod";
4
+ } from "./chunk-CNXDFCLN.js";
10
5
 
11
6
  // src/client/core/bodySerializer.gen.ts
12
7
  var jsonBodySerializer = {
@@ -819,6 +814,13 @@ client.setConfig({
819
814
  auth: async () => getAccessToken()
820
815
  });
821
816
 
817
+ // src/server.ts
818
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
819
+
820
+ // src/create-server.ts
821
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
822
+ import { z as z3 } from "zod";
823
+
822
824
  // src/client/sdk.gen.ts
823
825
  var accountsGetAccount = (options) => (options.client ?? client).get({
824
826
  security: [{ scheme: "bearer", type: "http" }],
@@ -2531,26 +2533,11 @@ var zUsersGetUsersData = z.looseObject({
2531
2533
  }).optional()
2532
2534
  });
2533
2535
 
2534
- // src/server.ts
2536
+ // src/helpers.ts
2537
+ import { z as z2 } from "zod";
2535
2538
  function listOf(schema) {
2536
2539
  return z2.looseObject({ items: z2.array(schema) });
2537
2540
  }
2538
- var server = new McpServer(
2539
- {
2540
- name: "practicepanther",
2541
- version: "1.0.0"
2542
- },
2543
- {
2544
- instructions: [
2545
- "PracticePanther is a legal practice management system.",
2546
- "IMPORTANT: The API does not support pagination.",
2547
- "List endpoints return ALL matching records, which can be very large.",
2548
- "Always constrain list calls with filters (date ranges, account/matter IDs, tags, etc.) to avoid returning excessive data.",
2549
- "Prefer using created_since/updated_since or date_from/date_to to narrow results.",
2550
- "If looking for a specific record, use a get-by-id tool instead of listing and filtering client-side."
2551
- ].join(" ")
2552
- }
2553
- );
2554
2541
  function cleanQuery(q) {
2555
2542
  return Object.fromEntries(
2556
2543
  Object.entries(q).filter(([, v]) => v !== void 0)
@@ -2563,610 +2550,639 @@ function err(e) {
2563
2550
  isError: true
2564
2551
  };
2565
2552
  }
2566
- var tools = [
2567
- // ── Accounts ──
2568
- {
2569
- name: "get_account",
2570
- description: "Get a single account (company or individual) by ID. Returns contacts, tags, custom fields, and assigned users.",
2571
- sdkFn: accountsGetAccount,
2572
- schema: zAccount,
2573
- pathParams: { id: "Account ID" }
2574
- },
2575
- {
2576
- name: "list_accounts",
2577
- description: "List accounts with optional filters. An account represents one or more contacts (e.g. a company).",
2578
- sdkFn: accountsGetAccounts,
2579
- schema: zAccount,
2580
- isList: true,
2581
- queryParams: {
2582
- assigned_to_user_id: z2.string().optional().describe("Filter by assigned user ID"),
2583
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2584
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2585
- search_text: z2.string().optional().describe("Search text"),
2586
- account_tag: z2.string().optional().describe("Filter by account tag")
2587
- }
2588
- },
2589
- // ── Bank Accounts ──
2590
- {
2591
- name: "get_bank_account",
2592
- description: "Get a single bank account (operating, trust, or credit card) by ID.",
2593
- sdkFn: bankAccountsGetBankAccount,
2594
- schema: zBankAccount,
2595
- pathParams: { id: "Bank Account ID" }
2596
- },
2597
- {
2598
- name: "list_bank_accounts",
2599
- description: "List all bank accounts.",
2600
- sdkFn: bankAccountsGetBankAccounts,
2601
- schema: zBankAccount,
2602
- isList: true,
2603
- queryParams: {
2604
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2605
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date")
2606
- }
2607
- },
2608
- // ── Call Logs ──
2609
- {
2610
- name: "get_call_log",
2611
- description: "Get a single call log entry by ID.",
2612
- sdkFn: callLogsGetCallLog,
2613
- schema: zCallLog,
2614
- pathParams: { id: "Call Log ID" }
2615
- },
2616
- {
2617
- name: "list_call_logs",
2618
- description: "List call log entries with optional filters by account, matter, user, date range, or tag.",
2619
- sdkFn: callLogsGetCallLogs,
2620
- schema: zCallLog,
2621
- isList: true,
2622
- queryParams: {
2623
- assigned_to_user_id: z2.string().optional().describe("Filter by assigned user ID"),
2624
- account_id: z2.string().optional().describe("Filter by account ID"),
2625
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2626
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2627
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2628
- date_from: z2.string().optional().describe("ISO date \u2014 filter from this date"),
2629
- date_to: z2.string().optional().describe("ISO date \u2014 filter to this date"),
2630
- activity_tag: z2.string().optional().describe("Filter by activity tag")
2631
- }
2632
- },
2633
- // ── Contacts ──
2634
- {
2635
- name: "get_contact",
2636
- description: "Get a single contact by ID. Each account can have multiple contacts; one is the primary.",
2637
- sdkFn: contactsGetContact,
2638
- schema: zContact,
2639
- pathParams: { id: "Contact ID" }
2640
- },
2641
- {
2642
- name: "list_contacts",
2643
- description: "List contacts with optional filters by account, status, user, search text, or company.",
2644
- sdkFn: contactsGetContacts,
2645
- schema: zContact,
2646
- isList: true,
2647
- queryParams: {
2648
- assigned_to_user_id: z2.string().optional().describe("Filter by assigned user ID"),
2649
- account_id: z2.string().optional().describe("Filter by account ID"),
2650
- status: z2.enum(["Active", "Archived"]).optional().describe("Filter by status"),
2651
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2652
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2653
- search_text: z2.string().optional().describe("Search text"),
2654
- account_tag: z2.string().optional().describe("Filter by account tag"),
2655
- company_name: z2.string().optional().describe("Filter by company name")
2656
- }
2657
- },
2658
- // ── Custom Fields ──
2659
- {
2660
- name: "get_custom_field",
2661
- description: "Get a single custom field definition by ID.",
2662
- sdkFn: customFieldsGetCustomField,
2663
- schema: zCustomField,
2664
- pathParams: { id: "Custom Field ID" }
2665
- },
2666
- {
2667
- name: "list_custom_fields_for_company",
2668
- description: "List custom field definitions for companies (accounts).",
2669
- sdkFn: customFieldsGetCustomFieldsForAccount,
2670
- schema: zCustomField,
2671
- isList: true,
2672
- queryParams: {
2673
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2674
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date")
2675
- }
2676
- },
2677
- {
2678
- name: "list_custom_fields_for_matter",
2679
- description: "List custom field definitions for matters.",
2680
- sdkFn: customFieldsGetCustomFieldsForMatter,
2681
- schema: zCustomField,
2682
- isList: true,
2683
- queryParams: {
2684
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2685
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date")
2686
- }
2687
- },
2688
- {
2689
- name: "list_custom_fields_for_contact",
2690
- description: "List custom field definitions for contacts.",
2691
- sdkFn: customFieldsGetCustomFieldsForContact,
2692
- schema: zCustomField,
2693
- isList: true,
2694
- queryParams: {
2695
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2696
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date")
2697
- }
2698
- },
2699
- // ── Emails ──
2700
- {
2701
- name: "get_email",
2702
- description: "Get a single email by ID. Returns full HTML body when fetched individually.",
2703
- sdkFn: emailsGetEmail,
2704
- schema: zEmail,
2705
- pathParams: { id: "Email ID" }
2706
- },
2707
- {
2708
- name: "list_emails",
2709
- description: "List emails with optional filters by account, matter, user, tag, or external message ID.",
2710
- sdkFn: emailsGetEmails,
2711
- schema: zEmail,
2712
- isList: true,
2713
- queryParams: {
2714
- assigned_to_user_id: z2.string().optional().describe("Filter by assigned user ID"),
2715
- account_id: z2.string().optional().describe("Filter by account ID"),
2716
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2717
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2718
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2719
- activity_tag: z2.string().optional().describe("Filter by activity tag"),
2720
- external_message_id: z2.string().optional().describe("Filter by external message ID")
2721
- }
2722
- },
2723
- // ── Events ──
2724
- {
2725
- name: "get_event",
2726
- description: "Get a single calendar event by ID.",
2727
- sdkFn: eventsGetEvent,
2728
- schema: zEvent,
2729
- pathParams: { id: "Event ID" }
2730
- },
2731
- {
2732
- name: "list_events",
2733
- description: "List calendar events with optional filters by account, matter, user, date range, or tag.",
2734
- sdkFn: eventsGetEvents,
2735
- schema: zEvent,
2736
- isList: true,
2737
- queryParams: {
2738
- assigned_to_user_id: z2.string().optional().describe("Filter by assigned user ID"),
2739
- account_id: z2.string().optional().describe("Filter by account ID"),
2740
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2741
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2742
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2743
- date_from: z2.string().optional().describe("ISO date \u2014 filter from this date"),
2744
- date_to: z2.string().optional().describe("ISO date \u2014 filter to this date"),
2745
- activity_tag: z2.string().optional().describe("Filter by activity tag")
2746
- }
2747
- },
2748
- // ── Expense Categories ──
2749
- {
2750
- name: "get_expense_category",
2751
- description: "Get a single expense category by ID.",
2752
- sdkFn: expenseCategoriesGetExpenseCategory,
2753
- schema: zExpenseCategory,
2754
- pathParams: { id: "Expense Category ID" }
2755
- },
2756
- {
2757
- name: "list_expense_categories",
2758
- description: "List all expense categories.",
2759
- sdkFn: expenseCategoriesGetExpenseCategories,
2760
- schema: zExpenseCategory,
2761
- isList: true,
2762
- queryParams: {
2763
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2764
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date")
2765
- }
2766
- },
2767
- // ── Expenses ──
2768
- {
2769
- name: "get_expense",
2770
- description: "Get a single expense by ID. Includes billable status, amount, and category.",
2771
- sdkFn: expensesGetExpense,
2772
- schema: zExpense,
2773
- pathParams: { id: "Expense ID" }
2774
- },
2775
- {
2776
- name: "list_expenses",
2777
- description: "List expenses with optional filters by account, matter, billing user, category, or date range.",
2778
- sdkFn: expensesGetExpensess,
2779
- schema: zExpense,
2780
- isList: true,
2781
- queryParams: {
2782
- account_id: z2.string().optional().describe("Filter by account ID"),
2783
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2784
- billed_by_user_id: z2.string().optional().describe("Filter by billing user ID"),
2785
- expense_category_id: z2.string().optional().describe("Filter by expense category ID"),
2786
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2787
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2788
- date_from: z2.string().optional().describe("ISO date \u2014 filter from this date"),
2789
- date_to: z2.string().optional().describe("ISO date \u2014 filter to this date")
2790
- }
2791
- },
2792
- // ── Files ──
2793
- {
2794
- name: "get_file",
2795
- description: "Get file metadata by ID (name, size, content type).",
2796
- sdkFn: filesGetFile,
2797
- schema: zFile,
2798
- pathParams: { id: "File ID" }
2799
- },
2800
- {
2801
- name: "download_file",
2802
- description: "Download a file's contents by ID.",
2803
- sdkFn: filesDownloadFile,
2804
- pathParams: { id: "File ID to download" },
2805
- rawContent: true
2806
- },
2807
- {
2808
- name: "list_files",
2809
- description: "List files with optional filters by account, matter, activity, creator, or search text.",
2810
- sdkFn: filesGetFiles,
2811
- schema: zFile,
2812
- isList: true,
2813
- queryParams: {
2814
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2815
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2816
- search_text: z2.string().optional().describe("Search text"),
2817
- account_id: z2.string().optional().describe("Filter by account ID"),
2818
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2819
- activity_id: z2.string().optional().describe("Filter by activity ID"),
2820
- created_by_user_id: z2.string().optional().describe("Filter by creating user ID")
2821
- }
2822
- },
2823
- // ── Flat Fees ──
2824
- {
2825
- name: "get_flat_fee",
2826
- description: "Get a single flat fee entry by ID.",
2827
- sdkFn: flatFeesGetFlatFee,
2828
- schema: zFlatFee,
2829
- pathParams: { id: "Flat Fee ID" }
2830
- },
2831
- {
2832
- name: "list_flat_fees",
2833
- description: "List flat fees with optional filters by account, matter, user, item, or date range.",
2834
- sdkFn: flatFeesGetFlatFees,
2835
- schema: zFlatFee,
2836
- isList: true,
2837
- queryParams: {
2838
- account_id: z2.string().optional().describe("Filter by account ID"),
2839
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2840
- user_id: z2.string().optional().describe("Filter by user ID"),
2841
- item_id: z2.string().optional().describe("Filter by item ID"),
2842
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2843
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2844
- date_from: z2.string().optional().describe("ISO date \u2014 filter from this date"),
2845
- date_to: z2.string().optional().describe("ISO date \u2014 filter to this date")
2846
- }
2847
- },
2848
- // ── Invoices ──
2849
- {
2850
- name: "get_invoice",
2851
- description: "Get a single invoice by ID with line items (time entries, expenses, flat fees).",
2852
- sdkFn: invoicesGetInvoice,
2853
- schema: zInvoice,
2854
- pathParams: { id: "Invoice ID" }
2855
- },
2856
- {
2857
- name: "list_invoices",
2858
- description: "List invoices with optional filters by account, matter, or date range.",
2859
- sdkFn: invoicesGetInvoices,
2860
- schema: zInvoice,
2861
- isList: true,
2862
- queryParams: {
2863
- account_id: z2.string().optional().describe("Filter by account ID"),
2864
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2865
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2866
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2867
- date_from: z2.string().optional().describe("ISO date \u2014 filter from this date"),
2868
- date_to: z2.string().optional().describe("ISO date \u2014 filter to this date")
2869
- }
2870
- },
2871
- // ── Items ──
2872
- {
2873
- name: "get_item",
2874
- description: "Get a single billing item/service by ID.",
2875
- sdkFn: itemsGetItem,
2876
- schema: zItem,
2877
- pathParams: { id: "Item ID" }
2878
- },
2879
- {
2880
- name: "list_items",
2881
- description: "List all billing items/services.",
2882
- sdkFn: itemsGetItems,
2883
- schema: zItem,
2884
- isList: true,
2885
- queryParams: {
2886
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2887
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date")
2888
- }
2889
- },
2890
- // ── Matters ──
2891
- {
2892
- name: "get_matter",
2893
- description: "Get a single matter (case/project) by ID. Returns status, assigned users, tags, and custom fields.",
2894
- sdkFn: mattersGetMatter,
2895
- schema: zMatter,
2896
- pathParams: { id: "Matter ID" }
2897
- },
2898
- {
2899
- name: "list_matters",
2900
- description: "List matters with optional filters by account, status (Open/Closed/Pending/Archived), user, search text, or tags.",
2901
- sdkFn: mattersGetMatters,
2902
- schema: zMatter,
2903
- isList: true,
2904
- queryParams: {
2905
- assigned_to_user_id: z2.string().optional().describe("Filter by assigned user ID"),
2906
- account_id: z2.string().optional().describe("Filter by account ID"),
2907
- status: z2.enum(["Closed", "Pending", "Open", "Archived"]).optional().describe("Filter by matter status"),
2908
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2909
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2910
- search_text: z2.string().optional().describe("Search text"),
2911
- account_tag: z2.string().optional().describe("Filter by account tag"),
2912
- matter_tag: z2.string().optional().describe("Filter by matter tag")
2913
- }
2914
- },
2915
- // ── Messages ──
2916
- {
2917
- name: "list_messages",
2918
- description: "List all messages.",
2919
- sdkFn: messagesGetMessagesAsync,
2920
- schema: zMessage,
2921
- isList: true
2922
- },
2923
- // ── Notes ──
2924
- {
2925
- name: "get_note",
2926
- description: "Get a single note by ID.",
2927
- sdkFn: notesGetNote,
2928
- schema: zNote,
2929
- pathParams: { id: "Note ID" }
2930
- },
2931
- {
2932
- name: "list_notes",
2933
- description: "List notes with optional filters by account, matter, user, date range, or tag.",
2934
- sdkFn: notesGetNotes,
2935
- schema: zNote,
2936
- isList: true,
2937
- queryParams: {
2938
- assigned_to_user_id: z2.string().optional().describe("Filter by assigned user ID"),
2939
- account_id: z2.string().optional().describe("Filter by account ID"),
2940
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2941
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2942
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2943
- date_from: z2.string().optional().describe("ISO date \u2014 filter from this date"),
2944
- date_to: z2.string().optional().describe("ISO date \u2014 filter to this date"),
2945
- activity_tag: z2.string().optional().describe("Filter by activity tag")
2946
- }
2947
- },
2948
- // ── Payments ──
2949
- {
2950
- name: "get_payment",
2951
- description: "Get a single payment by ID with full details including status.",
2952
- sdkFn: paymentsGetPayment,
2953
- schema: zPaymentDetail,
2954
- pathParams: { id: "Payment ID" }
2955
- },
2956
- {
2957
- name: "list_payments",
2958
- description: "List payments with optional filters by account, matter, bank account, type, or date range.",
2959
- sdkFn: paymentsGetPayments,
2960
- schema: zPayment,
2961
- isList: true,
2962
- queryParams: {
2963
- account_id: z2.string().optional().describe("Filter by account ID"),
2964
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2965
- bank_account_id: z2.string().optional().describe("Filter by bank account ID"),
2966
- bank_account_type: z2.enum(["Operating", "Trust", "CreditCard"]).optional().describe("Filter by bank account type"),
2967
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2968
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
2969
- date_from: z2.string().optional().describe("ISO date \u2014 filter from this date"),
2970
- date_to: z2.string().optional().describe("ISO date \u2014 filter to this date")
2971
- }
2972
- },
2973
- // ── Relationships ──
2974
- {
2975
- name: "get_relationship",
2976
- description: "Get a single matter-contact relationship by ID.",
2977
- sdkFn: relationshipsGetRelationship,
2978
- schema: zRelationship,
2979
- pathParams: { id: "Relationship ID" }
2980
- },
2981
- {
2982
- name: "list_relationships",
2983
- description: "List relationships between contacts and matters with optional filters.",
2984
- sdkFn: relationshipsGetRelationships,
2985
- schema: zRelationship,
2986
- isList: true,
2987
- queryParams: {
2988
- contact_id: z2.string().optional().describe("Filter by contact ID"),
2989
- matter_id: z2.string().optional().describe("Filter by matter ID"),
2990
- account_id: z2.string().optional().describe("Filter by account ID"),
2991
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
2992
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date")
2993
- }
2994
- },
2995
- // ── Tags ──
2996
- {
2997
- name: "list_account_tags",
2998
- description: "List all tags available for accounts.",
2999
- sdkFn: tagsGetTagsForAccounts,
3000
- schema: zTag,
3001
- isList: true
3002
- },
3003
- {
3004
- name: "list_matter_tags",
3005
- description: "List all tags available for matters.",
3006
- sdkFn: tagsGetTagsForProjects,
3007
- schema: zTag,
3008
- isList: true
3009
- },
3010
- {
3011
- name: "list_activity_tags",
3012
- description: "List all tags available for activities (call logs, events, notes, etc.).",
3013
- sdkFn: tagsGetTagsForActivities,
3014
- schema: zTag,
3015
- isList: true
3016
- },
3017
- // ── Tasks ──
3018
- {
3019
- name: "get_task",
3020
- description: "Get a single task by ID.",
3021
- sdkFn: tasksGetTask,
3022
- schema: zTask,
3023
- pathParams: { id: "Task ID" }
3024
- },
3025
- {
3026
- name: "list_tasks",
3027
- description: "List tasks with optional filters by account, matter, user, status, due date range, or tag.",
3028
- sdkFn: tasksGetTasks,
3029
- schema: zTask,
3030
- isList: true,
3031
- queryParams: {
3032
- assigned_to_user_id: z2.string().optional().describe("Filter by assigned user ID"),
3033
- account_id: z2.string().optional().describe("Filter by account ID"),
3034
- matter_id: z2.string().optional().describe("Filter by matter ID"),
3035
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
3036
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
3037
- status: z2.enum(["NotCompleted", "InProgress", "Completed", "Conditional"]).optional().describe("Filter by task status"),
3038
- due_date_from: z2.string().optional().describe("ISO date \u2014 filter by due date from"),
3039
- due_date_to: z2.string().optional().describe("ISO date \u2014 filter by due date to"),
3040
- activity_tag: z2.string().optional().describe("Filter by activity tag")
3041
- }
3042
- },
3043
- // ── Time Entries ──
3044
- {
3045
- name: "get_time_entry",
3046
- description: "Get a single time entry by ID. Hours are decimal (e.g. 1.5 = 1h30m).",
3047
- sdkFn: timeEntriesGetTimeEntry,
3048
- schema: zTimeEntry,
3049
- pathParams: { id: "Time Entry ID" }
3050
- },
3051
- {
3052
- name: "list_time_entries",
3053
- description: "List time entries with optional filters by account, matter, user, item, or date range.",
3054
- sdkFn: timeEntriesGetTimeEntrys,
3055
- schema: zTimeEntry,
3056
- isList: true,
3057
- queryParams: {
3058
- account_id: z2.string().optional().describe("Filter by account ID"),
3059
- matter_id: z2.string().optional().describe("Filter by matter ID"),
3060
- user_id: z2.string().optional().describe("Filter by user ID"),
3061
- item_id: z2.string().optional().describe("Filter by item ID"),
3062
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
3063
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
3064
- date_from: z2.string().optional().describe("ISO date \u2014 filter from this date"),
3065
- date_to: z2.string().optional().describe("ISO date \u2014 filter to this date")
3066
- }
3067
- },
3068
- // ── Users ──
3069
- {
3070
- name: "get_me",
3071
- description: "Get the currently authenticated user's profile.",
3072
- sdkFn: usersMe,
3073
- schema: zUser
3074
- },
3075
- {
3076
- name: "get_user",
3077
- description: "Get a single user by ID.",
3078
- sdkFn: usersGetUser,
3079
- schema: zUser,
3080
- pathParams: { id: "User ID" }
3081
- },
3082
- {
3083
- name: "list_users",
3084
- description: "List users with optional filters by creation date, update date, or email address.",
3085
- sdkFn: usersGetUsers,
3086
- schema: zUser,
3087
- isList: true,
3088
- queryParams: {
3089
- created_since: z2.string().optional().describe("ISO date \u2014 return records created after this date"),
3090
- updated_since: z2.string().optional().describe("ISO date \u2014 return records updated after this date"),
3091
- email_address: z2.string().optional().describe("Filter by email address")
3092
- }
3093
- }
3094
- ];
3095
- for (const tool of tools) {
3096
- const inputSchema = {};
3097
- if (tool.pathParams) {
3098
- for (const [paramName, description] of Object.entries(tool.pathParams)) {
3099
- inputSchema[paramName] = z2.string().describe(description);
3100
- }
3101
- }
3102
- if (tool.queryParams) {
3103
- for (const [paramName, zodType] of Object.entries(tool.queryParams)) {
3104
- inputSchema[paramName] = zodType;
3105
- }
3106
- }
3107
- const outputSchema = tool.schema ? tool.isList ? listOf(tool.schema) : tool.schema : void 0;
3108
- server.registerTool(
3109
- tool.name,
3110
- {
3111
- description: tool.description,
3112
- inputSchema: Object.keys(inputSchema).length > 0 ? inputSchema : void 0,
3113
- outputSchema
3114
- },
3115
- async (params) => {
3116
- try {
3117
- const options = {};
3118
- if (tool.pathParams) {
3119
- const path = {};
3120
- for (const paramName of Object.keys(tool.pathParams)) {
3121
- path[paramName] = params[paramName];
3122
- }
3123
- options.path = path;
2553
+
2554
+ // src/tool-handler.ts
2555
+ function createToolHandler(tool) {
2556
+ return async (params) => {
2557
+ try {
2558
+ const options = {};
2559
+ if (tool.pathParams) {
2560
+ const path = {};
2561
+ for (const paramName of Object.keys(tool.pathParams)) {
2562
+ path[paramName] = params[paramName];
3124
2563
  }
3125
- if (tool.queryParams) {
3126
- const query = {};
3127
- for (const paramName of Object.keys(tool.queryParams)) {
3128
- if (params[paramName] !== void 0) {
3129
- query[paramName] = params[paramName];
3130
- }
3131
- }
3132
- if (Object.keys(query).length > 0) {
3133
- options.query = cleanQuery(query);
2564
+ options.path = path;
2565
+ }
2566
+ if (tool.queryParams) {
2567
+ const query = {};
2568
+ for (const paramName of Object.keys(tool.queryParams)) {
2569
+ if (params[paramName] !== void 0) {
2570
+ query[paramName] = params[paramName];
3134
2571
  }
3135
2572
  }
3136
- const res = await tool.sdkFn(
3137
- Object.keys(options).length > 0 ? options : void 0
3138
- );
3139
- if (tool.rawContent) {
3140
- return {
3141
- content: [
3142
- {
3143
- type: "text",
3144
- text: JSON.stringify(res.data, null, 2)
3145
- }
3146
- ]
3147
- };
2573
+ if (Object.keys(query).length > 0) {
2574
+ options.query = cleanQuery(query);
3148
2575
  }
3149
- const structured = tool.isList ? { items: res.data } : res.data;
2576
+ }
2577
+ const res = await tool.sdkFn(
2578
+ Object.keys(options).length > 0 ? options : void 0
2579
+ );
2580
+ if (tool.rawContent) {
3150
2581
  return {
3151
2582
  content: [
3152
2583
  {
3153
2584
  type: "text",
3154
- text: JSON.stringify(structured, null, 2)
2585
+ text: JSON.stringify(res.data, null, 2)
3155
2586
  }
3156
- ],
3157
- structuredContent: tool.schema ? structured : void 0
2587
+ ]
3158
2588
  };
3159
- } catch (e) {
3160
- return err(e);
3161
2589
  }
2590
+ const structured = tool.isList ? { items: res.data } : res.data;
2591
+ return {
2592
+ content: [
2593
+ {
2594
+ type: "text",
2595
+ text: JSON.stringify(structured, null, 2)
2596
+ }
2597
+ ],
2598
+ structuredContent: tool.schema ? structured : void 0
2599
+ };
2600
+ } catch (e) {
2601
+ return err(e);
2602
+ }
2603
+ };
2604
+ }
2605
+
2606
+ // src/create-server.ts
2607
+ function createServer() {
2608
+ const server = new McpServer(
2609
+ {
2610
+ name: "practicepanther",
2611
+ version: "1.0.0"
2612
+ },
2613
+ {
2614
+ instructions: [
2615
+ "PracticePanther is a legal practice management system.",
2616
+ "IMPORTANT: The API does not support pagination.",
2617
+ "List endpoints return ALL matching records, which can be very large.",
2618
+ "Always constrain list calls with filters (date ranges, account/matter IDs, tags, etc.) to avoid returning excessive data.",
2619
+ "Prefer using created_since/updated_since or date_from/date_to to narrow results.",
2620
+ "If looking for a specific record, use a get-by-id tool instead of listing and filtering client-side."
2621
+ ].join(" ")
3162
2622
  }
3163
2623
  );
2624
+ const tools = [
2625
+ // ── Accounts ──
2626
+ {
2627
+ name: "get_account",
2628
+ description: "Get a single account (company or individual) by ID. Returns contacts, tags, custom fields, and assigned users.",
2629
+ sdkFn: accountsGetAccount,
2630
+ schema: zAccount,
2631
+ pathParams: { id: "Account ID" }
2632
+ },
2633
+ {
2634
+ name: "list_accounts",
2635
+ description: "List accounts with optional filters. An account represents one or more contacts (e.g. a company).",
2636
+ sdkFn: accountsGetAccounts,
2637
+ schema: zAccount,
2638
+ isList: true,
2639
+ queryParams: {
2640
+ assigned_to_user_id: z3.string().optional().describe("Filter by assigned user ID"),
2641
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2642
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2643
+ search_text: z3.string().optional().describe("Search text"),
2644
+ account_tag: z3.string().optional().describe("Filter by account tag")
2645
+ }
2646
+ },
2647
+ // ── Bank Accounts ──
2648
+ {
2649
+ name: "get_bank_account",
2650
+ description: "Get a single bank account (operating, trust, or credit card) by ID.",
2651
+ sdkFn: bankAccountsGetBankAccount,
2652
+ schema: zBankAccount,
2653
+ pathParams: { id: "Bank Account ID" }
2654
+ },
2655
+ {
2656
+ name: "list_bank_accounts",
2657
+ description: "List all bank accounts.",
2658
+ sdkFn: bankAccountsGetBankAccounts,
2659
+ schema: zBankAccount,
2660
+ isList: true,
2661
+ queryParams: {
2662
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2663
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date")
2664
+ }
2665
+ },
2666
+ // ── Call Logs ──
2667
+ {
2668
+ name: "get_call_log",
2669
+ description: "Get a single call log entry by ID.",
2670
+ sdkFn: callLogsGetCallLog,
2671
+ schema: zCallLog,
2672
+ pathParams: { id: "Call Log ID" }
2673
+ },
2674
+ {
2675
+ name: "list_call_logs",
2676
+ description: "List call log entries with optional filters by account, matter, user, date range, or tag.",
2677
+ sdkFn: callLogsGetCallLogs,
2678
+ schema: zCallLog,
2679
+ isList: true,
2680
+ queryParams: {
2681
+ assigned_to_user_id: z3.string().optional().describe("Filter by assigned user ID"),
2682
+ account_id: z3.string().optional().describe("Filter by account ID"),
2683
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
2684
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2685
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2686
+ date_from: z3.string().optional().describe("ISO date \u2014 filter from this date"),
2687
+ date_to: z3.string().optional().describe("ISO date \u2014 filter to this date"),
2688
+ activity_tag: z3.string().optional().describe("Filter by activity tag")
2689
+ }
2690
+ },
2691
+ // ── Contacts ──
2692
+ {
2693
+ name: "get_contact",
2694
+ description: "Get a single contact by ID. Each account can have multiple contacts; one is the primary.",
2695
+ sdkFn: contactsGetContact,
2696
+ schema: zContact,
2697
+ pathParams: { id: "Contact ID" }
2698
+ },
2699
+ {
2700
+ name: "list_contacts",
2701
+ description: "List contacts with optional filters by account, status, user, search text, or company.",
2702
+ sdkFn: contactsGetContacts,
2703
+ schema: zContact,
2704
+ isList: true,
2705
+ queryParams: {
2706
+ assigned_to_user_id: z3.string().optional().describe("Filter by assigned user ID"),
2707
+ account_id: z3.string().optional().describe("Filter by account ID"),
2708
+ status: z3.enum(["Active", "Archived"]).optional().describe("Filter by status"),
2709
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2710
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2711
+ search_text: z3.string().optional().describe("Search text"),
2712
+ account_tag: z3.string().optional().describe("Filter by account tag"),
2713
+ company_name: z3.string().optional().describe("Filter by company name")
2714
+ }
2715
+ },
2716
+ // ── Custom Fields ──
2717
+ {
2718
+ name: "get_custom_field",
2719
+ description: "Get a single custom field definition by ID.",
2720
+ sdkFn: customFieldsGetCustomField,
2721
+ schema: zCustomField,
2722
+ pathParams: { id: "Custom Field ID" }
2723
+ },
2724
+ {
2725
+ name: "list_custom_fields_for_company",
2726
+ description: "List custom field definitions for companies (accounts).",
2727
+ sdkFn: customFieldsGetCustomFieldsForAccount,
2728
+ schema: zCustomField,
2729
+ isList: true,
2730
+ queryParams: {
2731
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2732
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date")
2733
+ }
2734
+ },
2735
+ {
2736
+ name: "list_custom_fields_for_matter",
2737
+ description: "List custom field definitions for matters.",
2738
+ sdkFn: customFieldsGetCustomFieldsForMatter,
2739
+ schema: zCustomField,
2740
+ isList: true,
2741
+ queryParams: {
2742
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2743
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date")
2744
+ }
2745
+ },
2746
+ {
2747
+ name: "list_custom_fields_for_contact",
2748
+ description: "List custom field definitions for contacts.",
2749
+ sdkFn: customFieldsGetCustomFieldsForContact,
2750
+ schema: zCustomField,
2751
+ isList: true,
2752
+ queryParams: {
2753
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2754
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date")
2755
+ }
2756
+ },
2757
+ // ── Emails ──
2758
+ {
2759
+ name: "get_email",
2760
+ description: "Get a single email by ID. Returns full HTML body when fetched individually.",
2761
+ sdkFn: emailsGetEmail,
2762
+ schema: zEmail,
2763
+ pathParams: { id: "Email ID" }
2764
+ },
2765
+ {
2766
+ name: "list_emails",
2767
+ description: "List emails with optional filters by account, matter, user, tag, or external message ID.",
2768
+ sdkFn: emailsGetEmails,
2769
+ schema: zEmail,
2770
+ isList: true,
2771
+ queryParams: {
2772
+ assigned_to_user_id: z3.string().optional().describe("Filter by assigned user ID"),
2773
+ account_id: z3.string().optional().describe("Filter by account ID"),
2774
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
2775
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2776
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2777
+ activity_tag: z3.string().optional().describe("Filter by activity tag"),
2778
+ external_message_id: z3.string().optional().describe("Filter by external message ID")
2779
+ }
2780
+ },
2781
+ // ── Events ──
2782
+ {
2783
+ name: "get_event",
2784
+ description: "Get a single calendar event by ID.",
2785
+ sdkFn: eventsGetEvent,
2786
+ schema: zEvent,
2787
+ pathParams: { id: "Event ID" }
2788
+ },
2789
+ {
2790
+ name: "list_events",
2791
+ description: "List calendar events with optional filters by account, matter, user, date range, or tag.",
2792
+ sdkFn: eventsGetEvents,
2793
+ schema: zEvent,
2794
+ isList: true,
2795
+ queryParams: {
2796
+ assigned_to_user_id: z3.string().optional().describe("Filter by assigned user ID"),
2797
+ account_id: z3.string().optional().describe("Filter by account ID"),
2798
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
2799
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2800
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2801
+ date_from: z3.string().optional().describe("ISO date \u2014 filter from this date"),
2802
+ date_to: z3.string().optional().describe("ISO date \u2014 filter to this date"),
2803
+ activity_tag: z3.string().optional().describe("Filter by activity tag")
2804
+ }
2805
+ },
2806
+ // ── Expense Categories ──
2807
+ {
2808
+ name: "get_expense_category",
2809
+ description: "Get a single expense category by ID.",
2810
+ sdkFn: expenseCategoriesGetExpenseCategory,
2811
+ schema: zExpenseCategory,
2812
+ pathParams: { id: "Expense Category ID" }
2813
+ },
2814
+ {
2815
+ name: "list_expense_categories",
2816
+ description: "List all expense categories.",
2817
+ sdkFn: expenseCategoriesGetExpenseCategories,
2818
+ schema: zExpenseCategory,
2819
+ isList: true,
2820
+ queryParams: {
2821
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2822
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date")
2823
+ }
2824
+ },
2825
+ // ── Expenses ──
2826
+ {
2827
+ name: "get_expense",
2828
+ description: "Get a single expense by ID. Includes billable status, amount, and category.",
2829
+ sdkFn: expensesGetExpense,
2830
+ schema: zExpense,
2831
+ pathParams: { id: "Expense ID" }
2832
+ },
2833
+ {
2834
+ name: "list_expenses",
2835
+ description: "List expenses with optional filters by account, matter, billing user, category, or date range.",
2836
+ sdkFn: expensesGetExpensess,
2837
+ schema: zExpense,
2838
+ isList: true,
2839
+ queryParams: {
2840
+ account_id: z3.string().optional().describe("Filter by account ID"),
2841
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
2842
+ billed_by_user_id: z3.string().optional().describe("Filter by billing user ID"),
2843
+ expense_category_id: z3.string().optional().describe("Filter by expense category ID"),
2844
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2845
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2846
+ date_from: z3.string().optional().describe("ISO date \u2014 filter from this date"),
2847
+ date_to: z3.string().optional().describe("ISO date \u2014 filter to this date")
2848
+ }
2849
+ },
2850
+ // ── Files ──
2851
+ {
2852
+ name: "get_file",
2853
+ description: "Get file metadata by ID (name, size, content type).",
2854
+ sdkFn: filesGetFile,
2855
+ schema: zFile,
2856
+ pathParams: { id: "File ID" }
2857
+ },
2858
+ {
2859
+ name: "download_file",
2860
+ description: "Download a file's contents by ID.",
2861
+ sdkFn: filesDownloadFile,
2862
+ pathParams: { id: "File ID to download" },
2863
+ rawContent: true
2864
+ },
2865
+ {
2866
+ name: "list_files",
2867
+ description: "List files with optional filters by account, matter, activity, creator, or search text.",
2868
+ sdkFn: filesGetFiles,
2869
+ schema: zFile,
2870
+ isList: true,
2871
+ queryParams: {
2872
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2873
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2874
+ search_text: z3.string().optional().describe("Search text"),
2875
+ account_id: z3.string().optional().describe("Filter by account ID"),
2876
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
2877
+ activity_id: z3.string().optional().describe("Filter by activity ID"),
2878
+ created_by_user_id: z3.string().optional().describe("Filter by creating user ID")
2879
+ }
2880
+ },
2881
+ // ── Flat Fees ──
2882
+ {
2883
+ name: "get_flat_fee",
2884
+ description: "Get a single flat fee entry by ID.",
2885
+ sdkFn: flatFeesGetFlatFee,
2886
+ schema: zFlatFee,
2887
+ pathParams: { id: "Flat Fee ID" }
2888
+ },
2889
+ {
2890
+ name: "list_flat_fees",
2891
+ description: "List flat fees with optional filters by account, matter, user, item, or date range.",
2892
+ sdkFn: flatFeesGetFlatFees,
2893
+ schema: zFlatFee,
2894
+ isList: true,
2895
+ queryParams: {
2896
+ account_id: z3.string().optional().describe("Filter by account ID"),
2897
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
2898
+ user_id: z3.string().optional().describe("Filter by user ID"),
2899
+ item_id: z3.string().optional().describe("Filter by item ID"),
2900
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2901
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2902
+ date_from: z3.string().optional().describe("ISO date \u2014 filter from this date"),
2903
+ date_to: z3.string().optional().describe("ISO date \u2014 filter to this date")
2904
+ }
2905
+ },
2906
+ // ── Invoices ──
2907
+ {
2908
+ name: "get_invoice",
2909
+ description: "Get a single invoice by ID with line items (time entries, expenses, flat fees).",
2910
+ sdkFn: invoicesGetInvoice,
2911
+ schema: zInvoice,
2912
+ pathParams: { id: "Invoice ID" }
2913
+ },
2914
+ {
2915
+ name: "list_invoices",
2916
+ description: "List invoices with optional filters by account, matter, or date range.",
2917
+ sdkFn: invoicesGetInvoices,
2918
+ schema: zInvoice,
2919
+ isList: true,
2920
+ queryParams: {
2921
+ account_id: z3.string().optional().describe("Filter by account ID"),
2922
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
2923
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2924
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2925
+ date_from: z3.string().optional().describe("ISO date \u2014 filter from this date"),
2926
+ date_to: z3.string().optional().describe("ISO date \u2014 filter to this date")
2927
+ }
2928
+ },
2929
+ // ── Items ──
2930
+ {
2931
+ name: "get_item",
2932
+ description: "Get a single billing item/service by ID.",
2933
+ sdkFn: itemsGetItem,
2934
+ schema: zItem,
2935
+ pathParams: { id: "Item ID" }
2936
+ },
2937
+ {
2938
+ name: "list_items",
2939
+ description: "List all billing items/services.",
2940
+ sdkFn: itemsGetItems,
2941
+ schema: zItem,
2942
+ isList: true,
2943
+ queryParams: {
2944
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2945
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date")
2946
+ }
2947
+ },
2948
+ // ── Matters ──
2949
+ {
2950
+ name: "get_matter",
2951
+ description: "Get a single matter (case/project) by ID. Returns status, assigned users, tags, and custom fields.",
2952
+ sdkFn: mattersGetMatter,
2953
+ schema: zMatter,
2954
+ pathParams: { id: "Matter ID" }
2955
+ },
2956
+ {
2957
+ name: "list_matters",
2958
+ description: "List matters with optional filters by account, status (Open/Closed/Pending/Archived), user, search text, or tags.",
2959
+ sdkFn: mattersGetMatters,
2960
+ schema: zMatter,
2961
+ isList: true,
2962
+ queryParams: {
2963
+ assigned_to_user_id: z3.string().optional().describe("Filter by assigned user ID"),
2964
+ account_id: z3.string().optional().describe("Filter by account ID"),
2965
+ status: z3.enum(["Closed", "Pending", "Open", "Archived"]).optional().describe("Filter by matter status"),
2966
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
2967
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
2968
+ search_text: z3.string().optional().describe("Search text"),
2969
+ account_tag: z3.string().optional().describe("Filter by account tag"),
2970
+ matter_tag: z3.string().optional().describe("Filter by matter tag")
2971
+ }
2972
+ },
2973
+ // ── Messages ──
2974
+ {
2975
+ name: "list_messages",
2976
+ description: "List all messages.",
2977
+ sdkFn: messagesGetMessagesAsync,
2978
+ schema: zMessage,
2979
+ isList: true
2980
+ },
2981
+ // ── Notes ──
2982
+ {
2983
+ name: "get_note",
2984
+ description: "Get a single note by ID.",
2985
+ sdkFn: notesGetNote,
2986
+ schema: zNote,
2987
+ pathParams: { id: "Note ID" }
2988
+ },
2989
+ {
2990
+ name: "list_notes",
2991
+ description: "List notes with optional filters by account, matter, user, date range, or tag.",
2992
+ sdkFn: notesGetNotes,
2993
+ schema: zNote,
2994
+ isList: true,
2995
+ queryParams: {
2996
+ assigned_to_user_id: z3.string().optional().describe("Filter by assigned user ID"),
2997
+ account_id: z3.string().optional().describe("Filter by account ID"),
2998
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
2999
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
3000
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
3001
+ date_from: z3.string().optional().describe("ISO date \u2014 filter from this date"),
3002
+ date_to: z3.string().optional().describe("ISO date \u2014 filter to this date"),
3003
+ activity_tag: z3.string().optional().describe("Filter by activity tag")
3004
+ }
3005
+ },
3006
+ // ── Payments ──
3007
+ {
3008
+ name: "get_payment",
3009
+ description: "Get a single payment by ID with full details including status.",
3010
+ sdkFn: paymentsGetPayment,
3011
+ schema: zPaymentDetail,
3012
+ pathParams: { id: "Payment ID" }
3013
+ },
3014
+ {
3015
+ name: "list_payments",
3016
+ description: "List payments with optional filters by account, matter, bank account, type, or date range.",
3017
+ sdkFn: paymentsGetPayments,
3018
+ schema: zPayment,
3019
+ isList: true,
3020
+ queryParams: {
3021
+ account_id: z3.string().optional().describe("Filter by account ID"),
3022
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
3023
+ bank_account_id: z3.string().optional().describe("Filter by bank account ID"),
3024
+ bank_account_type: z3.enum(["Operating", "Trust", "CreditCard"]).optional().describe("Filter by bank account type"),
3025
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
3026
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
3027
+ date_from: z3.string().optional().describe("ISO date \u2014 filter from this date"),
3028
+ date_to: z3.string().optional().describe("ISO date \u2014 filter to this date")
3029
+ }
3030
+ },
3031
+ // ── Relationships ──
3032
+ {
3033
+ name: "get_relationship",
3034
+ description: "Get a single matter-contact relationship by ID.",
3035
+ sdkFn: relationshipsGetRelationship,
3036
+ schema: zRelationship,
3037
+ pathParams: { id: "Relationship ID" }
3038
+ },
3039
+ {
3040
+ name: "list_relationships",
3041
+ description: "List relationships between contacts and matters with optional filters.",
3042
+ sdkFn: relationshipsGetRelationships,
3043
+ schema: zRelationship,
3044
+ isList: true,
3045
+ queryParams: {
3046
+ contact_id: z3.string().optional().describe("Filter by contact ID"),
3047
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
3048
+ account_id: z3.string().optional().describe("Filter by account ID"),
3049
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
3050
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date")
3051
+ }
3052
+ },
3053
+ // ── Tags ──
3054
+ {
3055
+ name: "list_account_tags",
3056
+ description: "List all tags available for accounts.",
3057
+ sdkFn: tagsGetTagsForAccounts,
3058
+ schema: zTag,
3059
+ isList: true
3060
+ },
3061
+ {
3062
+ name: "list_matter_tags",
3063
+ description: "List all tags available for matters.",
3064
+ sdkFn: tagsGetTagsForProjects,
3065
+ schema: zTag,
3066
+ isList: true
3067
+ },
3068
+ {
3069
+ name: "list_activity_tags",
3070
+ description: "List all tags available for activities (call logs, events, notes, etc.).",
3071
+ sdkFn: tagsGetTagsForActivities,
3072
+ schema: zTag,
3073
+ isList: true
3074
+ },
3075
+ // ── Tasks ──
3076
+ {
3077
+ name: "get_task",
3078
+ description: "Get a single task by ID.",
3079
+ sdkFn: tasksGetTask,
3080
+ schema: zTask,
3081
+ pathParams: { id: "Task ID" }
3082
+ },
3083
+ {
3084
+ name: "list_tasks",
3085
+ description: "List tasks with optional filters by account, matter, user, status, due date range, or tag.",
3086
+ sdkFn: tasksGetTasks,
3087
+ schema: zTask,
3088
+ isList: true,
3089
+ queryParams: {
3090
+ assigned_to_user_id: z3.string().optional().describe("Filter by assigned user ID"),
3091
+ account_id: z3.string().optional().describe("Filter by account ID"),
3092
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
3093
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
3094
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
3095
+ status: z3.enum(["NotCompleted", "InProgress", "Completed", "Conditional"]).optional().describe("Filter by task status"),
3096
+ due_date_from: z3.string().optional().describe("ISO date \u2014 filter by due date from"),
3097
+ due_date_to: z3.string().optional().describe("ISO date \u2014 filter by due date to"),
3098
+ activity_tag: z3.string().optional().describe("Filter by activity tag")
3099
+ }
3100
+ },
3101
+ // ── Time Entries ──
3102
+ {
3103
+ name: "get_time_entry",
3104
+ description: "Get a single time entry by ID. Hours are decimal (e.g. 1.5 = 1h30m).",
3105
+ sdkFn: timeEntriesGetTimeEntry,
3106
+ schema: zTimeEntry,
3107
+ pathParams: { id: "Time Entry ID" }
3108
+ },
3109
+ {
3110
+ name: "list_time_entries",
3111
+ description: "List time entries with optional filters by account, matter, user, item, or date range.",
3112
+ sdkFn: timeEntriesGetTimeEntrys,
3113
+ schema: zTimeEntry,
3114
+ isList: true,
3115
+ queryParams: {
3116
+ account_id: z3.string().optional().describe("Filter by account ID"),
3117
+ matter_id: z3.string().optional().describe("Filter by matter ID"),
3118
+ user_id: z3.string().optional().describe("Filter by user ID"),
3119
+ item_id: z3.string().optional().describe("Filter by item ID"),
3120
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
3121
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
3122
+ date_from: z3.string().optional().describe("ISO date \u2014 filter from this date"),
3123
+ date_to: z3.string().optional().describe("ISO date \u2014 filter to this date")
3124
+ }
3125
+ },
3126
+ // ── Users ──
3127
+ {
3128
+ name: "get_me",
3129
+ description: "Get the currently authenticated user's profile.",
3130
+ sdkFn: usersMe,
3131
+ schema: zUser
3132
+ },
3133
+ {
3134
+ name: "get_user",
3135
+ description: "Get a single user by ID.",
3136
+ sdkFn: usersGetUser,
3137
+ schema: zUser,
3138
+ pathParams: { id: "User ID" }
3139
+ },
3140
+ {
3141
+ name: "list_users",
3142
+ description: "List users with optional filters by creation date, update date, or email address.",
3143
+ sdkFn: usersGetUsers,
3144
+ schema: zUser,
3145
+ isList: true,
3146
+ queryParams: {
3147
+ created_since: z3.string().optional().describe("ISO date \u2014 return records created after this date"),
3148
+ updated_since: z3.string().optional().describe("ISO date \u2014 return records updated after this date"),
3149
+ email_address: z3.string().optional().describe("Filter by email address")
3150
+ }
3151
+ }
3152
+ ];
3153
+ for (const tool of tools) {
3154
+ const inputSchema = {};
3155
+ if (tool.pathParams) {
3156
+ for (const [paramName, description] of Object.entries(tool.pathParams)) {
3157
+ inputSchema[paramName] = z3.string().describe(description);
3158
+ }
3159
+ }
3160
+ if (tool.queryParams) {
3161
+ for (const [paramName, zodType] of Object.entries(tool.queryParams)) {
3162
+ inputSchema[paramName] = zodType;
3163
+ }
3164
+ }
3165
+ const outputSchema = tool.schema ? tool.isList ? listOf(tool.schema) : tool.schema : void 0;
3166
+ server.registerTool(
3167
+ tool.name,
3168
+ {
3169
+ description: tool.description,
3170
+ inputSchema: Object.keys(inputSchema).length > 0 ? inputSchema : void 0,
3171
+ outputSchema
3172
+ },
3173
+ createToolHandler(tool)
3174
+ );
3175
+ }
3176
+ return server;
3164
3177
  }
3178
+
3179
+ // src/server.ts
3165
3180
  var command = process.argv[2];
3166
3181
  if (command === "auth") {
3167
3182
  const { runCli } = await import("./auth.js");
3168
3183
  runCli(process.argv[3]);
3169
3184
  } else {
3185
+ const server = createServer();
3170
3186
  const transport = new StdioServerTransport();
3171
3187
  await server.connect(transport);
3172
3188
  }