@studiometa/productive-mcp 0.10.10 → 0.10.11

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.
Files changed (36) hide show
  1. package/README.md +120 -0
  2. package/dist/api-reference/generated.d.ts +3 -0
  3. package/dist/api-reference/generated.d.ts.map +1 -0
  4. package/dist/api-reference/types.d.ts +31 -0
  5. package/dist/api-reference/types.d.ts.map +1 -0
  6. package/dist/handlers/api-read.d.ts +14 -0
  7. package/dist/handlers/api-read.d.ts.map +1 -0
  8. package/dist/handlers/api-utils.d.ts +27 -0
  9. package/dist/handlers/api-utils.d.ts.map +1 -0
  10. package/dist/handlers/api-write.d.ts +10 -0
  11. package/dist/handlers/api-write.d.ts.map +1 -0
  12. package/dist/handlers/index.d.ts.map +1 -1
  13. package/dist/handlers-B9FASjNJ.js +41290 -0
  14. package/dist/handlers-B9FASjNJ.js.map +1 -0
  15. package/dist/handlers.js +1 -1
  16. package/dist/http-B3J8ZV4I.js +2534 -0
  17. package/dist/http-B3J8ZV4I.js.map +1 -0
  18. package/dist/http.js +1 -1
  19. package/dist/index.js +2 -2
  20. package/dist/schema.d.ts +32 -1
  21. package/dist/schema.d.ts.map +1 -1
  22. package/dist/server.js +2 -2
  23. package/dist/{stdio-BFK9AcdQ.js → stdio-BpKd5pcS.js} +2 -2
  24. package/dist/{stdio-BFK9AcdQ.js.map → stdio-BpKd5pcS.js.map} +1 -1
  25. package/dist/stdio.js +1 -1
  26. package/dist/tools.d.ts.map +1 -1
  27. package/dist/tools.js +193 -119
  28. package/dist/tools.js.map +1 -1
  29. package/dist/{version-Cy8UEAT1.js → version-Dm6m3p60.js} +3 -3
  30. package/dist/{version-Cy8UEAT1.js.map → version-Dm6m3p60.js.map} +1 -1
  31. package/package.json +3 -3
  32. package/skills/SKILL.md +113 -1
  33. package/dist/handlers-vtRpc-Lx.js +0 -4301
  34. package/dist/handlers-vtRpc-Lx.js.map +0 -1
  35. package/dist/http-CVE4qtko.js +0 -6541
  36. package/dist/http-CVE4qtko.js.map +0 -1
package/README.md CHANGED
@@ -17,6 +17,7 @@ MCP (Model Context Protocol) server for [Productive.io](https://productive.io).
17
17
  - Two modes: **local (stdio)** for personal use, **remote (HTTP)** for teams
18
18
  - OAuth 2.0 support for Claude Desktop custom connectors
19
19
  - Built-in `help` action for self-documentation
20
+ - Raw API escape hatches: `api_read` for documented GET endpoints and gated `api_write` for documented writes
20
21
 
21
22
  ## Mode 1: Local (stdio)
22
23
 
@@ -144,6 +145,125 @@ Use `action="help"` with any resource for detailed documentation on available pa
144
145
  | `include` | string[] | Related resources to include (e.g. `["project", "assignee"]`) |
145
146
  | `query` | string | Text search for `list` actions |
146
147
 
148
+ ### Raw API Tools
149
+
150
+ In addition to the unified `productive` tool, the server exposes two low-level tools for documented Productive API endpoints.
151
+
152
+ | Tool | Description |
153
+ | ----------- | ---------------------------------------------------------------------------------------- |
154
+ | `api_read` | Read-only raw API access for documented `GET` endpoints |
155
+ | `api_write` | Gated raw API write access for documented `POST`, `PATCH`, `PUT`, and `DELETE` endpoints |
156
+
157
+ #### `api_read`
158
+
159
+ Use `api_read` when you need a documented endpoint that is not yet covered by the higher-level `productive` tool.
160
+
161
+ **Parameters**
162
+
163
+ | Parameter | Type | Description |
164
+ | ----------- | -------- | -------------------------------------------------------- |
165
+ | `path` | string | Required relative API path, starting with `/` |
166
+ | `describe` | boolean | Return endpoint docs instead of executing the request |
167
+ | `filter` | object | Filter object, validated against the documented endpoint |
168
+ | `include` | string[] | Related resources to include |
169
+ | `sort` | string[] | Sort values, validated against the documented endpoint |
170
+ | `page` | number | Page number |
171
+ | `per_page` | number | Page size, max `200` |
172
+ | `paginate` | boolean | Follow pagination automatically |
173
+ | `max_pages` | number | Max pages when `paginate=true`, default `20`, max `50` |
174
+
175
+ **Safety model**
176
+
177
+ - `GET` only
178
+ - Path must be relative and start with `/`
179
+ - Absolute URLs and path traversal are rejected
180
+ - Only documented Productive endpoints are allowed
181
+ - Filters and sort values are validated against the endpoint spec
182
+ - `describe=true` is the safest way to inspect an endpoint before calling it
183
+
184
+ **Examples**
185
+
186
+ ```json
187
+ {
188
+ "path": "/invoices",
189
+ "describe": true
190
+ }
191
+ ```
192
+
193
+ ```json
194
+ {
195
+ "path": "/projects/123/tasks",
196
+ "filter": { "status": "open" },
197
+ "sort": ["due_date"],
198
+ "page": 1,
199
+ "per_page": 50
200
+ }
201
+ ```
202
+
203
+ ```json
204
+ {
205
+ "path": "/time_entries",
206
+ "filter": { "person_id": ["me"], "after": "2025-01-01", "before": "2025-01-31" },
207
+ "paginate": true,
208
+ "max_pages": 5
209
+ }
210
+ ```
211
+
212
+ #### `api_write`
213
+
214
+ Use `api_write` only when the higher-level `productive` tool does not expose the mutation you need.
215
+
216
+ **Parameters**
217
+
218
+ | Parameter | Type | Description |
219
+ | --------- | ------- | -------------------------------------------------- |
220
+ | `method` | string | Required, one of `POST`, `PATCH`, `PUT`, `DELETE` |
221
+ | `path` | string | Required relative API path |
222
+ | `body` | object | Request body for write methods |
223
+ | `confirm` | boolean | Required, must be `true` |
224
+ | `dry_run` | boolean | Return the normalized request without executing it |
225
+
226
+ **Safety model**
227
+
228
+ - Disabled by default
229
+ - Requires `PRODUCTIVE_MCP_ENABLE_API_WRITE=true` on the server
230
+ - Requires `confirm=true` on every call
231
+ - Only documented Productive endpoints are allowed
232
+ - Path must be relative; absolute URLs and traversal are rejected
233
+ - `dry_run=true` lets you verify the exact method, path, and body before execution
234
+
235
+ To enable writes in local or remote deployments:
236
+
237
+ ```bash
238
+ PRODUCTIVE_MCP_ENABLE_API_WRITE=true productive-mcp-server
239
+ ```
240
+
241
+ **Examples**
242
+
243
+ ```json
244
+ {
245
+ "method": "PATCH",
246
+ "path": "/tasks/123",
247
+ "body": {
248
+ "data": {
249
+ "type": "tasks",
250
+ "id": "123",
251
+ "attributes": { "name": "Updated title" }
252
+ }
253
+ },
254
+ "confirm": true,
255
+ "dry_run": true
256
+ }
257
+ ```
258
+
259
+ ```json
260
+ {
261
+ "method": "DELETE",
262
+ "path": "/attachments/456",
263
+ "confirm": true
264
+ }
265
+ ```
266
+
147
267
  ### Configuration Tools (Local mode only)
148
268
 
149
269
  | Tool | Description |
@@ -0,0 +1,3 @@
1
+ import type { ApiReference } from './types.js';
2
+ export declare const PRODUCTIVE_API_REFERENCE: ApiReference;
3
+ //# sourceMappingURL=generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generated.d.ts","sourceRoot":"","sources":["../../src/api-reference/generated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,eAAO,MAAM,wBAAwB,EAAE,YAk3jD7B,CAAC"}
@@ -0,0 +1,31 @@
1
+ export interface ApiFilterOperatorSpec {
2
+ description?: string;
3
+ }
4
+ export interface ApiFilterSpec {
5
+ type?: string;
6
+ format?: string;
7
+ description?: string;
8
+ enum?: Array<string | number>;
9
+ operators?: Record<string, ApiFilterOperatorSpec>;
10
+ }
11
+ export interface ApiQueryParamSpec {
12
+ type?: string;
13
+ description?: string;
14
+ }
15
+ export interface ApiMethodSpec {
16
+ summary: string;
17
+ description?: string;
18
+ operationId?: string;
19
+ query?: Record<string, ApiQueryParamSpec>;
20
+ filters?: Record<string, ApiFilterSpec>;
21
+ sort?: string[];
22
+ pathParams?: Record<string, ApiQueryParamSpec>;
23
+ requestBodyFields?: string[];
24
+ supportsBody?: boolean;
25
+ }
26
+ export interface ApiEndpointSpec {
27
+ path: string;
28
+ methods: Partial<Record<'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE', ApiMethodSpec>>;
29
+ }
30
+ export type ApiReference = Record<string, ApiEndpointSpec>;
31
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api-reference/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC/C,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;CACtF;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { HandlerContext, ToolResult } from './types.js';
2
+ export interface ApiReadArgs {
3
+ path: string;
4
+ describe?: boolean;
5
+ filter?: Record<string, unknown>;
6
+ include?: string[];
7
+ sort?: string[];
8
+ page?: number;
9
+ per_page?: number;
10
+ paginate?: boolean;
11
+ max_pages?: number;
12
+ }
13
+ export declare function handleApiRead(args: ApiReadArgs, ctx: HandlerContext): Promise<ToolResult>;
14
+ //# sourceMappingURL=api-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-read.d.ts","sourceRoot":"","sources":["../../src/handlers/api-read.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAa7D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CA0B/F"}
@@ -0,0 +1,27 @@
1
+ import type { ApiEndpointSpec, ApiMethodSpec } from '../api-reference/types.js';
2
+ export declare const MAX_PER_PAGE = 200;
3
+ export declare const DEFAULT_MAX_PAGES = 20;
4
+ export declare const MAX_MAX_PAGES = 50;
5
+ export interface ResolvedApiEndpoint {
6
+ spec: ApiEndpointSpec;
7
+ methodSpec: ApiMethodSpec;
8
+ normalizedPath: string;
9
+ }
10
+ export declare function normalizeApiPath(path: string): string;
11
+ export declare function resolveApiEndpoint(path: string, method: keyof ApiEndpointSpec['methods']): ResolvedApiEndpoint;
12
+ export declare function serializeFilter(filter?: Record<string, unknown>): Record<string, string>;
13
+ export declare function buildApiReadQuery(args: {
14
+ filter?: Record<string, unknown>;
15
+ include?: string[];
16
+ sort?: string[];
17
+ page?: number;
18
+ per_page?: number;
19
+ }): Record<string, string>;
20
+ export declare function validatePagination(args: {
21
+ per_page?: number;
22
+ max_pages?: number;
23
+ }): void;
24
+ export declare function validateFilterSpec(filter: Record<string, unknown> | undefined, methodSpec: ApiMethodSpec): void;
25
+ export declare function validateSort(sort: string[] | undefined, methodSpec: ApiMethodSpec): void;
26
+ export declare function describeApiEndpoint(path: string): Record<string, unknown>;
27
+ //# sourceMappingURL=api-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-utils.d.ts","sourceRoot":"","sources":["../../src/handlers/api-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAKhF,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,CAAC;IACtB,UAAU,EAAE,aAAa,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAMD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAerD;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,eAAe,CAAC,SAAS,CAAC,GACvC,mBAAmB,CAgBrB;AAwBD,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASzB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQxF;AAwCD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC3C,UAAU,EAAE,aAAa,GACxB,IAAI,CAIN;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,UAAU,EAAE,aAAa,GAAG,IAAI,CAYxF;AA+CD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAmCzE"}
@@ -0,0 +1,10 @@
1
+ import type { HandlerContext, ToolResult } from './types.js';
2
+ export interface ApiWriteArgs {
3
+ method: 'POST' | 'PATCH' | 'PUT' | 'DELETE';
4
+ path: string;
5
+ body?: unknown;
6
+ confirm?: boolean;
7
+ dry_run?: boolean;
8
+ }
9
+ export declare function handleApiWrite(args: ApiWriteArgs, ctx: HandlerContext): Promise<ToolResult>;
10
+ //# sourceMappingURL=api-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-write.d.ts","sourceRoot":"","sources":["../../src/handlers/api-write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM7D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAoCjG"}
@@ -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;AAgC7D,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA2I7C;;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,CA0IrB"}
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;AAuC7D,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA8I7C;;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,CA0LrB"}