@studiometa/productive-mcp 0.9.1 → 0.9.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.
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/{handlers-BYE2INiR.js → handlers-D4tRd30c.js} +4 -20
- package/dist/{handlers-BYE2INiR.js.map → handlers-D4tRd30c.js.map} +1 -1
- package/dist/handlers.js +1 -1
- package/dist/http.js +2 -2
- package/dist/index.js +2 -2
- package/dist/schema.d.ts +4 -3
- package/dist/schema.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/stdio.js +1 -1
- package/dist/tools.d.ts +5 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +29 -38
- package/dist/tools.js.map +1 -1
- package/dist/{version-D3sSBq_j.js → version-IB2ulmSy.js} +2 -2
- package/dist/{version-D3sSBq_j.js.map → version-IB2ulmSy.js.map} +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,YAAY,CAAC;AAwB7D,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,YAAY,CAAC;AAwB7D,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA2D7C;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,EAAE,qBAAqB,GACjC,OAAO,CAAC,UAAU,CAAC,CAkIrB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ProductiveApi, formatAttachment, formatBooking, formatBudget, formatComment, formatCompany, formatDeal, formatDiscussion, formatListResponse, formatPage, formatPerson, formatProject, formatService, formatTask, formatTimeEntry, formatTimer } from "@studiometa/productive-api";
|
|
2
|
-
import { ResolveError, VALID_REPORT_TYPES, createBooking, createComment, createCompany, createDeal, createDiscussion, createPage, createTask, createTimeEntry, deleteAttachment, deleteDiscussion, deletePage, fromHandlerContext, getAttachment, getBooking, getBudget, getComment, getCompany, getDeal, getDiscussion, getPage, getPerson, getProject, getReport, getTask, getTimeEntry, getTimer, listAttachments, listBookings, listBudgets, listComments, listCompanies, listDeals, listDiscussions, listPages, listPeople, listProjects, listServices, listTasks, listTimeEntries, listTimers, reopenDiscussion, resolveDiscussion, resolveResource, startTimer, stopTimer, updateBooking, updateComment, updateCompany, updateDeal, updateDiscussion, updatePage, updateTask, updateTimeEntry } from "@studiometa/productive-core";
|
|
2
|
+
import { RESOURCES, ResolveError, VALID_REPORT_TYPES, createBooking, createComment, createCompany, createDeal, createDiscussion, createPage, createTask, createTimeEntry, deleteAttachment, deleteDiscussion, deletePage, fromHandlerContext, getAttachment, getBooking, getBudget, getComment, getCompany, getDeal, getDiscussion, getPage, getPerson, getProject, getReport, getTask, getTimeEntry, getTimer, listAttachments, listBookings, listBudgets, listComments, listCompanies, listDeals, listDiscussions, listPages, listPeople, listProjects, listServices, listTasks, listTimeEntries, listTimers, reopenDiscussion, resolveDiscussion, resolveResource, startTimer, stopTimer, updateBooking, updateComment, updateCompany, updateDeal, updateDiscussion, updatePage, updateTask, updateTimeEntry } from "@studiometa/productive-core";
|
|
3
3
|
/**
|
|
4
4
|
* Custom error classes for MCP server
|
|
5
5
|
*
|
|
@@ -2573,24 +2573,8 @@ async function handleTimers(action, args, ctx) {
|
|
|
2573
2573
|
* Single consolidated tool for minimal token overhead:
|
|
2574
2574
|
* - productive: resource + action based API
|
|
2575
2575
|
*/
|
|
2576
|
-
/** Valid resources for the productive tool */
|
|
2577
|
-
var VALID_RESOURCES = [
|
|
2578
|
-
"projects",
|
|
2579
|
-
"time",
|
|
2580
|
-
"tasks",
|
|
2581
|
-
"services",
|
|
2582
|
-
"people",
|
|
2583
|
-
"companies",
|
|
2584
|
-
"comments",
|
|
2585
|
-
"attachments",
|
|
2586
|
-
"timers",
|
|
2587
|
-
"deals",
|
|
2588
|
-
"bookings",
|
|
2589
|
-
"budgets",
|
|
2590
|
-
"pages",
|
|
2591
|
-
"discussions",
|
|
2592
|
-
"reports"
|
|
2593
|
-
];
|
|
2576
|
+
/** Valid resources for the productive tool (derived from core constants) */
|
|
2577
|
+
var VALID_RESOURCES = [...RESOURCES];
|
|
2594
2578
|
/** Default page size for MCP (smaller than CLI to reduce token usage) */
|
|
2595
2579
|
var DEFAULT_PER_PAGE = 20;
|
|
2596
2580
|
/**
|
|
@@ -2678,4 +2662,4 @@ async function executeToolWithCredentials(name, args, credentials) {
|
|
|
2678
2662
|
}
|
|
2679
2663
|
export { executeToolWithCredentials as t };
|
|
2680
2664
|
|
|
2681
|
-
//# sourceMappingURL=handlers-
|
|
2665
|
+
//# sourceMappingURL=handlers-D4tRd30c.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers-BYE2INiR.js","names":[],"sources":["../src/errors.ts","../src/formatters.ts","../src/hints.ts","../src/handlers/utils.ts","../src/handlers/attachments.ts","../src/handlers/bookings.ts","../src/handlers/budgets.ts","../src/handlers/comments.ts","../src/handlers/resolve.ts","../src/handlers/companies.ts","../src/handlers/deals.ts","../src/handlers/discussions.ts","../src/handlers/help.ts","../src/handlers/pages.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-api\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 formatBudget as cliFormatBudget,\n formatCompany as cliFormatCompany,\n formatComment as cliFormatComment,\n formatTimer as cliFormatTimer,\n formatDeal as cliFormatDeal,\n formatBooking as cliFormatBooking,\n formatAttachment as cliFormatAttachment,\n formatPage as cliFormatPage,\n formatDiscussion as cliFormatDiscussion,\n formatListResponse as cliFormatListResponse,\n type JsonApiResource,\n type JsonApiMeta,\n type FormatOptions,\n type FormattedPagination,\n} from '@studiometa/productive-api';\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 budget for agent consumption\n */\nexport function formatBudget(\n budget: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatBudget(budget, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['budget_type', 'currency']);\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 attachment for agent consumption\n */\nexport function formatAttachment(\n attachment: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatAttachment(attachment, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['url']);\n }\n return result;\n}\n\n/**\n * Format page for agent consumption\n */\nexport function formatPage(\n page: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatPage(page, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['body', 'version_number']);\n }\n return result;\n}\n\n/**\n * Format discussion for agent consumption\n */\nexport function formatDiscussion(\n discussion: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatDiscussion(discussion, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['body']);\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 * Contextual hints for AI agents\n *\n * Provides suggestions for related resources and common actions\n * to help agents discover how to fetch additional context.\n */\n\nexport interface ResourceHint {\n resource: string;\n description: string;\n example: Record<string, unknown>;\n}\n\nexport interface ActionHint {\n action: string;\n example: Record<string, unknown>;\n}\n\nexport interface ContextualHints {\n related_resources?: ResourceHint[];\n common_actions?: ActionHint[];\n}\n\n/**\n * Generate hints for a task\n */\nexport function getTaskHints(taskId: string, serviceId?: string): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [\n {\n resource: 'comments',\n description: 'Get comments on this task',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { task_id: taskId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries logged on this task',\n example: {\n resource: 'time',\n action: 'list',\n filter: { task_id: taskId },\n },\n },\n {\n resource: 'tasks',\n description: 'Get subtasks of this task',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { parent_task_id: taskId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Add a comment',\n example: {\n resource: 'comments',\n action: 'create',\n task_id: taskId,\n body: '<your comment>',\n },\n },\n ],\n };\n\n // Add time logging hint if we have a service ID\n if (serviceId) {\n hints.common_actions!.push({\n action: 'Log time on this task',\n example: {\n resource: 'time',\n action: 'create',\n service_id: serviceId,\n task_id: taskId,\n date: new Date().toISOString().split('T')[0],\n time: 60,\n note: '<description of work>',\n },\n });\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a project\n */\nexport function getProjectHints(projectId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'tasks',\n description: 'Get tasks in this project',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n {\n resource: 'services',\n description: 'Get services (budget lines) for this project',\n example: {\n resource: 'services',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries for this project',\n example: {\n resource: 'time',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n {\n resource: 'comments',\n description: 'Get comments on this project',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n {\n resource: 'deals',\n description: 'Get deals/budgets for this project',\n example: {\n resource: 'deals',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Create a task',\n example: {\n resource: 'tasks',\n action: 'create',\n project_id: projectId,\n task_list_id: '<task_list_id>',\n title: '<task title>',\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a deal/budget\n */\nexport function getDealHints(dealId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'comments',\n description: 'Get comments on this deal/budget',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { deal_id: dealId },\n },\n },\n {\n resource: 'services',\n description: 'Get services (budget lines) for this deal',\n example: {\n resource: 'services',\n action: 'list',\n filter: { deal_id: dealId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries for this deal/budget',\n example: {\n resource: 'time',\n action: 'list',\n filter: { deal_id: dealId },\n },\n },\n {\n resource: 'bookings',\n description: 'Get resource bookings for this deal',\n example: {\n resource: 'bookings',\n action: 'list',\n filter: { deal_id: dealId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Add a comment',\n example: {\n resource: 'comments',\n action: 'create',\n deal_id: dealId,\n body: '<your comment>',\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a budget\n */\nexport function getBudgetHints(budgetId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'services',\n description: 'Get services (budget lines) for this budget',\n example: {\n resource: 'services',\n action: 'list',\n filter: { budget_id: budgetId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries for this budget',\n example: {\n resource: 'time',\n action: 'list',\n filter: { budget_id: budgetId },\n },\n },\n {\n resource: 'bookings',\n description: 'Get bookings for this budget',\n example: {\n resource: 'bookings',\n action: 'list',\n filter: { budget_id: budgetId },\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a person\n */\nexport function getPersonHints(personId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'tasks',\n description: 'Get tasks assigned to this person',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { assignee_id: personId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries by this person',\n example: {\n resource: 'time',\n action: 'list',\n filter: { person_id: personId },\n },\n },\n {\n resource: 'bookings',\n description: 'Get bookings for this person',\n example: {\n resource: 'bookings',\n action: 'list',\n filter: { person_id: personId },\n },\n },\n {\n resource: 'timers',\n description: 'Get active timers for this person',\n example: {\n resource: 'timers',\n action: 'list',\n filter: { person_id: personId },\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a service\n */\nexport function getServiceHints(serviceId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'time',\n description: 'Get time entries for this service',\n example: {\n resource: 'time',\n action: 'list',\n filter: { service_id: serviceId },\n },\n },\n {\n resource: 'tasks',\n description: 'Get tasks linked to this service',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { service_id: serviceId },\n },\n },\n {\n resource: 'bookings',\n description: 'Get bookings for this service',\n example: {\n resource: 'bookings',\n action: 'list',\n filter: { service_id: serviceId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Log time on this service',\n example: {\n resource: 'time',\n action: 'create',\n service_id: serviceId,\n date: new Date().toISOString().split('T')[0],\n time: 60,\n note: '<description of work>',\n },\n },\n {\n action: 'Start a timer',\n example: {\n resource: 'timers',\n action: 'start',\n service_id: serviceId,\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a company\n */\nexport function getCompanyHints(companyId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'projects',\n description: 'Get projects for this company',\n example: {\n resource: 'projects',\n action: 'list',\n filter: { company_id: companyId },\n },\n },\n {\n resource: 'deals',\n description: 'Get deals for this company',\n example: {\n resource: 'deals',\n action: 'list',\n filter: { company_id: companyId },\n },\n },\n {\n resource: 'tasks',\n description: 'Get tasks for this company',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { company_id: companyId },\n },\n },\n {\n resource: 'people',\n description: 'Get contacts at this company',\n example: {\n resource: 'people',\n action: 'list',\n filter: { company_id: companyId },\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a time entry\n */\nexport function getTimeEntryHints(\n timeEntryId: string,\n taskId?: string,\n serviceId?: string,\n): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [],\n common_actions: [\n {\n action: 'Update this time entry',\n example: {\n resource: 'time',\n action: 'update',\n id: timeEntryId,\n time: 120,\n note: '<updated note>',\n },\n },\n ],\n };\n\n if (taskId) {\n hints.related_resources!.push({\n resource: 'tasks',\n description: 'Get the associated task',\n example: {\n resource: 'tasks',\n action: 'get',\n id: taskId,\n },\n });\n }\n\n if (serviceId) {\n hints.related_resources!.push({\n resource: 'services',\n description: 'Get the associated service',\n example: {\n resource: 'services',\n action: 'get',\n id: serviceId,\n },\n });\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a comment\n */\nexport function getCommentHints(\n _commentId: string,\n commentableType?: string,\n commentableId?: string,\n): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [],\n };\n\n if (commentableType && commentableId) {\n const resourceMap: Record<string, string> = {\n task: 'tasks',\n deal: 'deals',\n project: 'projects',\n company: 'companies',\n };\n\n const resource = resourceMap[commentableType];\n if (resource) {\n hints.related_resources!.push({\n resource,\n description: `Get the ${commentableType} this comment is on`,\n example: {\n resource,\n action: 'get',\n id: commentableId,\n },\n });\n }\n }\n\n return hints;\n}\n\n/**\n * Generate hints for an attachment\n */\nexport function getAttachmentHints(\n _attachmentId: string,\n attachableType?: string,\n): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [],\n common_actions: [\n {\n action: 'Delete this attachment',\n example: {\n resource: 'attachments',\n action: 'delete',\n id: _attachmentId,\n },\n },\n ],\n };\n\n if (attachableType) {\n const resourceMap: Record<string, string> = {\n Task: 'tasks',\n Comment: 'comments',\n Deal: 'deals',\n Page: 'projects',\n };\n\n const resource = resourceMap[attachableType];\n if (resource) {\n hints.related_resources!.push({\n resource,\n description: `View the ${attachableType.toLowerCase()} this attachment belongs to`,\n example: {\n resource,\n action: 'list',\n },\n });\n }\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a booking\n */\nexport function getBookingHints(bookingId: string, personId?: string): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [],\n common_actions: [\n {\n action: 'Update this booking',\n example: {\n resource: 'bookings',\n action: 'update',\n id: bookingId,\n time: 480,\n },\n },\n ],\n };\n\n if (personId) {\n hints.related_resources!.push({\n resource: 'people',\n description: 'Get the person this booking is for',\n example: {\n resource: 'people',\n action: 'get',\n id: personId,\n },\n });\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a page\n */\nexport function getPageHints(pageId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'discussions',\n description: 'Get discussions on this page',\n example: {\n resource: 'discussions',\n action: 'list',\n filter: { page_id: pageId },\n },\n },\n {\n resource: 'comments',\n description: 'Get comments on this page',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { page_id: pageId },\n },\n },\n {\n resource: 'pages',\n description: 'Get sub-pages of this page',\n example: {\n resource: 'pages',\n action: 'list',\n filter: { parent_page_id: pageId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Create a discussion',\n example: {\n resource: 'discussions',\n action: 'create',\n page_id: pageId,\n body: '<your discussion>',\n },\n },\n {\n action: 'Create a sub-page',\n example: {\n resource: 'pages',\n action: 'create',\n parent_page_id: pageId,\n title: '<sub-page title>',\n project_id: '<project_id>',\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a discussion\n */\nexport function getDiscussionHints(discussionId: string, pageId?: string): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [\n {\n resource: 'comments',\n description: 'Get comments on this discussion',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { discussion_id: discussionId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Resolve this discussion',\n example: {\n resource: 'discussions',\n action: 'resolve',\n id: discussionId,\n },\n },\n {\n action: 'Add a comment',\n example: {\n resource: 'comments',\n action: 'create',\n discussion_id: discussionId,\n body: '<your comment>',\n },\n },\n ],\n };\n\n if (pageId) {\n hints.related_resources!.push({\n resource: 'pages',\n description: 'Get the page this discussion is on',\n example: {\n resource: 'pages',\n action: 'get',\n id: pageId,\n },\n });\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a timer\n */\nexport function getTimerHints(timerId: string, serviceId?: string): ContextualHints {\n const hints: ContextualHints = {\n common_actions: [\n {\n action: 'Stop this timer',\n example: {\n resource: 'timers',\n action: 'stop',\n id: timerId,\n },\n },\n ],\n related_resources: [],\n };\n\n if (serviceId) {\n hints.related_resources!.push({\n resource: 'services',\n description: 'Get the service this timer is running on',\n example: {\n resource: 'services',\n action: 'get',\n id: serviceId,\n },\n });\n }\n\n return hints;\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 * Attachments MCP handler.\n */\n\nimport { listAttachments, getAttachment, deleteAttachment } from '@studiometa/productive-core';\n\nimport type { AttachmentArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatAttachment, formatListResponse } from '../formatters.js';\nimport { getAttachmentHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'delete'];\n\nexport async function handleAttachments(\n action: string,\n args: AttachmentArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, task_id, comment_id, deal_id } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await getAttachment({ id }, execCtx);\n const formatted = formatAttachment(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n const attachableType = result.data.attributes?.attachable_type as string | undefined;\n return jsonResult({\n ...formatted,\n _hints: getAttachmentHints(id, attachableType),\n });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'delete') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('delete'));\n await deleteAttachment({ id }, execCtx);\n return jsonResult({ success: true, deleted: id });\n }\n\n if (action === 'list') {\n const options: Record<string, string> = { ...filter };\n if (task_id) options.task_id = task_id;\n if (comment_id) options.comment_id = comment_id;\n if (deal_id) options.deal_id = deal_id;\n\n const result = await listAttachments({ page, perPage, additionalFilters: options }, execCtx);\n return jsonResult(\n formatListResponse(result.data, formatAttachment, result.meta, formatOptions),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'attachments', VALID_ACTIONS));\n}\n","/**\n * Bookings MCP handler.\n */\n\nimport {\n listBookings,\n getBooking,\n createBooking,\n updateBooking,\n} from '@studiometa/productive-core';\n\nimport type { BookingArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatBooking, formatListResponse } from '../formatters.js';\nimport { getBookingHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\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 { formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, person_id, service_id, event_id, started_on, ended_on, time, note } = args;\n const include = userInclude?.length\n ? [...new Set(['person', 'service', ...userInclude])]\n : ['person', 'service'];\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await getBooking({ id, include }, execCtx);\n const formatted = formatBooking(result.data, { ...formatOptions, included: result.included });\n\n if (ctx.includeHints !== false) {\n const personId = result.data.relationships?.person?.data?.id;\n return jsonResult({ ...formatted, _hints: getBookingHints(id, personId) });\n }\n return jsonResult(formatted);\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 createBooking(\n {\n personId: person_id,\n serviceId: service_id ?? '',\n startedOn: started_on,\n endedOn: ended_on,\n time,\n note,\n eventId: event_id,\n },\n execCtx,\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 result = await updateBooking(\n {\n id,\n startedOn: started_on,\n endedOn: ended_on,\n time,\n note,\n },\n execCtx,\n );\n return jsonResult({ success: true, ...formatBooking(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listBookings(\n { page, perPage, additionalFilters: filter, include },\n execCtx,\n );\n return jsonResult(formatListResponse(result.data, formatBooking, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'bookings', VALID_ACTIONS));\n}\n","/**\n * Budgets MCP handler.\n *\n * Thin adapter that delegates business logic to core executors\n * and handles MCP-specific concerns (hints, error formatting, JSON results).\n */\n\nimport { listBudgets, getBudget } from '@studiometa/productive-core';\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatBudget, formatListResponse } from '../formatters.js';\nimport { getBudgetHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get'];\n\nexport async function handleBudgets(\n action: string,\n args: CommonArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getBudget({ id }, execCtx);\n const formatted = formatBudget(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getBudgetHints(id) });\n }\n\n return jsonResult(formatted);\n }\n\n if (action === 'list') {\n const result = await listBudgets(\n {\n page,\n perPage,\n additionalFilters: filter,\n },\n execCtx,\n );\n\n return jsonResult(formatListResponse(result.data, formatBudget, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'budgets', VALID_ACTIONS));\n}\n","/**\n * Comments MCP handler.\n */\n\nimport {\n listComments,\n getComment,\n createComment,\n updateComment,\n} from '@studiometa/productive-core';\n\nimport type { CommentArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatComment, formatListResponse } from '../formatters.js';\nimport { getCommentHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\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 { formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, body, task_id, deal_id, company_id } = args;\n const include = userInclude?.length ? [...new Set(['creator', ...userInclude])] : ['creator'];\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await getComment({ id, include }, execCtx);\n const formatted = formatComment(result.data, { ...formatOptions, included: result.included });\n\n if (ctx.includeHints !== false) {\n const commentableType = result.data.attributes?.commentable_type as string | undefined;\n let commentableId: string | undefined;\n if (commentableType === 'task') {\n commentableId = result.data.relationships?.task?.data?.id;\n } else if (commentableType === 'deal') {\n commentableId = result.data.relationships?.deal?.data?.id;\n } else if (commentableType === 'company') {\n commentableId = result.data.relationships?.company?.data?.id;\n }\n return jsonResult({\n ...formatted,\n _hints: getCommentHints(id, commentableType, commentableId),\n });\n }\n return jsonResult(formatted);\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 createComment(\n { body, taskId: task_id, dealId: deal_id, companyId: company_id },\n execCtx,\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 updateComment({ id, body }, execCtx);\n return jsonResult({ success: true, ...formatComment(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listComments(\n { page, perPage, additionalFilters: filter, include },\n execCtx,\n );\n return jsonResult(formatListResponse(result.data, formatComment, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'comments', VALID_ACTIONS));\n}\n","/**\n * Resolve handler for MCP.\n *\n * Thin wrapper around core's resource resolver.\n * Provides handleResolve for the MCP 'resolve' action.\n */\n\nimport { resolveResource, ResolveError, type ResolveResult } from '@studiometa/productive-core';\n\nimport type { HandlerContext, ToolResult } from './types.js';\n\nimport { UserInputError } from '../errors.js';\nimport { errorResult, inputErrorResult, jsonResult } from './utils.js';\n\n// Re-export types used by MCP handlers\nexport type { ResolvableResourceType, ResolveResult } from '@studiometa/productive-core';\n\n/**\n * Arguments for resolve action\n */\ninterface ResolveArgs {\n query?: string;\n type?: 'person' | 'project' | 'company' | 'deal' | 'service';\n project_id?: string;\n}\n\n/**\n * Handle resolve action for a resource.\n *\n * Delegates to core's resolveResource function and wraps\n * errors in MCP-friendly format.\n */\nexport async function handleResolve(args: ResolveArgs, ctx: HandlerContext): Promise<ToolResult> {\n const { query, type, project_id } = args;\n\n if (!query) {\n return errorResult('query is required for resolve action');\n }\n\n try {\n const execCtx = ctx.executor();\n const results: ResolveResult[] = await resolveResource(execCtx.api, query, {\n type,\n projectId: project_id,\n });\n\n return jsonResult({\n query,\n matches: results,\n exact: results.length === 1 && results[0].exact,\n });\n } catch (error) {\n if (error instanceof ResolveError) {\n return inputErrorResult(\n new UserInputError(error.message, [\n `Query: \"${error.query}\"`,\n ...(error.type ? [`Type: ${error.type}`] : []),\n ]),\n );\n }\n throw error;\n }\n}\n","/**\n * Companies MCP handler.\n */\n\nimport {\n listCompanies,\n getCompany,\n createCompany,\n updateCompany,\n} from '@studiometa/productive-core';\n\nimport type { CompanyArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatCompany } from '../formatters.js';\nimport { getCompanyHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'resolve'];\n\nexport async function handleCompanies(\n action: string,\n args: CompanyArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, name, query, type } = args;\n\n if (action === 'resolve') {\n return handleResolve({ query, type }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getCompany({ id }, execCtx);\n const formatted = formatCompany(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getCompanyHints(id) });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'create') {\n if (!name) return inputErrorResult(ErrorMessages.missingRequiredFields('company', ['name']));\n\n const result = await createCompany({ name }, execCtx);\n return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n\n const result = await updateCompany({ id, name }, execCtx);\n return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listCompanies({ page, perPage, additionalFilters: filter }, execCtx);\n\n const response = formatListResponse(result.data, formatCompany, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'companies', VALID_ACTIONS));\n}\n","/**\n * Deals MCP handler.\n */\n\nimport { listDeals, getDeal, createDeal, updateDeal } from '@studiometa/productive-core';\n\nimport type { DealArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatDeal, formatListResponse } from '../formatters.js';\nimport { getDealHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'resolve'];\n\nexport async function handleDeals(\n action: string,\n args: DealArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, name, company_id, query, type } = args;\n\n if (action === 'resolve') {\n return handleResolve({ query, type }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const getInclude = userInclude?.length\n ? [...new Set(['company', 'deal_status', 'responsible', ...userInclude])]\n : ['company', 'deal_status', 'responsible'];\n const result = await getDeal({ id, include: getInclude }, execCtx);\n const formatted = formatDeal(result.data, { ...formatOptions, included: result.included });\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getDealHints(id) });\n }\n return jsonResult(formatted);\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 createDeal({ name, companyId: company_id }, execCtx);\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 result = await updateDeal({ id, name }, execCtx);\n return jsonResult({ success: true, ...formatDeal(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const listInclude = userInclude?.length\n ? [...new Set(['company', 'deal_status', ...userInclude])]\n : ['company', 'deal_status'];\n const result = await listDeals(\n { page, perPage, additionalFilters: filter, include: listInclude },\n execCtx,\n );\n\n const response = formatListResponse(result.data, formatDeal, result.meta, {\n ...formatOptions,\n included: result.included,\n });\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'deals', VALID_ACTIONS));\n}\n","/**\n * Discussions MCP handler.\n */\n\nimport {\n listDiscussions,\n getDiscussion,\n createDiscussion,\n updateDiscussion,\n deleteDiscussion,\n resolveDiscussion,\n reopenDiscussion,\n} from '@studiometa/productive-core';\n\nimport type { HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatDiscussion } from '../formatters.js';\nimport { getDiscussionHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nexport interface DiscussionArgs {\n id?: string;\n title?: string;\n body?: string;\n page_id?: string;\n status?: string;\n}\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'delete', 'resolve', 'reopen'];\n\nexport async function handleDiscussions(\n action: string,\n args: DiscussionArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, title, body, page_id, status } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getDiscussion({ id }, execCtx);\n const formatted = formatDiscussion(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getDiscussionHints(id, page_id) });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'create') {\n if (!body || !page_id) {\n return inputErrorResult(\n ErrorMessages.missingRequiredFields('discussion', ['body', 'page_id']),\n );\n }\n const result = await createDiscussion(\n {\n body,\n pageId: page_id,\n title,\n },\n execCtx,\n );\n return jsonResult({ success: true, ...formatDiscussion(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const result = await updateDiscussion({ id, title, body }, execCtx);\n return jsonResult({ success: true, ...formatDiscussion(result.data, formatOptions) });\n }\n\n if (action === 'delete') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('delete'));\n await deleteDiscussion({ id }, execCtx);\n return jsonResult({ success: true, deleted: id });\n }\n\n if (action === 'resolve') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('resolve'));\n const result = await resolveDiscussion({ id }, execCtx);\n return jsonResult({ success: true, ...formatDiscussion(result.data, formatOptions) });\n }\n\n if (action === 'reopen') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('reopen'));\n const result = await reopenDiscussion({ id }, execCtx);\n return jsonResult({ success: true, ...formatDiscussion(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const listOptions: {\n page?: number;\n perPage?: number;\n additionalFilters?: Record<string, string>;\n status?: string;\n } = {\n page,\n perPage,\n additionalFilters: filter,\n };\n if (status) listOptions.status = status;\n\n const result = await listDiscussions(listOptions, execCtx);\n\n const response = formatListResponse(result.data, formatDiscussion, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'discussions', 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 attachments: {\n description: 'File attachments on tasks, comments, deals, and pages',\n actions: {\n list: 'List attachments with optional filters',\n get: 'Get a single attachment by ID',\n delete: 'Delete an attachment by ID',\n },\n filters: {\n task_id: 'Filter by task',\n comment_id: 'Filter by comment',\n deal_id: 'Filter by deal',\n page_id: 'Filter by page',\n },\n fields: {\n id: 'Unique attachment identifier',\n name: 'File name',\n content_type: 'MIME type (e.g., image/png, application/pdf)',\n size: 'File size in bytes',\n size_human: 'Human-readable file size (e.g., 1.5 MB)',\n url: 'Download URL',\n attachable_type: 'Parent resource type (Task, Comment, Deal, Page)',\n },\n examples: [\n {\n description: 'List attachments on a task',\n params: { resource: 'attachments', action: 'list', filter: { task_id: '12345' } },\n },\n {\n description: 'Get attachment details',\n params: { resource: 'attachments', action: 'get', id: '67890' },\n },\n {\n description: 'Delete an attachment',\n params: { resource: 'attachments', action: 'delete', id: '67890' },\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 budgets: {\n description: 'Budget tracking and financial overview',\n actions: {\n list: 'List budgets with optional filters',\n get: 'Get a single budget by ID with full details',\n },\n filters: {\n project_id: 'Filter by project',\n company_id: 'Filter by company',\n deal_id: 'Filter by deal',\n billable: 'Filter by billable status (true/false)',\n budget_type: 'Filter by budget type',\n },\n fields: {\n id: 'Unique budget identifier',\n name: 'Budget name',\n budget_type: 'Type of budget',\n billable: 'Whether the budget is billable',\n started_on: 'Budget start date (YYYY-MM-DD)',\n ended_on: 'Budget end date (YYYY-MM-DD)',\n currency: 'Budget currency code',\n total_time_budget: 'Total time budget in minutes',\n remaining_time_budget: 'Remaining time budget in minutes',\n total_monetary_budget: 'Total monetary budget',\n remaining_monetary_budget: 'Remaining monetary budget',\n },\n examples: [\n {\n description: 'List all budgets',\n params: { resource: 'budgets', action: 'list' },\n },\n {\n description: 'List budgets for a project',\n params: { resource: 'budgets', action: 'list', filter: { project_id: '12345' } },\n },\n {\n description: 'Get budget details',\n params: { resource: 'budgets', action: 'get', id: '67890' },\n },\n {\n description: 'List billable budgets',\n params: { resource: 'budgets', action: 'list', filter: { billable: 'true' } },\n },\n ],\n },\n\n pages: {\n description: 'Manage pages (wiki/docs) within projects',\n actions: {\n list: 'List pages with optional filters',\n get: 'Get a single page by ID with full details',\n create: 'Create a new page (requires title, project_id)',\n update: 'Update an existing page',\n delete: 'Delete a page',\n },\n filters: {\n project_id: 'Filter by project',\n creator_id: 'Filter by creator',\n parent_page_id: 'Filter by parent page (for sub-pages)',\n },\n fields: {\n id: 'Unique page identifier',\n title: 'Page title',\n body: 'Page body content (HTML)',\n public: 'Whether the page is publicly accessible',\n version_number: 'Current version number',\n parent_page_id: 'Parent page ID (for sub-pages)',\n },\n examples: [\n {\n description: 'List pages for a project',\n params: { resource: 'pages', action: 'list', filter: { project_id: '12345' } },\n },\n {\n description: 'Get page details',\n params: { resource: 'pages', action: 'get', id: '67890' },\n },\n {\n description: 'Create a page',\n params: {\n resource: 'pages',\n action: 'create',\n title: 'Getting Started',\n project_id: '12345',\n },\n },\n {\n description: 'Create a sub-page',\n params: {\n resource: 'pages',\n action: 'create',\n title: 'Sub-section',\n project_id: '12345',\n parent_page_id: '67890',\n },\n },\n {\n description: 'Delete a page',\n params: { resource: 'pages', action: 'delete', id: '67890' },\n },\n ],\n },\n\n discussions: {\n description: 'Manage discussions (comment threads on highlighted page content)',\n actions: {\n list: 'List discussions with optional filters',\n get: 'Get a single discussion by ID',\n create: 'Create a new discussion (requires body, page_id)',\n update: 'Update an existing discussion',\n delete: 'Delete a discussion',\n resolve: 'Resolve a discussion (mark as resolved)',\n reopen: 'Reopen a resolved discussion',\n },\n filters: {\n page_id: 'Filter by page',\n status: 'Filter by status: 1=active, 2=resolved',\n },\n fields: {\n id: 'Unique discussion identifier',\n title: 'Discussion title',\n body: 'Discussion body (HTML)',\n status: 'Status: active or resolved',\n resolved_at: 'When the discussion was resolved',\n },\n examples: [\n {\n description: 'List discussions on a page',\n params: { resource: 'discussions', action: 'list', filter: { page_id: '12345' } },\n },\n {\n description: 'List active discussions',\n params: { resource: 'discussions', action: 'list', status: 'active' },\n },\n {\n description: 'Create a discussion',\n params: {\n resource: 'discussions',\n action: 'create',\n page_id: '12345',\n body: 'Review this section',\n },\n },\n {\n description: 'Resolve a discussion',\n params: { resource: 'discussions', action: 'resolve', id: '67890' },\n },\n {\n description: 'Reopen a discussion',\n params: { resource: 'discussions', action: 'reopen', id: '67890' },\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 * Pages MCP handler.\n */\n\nimport {\n listPages,\n getPage,\n createPage,\n updatePage,\n deletePage,\n} from '@studiometa/productive-core';\n\nimport type { HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatPage } from '../formatters.js';\nimport { getPageHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nexport interface PageArgs {\n id?: string;\n title?: string;\n body?: string;\n project_id?: string;\n parent_page_id?: string;\n}\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'delete'];\n\nexport async function handlePages(\n action: string,\n args: PageArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, title, body, project_id, parent_page_id } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getPage({ id }, execCtx);\n const formatted = formatPage(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getPageHints(id) });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'create') {\n if (!title || !project_id) {\n return inputErrorResult(ErrorMessages.missingRequiredFields('page', ['title', 'project_id']));\n }\n const result = await createPage(\n {\n title,\n projectId: project_id,\n body,\n parentPageId: parent_page_id,\n },\n execCtx,\n );\n return jsonResult({ success: true, ...formatPage(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const result = await updatePage({ id, title, body }, execCtx);\n return jsonResult({ success: true, ...formatPage(result.data, formatOptions) });\n }\n\n if (action === 'delete') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('delete'));\n await deletePage({ id }, execCtx);\n return jsonResult({ success: true, deleted: id });\n }\n\n if (action === 'list') {\n const result = await listPages({ page, perPage, additionalFilters: filter }, execCtx);\n\n const response = formatListResponse(result.data, formatPage, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'pages', VALID_ACTIONS));\n}\n","/**\n * People MCP handler.\n */\n\nimport { listPeople, getPerson } from '@studiometa/productive-core';\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 { getPersonHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'me', 'resolve'];\n\nexport async function handlePeople(\n action: string,\n args: CommonArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n credentials: ProductiveCredentials,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, query, type } = args;\n\n if (action === 'resolve') {\n return handleResolve({ query, type }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getPerson({ id }, execCtx);\n const formatted = formatPerson(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getPersonHints(id) });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'me') {\n if (credentials.userId) {\n const result = await getPerson({ id: credentials.userId }, execCtx);\n const formatted = formatPerson(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getPersonHints(credentials.userId) });\n }\n return jsonResult(formatted);\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 listPeople({ page, perPage, additionalFilters: filter }, execCtx);\n\n const response = formatListResponse(result.data, formatPerson, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'people', VALID_ACTIONS));\n}\n","/**\n * Projects MCP handler.\n */\n\nimport { listProjects, getProject } from '@studiometa/productive-core';\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatProject } from '../formatters.js';\nimport { getProjectHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'resolve'];\n\nexport async function handleProjects(\n action: string,\n args: CommonArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, query, type } = args;\n\n if (action === 'resolve') {\n return handleResolve({ query, type }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getProject({ id }, execCtx);\n const formatted = formatProject(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({\n ...formatted,\n _hints: getProjectHints(id),\n });\n }\n\n return jsonResult(formatted);\n }\n\n if (action === 'list') {\n const result = await listProjects({ page, perPage, additionalFilters: filter }, execCtx);\n\n const response = formatListResponse(result.data, formatProject, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'projects', VALID_ACTIONS));\n}\n","/**\n * Reports MCP handler.\n */\n\nimport { getReport, VALID_REPORT_TYPES, type ReportType } from '@studiometa/productive-core';\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\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\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\nconst VALID_ACTIONS = ['get'];\n\nexport async function handleReports(\n action: string,\n args: ReportArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { 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 as ReportType)) {\n return inputErrorResult(ErrorMessages.invalidReportType(report_type, [...VALID_REPORT_TYPES]));\n }\n\n const execCtx = ctx.executor();\n\n const result = await getReport(\n {\n reportType: report_type as ReportType,\n page,\n perPage,\n group,\n from,\n to,\n personId: person_id,\n projectId: project_id,\n companyId: company_id,\n dealId: deal_id,\n status,\n additionalFilters: filter,\n },\n execCtx,\n );\n\n const formattedData = formatReportData(result.data);\n\n return jsonResult({\n data: formattedData,\n meta: result.meta,\n });\n}\n","/**\n * Services MCP handler.\n */\n\nimport { listServices } from '@studiometa/productive-core';\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 { formatOptions, filter, page, perPage } = ctx;\n\n if (action === 'list') {\n const execCtx = ctx.executor();\n const result = await listServices({ page, perPage, additionalFilters: filter }, execCtx);\n\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 MCP handler.\n */\n\nimport { listTasks, getTask, createTask, updateTask } from '@studiometa/productive-core';\n\nimport type { HandlerContext, TaskArgs, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTask } from '../formatters.js';\nimport { getTaskHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst DEFAULT_TASK_INCLUDE = ['project', 'project.company'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'resolve'];\n\nexport async function handleTasks(\n action: string,\n args: TaskArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, title, project_id, task_list_id, description, assignee_id, query, type } = args;\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_TASK_INCLUDE, ...userInclude])]\n : DEFAULT_TASK_INCLUDE;\n\n if (action === 'resolve') {\n return handleResolve({ query, type, project_id }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getTask({ id, include }, execCtx);\n const formatted = formatTask(result.data, { ...formatOptions, included: result.included });\n\n if (ctx.includeHints !== false) {\n const serviceId = result.data.relationships?.service?.data?.id;\n return jsonResult({ ...formatted, _hints: getTaskHints(id, serviceId) });\n }\n return jsonResult(formatted);\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 createTask(\n {\n title,\n projectId: project_id,\n taskListId: task_list_id,\n assigneeId: assignee_id,\n description,\n },\n execCtx,\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 result = await updateTask(\n {\n id,\n title,\n description,\n assigneeId: assignee_id,\n },\n execCtx,\n );\n return jsonResult({ success: true, ...formatTask(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listTasks({ page, perPage, additionalFilters: filter, include }, execCtx);\n\n const response = formatListResponse(result.data, formatTask, result.meta, {\n ...formatOptions,\n included: result.included,\n });\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'tasks', VALID_ACTIONS));\n}\n","/**\n * Time entries MCP handler.\n *\n * Thin adapter that delegates business logic to core executors\n * and handles MCP-specific concerns (hints, error formatting, JSON results).\n */\n\nimport {\n listTimeEntries,\n getTimeEntry,\n createTimeEntry,\n updateTimeEntry,\n} from '@studiometa/productive-core';\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTimeEntry } from '../formatters.js';\nimport { getTimeEntryHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'resolve'];\n\nexport async function handleTime(\n action: string,\n args: CommonArgs & { query?: string; type?: ResolvableResourceType; project_id?: string },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, person_id, service_id, task_id, time, date, note, query, type, project_id } = args;\n\n // Handle resolve action (MCP-specific, no executor equivalent)\n if (action === 'resolve') {\n return handleResolve({ query, type, project_id }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getTimeEntry({ id }, execCtx);\n const formatted = formatTimeEntry(result.data, formatOptions);\n\n // Add contextual hints unless disabled (MCP-specific)\n if (ctx.includeHints !== false) {\n const serviceId = result.data.relationships?.service?.data?.id;\n return jsonResult({\n ...formatted,\n _hints: getTimeEntryHints(id, undefined, serviceId),\n });\n }\n\n return jsonResult(formatted);\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\n const result = await createTimeEntry(\n {\n personId: person_id,\n serviceId: service_id,\n time,\n date,\n note: note ?? undefined,\n taskId: task_id,\n projectId: project_id,\n },\n execCtx,\n );\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\n const result = await updateTimeEntry(\n {\n id,\n time: time ?? undefined,\n date: date ?? undefined,\n note: note ?? undefined,\n },\n execCtx,\n );\n\n return jsonResult({ success: true, ...formatTimeEntry(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listTimeEntries(\n {\n page,\n perPage,\n additionalFilters: filter,\n },\n execCtx,\n );\n\n const response = formatListResponse(result.data, formatTimeEntry, result.meta, formatOptions);\n\n // Include resolution metadata if any resolutions occurred\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'time', VALID_ACTIONS));\n}\n","/**\n * Timers MCP handler.\n */\n\nimport { listTimers, getTimer, startTimer, stopTimer } from '@studiometa/productive-core';\n\nimport type { HandlerContext, TimerArgs, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTimer } from '../formatters.js';\nimport { getTimerHints } from '../hints.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 { formatOptions, filter, page, perPage, include } = ctx;\n const { id, service_id, time_entry_id } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await getTimer({ id, include }, execCtx);\n const formatted = formatTimer(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getTimerHints(id) });\n }\n return jsonResult(formatted);\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 startTimer({ serviceId: service_id, timeEntryId: time_entry_id }, execCtx);\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 stopTimer({ id }, execCtx);\n return jsonResult({ success: true, ...formatTimer(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listTimers({ page, perPage, additionalFilters: filter, include }, execCtx);\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-api';\nimport { fromHandlerContext } from '@studiometa/productive-core';\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 { handleAttachments } from './attachments.js';\nimport { handleBookings } from './bookings.js';\nimport { handleBudgets } from './budgets.js';\nimport { handleComments } from './comments.js';\nimport { handleCompanies } from './companies.js';\nimport { handleDeals } from './deals.js';\nimport { handleDiscussions } from './discussions.js';\nimport { handleHelp, handleHelpOverview } from './help.js';\nimport { handlePages } from './pages.js';\nimport { handlePeople } from './people.js';\n// Resource handlers\nimport { handleProjects } from './projects.js';\nimport { handleReports } from './reports.js';\nimport { type ResolvableResourceType } from './resolve.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 'attachments',\n 'timers',\n 'deals',\n 'bookings',\n 'budgets',\n 'pages',\n 'discussions',\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 // Attachment fields\n comment_id?: string;\n // Timer fields\n time_entry_id?: string;\n // Page fields\n parent_page_id?: string;\n page_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 config: {\n apiToken: credentials.apiToken,\n organizationId: credentials.organizationId,\n userId: credentials.userId,\n },\n });\n\n // Handle the single consolidated tool\n if (name !== 'productive') {\n return errorResult(`Unknown tool: ${name}`);\n }\n\n const {\n resource,\n action,\n filter,\n page,\n per_page,\n compact,\n include,\n query,\n no_hints,\n type,\n ...restArgs\n } = args as unknown as ProductiveArgs & { no_hints?: boolean; type?: ResolvableResourceType };\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 // Hints are included by default for 'get' action, disabled for 'list' or when compact\n // Can be explicitly disabled with no_hints: true\n const includeHints = no_hints !== true && action === 'get' && !isCompact;\n\n // Build handler context — api is not exposed directly.\n // Handlers access executors via ctx.executor() which creates an ExecutorContext.\n const execCtx = fromHandlerContext({ api });\n const ctx: HandlerContext = {\n formatOptions,\n filter: stringFilter,\n page,\n perPage,\n include,\n includeHints,\n executor: () => execCtx,\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 // Note: query and type are passed explicitly for resolve action support\n const resolveArgs = { query, type };\n switch (resource) {\n case 'projects':\n return await handleProjects(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'time':\n return await handleTime(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'tasks':\n return await handleTasks(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'services':\n return await handleServices(action, restArgs, ctx);\n\n case 'people':\n return await handlePeople(action, { ...restArgs, ...resolveArgs }, ctx, credentials);\n\n case 'companies':\n return await handleCompanies(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'comments':\n return await handleComments(action, restArgs, ctx);\n\n case 'attachments':\n return await handleAttachments(action, restArgs, ctx);\n\n case 'timers':\n return await handleTimers(action, restArgs, ctx);\n\n case 'deals':\n return await handleDeals(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'bookings':\n return await handleBookings(action, restArgs, ctx);\n\n case 'budgets':\n return await handleBudgets(action, restArgs, ctx);\n case 'pages':\n return await handlePages(action, restArgs, ctx);\n\n case 'discussions':\n return await handleDiscussions(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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"handlers-D4tRd30c.js","names":[],"sources":["../src/errors.ts","../src/formatters.ts","../src/hints.ts","../src/handlers/utils.ts","../src/handlers/attachments.ts","../src/handlers/bookings.ts","../src/handlers/budgets.ts","../src/handlers/comments.ts","../src/handlers/resolve.ts","../src/handlers/companies.ts","../src/handlers/deals.ts","../src/handlers/discussions.ts","../src/handlers/help.ts","../src/handlers/pages.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-api\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 formatBudget as cliFormatBudget,\n formatCompany as cliFormatCompany,\n formatComment as cliFormatComment,\n formatTimer as cliFormatTimer,\n formatDeal as cliFormatDeal,\n formatBooking as cliFormatBooking,\n formatAttachment as cliFormatAttachment,\n formatPage as cliFormatPage,\n formatDiscussion as cliFormatDiscussion,\n formatListResponse as cliFormatListResponse,\n type JsonApiResource,\n type JsonApiMeta,\n type FormatOptions,\n type FormattedPagination,\n} from '@studiometa/productive-api';\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 budget for agent consumption\n */\nexport function formatBudget(\n budget: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatBudget(budget, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['budget_type', 'currency']);\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 attachment for agent consumption\n */\nexport function formatAttachment(\n attachment: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatAttachment(attachment, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['url']);\n }\n return result;\n}\n\n/**\n * Format page for agent consumption\n */\nexport function formatPage(\n page: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatPage(page, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['body', 'version_number']);\n }\n return result;\n}\n\n/**\n * Format discussion for agent consumption\n */\nexport function formatDiscussion(\n discussion: JsonApiResource,\n options?: McpFormatOptions,\n): Record<string, unknown> {\n const result = cliFormatDiscussion(discussion, MCP_FORMAT_OPTIONS);\n if (options?.compact) {\n return compactify(result, ['body']);\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 * Contextual hints for AI agents\n *\n * Provides suggestions for related resources and common actions\n * to help agents discover how to fetch additional context.\n */\n\nexport interface ResourceHint {\n resource: string;\n description: string;\n example: Record<string, unknown>;\n}\n\nexport interface ActionHint {\n action: string;\n example: Record<string, unknown>;\n}\n\nexport interface ContextualHints {\n related_resources?: ResourceHint[];\n common_actions?: ActionHint[];\n}\n\n/**\n * Generate hints for a task\n */\nexport function getTaskHints(taskId: string, serviceId?: string): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [\n {\n resource: 'comments',\n description: 'Get comments on this task',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { task_id: taskId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries logged on this task',\n example: {\n resource: 'time',\n action: 'list',\n filter: { task_id: taskId },\n },\n },\n {\n resource: 'tasks',\n description: 'Get subtasks of this task',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { parent_task_id: taskId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Add a comment',\n example: {\n resource: 'comments',\n action: 'create',\n task_id: taskId,\n body: '<your comment>',\n },\n },\n ],\n };\n\n // Add time logging hint if we have a service ID\n if (serviceId) {\n hints.common_actions!.push({\n action: 'Log time on this task',\n example: {\n resource: 'time',\n action: 'create',\n service_id: serviceId,\n task_id: taskId,\n date: new Date().toISOString().split('T')[0],\n time: 60,\n note: '<description of work>',\n },\n });\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a project\n */\nexport function getProjectHints(projectId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'tasks',\n description: 'Get tasks in this project',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n {\n resource: 'services',\n description: 'Get services (budget lines) for this project',\n example: {\n resource: 'services',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries for this project',\n example: {\n resource: 'time',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n {\n resource: 'comments',\n description: 'Get comments on this project',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n {\n resource: 'deals',\n description: 'Get deals/budgets for this project',\n example: {\n resource: 'deals',\n action: 'list',\n filter: { project_id: projectId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Create a task',\n example: {\n resource: 'tasks',\n action: 'create',\n project_id: projectId,\n task_list_id: '<task_list_id>',\n title: '<task title>',\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a deal/budget\n */\nexport function getDealHints(dealId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'comments',\n description: 'Get comments on this deal/budget',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { deal_id: dealId },\n },\n },\n {\n resource: 'services',\n description: 'Get services (budget lines) for this deal',\n example: {\n resource: 'services',\n action: 'list',\n filter: { deal_id: dealId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries for this deal/budget',\n example: {\n resource: 'time',\n action: 'list',\n filter: { deal_id: dealId },\n },\n },\n {\n resource: 'bookings',\n description: 'Get resource bookings for this deal',\n example: {\n resource: 'bookings',\n action: 'list',\n filter: { deal_id: dealId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Add a comment',\n example: {\n resource: 'comments',\n action: 'create',\n deal_id: dealId,\n body: '<your comment>',\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a budget\n */\nexport function getBudgetHints(budgetId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'services',\n description: 'Get services (budget lines) for this budget',\n example: {\n resource: 'services',\n action: 'list',\n filter: { budget_id: budgetId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries for this budget',\n example: {\n resource: 'time',\n action: 'list',\n filter: { budget_id: budgetId },\n },\n },\n {\n resource: 'bookings',\n description: 'Get bookings for this budget',\n example: {\n resource: 'bookings',\n action: 'list',\n filter: { budget_id: budgetId },\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a person\n */\nexport function getPersonHints(personId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'tasks',\n description: 'Get tasks assigned to this person',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { assignee_id: personId },\n },\n },\n {\n resource: 'time',\n description: 'Get time entries by this person',\n example: {\n resource: 'time',\n action: 'list',\n filter: { person_id: personId },\n },\n },\n {\n resource: 'bookings',\n description: 'Get bookings for this person',\n example: {\n resource: 'bookings',\n action: 'list',\n filter: { person_id: personId },\n },\n },\n {\n resource: 'timers',\n description: 'Get active timers for this person',\n example: {\n resource: 'timers',\n action: 'list',\n filter: { person_id: personId },\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a service\n */\nexport function getServiceHints(serviceId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'time',\n description: 'Get time entries for this service',\n example: {\n resource: 'time',\n action: 'list',\n filter: { service_id: serviceId },\n },\n },\n {\n resource: 'tasks',\n description: 'Get tasks linked to this service',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { service_id: serviceId },\n },\n },\n {\n resource: 'bookings',\n description: 'Get bookings for this service',\n example: {\n resource: 'bookings',\n action: 'list',\n filter: { service_id: serviceId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Log time on this service',\n example: {\n resource: 'time',\n action: 'create',\n service_id: serviceId,\n date: new Date().toISOString().split('T')[0],\n time: 60,\n note: '<description of work>',\n },\n },\n {\n action: 'Start a timer',\n example: {\n resource: 'timers',\n action: 'start',\n service_id: serviceId,\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a company\n */\nexport function getCompanyHints(companyId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'projects',\n description: 'Get projects for this company',\n example: {\n resource: 'projects',\n action: 'list',\n filter: { company_id: companyId },\n },\n },\n {\n resource: 'deals',\n description: 'Get deals for this company',\n example: {\n resource: 'deals',\n action: 'list',\n filter: { company_id: companyId },\n },\n },\n {\n resource: 'tasks',\n description: 'Get tasks for this company',\n example: {\n resource: 'tasks',\n action: 'list',\n filter: { company_id: companyId },\n },\n },\n {\n resource: 'people',\n description: 'Get contacts at this company',\n example: {\n resource: 'people',\n action: 'list',\n filter: { company_id: companyId },\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a time entry\n */\nexport function getTimeEntryHints(\n timeEntryId: string,\n taskId?: string,\n serviceId?: string,\n): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [],\n common_actions: [\n {\n action: 'Update this time entry',\n example: {\n resource: 'time',\n action: 'update',\n id: timeEntryId,\n time: 120,\n note: '<updated note>',\n },\n },\n ],\n };\n\n if (taskId) {\n hints.related_resources!.push({\n resource: 'tasks',\n description: 'Get the associated task',\n example: {\n resource: 'tasks',\n action: 'get',\n id: taskId,\n },\n });\n }\n\n if (serviceId) {\n hints.related_resources!.push({\n resource: 'services',\n description: 'Get the associated service',\n example: {\n resource: 'services',\n action: 'get',\n id: serviceId,\n },\n });\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a comment\n */\nexport function getCommentHints(\n _commentId: string,\n commentableType?: string,\n commentableId?: string,\n): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [],\n };\n\n if (commentableType && commentableId) {\n const resourceMap: Record<string, string> = {\n task: 'tasks',\n deal: 'deals',\n project: 'projects',\n company: 'companies',\n };\n\n const resource = resourceMap[commentableType];\n if (resource) {\n hints.related_resources!.push({\n resource,\n description: `Get the ${commentableType} this comment is on`,\n example: {\n resource,\n action: 'get',\n id: commentableId,\n },\n });\n }\n }\n\n return hints;\n}\n\n/**\n * Generate hints for an attachment\n */\nexport function getAttachmentHints(\n _attachmentId: string,\n attachableType?: string,\n): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [],\n common_actions: [\n {\n action: 'Delete this attachment',\n example: {\n resource: 'attachments',\n action: 'delete',\n id: _attachmentId,\n },\n },\n ],\n };\n\n if (attachableType) {\n const resourceMap: Record<string, string> = {\n Task: 'tasks',\n Comment: 'comments',\n Deal: 'deals',\n Page: 'projects',\n };\n\n const resource = resourceMap[attachableType];\n if (resource) {\n hints.related_resources!.push({\n resource,\n description: `View the ${attachableType.toLowerCase()} this attachment belongs to`,\n example: {\n resource,\n action: 'list',\n },\n });\n }\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a booking\n */\nexport function getBookingHints(bookingId: string, personId?: string): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [],\n common_actions: [\n {\n action: 'Update this booking',\n example: {\n resource: 'bookings',\n action: 'update',\n id: bookingId,\n time: 480,\n },\n },\n ],\n };\n\n if (personId) {\n hints.related_resources!.push({\n resource: 'people',\n description: 'Get the person this booking is for',\n example: {\n resource: 'people',\n action: 'get',\n id: personId,\n },\n });\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a page\n */\nexport function getPageHints(pageId: string): ContextualHints {\n return {\n related_resources: [\n {\n resource: 'discussions',\n description: 'Get discussions on this page',\n example: {\n resource: 'discussions',\n action: 'list',\n filter: { page_id: pageId },\n },\n },\n {\n resource: 'comments',\n description: 'Get comments on this page',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { page_id: pageId },\n },\n },\n {\n resource: 'pages',\n description: 'Get sub-pages of this page',\n example: {\n resource: 'pages',\n action: 'list',\n filter: { parent_page_id: pageId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Create a discussion',\n example: {\n resource: 'discussions',\n action: 'create',\n page_id: pageId,\n body: '<your discussion>',\n },\n },\n {\n action: 'Create a sub-page',\n example: {\n resource: 'pages',\n action: 'create',\n parent_page_id: pageId,\n title: '<sub-page title>',\n project_id: '<project_id>',\n },\n },\n ],\n };\n}\n\n/**\n * Generate hints for a discussion\n */\nexport function getDiscussionHints(discussionId: string, pageId?: string): ContextualHints {\n const hints: ContextualHints = {\n related_resources: [\n {\n resource: 'comments',\n description: 'Get comments on this discussion',\n example: {\n resource: 'comments',\n action: 'list',\n filter: { discussion_id: discussionId },\n },\n },\n ],\n common_actions: [\n {\n action: 'Resolve this discussion',\n example: {\n resource: 'discussions',\n action: 'resolve',\n id: discussionId,\n },\n },\n {\n action: 'Add a comment',\n example: {\n resource: 'comments',\n action: 'create',\n discussion_id: discussionId,\n body: '<your comment>',\n },\n },\n ],\n };\n\n if (pageId) {\n hints.related_resources!.push({\n resource: 'pages',\n description: 'Get the page this discussion is on',\n example: {\n resource: 'pages',\n action: 'get',\n id: pageId,\n },\n });\n }\n\n return hints;\n}\n\n/**\n * Generate hints for a timer\n */\nexport function getTimerHints(timerId: string, serviceId?: string): ContextualHints {\n const hints: ContextualHints = {\n common_actions: [\n {\n action: 'Stop this timer',\n example: {\n resource: 'timers',\n action: 'stop',\n id: timerId,\n },\n },\n ],\n related_resources: [],\n };\n\n if (serviceId) {\n hints.related_resources!.push({\n resource: 'services',\n description: 'Get the service this timer is running on',\n example: {\n resource: 'services',\n action: 'get',\n id: serviceId,\n },\n });\n }\n\n return hints;\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 * Attachments MCP handler.\n */\n\nimport { listAttachments, getAttachment, deleteAttachment } from '@studiometa/productive-core';\n\nimport type { AttachmentArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatAttachment, formatListResponse } from '../formatters.js';\nimport { getAttachmentHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'delete'];\n\nexport async function handleAttachments(\n action: string,\n args: AttachmentArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, task_id, comment_id, deal_id } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await getAttachment({ id }, execCtx);\n const formatted = formatAttachment(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n const attachableType = result.data.attributes?.attachable_type as string | undefined;\n return jsonResult({\n ...formatted,\n _hints: getAttachmentHints(id, attachableType),\n });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'delete') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('delete'));\n await deleteAttachment({ id }, execCtx);\n return jsonResult({ success: true, deleted: id });\n }\n\n if (action === 'list') {\n const options: Record<string, string> = { ...filter };\n if (task_id) options.task_id = task_id;\n if (comment_id) options.comment_id = comment_id;\n if (deal_id) options.deal_id = deal_id;\n\n const result = await listAttachments({ page, perPage, additionalFilters: options }, execCtx);\n return jsonResult(\n formatListResponse(result.data, formatAttachment, result.meta, formatOptions),\n );\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'attachments', VALID_ACTIONS));\n}\n","/**\n * Bookings MCP handler.\n */\n\nimport {\n listBookings,\n getBooking,\n createBooking,\n updateBooking,\n} from '@studiometa/productive-core';\n\nimport type { BookingArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatBooking, formatListResponse } from '../formatters.js';\nimport { getBookingHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\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 { formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, person_id, service_id, event_id, started_on, ended_on, time, note } = args;\n const include = userInclude?.length\n ? [...new Set(['person', 'service', ...userInclude])]\n : ['person', 'service'];\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await getBooking({ id, include }, execCtx);\n const formatted = formatBooking(result.data, { ...formatOptions, included: result.included });\n\n if (ctx.includeHints !== false) {\n const personId = result.data.relationships?.person?.data?.id;\n return jsonResult({ ...formatted, _hints: getBookingHints(id, personId) });\n }\n return jsonResult(formatted);\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 createBooking(\n {\n personId: person_id,\n serviceId: service_id ?? '',\n startedOn: started_on,\n endedOn: ended_on,\n time,\n note,\n eventId: event_id,\n },\n execCtx,\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 result = await updateBooking(\n {\n id,\n startedOn: started_on,\n endedOn: ended_on,\n time,\n note,\n },\n execCtx,\n );\n return jsonResult({ success: true, ...formatBooking(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listBookings(\n { page, perPage, additionalFilters: filter, include },\n execCtx,\n );\n return jsonResult(formatListResponse(result.data, formatBooking, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'bookings', VALID_ACTIONS));\n}\n","/**\n * Budgets MCP handler.\n *\n * Thin adapter that delegates business logic to core executors\n * and handles MCP-specific concerns (hints, error formatting, JSON results).\n */\n\nimport { listBudgets, getBudget } from '@studiometa/productive-core';\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatBudget, formatListResponse } from '../formatters.js';\nimport { getBudgetHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get'];\n\nexport async function handleBudgets(\n action: string,\n args: CommonArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getBudget({ id }, execCtx);\n const formatted = formatBudget(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getBudgetHints(id) });\n }\n\n return jsonResult(formatted);\n }\n\n if (action === 'list') {\n const result = await listBudgets(\n {\n page,\n perPage,\n additionalFilters: filter,\n },\n execCtx,\n );\n\n return jsonResult(formatListResponse(result.data, formatBudget, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'budgets', VALID_ACTIONS));\n}\n","/**\n * Comments MCP handler.\n */\n\nimport {\n listComments,\n getComment,\n createComment,\n updateComment,\n} from '@studiometa/productive-core';\n\nimport type { CommentArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatComment, formatListResponse } from '../formatters.js';\nimport { getCommentHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\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 { formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, body, task_id, deal_id, company_id } = args;\n const include = userInclude?.length ? [...new Set(['creator', ...userInclude])] : ['creator'];\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await getComment({ id, include }, execCtx);\n const formatted = formatComment(result.data, { ...formatOptions, included: result.included });\n\n if (ctx.includeHints !== false) {\n const commentableType = result.data.attributes?.commentable_type as string | undefined;\n let commentableId: string | undefined;\n if (commentableType === 'task') {\n commentableId = result.data.relationships?.task?.data?.id;\n } else if (commentableType === 'deal') {\n commentableId = result.data.relationships?.deal?.data?.id;\n } else if (commentableType === 'company') {\n commentableId = result.data.relationships?.company?.data?.id;\n }\n return jsonResult({\n ...formatted,\n _hints: getCommentHints(id, commentableType, commentableId),\n });\n }\n return jsonResult(formatted);\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 createComment(\n { body, taskId: task_id, dealId: deal_id, companyId: company_id },\n execCtx,\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 updateComment({ id, body }, execCtx);\n return jsonResult({ success: true, ...formatComment(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listComments(\n { page, perPage, additionalFilters: filter, include },\n execCtx,\n );\n return jsonResult(formatListResponse(result.data, formatComment, result.meta, formatOptions));\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'comments', VALID_ACTIONS));\n}\n","/**\n * Resolve handler for MCP.\n *\n * Thin wrapper around core's resource resolver.\n * Provides handleResolve for the MCP 'resolve' action.\n */\n\nimport { resolveResource, ResolveError, type ResolveResult } from '@studiometa/productive-core';\n\nimport type { HandlerContext, ToolResult } from './types.js';\n\nimport { UserInputError } from '../errors.js';\nimport { errorResult, inputErrorResult, jsonResult } from './utils.js';\n\n// Re-export types used by MCP handlers\nexport type { ResolvableResourceType, ResolveResult } from '@studiometa/productive-core';\n\n/**\n * Arguments for resolve action\n */\ninterface ResolveArgs {\n query?: string;\n type?: 'person' | 'project' | 'company' | 'deal' | 'service';\n project_id?: string;\n}\n\n/**\n * Handle resolve action for a resource.\n *\n * Delegates to core's resolveResource function and wraps\n * errors in MCP-friendly format.\n */\nexport async function handleResolve(args: ResolveArgs, ctx: HandlerContext): Promise<ToolResult> {\n const { query, type, project_id } = args;\n\n if (!query) {\n return errorResult('query is required for resolve action');\n }\n\n try {\n const execCtx = ctx.executor();\n const results: ResolveResult[] = await resolveResource(execCtx.api, query, {\n type,\n projectId: project_id,\n });\n\n return jsonResult({\n query,\n matches: results,\n exact: results.length === 1 && results[0].exact,\n });\n } catch (error) {\n if (error instanceof ResolveError) {\n return inputErrorResult(\n new UserInputError(error.message, [\n `Query: \"${error.query}\"`,\n ...(error.type ? [`Type: ${error.type}`] : []),\n ]),\n );\n }\n throw error;\n }\n}\n","/**\n * Companies MCP handler.\n */\n\nimport {\n listCompanies,\n getCompany,\n createCompany,\n updateCompany,\n} from '@studiometa/productive-core';\n\nimport type { CompanyArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatCompany } from '../formatters.js';\nimport { getCompanyHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'resolve'];\n\nexport async function handleCompanies(\n action: string,\n args: CompanyArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, name, query, type } = args;\n\n if (action === 'resolve') {\n return handleResolve({ query, type }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getCompany({ id }, execCtx);\n const formatted = formatCompany(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getCompanyHints(id) });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'create') {\n if (!name) return inputErrorResult(ErrorMessages.missingRequiredFields('company', ['name']));\n\n const result = await createCompany({ name }, execCtx);\n return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n\n const result = await updateCompany({ id, name }, execCtx);\n return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listCompanies({ page, perPage, additionalFilters: filter }, execCtx);\n\n const response = formatListResponse(result.data, formatCompany, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'companies', VALID_ACTIONS));\n}\n","/**\n * Deals MCP handler.\n */\n\nimport { listDeals, getDeal, createDeal, updateDeal } from '@studiometa/productive-core';\n\nimport type { DealArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatDeal, formatListResponse } from '../formatters.js';\nimport { getDealHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'resolve'];\n\nexport async function handleDeals(\n action: string,\n args: DealArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, name, company_id, query, type } = args;\n\n if (action === 'resolve') {\n return handleResolve({ query, type }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const getInclude = userInclude?.length\n ? [...new Set(['company', 'deal_status', 'responsible', ...userInclude])]\n : ['company', 'deal_status', 'responsible'];\n const result = await getDeal({ id, include: getInclude }, execCtx);\n const formatted = formatDeal(result.data, { ...formatOptions, included: result.included });\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getDealHints(id) });\n }\n return jsonResult(formatted);\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 createDeal({ name, companyId: company_id }, execCtx);\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 result = await updateDeal({ id, name }, execCtx);\n return jsonResult({ success: true, ...formatDeal(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const listInclude = userInclude?.length\n ? [...new Set(['company', 'deal_status', ...userInclude])]\n : ['company', 'deal_status'];\n const result = await listDeals(\n { page, perPage, additionalFilters: filter, include: listInclude },\n execCtx,\n );\n\n const response = formatListResponse(result.data, formatDeal, result.meta, {\n ...formatOptions,\n included: result.included,\n });\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'deals', VALID_ACTIONS));\n}\n","/**\n * Discussions MCP handler.\n */\n\nimport {\n listDiscussions,\n getDiscussion,\n createDiscussion,\n updateDiscussion,\n deleteDiscussion,\n resolveDiscussion,\n reopenDiscussion,\n} from '@studiometa/productive-core';\n\nimport type { HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatDiscussion } from '../formatters.js';\nimport { getDiscussionHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nexport interface DiscussionArgs {\n id?: string;\n title?: string;\n body?: string;\n page_id?: string;\n status?: string;\n}\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'delete', 'resolve', 'reopen'];\n\nexport async function handleDiscussions(\n action: string,\n args: DiscussionArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, title, body, page_id, status } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getDiscussion({ id }, execCtx);\n const formatted = formatDiscussion(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getDiscussionHints(id, page_id) });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'create') {\n if (!body || !page_id) {\n return inputErrorResult(\n ErrorMessages.missingRequiredFields('discussion', ['body', 'page_id']),\n );\n }\n const result = await createDiscussion(\n {\n body,\n pageId: page_id,\n title,\n },\n execCtx,\n );\n return jsonResult({ success: true, ...formatDiscussion(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const result = await updateDiscussion({ id, title, body }, execCtx);\n return jsonResult({ success: true, ...formatDiscussion(result.data, formatOptions) });\n }\n\n if (action === 'delete') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('delete'));\n await deleteDiscussion({ id }, execCtx);\n return jsonResult({ success: true, deleted: id });\n }\n\n if (action === 'resolve') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('resolve'));\n const result = await resolveDiscussion({ id }, execCtx);\n return jsonResult({ success: true, ...formatDiscussion(result.data, formatOptions) });\n }\n\n if (action === 'reopen') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('reopen'));\n const result = await reopenDiscussion({ id }, execCtx);\n return jsonResult({ success: true, ...formatDiscussion(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const listOptions: {\n page?: number;\n perPage?: number;\n additionalFilters?: Record<string, string>;\n status?: string;\n } = {\n page,\n perPage,\n additionalFilters: filter,\n };\n if (status) listOptions.status = status;\n\n const result = await listDiscussions(listOptions, execCtx);\n\n const response = formatListResponse(result.data, formatDiscussion, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'discussions', 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 attachments: {\n description: 'File attachments on tasks, comments, deals, and pages',\n actions: {\n list: 'List attachments with optional filters',\n get: 'Get a single attachment by ID',\n delete: 'Delete an attachment by ID',\n },\n filters: {\n task_id: 'Filter by task',\n comment_id: 'Filter by comment',\n deal_id: 'Filter by deal',\n page_id: 'Filter by page',\n },\n fields: {\n id: 'Unique attachment identifier',\n name: 'File name',\n content_type: 'MIME type (e.g., image/png, application/pdf)',\n size: 'File size in bytes',\n size_human: 'Human-readable file size (e.g., 1.5 MB)',\n url: 'Download URL',\n attachable_type: 'Parent resource type (Task, Comment, Deal, Page)',\n },\n examples: [\n {\n description: 'List attachments on a task',\n params: { resource: 'attachments', action: 'list', filter: { task_id: '12345' } },\n },\n {\n description: 'Get attachment details',\n params: { resource: 'attachments', action: 'get', id: '67890' },\n },\n {\n description: 'Delete an attachment',\n params: { resource: 'attachments', action: 'delete', id: '67890' },\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 budgets: {\n description: 'Budget tracking and financial overview',\n actions: {\n list: 'List budgets with optional filters',\n get: 'Get a single budget by ID with full details',\n },\n filters: {\n project_id: 'Filter by project',\n company_id: 'Filter by company',\n deal_id: 'Filter by deal',\n billable: 'Filter by billable status (true/false)',\n budget_type: 'Filter by budget type',\n },\n fields: {\n id: 'Unique budget identifier',\n name: 'Budget name',\n budget_type: 'Type of budget',\n billable: 'Whether the budget is billable',\n started_on: 'Budget start date (YYYY-MM-DD)',\n ended_on: 'Budget end date (YYYY-MM-DD)',\n currency: 'Budget currency code',\n total_time_budget: 'Total time budget in minutes',\n remaining_time_budget: 'Remaining time budget in minutes',\n total_monetary_budget: 'Total monetary budget',\n remaining_monetary_budget: 'Remaining monetary budget',\n },\n examples: [\n {\n description: 'List all budgets',\n params: { resource: 'budgets', action: 'list' },\n },\n {\n description: 'List budgets for a project',\n params: { resource: 'budgets', action: 'list', filter: { project_id: '12345' } },\n },\n {\n description: 'Get budget details',\n params: { resource: 'budgets', action: 'get', id: '67890' },\n },\n {\n description: 'List billable budgets',\n params: { resource: 'budgets', action: 'list', filter: { billable: 'true' } },\n },\n ],\n },\n\n pages: {\n description: 'Manage pages (wiki/docs) within projects',\n actions: {\n list: 'List pages with optional filters',\n get: 'Get a single page by ID with full details',\n create: 'Create a new page (requires title, project_id)',\n update: 'Update an existing page',\n delete: 'Delete a page',\n },\n filters: {\n project_id: 'Filter by project',\n creator_id: 'Filter by creator',\n parent_page_id: 'Filter by parent page (for sub-pages)',\n },\n fields: {\n id: 'Unique page identifier',\n title: 'Page title',\n body: 'Page body content (HTML)',\n public: 'Whether the page is publicly accessible',\n version_number: 'Current version number',\n parent_page_id: 'Parent page ID (for sub-pages)',\n },\n examples: [\n {\n description: 'List pages for a project',\n params: { resource: 'pages', action: 'list', filter: { project_id: '12345' } },\n },\n {\n description: 'Get page details',\n params: { resource: 'pages', action: 'get', id: '67890' },\n },\n {\n description: 'Create a page',\n params: {\n resource: 'pages',\n action: 'create',\n title: 'Getting Started',\n project_id: '12345',\n },\n },\n {\n description: 'Create a sub-page',\n params: {\n resource: 'pages',\n action: 'create',\n title: 'Sub-section',\n project_id: '12345',\n parent_page_id: '67890',\n },\n },\n {\n description: 'Delete a page',\n params: { resource: 'pages', action: 'delete', id: '67890' },\n },\n ],\n },\n\n discussions: {\n description: 'Manage discussions (comment threads on highlighted page content)',\n actions: {\n list: 'List discussions with optional filters',\n get: 'Get a single discussion by ID',\n create: 'Create a new discussion (requires body, page_id)',\n update: 'Update an existing discussion',\n delete: 'Delete a discussion',\n resolve: 'Resolve a discussion (mark as resolved)',\n reopen: 'Reopen a resolved discussion',\n },\n filters: {\n page_id: 'Filter by page',\n status: 'Filter by status: 1=active, 2=resolved',\n },\n fields: {\n id: 'Unique discussion identifier',\n title: 'Discussion title',\n body: 'Discussion body (HTML)',\n status: 'Status: active or resolved',\n resolved_at: 'When the discussion was resolved',\n },\n examples: [\n {\n description: 'List discussions on a page',\n params: { resource: 'discussions', action: 'list', filter: { page_id: '12345' } },\n },\n {\n description: 'List active discussions',\n params: { resource: 'discussions', action: 'list', status: 'active' },\n },\n {\n description: 'Create a discussion',\n params: {\n resource: 'discussions',\n action: 'create',\n page_id: '12345',\n body: 'Review this section',\n },\n },\n {\n description: 'Resolve a discussion',\n params: { resource: 'discussions', action: 'resolve', id: '67890' },\n },\n {\n description: 'Reopen a discussion',\n params: { resource: 'discussions', action: 'reopen', id: '67890' },\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 * Pages MCP handler.\n */\n\nimport {\n listPages,\n getPage,\n createPage,\n updatePage,\n deletePage,\n} from '@studiometa/productive-core';\n\nimport type { HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatPage } from '../formatters.js';\nimport { getPageHints } from '../hints.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nexport interface PageArgs {\n id?: string;\n title?: string;\n body?: string;\n project_id?: string;\n parent_page_id?: string;\n}\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'delete'];\n\nexport async function handlePages(\n action: string,\n args: PageArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, title, body, project_id, parent_page_id } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getPage({ id }, execCtx);\n const formatted = formatPage(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getPageHints(id) });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'create') {\n if (!title || !project_id) {\n return inputErrorResult(ErrorMessages.missingRequiredFields('page', ['title', 'project_id']));\n }\n const result = await createPage(\n {\n title,\n projectId: project_id,\n body,\n parentPageId: parent_page_id,\n },\n execCtx,\n );\n return jsonResult({ success: true, ...formatPage(result.data, formatOptions) });\n }\n\n if (action === 'update') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('update'));\n const result = await updatePage({ id, title, body }, execCtx);\n return jsonResult({ success: true, ...formatPage(result.data, formatOptions) });\n }\n\n if (action === 'delete') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('delete'));\n await deletePage({ id }, execCtx);\n return jsonResult({ success: true, deleted: id });\n }\n\n if (action === 'list') {\n const result = await listPages({ page, perPage, additionalFilters: filter }, execCtx);\n\n const response = formatListResponse(result.data, formatPage, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'pages', VALID_ACTIONS));\n}\n","/**\n * People MCP handler.\n */\n\nimport { listPeople, getPerson } from '@studiometa/productive-core';\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 { getPersonHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'me', 'resolve'];\n\nexport async function handlePeople(\n action: string,\n args: CommonArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n credentials: ProductiveCredentials,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, query, type } = args;\n\n if (action === 'resolve') {\n return handleResolve({ query, type }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getPerson({ id }, execCtx);\n const formatted = formatPerson(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getPersonHints(id) });\n }\n return jsonResult(formatted);\n }\n\n if (action === 'me') {\n if (credentials.userId) {\n const result = await getPerson({ id: credentials.userId }, execCtx);\n const formatted = formatPerson(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getPersonHints(credentials.userId) });\n }\n return jsonResult(formatted);\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 listPeople({ page, perPage, additionalFilters: filter }, execCtx);\n\n const response = formatListResponse(result.data, formatPerson, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'people', VALID_ACTIONS));\n}\n","/**\n * Projects MCP handler.\n */\n\nimport { listProjects, getProject } from '@studiometa/productive-core';\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatProject } from '../formatters.js';\nimport { getProjectHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'resolve'];\n\nexport async function handleProjects(\n action: string,\n args: CommonArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, query, type } = args;\n\n if (action === 'resolve') {\n return handleResolve({ query, type }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getProject({ id }, execCtx);\n const formatted = formatProject(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({\n ...formatted,\n _hints: getProjectHints(id),\n });\n }\n\n return jsonResult(formatted);\n }\n\n if (action === 'list') {\n const result = await listProjects({ page, perPage, additionalFilters: filter }, execCtx);\n\n const response = formatListResponse(result.data, formatProject, result.meta, formatOptions);\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'projects', VALID_ACTIONS));\n}\n","/**\n * Reports MCP handler.\n */\n\nimport { getReport, VALID_REPORT_TYPES, type ReportType } from '@studiometa/productive-core';\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\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\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\nconst VALID_ACTIONS = ['get'];\n\nexport async function handleReports(\n action: string,\n args: ReportArgs,\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { 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 as ReportType)) {\n return inputErrorResult(ErrorMessages.invalidReportType(report_type, [...VALID_REPORT_TYPES]));\n }\n\n const execCtx = ctx.executor();\n\n const result = await getReport(\n {\n reportType: report_type as ReportType,\n page,\n perPage,\n group,\n from,\n to,\n personId: person_id,\n projectId: project_id,\n companyId: company_id,\n dealId: deal_id,\n status,\n additionalFilters: filter,\n },\n execCtx,\n );\n\n const formattedData = formatReportData(result.data);\n\n return jsonResult({\n data: formattedData,\n meta: result.meta,\n });\n}\n","/**\n * Services MCP handler.\n */\n\nimport { listServices } from '@studiometa/productive-core';\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 { formatOptions, filter, page, perPage } = ctx;\n\n if (action === 'list') {\n const execCtx = ctx.executor();\n const result = await listServices({ page, perPage, additionalFilters: filter }, execCtx);\n\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 MCP handler.\n */\n\nimport { listTasks, getTask, createTask, updateTask } from '@studiometa/productive-core';\n\nimport type { HandlerContext, TaskArgs, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTask } from '../formatters.js';\nimport { getTaskHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst DEFAULT_TASK_INCLUDE = ['project', 'project.company'];\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'resolve'];\n\nexport async function handleTasks(\n action: string,\n args: TaskArgs & { query?: string; type?: ResolvableResourceType },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage, include: userInclude } = ctx;\n const { id, title, project_id, task_list_id, description, assignee_id, query, type } = args;\n const include = userInclude?.length\n ? [...new Set([...DEFAULT_TASK_INCLUDE, ...userInclude])]\n : DEFAULT_TASK_INCLUDE;\n\n if (action === 'resolve') {\n return handleResolve({ query, type, project_id }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getTask({ id, include }, execCtx);\n const formatted = formatTask(result.data, { ...formatOptions, included: result.included });\n\n if (ctx.includeHints !== false) {\n const serviceId = result.data.relationships?.service?.data?.id;\n return jsonResult({ ...formatted, _hints: getTaskHints(id, serviceId) });\n }\n return jsonResult(formatted);\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 createTask(\n {\n title,\n projectId: project_id,\n taskListId: task_list_id,\n assigneeId: assignee_id,\n description,\n },\n execCtx,\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 result = await updateTask(\n {\n id,\n title,\n description,\n assigneeId: assignee_id,\n },\n execCtx,\n );\n return jsonResult({ success: true, ...formatTask(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listTasks({ page, perPage, additionalFilters: filter, include }, execCtx);\n\n const response = formatListResponse(result.data, formatTask, result.meta, {\n ...formatOptions,\n included: result.included,\n });\n\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'tasks', VALID_ACTIONS));\n}\n","/**\n * Time entries MCP handler.\n *\n * Thin adapter that delegates business logic to core executors\n * and handles MCP-specific concerns (hints, error formatting, JSON results).\n */\n\nimport {\n listTimeEntries,\n getTimeEntry,\n createTimeEntry,\n updateTimeEntry,\n} from '@studiometa/productive-core';\n\nimport type { CommonArgs, HandlerContext, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTimeEntry } from '../formatters.js';\nimport { getTimeEntryHints } from '../hints.js';\nimport { handleResolve, type ResolvableResourceType } from './resolve.js';\nimport { inputErrorResult, jsonResult } from './utils.js';\n\nconst VALID_ACTIONS = ['list', 'get', 'create', 'update', 'resolve'];\n\nexport async function handleTime(\n action: string,\n args: CommonArgs & { query?: string; type?: ResolvableResourceType; project_id?: string },\n ctx: HandlerContext,\n): Promise<ToolResult> {\n const { formatOptions, filter, page, perPage } = ctx;\n const { id, person_id, service_id, task_id, time, date, note, query, type, project_id } = args;\n\n // Handle resolve action (MCP-specific, no executor equivalent)\n if (action === 'resolve') {\n return handleResolve({ query, type, project_id }, ctx);\n }\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n\n const result = await getTimeEntry({ id }, execCtx);\n const formatted = formatTimeEntry(result.data, formatOptions);\n\n // Add contextual hints unless disabled (MCP-specific)\n if (ctx.includeHints !== false) {\n const serviceId = result.data.relationships?.service?.data?.id;\n return jsonResult({\n ...formatted,\n _hints: getTimeEntryHints(id, undefined, serviceId),\n });\n }\n\n return jsonResult(formatted);\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\n const result = await createTimeEntry(\n {\n personId: person_id,\n serviceId: service_id,\n time,\n date,\n note: note ?? undefined,\n taskId: task_id,\n projectId: project_id,\n },\n execCtx,\n );\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\n const result = await updateTimeEntry(\n {\n id,\n time: time ?? undefined,\n date: date ?? undefined,\n note: note ?? undefined,\n },\n execCtx,\n );\n\n return jsonResult({ success: true, ...formatTimeEntry(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listTimeEntries(\n {\n page,\n perPage,\n additionalFilters: filter,\n },\n execCtx,\n );\n\n const response = formatListResponse(result.data, formatTimeEntry, result.meta, formatOptions);\n\n // Include resolution metadata if any resolutions occurred\n if (result.resolved && Object.keys(result.resolved).length > 0) {\n return jsonResult({ ...response, _resolved: result.resolved });\n }\n\n return jsonResult(response);\n }\n\n return inputErrorResult(ErrorMessages.invalidAction(action, 'time', VALID_ACTIONS));\n}\n","/**\n * Timers MCP handler.\n */\n\nimport { listTimers, getTimer, startTimer, stopTimer } from '@studiometa/productive-core';\n\nimport type { HandlerContext, TimerArgs, ToolResult } from './types.js';\n\nimport { ErrorMessages } from '../errors.js';\nimport { formatListResponse, formatTimer } from '../formatters.js';\nimport { getTimerHints } from '../hints.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 { formatOptions, filter, page, perPage, include } = ctx;\n const { id, service_id, time_entry_id } = args;\n\n const execCtx = ctx.executor();\n\n if (action === 'get') {\n if (!id) return inputErrorResult(ErrorMessages.missingId('get'));\n const result = await getTimer({ id, include }, execCtx);\n const formatted = formatTimer(result.data, formatOptions);\n\n if (ctx.includeHints !== false) {\n return jsonResult({ ...formatted, _hints: getTimerHints(id) });\n }\n return jsonResult(formatted);\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 startTimer({ serviceId: service_id, timeEntryId: time_entry_id }, execCtx);\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 stopTimer({ id }, execCtx);\n return jsonResult({ success: true, ...formatTimer(result.data, formatOptions) });\n }\n\n if (action === 'list') {\n const result = await listTimers({ page, perPage, additionalFilters: filter, include }, execCtx);\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-api';\nimport { fromHandlerContext, RESOURCES } from '@studiometa/productive-core';\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 { handleAttachments } from './attachments.js';\nimport { handleBookings } from './bookings.js';\nimport { handleBudgets } from './budgets.js';\nimport { handleComments } from './comments.js';\nimport { handleCompanies } from './companies.js';\nimport { handleDeals } from './deals.js';\nimport { handleDiscussions } from './discussions.js';\nimport { handleHelp, handleHelpOverview } from './help.js';\nimport { handlePages } from './pages.js';\nimport { handlePeople } from './people.js';\n// Resource handlers\nimport { handleProjects } from './projects.js';\nimport { handleReports } from './reports.js';\nimport { type ResolvableResourceType } from './resolve.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 (derived from core constants) */\nconst VALID_RESOURCES = [...RESOURCES];\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 // Attachment fields\n comment_id?: string;\n // Timer fields\n time_entry_id?: string;\n // Page fields\n parent_page_id?: string;\n page_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 config: {\n apiToken: credentials.apiToken,\n organizationId: credentials.organizationId,\n userId: credentials.userId,\n },\n });\n\n // Handle the single consolidated tool\n if (name !== 'productive') {\n return errorResult(`Unknown tool: ${name}`);\n }\n\n const {\n resource,\n action,\n filter,\n page,\n per_page,\n compact,\n include,\n query,\n no_hints,\n type,\n ...restArgs\n } = args as unknown as ProductiveArgs & { no_hints?: boolean; type?: ResolvableResourceType };\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 // Hints are included by default for 'get' action, disabled for 'list' or when compact\n // Can be explicitly disabled with no_hints: true\n const includeHints = no_hints !== true && action === 'get' && !isCompact;\n\n // Build handler context — api is not exposed directly.\n // Handlers access executors via ctx.executor() which creates an ExecutorContext.\n const execCtx = fromHandlerContext({ api });\n const ctx: HandlerContext = {\n formatOptions,\n filter: stringFilter,\n page,\n perPage,\n include,\n includeHints,\n executor: () => execCtx,\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 // Note: query and type are passed explicitly for resolve action support\n const resolveArgs = { query, type };\n switch (resource) {\n case 'projects':\n return await handleProjects(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'time':\n return await handleTime(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'tasks':\n return await handleTasks(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'services':\n return await handleServices(action, restArgs, ctx);\n\n case 'people':\n return await handlePeople(action, { ...restArgs, ...resolveArgs }, ctx, credentials);\n\n case 'companies':\n return await handleCompanies(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'comments':\n return await handleComments(action, restArgs, ctx);\n\n case 'attachments':\n return await handleAttachments(action, restArgs, ctx);\n\n case 'timers':\n return await handleTimers(action, restArgs, ctx);\n\n case 'deals':\n return await handleDeals(action, { ...restArgs, ...resolveArgs }, ctx);\n\n case 'bookings':\n return await handleBookings(action, restArgs, ctx);\n\n case 'budgets':\n return await handleBudgets(action, restArgs, ctx);\n case 'pages':\n return await handlePages(action, restArgs, ctx);\n\n case 'discussions':\n return await handleDiscussions(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"],"mappings":"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"}
|
package/dist/handlers.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as executeToolWithCredentials } from "./handlers-
|
|
1
|
+
import { t as executeToolWithCredentials } from "./handlers-D4tRd30c.js";
|
|
2
2
|
export { executeToolWithCredentials };
|
package/dist/http.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as INSTRUCTIONS, t as VERSION } from "./version-
|
|
2
|
-
import { t as executeToolWithCredentials } from "./handlers-
|
|
1
|
+
import { n as INSTRUCTIONS, t as VERSION } from "./version-IB2ulmSy.js";
|
|
2
|
+
import { t as executeToolWithCredentials } from "./handlers-D4tRd30c.js";
|
|
3
3
|
import "./handlers.js";
|
|
4
4
|
import { TOOLS } from "./tools.js";
|
|
5
5
|
import { parseAuthHeader } from "./auth.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as INSTRUCTIONS, t as VERSION } from "./version-
|
|
3
|
-
import "./handlers-
|
|
2
|
+
import { n as INSTRUCTIONS, t as VERSION } from "./version-IB2ulmSy.js";
|
|
3
|
+
import "./handlers-D4tRd30c.js";
|
|
4
4
|
import { getAvailablePrompts, getAvailableTools, handlePrompt, handleToolCall } from "./stdio.js";
|
|
5
5
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
package/dist/schema.d.ts
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
* - TypeScript type inference
|
|
9
9
|
*/
|
|
10
10
|
import { z, type ZodSafeParseResult, type ZodError } from 'zod';
|
|
11
|
+
export type { Resource, Action, ReportType } from '@studiometa/productive-core';
|
|
11
12
|
/**
|
|
12
13
|
* Resource types available in Productive.io
|
|
14
|
+
* Values derived from RESOURCES constant in constants.ts
|
|
13
15
|
*/
|
|
14
16
|
export declare const ResourceSchema: z.ZodEnum<{
|
|
15
17
|
comments: "comments";
|
|
@@ -28,9 +30,9 @@ export declare const ResourceSchema: z.ZodEnum<{
|
|
|
28
30
|
budgets: "budgets";
|
|
29
31
|
reports: "reports";
|
|
30
32
|
}>;
|
|
31
|
-
export type Resource = z.infer<typeof ResourceSchema>;
|
|
32
33
|
/**
|
|
33
34
|
* Actions available for resources
|
|
35
|
+
* Values derived from ACTIONS constant in constants.ts
|
|
34
36
|
*/
|
|
35
37
|
export declare const ActionSchema: z.ZodEnum<{
|
|
36
38
|
list: "list";
|
|
@@ -45,9 +47,9 @@ export declare const ActionSchema: z.ZodEnum<{
|
|
|
45
47
|
me: "me";
|
|
46
48
|
help: "help";
|
|
47
49
|
}>;
|
|
48
|
-
export type Action = z.infer<typeof ActionSchema>;
|
|
49
50
|
/**
|
|
50
51
|
* Report types available in Productive.io
|
|
52
|
+
* Values derived from REPORT_TYPES constant in constants.ts
|
|
51
53
|
*/
|
|
52
54
|
export declare const ReportTypeSchema: z.ZodEnum<{
|
|
53
55
|
time_reports: "time_reports";
|
|
@@ -62,7 +64,6 @@ export declare const ReportTypeSchema: z.ZodEnum<{
|
|
|
62
64
|
deal_reports: "deal_reports";
|
|
63
65
|
timesheet_reports: "timesheet_reports";
|
|
64
66
|
}>;
|
|
65
|
-
export type ReportType = z.infer<typeof ReportTypeSchema>;
|
|
66
67
|
/**
|
|
67
68
|
* Resource ID parameter
|
|
68
69
|
*/
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,CAAC,EAAoB,KAAK,kBAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGlF,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAMhF;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;EAAoB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;EAAkB,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAAuB,CAAC;AAMrD;;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,6BAKtB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoEpC,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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as VERSION } from "./version-
|
|
3
|
-
import "./handlers-
|
|
2
|
+
import { t as VERSION } from "./version-IB2ulmSy.js";
|
|
3
|
+
import "./handlers-D4tRd30c.js";
|
|
4
4
|
import { createHttpApp } from "./http.js";
|
|
5
5
|
import { toNodeListener } from "h3";
|
|
6
6
|
import { createServer } from "node:http";
|
package/dist/stdio.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as executeToolWithCredentials } from "./handlers-
|
|
1
|
+
import { t as executeToolWithCredentials } from "./handlers-D4tRd30c.js";
|
|
2
2
|
import "./handlers.js";
|
|
3
3
|
import { STDIO_ONLY_TOOLS, TOOLS } from "./tools.js";
|
|
4
4
|
import { getConfig, setConfig } from "@studiometa/productive-api";
|
package/dist/tools.d.ts
CHANGED
|
@@ -2,7 +2,11 @@ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Single consolidated tool for Productive.io MCP server
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* The resource/action/report_type enums and description are derived from
|
|
6
|
+
* the shared constants in constants.ts — the single source of truth for both
|
|
7
|
+
* the MCP tool definition and the Zod validation schemas.
|
|
8
|
+
* Adding a new resource, action, or report type there automatically updates
|
|
9
|
+
* both the tool exposed to clients and the validation layer.
|
|
6
10
|
*
|
|
7
11
|
* MCP Annotations (for MCP directory compliance):
|
|
8
12
|
* - readOnlyHint: false - Tool can create/update data
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAqB/D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,KAAK,EAAE,IAAI,EAsFvB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,IAAI,EAoClC,CAAC"}
|
package/dist/tools.js
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
+
import { ACTIONS, REPORT_TYPES, RESOURCES } from "@studiometa/productive-core";
|
|
2
|
+
/**
|
|
3
|
+
* Generate the tool description dynamically from the constants.
|
|
4
|
+
* Adding a resource or action to constants.ts automatically updates this description.
|
|
5
|
+
*/
|
|
6
|
+
function generateDescription() {
|
|
7
|
+
return `Productive.io API. Resources: ${RESOURCES.join(", ")}. Actions: ${ACTIONS.join(", ")} (varies by resource). Use query for text search on list actions. Reports: use resource=reports, action=get with report_type. Filters: project_id, person_id, service_id, company_id, after/before (dates). Use include to fetch related data. Use compact=false for full details (default for get, true for list). Use action=help with a resource for detailed documentation.`;
|
|
8
|
+
}
|
|
1
9
|
/**
|
|
2
10
|
* Single consolidated tool for Productive.io MCP server
|
|
3
11
|
*
|
|
4
|
-
*
|
|
12
|
+
* The resource/action/report_type enums and description are derived from
|
|
13
|
+
* the shared constants in constants.ts — the single source of truth for both
|
|
14
|
+
* the MCP tool definition and the Zod validation schemas.
|
|
15
|
+
* Adding a new resource, action, or report type there automatically updates
|
|
16
|
+
* both the tool exposed to clients and the validation layer.
|
|
5
17
|
*
|
|
6
18
|
* MCP Annotations (for MCP directory compliance):
|
|
7
19
|
* - readOnlyHint: false - Tool can create/update data
|
|
@@ -11,7 +23,7 @@
|
|
|
11
23
|
*/
|
|
12
24
|
const TOOLS = [{
|
|
13
25
|
name: "productive",
|
|
14
|
-
description:
|
|
26
|
+
description: generateDescription(),
|
|
15
27
|
annotations: {
|
|
16
28
|
title: "Productive.io",
|
|
17
29
|
readOnlyHint: false,
|
|
@@ -24,32 +36,11 @@ const TOOLS = [{
|
|
|
24
36
|
properties: {
|
|
25
37
|
resource: {
|
|
26
38
|
type: "string",
|
|
27
|
-
enum: [
|
|
28
|
-
"projects",
|
|
29
|
-
"time",
|
|
30
|
-
"tasks",
|
|
31
|
-
"services",
|
|
32
|
-
"people",
|
|
33
|
-
"companies",
|
|
34
|
-
"comments",
|
|
35
|
-
"timers",
|
|
36
|
-
"deals",
|
|
37
|
-
"bookings",
|
|
38
|
-
"reports"
|
|
39
|
-
]
|
|
39
|
+
enum: [...RESOURCES]
|
|
40
40
|
},
|
|
41
41
|
action: {
|
|
42
42
|
type: "string",
|
|
43
|
-
enum: [
|
|
44
|
-
"list",
|
|
45
|
-
"get",
|
|
46
|
-
"create",
|
|
47
|
-
"update",
|
|
48
|
-
"me",
|
|
49
|
-
"start",
|
|
50
|
-
"stop",
|
|
51
|
-
"help"
|
|
52
|
-
],
|
|
43
|
+
enum: [...ACTIONS],
|
|
53
44
|
description: "Action to perform. Use \"help\" for detailed documentation on a resource."
|
|
54
45
|
},
|
|
55
46
|
id: { type: "string" },
|
|
@@ -82,27 +73,27 @@ const TOOLS = [{
|
|
|
82
73
|
description: { type: "string" },
|
|
83
74
|
assignee_id: { type: "string" },
|
|
84
75
|
name: { type: "string" },
|
|
76
|
+
page_id: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "Page ID. Find pages using resource=\"pages\" action=\"list\""
|
|
79
|
+
},
|
|
80
|
+
parent_page_id: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "Parent page ID for creating sub-pages"
|
|
83
|
+
},
|
|
85
84
|
body: { type: "string" },
|
|
86
85
|
deal_id: { type: "string" },
|
|
86
|
+
comment_id: {
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "Comment ID for filtering attachments"
|
|
89
|
+
},
|
|
87
90
|
time_entry_id: { type: "string" },
|
|
88
91
|
started_on: { type: "string" },
|
|
89
92
|
ended_on: { type: "string" },
|
|
90
93
|
event_id: { type: "string" },
|
|
91
94
|
report_type: {
|
|
92
95
|
type: "string",
|
|
93
|
-
enum: [
|
|
94
|
-
"time_reports",
|
|
95
|
-
"project_reports",
|
|
96
|
-
"budget_reports",
|
|
97
|
-
"person_reports",
|
|
98
|
-
"invoice_reports",
|
|
99
|
-
"payment_reports",
|
|
100
|
-
"service_reports",
|
|
101
|
-
"task_reports",
|
|
102
|
-
"company_reports",
|
|
103
|
-
"deal_reports",
|
|
104
|
-
"timesheet_reports"
|
|
105
|
-
]
|
|
96
|
+
enum: [...REPORT_TYPES]
|
|
106
97
|
},
|
|
107
98
|
group: { type: "string" },
|
|
108
99
|
from: { type: "string" },
|
package/dist/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","names":[],"sources":["../src/tools.ts"],"sourcesContent":["import type { Tool } from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Single consolidated tool for Productive.io MCP server\n *\n *
|
|
1
|
+
{"version":3,"file":"tools.js","names":[],"sources":["../src/tools.ts"],"sourcesContent":["import type { Tool } from '@modelcontextprotocol/sdk/types.js';\n\nimport { RESOURCES, ACTIONS, REPORT_TYPES } from '@studiometa/productive-core';\n\n/**\n * Generate the tool description dynamically from the constants.\n * Adding a resource or action to constants.ts automatically updates this description.\n */\nfunction generateDescription(): string {\n return (\n `Productive.io API. Resources: ${RESOURCES.join(', ')}. ` +\n `Actions: ${ACTIONS.join(', ')} (varies by resource). ` +\n 'Use query for text search on list actions. ' +\n 'Reports: use resource=reports, action=get with report_type. ' +\n 'Filters: project_id, person_id, service_id, company_id, after/before (dates). ' +\n 'Use include to fetch related data. ' +\n 'Use compact=false for full details (default for get, true for list). ' +\n 'Use action=help with a resource for detailed documentation.'\n );\n}\n\n/**\n * Single consolidated tool for Productive.io MCP server\n *\n * The resource/action/report_type enums and description are derived from\n * the shared constants in constants.ts — the single source of truth for both\n * the MCP tool definition and the Zod validation schemas.\n * Adding a new resource, action, or report type there automatically updates\n * both the tool exposed to clients and the validation layer.\n *\n * MCP Annotations (for MCP directory compliance):\n * - readOnlyHint: false - Tool can create/update data\n * - destructiveHint: false - Tool does not permanently delete data\n * - idempotentHint: false - Create actions are not idempotent\n * - openWorldHint: true - Tool interacts with external Productive.io API\n */\nexport const TOOLS: Tool[] = [\n {\n name: 'productive',\n description: generateDescription(),\n annotations: {\n title: 'Productive.io',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n inputSchema: {\n type: 'object',\n properties: {\n resource: {\n type: 'string',\n enum: [...RESOURCES],\n },\n action: {\n type: 'string',\n enum: [...ACTIONS],\n description: 'Action to perform. Use \"help\" for detailed documentation on a resource.',\n },\n id: { type: 'string' },\n filter: { type: 'object' },\n page: { type: 'number' },\n per_page: { type: 'number' },\n compact: {\n type: 'boolean',\n description: 'Compact output (default: true for list, false for get)',\n },\n include: {\n type: 'array',\n items: { type: 'string' },\n description: 'Related resources to include (e.g., [\"project\", \"assignee\", \"comments\"])',\n },\n query: {\n type: 'string',\n description: 'Text search query for list actions (searches name/title fields)',\n },\n // Common fields\n person_id: { type: 'string' },\n service_id: { type: 'string' },\n task_id: { type: 'string' },\n company_id: { type: 'string' },\n time: { type: 'number' },\n date: { type: 'string' },\n note: { type: 'string' },\n // Task fields\n title: { type: 'string' },\n project_id: { type: 'string' },\n task_list_id: { type: 'string' },\n description: { type: 'string' },\n assignee_id: { type: 'string' },\n // Company fields\n name: { type: 'string' },\n // Page fields\n page_id: {\n type: 'string',\n description: 'Page ID. Find pages using resource=\"pages\" action=\"list\"',\n },\n parent_page_id: { type: 'string', description: 'Parent page ID for creating sub-pages' },\n // Comment fields\n body: { type: 'string' },\n deal_id: { type: 'string' },\n // Attachment fields\n comment_id: { type: 'string', description: 'Comment ID for filtering attachments' },\n // Timer fields\n time_entry_id: { type: 'string' },\n // Booking fields\n started_on: { type: 'string' },\n ended_on: { type: 'string' },\n event_id: { type: 'string' },\n // Report fields\n report_type: {\n type: 'string',\n enum: [...REPORT_TYPES],\n },\n group: { type: 'string' },\n from: { type: 'string' },\n to: { type: 'string' },\n status: { type: 'string' },\n },\n required: ['resource', 'action'],\n },\n },\n];\n\n/**\n * Additional tools only available in stdio mode (local execution)\n * These tools manage persistent configuration\n */\nexport const STDIO_ONLY_TOOLS: Tool[] = [\n {\n name: 'productive_configure',\n description: 'Configure Productive.io credentials',\n annotations: {\n title: 'Configure Productive',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n inputSchema: {\n type: 'object',\n properties: {\n organizationId: { type: 'string' },\n apiToken: { type: 'string' },\n userId: { type: 'string' },\n },\n required: ['organizationId', 'apiToken'],\n },\n },\n {\n name: 'productive_get_config',\n description: 'Get current configuration',\n annotations: {\n title: 'Get Productive Config',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n inputSchema: {\n type: 'object',\n properties: {},\n },\n },\n];\n"],"mappings":";;;;;AAQA,SAAS,sBAA8B;AACrC,QACE,iCAAiC,UAAU,KAAK,KAAK,CAAC,aAC1C,QAAQ,KAAK,KAAK,CAAC;;;;;;;;;;;;;;;;;AAyBnC,MAAa,QAAgB,CAC3B;CACE,MAAM;CACN,aAAa,qBAAqB;CAClC,aAAa;EACX,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EAChB,eAAe;EAChB;CACD,aAAa;EACX,MAAM;EACN,YAAY;GACV,UAAU;IACR,MAAM;IACN,MAAM,CAAC,GAAG,UAAU;IACrB;GACD,QAAQ;IACN,MAAM;IACN,MAAM,CAAC,GAAG,QAAQ;IAClB,aAAa;IACd;GACD,IAAI,EAAE,MAAM,UAAU;GACtB,QAAQ,EAAE,MAAM,UAAU;GAC1B,MAAM,EAAE,MAAM,UAAU;GACxB,UAAU,EAAE,MAAM,UAAU;GAC5B,SAAS;IACP,MAAM;IACN,aAAa;IACd;GACD,SAAS;IACP,MAAM;IACN,OAAO,EAAE,MAAM,UAAU;IACzB,aAAa;IACd;GACD,OAAO;IACL,MAAM;IACN,aAAa;IACd;GAED,WAAW,EAAE,MAAM,UAAU;GAC7B,YAAY,EAAE,MAAM,UAAU;GAC9B,SAAS,EAAE,MAAM,UAAU;GAC3B,YAAY,EAAE,MAAM,UAAU;GAC9B,MAAM,EAAE,MAAM,UAAU;GACxB,MAAM,EAAE,MAAM,UAAU;GACxB,MAAM,EAAE,MAAM,UAAU;GAExB,OAAO,EAAE,MAAM,UAAU;GACzB,YAAY,EAAE,MAAM,UAAU;GAC9B,cAAc,EAAE,MAAM,UAAU;GAChC,aAAa,EAAE,MAAM,UAAU;GAC/B,aAAa,EAAE,MAAM,UAAU;GAE/B,MAAM,EAAE,MAAM,UAAU;GAExB,SAAS;IACP,MAAM;IACN,aAAa;IACd;GACD,gBAAgB;IAAE,MAAM;IAAU,aAAa;IAAyC;GAExF,MAAM,EAAE,MAAM,UAAU;GACxB,SAAS,EAAE,MAAM,UAAU;GAE3B,YAAY;IAAE,MAAM;IAAU,aAAa;IAAwC;GAEnF,eAAe,EAAE,MAAM,UAAU;GAEjC,YAAY,EAAE,MAAM,UAAU;GAC9B,UAAU,EAAE,MAAM,UAAU;GAC5B,UAAU,EAAE,MAAM,UAAU;GAE5B,aAAa;IACX,MAAM;IACN,MAAM,CAAC,GAAG,aAAa;IACxB;GACD,OAAO,EAAE,MAAM,UAAU;GACzB,MAAM,EAAE,MAAM,UAAU;GACxB,IAAI,EAAE,MAAM,UAAU;GACtB,QAAQ,EAAE,MAAM,UAAU;GAC3B;EACD,UAAU,CAAC,YAAY,SAAS;EACjC;CACF,CACF;;;;;AAMD,MAAa,mBAA2B,CACtC;CACE,MAAM;CACN,aAAa;CACb,aAAa;EACX,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EAChB,eAAe;EAChB;CACD,aAAa;EACX,MAAM;EACN,YAAY;GACV,gBAAgB,EAAE,MAAM,UAAU;GAClC,UAAU,EAAE,MAAM,UAAU;GAC5B,QAAQ,EAAE,MAAM,UAAU;GAC3B;EACD,UAAU,CAAC,kBAAkB,WAAW;EACzC;CACF,EACD;CACE,MAAM;CACN,aAAa;CACb,aAAa;EACX,OAAO;EACP,cAAc;EACd,iBAAiB;EACjB,gBAAgB;EAChB,eAAe;EAChB;CACD,aAAa;EACX,MAAM;EACN,YAAY,EAAE;EACf;CACF,CACF"}
|
|
@@ -23,7 +23,7 @@ function loadInstructions() {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
const INSTRUCTIONS = loadInstructions();
|
|
26
|
-
const VERSION = "0.9.
|
|
26
|
+
const VERSION = "0.9.2";
|
|
27
27
|
export { INSTRUCTIONS as n, VERSION as t };
|
|
28
28
|
|
|
29
|
-
//# sourceMappingURL=version-
|
|
29
|
+
//# sourceMappingURL=version-IB2ulmSy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-
|
|
1
|
+
{"version":3,"file":"version-IB2ulmSy.js","names":[],"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"],"mappings":";;;;;;;;;;;;AAcA,IAAM,YAAY,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;;;;;AAMzD,SAAS,mBAA2B;AAClC,KAAI;AAQF,SALgB,aADE,KAAK,WAAW,MAAM,UAAU,WAAW,EACrB,QAAQ,CAGb,QAAQ,0BAA0B,GAAG,CAE9C,MAAM;SAC1B;AAEN,SAAO;;;AAIX,MAAa,eAAe,kBAAkB;AChC9C,MAAa,UAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studiometa/productive-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "MCP server for Productive.io API - Model Context Protocol integration for Claude Desktop",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
90
|
-
"@studiometa/productive-api": "0.9.
|
|
91
|
-
"@studiometa/productive-core": "0.9.
|
|
90
|
+
"@studiometa/productive-api": "0.9.2",
|
|
91
|
+
"@studiometa/productive-core": "0.9.2",
|
|
92
92
|
"h3": "^1.15.1",
|
|
93
93
|
"zod": "4.3.6"
|
|
94
94
|
},
|