@studiometa/productive-mcp 0.5.0 → 0.6.1
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/Dockerfile +7 -0
- package/README.md +51 -43
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js.map +1 -1
- package/dist/crypto.js +1 -1
- package/dist/crypto.js.map +1 -1
- package/dist/formatters.d.ts +20 -0
- package/dist/formatters.d.ts.map +1 -1
- package/dist/handlers/bookings.d.ts +6 -0
- package/dist/handlers/bookings.d.ts.map +1 -0
- package/dist/handlers/comments.d.ts +6 -0
- package/dist/handlers/comments.d.ts.map +1 -0
- package/dist/handlers/companies.d.ts +6 -0
- package/dist/handlers/companies.d.ts.map +1 -0
- package/dist/handlers/deals.d.ts +6 -0
- package/dist/handlers/deals.d.ts.map +1 -0
- package/dist/handlers/index.d.ts +15 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/people.d.ts +7 -0
- package/dist/handlers/people.d.ts.map +1 -0
- package/dist/handlers/projects.d.ts +6 -0
- package/dist/handlers/projects.d.ts.map +1 -0
- package/dist/handlers/services.d.ts +6 -0
- package/dist/handlers/services.d.ts.map +1 -0
- package/dist/handlers/tasks.d.ts +6 -0
- package/dist/handlers/tasks.d.ts.map +1 -0
- package/dist/handlers/time.d.ts +6 -0
- package/dist/handlers/time.d.ts.map +1 -0
- package/dist/handlers/timers.d.ts +6 -0
- package/dist/handlers/timers.d.ts.map +1 -0
- package/dist/handlers/types.d.ts +78 -0
- package/dist/handlers/types.d.ts.map +1 -0
- package/dist/handlers/utils.d.ts +17 -0
- package/dist/handlers/utils.d.ts.map +1 -0
- package/dist/handlers.d.ts +3 -10
- package/dist/handlers.d.ts.map +1 -1
- package/dist/handlers.js +2 -233
- package/dist/handlers.js.map +1 -1
- package/dist/http.js +3 -3
- package/dist/http.js.map +1 -1
- package/dist/index-CmTDkz-y.js +480 -0
- package/dist/index-CmTDkz-y.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/oauth.d.ts +1 -1
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +111 -12
- package/dist/oauth.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/stdio.d.ts.map +1 -1
- package/dist/stdio.js +1 -1
- package/dist/stdio.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +34 -5
- package/dist/tools.js.map +1 -1
- package/dist/version-BBHuTm1A.js +5 -0
- package/dist/{version-eQNCcjOb.js.map → version-BBHuTm1A.js.map} +1 -1
- package/package.json +46 -46
- package/dist/version-eQNCcjOb.js +0 -5
package/Dockerfile
CHANGED
|
@@ -18,6 +18,10 @@ ENV NODE_ENV=production
|
|
|
18
18
|
ENV PORT=3000
|
|
19
19
|
ENV HOST=0.0.0.0
|
|
20
20
|
|
|
21
|
+
# Create non-root user for security
|
|
22
|
+
RUN addgroup -g 1001 -S nodejs && \
|
|
23
|
+
adduser -S nodejs -u 1001 -G nodejs
|
|
24
|
+
|
|
21
25
|
# Expose port
|
|
22
26
|
EXPOSE 3000
|
|
23
27
|
|
|
@@ -25,5 +29,8 @@ EXPOSE 3000
|
|
|
25
29
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
26
30
|
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
|
|
27
31
|
|
|
32
|
+
# Switch to non-root user
|
|
33
|
+
USER nodejs
|
|
34
|
+
|
|
28
35
|
# Run the HTTP server
|
|
29
36
|
CMD ["productive-mcp-server"]
|
package/README.md
CHANGED
|
@@ -20,9 +20,9 @@ MCP (Model Context Protocol) server for [Productive.io](https://productive.io) A
|
|
|
20
20
|
|
|
21
21
|
This package supports two modes:
|
|
22
22
|
|
|
23
|
-
| Mode
|
|
24
|
-
|
|
25
|
-
| **Local (stdio)** | `productive-mcp`
|
|
23
|
+
| Mode | Command | Use Case |
|
|
24
|
+
| ----------------- | ----------------------- | -------------------------------------------- |
|
|
25
|
+
| **Local (stdio)** | `productive-mcp` | Personal use via Claude Desktop config |
|
|
26
26
|
| **Remote (HTTP)** | `productive-mcp-server` | Team use via Claude Desktop custom connector |
|
|
27
27
|
|
|
28
28
|
---
|
|
@@ -40,6 +40,7 @@ npm install -g @studiometa/productive-mcp
|
|
|
40
40
|
### Claude Desktop Configuration
|
|
41
41
|
|
|
42
42
|
Edit your Claude Desktop config:
|
|
43
|
+
|
|
43
44
|
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
44
45
|
- **Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
|
|
45
46
|
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
|
@@ -131,22 +132,23 @@ services:
|
|
|
131
132
|
dockerfile: packages/productive-mcp/Dockerfile
|
|
132
133
|
restart: unless-stopped
|
|
133
134
|
ports:
|
|
134
|
-
-
|
|
135
|
+
- '3000:3000'
|
|
135
136
|
environment:
|
|
136
137
|
PORT: 3000
|
|
137
138
|
HOST: 0.0.0.0
|
|
138
|
-
OAUTH_SECRET:
|
|
139
|
+
OAUTH_SECRET: 'your-random-secret-here' # Required for production!
|
|
139
140
|
```
|
|
140
141
|
|
|
141
142
|
### Environment Variables
|
|
142
143
|
|
|
143
|
-
| Variable
|
|
144
|
-
|
|
145
|
-
| `PORT`
|
|
146
|
-
| `HOST`
|
|
144
|
+
| Variable | Required | Description |
|
|
145
|
+
| -------------- | -------------------- | -------------------------------------- |
|
|
146
|
+
| `PORT` | No | Server port (default: 3000) |
|
|
147
|
+
| `HOST` | No | Bind address (default: 0.0.0.0) |
|
|
147
148
|
| `OAUTH_SECRET` | **Yes (production)** | Secret key for encrypting OAuth tokens |
|
|
148
149
|
|
|
149
150
|
> ⚠️ **Important**: Always set `OAUTH_SECRET` in production. Generate a random secret:
|
|
151
|
+
>
|
|
150
152
|
> ```bash
|
|
151
153
|
> openssl rand -base64 32
|
|
152
154
|
> ```
|
|
@@ -174,6 +176,7 @@ echo -n "YOUR_ORG_ID:YOUR_API_TOKEN:YOUR_USER_ID" | base64
|
|
|
174
176
|
```
|
|
175
177
|
|
|
176
178
|
Example:
|
|
179
|
+
|
|
177
180
|
```bash
|
|
178
181
|
echo -n "12345:pk_abc123xyz:67890" | base64
|
|
179
182
|
# Output: MTIzNDU6cGtfYWJjMTIzeHl6OjY3ODkw
|
|
@@ -181,15 +184,15 @@ echo -n "12345:pk_abc123xyz:67890" | base64
|
|
|
181
184
|
|
|
182
185
|
### Server Endpoints
|
|
183
186
|
|
|
184
|
-
| Endpoint
|
|
185
|
-
|
|
186
|
-
| `/mcp`
|
|
187
|
-
| `/health`
|
|
188
|
-
| `/`
|
|
189
|
-
| `/authorize`
|
|
190
|
-
| `/authorize`
|
|
191
|
-
| `/token`
|
|
192
|
-
| `/.well-known/oauth-authorization-server` | GET
|
|
187
|
+
| Endpoint | Method | Description |
|
|
188
|
+
| ----------------------------------------- | ------ | ----------------------------------- |
|
|
189
|
+
| `/mcp` | POST | MCP JSON-RPC endpoint |
|
|
190
|
+
| `/health` | GET | Health check |
|
|
191
|
+
| `/` | GET | Server info |
|
|
192
|
+
| `/authorize` | GET | OAuth authorization (login form) |
|
|
193
|
+
| `/authorize` | POST | OAuth authorization (process login) |
|
|
194
|
+
| `/token` | POST | OAuth token exchange |
|
|
195
|
+
| `/.well-known/oauth-authorization-server` | GET | OAuth metadata |
|
|
193
196
|
|
|
194
197
|
---
|
|
195
198
|
|
|
@@ -203,38 +206,40 @@ productive(resource, action, ...)
|
|
|
203
206
|
|
|
204
207
|
### Resources & Actions
|
|
205
208
|
|
|
206
|
-
| Resource
|
|
207
|
-
|
|
208
|
-
| `projects` | `list`, `get`
|
|
209
|
-
| `time`
|
|
210
|
-
| `tasks`
|
|
211
|
-
| `services` | `list`
|
|
212
|
-
| `people`
|
|
209
|
+
| Resource | Actions | Description |
|
|
210
|
+
| ---------- | ------------------------------------------- | ------------------ |
|
|
211
|
+
| `projects` | `list`, `get` | Project management |
|
|
212
|
+
| `time` | `list`, `get`, `create`, `update`, `delete` | Time tracking |
|
|
213
|
+
| `tasks` | `list`, `get` | Task management |
|
|
214
|
+
| `services` | `list` | Budget line items |
|
|
215
|
+
| `people` | `list`, `get`, `me` | Team members |
|
|
213
216
|
|
|
214
217
|
### Parameters
|
|
215
218
|
|
|
216
|
-
| Parameter
|
|
217
|
-
|
|
218
|
-
| `resource`
|
|
219
|
-
| `action`
|
|
220
|
-
| `id`
|
|
221
|
-
| `filter`
|
|
222
|
-
| `page`
|
|
223
|
-
| `per_page`
|
|
224
|
-
| `compact`
|
|
225
|
-
| `person_id`
|
|
226
|
-
| `service_id` | string
|
|
227
|
-
| `time`
|
|
228
|
-
| `date`
|
|
229
|
-
| `note`
|
|
219
|
+
| Parameter | Type | Description |
|
|
220
|
+
| ------------ | ------- | ----------------------------------------------------------------------- |
|
|
221
|
+
| `resource` | string | **Required**. One of: `projects`, `time`, `tasks`, `services`, `people` |
|
|
222
|
+
| `action` | string | **Required**. Action to perform (see table above) |
|
|
223
|
+
| `id` | string | Resource ID (required for `get`, `update`, `delete`) |
|
|
224
|
+
| `filter` | object | Filter criteria for `list` actions |
|
|
225
|
+
| `page` | number | Page number for pagination |
|
|
226
|
+
| `per_page` | number | Items per page (default: 20, max: 200) |
|
|
227
|
+
| `compact` | boolean | Compact output mode (default: true) |
|
|
228
|
+
| `person_id` | string | Person ID (for time entry creation) |
|
|
229
|
+
| `service_id` | string | Service ID (for time entry creation) |
|
|
230
|
+
| `time` | number | Time in minutes (for time entries) |
|
|
231
|
+
| `date` | string | Date in YYYY-MM-DD format |
|
|
232
|
+
| `note` | string | Note/description |
|
|
230
233
|
|
|
231
234
|
### Filter Options
|
|
232
235
|
|
|
233
236
|
#### Projects
|
|
237
|
+
|
|
234
238
|
- `company_id` - Filter by company
|
|
235
239
|
- `project_manager_id` - Filter by project manager
|
|
236
240
|
|
|
237
241
|
#### Time Entries
|
|
242
|
+
|
|
238
243
|
- `person_id` - Filter by person
|
|
239
244
|
- `project_id` - Filter by project
|
|
240
245
|
- `service_id` - Filter by service
|
|
@@ -242,23 +247,26 @@ productive(resource, action, ...)
|
|
|
242
247
|
- `before` - Before date (YYYY-MM-DD)
|
|
243
248
|
|
|
244
249
|
#### Tasks
|
|
250
|
+
|
|
245
251
|
- `project_id` - Filter by project
|
|
246
252
|
- `assignee_id` - Filter by assignee
|
|
247
253
|
- `task_list_id` - Filter by task list
|
|
248
254
|
|
|
249
255
|
#### Services
|
|
256
|
+
|
|
250
257
|
- `project_id` - Filter by project
|
|
251
258
|
- `deal_id` - Filter by deal
|
|
252
259
|
|
|
253
260
|
#### People
|
|
261
|
+
|
|
254
262
|
- `archived` - Include archived (boolean)
|
|
255
263
|
|
|
256
264
|
### Configuration Tools (Local mode only)
|
|
257
265
|
|
|
258
|
-
| Tool
|
|
259
|
-
|
|
260
|
-
| `productive_configure`
|
|
261
|
-
| `productive_get_config` | View current configuration (token masked)
|
|
266
|
+
| Tool | Description |
|
|
267
|
+
| ----------------------- | -------------------------------------------------------- |
|
|
268
|
+
| `productive_configure` | Configure credentials (organizationId, apiToken, userId) |
|
|
269
|
+
| `productive_get_config` | View current configuration (token masked) |
|
|
262
270
|
|
|
263
271
|
---
|
|
264
272
|
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GACpC,qBAAqB,GAAG,IAAI,CAkC9B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,qBAAqB,GAAG,MAAM,CAM1E"}
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sources":["../src/auth.ts"],"sourcesContent":["/**\n * Authentication utilities for Productive MCP server\n */\n\nexport interface ProductiveCredentials {\n organizationId: string;\n apiToken: string;\n userId?: string;\n}\n\n/**\n * Parse Bearer token containing Productive credentials\n * Token format: base64(organizationId:apiToken) or base64(organizationId:apiToken:userId)\n *\n * @param authHeader - Authorization header value (e.g., \"Bearer base64...\")\n * @returns Parsed credentials or null if invalid\n */\nexport function parseAuthHeader(authHeader: string | undefined | null): ProductiveCredentials | null {\n if (!authHeader) {\n return null;\n }\n\n const match = authHeader.match(/^Bearer\\s+(.+)$/i);\n if (!match) {\n return null;\n }\n\n const token = match[1];\n\n try {\n const decoded = Buffer.from(token, 'base64').toString('utf-8');\n const parts = decoded.split(':');\n\n if (parts.length < 2) {\n return null;\n }\n\n const [organizationId, apiToken, userId] = parts;\n\n if (!organizationId || !apiToken) {\n return null;\n }\n\n return {\n organizationId,\n apiToken,\n userId: userId || undefined,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Create a Bearer token from Productive credentials\n * Useful for documentation and testing\n *\n * @param credentials - Productive credentials\n * @returns Base64 encoded token (without \"Bearer \" prefix)\n */\nexport function createAuthToken(credentials: ProductiveCredentials): string {\n const parts = [credentials.organizationId, credentials.apiToken];\n if (credentials.userId) {\n parts.push(credentials.userId);\n }\n return Buffer.from(parts.join(':')).toString('base64');\n}\n"],"names":[],"mappings":"AAiBO,SAAS,
|
|
1
|
+
{"version":3,"file":"auth.js","sources":["../src/auth.ts"],"sourcesContent":["/**\n * Authentication utilities for Productive MCP server\n */\n\nexport interface ProductiveCredentials {\n organizationId: string;\n apiToken: string;\n userId?: string;\n}\n\n/**\n * Parse Bearer token containing Productive credentials\n * Token format: base64(organizationId:apiToken) or base64(organizationId:apiToken:userId)\n *\n * @param authHeader - Authorization header value (e.g., \"Bearer base64...\")\n * @returns Parsed credentials or null if invalid\n */\nexport function parseAuthHeader(\n authHeader: string | undefined | null,\n): ProductiveCredentials | null {\n if (!authHeader) {\n return null;\n }\n\n const match = authHeader.match(/^Bearer\\s+(.+)$/i);\n if (!match) {\n return null;\n }\n\n const token = match[1];\n\n try {\n const decoded = Buffer.from(token, 'base64').toString('utf-8');\n const parts = decoded.split(':');\n\n if (parts.length < 2) {\n return null;\n }\n\n const [organizationId, apiToken, userId] = parts;\n\n if (!organizationId || !apiToken) {\n return null;\n }\n\n return {\n organizationId,\n apiToken,\n userId: userId || undefined,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Create a Bearer token from Productive credentials\n * Useful for documentation and testing\n *\n * @param credentials - Productive credentials\n * @returns Base64 encoded token (without \"Bearer \" prefix)\n */\nexport function createAuthToken(credentials: ProductiveCredentials): string {\n const parts = [credentials.organizationId, credentials.apiToken];\n if (credentials.userId) {\n parts.push(credentials.userId);\n }\n return Buffer.from(parts.join(':')).toString('base64');\n}\n"],"names":[],"mappings":"AAiBO,SAAS,gBACd,YAC8B;AAC9B,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,WAAW,MAAM,kBAAkB;AACjD,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,MAAM,CAAC;AAErB,MAAI;AACF,UAAM,UAAU,OAAO,KAAK,OAAO,QAAQ,EAAE,SAAS,OAAO;AAC7D,UAAM,QAAQ,QAAQ,MAAM,GAAG;AAE/B,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO;AAAA,IACT;AAEA,UAAM,CAAC,gBAAgB,UAAU,MAAM,IAAI;AAE3C,QAAI,CAAC,kBAAkB,CAAC,UAAU;AAChC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,QAAQ,UAAU;AAAA,IAAA;AAAA,EAEtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASO,SAAS,gBAAgB,aAA4C;AAC1E,QAAM,QAAQ,CAAC,YAAY,gBAAgB,YAAY,QAAQ;AAC/D,MAAI,YAAY,QAAQ;AACtB,UAAM,KAAK,YAAY,MAAM;AAAA,EAC/B;AACA,SAAO,OAAO,KAAK,MAAM,KAAK,GAAG,CAAC,EAAE,SAAS,QAAQ;AACvD;"}
|
package/dist/crypto.js
CHANGED
|
@@ -37,7 +37,7 @@ function decrypt(ciphertext, secret = getSecret()) {
|
|
|
37
37
|
);
|
|
38
38
|
const encrypted = combined.subarray(SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH);
|
|
39
39
|
const key = deriveKey(secret, salt);
|
|
40
|
-
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
40
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });
|
|
41
41
|
decipher.setAuthTag(authTag);
|
|
42
42
|
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
43
43
|
return decrypted.toString("utf8");
|
package/dist/crypto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.js","sources":["../src/crypto.ts"],"sourcesContent":["/**\n * Cryptographic utilities for stateless OAuth tokens\n *\n * Uses AES-256-GCM for authenticated encryption.\n * The authorization code contains encrypted credentials that can be\n * decrypted without server-side storage.\n */\n\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst ALGORITHM = 'aes-256-gcm';\nconst IV_LENGTH = 12; // GCM recommended IV length\nconst AUTH_TAG_LENGTH = 16;\nconst SALT_LENGTH = 16;\n\n/**\n * Derive a 256-bit key from a password using scrypt\n */\nfunction deriveKey(password: string, salt: Buffer): Buffer {\n return scryptSync(password, salt, 32);\n}\n\n/**\n * Get the encryption secret from environment or generate a default\n * In production, OAUTH_SECRET should always be set\n */\nexport function getSecret(): string {\n const secret = process.env.OAUTH_SECRET;\n if (!secret) {\n console.warn(\n 'WARNING: OAUTH_SECRET not set. Using default secret. Set OAUTH_SECRET in production!'
|
|
1
|
+
{"version":3,"file":"crypto.js","sources":["../src/crypto.ts"],"sourcesContent":["/**\n * Cryptographic utilities for stateless OAuth tokens\n *\n * Uses AES-256-GCM for authenticated encryption.\n * The authorization code contains encrypted credentials that can be\n * decrypted without server-side storage.\n */\n\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\n\nconst ALGORITHM = 'aes-256-gcm';\nconst IV_LENGTH = 12; // GCM recommended IV length\nconst AUTH_TAG_LENGTH = 16;\nconst SALT_LENGTH = 16;\n\n/**\n * Derive a 256-bit key from a password using scrypt\n */\nfunction deriveKey(password: string, salt: Buffer): Buffer {\n return scryptSync(password, salt, 32);\n}\n\n/**\n * Get the encryption secret from environment or generate a default\n * In production, OAUTH_SECRET should always be set\n */\nexport function getSecret(): string {\n const secret = process.env.OAUTH_SECRET;\n if (!secret) {\n console.warn(\n 'WARNING: OAUTH_SECRET not set. Using default secret. Set OAUTH_SECRET in production!',\n );\n return 'productive-mcp-default-secret-change-me';\n }\n return secret;\n}\n\n/**\n * Encrypt data using AES-256-GCM\n *\n * Output format: base64(salt + iv + authTag + ciphertext)\n *\n * @param plaintext - Data to encrypt\n * @param secret - Encryption secret (defaults to OAUTH_SECRET env var)\n * @returns Base64-encoded encrypted data\n */\nexport function encrypt(plaintext: string, secret: string = getSecret()): string {\n const salt = randomBytes(SALT_LENGTH);\n const key = deriveKey(secret, salt);\n const iv = randomBytes(IV_LENGTH);\n\n const cipher = createCipheriv(ALGORITHM, key, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n // Combine: salt + iv + authTag + ciphertext\n const combined = Buffer.concat([salt, iv, authTag, encrypted]);\n\n return combined.toString('base64url');\n}\n\n/**\n * Decrypt data encrypted with encrypt()\n *\n * @param ciphertext - Base64-encoded encrypted data\n * @param secret - Encryption secret (defaults to OAUTH_SECRET env var)\n * @returns Decrypted plaintext\n * @throws Error if decryption fails (invalid data or wrong secret)\n */\nexport function decrypt(ciphertext: string, secret: string = getSecret()): string {\n try {\n const combined = Buffer.from(ciphertext, 'base64url');\n\n // Extract components\n const salt = combined.subarray(0, SALT_LENGTH);\n const iv = combined.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);\n const authTag = combined.subarray(\n SALT_LENGTH + IV_LENGTH,\n SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH,\n );\n const encrypted = combined.subarray(SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH);\n\n const key = deriveKey(secret, salt);\n\n const decipher = createDecipheriv(ALGORITHM, key, iv, { authTagLength: AUTH_TAG_LENGTH });\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);\n\n return decrypted.toString('utf8');\n } catch {\n throw new Error('Decryption failed: invalid token or secret');\n }\n}\n\n/**\n * Authorization code payload structure\n */\nexport interface AuthCodePayload {\n orgId: string;\n apiToken: string;\n userId?: string;\n codeChallenge?: string;\n codeChallengeMethod?: string;\n}\n\n/**\n * Create an encrypted authorization code containing credentials and PKCE challenge\n *\n * @param credentials - Object with orgId, apiToken, userId, and optional PKCE params\n * @param expiresInSeconds - Code expiration time (default: 5 minutes)\n * @returns Encrypted authorization code\n */\nexport function createAuthCode(\n credentials: AuthCodePayload,\n expiresInSeconds: number = 300,\n): string {\n const payload = {\n ...credentials,\n exp: Date.now() + expiresInSeconds * 1000,\n };\n return encrypt(JSON.stringify(payload));\n}\n\n/**\n * Decode and validate an authorization code\n *\n * @param code - Encrypted authorization code\n * @returns Decoded payload with credentials and PKCE challenge\n * @throws Error if code is invalid or expired\n */\nexport function decodeAuthCode(code: string): AuthCodePayload {\n const payload = JSON.parse(decrypt(code));\n\n if (payload.exp && Date.now() > payload.exp) {\n throw new Error('Authorization code expired');\n }\n\n const { orgId, apiToken, userId, codeChallenge, codeChallengeMethod } = payload;\n\n if (!orgId || !apiToken) {\n throw new Error('Invalid authorization code: missing credentials');\n }\n\n return { orgId, apiToken, userId, codeChallenge, codeChallengeMethod };\n}\n"],"names":[],"mappings":";AAUA,MAAM,YAAY;AAClB,MAAM,YAAY;AAClB,MAAM,kBAAkB;AACxB,MAAM,cAAc;AAKpB,SAAS,UAAU,UAAkB,MAAsB;AACzD,SAAO,WAAW,UAAU,MAAM,EAAE;AACtC;AAMO,SAAS,YAAoB;AAClC,QAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,CAAC,QAAQ;AACX,YAAQ;AAAA,MACN;AAAA,IAAA;AAEF,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAWO,SAAS,QAAQ,WAAmB,SAAiB,aAAqB;AAC/E,QAAM,OAAO,YAAY,WAAW;AACpC,QAAM,MAAM,UAAU,QAAQ,IAAI;AAClC,QAAM,KAAK,YAAY,SAAS;AAEhC,QAAM,SAAS,eAAe,WAAW,KAAK,EAAE;AAChD,QAAM,YAAY,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,MAAM,GAAG,OAAO,MAAA,CAAO,CAAC;AAClF,QAAM,UAAU,OAAO,WAAA;AAGvB,QAAM,WAAW,OAAO,OAAO,CAAC,MAAM,IAAI,SAAS,SAAS,CAAC;AAE7D,SAAO,SAAS,SAAS,WAAW;AACtC;AAUO,SAAS,QAAQ,YAAoB,SAAiB,aAAqB;AAChF,MAAI;AACF,UAAM,WAAW,OAAO,KAAK,YAAY,WAAW;AAGpD,UAAM,OAAO,SAAS,SAAS,GAAG,WAAW;AAC7C,UAAM,KAAK,SAAS,SAAS,aAAa,cAAc,SAAS;AACjE,UAAM,UAAU,SAAS;AAAA,MACvB,cAAc;AAAA,MACd,cAAc,YAAY;AAAA,IAAA;AAE5B,UAAM,YAAY,SAAS,SAAS,cAAc,YAAY,eAAe;AAE7E,UAAM,MAAM,UAAU,QAAQ,IAAI;AAElC,UAAM,WAAW,iBAAiB,WAAW,KAAK,IAAI,EAAE,eAAe,iBAAiB;AACxF,aAAS,WAAW,OAAO;AAE3B,UAAM,YAAY,OAAO,OAAO,CAAC,SAAS,OAAO,SAAS,GAAG,SAAS,MAAA,CAAO,CAAC;AAE9E,WAAO,UAAU,SAAS,MAAM;AAAA,EAClC,QAAQ;AACN,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACF;AAoBO,SAAS,eACd,aACA,mBAA2B,KACnB;AACR,QAAM,UAAU;AAAA,IACd,GAAG;AAAA,IACH,KAAK,KAAK,IAAA,IAAQ,mBAAmB;AAAA,EAAA;AAEvC,SAAO,QAAQ,KAAK,UAAU,OAAO,CAAC;AACxC;AASO,SAAS,eAAe,MAA+B;AAC5D,QAAM,UAAU,KAAK,MAAM,QAAQ,IAAI,CAAC;AAExC,MAAI,QAAQ,OAAO,KAAK,IAAA,IAAQ,QAAQ,KAAK;AAC3C,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAEA,QAAM,EAAE,OAAO,UAAU,QAAQ,eAAe,wBAAwB;AAExE,MAAI,CAAC,SAAS,CAAC,UAAU;AACvB,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEA,SAAO,EAAE,OAAO,UAAU,QAAQ,eAAe,oBAAA;AACnD;"}
|
package/dist/formatters.d.ts
CHANGED
|
@@ -37,6 +37,26 @@ export declare function formatPerson(person: JsonApiResource, options?: McpForma
|
|
|
37
37
|
* Format service for agent consumption
|
|
38
38
|
*/
|
|
39
39
|
export declare function formatService(service: JsonApiResource, options?: McpFormatOptions): Record<string, unknown>;
|
|
40
|
+
/**
|
|
41
|
+
* Format company for agent consumption
|
|
42
|
+
*/
|
|
43
|
+
export declare function formatCompany(company: JsonApiResource, options?: McpFormatOptions): Record<string, unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* Format comment for agent consumption
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatComment(comment: JsonApiResource, options?: McpFormatOptions): Record<string, unknown>;
|
|
48
|
+
/**
|
|
49
|
+
* Format timer for agent consumption
|
|
50
|
+
*/
|
|
51
|
+
export declare function formatTimer(timer: JsonApiResource, _options?: McpFormatOptions): Record<string, unknown>;
|
|
52
|
+
/**
|
|
53
|
+
* Format deal for agent consumption
|
|
54
|
+
*/
|
|
55
|
+
export declare function formatDeal(deal: JsonApiResource, options?: McpFormatOptions): Record<string, unknown>;
|
|
56
|
+
/**
|
|
57
|
+
* Format booking for agent consumption
|
|
58
|
+
*/
|
|
59
|
+
export declare function formatBooking(booking: JsonApiResource, options?: McpFormatOptions): Record<string, unknown>;
|
|
40
60
|
/**
|
|
41
61
|
* Format list response with pagination
|
|
42
62
|
*
|
package/dist/formatters.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAYL,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACzB,MAAM,4BAA4B,CAAC;AAGpC,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,mBAAmB,EAAE,CAAC;AAcjF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;CAC9B;AAaD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAazB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGzB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,eAAe,EACtB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGzB;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,IAAI,EAAE,eAAe,EAAE,EACvB,SAAS,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,gBAAgB,KAAK,CAAC,EACnE,IAAI,CAAC,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,gBAAgB,GACzB;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,mBAAmB,CAAA;CAAE,CAY3C"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bookings resource handler
|
|
3
|
+
*/
|
|
4
|
+
import type { HandlerContext, BookingArgs, ToolResult } from './types.js';
|
|
5
|
+
export declare function handleBookings(action: string, args: BookingArgs, ctx: HandlerContext): Promise<ToolResult>;
|
|
6
|
+
//# sourceMappingURL=bookings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bookings.d.ts","sourceRoot":"","sources":["../../src/handlers/bookings.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAK1E,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CAmDrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comments resource handler
|
|
3
|
+
*/
|
|
4
|
+
import type { HandlerContext, CommentArgs, ToolResult } from './types.js';
|
|
5
|
+
export declare function handleComments(action: string, args: CommentArgs, ctx: HandlerContext): Promise<ToolResult>;
|
|
6
|
+
//# sourceMappingURL=comments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../src/handlers/comments.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAK1E,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CA0CrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Companies resource handler
|
|
3
|
+
*/
|
|
4
|
+
import type { HandlerContext, CompanyArgs, ToolResult } from './types.js';
|
|
5
|
+
export declare function handleCompanies(action: string, args: CompanyArgs, ctx: HandlerContext): Promise<ToolResult>;
|
|
6
|
+
//# sourceMappingURL=companies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companies.d.ts","sourceRoot":"","sources":["../../src/handlers/companies.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAK1E,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CA8BrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deals.d.ts","sourceRoot":"","sources":["../../src/handlers/deals.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKvE,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CA0CrB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool execution handlers for Productive MCP server
|
|
3
|
+
* These are shared between stdio and HTTP transports
|
|
4
|
+
*
|
|
5
|
+
* Single consolidated tool for minimal token overhead:
|
|
6
|
+
* - productive: resource + action based API
|
|
7
|
+
*/
|
|
8
|
+
import type { ProductiveCredentials } from '../auth.js';
|
|
9
|
+
import type { ToolResult } from './types.js';
|
|
10
|
+
export type { ToolResult } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Execute a tool with the given credentials and arguments
|
|
13
|
+
*/
|
|
14
|
+
export declare function executeToolWithCredentials(name: string, args: Record<string, unknown>, credentials: ProductiveCredentials): Promise<ToolResult>;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,YAAY,CAAC;AAgB7D,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA2C7C;;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,CA4ErB"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* People resource handler
|
|
3
|
+
*/
|
|
4
|
+
import type { ProductiveCredentials } from '../auth.js';
|
|
5
|
+
import type { HandlerContext, CommonArgs, ToolResult } from './types.js';
|
|
6
|
+
export declare function handlePeople(action: string, args: CommonArgs, ctx: HandlerContext, credentials: ProductiveCredentials): Promise<ToolResult>;
|
|
7
|
+
//# sourceMappingURL=people.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"people.d.ts","sourceRoot":"","sources":["../../src/handlers/people.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKzE,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,cAAc,EACnB,WAAW,EAAE,qBAAqB,GACjC,OAAO,CAAC,UAAU,CAAC,CA2BrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projects resource handler
|
|
3
|
+
*/
|
|
4
|
+
import type { HandlerContext, CommonArgs, ToolResult } from './types.js';
|
|
5
|
+
export declare function handleProjects(action: string, args: CommonArgs, ctx: HandlerContext): Promise<ToolResult>;
|
|
6
|
+
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKzE,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CAgBrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Services resource handler
|
|
3
|
+
*/
|
|
4
|
+
import type { HandlerContext, CommonArgs, ToolResult } from './types.js';
|
|
5
|
+
export declare function handleServices(action: string, _args: CommonArgs, ctx: HandlerContext): Promise<ToolResult>;
|
|
6
|
+
//# sourceMappingURL=services.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/handlers/services.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKzE,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CASrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/handlers/tasks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKvE,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CA8CrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../../src/handlers/time.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKzE,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CAyCrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../../src/handlers/timers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKxE,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,EACf,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CA8BrB"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for resource handlers
|
|
3
|
+
*/
|
|
4
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import type { ProductiveApi } from '@studiometa/productive-cli';
|
|
6
|
+
import type { McpFormatOptions } from '../formatters.js';
|
|
7
|
+
export type ToolResult = CallToolResult;
|
|
8
|
+
/**
|
|
9
|
+
* Context passed to each resource handler
|
|
10
|
+
*/
|
|
11
|
+
export interface HandlerContext {
|
|
12
|
+
api: ProductiveApi;
|
|
13
|
+
formatOptions: McpFormatOptions;
|
|
14
|
+
filter?: Record<string, string>;
|
|
15
|
+
page?: number;
|
|
16
|
+
perPage: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Common args shared across resources
|
|
20
|
+
*/
|
|
21
|
+
export interface CommonArgs {
|
|
22
|
+
id?: string;
|
|
23
|
+
person_id?: string;
|
|
24
|
+
service_id?: string;
|
|
25
|
+
task_id?: string;
|
|
26
|
+
company_id?: string;
|
|
27
|
+
time?: number;
|
|
28
|
+
date?: string;
|
|
29
|
+
note?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Task-specific args
|
|
33
|
+
*/
|
|
34
|
+
export interface TaskArgs extends CommonArgs {
|
|
35
|
+
title?: string;
|
|
36
|
+
project_id?: string;
|
|
37
|
+
task_list_id?: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
assignee_id?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Comment-specific args
|
|
43
|
+
*/
|
|
44
|
+
export interface CommentArgs extends CommonArgs {
|
|
45
|
+
body?: string;
|
|
46
|
+
deal_id?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Timer-specific args
|
|
50
|
+
*/
|
|
51
|
+
export interface TimerArgs extends CommonArgs {
|
|
52
|
+
time_entry_id?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Deal-specific args
|
|
56
|
+
*/
|
|
57
|
+
export interface DealArgs extends CommonArgs {
|
|
58
|
+
name?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Booking-specific args
|
|
62
|
+
*/
|
|
63
|
+
export interface BookingArgs extends CommonArgs {
|
|
64
|
+
started_on?: string;
|
|
65
|
+
ended_on?: string;
|
|
66
|
+
event_id?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Company-specific args
|
|
70
|
+
*/
|
|
71
|
+
export interface CompanyArgs extends CommonArgs {
|
|
72
|
+
name?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resource handler function signature
|
|
76
|
+
*/
|
|
77
|
+
export type ResourceHandler<T extends CommonArgs = CommonArgs> = (action: string, args: T, ctx: HandlerContext) => Promise<ToolResult>;
|
|
78
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/handlers/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,MAAM,MAAM,UAAU,GAAG,cAAc,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,aAAa,CAAC;IACnB,aAAa,EAAE,gBAAgB,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,SAAU,SAAQ,UAAU;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,IAAI,CAC/D,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,CAAC,EACP,GAAG,EAAE,cAAc,KAChB,OAAO,CAAC,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for resource handlers
|
|
3
|
+
*/
|
|
4
|
+
import type { ToolResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Helper to create a successful JSON response
|
|
7
|
+
*/
|
|
8
|
+
export declare function jsonResult(data: unknown): ToolResult;
|
|
9
|
+
/**
|
|
10
|
+
* Helper to create an error response
|
|
11
|
+
*/
|
|
12
|
+
export declare function errorResult(message: string): ToolResult;
|
|
13
|
+
/**
|
|
14
|
+
* Convert unknown filter to string filter for API
|
|
15
|
+
*/
|
|
16
|
+
export declare function toStringFilter(filter?: Record<string, unknown>): Record<string, string> | undefined;
|
|
17
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/handlers/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAIpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAKvD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CASpC"}
|
package/dist/handlers.d.ts
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool execution handlers for Productive MCP server
|
|
3
|
-
* These are shared between stdio and HTTP transports
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* This module re-exports from the handlers/ directory for backwards compatibility.
|
|
5
|
+
* The handlers have been refactored into separate modules for better maintainability.
|
|
7
6
|
*/
|
|
8
|
-
|
|
9
|
-
import type { ProductiveCredentials } from './auth.js';
|
|
10
|
-
export type ToolResult = CallToolResult;
|
|
11
|
-
/**
|
|
12
|
-
* Execute a tool with the given credentials and arguments
|
|
13
|
-
*/
|
|
14
|
-
export declare function executeToolWithCredentials(name: string, args: Record<string, unknown>, credentials: ProductiveCredentials): Promise<ToolResult>;
|
|
7
|
+
export { executeToolWithCredentials, type ToolResult } from './handlers/index.js';
|
|
15
8
|
//# sourceMappingURL=handlers.d.ts.map
|
package/dist/handlers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,0BAA0B,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
|