@studiometa/productive-mcp 0.6.4 → 0.8.0
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/errors.d.ts +41 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/handlers/bookings.d.ts +1 -1
- package/dist/handlers/bookings.d.ts.map +1 -1
- package/dist/handlers/comments.d.ts +1 -1
- package/dist/handlers/comments.d.ts.map +1 -1
- package/dist/handlers/companies.d.ts +1 -1
- package/dist/handlers/companies.d.ts.map +1 -1
- package/dist/handlers/deals.d.ts +1 -1
- package/dist/handlers/deals.d.ts.map +1 -1
- package/dist/handlers/help.d.ts +13 -0
- package/dist/handlers/help.d.ts.map +1 -0
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/people.d.ts +1 -1
- package/dist/handlers/people.d.ts.map +1 -1
- package/dist/handlers/projects.d.ts +1 -1
- package/dist/handlers/projects.d.ts.map +1 -1
- package/dist/handlers/reports.d.ts +21 -0
- package/dist/handlers/reports.d.ts.map +1 -0
- package/dist/handlers/services.d.ts +1 -1
- package/dist/handlers/services.d.ts.map +1 -1
- package/dist/handlers/tasks.d.ts.map +1 -1
- package/dist/handlers/time.d.ts +1 -1
- package/dist/handlers/time.d.ts.map +1 -1
- package/dist/handlers/timers.d.ts.map +1 -1
- package/dist/handlers/types.d.ts +1 -0
- package/dist/handlers/types.d.ts.map +1 -1
- package/dist/handlers/utils.d.ts +12 -1
- package/dist/handlers/utils.d.ts.map +1 -1
- package/dist/handlers.js +1 -1
- package/dist/http.d.ts +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +4 -3
- package/dist/http.js.map +1 -1
- package/dist/index-D743zTS1.js +1177 -0
- package/dist/index-D743zTS1.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +11 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/schema.d.ts +218 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/server.js +1 -1
- package/dist/stdio.js +1 -1
- package/dist/tools.d.ts +6 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +61 -5
- package/dist/tools.js.map +1 -1
- package/dist/version-i2-GF6d1.js +21 -0
- package/dist/version-i2-GF6d1.js.map +1 -0
- package/package.json +13 -3
- package/skills/SKILL.md +330 -0
- package/dist/index-CmTDkz-y.js +0 -480
- package/dist/index-CmTDkz-y.js.map +0 -1
- package/dist/version-BRw90xAB.js +0 -5
- package/dist/version-BRw90xAB.js.map +0 -1
package/dist/tools.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
const TOOLS = [
|
|
2
2
|
{
|
|
3
3
|
name: "productive",
|
|
4
|
-
description: "Productive.io API. Resources: projects, time, tasks, services, people, companies, comments, timers, deals, bookings. Actions: list, get, create, update (varies by resource), start/stop (timers), me (people). Filters: project_id, person_id, service_id, company_id, after/before (dates).",
|
|
4
|
+
description: "Productive.io API. Resources: projects, time, tasks, services, people, companies, comments, timers, deals, bookings, reports. Actions: list, get, create, update (varies by resource), start/stop (timers), me (people), help (documentation). 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.",
|
|
5
|
+
annotations: {
|
|
6
|
+
title: "Productive.io",
|
|
7
|
+
readOnlyHint: false,
|
|
8
|
+
destructiveHint: false,
|
|
9
|
+
idempotentHint: false,
|
|
10
|
+
openWorldHint: true
|
|
11
|
+
},
|
|
5
12
|
inputSchema: {
|
|
6
13
|
type: "object",
|
|
7
14
|
properties: {
|
|
@@ -17,18 +24,32 @@ const TOOLS = [
|
|
|
17
24
|
"comments",
|
|
18
25
|
"timers",
|
|
19
26
|
"deals",
|
|
20
|
-
"bookings"
|
|
27
|
+
"bookings",
|
|
28
|
+
"reports"
|
|
21
29
|
]
|
|
22
30
|
},
|
|
23
31
|
action: {
|
|
24
32
|
type: "string",
|
|
25
|
-
enum: ["list", "get", "create", "update", "me", "start", "stop"]
|
|
33
|
+
enum: ["list", "get", "create", "update", "me", "start", "stop", "help"],
|
|
34
|
+
description: 'Action to perform. Use "help" for detailed documentation on a resource.'
|
|
26
35
|
},
|
|
27
36
|
id: { type: "string" },
|
|
28
37
|
filter: { type: "object" },
|
|
29
38
|
page: { type: "number" },
|
|
30
39
|
per_page: { type: "number" },
|
|
31
|
-
compact: {
|
|
40
|
+
compact: {
|
|
41
|
+
type: "boolean",
|
|
42
|
+
description: "Compact output (default: true for list, false for get)"
|
|
43
|
+
},
|
|
44
|
+
include: {
|
|
45
|
+
type: "array",
|
|
46
|
+
items: { type: "string" },
|
|
47
|
+
description: 'Related resources to include (e.g., ["project", "assignee", "comments"])'
|
|
48
|
+
},
|
|
49
|
+
query: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "Text search query for list actions (searches name/title fields)"
|
|
52
|
+
},
|
|
32
53
|
// Common fields
|
|
33
54
|
person_id: { type: "string" },
|
|
34
55
|
service_id: { type: "string" },
|
|
@@ -53,7 +74,28 @@ const TOOLS = [
|
|
|
53
74
|
// Booking fields
|
|
54
75
|
started_on: { type: "string" },
|
|
55
76
|
ended_on: { type: "string" },
|
|
56
|
-
event_id: { type: "string" }
|
|
77
|
+
event_id: { type: "string" },
|
|
78
|
+
// Report fields
|
|
79
|
+
report_type: {
|
|
80
|
+
type: "string",
|
|
81
|
+
enum: [
|
|
82
|
+
"time_reports",
|
|
83
|
+
"project_reports",
|
|
84
|
+
"budget_reports",
|
|
85
|
+
"person_reports",
|
|
86
|
+
"invoice_reports",
|
|
87
|
+
"payment_reports",
|
|
88
|
+
"service_reports",
|
|
89
|
+
"task_reports",
|
|
90
|
+
"company_reports",
|
|
91
|
+
"deal_reports",
|
|
92
|
+
"timesheet_reports"
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
group: { type: "string" },
|
|
96
|
+
from: { type: "string" },
|
|
97
|
+
to: { type: "string" },
|
|
98
|
+
status: { type: "string" }
|
|
57
99
|
},
|
|
58
100
|
required: ["resource", "action"]
|
|
59
101
|
}
|
|
@@ -63,6 +105,13 @@ const STDIO_ONLY_TOOLS = [
|
|
|
63
105
|
{
|
|
64
106
|
name: "productive_configure",
|
|
65
107
|
description: "Configure Productive.io credentials",
|
|
108
|
+
annotations: {
|
|
109
|
+
title: "Configure Productive",
|
|
110
|
+
readOnlyHint: false,
|
|
111
|
+
destructiveHint: false,
|
|
112
|
+
idempotentHint: true,
|
|
113
|
+
openWorldHint: false
|
|
114
|
+
},
|
|
66
115
|
inputSchema: {
|
|
67
116
|
type: "object",
|
|
68
117
|
properties: {
|
|
@@ -76,6 +125,13 @@ const STDIO_ONLY_TOOLS = [
|
|
|
76
125
|
{
|
|
77
126
|
name: "productive_get_config",
|
|
78
127
|
description: "Get current configuration",
|
|
128
|
+
annotations: {
|
|
129
|
+
title: "Get Productive Config",
|
|
130
|
+
readOnlyHint: true,
|
|
131
|
+
destructiveHint: false,
|
|
132
|
+
idempotentHint: true,
|
|
133
|
+
openWorldHint: false
|
|
134
|
+
},
|
|
79
135
|
inputSchema: {
|
|
80
136
|
type: "object",
|
|
81
137
|
properties: {}
|
package/dist/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","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 * Optimized for minimal token overhead (~170 tokens vs ~1300 for individual tools)\n */\nexport const TOOLS: Tool[] = [\n {\n name: 'productive',\n description:\n 'Productive.io API. Resources: projects, time, tasks, services, people, companies, comments, timers, deals, bookings. Actions: list, get, create, update (varies by resource), start/stop (timers), me (people). Filters: project_id, person_id, service_id, company_id, after/before (dates).',\n inputSchema: {\n type: 'object',\n properties: {\n resource: {\n type: 'string',\n enum: [\n 'projects',\n 'time',\n 'tasks',\n 'services',\n 'people',\n 'companies',\n 'comments',\n 'timers',\n 'deals',\n 'bookings',\n ],\n },\n action: {\n type: 'string',\n enum: ['list', 'get', 'create', 'update', 'me', 'start', 'stop'],\n },\n id: { type: 'string' },\n filter: { type: 'object' },\n page: { type: 'number' },\n per_page: { type: 'number' },\n compact: {
|
|
1
|
+
{"version":3,"file":"tools.js","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 * Optimized for minimal token overhead (~170 tokens vs ~1300 for individual tools)\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:\n 'Productive.io API. Resources: projects, time, tasks, services, people, companies, comments, timers, deals, bookings, reports. Actions: list, get, create, update (varies by resource), start/stop (timers), me (people), help (documentation). 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.',\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: [\n 'projects',\n 'time',\n 'tasks',\n 'services',\n 'people',\n 'companies',\n 'comments',\n 'timers',\n 'deals',\n 'bookings',\n 'reports',\n ],\n },\n action: {\n type: 'string',\n enum: ['list', 'get', 'create', 'update', 'me', 'start', 'stop', 'help'],\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 // Comment fields\n body: { type: 'string' },\n deal_id: { type: 'string' },\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: [\n 'time_reports',\n 'project_reports',\n 'budget_reports',\n 'person_reports',\n 'invoice_reports',\n 'payment_reports',\n 'service_reports',\n 'task_reports',\n 'company_reports',\n 'deal_reports',\n 'timesheet_reports',\n ],\n },\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"],"names":[],"mappings":"AAaO,MAAM,QAAgB;AAAA,EAC3B;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,OAAO;AAAA,MACP,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IAAA;AAAA,IAEjB,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,UAAU;AAAA,UACR,MAAM;AAAA,UACN,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QACF;AAAA,QAEF,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,MAAM,CAAC,QAAQ,OAAO,UAAU,UAAU,MAAM,SAAS,QAAQ,MAAM;AAAA,UACvE,aAAa;AAAA,QAAA;AAAA,QAEf,IAAI,EAAE,MAAM,SAAA;AAAA,QACZ,QAAQ,EAAE,MAAM,SAAA;AAAA,QAChB,MAAM,EAAE,MAAM,SAAA;AAAA,QACd,UAAU,EAAE,MAAM,SAAA;AAAA,QAClB,SAAS;AAAA,UACP,MAAM;AAAA,UACN,aAAa;AAAA,QAAA;AAAA,QAEf,SAAS;AAAA,UACP,MAAM;AAAA,UACN,OAAO,EAAE,MAAM,SAAA;AAAA,UACf,aAAa;AAAA,QAAA;AAAA,QAEf,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa;AAAA,QAAA;AAAA;AAAA,QAGf,WAAW,EAAE,MAAM,SAAA;AAAA,QACnB,YAAY,EAAE,MAAM,SAAA;AAAA,QACpB,SAAS,EAAE,MAAM,SAAA;AAAA,QACjB,YAAY,EAAE,MAAM,SAAA;AAAA,QACpB,MAAM,EAAE,MAAM,SAAA;AAAA,QACd,MAAM,EAAE,MAAM,SAAA;AAAA,QACd,MAAM,EAAE,MAAM,SAAA;AAAA;AAAA,QAEd,OAAO,EAAE,MAAM,SAAA;AAAA,QACf,YAAY,EAAE,MAAM,SAAA;AAAA,QACpB,cAAc,EAAE,MAAM,SAAA;AAAA,QACtB,aAAa,EAAE,MAAM,SAAA;AAAA,QACrB,aAAa,EAAE,MAAM,SAAA;AAAA;AAAA,QAErB,MAAM,EAAE,MAAM,SAAA;AAAA;AAAA,QAEd,MAAM,EAAE,MAAM,SAAA;AAAA,QACd,SAAS,EAAE,MAAM,SAAA;AAAA;AAAA,QAEjB,eAAe,EAAE,MAAM,SAAA;AAAA;AAAA,QAEvB,YAAY,EAAE,MAAM,SAAA;AAAA,QACpB,UAAU,EAAE,MAAM,SAAA;AAAA,QAClB,UAAU,EAAE,MAAM,SAAA;AAAA;AAAA,QAElB,aAAa;AAAA,UACX,MAAM;AAAA,UACN,MAAM;AAAA,YACJ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QACF;AAAA,QAEF,OAAO,EAAE,MAAM,SAAA;AAAA,QACf,MAAM,EAAE,MAAM,SAAA;AAAA,QACd,IAAI,EAAE,MAAM,SAAA;AAAA,QACZ,QAAQ,EAAE,MAAM,SAAA;AAAA,MAAS;AAAA,MAE3B,UAAU,CAAC,YAAY,QAAQ;AAAA,IAAA;AAAA,EACjC;AAEJ;AAMO,MAAM,mBAA2B;AAAA,EACtC;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,OAAO;AAAA,MACP,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IAAA;AAAA,IAEjB,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,gBAAgB,EAAE,MAAM,SAAA;AAAA,QACxB,UAAU,EAAE,MAAM,SAAA;AAAA,QAClB,QAAQ,EAAE,MAAM,SAAA;AAAA,MAAS;AAAA,MAE3B,UAAU,CAAC,kBAAkB,UAAU;AAAA,IAAA;AAAA,EACzC;AAAA,EAEF;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,OAAO;AAAA,MACP,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IAAA;AAAA,IAEjB,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,CAAA;AAAA,IAAC;AAAA,EACf;AAEJ;"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
function loadInstructions() {
|
|
6
|
+
try {
|
|
7
|
+
const skillPath = join(__dirname$1, "..", "skills", "SKILL.md");
|
|
8
|
+
const content = readFileSync(skillPath, "utf-8");
|
|
9
|
+
const withoutFrontmatter = content.replace(/^---\n[\s\S]*?\n---\n+/, "");
|
|
10
|
+
return withoutFrontmatter.trim();
|
|
11
|
+
} catch {
|
|
12
|
+
return "Productive.io MCP Server - Use the productive tool with resource and action parameters.";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const INSTRUCTIONS = loadInstructions();
|
|
16
|
+
const VERSION = "0.8.0";
|
|
17
|
+
export {
|
|
18
|
+
INSTRUCTIONS as I,
|
|
19
|
+
VERSION as V
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=version-i2-GF6d1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-i2-GF6d1.js","sources":["../src/instructions.ts","../src/version.ts"],"sourcesContent":["/**\n * MCP Server Instructions\n *\n * These instructions are sent to Claude Desktop during initialization\n * and used as context/hints for the LLM. This ensures the AI agent\n * knows how to properly use the Productive.io MCP server.\n *\n * The content is derived from skills/SKILL.md (without YAML frontmatter).\n */\n\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Load instructions from SKILL.md file\n * Removes YAML frontmatter (content between --- markers)\n */\nfunction loadInstructions(): string {\n try {\n // In dist/, go up to package root, then to skills/\n const skillPath = join(__dirname, '..', 'skills', 'SKILL.md');\n const content = readFileSync(skillPath, 'utf-8');\n\n // Remove YAML frontmatter (between --- markers at start of file)\n const withoutFrontmatter = content.replace(/^---\\n[\\s\\S]*?\\n---\\n+/, '');\n\n return withoutFrontmatter.trim();\n } catch {\n // Fallback if file not found (shouldn't happen in production)\n return 'Productive.io MCP Server - Use the productive tool with resource and action parameters.';\n }\n}\n\nexport const INSTRUCTIONS = loadInstructions();\n","/**\n * Package version - injected from package.json at build time\n */\ndeclare const __VERSION__: string;\nexport const VERSION = __VERSION__;\n"],"names":["__dirname"],"mappings":";;;AAcA,MAAMA,cAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAMxD,SAAS,mBAA2B;AAClC,MAAI;AAEF,UAAM,YAAY,KAAKA,aAAW,MAAM,UAAU,UAAU;AAC5D,UAAM,UAAU,aAAa,WAAW,OAAO;AAG/C,UAAM,qBAAqB,QAAQ,QAAQ,0BAA0B,EAAE;AAEvE,WAAO,mBAAmB,KAAA;AAAA,EAC5B,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAEO,MAAM,eAAe,iBAAA;AChCrB,MAAM,UAAU;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studiometa/productive-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "MCP server for Productive.io API - Model Context Protocol integration for Claude Desktop",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
|
+
"skills",
|
|
28
29
|
"Dockerfile"
|
|
29
30
|
],
|
|
30
31
|
"type": "module",
|
|
@@ -58,6 +59,14 @@
|
|
|
58
59
|
"./handlers": {
|
|
59
60
|
"types": "./dist/handlers.d.ts",
|
|
60
61
|
"import": "./dist/handlers.js"
|
|
62
|
+
},
|
|
63
|
+
"./errors": {
|
|
64
|
+
"types": "./dist/errors.d.ts",
|
|
65
|
+
"import": "./dist/errors.js"
|
|
66
|
+
},
|
|
67
|
+
"./schema": {
|
|
68
|
+
"types": "./dist/schema.d.ts",
|
|
69
|
+
"import": "./dist/schema.js"
|
|
61
70
|
}
|
|
62
71
|
},
|
|
63
72
|
"publishConfig": {
|
|
@@ -79,8 +88,9 @@
|
|
|
79
88
|
},
|
|
80
89
|
"dependencies": {
|
|
81
90
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
82
|
-
"@studiometa/productive-cli": "0.
|
|
83
|
-
"h3": "^1.15.1"
|
|
91
|
+
"@studiometa/productive-cli": "0.8.0",
|
|
92
|
+
"h3": "^1.15.1",
|
|
93
|
+
"zod": "4.3.6"
|
|
84
94
|
},
|
|
85
95
|
"devDependencies": {
|
|
86
96
|
"@types/node": "^22.10.5",
|
package/skills/SKILL.md
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: productive-mcp
|
|
3
|
+
description: MCP server for Productive.io - use with Claude Desktop or MCP-compatible clients for time tracking, projects, and tasks
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Productive MCP Server
|
|
7
|
+
|
|
8
|
+
MCP (Model Context Protocol) server for Productive.io. Provides a single unified tool for all operations.
|
|
9
|
+
|
|
10
|
+
## The `productive` Tool
|
|
11
|
+
|
|
12
|
+
Single unified tool with this signature:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
productive(resource, action, [parameters...])
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Resources & Actions
|
|
19
|
+
|
|
20
|
+
| Resource | Actions | Description |
|
|
21
|
+
| ----------- | ----------------------------------------- | ----------------------- |
|
|
22
|
+
| `projects` | `list`, `get`, `help` | Project management |
|
|
23
|
+
| `time` | `list`, `get`, `create`, `update`, `help` | Time tracking |
|
|
24
|
+
| `tasks` | `list`, `get`, `create`, `update`, `help` | Task management |
|
|
25
|
+
| `services` | `list`, `get`, `help` | Budget line items |
|
|
26
|
+
| `people` | `list`, `get`, `me`, `help` | Team members |
|
|
27
|
+
| `companies` | `list`, `get`, `create`, `update`, `help` | Client companies |
|
|
28
|
+
| `comments` | `list`, `get`, `create`, `update`, `help` | Comments on tasks/deals |
|
|
29
|
+
| `timers` | `list`, `get`, `start`, `stop`, `help` | Active timers |
|
|
30
|
+
| `deals` | `list`, `get`, `create`, `update`, `help` | Sales deals |
|
|
31
|
+
| `bookings` | `list`, `get`, `create`, `update`, `help` | Resource scheduling |
|
|
32
|
+
| `reports` | `get`, `help` | Generate reports |
|
|
33
|
+
|
|
34
|
+
### Getting Help
|
|
35
|
+
|
|
36
|
+
Use `action: "help"` to get detailed documentation for any resource:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"resource": "time",
|
|
41
|
+
"action": "help"
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Returns filters, fields, includes, and examples for that resource.
|
|
46
|
+
|
|
47
|
+
## Common Parameters
|
|
48
|
+
|
|
49
|
+
| Parameter | Type | Description |
|
|
50
|
+
| ---------- | ------- | ------------------------------------------------------ |
|
|
51
|
+
| `resource` | string | **Required**. Resource type (see table above) |
|
|
52
|
+
| `action` | string | **Required**. Action to perform |
|
|
53
|
+
| `id` | string | Resource ID (for `get`, `update`, `stop`) |
|
|
54
|
+
| `filter` | object | Filter criteria for `list` actions |
|
|
55
|
+
| `page` | number | Page number (default: 1) |
|
|
56
|
+
| `per_page` | number | Items per page (default: 20, max: 200) |
|
|
57
|
+
| `compact` | boolean | Compact output (default: true for list, false for get) |
|
|
58
|
+
| `include` | array | Related resources to include |
|
|
59
|
+
| `query` | string | Text search on name/title fields |
|
|
60
|
+
|
|
61
|
+
## Examples by Resource
|
|
62
|
+
|
|
63
|
+
### Projects
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
// List projects
|
|
67
|
+
{ "resource": "projects", "action": "list" }
|
|
68
|
+
|
|
69
|
+
// Search projects
|
|
70
|
+
{ "resource": "projects", "action": "list", "query": "website" }
|
|
71
|
+
|
|
72
|
+
// Get project details
|
|
73
|
+
{ "resource": "projects", "action": "get", "id": "12345" }
|
|
74
|
+
|
|
75
|
+
// Filter active projects
|
|
76
|
+
{ "resource": "projects", "action": "list", "filter": { "archived": "false" } }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Time Entries
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
// List my time entries for a date range
|
|
83
|
+
{
|
|
84
|
+
"resource": "time",
|
|
85
|
+
"action": "list",
|
|
86
|
+
"filter": {
|
|
87
|
+
"person_id": "me",
|
|
88
|
+
"after": "2024-01-15",
|
|
89
|
+
"before": "2024-01-21"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Create time entry (time in MINUTES)
|
|
94
|
+
{
|
|
95
|
+
"resource": "time",
|
|
96
|
+
"action": "create",
|
|
97
|
+
"service_id": "12345",
|
|
98
|
+
"date": "2024-01-16",
|
|
99
|
+
"time": 480,
|
|
100
|
+
"note": "Development work"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Update time entry
|
|
104
|
+
{
|
|
105
|
+
"resource": "time",
|
|
106
|
+
"action": "update",
|
|
107
|
+
"id": "67890",
|
|
108
|
+
"time": 240,
|
|
109
|
+
"note": "Updated note"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Tasks
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
// List open tasks for a project
|
|
117
|
+
{
|
|
118
|
+
"resource": "tasks",
|
|
119
|
+
"action": "list",
|
|
120
|
+
"filter": { "project_id": "12345", "status": "open" }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Get task with comments
|
|
124
|
+
{
|
|
125
|
+
"resource": "tasks",
|
|
126
|
+
"action": "get",
|
|
127
|
+
"id": "67890",
|
|
128
|
+
"include": ["comments", "assignee"]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Search tasks
|
|
132
|
+
{ "resource": "tasks", "action": "list", "query": "bug fix" }
|
|
133
|
+
|
|
134
|
+
// Create task
|
|
135
|
+
{
|
|
136
|
+
"resource": "tasks",
|
|
137
|
+
"action": "create",
|
|
138
|
+
"title": "New task",
|
|
139
|
+
"project_id": "12345",
|
|
140
|
+
"task_list_id": "111"
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### People
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
// Get current user
|
|
148
|
+
{ "resource": "people", "action": "me" }
|
|
149
|
+
|
|
150
|
+
// List people
|
|
151
|
+
{ "resource": "people", "action": "list" }
|
|
152
|
+
|
|
153
|
+
// Search by name
|
|
154
|
+
{ "resource": "people", "action": "list", "query": "john" }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Services
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
// List services for a project
|
|
161
|
+
{
|
|
162
|
+
"resource": "services",
|
|
163
|
+
"action": "list",
|
|
164
|
+
"filter": { "project_id": "12345" }
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Comments
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
// List comments on a task
|
|
172
|
+
{
|
|
173
|
+
"resource": "comments",
|
|
174
|
+
"action": "list",
|
|
175
|
+
"filter": { "task_id": "12345" }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Add comment
|
|
179
|
+
{
|
|
180
|
+
"resource": "comments",
|
|
181
|
+
"action": "create",
|
|
182
|
+
"task_id": "12345",
|
|
183
|
+
"body": "Looking good!"
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Timers
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
// List active timers
|
|
191
|
+
{ "resource": "timers", "action": "list" }
|
|
192
|
+
|
|
193
|
+
// Start timer on a service
|
|
194
|
+
{ "resource": "timers", "action": "start", "service_id": "12345" }
|
|
195
|
+
|
|
196
|
+
// Stop timer
|
|
197
|
+
{ "resource": "timers", "action": "stop", "id": "67890" }
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Reports
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
// Time report by person
|
|
204
|
+
{
|
|
205
|
+
"resource": "reports",
|
|
206
|
+
"action": "get",
|
|
207
|
+
"report_type": "time_reports",
|
|
208
|
+
"group": "person",
|
|
209
|
+
"from": "2024-01-01",
|
|
210
|
+
"to": "2024-01-31"
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Budget report for a project
|
|
214
|
+
{
|
|
215
|
+
"resource": "reports",
|
|
216
|
+
"action": "get",
|
|
217
|
+
"report_type": "budget_reports",
|
|
218
|
+
"filter": { "project_id": "12345" }
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Filters Reference
|
|
223
|
+
|
|
224
|
+
### Time Entries
|
|
225
|
+
|
|
226
|
+
- `person_id` - Filter by person (use "me" for current user)
|
|
227
|
+
- `project_id` - Filter by project
|
|
228
|
+
- `service_id` - Filter by service
|
|
229
|
+
- `after` - After date (YYYY-MM-DD)
|
|
230
|
+
- `before` - Before date (YYYY-MM-DD)
|
|
231
|
+
|
|
232
|
+
### Tasks
|
|
233
|
+
|
|
234
|
+
- `project_id` - Filter by project
|
|
235
|
+
- `assignee_id` - Filter by assigned person
|
|
236
|
+
- `status` - Filter by status: `open`, `closed`, `all`
|
|
237
|
+
- `task_list_id` - Filter by task list
|
|
238
|
+
|
|
239
|
+
### Projects
|
|
240
|
+
|
|
241
|
+
- `company_id` - Filter by company
|
|
242
|
+
- `archived` - Include archived: `true`, `false`
|
|
243
|
+
|
|
244
|
+
### Services
|
|
245
|
+
|
|
246
|
+
- `project_id` - Filter by project
|
|
247
|
+
- `deal_id` - Filter by deal
|
|
248
|
+
|
|
249
|
+
### Bookings
|
|
250
|
+
|
|
251
|
+
- `person_id` - Filter by person
|
|
252
|
+
- `service_id` - Filter by service
|
|
253
|
+
- `after` / `before` - Date range
|
|
254
|
+
|
|
255
|
+
## Include (Related Resources)
|
|
256
|
+
|
|
257
|
+
Fetch related data in a single request:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"resource": "tasks",
|
|
262
|
+
"action": "get",
|
|
263
|
+
"id": "12345",
|
|
264
|
+
"include": ["project", "project.company", "assignee", "comments"]
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Common includes:
|
|
269
|
+
|
|
270
|
+
- Tasks: `project`, `assignee`, `workflow_status`, `comments`, `subtasks`
|
|
271
|
+
- Time entries: `person`, `service`, `project`
|
|
272
|
+
- Deals: `company`, `deal_status`, `responsible`
|
|
273
|
+
|
|
274
|
+
## Compact Mode
|
|
275
|
+
|
|
276
|
+
- `compact: true` (default for `list`) - Returns minimal fields
|
|
277
|
+
- `compact: false` (default for `get`) - Returns full details
|
|
278
|
+
|
|
279
|
+
Force full details on list:
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{ "resource": "projects", "action": "list", "compact": false }
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Time Values
|
|
286
|
+
|
|
287
|
+
**Time is always in MINUTES:**
|
|
288
|
+
|
|
289
|
+
- 60 = 1 hour
|
|
290
|
+
- 480 = 8 hours (full day)
|
|
291
|
+
- 240 = 4 hours (half day)
|
|
292
|
+
|
|
293
|
+
## Configuration Tools (stdio mode only)
|
|
294
|
+
|
|
295
|
+
In local/stdio mode, additional configuration tools are available:
|
|
296
|
+
|
|
297
|
+
```json
|
|
298
|
+
// Configure credentials
|
|
299
|
+
productive_configure({
|
|
300
|
+
"organizationId": "...",
|
|
301
|
+
"apiToken": "...",
|
|
302
|
+
"userId": "..."
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
// View current config (token masked)
|
|
306
|
+
productive_get_config()
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Best Practices for AI Agents
|
|
312
|
+
|
|
313
|
+
**For data handling best practices, confirmation workflows, and error handling patterns, see the CLI skill documentation:**
|
|
314
|
+
|
|
315
|
+
→ `@studiometa/productive-cli/skills/SKILL.md`
|
|
316
|
+
|
|
317
|
+
Key points:
|
|
318
|
+
|
|
319
|
+
1. **Never modify text content** - Use exact titles, descriptions, notes from API
|
|
320
|
+
2. **Never invent IDs** - Always fetch first to get valid IDs
|
|
321
|
+
3. **Always confirm before mutations** - Ask user before create/update/delete
|
|
322
|
+
4. **Time is in minutes** - 480 = 8 hours
|
|
323
|
+
|
|
324
|
+
### MCP-Specific Tips
|
|
325
|
+
|
|
326
|
+
1. **Use `action: "help"`** - Get resource documentation before using unfamiliar resources
|
|
327
|
+
2. **Use `compact: false`** for detailed single-item views
|
|
328
|
+
3. **Use `include`** to reduce round-trips when you need related data
|
|
329
|
+
4. **Use `query`** for text search instead of fetching all and filtering
|
|
330
|
+
5. **Check `people.me`** first to get the current user's ID for filters
|