@studiometa/productive-mcp 0.8.0 → 0.8.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/handlers/help.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA+Z7C;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAcvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAW/C"}
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/handlers/help.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA4c7C;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAcvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAW/C"}
package/dist/handlers.js CHANGED
@@ -1,4 +1,4 @@
1
- import { e } from "./index-D743zTS1.js";
1
+ import { e } from "./index-BDke-bMP.js";
2
2
  export {
3
3
  e as executeToolWithCredentials
4
4
  };
package/dist/http.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createApp, createRouter, defineEventHandler, setResponseHeader, getHeader, readBody } from "h3";
2
2
  import { parseAuthHeader } from "./auth.js";
3
- import { e as executeToolWithCredentials } from "./index-D743zTS1.js";
4
- import { V as VERSION, I as INSTRUCTIONS } from "./version-i2-GF6d1.js";
3
+ import { e as executeToolWithCredentials } from "./index-BDke-bMP.js";
4
+ import { V as VERSION, I as INSTRUCTIONS } from "./version-DR8X3j5G.js";
5
5
  import { oauthMetadataHandler, registerHandler, authorizeGetHandler, authorizePostHandler, tokenHandler } from "./oauth.js";
6
6
  import { TOOLS } from "./tools.js";
7
7
  function jsonRpcError(code, message, id = null) {
@@ -397,9 +397,11 @@ const RESOURCE_HELP = {
397
397
  },
398
398
  filters: {
399
399
  query: "Text search on project name",
400
- project_type_id: "Filter by project type",
400
+ project_type: "Filter by project type: 1=internal, 2=client",
401
401
  company_id: "Filter by company",
402
- archived: "Filter by archived status (true/false)"
402
+ responsible_id: "Filter by project manager",
403
+ person_id: "Filter by team member",
404
+ status: "Filter by status: 1=active, 2=archived"
403
405
  },
404
406
  fields: {
405
407
  id: "Unique project identifier",
@@ -434,9 +436,18 @@ const RESOURCE_HELP = {
434
436
  filters: {
435
437
  query: "Text search on task title",
436
438
  project_id: "Filter by project",
439
+ company_id: "Filter by company",
437
440
  assignee_id: "Filter by assigned person",
438
- status: "Filter by status (open, closed, all)",
439
- task_list_id: "Filter by task list"
441
+ creator_id: "Filter by task creator",
442
+ status: 'Filter by status: 1=open, 2=closed (or "open", "closed", "all")',
443
+ task_list_id: "Filter by task list",
444
+ board_id: "Filter by board",
445
+ workflow_status_id: "Filter by workflow status (kanban column)",
446
+ parent_task_id: "Filter by parent task (for subtasks)",
447
+ overdue_status: "Filter by overdue: 1=not overdue, 2=overdue",
448
+ due_date_on: "Filter by exact due date (YYYY-MM-DD)",
449
+ due_date_before: "Filter by due date before (YYYY-MM-DD)",
450
+ due_date_after: "Filter by due date after (YYYY-MM-DD)"
440
451
  },
441
452
  includes: [
442
453
  "project",
@@ -501,11 +512,18 @@ const RESOURCE_HELP = {
501
512
  update: "Update an existing time entry"
502
513
  },
503
514
  filters: {
504
- person_id: "Filter by person",
515
+ person_id: 'Filter by person (use "me" for current user)',
505
516
  service_id: "Filter by service",
506
517
  project_id: "Filter by project",
518
+ task_id: "Filter by task",
519
+ company_id: "Filter by company",
520
+ deal_id: "Filter by deal",
521
+ budget_id: "Filter by budget",
507
522
  after: "Filter entries after date (YYYY-MM-DD)",
508
- before: "Filter entries before date (YYYY-MM-DD)"
523
+ before: "Filter entries before date (YYYY-MM-DD)",
524
+ status: "Filter by approval status: 1=approved, 2=unapproved, 3=rejected",
525
+ billing_type_id: "Filter by billing type: 1=fixed, 2=actuals, 3=non_billable",
526
+ invoicing_status: "Filter by invoicing: 1=not_invoiced, 2=drafted, 3=finalized"
509
527
  },
510
528
  fields: {
511
529
  id: "Unique time entry identifier",
@@ -545,7 +563,12 @@ const RESOURCE_HELP = {
545
563
  },
546
564
  filters: {
547
565
  project_id: "Filter by project",
548
- deal_id: "Filter by deal"
566
+ deal_id: "Filter by deal",
567
+ task_id: "Filter by task",
568
+ person_id: "Filter by person (trackable by)",
569
+ budget_status: "Filter by budget status: 1=open, 2=delivered",
570
+ billing_type: "Filter by billing type: 1=fixed, 2=actuals, 3=none",
571
+ time_tracking_enabled: "Filter by time tracking: true/false"
549
572
  },
550
573
  fields: {
551
574
  id: "Unique service identifier",
@@ -569,7 +592,12 @@ const RESOURCE_HELP = {
569
592
  },
570
593
  filters: {
571
594
  query: "Text search on name or email",
572
- status: "Filter by status (active, inactive)"
595
+ status: "Filter by status: 1=active, 2=deactivated",
596
+ person_type: "Filter by type: 1=user, 2=contact, 3=placeholder",
597
+ company_id: "Filter by company",
598
+ project_id: "Filter by project",
599
+ role_id: "Filter by role",
600
+ team: "Filter by team name"
573
601
  },
574
602
  fields: {
575
603
  id: "Unique person identifier",
@@ -632,7 +660,10 @@ const RESOURCE_HELP = {
632
660
  },
633
661
  filters: {
634
662
  task_id: "Filter by task",
635
- deal_id: "Filter by deal"
663
+ deal_id: "Filter by deal",
664
+ project_id: "Filter by project",
665
+ page_id: "Filter by page",
666
+ discussion_id: "Filter by discussion"
636
667
  },
637
668
  includes: ["creator", "task", "deal"],
638
669
  fields: {
@@ -659,6 +690,10 @@ const RESOURCE_HELP = {
659
690
  start: "Start a new timer (requires service_id or time_entry_id)",
660
691
  stop: "Stop an active timer by ID"
661
692
  },
693
+ filters: {
694
+ person_id: "Filter by person",
695
+ time_entry_id: "Filter by time entry"
696
+ },
662
697
  fields: {
663
698
  id: "Unique timer identifier",
664
699
  started_at: "When the timer started (ISO 8601)",
@@ -684,7 +719,12 @@ const RESOURCE_HELP = {
684
719
  filters: {
685
720
  query: "Text search on deal name",
686
721
  company_id: "Filter by company",
687
- deal_status_id: "Filter by status"
722
+ project_id: "Filter by project",
723
+ responsible_id: "Filter by responsible person",
724
+ pipeline_id: "Filter by pipeline",
725
+ stage_status_id: "Filter by stage: 1=open, 2=won, 3=lost",
726
+ type: "Filter by type: 1=deal, 2=budget",
727
+ budget_status: "Filter by budget status: 1=open, 2=closed"
688
728
  },
689
729
  includes: ["company", "deal_status", "responsible", "project"],
690
730
  fields: {
@@ -716,8 +756,13 @@ const RESOURCE_HELP = {
716
756
  filters: {
717
757
  person_id: "Filter by person",
718
758
  service_id: "Filter by service",
759
+ project_id: "Filter by project",
760
+ company_id: "Filter by company",
761
+ event_id: "Filter by event",
719
762
  after: "Filter bookings after date (YYYY-MM-DD)",
720
- before: "Filter bookings before date (YYYY-MM-DD)"
763
+ before: "Filter bookings before date (YYYY-MM-DD)",
764
+ booking_type: "Filter by type: event (absence) or service (budget)",
765
+ draft: "Filter by tentative status: true/false"
721
766
  },
722
767
  includes: ["person", "service", "event"],
723
768
  fields: {
@@ -1174,4 +1219,4 @@ async function executeToolWithCredentials(name, args, credentials) {
1174
1219
  export {
1175
1220
  executeToolWithCredentials as e
1176
1221
  };
1177
- //# sourceMappingURL=index-D743zTS1.js.map
1222
+ //# sourceMappingURL=index-BDke-bMP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BDke-bMP.js","sources":["../src/errors.ts","../src/formatters.ts","../src/handlers/utils.ts","../src/handlers/bookings.ts","../src/handlers/comments.ts","../src/handlers/companies.ts","../src/handlers/deals.ts","../src/handlers/help.ts","../src/handlers/people.ts","../src/handlers/projects.ts","../src/handlers/reports.ts","../src/handlers/services.ts","../src/handlers/tasks.ts","../src/handlers/time.ts","../src/handlers/timers.ts","../src/handlers/index.ts"],"sourcesContent":["/**\n * Custom error classes for MCP server\n *\n * These provide structured error handling with LLM-friendly messages\n * that include guidance on how to resolve issues.\n */\n\n/**\n * Error thrown when user input validation fails.\n * These errors should be returned to the user directly.\n *\n * Includes optional hints for how to resolve the issue.\n */\nexport class UserInputError extends Error {\n public readonly hints?: string[];\n\n constructor(message: string, hints?: string[]) {\n super(message);\n this.name = 'UserInputError';\n this.hints = hints;\n }\n\n /**\n * Format error message with hints for LLM consumption\n */\n toFormattedMessage(): string {\n let msg = `**Input Error:** ${this.message}`;\n if (this.hints && this.hints.length > 0) {\n msg += '\\n\\n**Hints:**\\n' + this.hints.map((h) => `- ${h}`).join('\\n');\n }\n return msg;\n }\n}\n\n/**\n * Error messages with guidance for common validation failures\n */\nexport const ErrorMessages = {\n // Required field errors\n missingId: (action: string) =>\n new UserInputError(`id is required for ${action} action`, [\n `Use action=\"list\" first to find the resource ID`,\n `Then use action=\"${action}\" with the id parameter`,\n ]),\n\n missingRequiredFields: (resource: string, fields: string[]) =>\n new UserInputError(\n `${fields.join(', ')} ${fields.length === 1 ? 'is' : 'are'} required for creating ${resource}`,\n [\n `Provide all required fields: ${fields.join(', ')}`,\n `Use action=\"help\" for detailed documentation on ${resource}`,\n ],\n ),\n\n // Invalid action errors\n invalidAction: (action: string, resource: string, validActions: string[]) =>\n new UserInputError(`Invalid action \"${action}\" for ${resource}`, [\n `Valid actions are: ${validActions.join(', ')}`,\n `Use action=\"help\" with resource=\"${resource}\" for detailed documentation`,\n ]),\n\n // Unknown resource errors\n unknownResource: (resource: string, validResources: string[]) =>\n new UserInputError(`Unknown resource: ${resource}`, [\n `Valid resources are: ${validResources.join(', ')}`,\n `Use action=\"help\" without a resource for an overview of all resources`,\n ]),\n\n // Report-specific errors\n missingReportType: () =>\n new UserInputError('report_type is required for reports', [\n 'Specify report_type parameter (e.g., \"time_reports\", \"project_reports\")',\n 'Use action=\"help\" with resource=\"reports\" for available report types',\n ]),\n\n invalidReportType: (reportType: string, validTypes: string[]) =>\n new UserInputError(`Invalid report_type: ${reportType}`, [\n `Valid report types are: ${validTypes.join(', ')}`,\n 'Use action=\"help\" with resource=\"reports\" for detailed documentation',\n ]),\n\n // Timer-specific errors\n missingServiceForTimer: () =>\n new UserInputError('service_id is required to start a timer', [\n 'First find a service using resource=\"services\" action=\"list\"',\n 'Then start the timer with the service_id',\n ]),\n\n // People-specific errors\n noUserIdConfigured: () =>\n new UserInputError('User ID not configured', [\n 'The \"me\" action requires a user ID to be configured',\n 'Use action=\"list\" to find people, or configure the user ID',\n ]),\n\n // Comment-specific errors\n missingCommentTarget: () =>\n new UserInputError('A target is required for creating a comment', [\n 'Provide one of: task_id, deal_id, or company_id',\n 'Find targets using resource=\"tasks\", \"deals\", or \"companies\" with action=\"list\"',\n ]),\n\n // Booking-specific errors\n missingBookingTarget: () =>\n new UserInputError('A service or event is required for creating a booking', [\n 'Provide either: service_id or event_id',\n 'Find services using resource=\"services\" with action=\"list\"',\n ]),\n\n // API errors\n apiError: (statusCode: number, message: string) => {\n const hints: string[] = [];\n\n if (statusCode === 401) {\n hints.push('Check that your API token is valid and not expired');\n hints.push('Verify the organization ID is correct');\n } else if (statusCode === 403) {\n hints.push('You may not have permission to access this resource');\n hints.push('Check your API token permissions');\n } else if (statusCode === 404) {\n hints.push('The resource may not exist or you may not have access');\n hints.push('Verify the resource ID is correct');\n hints.push('Use action=\"list\" to find valid resource IDs');\n } else if (statusCode === 422) {\n hints.push('The request data may be invalid');\n hints.push('Check the field values and types');\n hints.push('Use action=\"help\" for field documentation');\n } else if (statusCode >= 500) {\n hints.push('This is a server error - try again later');\n }\n\n return new UserInputError(`API error (${statusCode}): ${message}`, hints);\n },\n} as const;\n\n/**\n * Check if an error is a UserInputError\n */\nexport function isUserInputError(error: unknown): error is UserInputError {\n return error instanceof UserInputError;\n}\n","/**\n * Response formatters for agent-friendly output\n *\n * This module re-exports formatters from @studiometa/productive-cli\n * with MCP-specific defaults (no relationship IDs, no timestamps).\n *\n * Supports compact mode to reduce token usage by omitting verbose fields\n * like descriptions and notes from list responses.\n */\n\nimport {\n formatTimeEntry as cliFormatTimeEntry,\n formatProject as cliFormatProject,\n formatTask as cliFormatTask,\n formatPerson as cliFormatPerson,\n formatService as cliFormatService,\n formatCompany as cliFormatCompany,\n formatComment as cliFormatComment,\n formatTimer as cliFormatTimer,\n formatDeal as cliFormatDeal,\n formatBooking as cliFormatBooking,\n formatListResponse as cliFormatListResponse,\n type JsonApiResource,\n type JsonApiMeta,\n type FormatOptions,\n type FormattedPagination,\n} from '@studiometa/productive-cli';\n\n// Re-export types\nexport type { JsonApiResource, JsonApiMeta, FormatOptions, FormattedPagination };\n\n/**\n * MCP-specific format options\n * - No relationship IDs (cleaner output for agents)\n * - No timestamps (reduce noise)\n * - HTML stripping enabled\n */\nconst MCP_FORMAT_OPTIONS: FormatOptions = {\n includeRelationshipIds: false,\n includeTimestamps: false,\n stripHtml: true,\n};\n\n/**\n * Extended format options for MCP with compact mode\n */\nexport interface McpFormatOptions {\n compact?: boolean;\n included?: JsonApiResource[];\n}\n\n/**\n * Remove verbose fields from an object for compact output\n */\nfunction compactify<T extends Record<string, unknown>>(obj: T, fieldsToRemove: string[]): T {\n const result = { ...obj };\n for (const field of fieldsToRemove) {\n delete result[field];\n }\n return result;\n}\n\n/**\n * Format time entry for agent consumption\n */\nexport function formatTimeEntry(\n entry: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatTimeEntry(entry, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['note', 'billable_time', 'approved']);\n }\n return result;\n}\n\n/**\n * Format project for agent consumption\n */\nexport function formatProject(\n project: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatProject(project, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['budget']);\n }\n return result;\n}\n\n/**\n * Format task for agent consumption\n * Tasks use included resources to resolve project/company names\n */\nexport function formatTask(\n task: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatTask(task, { ...MCP_FORMAT_OPTIONS, included: options?.included });\n if (options?.compact) {\n return compactify(result, [\n 'description',\n 'initial_estimate',\n 'worked_time',\n 'remaining_time',\n 'project', // Keep project_name but remove nested object\n 'company', // Keep company name inline if needed\n ]);\n }\n return result;\n}\n\n/**\n * Format person for agent consumption\n */\nexport function formatPerson(\n person: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatPerson(person, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['title', 'first_name', 'last_name']); // Keep 'name' which combines them\n }\n return result;\n}\n\n/**\n * Format service for agent consumption\n */\nexport function formatService(\n service: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatService(service, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['budgeted_time', 'worked_time']);\n }\n return result;\n}\n\n/**\n * Format company for agent consumption\n */\nexport function formatCompany(\n company: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatCompany(company, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['billing_name', 'domain', 'due_days']);\n }\n return result;\n}\n\n/**\n * Format comment for agent consumption\n */\nexport function formatComment(\n comment: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatComment(comment, { ...MCP_FORMAT_OPTIONS, included: options?.included });\n return result;\n}\n\n/**\n * Format timer for agent consumption\n */\nexport function formatTimer(\n timer: JsonApiResource,\n _options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatTimer(timer, MCP_FORMAT_OPTIONS);\n return result;\n}\n\n/**\n * Format deal for agent consumption\n */\nexport function formatDeal(\n deal: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatDeal(deal, { ...MCP_FORMAT_OPTIONS, included: options?.included });\n if (options?.compact) {\n return compactify(result, ['won_at', 'lost_at']);\n }\n return result;\n}\n\n/**\n * Format booking for agent consumption\n */\nexport function formatBooking(\n booking: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatBooking(booking, { ...MCP_FORMAT_OPTIONS, included: options?.included });\n if (options?.compact) {\n return compactify(result, ['approved_at', 'rejected_at', 'rejected_reason']);\n }\n return result;\n}\n\n/**\n * Format list response with pagination\n *\n * @param data - Array of JSON:API resources\n * @param formatter - Formatter function (item, options?) => T\n * @param meta - Pagination metadata\n * @param options - MCP format options (compact, included)\n */\nexport function formatListResponse<T>(\n data: JsonApiResource[],\n formatter: (item: JsonApiResource, options?: McpFormatOptions) => T,\n meta?: JsonApiMeta,\n options?: McpFormatOptions,\n): { data: T[]; meta?: FormattedPagination } {\n // Create a wrapper that passes MCP options to the formatter\n const wrappedFormatter = (item: JsonApiResource, _cliOptions?: FormatOptions) => {\n return formatter(item, options);\n };\n\n const result = cliFormatListResponse(data, wrappedFormatter, meta, {\n ...MCP_FORMAT_OPTIONS,\n included: options?.included,\n });\n\n return result as { data: T[]; meta?: FormattedPagination };\n}\n","/**\n * Utility functions for resource handlers\n */\n\nimport type { ToolResult } from './types.js';\n\nimport { UserInputError, isUserInputError } from '../errors.js';\n\n/**\n * Helper to create a successful JSON response\n */\nexport function jsonResult(data: unknown): ToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],\n };\n}\n\n/**\n * Helper to create an error response from a string message\n */\nexport function errorResult(message: string): ToolResult {\n return {\n content: [{ type: 'text', text: `**Error:** ${message}` }],\n isError: true,\n };\n}\n\n/**\n * Helper to create an error response from a UserInputError\n * Includes formatted hints for LLM consumption\n */\nexport function inputErrorResult(error: UserInputError): ToolResult {\n return {\n content: [{ type: 'text', text: error.toFormattedMessage() }],\n isError: true,\n };\n}\n\n/**\n * Helper to create an error response from any error type\n * Automatically formats UserInputError with hints\n */\nexport function formatError(error: unknown): ToolResult {\n if (isUserInputError(error)) {\n return inputErrorResult(error);\n }\n\n const message = error instanceof Error ? error.message : String(error);\n return errorResult(message);\n}\n\n/**\n * Convert unknown filter to string filter for API\n */\nexport function toStringFilter(\n filter?: Record<string, unknown>,\n): Record<string, string> | undefined {\n if (!filter) return undefined;\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(filter)) {\n if (value !== undefined && value !== null) {\n result[key] = String(value);\n }\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","/**\n * Bookings resource handler\n */\n\nimport type { BookingArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatBooking, formatListResponse } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/** Default includes for bookings */\nconst DEFAULT_BOOKING_INCLUDE = ['person', 'service'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleBookings(\n action: string,\n args: BookingArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, person_id, service_id, event_id, started_on, ended_on, time, note } = args;\n // Merge default includes with user-provided includes\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_BOOKING_INCLUDE, ...userInclude])]\n : DEFAULT_BOOKING_INCLUDE;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getBooking(id, { include });\n return jsonResult(formatBooking(result.data, { ...formatOptions, included: result.included }));\n }\n\n if (action === 'create') {\n if (!person_id || !started_on || !ended_on) {\n return inputErrorResult(\n ErrorMessages.missingRequiredFields('booking', ['person_id', 'started_on', 'ended_on']),\n );\n }\n if (!service_id && !event_id) {\n return inputErrorResult(ErrorMessages.missingBookingTarget());\n }\n const result = await api.createBooking({\n person_id,\n service_id,\n event_id,\n started_on,\n ended_on,\n time,\n note,\n });\n return jsonResult({ success: true, ...formatBooking(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateBooking>[1] = {};\n if (started_on !== undefined) updateData.started_on = started_on;\n if (ended_on !== undefined) updateData.ended_on = ended_on;\n if (time !== undefined) updateData.time = time;\n if (note !== undefined) updateData.note = note;\n const result = await api.updateBooking(id, updateData);\n return jsonResult({ success: true, ...formatBooking(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getBookings({ filter, page, perPage, include });\n return jsonResult(\n formatListResponse(result.data, formatBooking, result.meta, {\n ...formatOptions,\n included: result.included,\n }),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'bookings', VALID_ACTIONS));\n}\n","/**\n * Comments resource handler\n */\n\nimport type { CommentArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatComment, formatListResponse } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/** Default includes for comments */\nconst DEFAULT_COMMENT_INCLUDE = ['creator'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleComments(\n action: string,\n args: CommentArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, body, task_id, deal_id, company_id } = args;\n // Merge default includes with user-provided includes\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_COMMENT_INCLUDE, ...userInclude])]\n : DEFAULT_COMMENT_INCLUDE;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getComment(id, { include });\n return jsonResult(formatComment(result.data, { ...formatOptions, included: result.included }));\n }\n\n if (action === 'create') {\n if (!body) return inputErrorResult(ErrorMessages.missingRequiredFields('comment', ['body']));\n if (!task_id && !deal_id && !company_id) {\n return inputErrorResult(ErrorMessages.missingCommentTarget());\n }\n const result = await api.createComment({\n body,\n task_id,\n deal_id,\n company_id,\n });\n return jsonResult({ success: true, ...formatComment(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n if (!body)\n return inputErrorResult(ErrorMessages.missingRequiredFields('comment update', ['body']));\n const result = await api.updateComment(id, { body });\n return jsonResult({ success: true, ...formatComment(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getComments({ filter, page, perPage, include });\n return jsonResult(\n formatListResponse(result.data, formatComment, result.meta, {\n ...formatOptions,\n included: result.included,\n }),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'comments', VALID_ACTIONS));\n}\n","/**\n * Companies resource handler\n */\n\nimport type { CompanyArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatCompany, formatListResponse } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleCompanies(\n action: string,\n args: CompanyArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n const { id, name } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getCompany(id);\n return jsonResult(formatCompany(result.data, formatOptions));\n }\n\n if (action === 'create') {\n if (!name) return inputErrorResult(ErrorMessages.missingRequiredFields('company', ['name']));\n const result = await api.createCompany({ name });\n return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateCompany>[1] = {};\n if (name !== undefined) updateData.name = name;\n const result = await api.updateCompany(id, updateData);\n return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getCompanies({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatCompany, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'companies', VALID_ACTIONS));\n}\n","/**\n * Deals resource handler\n */\n\nimport type { DealArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatDeal, formatListResponse } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/** Default includes for deals */\nconst DEFAULT_DEAL_INCLUDE_GET = ['company', 'deal_status', 'responsible'];\nconst DEFAULT_DEAL_INCLUDE_LIST = ['company', 'deal_status'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleDeals(\n action: string,\n args: DealArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, name, company_id } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_DEAL_INCLUDE_GET, ...userInclude])]\n : DEFAULT_DEAL_INCLUDE_GET;\n const result = await api.getDeal(id, { include });\n return jsonResult(formatDeal(result.data, { ...formatOptions, included: result.included }));\n }\n\n if (action === 'create') {\n if (!name || !company_id) {\n return inputErrorResult(ErrorMessages.missingRequiredFields('deal', ['name', 'company_id']));\n }\n const result = await api.createDeal({ name, company_id });\n return jsonResult({ success: true, ...formatDeal(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateDeal>[1] = {};\n if (name !== undefined) updateData.name = name;\n const result = await api.updateDeal(id, updateData);\n return jsonResult({ success: true, ...formatDeal(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_DEAL_INCLUDE_LIST, ...userInclude])]\n : DEFAULT_DEAL_INCLUDE_LIST;\n const result = await api.getDeals({\n filter,\n page,\n perPage,\n include,\n });\n return jsonResult(\n formatListResponse(result.data, formatDeal, result.meta, {\n ...formatOptions,\n included: result.included,\n }),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'deals', VALID_ACTIONS));\n}\n","/**\n * Help handler - provides detailed documentation for each resource\n */\n\nimport type { ToolResult } from './types.js';\n\nimport { jsonResult } from './utils.js';\n\ninterface ResourceHelp {\n description: string;\n actions: Record<string, string>;\n filters?: Record<string, string>;\n includes?: string[];\n fields?: Record<string, string>;\n examples?: Array<{ description: string; params: Record<string, unknown> }>;\n}\n\nconst RESOURCE_HELP: Record<string, ResourceHelp> = {\n projects: {\n description: 'Manage projects in Productive.io',\n actions: {\n list: 'List all projects with optional filters',\n get: 'Get a single project by ID with full details',\n },\n filters: {\n query: 'Text search on project name',\n project_type: 'Filter by project type: 1=internal, 2=client',\n company_id: 'Filter by company',\n responsible_id: 'Filter by project manager',\n person_id: 'Filter by team member',\n status: 'Filter by status: 1=active, 2=archived',\n },\n fields: {\n id: 'Unique project identifier',\n name: 'Project name',\n project_number: 'Project reference number',\n archived: 'Whether the project is archived',\n budget: 'Project budget amount',\n },\n examples: [\n {\n description: 'Search projects by name',\n params: { resource: 'projects', action: 'list', query: 'website' },\n },\n {\n description: 'List active projects',\n params: { resource: 'projects', action: 'list', filter: { archived: 'false' } },\n },\n {\n description: 'Get project details',\n params: { resource: 'projects', action: 'get', id: '12345' },\n },\n ],\n },\n\n tasks: {\n description: 'Manage tasks within projects',\n actions: {\n list: 'List tasks with optional filters',\n get: 'Get a single task by ID with full details (description, comments, etc.)',\n create: 'Create a new task (requires title, project_id, task_list_id)',\n update: 'Update an existing task',\n },\n filters: {\n query: 'Text search on task title',\n project_id: 'Filter by project',\n company_id: 'Filter by company',\n assignee_id: 'Filter by assigned person',\n creator_id: 'Filter by task creator',\n status: 'Filter by status: 1=open, 2=closed (or \"open\", \"closed\", \"all\")',\n task_list_id: 'Filter by task list',\n board_id: 'Filter by board',\n workflow_status_id: 'Filter by workflow status (kanban column)',\n parent_task_id: 'Filter by parent task (for subtasks)',\n overdue_status: 'Filter by overdue: 1=not overdue, 2=overdue',\n due_date_on: 'Filter by exact due date (YYYY-MM-DD)',\n due_date_before: 'Filter by due date before (YYYY-MM-DD)',\n due_date_after: 'Filter by due date after (YYYY-MM-DD)',\n },\n includes: [\n 'project',\n 'project.company',\n 'assignee',\n 'workflow_status',\n 'comments',\n 'attachments',\n 'subtasks',\n ],\n fields: {\n id: 'Unique task identifier',\n title: 'Task title',\n description: 'Full task description (HTML)',\n number: 'Task number within project',\n due_date: 'Due date (YYYY-MM-DD)',\n initial_estimate: 'Estimated time in minutes',\n worked_time: 'Logged time in minutes',\n remaining_time: 'Remaining time in minutes',\n closed: 'Whether the task is closed',\n },\n examples: [\n {\n description: 'Search tasks by title',\n params: { resource: 'tasks', action: 'list', query: 'bug fix' },\n },\n {\n description: 'List open tasks for a project',\n params: {\n resource: 'tasks',\n action: 'list',\n filter: { project_id: '12345', status: 'open' },\n },\n },\n {\n description: 'Get task with comments',\n params: {\n resource: 'tasks',\n action: 'get',\n id: '67890',\n include: ['comments', 'assignee'],\n },\n },\n {\n description: 'Create a task',\n params: {\n resource: 'tasks',\n action: 'create',\n title: 'New task',\n project_id: '12345',\n task_list_id: '111',\n },\n },\n ],\n },\n\n time: {\n description: 'Track time entries against services/tasks',\n actions: {\n list: 'List time entries with optional filters',\n get: 'Get a single time entry by ID',\n create: 'Create a new time entry (requires person_id, service_id, date, time)',\n update: 'Update an existing time entry',\n },\n filters: {\n person_id: 'Filter by person (use \"me\" for current user)',\n service_id: 'Filter by service',\n project_id: 'Filter by project',\n task_id: 'Filter by task',\n company_id: 'Filter by company',\n deal_id: 'Filter by deal',\n budget_id: 'Filter by budget',\n after: 'Filter entries after date (YYYY-MM-DD)',\n before: 'Filter entries before date (YYYY-MM-DD)',\n status: 'Filter by approval status: 1=approved, 2=unapproved, 3=rejected',\n billing_type_id: 'Filter by billing type: 1=fixed, 2=actuals, 3=non_billable',\n invoicing_status: 'Filter by invoicing: 1=not_invoiced, 2=drafted, 3=finalized',\n },\n fields: {\n id: 'Unique time entry identifier',\n date: 'Date of the entry (YYYY-MM-DD)',\n time: 'Time in minutes',\n note: 'Description of work done',\n billable_time: 'Billable time in minutes',\n approved: 'Whether the entry is approved',\n },\n examples: [\n {\n description: 'List my time entries this week',\n params: {\n resource: 'time',\n action: 'list',\n filter: { person_id: 'me', after: '2024-01-15', before: '2024-01-21' },\n },\n },\n {\n description: 'Log 2 hours',\n params: {\n resource: 'time',\n action: 'create',\n service_id: '12345',\n date: '2024-01-16',\n time: 120,\n note: 'Development work',\n },\n },\n ],\n },\n\n services: {\n description: 'Budget line items within projects',\n actions: {\n list: 'List services with optional filters',\n get: 'Get a single service by ID',\n },\n filters: {\n project_id: 'Filter by project',\n deal_id: 'Filter by deal',\n task_id: 'Filter by task',\n person_id: 'Filter by person (trackable by)',\n budget_status: 'Filter by budget status: 1=open, 2=delivered',\n billing_type: 'Filter by billing type: 1=fixed, 2=actuals, 3=none',\n time_tracking_enabled: 'Filter by time tracking: true/false',\n },\n fields: {\n id: 'Unique service identifier',\n name: 'Service name',\n budgeted_time: 'Budgeted time in minutes',\n worked_time: 'Logged time in minutes',\n },\n examples: [\n {\n description: 'List services for a project',\n params: { resource: 'services', action: 'list', filter: { project_id: '12345' } },\n },\n ],\n },\n\n people: {\n description: 'Team members and contacts',\n actions: {\n list: 'List people with optional filters',\n get: 'Get a single person by ID',\n me: 'Get the currently authenticated user',\n },\n filters: {\n query: 'Text search on name or email',\n status: 'Filter by status: 1=active, 2=deactivated',\n person_type: 'Filter by type: 1=user, 2=contact, 3=placeholder',\n company_id: 'Filter by company',\n project_id: 'Filter by project',\n role_id: 'Filter by role',\n team: 'Filter by team name',\n },\n fields: {\n id: 'Unique person identifier',\n name: 'Full name',\n first_name: 'First name',\n last_name: 'Last name',\n email: 'Email address',\n title: 'Job title',\n active: 'Whether the person is active',\n },\n examples: [\n { description: 'Get current user', params: { resource: 'people', action: 'me' } },\n {\n description: 'Search people by name',\n params: { resource: 'people', action: 'list', query: 'john' },\n },\n {\n description: 'List active team members',\n params: { resource: 'people', action: 'list', filter: { status: 'active' } },\n },\n ],\n },\n\n companies: {\n description: 'Client companies and organizations',\n actions: {\n list: 'List companies with optional filters',\n get: 'Get a single company by ID',\n create: 'Create a new company (requires name)',\n update: 'Update an existing company',\n },\n filters: {\n query: 'Text search on company name',\n archived: 'Filter by archived status (true/false)',\n },\n fields: {\n id: 'Unique company identifier',\n name: 'Company name',\n billing_name: 'Legal/billing name',\n domain: 'Website domain',\n vat: 'VAT number',\n },\n examples: [\n {\n description: 'Search companies',\n params: { resource: 'companies', action: 'list', query: 'acme' },\n },\n {\n description: 'List active companies',\n params: { resource: 'companies', action: 'list', filter: { archived: 'false' } },\n },\n ],\n },\n\n comments: {\n description: 'Comments on tasks, deals, and other resources',\n actions: {\n list: 'List comments with optional filters',\n get: 'Get a single comment by ID',\n create: 'Create a new comment (requires body and one of: task_id, deal_id, company_id)',\n update: 'Update an existing comment',\n },\n filters: {\n task_id: 'Filter by task',\n deal_id: 'Filter by deal',\n project_id: 'Filter by project',\n page_id: 'Filter by page',\n discussion_id: 'Filter by discussion',\n },\n includes: ['creator', 'task', 'deal'],\n fields: {\n id: 'Unique comment identifier',\n body: 'Comment text (may contain HTML)',\n creator: 'Person who created the comment',\n },\n examples: [\n {\n description: 'List comments on a task',\n params: { resource: 'comments', action: 'list', filter: { task_id: '12345' } },\n },\n {\n description: 'Add a comment',\n params: { resource: 'comments', action: 'create', task_id: '12345', body: 'Looking good!' },\n },\n ],\n },\n\n timers: {\n description: 'Active time tracking timers',\n actions: {\n list: 'List active timers',\n get: 'Get a single timer by ID',\n start: 'Start a new timer (requires service_id or time_entry_id)',\n stop: 'Stop an active timer by ID',\n },\n filters: {\n person_id: 'Filter by person',\n time_entry_id: 'Filter by time entry',\n },\n fields: {\n id: 'Unique timer identifier',\n started_at: 'When the timer started (ISO 8601)',\n total_time: 'Elapsed time in seconds',\n },\n examples: [\n { description: 'List active timers', params: { resource: 'timers', action: 'list' } },\n {\n description: 'Start timer on service',\n params: { resource: 'timers', action: 'start', service_id: '12345' },\n },\n { description: 'Stop timer', params: { resource: 'timers', action: 'stop', id: '67890' } },\n ],\n },\n\n deals: {\n description: 'Sales deals and opportunities',\n actions: {\n list: 'List deals with optional filters',\n get: 'Get a single deal by ID',\n create: 'Create a new deal (requires name, company_id)',\n update: 'Update an existing deal',\n },\n filters: {\n query: 'Text search on deal name',\n company_id: 'Filter by company',\n project_id: 'Filter by project',\n responsible_id: 'Filter by responsible person',\n pipeline_id: 'Filter by pipeline',\n stage_status_id: 'Filter by stage: 1=open, 2=won, 3=lost',\n type: 'Filter by type: 1=deal, 2=budget',\n budget_status: 'Filter by budget status: 1=open, 2=closed',\n },\n includes: ['company', 'deal_status', 'responsible', 'project'],\n fields: {\n id: 'Unique deal identifier',\n name: 'Deal name',\n number: 'Deal number',\n date: 'Deal date',\n status: 'Current status (from deal_status)',\n },\n examples: [\n {\n description: 'Search deals',\n params: { resource: 'deals', action: 'list', query: 'website redesign' },\n },\n {\n description: 'List deals for a company',\n params: { resource: 'deals', action: 'list', filter: { company_id: '12345' } },\n },\n ],\n },\n\n bookings: {\n description: 'Resource scheduling and capacity planning',\n actions: {\n list: 'List bookings with optional filters',\n get: 'Get a single booking by ID',\n create:\n 'Create a new booking (requires person_id, started_on, ended_on, and service_id or event_id)',\n update: 'Update an existing booking',\n },\n filters: {\n person_id: 'Filter by person',\n service_id: 'Filter by service',\n project_id: 'Filter by project',\n company_id: 'Filter by company',\n event_id: 'Filter by event',\n after: 'Filter bookings after date (YYYY-MM-DD)',\n before: 'Filter bookings before date (YYYY-MM-DD)',\n booking_type: 'Filter by type: event (absence) or service (budget)',\n draft: 'Filter by tentative status: true/false',\n },\n includes: ['person', 'service', 'event'],\n fields: {\n id: 'Unique booking identifier',\n started_on: 'Start date (YYYY-MM-DD)',\n ended_on: 'End date (YYYY-MM-DD)',\n time: 'Time per day in minutes',\n total_time: 'Total booked time in minutes',\n note: 'Booking note',\n },\n examples: [\n {\n description: 'List my bookings',\n params: { resource: 'bookings', action: 'list', filter: { person_id: 'me' } },\n },\n ],\n },\n\n reports: {\n description: 'Generate various reports (time, budget, project, etc.)',\n actions: {\n get: 'Generate a report (requires report_type)',\n },\n filters: {\n person_id: 'Filter by person',\n project_id: 'Filter by project',\n company_id: 'Filter by company',\n after: 'Filter from date (YYYY-MM-DD)',\n before: 'Filter to date (YYYY-MM-DD)',\n },\n fields: {\n report_type:\n 'Type of report: time_reports, project_reports, budget_reports, person_reports, invoice_reports, payment_reports, service_reports, task_reports, company_reports, deal_reports, timesheet_reports',\n group: 'Grouping dimension (varies by report type)',\n from: 'Start date for date range',\n to: 'End date for date range',\n },\n examples: [\n {\n description: 'Time report by person',\n params: {\n resource: 'reports',\n action: 'get',\n report_type: 'time_reports',\n group: 'person',\n from: '2024-01-01',\n to: '2024-01-31',\n },\n },\n {\n description: 'Project budget report',\n params: {\n resource: 'reports',\n action: 'get',\n report_type: 'budget_reports',\n filter: { project_id: '12345' },\n },\n },\n ],\n },\n};\n\n/**\n * Handle help action - returns documentation for a specific resource\n */\nexport function handleHelp(resource: string): ToolResult {\n const help = RESOURCE_HELP[resource];\n\n if (!help) {\n return jsonResult({\n error: `Unknown resource: ${resource}`,\n available_resources: Object.keys(RESOURCE_HELP),\n });\n }\n\n return jsonResult({\n resource,\n ...help,\n });\n}\n\n/**\n * Get help for all resources (overview)\n */\nexport function handleHelpOverview(): ToolResult {\n const overview = Object.entries(RESOURCE_HELP).map(([resource, help]) => ({\n resource,\n description: help.description,\n actions: Object.keys(help.actions),\n }));\n\n return jsonResult({\n message: 'Use action=\"help\" with a specific resource for detailed documentation',\n resources: overview,\n });\n}\n","/**\n * People resource handler\n */\n\nimport type { ProductiveCredentials } from '../auth.js';\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatPerson } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'me'];\n\nexport async function handlePeople(\n action: string,\n args: CommonArgs,\n ctx: HandlerContext,\n credentials: ProductiveCredentials,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n const { id } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getPerson(id);\n return jsonResult(formatPerson(result.data, formatOptions));\n }\n\n if (action === 'me') {\n if (credentials.userId) {\n const result = await api.getPerson(credentials.userId);\n return jsonResult(formatPerson(result.data, formatOptions));\n }\n return jsonResult({\n message: 'User ID not configured. Set userId in credentials to use this action.',\n hint: 'Use action=\"list\" to find people, or configure the user ID in your credentials.',\n organizationId: credentials.organizationId,\n });\n }\n\n if (action === 'list') {\n const result = await api.getPeople({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatPerson, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'people', VALID_ACTIONS));\n}\n","/**\n * Projects resource handler\n */\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatProject } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get'];\n\nexport async function handleProjects(\n action: string,\n args: CommonArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n const { id } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getProject(id);\n return jsonResult(formatProject(result.data, formatOptions));\n }\n\n if (action === 'list') {\n const result = await api.getProjects({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatProject, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'projects', VALID_ACTIONS));\n}\n","/**\n * Reports resource handler\n */\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/**\n * Report-specific args\n */\ninterface ReportArgs extends CommonArgs {\n report_type?: string;\n group?: string;\n from?: string;\n to?: string;\n person_id?: string;\n project_id?: string;\n company_id?: string;\n deal_id?: string;\n status?: string;\n}\n\n/**\n * Format report data for agent consumption\n * Flattens attributes for easier reading\n */\nfunction formatReportData(data: unknown[]): unknown[] {\n return data.map((item: unknown) => {\n const record = item as { id: string; type: string; attributes: Record<string, unknown> };\n return {\n id: record.id,\n type: record.type,\n ...record.attributes,\n };\n });\n}\n\n/**\n * Valid report types\n */\nconst VALID_REPORT_TYPES = [\n 'time_reports',\n 'project_reports',\n 'budget_reports',\n 'person_reports',\n 'invoice_reports',\n 'payment_reports',\n 'service_reports',\n 'task_reports',\n 'company_reports',\n 'deal_reports',\n 'timesheet_reports',\n];\n\nconst VALID_ACTIONS = ['get'];\n\nexport async function handleReports(\n action: string,\n args: ReportArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, filter, page, perPage } = ctx;\n const { report_type, group, from, to, person_id, project_id, company_id, deal_id, status } = args;\n\n if (action !== 'get') {\n return inputErrorResult(ErrorMessages.invalidAction(action, 'reports', VALID_ACTIONS));\n }\n\n if (!report_type) {\n return inputErrorResult(ErrorMessages.missingReportType());\n }\n\n if (!VALID_REPORT_TYPES.includes(report_type)) {\n return inputErrorResult(ErrorMessages.invalidReportType(report_type, VALID_REPORT_TYPES));\n }\n\n // Build filters based on report type\n const reportFilter: Record<string, string> = { ...filter };\n\n // Date filters (different APIs use different param names)\n if (from) {\n if (report_type === 'invoice_reports') {\n reportFilter.invoice_date_after = from;\n } else if (report_type === 'payment_reports' || report_type === 'deal_reports') {\n reportFilter.date_after = from;\n } else {\n reportFilter.after = from;\n }\n }\n\n if (to) {\n if (report_type === 'invoice_reports') {\n reportFilter.invoice_date_before = to;\n } else if (report_type === 'payment_reports' || report_type === 'deal_reports') {\n reportFilter.date_before = to;\n } else {\n reportFilter.before = to;\n }\n }\n\n // Entity filters\n if (person_id) {\n if (report_type === 'task_reports') {\n reportFilter.assignee_id = person_id;\n } else {\n reportFilter.person_id = person_id;\n }\n }\n\n if (project_id) reportFilter.project_id = project_id;\n if (company_id) reportFilter.company_id = company_id;\n if (deal_id) {\n if (report_type === 'deal_reports') {\n reportFilter.deal_status_id = deal_id;\n } else {\n reportFilter.deal_id = deal_id;\n }\n }\n if (status) {\n if (report_type === 'deal_reports') {\n reportFilter.deal_status_id = status;\n } else {\n reportFilter.status = status;\n }\n }\n\n // Determine default grouping based on report type\n let effectiveGroup = group;\n if (!effectiveGroup) {\n const defaultGroups: Record<string, string> = {\n time_reports: 'person',\n project_reports: 'project',\n budget_reports: 'deal',\n person_reports: 'person',\n invoice_reports: 'invoice',\n payment_reports: 'payment',\n service_reports: 'service',\n task_reports: 'task',\n company_reports: 'company',\n deal_reports: 'deal',\n };\n effectiveGroup = defaultGroups[report_type];\n }\n\n // Determine include based on report type\n const includeMap: Record<string, string[]> = {\n project_reports: ['project'],\n budget_reports: ['deal'],\n person_reports: ['person'],\n invoice_reports: ['invoice'],\n payment_reports: ['payment'],\n service_reports: ['service'],\n task_reports: ['task'],\n company_reports: ['company'],\n deal_reports: ['deal'],\n timesheet_reports: ['person'],\n };\n const include = includeMap[report_type];\n\n const result = await api.getReports(report_type, {\n page,\n perPage,\n filter: reportFilter,\n group: effectiveGroup,\n include,\n });\n\n const formattedData = formatReportData(result.data);\n\n return jsonResult({\n data: formattedData,\n meta: result.meta,\n });\n}\n","/**\n * Services resource handler\n */\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatService } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list'];\n\nexport async function handleServices(\n action: string,\n _args: CommonArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n\n if (action === 'list') {\n const result = await api.getServices({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatService, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'services', VALID_ACTIONS));\n}\n","/**\n * Tasks resource handler\n */\n\nimport type { HandlerContext, TaskArgs, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTask } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/** Default includes for tasks */\nconst DEFAULT_TASK_INCLUDE = ['project', 'project.company'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleTasks(\n action: string,\n args: TaskArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, title, project_id, task_list_id, description, assignee_id } = args;\n // Merge default includes with user-provided includes\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_TASK_INCLUDE, ...userInclude])]\n : DEFAULT_TASK_INCLUDE;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getTask(id, { include });\n return jsonResult(formatTask(result.data, { ...formatOptions, included: result.included }));\n }\n\n if (action === 'create') {\n if (!title || !project_id || !task_list_id) {\n return inputErrorResult(\n ErrorMessages.missingRequiredFields('task', ['title', 'project_id', 'task_list_id']),\n );\n }\n const result = await api.createTask({\n title,\n project_id,\n task_list_id,\n assignee_id,\n description,\n });\n return jsonResult({ success: true, ...formatTask(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateTask>[1] = {};\n if (title !== undefined) updateData.title = title;\n if (description !== undefined) updateData.description = description;\n if (assignee_id !== undefined) updateData.assignee_id = assignee_id;\n const result = await api.updateTask(id, updateData);\n return jsonResult({ success: true, ...formatTask(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getTasks({ filter, page, perPage, include });\n return jsonResult(\n formatListResponse(result.data, formatTask, result.meta, {\n ...formatOptions,\n included: result.included,\n }),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'tasks', VALID_ACTIONS));\n}\n","/**\n * Time entries resource handler\n */\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTimeEntry } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleTime(\n action: string,\n args: CommonArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n const { id, person_id, service_id, task_id, time, date, note } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getTimeEntry(id);\n return jsonResult(formatTimeEntry(result.data, formatOptions));\n }\n\n if (action === 'create') {\n if (!person_id || !service_id || !time || !date) {\n return inputErrorResult(\n ErrorMessages.missingRequiredFields('time entry', [\n 'person_id',\n 'service_id',\n 'time',\n 'date',\n ]),\n );\n }\n const result = await api.createTimeEntry({\n person_id,\n service_id,\n time,\n date,\n note,\n task_id,\n });\n return jsonResult({ success: true, ...formatTimeEntry(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateTimeEntry>[1] = {};\n if (time !== undefined) updateData.time = time;\n if (date !== undefined) updateData.date = date;\n if (note !== undefined) updateData.note = note;\n const result = await api.updateTimeEntry(id, updateData);\n return jsonResult({ success: true, ...formatTimeEntry(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getTimeEntries({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatTimeEntry, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'time', VALID_ACTIONS));\n}\n","/**\n * Timers resource handler\n */\n\nimport type { HandlerContext, TimerArgs, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTimer } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'start', 'stop'];\n\nexport async function handleTimers(\n action: string,\n args: TimerArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include } = ctx;\n const { id, service_id, time_entry_id } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getTimer(id, { include });\n return jsonResult(formatTimer(result.data, formatOptions));\n }\n\n if (action === 'start' || action === 'create') {\n if (!service_id && !time_entry_id) {\n return inputErrorResult(ErrorMessages.missingServiceForTimer());\n }\n const result = await api.startTimer({ service_id, time_entry_id });\n return jsonResult({ success: true, ...formatTimer(result.data, formatOptions) });\n }\n\n if (action === 'stop') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('stop'));\n const result = await api.stopTimer(id);\n return jsonResult({ success: true, ...formatTimer(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getTimers({ filter, page, perPage, include });\n return jsonResult(formatListResponse(result.data, formatTimer, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'timers', VALID_ACTIONS));\n}\n","/**\n * Tool execution handlers for Productive MCP server\n * These are shared between stdio and HTTP transports\n *\n * Single consolidated tool for minimal token overhead:\n * - productive: resource + action based API\n */\n\nimport { ProductiveApi } from '@studiometa/productive-cli';\n\nimport type { ProductiveCredentials } from '../auth.js';\nimport type { McpFormatOptions } from '../formatters.js';\nimport type { HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages, isUserInputError } from '../errors.js';\nimport { handleBookings } from './bookings.js';\nimport { handleComments } from './comments.js';\nimport { handleCompanies } from './companies.js';\nimport { handleDeals } from './deals.js';\nimport { handleHelp, handleHelpOverview } from './help.js';\nimport { handlePeople } from './people.js';\n// Resource handlers\nimport { handleProjects } from './projects.js';\nimport { handleReports } from './reports.js';\nimport { handleServices } from './services.js';\nimport { handleTasks } from './tasks.js';\nimport { handleTime } from './time.js';\nimport { handleTimers } from './timers.js';\nimport { errorResult, formatError, inputErrorResult, toStringFilter } from './utils.js';\n\n// Re-export types\nexport type { ToolResult } from './types.js';\n\n/** Valid resources for the productive tool */\nconst VALID_RESOURCES = [\n 'projects',\n 'time',\n 'tasks',\n 'services',\n 'people',\n 'companies',\n 'comments',\n 'timers',\n 'deals',\n 'bookings',\n 'reports',\n];\n\n/** Default page size for MCP (smaller than CLI to reduce token usage) */\nconst DEFAULT_PER_PAGE = 20;\n\n/**\n * Args interface for the consolidated tool\n */\ninterface ProductiveArgs {\n resource: string;\n action: string;\n id?: string;\n filter?: Record<string, unknown>;\n page?: number;\n per_page?: number;\n compact?: boolean;\n include?: string[];\n query?: string;\n // Common fields\n person_id?: string;\n service_id?: string;\n task_id?: string;\n company_id?: string;\n time?: number;\n date?: string;\n note?: string;\n // Task fields\n title?: string;\n project_id?: string;\n task_list_id?: string;\n description?: string;\n assignee_id?: string;\n // Company fields\n name?: string;\n // Comment fields\n body?: string;\n deal_id?: string;\n // Timer fields\n time_entry_id?: string;\n // Booking fields\n started_on?: string;\n ended_on?: string;\n event_id?: string;\n // Report fields\n report_type?: string;\n group?: string;\n from?: string;\n to?: string;\n status?: string;\n}\n\n/**\n * Execute a tool with the given credentials and arguments\n */\nexport async function executeToolWithCredentials(\n name: string,\n args: Record<string, unknown>,\n credentials: ProductiveCredentials,\n): Promise<ToolResult> {\n // Initialize API client with provided credentials\n const api = new ProductiveApi({\n token: credentials.apiToken,\n 'org-id': credentials.organizationId,\n 'user-id': credentials.userId,\n } as Record<string, string>);\n\n // Handle the single consolidated tool\n if (name !== 'productive') {\n return errorResult(`Unknown tool: ${name}`);\n }\n\n const { resource, action, filter, page, per_page, compact, include, query, ...restArgs } =\n args as unknown as ProductiveArgs;\n\n // Default compact to false for 'get' action (single resource), true for 'list'\n const isCompact = compact ?? action !== 'get';\n const formatOptions: McpFormatOptions = { compact: isCompact };\n let stringFilter = toStringFilter(filter);\n const perPage = per_page ?? DEFAULT_PER_PAGE;\n\n // Add query to filter if provided (for text search)\n if (query) {\n stringFilter = { ...stringFilter, query };\n }\n\n // Build handler context\n const ctx: HandlerContext = {\n api,\n formatOptions,\n filter: stringFilter,\n page,\n perPage,\n include,\n };\n\n try {\n // Handle help action first (doesn't need API)\n if (action === 'help') {\n return resource ? handleHelp(resource) : handleHelpOverview();\n }\n\n // Route to appropriate resource handler\n switch (resource) {\n case 'projects':\n return await handleProjects(action, restArgs, ctx);\n\n case 'time':\n return await handleTime(action, restArgs, ctx);\n\n case 'tasks':\n return await handleTasks(action, restArgs, ctx);\n\n case 'services':\n return await handleServices(action, restArgs, ctx);\n\n case 'people':\n return await handlePeople(action, restArgs, ctx, credentials);\n\n case 'companies':\n return await handleCompanies(action, restArgs, ctx);\n\n case 'comments':\n return await handleComments(action, restArgs, ctx);\n\n case 'timers':\n return await handleTimers(action, restArgs, ctx);\n\n case 'deals':\n return await handleDeals(action, restArgs, ctx);\n\n case 'bookings':\n return await handleBookings(action, restArgs, ctx);\n\n case 'reports':\n return await handleReports(action, restArgs, ctx);\n\n default:\n return inputErrorResult(ErrorMessages.unknownResource(resource, VALID_RESOURCES));\n }\n } catch (error) {\n // Handle UserInputError with formatted hints\n if (isUserInputError(error)) {\n return formatError(error);\n }\n\n // Handle API errors with status codes\n const message = error instanceof Error ? error.message : String(error);\n const statusMatch = message.match(/(\\d{3})/);\n if (statusMatch) {\n const statusCode = Number.parseInt(statusMatch[1], 10);\n return inputErrorResult(ErrorMessages.apiError(statusCode, message));\n }\n\n return errorResult(message);\n }\n}\n"],"names":["cliFormatTimeEntry","cliFormatProject","cliFormatTask","cliFormatPerson","cliFormatService","cliFormatCompany","cliFormatComment","cliFormatTimer","cliFormatDeal","cliFormatBooking","cliFormatListResponse","VALID_ACTIONS"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
5
- import { V as VERSION, I as INSTRUCTIONS } from "./version-i2-GF6d1.js";
5
+ import { V as VERSION, I as INSTRUCTIONS } from "./version-DR8X3j5G.js";
6
6
  import { getAvailableTools, getAvailablePrompts, handlePrompt, handleToolCall } from "./stdio.js";
7
7
  function createStdioServer() {
8
8
  const server = new Server(
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAoB,KAAK,kBAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAMlF;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;EAYzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;EASvB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAY3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAM1D;;GAEG;AACH,eAAO,MAAM,OAAO,aAIgC,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,aAAa,aAKvB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,aAKxB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,aAGqD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,cAAc,aAGuD,CAAC;AAEnF;;GAEG;AACH,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,SAAS,aAIuC,CAAC;AAE9D;;GAEG;AACH,eAAO,MAAM,gBAAgB,aAKiE,CAAC;AAE/F;;GAEG;AACH,eAAO,MAAM,SAAS,2BAKiC,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,YAAY,2BAMsC,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,YAAY,6BAKtB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,UAAU,aAI4C,CAAC;AAEpE;;GAEG;AACH,eAAO,MAAM,YAAY,yBAItB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,SAAS,aAAkD,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,UAAU,aAIqB,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,SAAS,aAGgB,CAAC;AAMvC;;GAEG;AACH,eAAO,MAAM,YAAY,uDAGsB,CAAC;AAMhD;;;GAGG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwDpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAM5E;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAErE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAE7F;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,mBAAmB,CAAC,GAAG,MAAM,CAOnF"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAoB,KAAK,kBAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAMlF;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;EAYzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;EASvB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAY3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAM1D;;GAEG;AACH,eAAO,MAAM,OAAO,aAIgC,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,aAAa,aAKvB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,aAKxB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,aAGqD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,cAAc,aAGuD,CAAC;AAEnF;;GAEG;AACH,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,SAAS,aAIuC,CAAC;AAE9D;;GAEG;AACH,eAAO,MAAM,gBAAgB,aAKiE,CAAC;AAE/F;;GAEG;AACH,eAAO,MAAM,SAAS,2BAKiC,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,YAAY,2BAMsC,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,YAAY,6BAKtB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,UAAU,aAMpB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,YAAY,yBAItB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,SAAS,aAAkD,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,UAAU,aAIqB,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,SAAS,aAGgB,CAAC;AAMvC;;GAEG;AACH,eAAO,MAAM,YAAY,uDAGsB,CAAC;AAMhD;;;GAGG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwDpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAM5E;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAErE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAE7F;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,mBAAmB,CAAC,GAAG,MAAM,CAOnF"}
package/dist/server.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { toNodeListener } from "h3";
3
3
  import { createServer } from "node:http";
4
4
  import { createHttpApp } from "./http.js";
5
- import { V as VERSION } from "./version-i2-GF6d1.js";
5
+ import { V as VERSION } from "./version-DR8X3j5G.js";
6
6
  const DEFAULT_PORT = 3e3;
7
7
  const DEFAULT_HOST = "0.0.0.0";
8
8
  function startHttpServer(port = DEFAULT_PORT, host = DEFAULT_HOST) {
package/dist/stdio.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getConfig, setConfig } from "@studiometa/productive-cli";
2
- import { e as executeToolWithCredentials } from "./index-D743zTS1.js";
2
+ import { e as executeToolWithCredentials } from "./index-BDke-bMP.js";
3
3
  import { TOOLS, STDIO_ONLY_TOOLS } from "./tools.js";
4
4
  function getAvailableTools() {
5
5
  return [...TOOLS, ...STDIO_ONLY_TOOLS];
@@ -13,9 +13,9 @@ function loadInstructions() {
13
13
  }
14
14
  }
15
15
  const INSTRUCTIONS = loadInstructions();
16
- const VERSION = "0.8.0";
16
+ const VERSION = "0.8.2";
17
17
  export {
18
18
  INSTRUCTIONS as I,
19
19
  VERSION as V
20
20
  };
21
- //# sourceMappingURL=version-i2-GF6d1.js.map
21
+ //# sourceMappingURL=version-DR8X3j5G.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-i2-GF6d1.js","sources":["../src/instructions.ts","../src/version.ts"],"sourcesContent":["/**\n * MCP Server Instructions\n *\n * These instructions are sent to Claude Desktop during initialization\n * and used as context/hints for the LLM. This ensures the AI agent\n * knows how to properly use the Productive.io MCP server.\n *\n * The content is derived from skills/SKILL.md (without YAML frontmatter).\n */\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Load instructions from SKILL.md file\n * Removes YAML frontmatter (content between --- markers)\n */\nfunction loadInstructions(): string {\n try {\n // In dist/, go up to package root, then to skills/\n const skillPath = join(__dirname, '..', 'skills', 'SKILL.md');\n const content = readFileSync(skillPath, 'utf-8');\n\n // Remove YAML frontmatter (between --- markers at start of file)\n const withoutFrontmatter = content.replace(/^---\\n[\\s\\S]*?\\n---\\n+/, '');\n\n return withoutFrontmatter.trim();\n } catch {\n // Fallback if file not found (shouldn't happen in production)\n return 'Productive.io MCP Server - Use the productive tool with resource and action parameters.';\n }\n}\n\nexport const INSTRUCTIONS = loadInstructions();\n","/**\n * Package version - injected from package.json at build time\n */\ndeclare const __VERSION__: string;\nexport const VERSION = __VERSION__;\n"],"names":["__dirname"],"mappings":";;;AAcA,MAAMA,cAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAMxD,SAAS,mBAA2B;AAClC,MAAI;AAEF,UAAM,YAAY,KAAKA,aAAW,MAAM,UAAU,UAAU;AAC5D,UAAM,UAAU,aAAa,WAAW,OAAO;AAG/C,UAAM,qBAAqB,QAAQ,QAAQ,0BAA0B,EAAE;AAEvE,WAAO,mBAAmB,KAAA;AAAA,EAC5B,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAEO,MAAM,eAAe,iBAAA;AChCrB,MAAM,UAAU;"}
1
+ {"version":3,"file":"version-DR8X3j5G.js","sources":["../src/instructions.ts","../src/version.ts"],"sourcesContent":["/**\n * MCP Server Instructions\n *\n * These instructions are sent to Claude Desktop during initialization\n * and used as context/hints for the LLM. This ensures the AI agent\n * knows how to properly use the Productive.io MCP server.\n *\n * The content is derived from skills/SKILL.md (without YAML frontmatter).\n */\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Load instructions from SKILL.md file\n * Removes YAML frontmatter (content between --- markers)\n */\nfunction loadInstructions(): string {\n try {\n // In dist/, go up to package root, then to skills/\n const skillPath = join(__dirname, '..', 'skills', 'SKILL.md');\n const content = readFileSync(skillPath, 'utf-8');\n\n // Remove YAML frontmatter (between --- markers at start of file)\n const withoutFrontmatter = content.replace(/^---\\n[\\s\\S]*?\\n---\\n+/, '');\n\n return withoutFrontmatter.trim();\n } catch {\n // Fallback if file not found (shouldn't happen in production)\n return 'Productive.io MCP Server - Use the productive tool with resource and action parameters.';\n }\n}\n\nexport const INSTRUCTIONS = loadInstructions();\n","/**\n * Package version - injected from package.json at build time\n */\ndeclare const __VERSION__: string;\nexport const VERSION = __VERSION__;\n"],"names":["__dirname"],"mappings":";;;AAcA,MAAMA,cAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAMxD,SAAS,mBAA2B;AAClC,MAAI;AAEF,UAAM,YAAY,KAAKA,aAAW,MAAM,UAAU,UAAU;AAC5D,UAAM,UAAU,aAAa,WAAW,OAAO;AAG/C,UAAM,qBAAqB,QAAQ,QAAQ,0BAA0B,EAAE;AAEvE,WAAO,mBAAmB,KAAA;AAAA,EAC5B,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAEO,MAAM,eAAe,iBAAA;AChCrB,MAAM,UAAU;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studiometa/productive-mcp",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "MCP server for Productive.io API - Model Context Protocol integration for Claude Desktop",
5
5
  "keywords": [
6
6
  "ai",
@@ -88,7 +88,7 @@
88
88
  },
89
89
  "dependencies": {
90
90
  "@modelcontextprotocol/sdk": "^1.0.4",
91
- "@studiometa/productive-cli": "0.8.0",
91
+ "@studiometa/productive-cli": "0.8.2",
92
92
  "h3": "^1.15.1",
93
93
  "zod": "4.3.6"
94
94
  },
package/skills/SKILL.md CHANGED
@@ -46,17 +46,17 @@ Returns filters, fields, includes, and examples for that resource.
46
46
 
47
47
  ## Common Parameters
48
48
 
49
- | Parameter | Type | Description |
50
- | ---------- | ------- | ------------------------------------------------------ |
51
- | `resource` | string | **Required**. Resource type (see table above) |
52
- | `action` | string | **Required**. Action to perform |
53
- | `id` | string | Resource ID (for `get`, `update`, `stop`) |
54
- | `filter` | object | Filter criteria for `list` actions |
55
- | `page` | number | Page number (default: 1) |
56
- | `per_page` | number | Items per page (default: 20, max: 200) |
57
- | `compact` | boolean | Compact output (default: true for list, false for get) |
58
- | `include` | array | Related resources to include |
59
- | `query` | string | Text search on name/title fields |
49
+ | Parameter | Type | Description |
50
+ | ---------- | ------- | ---------------------------------------------------------------------------------------- |
51
+ | `resource` | string | **Required**. Resource type (see table above) |
52
+ | `action` | string | **Required**. Action to perform |
53
+ | `id` | string | Resource ID (for `get`, `update`, `stop`) |
54
+ | `filter` | object | Filter criteria for `list` actions |
55
+ | `page` | number | Page number (default: 1) |
56
+ | `per_page` | number | Items per page (default: 20, max: 200) |
57
+ | `compact` | boolean | Compact output (default: true for list, false for get) |
58
+ | `include` | array | Related resources to include |
59
+ | `query` | string | Text search (behavior varies by resource - may search related fields like project names) |
60
60
 
61
61
  ## Examples by Resource
62
62
 
@@ -128,8 +128,9 @@ Returns filters, fields, includes, and examples for that resource.
128
128
  "include": ["comments", "assignee"]
129
129
  }
130
130
 
131
- // Search tasks
131
+ // Search tasks by title or project name
132
132
  { "resource": "tasks", "action": "list", "query": "bug fix" }
133
+ { "resource": "tasks", "action": "list", "query": "crosscall" } // Also matches project names
133
134
 
134
135
  // Create task
135
136
  {
@@ -226,31 +227,89 @@ Returns filters, fields, includes, and examples for that resource.
226
227
  - `person_id` - Filter by person (use "me" for current user)
227
228
  - `project_id` - Filter by project
228
229
  - `service_id` - Filter by service
230
+ - `task_id` - Filter by task
231
+ - `company_id` - Filter by company
232
+ - `deal_id` / `budget_id` - Filter by deal/budget
229
233
  - `after` - After date (YYYY-MM-DD)
230
234
  - `before` - Before date (YYYY-MM-DD)
235
+ - `status` - Approval status: `1`=approved, `2`=unapproved, `3`=rejected
236
+ - `billing_type_id` - Billing type: `1`=fixed, `2`=actuals, `3`=non_billable
237
+ - `invoicing_status` - Invoicing: `1`=not_invoiced, `2`=drafted, `3`=finalized
231
238
 
232
239
  ### Tasks
233
240
 
234
241
  - `project_id` - Filter by project
242
+ - `company_id` - Filter by company
235
243
  - `assignee_id` - Filter by assigned person
236
- - `status` - Filter by status: `open`, `closed`, `all`
244
+ - `creator_id` - Filter by task creator
245
+ - `status` - Status: `1`=open, `2`=closed (or "open", "closed", "all")
237
246
  - `task_list_id` - Filter by task list
247
+ - `board_id` - Filter by board
248
+ - `workflow_status_id` - Filter by workflow status (kanban column)
249
+ - `parent_task_id` - Filter by parent task (for subtasks)
250
+ - `overdue_status` - Overdue: `1`=not overdue, `2`=overdue
251
+ - `due_date_on` / `due_date_before` / `due_date_after` - Due date filters
238
252
 
239
253
  ### Projects
240
254
 
241
255
  - `company_id` - Filter by company
242
- - `archived` - Include archived: `true`, `false`
256
+ - `project_type` - Type: `1`=internal, `2`=client
257
+ - `responsible_id` - Filter by project manager
258
+ - `person_id` - Filter by team member
259
+ - `status` - Status: `1`=active, `2`=archived
243
260
 
244
261
  ### Services
245
262
 
246
263
  - `project_id` - Filter by project
247
264
  - `deal_id` - Filter by deal
265
+ - `task_id` - Filter by task
266
+ - `person_id` - Filter by person (trackable by)
267
+ - `budget_status` - Status: `1`=open, `2`=delivered
268
+ - `billing_type` - Type: `1`=fixed, `2`=actuals, `3`=none
269
+ - `time_tracking_enabled` - Boolean
270
+
271
+ ### People
272
+
273
+ - `status` - Status: `1`=active, `2`=deactivated
274
+ - `person_type` - Type: `1`=user, `2`=contact, `3`=placeholder
275
+ - `company_id` - Filter by company
276
+ - `project_id` - Filter by project
277
+ - `role_id` - Filter by role
278
+ - `team` - Filter by team name
279
+
280
+ ### Deals
281
+
282
+ - `company_id` - Filter by company
283
+ - `project_id` - Filter by project
284
+ - `responsible_id` - Filter by responsible person
285
+ - `pipeline_id` - Filter by pipeline
286
+ - `stage_status_id` - Stage: `1`=open, `2`=won, `3`=lost
287
+ - `type` - Type: `1`=deal, `2`=budget
288
+ - `budget_status` - Budget status: `1`=open, `2`=closed
248
289
 
249
290
  ### Bookings
250
291
 
251
292
  - `person_id` - Filter by person
252
293
  - `service_id` - Filter by service
294
+ - `project_id` - Filter by project
295
+ - `company_id` - Filter by company
296
+ - `event_id` - Filter by event
253
297
  - `after` / `before` - Date range
298
+ - `booking_type` - Type: `event` (absence) or `service` (budget)
299
+ - `draft` - Tentative status: `true`/`false`
300
+
301
+ ### Comments
302
+
303
+ - `task_id` - Filter by task
304
+ - `deal_id` - Filter by deal
305
+ - `project_id` - Filter by project
306
+ - `page_id` - Filter by page
307
+ - `discussion_id` - Filter by discussion
308
+
309
+ ### Timers
310
+
311
+ - `person_id` - Filter by person
312
+ - `time_entry_id` - Filter by time entry
254
313
 
255
314
  ## Include (Related Resources)
256
315
 
@@ -326,5 +385,5 @@ Key points:
326
385
  1. **Use `action: "help"`** - Get resource documentation before using unfamiliar resources
327
386
  2. **Use `compact: false`** for detailed single-item views
328
387
  3. **Use `include`** to reduce round-trips when you need related data
329
- 4. **Use `query`** for text search instead of fetching all and filtering
388
+ 4. **Use `query`** for text search - behavior varies by resource but may include related fields (e.g., tasks query may match project names)
330
389
  5. **Check `people.me`** first to get the current user's ID for filters
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-D743zTS1.js","sources":["../src/errors.ts","../src/formatters.ts","../src/handlers/utils.ts","../src/handlers/bookings.ts","../src/handlers/comments.ts","../src/handlers/companies.ts","../src/handlers/deals.ts","../src/handlers/help.ts","../src/handlers/people.ts","../src/handlers/projects.ts","../src/handlers/reports.ts","../src/handlers/services.ts","../src/handlers/tasks.ts","../src/handlers/time.ts","../src/handlers/timers.ts","../src/handlers/index.ts"],"sourcesContent":["/**\n * Custom error classes for MCP server\n *\n * These provide structured error handling with LLM-friendly messages\n * that include guidance on how to resolve issues.\n */\n\n/**\n * Error thrown when user input validation fails.\n * These errors should be returned to the user directly.\n *\n * Includes optional hints for how to resolve the issue.\n */\nexport class UserInputError extends Error {\n public readonly hints?: string[];\n\n constructor(message: string, hints?: string[]) {\n super(message);\n this.name = 'UserInputError';\n this.hints = hints;\n }\n\n /**\n * Format error message with hints for LLM consumption\n */\n toFormattedMessage(): string {\n let msg = `**Input Error:** ${this.message}`;\n if (this.hints && this.hints.length > 0) {\n msg += '\\n\\n**Hints:**\\n' + this.hints.map((h) => `- ${h}`).join('\\n');\n }\n return msg;\n }\n}\n\n/**\n * Error messages with guidance for common validation failures\n */\nexport const ErrorMessages = {\n // Required field errors\n missingId: (action: string) =>\n new UserInputError(`id is required for ${action} action`, [\n `Use action=\"list\" first to find the resource ID`,\n `Then use action=\"${action}\" with the id parameter`,\n ]),\n\n missingRequiredFields: (resource: string, fields: string[]) =>\n new UserInputError(\n `${fields.join(', ')} ${fields.length === 1 ? 'is' : 'are'} required for creating ${resource}`,\n [\n `Provide all required fields: ${fields.join(', ')}`,\n `Use action=\"help\" for detailed documentation on ${resource}`,\n ],\n ),\n\n // Invalid action errors\n invalidAction: (action: string, resource: string, validActions: string[]) =>\n new UserInputError(`Invalid action \"${action}\" for ${resource}`, [\n `Valid actions are: ${validActions.join(', ')}`,\n `Use action=\"help\" with resource=\"${resource}\" for detailed documentation`,\n ]),\n\n // Unknown resource errors\n unknownResource: (resource: string, validResources: string[]) =>\n new UserInputError(`Unknown resource: ${resource}`, [\n `Valid resources are: ${validResources.join(', ')}`,\n `Use action=\"help\" without a resource for an overview of all resources`,\n ]),\n\n // Report-specific errors\n missingReportType: () =>\n new UserInputError('report_type is required for reports', [\n 'Specify report_type parameter (e.g., \"time_reports\", \"project_reports\")',\n 'Use action=\"help\" with resource=\"reports\" for available report types',\n ]),\n\n invalidReportType: (reportType: string, validTypes: string[]) =>\n new UserInputError(`Invalid report_type: ${reportType}`, [\n `Valid report types are: ${validTypes.join(', ')}`,\n 'Use action=\"help\" with resource=\"reports\" for detailed documentation',\n ]),\n\n // Timer-specific errors\n missingServiceForTimer: () =>\n new UserInputError('service_id is required to start a timer', [\n 'First find a service using resource=\"services\" action=\"list\"',\n 'Then start the timer with the service_id',\n ]),\n\n // People-specific errors\n noUserIdConfigured: () =>\n new UserInputError('User ID not configured', [\n 'The \"me\" action requires a user ID to be configured',\n 'Use action=\"list\" to find people, or configure the user ID',\n ]),\n\n // Comment-specific errors\n missingCommentTarget: () =>\n new UserInputError('A target is required for creating a comment', [\n 'Provide one of: task_id, deal_id, or company_id',\n 'Find targets using resource=\"tasks\", \"deals\", or \"companies\" with action=\"list\"',\n ]),\n\n // Booking-specific errors\n missingBookingTarget: () =>\n new UserInputError('A service or event is required for creating a booking', [\n 'Provide either: service_id or event_id',\n 'Find services using resource=\"services\" with action=\"list\"',\n ]),\n\n // API errors\n apiError: (statusCode: number, message: string) => {\n const hints: string[] = [];\n\n if (statusCode === 401) {\n hints.push('Check that your API token is valid and not expired');\n hints.push('Verify the organization ID is correct');\n } else if (statusCode === 403) {\n hints.push('You may not have permission to access this resource');\n hints.push('Check your API token permissions');\n } else if (statusCode === 404) {\n hints.push('The resource may not exist or you may not have access');\n hints.push('Verify the resource ID is correct');\n hints.push('Use action=\"list\" to find valid resource IDs');\n } else if (statusCode === 422) {\n hints.push('The request data may be invalid');\n hints.push('Check the field values and types');\n hints.push('Use action=\"help\" for field documentation');\n } else if (statusCode >= 500) {\n hints.push('This is a server error - try again later');\n }\n\n return new UserInputError(`API error (${statusCode}): ${message}`, hints);\n },\n} as const;\n\n/**\n * Check if an error is a UserInputError\n */\nexport function isUserInputError(error: unknown): error is UserInputError {\n return error instanceof UserInputError;\n}\n","/**\n * Response formatters for agent-friendly output\n *\n * This module re-exports formatters from @studiometa/productive-cli\n * with MCP-specific defaults (no relationship IDs, no timestamps).\n *\n * Supports compact mode to reduce token usage by omitting verbose fields\n * like descriptions and notes from list responses.\n */\n\nimport {\n formatTimeEntry as cliFormatTimeEntry,\n formatProject as cliFormatProject,\n formatTask as cliFormatTask,\n formatPerson as cliFormatPerson,\n formatService as cliFormatService,\n formatCompany as cliFormatCompany,\n formatComment as cliFormatComment,\n formatTimer as cliFormatTimer,\n formatDeal as cliFormatDeal,\n formatBooking as cliFormatBooking,\n formatListResponse as cliFormatListResponse,\n type JsonApiResource,\n type JsonApiMeta,\n type FormatOptions,\n type FormattedPagination,\n} from '@studiometa/productive-cli';\n\n// Re-export types\nexport type { JsonApiResource, JsonApiMeta, FormatOptions, FormattedPagination };\n\n/**\n * MCP-specific format options\n * - No relationship IDs (cleaner output for agents)\n * - No timestamps (reduce noise)\n * - HTML stripping enabled\n */\nconst MCP_FORMAT_OPTIONS: FormatOptions = {\n includeRelationshipIds: false,\n includeTimestamps: false,\n stripHtml: true,\n};\n\n/**\n * Extended format options for MCP with compact mode\n */\nexport interface McpFormatOptions {\n compact?: boolean;\n included?: JsonApiResource[];\n}\n\n/**\n * Remove verbose fields from an object for compact output\n */\nfunction compactify<T extends Record<string, unknown>>(obj: T, fieldsToRemove: string[]): T {\n const result = { ...obj };\n for (const field of fieldsToRemove) {\n delete result[field];\n }\n return result;\n}\n\n/**\n * Format time entry for agent consumption\n */\nexport function formatTimeEntry(\n entry: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatTimeEntry(entry, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['note', 'billable_time', 'approved']);\n }\n return result;\n}\n\n/**\n * Format project for agent consumption\n */\nexport function formatProject(\n project: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatProject(project, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['budget']);\n }\n return result;\n}\n\n/**\n * Format task for agent consumption\n * Tasks use included resources to resolve project/company names\n */\nexport function formatTask(\n task: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatTask(task, { ...MCP_FORMAT_OPTIONS, included: options?.included });\n if (options?.compact) {\n return compactify(result, [\n 'description',\n 'initial_estimate',\n 'worked_time',\n 'remaining_time',\n 'project', // Keep project_name but remove nested object\n 'company', // Keep company name inline if needed\n ]);\n }\n return result;\n}\n\n/**\n * Format person for agent consumption\n */\nexport function formatPerson(\n person: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatPerson(person, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['title', 'first_name', 'last_name']); // Keep 'name' which combines them\n }\n return result;\n}\n\n/**\n * Format service for agent consumption\n */\nexport function formatService(\n service: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatService(service, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['budgeted_time', 'worked_time']);\n }\n return result;\n}\n\n/**\n * Format company for agent consumption\n */\nexport function formatCompany(\n company: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatCompany(company, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['billing_name', 'domain', 'due_days']);\n }\n return result;\n}\n\n/**\n * Format comment for agent consumption\n */\nexport function formatComment(\n comment: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatComment(comment, { ...MCP_FORMAT_OPTIONS, included: options?.included });\n return result;\n}\n\n/**\n * Format timer for agent consumption\n */\nexport function formatTimer(\n timer: JsonApiResource,\n _options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatTimer(timer, MCP_FORMAT_OPTIONS);\n return result;\n}\n\n/**\n * Format deal for agent consumption\n */\nexport function formatDeal(\n deal: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatDeal(deal, { ...MCP_FORMAT_OPTIONS, included: options?.included });\n if (options?.compact) {\n return compactify(result, ['won_at', 'lost_at']);\n }\n return result;\n}\n\n/**\n * Format booking for agent consumption\n */\nexport function formatBooking(\n booking: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatBooking(booking, { ...MCP_FORMAT_OPTIONS, included: options?.included });\n if (options?.compact) {\n return compactify(result, ['approved_at', 'rejected_at', 'rejected_reason']);\n }\n return result;\n}\n\n/**\n * Format list response with pagination\n *\n * @param data - Array of JSON:API resources\n * @param formatter - Formatter function (item, options?) => T\n * @param meta - Pagination metadata\n * @param options - MCP format options (compact, included)\n */\nexport function formatListResponse<T>(\n data: JsonApiResource[],\n formatter: (item: JsonApiResource, options?: McpFormatOptions) => T,\n meta?: JsonApiMeta,\n options?: McpFormatOptions,\n): { data: T[]; meta?: FormattedPagination } {\n // Create a wrapper that passes MCP options to the formatter\n const wrappedFormatter = (item: JsonApiResource, _cliOptions?: FormatOptions) => {\n return formatter(item, options);\n };\n\n const result = cliFormatListResponse(data, wrappedFormatter, meta, {\n ...MCP_FORMAT_OPTIONS,\n included: options?.included,\n });\n\n return result as { data: T[]; meta?: FormattedPagination };\n}\n","/**\n * Utility functions for resource handlers\n */\n\nimport type { ToolResult } from './types.js';\n\nimport { UserInputError, isUserInputError } from '../errors.js';\n\n/**\n * Helper to create a successful JSON response\n */\nexport function jsonResult(data: unknown): ToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],\n };\n}\n\n/**\n * Helper to create an error response from a string message\n */\nexport function errorResult(message: string): ToolResult {\n return {\n content: [{ type: 'text', text: `**Error:** ${message}` }],\n isError: true,\n };\n}\n\n/**\n * Helper to create an error response from a UserInputError\n * Includes formatted hints for LLM consumption\n */\nexport function inputErrorResult(error: UserInputError): ToolResult {\n return {\n content: [{ type: 'text', text: error.toFormattedMessage() }],\n isError: true,\n };\n}\n\n/**\n * Helper to create an error response from any error type\n * Automatically formats UserInputError with hints\n */\nexport function formatError(error: unknown): ToolResult {\n if (isUserInputError(error)) {\n return inputErrorResult(error);\n }\n\n const message = error instanceof Error ? error.message : String(error);\n return errorResult(message);\n}\n\n/**\n * Convert unknown filter to string filter for API\n */\nexport function toStringFilter(\n filter?: Record<string, unknown>,\n): Record<string, string> | undefined {\n if (!filter) return undefined;\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(filter)) {\n if (value !== undefined && value !== null) {\n result[key] = String(value);\n }\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","/**\n * Bookings resource handler\n */\n\nimport type { BookingArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatBooking, formatListResponse } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/** Default includes for bookings */\nconst DEFAULT_BOOKING_INCLUDE = ['person', 'service'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleBookings(\n action: string,\n args: BookingArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, person_id, service_id, event_id, started_on, ended_on, time, note } = args;\n // Merge default includes with user-provided includes\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_BOOKING_INCLUDE, ...userInclude])]\n : DEFAULT_BOOKING_INCLUDE;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getBooking(id, { include });\n return jsonResult(formatBooking(result.data, { ...formatOptions, included: result.included }));\n }\n\n if (action === 'create') {\n if (!person_id || !started_on || !ended_on) {\n return inputErrorResult(\n ErrorMessages.missingRequiredFields('booking', ['person_id', 'started_on', 'ended_on']),\n );\n }\n if (!service_id && !event_id) {\n return inputErrorResult(ErrorMessages.missingBookingTarget());\n }\n const result = await api.createBooking({\n person_id,\n service_id,\n event_id,\n started_on,\n ended_on,\n time,\n note,\n });\n return jsonResult({ success: true, ...formatBooking(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateBooking>[1] = {};\n if (started_on !== undefined) updateData.started_on = started_on;\n if (ended_on !== undefined) updateData.ended_on = ended_on;\n if (time !== undefined) updateData.time = time;\n if (note !== undefined) updateData.note = note;\n const result = await api.updateBooking(id, updateData);\n return jsonResult({ success: true, ...formatBooking(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getBookings({ filter, page, perPage, include });\n return jsonResult(\n formatListResponse(result.data, formatBooking, result.meta, {\n ...formatOptions,\n included: result.included,\n }),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'bookings', VALID_ACTIONS));\n}\n","/**\n * Comments resource handler\n */\n\nimport type { CommentArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatComment, formatListResponse } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/** Default includes for comments */\nconst DEFAULT_COMMENT_INCLUDE = ['creator'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleComments(\n action: string,\n args: CommentArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, body, task_id, deal_id, company_id } = args;\n // Merge default includes with user-provided includes\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_COMMENT_INCLUDE, ...userInclude])]\n : DEFAULT_COMMENT_INCLUDE;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getComment(id, { include });\n return jsonResult(formatComment(result.data, { ...formatOptions, included: result.included }));\n }\n\n if (action === 'create') {\n if (!body) return inputErrorResult(ErrorMessages.missingRequiredFields('comment', ['body']));\n if (!task_id && !deal_id && !company_id) {\n return inputErrorResult(ErrorMessages.missingCommentTarget());\n }\n const result = await api.createComment({\n body,\n task_id,\n deal_id,\n company_id,\n });\n return jsonResult({ success: true, ...formatComment(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n if (!body)\n return inputErrorResult(ErrorMessages.missingRequiredFields('comment update', ['body']));\n const result = await api.updateComment(id, { body });\n return jsonResult({ success: true, ...formatComment(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getComments({ filter, page, perPage, include });\n return jsonResult(\n formatListResponse(result.data, formatComment, result.meta, {\n ...formatOptions,\n included: result.included,\n }),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'comments', VALID_ACTIONS));\n}\n","/**\n * Companies resource handler\n */\n\nimport type { CompanyArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatCompany, formatListResponse } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleCompanies(\n action: string,\n args: CompanyArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n const { id, name } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getCompany(id);\n return jsonResult(formatCompany(result.data, formatOptions));\n }\n\n if (action === 'create') {\n if (!name) return inputErrorResult(ErrorMessages.missingRequiredFields('company', ['name']));\n const result = await api.createCompany({ name });\n return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateCompany>[1] = {};\n if (name !== undefined) updateData.name = name;\n const result = await api.updateCompany(id, updateData);\n return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getCompanies({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatCompany, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'companies', VALID_ACTIONS));\n}\n","/**\n * Deals resource handler\n */\n\nimport type { DealArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatDeal, formatListResponse } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/** Default includes for deals */\nconst DEFAULT_DEAL_INCLUDE_GET = ['company', 'deal_status', 'responsible'];\nconst DEFAULT_DEAL_INCLUDE_LIST = ['company', 'deal_status'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleDeals(\n action: string,\n args: DealArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, name, company_id } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_DEAL_INCLUDE_GET, ...userInclude])]\n : DEFAULT_DEAL_INCLUDE_GET;\n const result = await api.getDeal(id, { include });\n return jsonResult(formatDeal(result.data, { ...formatOptions, included: result.included }));\n }\n\n if (action === 'create') {\n if (!name || !company_id) {\n return inputErrorResult(ErrorMessages.missingRequiredFields('deal', ['name', 'company_id']));\n }\n const result = await api.createDeal({ name, company_id });\n return jsonResult({ success: true, ...formatDeal(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateDeal>[1] = {};\n if (name !== undefined) updateData.name = name;\n const result = await api.updateDeal(id, updateData);\n return jsonResult({ success: true, ...formatDeal(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_DEAL_INCLUDE_LIST, ...userInclude])]\n : DEFAULT_DEAL_INCLUDE_LIST;\n const result = await api.getDeals({\n filter,\n page,\n perPage,\n include,\n });\n return jsonResult(\n formatListResponse(result.data, formatDeal, result.meta, {\n ...formatOptions,\n included: result.included,\n }),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'deals', VALID_ACTIONS));\n}\n","/**\n * Help handler - provides detailed documentation for each resource\n */\n\nimport type { ToolResult } from './types.js';\n\nimport { jsonResult } from './utils.js';\n\ninterface ResourceHelp {\n description: string;\n actions: Record<string, string>;\n filters?: Record<string, string>;\n includes?: string[];\n fields?: Record<string, string>;\n examples?: Array<{ description: string; params: Record<string, unknown> }>;\n}\n\nconst RESOURCE_HELP: Record<string, ResourceHelp> = {\n projects: {\n description: 'Manage projects in Productive.io',\n actions: {\n list: 'List all projects with optional filters',\n get: 'Get a single project by ID with full details',\n },\n filters: {\n query: 'Text search on project name',\n project_type_id: 'Filter by project type',\n company_id: 'Filter by company',\n archived: 'Filter by archived status (true/false)',\n },\n fields: {\n id: 'Unique project identifier',\n name: 'Project name',\n project_number: 'Project reference number',\n archived: 'Whether the project is archived',\n budget: 'Project budget amount',\n },\n examples: [\n {\n description: 'Search projects by name',\n params: { resource: 'projects', action: 'list', query: 'website' },\n },\n {\n description: 'List active projects',\n params: { resource: 'projects', action: 'list', filter: { archived: 'false' } },\n },\n {\n description: 'Get project details',\n params: { resource: 'projects', action: 'get', id: '12345' },\n },\n ],\n },\n\n tasks: {\n description: 'Manage tasks within projects',\n actions: {\n list: 'List tasks with optional filters',\n get: 'Get a single task by ID with full details (description, comments, etc.)',\n create: 'Create a new task (requires title, project_id, task_list_id)',\n update: 'Update an existing task',\n },\n filters: {\n query: 'Text search on task title',\n project_id: 'Filter by project',\n assignee_id: 'Filter by assigned person',\n status: 'Filter by status (open, closed, all)',\n task_list_id: 'Filter by task list',\n },\n includes: [\n 'project',\n 'project.company',\n 'assignee',\n 'workflow_status',\n 'comments',\n 'attachments',\n 'subtasks',\n ],\n fields: {\n id: 'Unique task identifier',\n title: 'Task title',\n description: 'Full task description (HTML)',\n number: 'Task number within project',\n due_date: 'Due date (YYYY-MM-DD)',\n initial_estimate: 'Estimated time in minutes',\n worked_time: 'Logged time in minutes',\n remaining_time: 'Remaining time in minutes',\n closed: 'Whether the task is closed',\n },\n examples: [\n {\n description: 'Search tasks by title',\n params: { resource: 'tasks', action: 'list', query: 'bug fix' },\n },\n {\n description: 'List open tasks for a project',\n params: {\n resource: 'tasks',\n action: 'list',\n filter: { project_id: '12345', status: 'open' },\n },\n },\n {\n description: 'Get task with comments',\n params: {\n resource: 'tasks',\n action: 'get',\n id: '67890',\n include: ['comments', 'assignee'],\n },\n },\n {\n description: 'Create a task',\n params: {\n resource: 'tasks',\n action: 'create',\n title: 'New task',\n project_id: '12345',\n task_list_id: '111',\n },\n },\n ],\n },\n\n time: {\n description: 'Track time entries against services/tasks',\n actions: {\n list: 'List time entries with optional filters',\n get: 'Get a single time entry by ID',\n create: 'Create a new time entry (requires person_id, service_id, date, time)',\n update: 'Update an existing time entry',\n },\n filters: {\n person_id: 'Filter by person',\n service_id: 'Filter by service',\n project_id: 'Filter by project',\n after: 'Filter entries after date (YYYY-MM-DD)',\n before: 'Filter entries before date (YYYY-MM-DD)',\n },\n fields: {\n id: 'Unique time entry identifier',\n date: 'Date of the entry (YYYY-MM-DD)',\n time: 'Time in minutes',\n note: 'Description of work done',\n billable_time: 'Billable time in minutes',\n approved: 'Whether the entry is approved',\n },\n examples: [\n {\n description: 'List my time entries this week',\n params: {\n resource: 'time',\n action: 'list',\n filter: { person_id: 'me', after: '2024-01-15', before: '2024-01-21' },\n },\n },\n {\n description: 'Log 2 hours',\n params: {\n resource: 'time',\n action: 'create',\n service_id: '12345',\n date: '2024-01-16',\n time: 120,\n note: 'Development work',\n },\n },\n ],\n },\n\n services: {\n description: 'Budget line items within projects',\n actions: {\n list: 'List services with optional filters',\n get: 'Get a single service by ID',\n },\n filters: {\n project_id: 'Filter by project',\n deal_id: 'Filter by deal',\n },\n fields: {\n id: 'Unique service identifier',\n name: 'Service name',\n budgeted_time: 'Budgeted time in minutes',\n worked_time: 'Logged time in minutes',\n },\n examples: [\n {\n description: 'List services for a project',\n params: { resource: 'services', action: 'list', filter: { project_id: '12345' } },\n },\n ],\n },\n\n people: {\n description: 'Team members and contacts',\n actions: {\n list: 'List people with optional filters',\n get: 'Get a single person by ID',\n me: 'Get the currently authenticated user',\n },\n filters: {\n query: 'Text search on name or email',\n status: 'Filter by status (active, inactive)',\n },\n fields: {\n id: 'Unique person identifier',\n name: 'Full name',\n first_name: 'First name',\n last_name: 'Last name',\n email: 'Email address',\n title: 'Job title',\n active: 'Whether the person is active',\n },\n examples: [\n { description: 'Get current user', params: { resource: 'people', action: 'me' } },\n {\n description: 'Search people by name',\n params: { resource: 'people', action: 'list', query: 'john' },\n },\n {\n description: 'List active team members',\n params: { resource: 'people', action: 'list', filter: { status: 'active' } },\n },\n ],\n },\n\n companies: {\n description: 'Client companies and organizations',\n actions: {\n list: 'List companies with optional filters',\n get: 'Get a single company by ID',\n create: 'Create a new company (requires name)',\n update: 'Update an existing company',\n },\n filters: {\n query: 'Text search on company name',\n archived: 'Filter by archived status (true/false)',\n },\n fields: {\n id: 'Unique company identifier',\n name: 'Company name',\n billing_name: 'Legal/billing name',\n domain: 'Website domain',\n vat: 'VAT number',\n },\n examples: [\n {\n description: 'Search companies',\n params: { resource: 'companies', action: 'list', query: 'acme' },\n },\n {\n description: 'List active companies',\n params: { resource: 'companies', action: 'list', filter: { archived: 'false' } },\n },\n ],\n },\n\n comments: {\n description: 'Comments on tasks, deals, and other resources',\n actions: {\n list: 'List comments with optional filters',\n get: 'Get a single comment by ID',\n create: 'Create a new comment (requires body and one of: task_id, deal_id, company_id)',\n update: 'Update an existing comment',\n },\n filters: {\n task_id: 'Filter by task',\n deal_id: 'Filter by deal',\n },\n includes: ['creator', 'task', 'deal'],\n fields: {\n id: 'Unique comment identifier',\n body: 'Comment text (may contain HTML)',\n creator: 'Person who created the comment',\n },\n examples: [\n {\n description: 'List comments on a task',\n params: { resource: 'comments', action: 'list', filter: { task_id: '12345' } },\n },\n {\n description: 'Add a comment',\n params: { resource: 'comments', action: 'create', task_id: '12345', body: 'Looking good!' },\n },\n ],\n },\n\n timers: {\n description: 'Active time tracking timers',\n actions: {\n list: 'List active timers',\n get: 'Get a single timer by ID',\n start: 'Start a new timer (requires service_id or time_entry_id)',\n stop: 'Stop an active timer by ID',\n },\n fields: {\n id: 'Unique timer identifier',\n started_at: 'When the timer started (ISO 8601)',\n total_time: 'Elapsed time in seconds',\n },\n examples: [\n { description: 'List active timers', params: { resource: 'timers', action: 'list' } },\n {\n description: 'Start timer on service',\n params: { resource: 'timers', action: 'start', service_id: '12345' },\n },\n { description: 'Stop timer', params: { resource: 'timers', action: 'stop', id: '67890' } },\n ],\n },\n\n deals: {\n description: 'Sales deals and opportunities',\n actions: {\n list: 'List deals with optional filters',\n get: 'Get a single deal by ID',\n create: 'Create a new deal (requires name, company_id)',\n update: 'Update an existing deal',\n },\n filters: {\n query: 'Text search on deal name',\n company_id: 'Filter by company',\n deal_status_id: 'Filter by status',\n },\n includes: ['company', 'deal_status', 'responsible', 'project'],\n fields: {\n id: 'Unique deal identifier',\n name: 'Deal name',\n number: 'Deal number',\n date: 'Deal date',\n status: 'Current status (from deal_status)',\n },\n examples: [\n {\n description: 'Search deals',\n params: { resource: 'deals', action: 'list', query: 'website redesign' },\n },\n {\n description: 'List deals for a company',\n params: { resource: 'deals', action: 'list', filter: { company_id: '12345' } },\n },\n ],\n },\n\n bookings: {\n description: 'Resource scheduling and capacity planning',\n actions: {\n list: 'List bookings with optional filters',\n get: 'Get a single booking by ID',\n create:\n 'Create a new booking (requires person_id, started_on, ended_on, and service_id or event_id)',\n update: 'Update an existing booking',\n },\n filters: {\n person_id: 'Filter by person',\n service_id: 'Filter by service',\n after: 'Filter bookings after date (YYYY-MM-DD)',\n before: 'Filter bookings before date (YYYY-MM-DD)',\n },\n includes: ['person', 'service', 'event'],\n fields: {\n id: 'Unique booking identifier',\n started_on: 'Start date (YYYY-MM-DD)',\n ended_on: 'End date (YYYY-MM-DD)',\n time: 'Time per day in minutes',\n total_time: 'Total booked time in minutes',\n note: 'Booking note',\n },\n examples: [\n {\n description: 'List my bookings',\n params: { resource: 'bookings', action: 'list', filter: { person_id: 'me' } },\n },\n ],\n },\n\n reports: {\n description: 'Generate various reports (time, budget, project, etc.)',\n actions: {\n get: 'Generate a report (requires report_type)',\n },\n filters: {\n person_id: 'Filter by person',\n project_id: 'Filter by project',\n company_id: 'Filter by company',\n after: 'Filter from date (YYYY-MM-DD)',\n before: 'Filter to date (YYYY-MM-DD)',\n },\n fields: {\n report_type:\n 'Type of report: time_reports, project_reports, budget_reports, person_reports, invoice_reports, payment_reports, service_reports, task_reports, company_reports, deal_reports, timesheet_reports',\n group: 'Grouping dimension (varies by report type)',\n from: 'Start date for date range',\n to: 'End date for date range',\n },\n examples: [\n {\n description: 'Time report by person',\n params: {\n resource: 'reports',\n action: 'get',\n report_type: 'time_reports',\n group: 'person',\n from: '2024-01-01',\n to: '2024-01-31',\n },\n },\n {\n description: 'Project budget report',\n params: {\n resource: 'reports',\n action: 'get',\n report_type: 'budget_reports',\n filter: { project_id: '12345' },\n },\n },\n ],\n },\n};\n\n/**\n * Handle help action - returns documentation for a specific resource\n */\nexport function handleHelp(resource: string): ToolResult {\n const help = RESOURCE_HELP[resource];\n\n if (!help) {\n return jsonResult({\n error: `Unknown resource: ${resource}`,\n available_resources: Object.keys(RESOURCE_HELP),\n });\n }\n\n return jsonResult({\n resource,\n ...help,\n });\n}\n\n/**\n * Get help for all resources (overview)\n */\nexport function handleHelpOverview(): ToolResult {\n const overview = Object.entries(RESOURCE_HELP).map(([resource, help]) => ({\n resource,\n description: help.description,\n actions: Object.keys(help.actions),\n }));\n\n return jsonResult({\n message: 'Use action=\"help\" with a specific resource for detailed documentation',\n resources: overview,\n });\n}\n","/**\n * People resource handler\n */\n\nimport type { ProductiveCredentials } from '../auth.js';\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatPerson } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'me'];\n\nexport async function handlePeople(\n action: string,\n args: CommonArgs,\n ctx: HandlerContext,\n credentials: ProductiveCredentials,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n const { id } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getPerson(id);\n return jsonResult(formatPerson(result.data, formatOptions));\n }\n\n if (action === 'me') {\n if (credentials.userId) {\n const result = await api.getPerson(credentials.userId);\n return jsonResult(formatPerson(result.data, formatOptions));\n }\n return jsonResult({\n message: 'User ID not configured. Set userId in credentials to use this action.',\n hint: 'Use action=\"list\" to find people, or configure the user ID in your credentials.',\n organizationId: credentials.organizationId,\n });\n }\n\n if (action === 'list') {\n const result = await api.getPeople({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatPerson, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'people', VALID_ACTIONS));\n}\n","/**\n * Projects resource handler\n */\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatProject } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get'];\n\nexport async function handleProjects(\n action: string,\n args: CommonArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n const { id } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getProject(id);\n return jsonResult(formatProject(result.data, formatOptions));\n }\n\n if (action === 'list') {\n const result = await api.getProjects({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatProject, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'projects', VALID_ACTIONS));\n}\n","/**\n * Reports resource handler\n */\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/**\n * Report-specific args\n */\ninterface ReportArgs extends CommonArgs {\n report_type?: string;\n group?: string;\n from?: string;\n to?: string;\n person_id?: string;\n project_id?: string;\n company_id?: string;\n deal_id?: string;\n status?: string;\n}\n\n/**\n * Format report data for agent consumption\n * Flattens attributes for easier reading\n */\nfunction formatReportData(data: unknown[]): unknown[] {\n return data.map((item: unknown) => {\n const record = item as { id: string; type: string; attributes: Record<string, unknown> };\n return {\n id: record.id,\n type: record.type,\n ...record.attributes,\n };\n });\n}\n\n/**\n * Valid report types\n */\nconst VALID_REPORT_TYPES = [\n 'time_reports',\n 'project_reports',\n 'budget_reports',\n 'person_reports',\n 'invoice_reports',\n 'payment_reports',\n 'service_reports',\n 'task_reports',\n 'company_reports',\n 'deal_reports',\n 'timesheet_reports',\n];\n\nconst VALID_ACTIONS = ['get'];\n\nexport async function handleReports(\n action: string,\n args: ReportArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, filter, page, perPage } = ctx;\n const { report_type, group, from, to, person_id, project_id, company_id, deal_id, status } = args;\n\n if (action !== 'get') {\n return inputErrorResult(ErrorMessages.invalidAction(action, 'reports', VALID_ACTIONS));\n }\n\n if (!report_type) {\n return inputErrorResult(ErrorMessages.missingReportType());\n }\n\n if (!VALID_REPORT_TYPES.includes(report_type)) {\n return inputErrorResult(ErrorMessages.invalidReportType(report_type, VALID_REPORT_TYPES));\n }\n\n // Build filters based on report type\n const reportFilter: Record<string, string> = { ...filter };\n\n // Date filters (different APIs use different param names)\n if (from) {\n if (report_type === 'invoice_reports') {\n reportFilter.invoice_date_after = from;\n } else if (report_type === 'payment_reports' || report_type === 'deal_reports') {\n reportFilter.date_after = from;\n } else {\n reportFilter.after = from;\n }\n }\n\n if (to) {\n if (report_type === 'invoice_reports') {\n reportFilter.invoice_date_before = to;\n } else if (report_type === 'payment_reports' || report_type === 'deal_reports') {\n reportFilter.date_before = to;\n } else {\n reportFilter.before = to;\n }\n }\n\n // Entity filters\n if (person_id) {\n if (report_type === 'task_reports') {\n reportFilter.assignee_id = person_id;\n } else {\n reportFilter.person_id = person_id;\n }\n }\n\n if (project_id) reportFilter.project_id = project_id;\n if (company_id) reportFilter.company_id = company_id;\n if (deal_id) {\n if (report_type === 'deal_reports') {\n reportFilter.deal_status_id = deal_id;\n } else {\n reportFilter.deal_id = deal_id;\n }\n }\n if (status) {\n if (report_type === 'deal_reports') {\n reportFilter.deal_status_id = status;\n } else {\n reportFilter.status = status;\n }\n }\n\n // Determine default grouping based on report type\n let effectiveGroup = group;\n if (!effectiveGroup) {\n const defaultGroups: Record<string, string> = {\n time_reports: 'person',\n project_reports: 'project',\n budget_reports: 'deal',\n person_reports: 'person',\n invoice_reports: 'invoice',\n payment_reports: 'payment',\n service_reports: 'service',\n task_reports: 'task',\n company_reports: 'company',\n deal_reports: 'deal',\n };\n effectiveGroup = defaultGroups[report_type];\n }\n\n // Determine include based on report type\n const includeMap: Record<string, string[]> = {\n project_reports: ['project'],\n budget_reports: ['deal'],\n person_reports: ['person'],\n invoice_reports: ['invoice'],\n payment_reports: ['payment'],\n service_reports: ['service'],\n task_reports: ['task'],\n company_reports: ['company'],\n deal_reports: ['deal'],\n timesheet_reports: ['person'],\n };\n const include = includeMap[report_type];\n\n const result = await api.getReports(report_type, {\n page,\n perPage,\n filter: reportFilter,\n group: effectiveGroup,\n include,\n });\n\n const formattedData = formatReportData(result.data);\n\n return jsonResult({\n data: formattedData,\n meta: result.meta,\n });\n}\n","/**\n * Services resource handler\n */\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatService } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list'];\n\nexport async function handleServices(\n action: string,\n _args: CommonArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n\n if (action === 'list') {\n const result = await api.getServices({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatService, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'services', VALID_ACTIONS));\n}\n","/**\n * Tasks resource handler\n */\n\nimport type { HandlerContext, TaskArgs, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTask } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\n/** Default includes for tasks */\nconst DEFAULT_TASK_INCLUDE = ['project', 'project.company'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleTasks(\n action: string,\n args: TaskArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, title, project_id, task_list_id, description, assignee_id } = args;\n // Merge default includes with user-provided includes\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_TASK_INCLUDE, ...userInclude])]\n : DEFAULT_TASK_INCLUDE;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getTask(id, { include });\n return jsonResult(formatTask(result.data, { ...formatOptions, included: result.included }));\n }\n\n if (action === 'create') {\n if (!title || !project_id || !task_list_id) {\n return inputErrorResult(\n ErrorMessages.missingRequiredFields('task', ['title', 'project_id', 'task_list_id']),\n );\n }\n const result = await api.createTask({\n title,\n project_id,\n task_list_id,\n assignee_id,\n description,\n });\n return jsonResult({ success: true, ...formatTask(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateTask>[1] = {};\n if (title !== undefined) updateData.title = title;\n if (description !== undefined) updateData.description = description;\n if (assignee_id !== undefined) updateData.assignee_id = assignee_id;\n const result = await api.updateTask(id, updateData);\n return jsonResult({ success: true, ...formatTask(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getTasks({ filter, page, perPage, include });\n return jsonResult(\n formatListResponse(result.data, formatTask, result.meta, {\n ...formatOptions,\n included: result.included,\n }),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'tasks', VALID_ACTIONS));\n}\n","/**\n * Time entries resource handler\n */\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTimeEntry } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update'];\n\nexport async function handleTime(\n action: string,\n args: CommonArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage } = ctx;\n const { id, person_id, service_id, task_id, time, date, note } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getTimeEntry(id);\n return jsonResult(formatTimeEntry(result.data, formatOptions));\n }\n\n if (action === 'create') {\n if (!person_id || !service_id || !time || !date) {\n return inputErrorResult(\n ErrorMessages.missingRequiredFields('time entry', [\n 'person_id',\n 'service_id',\n 'time',\n 'date',\n ]),\n );\n }\n const result = await api.createTimeEntry({\n person_id,\n service_id,\n time,\n date,\n note,\n task_id,\n });\n return jsonResult({ success: true, ...formatTimeEntry(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const updateData: Parameters<typeof api.updateTimeEntry>[1] = {};\n if (time !== undefined) updateData.time = time;\n if (date !== undefined) updateData.date = date;\n if (note !== undefined) updateData.note = note;\n const result = await api.updateTimeEntry(id, updateData);\n return jsonResult({ success: true, ...formatTimeEntry(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getTimeEntries({ filter, page, perPage });\n return jsonResult(formatListResponse(result.data, formatTimeEntry, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'time', VALID_ACTIONS));\n}\n","/**\n * Timers resource handler\n */\n\nimport type { HandlerContext, TimerArgs, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTimer } from '../formatters.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'start', 'stop'];\n\nexport async function handleTimers(\n action: string,\n args: TimerArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { api, formatOptions, filter, page, perPage, include } = ctx;\n const { id, service_id, time_entry_id } = args;\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await api.getTimer(id, { include });\n return jsonResult(formatTimer(result.data, formatOptions));\n }\n\n if (action === 'start' || action === 'create') {\n if (!service_id && !time_entry_id) {\n return inputErrorResult(ErrorMessages.missingServiceForTimer());\n }\n const result = await api.startTimer({ service_id, time_entry_id });\n return jsonResult({ success: true, ...formatTimer(result.data, formatOptions) });\n }\n\n if (action === 'stop') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('stop'));\n const result = await api.stopTimer(id);\n return jsonResult({ success: true, ...formatTimer(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await api.getTimers({ filter, page, perPage, include });\n return jsonResult(formatListResponse(result.data, formatTimer, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'timers', VALID_ACTIONS));\n}\n","/**\n * Tool execution handlers for Productive MCP server\n * These are shared between stdio and HTTP transports\n *\n * Single consolidated tool for minimal token overhead:\n * - productive: resource + action based API\n */\n\nimport { ProductiveApi } from '@studiometa/productive-cli';\n\nimport type { ProductiveCredentials } from '../auth.js';\nimport type { McpFormatOptions } from '../formatters.js';\nimport type { HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages, isUserInputError } from '../errors.js';\nimport { handleBookings } from './bookings.js';\nimport { handleComments } from './comments.js';\nimport { handleCompanies } from './companies.js';\nimport { handleDeals } from './deals.js';\nimport { handleHelp, handleHelpOverview } from './help.js';\nimport { handlePeople } from './people.js';\n// Resource handlers\nimport { handleProjects } from './projects.js';\nimport { handleReports } from './reports.js';\nimport { handleServices } from './services.js';\nimport { handleTasks } from './tasks.js';\nimport { handleTime } from './time.js';\nimport { handleTimers } from './timers.js';\nimport { errorResult, formatError, inputErrorResult, toStringFilter } from './utils.js';\n\n// Re-export types\nexport type { ToolResult } from './types.js';\n\n/** Valid resources for the productive tool */\nconst VALID_RESOURCES = [\n 'projects',\n 'time',\n 'tasks',\n 'services',\n 'people',\n 'companies',\n 'comments',\n 'timers',\n 'deals',\n 'bookings',\n 'reports',\n];\n\n/** Default page size for MCP (smaller than CLI to reduce token usage) */\nconst DEFAULT_PER_PAGE = 20;\n\n/**\n * Args interface for the consolidated tool\n */\ninterface ProductiveArgs {\n resource: string;\n action: string;\n id?: string;\n filter?: Record<string, unknown>;\n page?: number;\n per_page?: number;\n compact?: boolean;\n include?: string[];\n query?: string;\n // Common fields\n person_id?: string;\n service_id?: string;\n task_id?: string;\n company_id?: string;\n time?: number;\n date?: string;\n note?: string;\n // Task fields\n title?: string;\n project_id?: string;\n task_list_id?: string;\n description?: string;\n assignee_id?: string;\n // Company fields\n name?: string;\n // Comment fields\n body?: string;\n deal_id?: string;\n // Timer fields\n time_entry_id?: string;\n // Booking fields\n started_on?: string;\n ended_on?: string;\n event_id?: string;\n // Report fields\n report_type?: string;\n group?: string;\n from?: string;\n to?: string;\n status?: string;\n}\n\n/**\n * Execute a tool with the given credentials and arguments\n */\nexport async function executeToolWithCredentials(\n name: string,\n args: Record<string, unknown>,\n credentials: ProductiveCredentials,\n): Promise<ToolResult> {\n // Initialize API client with provided credentials\n const api = new ProductiveApi({\n token: credentials.apiToken,\n 'org-id': credentials.organizationId,\n 'user-id': credentials.userId,\n } as Record<string, string>);\n\n // Handle the single consolidated tool\n if (name !== 'productive') {\n return errorResult(`Unknown tool: ${name}`);\n }\n\n const { resource, action, filter, page, per_page, compact, include, query, ...restArgs } =\n args as unknown as ProductiveArgs;\n\n // Default compact to false for 'get' action (single resource), true for 'list'\n const isCompact = compact ?? action !== 'get';\n const formatOptions: McpFormatOptions = { compact: isCompact };\n let stringFilter = toStringFilter(filter);\n const perPage = per_page ?? DEFAULT_PER_PAGE;\n\n // Add query to filter if provided (for text search)\n if (query) {\n stringFilter = { ...stringFilter, query };\n }\n\n // Build handler context\n const ctx: HandlerContext = {\n api,\n formatOptions,\n filter: stringFilter,\n page,\n perPage,\n include,\n };\n\n try {\n // Handle help action first (doesn't need API)\n if (action === 'help') {\n return resource ? handleHelp(resource) : handleHelpOverview();\n }\n\n // Route to appropriate resource handler\n switch (resource) {\n case 'projects':\n return await handleProjects(action, restArgs, ctx);\n\n case 'time':\n return await handleTime(action, restArgs, ctx);\n\n case 'tasks':\n return await handleTasks(action, restArgs, ctx);\n\n case 'services':\n return await handleServices(action, restArgs, ctx);\n\n case 'people':\n return await handlePeople(action, restArgs, ctx, credentials);\n\n case 'companies':\n return await handleCompanies(action, restArgs, ctx);\n\n case 'comments':\n return await handleComments(action, restArgs, ctx);\n\n case 'timers':\n return await handleTimers(action, restArgs, ctx);\n\n case 'deals':\n return await handleDeals(action, restArgs, ctx);\n\n case 'bookings':\n return await handleBookings(action, restArgs, ctx);\n\n case 'reports':\n return await handleReports(action, restArgs, ctx);\n\n default:\n return inputErrorResult(ErrorMessages.unknownResource(resource, VALID_RESOURCES));\n }\n } catch (error) {\n // Handle UserInputError with formatted hints\n if (isUserInputError(error)) {\n return formatError(error);\n }\n\n // Handle API errors with status codes\n const message = error instanceof Error ? error.message : String(error);\n const statusMatch = message.match(/(\\d{3})/);\n if (statusMatch) {\n const statusCode = Number.parseInt(statusMatch[1], 10);\n return inputErrorResult(ErrorMessages.apiError(statusCode, message));\n }\n\n return errorResult(message);\n }\n}\n"],"names":["cliFormatTimeEntry","cliFormatProject","cliFormatTask","cliFormatPerson","cliFormatService","cliFormatCompany","cliFormatComment","cliFormatTimer","cliFormatDeal","cliFormatBooking","cliFormatListResponse","VALID_ACTIONS"],"mappings":"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"}