@studiometa/productive-mcp 0.10.16 → 0.10.17
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-Ca2x4dM8.js → handlers-Dk4AQQ3K.js} +6 -2
- package/dist/{handlers-Ca2x4dM8.js.map → handlers-Dk4AQQ3K.js.map} +1 -1
- package/dist/handlers.js +1 -1
- package/dist/{http-xNZOdN_t.js → http-B7M9meAw.js} +4 -4
- package/dist/{http-xNZOdN_t.js.map → http-B7M9meAw.js.map} +1 -1
- package/dist/http.js +1 -1
- package/dist/index.js +2 -2
- package/dist/run/docs.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/{stdio-jqfOnE6-.js → stdio-DlulXg7G.js} +2 -2
- package/dist/{stdio-jqfOnE6-.js.map → stdio-DlulXg7G.js.map} +1 -1
- package/dist/stdio.js +1 -1
- package/dist/{version-Jj_0Ypf8.js → version-C8z9HRGX.js} +3 -3
- package/dist/{version-Jj_0Ypf8.js.map → version-C8z9HRGX.js.map} +1 -1
- package/package.json +3 -3
package/dist/http.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as handleToolsList, i as handleInitialize, n as createHttpMcpServer, o as jsonRpcError, r as createHttpMcpTransport, s as jsonRpcSuccess, t as createHttpApp } from "./http-
|
|
1
|
+
import { a as handleToolsList, i as handleInitialize, n as createHttpMcpServer, o as jsonRpcError, r as createHttpMcpTransport, s as jsonRpcSuccess, t as createHttpApp } from "./http-B7M9meAw.js";
|
|
2
2
|
export { createHttpApp, createHttpMcpServer, createHttpMcpTransport, handleInitialize, handleToolsList, jsonRpcError, jsonRpcSuccess };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-
|
|
3
|
-
import { a as handlePrompt, n as getAvailableTools, s as handleToolCall, t as getAvailablePrompts } from "./stdio-
|
|
2
|
+
import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-C8z9HRGX.js";
|
|
3
|
+
import { a as handlePrompt, n as getAvailableTools, s as handleToolCall, t as getAvailablePrompts } from "./stdio-DlulXg7G.js";
|
|
4
4
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
package/dist/run/docs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/run/docs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,YAAY,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/run/docs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,YAAY,EAAE,UAAU,EA4HpC,CAAC;AAEF,+DAA+D;AAC/D,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAS3D"}
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as VERSION } from "./version-
|
|
3
|
-
import { t as createHttpApp } from "./http-
|
|
2
|
+
import { t as VERSION } from "./version-C8z9HRGX.js";
|
|
3
|
+
import { t as createHttpApp } from "./http-B7M9meAw.js";
|
|
4
4
|
import { toNodeHandler } from "h3";
|
|
5
5
|
import { createServer } from "node:http";
|
|
6
6
|
//#region src/server.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as executeToolWithCredentials } from "./handlers-
|
|
1
|
+
import { t as executeToolWithCredentials } from "./handlers-Dk4AQQ3K.js";
|
|
2
2
|
import { STDIO_ONLY_TOOLS, TOOLS } from "./tools.js";
|
|
3
3
|
import { getConfig, setConfig } from "@studiometa/productive-api";
|
|
4
4
|
//#region src/prompts/definitions.ts
|
|
@@ -354,4 +354,4 @@ async function handlePrompt(name, args) {
|
|
|
354
354
|
//#endregion
|
|
355
355
|
export { handlePrompt as a, handleGetConfigTool as i, getAvailableTools as n, handleSetupPrompt as o, handleConfigureTool as r, handleToolCall as s, getAvailablePrompts as t };
|
|
356
356
|
|
|
357
|
-
//# sourceMappingURL=stdio-
|
|
357
|
+
//# sourceMappingURL=stdio-DlulXg7G.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio-jqfOnE6-.js","names":[],"sources":["../src/prompts/definitions.ts","../src/prompts/handlers.ts","../src/stdio.ts"],"sourcesContent":["/**\n * MCP Prompt Template Definitions\n *\n * Prompt templates serve as guided conversation starters that instruct the LLM\n * which productive tool calls to make and how to format the output.\n */\n\nexport interface PromptArgument {\n name: string;\n description: string;\n required: boolean;\n}\n\nexport interface PromptDefinition {\n name: string;\n description: string;\n arguments: PromptArgument[];\n}\n\nexport const PROMPT_DEFINITIONS: PromptDefinition[] = [\n {\n name: 'end-of-day',\n description: 'Compose an end-of-day standup message based on your activity today',\n arguments: [\n {\n name: 'format',\n description: 'Output format: slack, email, or plain (default: plain)',\n required: false,\n },\n ],\n },\n {\n name: 'project-review',\n description: 'Analyze project health and status with budget, tasks, and timeline overview',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n ],\n },\n {\n name: 'plan-sprint',\n description: 'Help prioritize tasks for the next sprint based on open tasks and budget',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n ],\n },\n {\n name: 'weekly-report',\n description: 'Generate a polished weekly progress report',\n arguments: [\n {\n name: 'person',\n description: 'Person email or ID to report on (default: current user)',\n required: false,\n },\n {\n name: 'format',\n description: 'Output format: slack, email, or plain (default: plain)',\n required: false,\n },\n ],\n },\n {\n name: 'invoice-prep',\n description: 'Prepare a billing summary for a project within a date range',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n {\n name: 'from',\n description: 'Start date in YYYY-MM-DD format',\n required: true,\n },\n {\n name: 'to',\n description: 'End date in YYYY-MM-DD format',\n required: true,\n },\n ],\n },\n];\n","/**\n * MCP Prompt Template Handlers\n *\n * Returns messages arrays that instruct the LLM which productive tool calls to\n * make and how to format and present the output to the user.\n */\n\ntype PromptMessage = {\n role: string;\n content: { type: string; text: string };\n};\n\ntype PromptResult = {\n messages: PromptMessage[];\n};\n\n/**\n * Build the end-of-day standup prompt messages\n */\nfunction endOfDay(args?: Record<string, string>): PromptResult {\n const format = args?.format ?? 'plain';\n\n const formatInstruction =\n format === 'slack'\n ? 'Format the output as a Slack message using emoji bullets and bold text with *asterisks*.'\n : format === 'email'\n ? 'Format the output as a professional email with a subject line and proper greeting/closing.'\n : 'Format the output as a plain-text standup message with clear sections.';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please compose my end-of-day standup message.\n\nFirst, call the productive tool to gather today's activity:\n\\`\\`\\`json\n{ \"resource\": \"summaries\", \"action\": \"my_day\" }\n\\`\\`\\`\n\nThen compose a standup message with these sections:\n- **What I did today**: Summarize completed tasks and logged time by project\n- **What I'm working on tomorrow**: Any open/in-progress tasks from today\n- **Blockers**: Note any overdue tasks or items needing attention\n\n${formatInstruction}\n\nKeep it concise — this is for a standup, not a novel.`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the project-review prompt messages\n */\nfunction projectReview(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please analyze the health and status of project ${project ? `\"${project}\"` : '(project not specified)'}.\n\nFetch all project context in one call:\n\\`\\`\\`json\n{ \"resource\": \"projects\", \"action\": \"context\", \"id\": \"${project}\" }\n\\`\\`\\`\n\nAlso check the project's tasks for a fuller picture:\n\\`\\`\\`json\n{ \"resource\": \"tasks\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"status\": 1 }, \"per_page\": 50 }\n\\`\\`\\`\n\nThen provide a structured project health review covering:\n1. **Overview**: Project name, client, current status\n2. **Budget**: Budget used vs total, burn rate, projected overage risk\n3. **Tasks**: Open vs completed task counts, overdue tasks, upcoming deadlines\n4. **Recent activity**: What has been worked on recently\n5. **Health assessment**: Overall RAG status (🟢 On track / 🟡 At risk / 🔴 Critical) with reasoning\n6. **Recommendations**: Concrete next steps or concerns to address`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the plan-sprint prompt messages\n */\nfunction planSprint(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please help me plan the next sprint for project ${project ? `\"${project}\"` : '(project not specified)'}.\n\nFetch all open tasks for the project:\n\\`\\`\\`json\n{ \"resource\": \"tasks\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"status\": 1 }, \"per_page\": 100 }\n\\`\\`\\`\n\nFetch the project's budget services to understand available capacity:\n\\`\\`\\`json\n{ \"resource\": \"services\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\" }, \"per_page\": 50 }\n\\`\\`\\`\n\nThen provide sprint planning recommendations:\n1. **Backlog summary**: Total open tasks, categories/task-lists breakdown\n2. **Priority candidates**: Top tasks to tackle next sprint based on:\n - Due dates and overdue items\n - Task dependencies (if visible)\n - Effort estimates\n3. **Budget check**: Remaining budget per service — flag if any service is near its limit\n4. **Suggested sprint scope**: A realistic list of tasks for a 1-2 week sprint\n5. **Risks**: Tasks that are blocked, unassigned, or missing estimates`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the weekly-report prompt messages\n */\nfunction weeklyReport(args?: Record<string, string>): PromptResult {\n const person = args?.person;\n const format = args?.format ?? 'plain';\n\n const personInstruction = person\n ? `Focus on person \"${person}\". Resolve the person ID if needed using: { \"resource\": \"people\", \"action\": \"resolve\", \"query\": \"${person}\" } first.`\n : 'Focus on the current authenticated user (use the default person from summaries).';\n\n const formatInstruction =\n format === 'slack'\n ? 'Format as a Slack message with emoji bullets, bold project names, and a summary header.'\n : format === 'email'\n ? 'Format as a professional email with subject line, greeting, bulleted highlights per project, and a closing.'\n : 'Format as a clean plain-text weekly report with clear section headers.';\n\n const standupCall = person\n ? `First resolve the person ID, then fetch weekly standup data:\n\\`\\`\\`json\n{ \"resource\": \"people\", \"action\": \"resolve\", \"query\": \"${person}\" }\n\\`\\`\\`\n\\`\\`\\`json\n{ \"resource\": \"workflows\", \"action\": \"weekly_standup\", \"person_id\": \"<resolved_person_id>\" }\n\\`\\`\\``\n : `Fetch weekly standup data:\n\\`\\`\\`json\n{ \"resource\": \"workflows\", \"action\": \"weekly_standup\" }\n\\`\\`\\``;\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please generate a weekly progress report.\n\n${personInstruction}\n\n${standupCall}\n\nThen compose a polished weekly report with:\n1. **This week's accomplishments**: Completed tasks grouped by project\n2. **Time logged**: Hours per project this week, total hours\n3. **In progress**: Tasks still open that were worked on\n4. **Upcoming**: Any tasks with deadlines in the next 7 days\n5. **Highlights**: Notable wins or milestones reached\n\n${formatInstruction}`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the invoice-prep prompt messages\n */\nfunction invoicePrep(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n const from = args?.from ?? '';\n const to = args?.to ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please prepare a billing summary for project ${project ? `\"${project}\"` : '(project not specified)'} from ${from || '(start date not specified)'} to ${to || '(end date not specified)'}.\n\nFetch time entries for the date range:\n\\`\\`\\`json\n{\n \"resource\": \"time\",\n \"action\": \"list\",\n \"filter\": {\n \"project_id\": \"${project}\",\n \"after\": \"${from}\",\n \"before\": \"${to}\"\n },\n \"include\": [\"person\", \"service\"],\n \"per_page\": 200\n}\n\\`\\`\\`\n\nFetch project services/budget lines:\n\\`\\`\\`json\n{ \"resource\": \"services\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\" }, \"per_page\": 50 }\n\\`\\`\\`\n\nFetch the project deal/budget details:\n\\`\\`\\`json\n{ \"resource\": \"deals\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"type\": 2 }, \"per_page\": 10 }\n\\`\\`\\`\n\nThen produce a billing summary:\n1. **Period**: ${from} → ${to}\n2. **Time entries by service**: Hours logged per service/budget line with team member breakdown\n3. **Billable totals**: If rates are available, calculate amounts per service\n4. **Budget consumed**: Planned vs actual hours per service\n5. **Invoice line items**: Suggested line items ready to copy into an invoice\n6. **Notes**: Any unbilled items, write-offs, or adjustments to flag`,\n },\n },\n ],\n };\n}\n\n/**\n * Get messages for a named prompt template\n */\nexport function getPromptMessages(name: string, args?: Record<string, string>): PromptResult {\n switch (name) {\n case 'end-of-day':\n return endOfDay(args);\n case 'project-review':\n return projectReview(args);\n case 'plan-sprint':\n return planSprint(args);\n case 'weekly-report':\n return weeklyReport(args);\n case 'invoice-prep':\n return invoicePrep(args);\n default:\n throw new Error(`Unknown prompt: ${name}`);\n }\n}\n","/**\n * Stdio transport handlers for Productive MCP Server\n *\n * This module contains the handler logic for the stdio transport.\n * The actual server startup is in index.ts.\n */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { getConfig, setConfig } from '@studiometa/productive-api';\n\nimport { executeToolWithCredentials } from './handlers.js';\nimport { PROMPT_DEFINITIONS, getPromptMessages } from './prompts/index.js';\nimport { TOOLS, STDIO_ONLY_TOOLS } from './tools.js';\n\nexport type ToolResult = CallToolResult;\n\n/**\n * Get all available tools (including stdio-only configuration tools)\n */\nexport function getAvailableTools() {\n return [...TOOLS, ...STDIO_ONLY_TOOLS];\n}\n\n/**\n * Get available prompts\n */\nexport function getAvailablePrompts() {\n return [\n {\n name: 'setup_productive',\n description: 'Interactive setup for Productive.io credentials',\n arguments: [],\n },\n ...PROMPT_DEFINITIONS,\n ];\n}\n\n/**\n * Handle the setup_productive prompt\n */\nexport async function handleSetupPrompt(): Promise<{\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n}> {\n const config = await getConfig();\n const hasConfig = !!(config.organizationId && config.apiToken);\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: hasConfig\n ? 'I have already configured Productive.io credentials. Would you like to update them?'\n : 'I need to configure my Productive.io credentials. Please help me set up:\\n1. Organization ID\\n2. API Token\\n3. User ID (optional)',\n },\n },\n ],\n };\n}\n\n/**\n * Handle the productive_configure tool\n */\nexport async function handleConfigureTool(args: {\n organizationId: string;\n apiToken: string;\n userId?: string;\n}): Promise<ToolResult> {\n const { organizationId, apiToken, userId } = args;\n\n await setConfig('organizationId', organizationId);\n await setConfig('apiToken', apiToken);\n if (userId) {\n await setConfig('userId', userId);\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Productive.io credentials configured successfully',\n configured: {\n organizationId,\n userId: userId || 'not set',\n apiToken: '***' + apiToken.slice(-4),\n },\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle the productive_get_config tool\n */\nexport async function handleGetConfigTool(): Promise<ToolResult> {\n const currentConfig = await getConfig();\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n organizationId: currentConfig.organizationId || 'not configured',\n userId: currentConfig.userId || 'not configured',\n apiToken: currentConfig.apiToken\n ? '***' + currentConfig.apiToken.slice(-4)\n : 'not configured',\n configured: !!(currentConfig.organizationId && currentConfig.apiToken),\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle a tool call request\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n): Promise<ToolResult> {\n // Handle stdio-only configuration tools\n if (name === 'productive_configure') {\n return handleConfigureTool(args as Parameters<typeof handleConfigureTool>[0]);\n }\n\n if (name === 'productive_get_config') {\n return handleGetConfigTool();\n }\n\n // Get config for API tools\n const config = await getConfig();\n if (!config.organizationId || !config.apiToken) {\n return {\n content: [\n {\n type: 'text',\n text: 'Error: Productive.io credentials not configured. Please use the \"productive_configure\" tool to set your credentials, or set PRODUCTIVE_ORG_ID and PRODUCTIVE_API_TOKEN environment variables.',\n },\n ],\n isError: true,\n };\n }\n\n // Execute tool with credentials from config\n return executeToolWithCredentials(name, args, {\n organizationId: config.organizationId,\n apiToken: config.apiToken,\n userId: config.userId,\n });\n}\n\n/**\n * Handle a prompt request\n */\nexport async function handlePrompt(\n name: string,\n args?: Record<string, string>,\n): Promise<{\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n}> {\n if (name === 'setup_productive') {\n return handleSetupPrompt();\n }\n\n return getPromptMessages(name, args);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stdio-DlulXg7G.js","names":[],"sources":["../src/prompts/definitions.ts","../src/prompts/handlers.ts","../src/stdio.ts"],"sourcesContent":["/**\n * MCP Prompt Template Definitions\n *\n * Prompt templates serve as guided conversation starters that instruct the LLM\n * which productive tool calls to make and how to format the output.\n */\n\nexport interface PromptArgument {\n name: string;\n description: string;\n required: boolean;\n}\n\nexport interface PromptDefinition {\n name: string;\n description: string;\n arguments: PromptArgument[];\n}\n\nexport const PROMPT_DEFINITIONS: PromptDefinition[] = [\n {\n name: 'end-of-day',\n description: 'Compose an end-of-day standup message based on your activity today',\n arguments: [\n {\n name: 'format',\n description: 'Output format: slack, email, or plain (default: plain)',\n required: false,\n },\n ],\n },\n {\n name: 'project-review',\n description: 'Analyze project health and status with budget, tasks, and timeline overview',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n ],\n },\n {\n name: 'plan-sprint',\n description: 'Help prioritize tasks for the next sprint based on open tasks and budget',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n ],\n },\n {\n name: 'weekly-report',\n description: 'Generate a polished weekly progress report',\n arguments: [\n {\n name: 'person',\n description: 'Person email or ID to report on (default: current user)',\n required: false,\n },\n {\n name: 'format',\n description: 'Output format: slack, email, or plain (default: plain)',\n required: false,\n },\n ],\n },\n {\n name: 'invoice-prep',\n description: 'Prepare a billing summary for a project within a date range',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n {\n name: 'from',\n description: 'Start date in YYYY-MM-DD format',\n required: true,\n },\n {\n name: 'to',\n description: 'End date in YYYY-MM-DD format',\n required: true,\n },\n ],\n },\n];\n","/**\n * MCP Prompt Template Handlers\n *\n * Returns messages arrays that instruct the LLM which productive tool calls to\n * make and how to format and present the output to the user.\n */\n\ntype PromptMessage = {\n role: string;\n content: { type: string; text: string };\n};\n\ntype PromptResult = {\n messages: PromptMessage[];\n};\n\n/**\n * Build the end-of-day standup prompt messages\n */\nfunction endOfDay(args?: Record<string, string>): PromptResult {\n const format = args?.format ?? 'plain';\n\n const formatInstruction =\n format === 'slack'\n ? 'Format the output as a Slack message using emoji bullets and bold text with *asterisks*.'\n : format === 'email'\n ? 'Format the output as a professional email with a subject line and proper greeting/closing.'\n : 'Format the output as a plain-text standup message with clear sections.';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please compose my end-of-day standup message.\n\nFirst, call the productive tool to gather today's activity:\n\\`\\`\\`json\n{ \"resource\": \"summaries\", \"action\": \"my_day\" }\n\\`\\`\\`\n\nThen compose a standup message with these sections:\n- **What I did today**: Summarize completed tasks and logged time by project\n- **What I'm working on tomorrow**: Any open/in-progress tasks from today\n- **Blockers**: Note any overdue tasks or items needing attention\n\n${formatInstruction}\n\nKeep it concise — this is for a standup, not a novel.`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the project-review prompt messages\n */\nfunction projectReview(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please analyze the health and status of project ${project ? `\"${project}\"` : '(project not specified)'}.\n\nFetch all project context in one call:\n\\`\\`\\`json\n{ \"resource\": \"projects\", \"action\": \"context\", \"id\": \"${project}\" }\n\\`\\`\\`\n\nAlso check the project's tasks for a fuller picture:\n\\`\\`\\`json\n{ \"resource\": \"tasks\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"status\": 1 }, \"per_page\": 50 }\n\\`\\`\\`\n\nThen provide a structured project health review covering:\n1. **Overview**: Project name, client, current status\n2. **Budget**: Budget used vs total, burn rate, projected overage risk\n3. **Tasks**: Open vs completed task counts, overdue tasks, upcoming deadlines\n4. **Recent activity**: What has been worked on recently\n5. **Health assessment**: Overall RAG status (🟢 On track / 🟡 At risk / 🔴 Critical) with reasoning\n6. **Recommendations**: Concrete next steps or concerns to address`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the plan-sprint prompt messages\n */\nfunction planSprint(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please help me plan the next sprint for project ${project ? `\"${project}\"` : '(project not specified)'}.\n\nFetch all open tasks for the project:\n\\`\\`\\`json\n{ \"resource\": \"tasks\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"status\": 1 }, \"per_page\": 100 }\n\\`\\`\\`\n\nFetch the project's budget services to understand available capacity:\n\\`\\`\\`json\n{ \"resource\": \"services\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\" }, \"per_page\": 50 }\n\\`\\`\\`\n\nThen provide sprint planning recommendations:\n1. **Backlog summary**: Total open tasks, categories/task-lists breakdown\n2. **Priority candidates**: Top tasks to tackle next sprint based on:\n - Due dates and overdue items\n - Task dependencies (if visible)\n - Effort estimates\n3. **Budget check**: Remaining budget per service — flag if any service is near its limit\n4. **Suggested sprint scope**: A realistic list of tasks for a 1-2 week sprint\n5. **Risks**: Tasks that are blocked, unassigned, or missing estimates`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the weekly-report prompt messages\n */\nfunction weeklyReport(args?: Record<string, string>): PromptResult {\n const person = args?.person;\n const format = args?.format ?? 'plain';\n\n const personInstruction = person\n ? `Focus on person \"${person}\". Resolve the person ID if needed using: { \"resource\": \"people\", \"action\": \"resolve\", \"query\": \"${person}\" } first.`\n : 'Focus on the current authenticated user (use the default person from summaries).';\n\n const formatInstruction =\n format === 'slack'\n ? 'Format as a Slack message with emoji bullets, bold project names, and a summary header.'\n : format === 'email'\n ? 'Format as a professional email with subject line, greeting, bulleted highlights per project, and a closing.'\n : 'Format as a clean plain-text weekly report with clear section headers.';\n\n const standupCall = person\n ? `First resolve the person ID, then fetch weekly standup data:\n\\`\\`\\`json\n{ \"resource\": \"people\", \"action\": \"resolve\", \"query\": \"${person}\" }\n\\`\\`\\`\n\\`\\`\\`json\n{ \"resource\": \"workflows\", \"action\": \"weekly_standup\", \"person_id\": \"<resolved_person_id>\" }\n\\`\\`\\``\n : `Fetch weekly standup data:\n\\`\\`\\`json\n{ \"resource\": \"workflows\", \"action\": \"weekly_standup\" }\n\\`\\`\\``;\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please generate a weekly progress report.\n\n${personInstruction}\n\n${standupCall}\n\nThen compose a polished weekly report with:\n1. **This week's accomplishments**: Completed tasks grouped by project\n2. **Time logged**: Hours per project this week, total hours\n3. **In progress**: Tasks still open that were worked on\n4. **Upcoming**: Any tasks with deadlines in the next 7 days\n5. **Highlights**: Notable wins or milestones reached\n\n${formatInstruction}`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the invoice-prep prompt messages\n */\nfunction invoicePrep(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n const from = args?.from ?? '';\n const to = args?.to ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please prepare a billing summary for project ${project ? `\"${project}\"` : '(project not specified)'} from ${from || '(start date not specified)'} to ${to || '(end date not specified)'}.\n\nFetch time entries for the date range:\n\\`\\`\\`json\n{\n \"resource\": \"time\",\n \"action\": \"list\",\n \"filter\": {\n \"project_id\": \"${project}\",\n \"after\": \"${from}\",\n \"before\": \"${to}\"\n },\n \"include\": [\"person\", \"service\"],\n \"per_page\": 200\n}\n\\`\\`\\`\n\nFetch project services/budget lines:\n\\`\\`\\`json\n{ \"resource\": \"services\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\" }, \"per_page\": 50 }\n\\`\\`\\`\n\nFetch the project deal/budget details:\n\\`\\`\\`json\n{ \"resource\": \"deals\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"type\": 2 }, \"per_page\": 10 }\n\\`\\`\\`\n\nThen produce a billing summary:\n1. **Period**: ${from} → ${to}\n2. **Time entries by service**: Hours logged per service/budget line with team member breakdown\n3. **Billable totals**: If rates are available, calculate amounts per service\n4. **Budget consumed**: Planned vs actual hours per service\n5. **Invoice line items**: Suggested line items ready to copy into an invoice\n6. **Notes**: Any unbilled items, write-offs, or adjustments to flag`,\n },\n },\n ],\n };\n}\n\n/**\n * Get messages for a named prompt template\n */\nexport function getPromptMessages(name: string, args?: Record<string, string>): PromptResult {\n switch (name) {\n case 'end-of-day':\n return endOfDay(args);\n case 'project-review':\n return projectReview(args);\n case 'plan-sprint':\n return planSprint(args);\n case 'weekly-report':\n return weeklyReport(args);\n case 'invoice-prep':\n return invoicePrep(args);\n default:\n throw new Error(`Unknown prompt: ${name}`);\n }\n}\n","/**\n * Stdio transport handlers for Productive MCP Server\n *\n * This module contains the handler logic for the stdio transport.\n * The actual server startup is in index.ts.\n */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { getConfig, setConfig } from '@studiometa/productive-api';\n\nimport { executeToolWithCredentials } from './handlers.js';\nimport { PROMPT_DEFINITIONS, getPromptMessages } from './prompts/index.js';\nimport { TOOLS, STDIO_ONLY_TOOLS } from './tools.js';\n\nexport type ToolResult = CallToolResult;\n\n/**\n * Get all available tools (including stdio-only configuration tools)\n */\nexport function getAvailableTools() {\n return [...TOOLS, ...STDIO_ONLY_TOOLS];\n}\n\n/**\n * Get available prompts\n */\nexport function getAvailablePrompts() {\n return [\n {\n name: 'setup_productive',\n description: 'Interactive setup for Productive.io credentials',\n arguments: [],\n },\n ...PROMPT_DEFINITIONS,\n ];\n}\n\n/**\n * Handle the setup_productive prompt\n */\nexport async function handleSetupPrompt(): Promise<{\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n}> {\n const config = await getConfig();\n const hasConfig = !!(config.organizationId && config.apiToken);\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: hasConfig\n ? 'I have already configured Productive.io credentials. Would you like to update them?'\n : 'I need to configure my Productive.io credentials. Please help me set up:\\n1. Organization ID\\n2. API Token\\n3. User ID (optional)',\n },\n },\n ],\n };\n}\n\n/**\n * Handle the productive_configure tool\n */\nexport async function handleConfigureTool(args: {\n organizationId: string;\n apiToken: string;\n userId?: string;\n}): Promise<ToolResult> {\n const { organizationId, apiToken, userId } = args;\n\n await setConfig('organizationId', organizationId);\n await setConfig('apiToken', apiToken);\n if (userId) {\n await setConfig('userId', userId);\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Productive.io credentials configured successfully',\n configured: {\n organizationId,\n userId: userId || 'not set',\n apiToken: '***' + apiToken.slice(-4),\n },\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle the productive_get_config tool\n */\nexport async function handleGetConfigTool(): Promise<ToolResult> {\n const currentConfig = await getConfig();\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n organizationId: currentConfig.organizationId || 'not configured',\n userId: currentConfig.userId || 'not configured',\n apiToken: currentConfig.apiToken\n ? '***' + currentConfig.apiToken.slice(-4)\n : 'not configured',\n configured: !!(currentConfig.organizationId && currentConfig.apiToken),\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle a tool call request\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n): Promise<ToolResult> {\n // Handle stdio-only configuration tools\n if (name === 'productive_configure') {\n return handleConfigureTool(args as Parameters<typeof handleConfigureTool>[0]);\n }\n\n if (name === 'productive_get_config') {\n return handleGetConfigTool();\n }\n\n // Get config for API tools\n const config = await getConfig();\n if (!config.organizationId || !config.apiToken) {\n return {\n content: [\n {\n type: 'text',\n text: 'Error: Productive.io credentials not configured. Please use the \"productive_configure\" tool to set your credentials, or set PRODUCTIVE_ORG_ID and PRODUCTIVE_API_TOKEN environment variables.',\n },\n ],\n isError: true,\n };\n }\n\n // Execute tool with credentials from config\n return executeToolWithCredentials(name, args, {\n organizationId: config.organizationId,\n apiToken: config.apiToken,\n userId: config.userId,\n });\n}\n\n/**\n * Handle a prompt request\n */\nexport async function handlePrompt(\n name: string,\n args?: Record<string, string>,\n): Promise<{\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n}> {\n if (name === 'setup_productive') {\n return handleSetupPrompt();\n }\n\n return getPromptMessages(name, args);\n}\n"],"mappings":";;;;AAmBA,IAAa,qBAAyC;CACpD;EACE,MAAM;EACN,aAAa;EACb,WAAW,CACT;GACE,MAAM;GACN,aAAa;GACb,UAAU;EACZ,CACF;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,WAAW,CACT;GACE,MAAM;GACN,aAAa;GACb,UAAU;EACZ,CACF;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,WAAW,CACT;GACE,MAAM;GACN,aAAa;GACb,UAAU;EACZ,CACF;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,WAAW,CACT;GACE,MAAM;GACN,aAAa;GACb,UAAU;EACZ,GACA;GACE,MAAM;GACN,aAAa;GACb,UAAU;EACZ,CACF;CACF;CACA;EACE,MAAM;EACN,aAAa;EACb,WAAW;GACT;IACE,MAAM;IACN,aAAa;IACb,UAAU;GACZ;GACA;IACE,MAAM;IACN,aAAa;IACb,UAAU;GACZ;GACA;IACE,MAAM;IACN,aAAa;IACb,UAAU;GACZ;EACF;CACF;AACF;;;;;;ACvEA,SAAS,SAAS,MAA6C;CAC7D,MAAM,SAAS,MAAM,UAAU;CAS/B,OAAO,EACL,UAAU,CACR;EACE,MAAM;EACN,SAAS;GACP,MAAM;GACN,MAAM;;;;;;;;;;;;EAZZ,WAAW,UACP,6FACA,WAAW,UACT,+FACA,yEAoBU;;;EAGZ;CACF,CACF,EACF;AACF;;;;AAKA,SAAS,cAAc,MAA6C;CAClE,MAAM,UAAU,MAAM,WAAW;CAEjC,OAAO,EACL,UAAU,CACR;EACE,MAAM;EACN,SAAS;GACP,MAAM;GACN,MAAM,mDAAmD,UAAU,IAAI,QAAQ,KAAK,0BAA0B;;;;wDAIhE,QAAQ;;;;;sEAKM,QAAQ;;;;;;;;;;EAUtE;CACF,CACF,EACF;AACF;;;;AAKA,SAAS,WAAW,MAA6C;CAC/D,MAAM,UAAU,MAAM,WAAW;CAEjC,OAAO,EACL,UAAU,CACR;EACE,MAAM;EACN,SAAS;GACP,MAAM;GACN,MAAM,mDAAmD,UAAU,IAAI,QAAQ,KAAK,0BAA0B;;;;sEAIlD,QAAQ;;;;;yEAKL,QAAQ;;;;;;;;;;;;EAYzE;CACF,CACF,EACF;AACF;;;;AAKA,SAAS,aAAa,MAA6C;CACjE,MAAM,SAAS,MAAM;CACrB,MAAM,SAAS,MAAM,UAAU;CAE/B,MAAM,oBAAoB,SACtB,oBAAoB,OAAO,mGAAmG,OAAO,cACrI;CAEJ,MAAM,oBACJ,WAAW,UACP,4FACA,WAAW,UACT,gHACA;CAeR,OAAO,EACL,UAAU,CACR;EACE,MAAM;EACN,SAAS;GACP,MAAM;GACN,MAAM;;EAEd,kBAAkB;;EArBE,SAChB;;yDAEmD,OAAO;;;;UAK1D;;;QAeQ;;;;;;;;;EASZ;EACM;CACF,CACF,EACF;AACF;;;;AAKA,SAAS,YAAY,MAA6C;CAChE,MAAM,UAAU,MAAM,WAAW;CACjC,MAAM,OAAO,MAAM,QAAQ;CAC3B,MAAM,KAAK,MAAM,MAAM;CAEvB,OAAO,EACL,UAAU,CACR;EACE,MAAM;EACN,SAAS;GACP,MAAM;GACN,MAAM,gDAAgD,UAAU,IAAI,QAAQ,KAAK,0BAA0B,QAAQ,QAAQ,6BAA6B,MAAM,MAAM,2BAA2B;;;;;;;;qBAQpL,QAAQ;gBACb,KAAK;iBACJ,GAAG;;;;;;;;;yEASqD,QAAQ;;;;;sEAKX,QAAQ;;;;iBAI7D,KAAK,KAAK,GAAG;;;;;;EAMtB;CACF,CACF,EACF;AACF;;;;AAKA,SAAgB,kBAAkB,MAAc,MAA6C;CAC3F,QAAQ,MAAR;EACE,KAAK,cACH,OAAO,SAAS,IAAI;EACtB,KAAK,kBACH,OAAO,cAAc,IAAI;EAC3B,KAAK,eACH,OAAO,WAAW,IAAI;EACxB,KAAK,iBACH,OAAO,aAAa,IAAI;EAC1B,KAAK,gBACH,OAAO,YAAY,IAAI;EACzB,SACE,MAAM,IAAI,MAAM,mBAAmB,MAAM;CAC7C;AACF;;;;;;ACjPA,SAAgB,oBAAoB;CAClC,OAAO,CAAC,GAAG,OAAO,GAAG,gBAAgB;AACvC;;;;AAKA,SAAgB,sBAAsB;CACpC,OAAO,CACL;EACE,MAAM;EACN,aAAa;EACb,WAAW,CAAC;CACd,GACA,GAAG,kBACL;AACF;;;;AAKA,eAAsB,oBAEnB;CACD,MAAM,SAAS,MAAM,UAAU;CAG/B,OAAO,EACL,UAAU,CACR;EACE,MAAM;EACN,SAAS;GACP,MAAM;GACN,MAAM,CARK,EAAE,OAAO,kBAAkB,OAAO,YASzC,wFACA;EACN;CACF,CACF,EACF;AACF;;;;AAKA,eAAsB,oBAAoB,MAIlB;CACtB,MAAM,EAAE,gBAAgB,UAAU,WAAW;CAE7C,MAAM,UAAU,kBAAkB,cAAc;CAChD,MAAM,UAAU,YAAY,QAAQ;CACpC,IAAI,QACF,MAAM,UAAU,UAAU,MAAM;CAGlC,OAAO,EACL,SAAS,CACP;EACE,MAAM;EACN,MAAM,KAAK,UACT;GACE,SAAS;GACT,SAAS;GACT,YAAY;IACV;IACA,QAAQ,UAAU;IAClB,UAAU,QAAQ,SAAS,MAAM,EAAE;GACrC;EACF,GACA,MACA,CACF;CACF,CACF,EACF;AACF;;;;AAKA,eAAsB,sBAA2C;CAC/D,MAAM,gBAAgB,MAAM,UAAU;CACtC,OAAO,EACL,SAAS,CACP;EACE,MAAM;EACN,MAAM,KAAK,UACT;GACE,gBAAgB,cAAc,kBAAkB;GAChD,QAAQ,cAAc,UAAU;GAChC,UAAU,cAAc,WACpB,QAAQ,cAAc,SAAS,MAAM,EAAE,IACvC;GACJ,YAAY,CAAC,EAAE,cAAc,kBAAkB,cAAc;EAC/D,GACA,MACA,CACF;CACF,CACF,EACF;AACF;;;;AAKA,eAAsB,eACpB,MACA,MACqB;CAErB,IAAI,SAAS,wBACX,OAAO,oBAAoB,IAAiD;CAG9E,IAAI,SAAS,yBACX,OAAO,oBAAoB;CAI7B,MAAM,SAAS,MAAM,UAAU;CAC/B,IAAI,CAAC,OAAO,kBAAkB,CAAC,OAAO,UACpC,OAAO;EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM;EACR,CACF;EACA,SAAS;CACX;CAIF,OAAO,2BAA2B,MAAM,MAAM;EAC5C,gBAAgB,OAAO;EACvB,UAAU,OAAO;EACjB,QAAQ,OAAO;CACjB,CAAC;AACH;;;;AAKA,eAAsB,aACpB,MACA,MAGC;CACD,IAAI,SAAS,oBACX,OAAO,kBAAkB;CAG3B,OAAO,kBAAkB,MAAM,IAAI;AACrC"}
|
package/dist/stdio.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as handlePrompt, i as handleGetConfigTool, n as getAvailableTools, o as handleSetupPrompt, r as handleConfigureTool, s as handleToolCall, t as getAvailablePrompts } from "./stdio-
|
|
1
|
+
import { a as handlePrompt, i as handleGetConfigTool, n as getAvailableTools, o as handleSetupPrompt, r as handleConfigureTool, s as handleToolCall, t as getAvailablePrompts } from "./stdio-DlulXg7G.js";
|
|
2
2
|
export { getAvailablePrompts, getAvailableTools, handleConfigureTool, handleGetConfigTool, handlePrompt, handleSetupPrompt, handleToolCall };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as handleSummaries, D as handlePeople, E as handleProjects, O as handleDeals, S as handleTasks, T as handleSchemaOverview, w as handleServices } from "./handlers-
|
|
1
|
+
import { C as handleSummaries, D as handlePeople, E as handleProjects, O as handleDeals, S as handleTasks, T as handleSchemaOverview, w as handleServices } from "./handlers-Dk4AQQ3K.js";
|
|
2
2
|
import { ProductiveApi } from "@studiometa/productive-api";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
@@ -235,8 +235,8 @@ async function readResource(uri, credentials) {
|
|
|
235
235
|
}
|
|
236
236
|
//#endregion
|
|
237
237
|
//#region src/version.ts
|
|
238
|
-
var VERSION = "0.10.
|
|
238
|
+
var VERSION = "0.10.17";
|
|
239
239
|
//#endregion
|
|
240
240
|
export { INSTRUCTIONS as a, readResource as i, listResourceTemplates as n, listResources as r, VERSION as t };
|
|
241
241
|
|
|
242
|
-
//# sourceMappingURL=version-
|
|
242
|
+
//# sourceMappingURL=version-C8z9HRGX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-Jj_0Ypf8.js","names":[],"sources":["../src/instructions.ts","../src/resources.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 * MCP Resources handlers for Productive MCP Server\n *\n * Exposes Productive data via MCP resources/ capability so clients can browse\n * and read data without tool calls.\n *\n * Static resources (always available):\n * productive://schema — full resource schema overview\n * productive://instructions — server instructions / SKILL.md content\n *\n * Resource templates (parameterized, require API calls):\n * productive://projects/{id} — project details\n * productive://tasks/{id} — task details\n * productive://people/{id} — person details\n * productive://deals/{id} — deal details\n * productive://projects/{id}/tasks — tasks for a project\n * productive://projects/{id}/services — services for a project\n *\n * Dynamic resources (computed):\n * productive://summaries/my_day — personal dashboard\n * productive://summaries/team_pulse — team activity\n */\n\nimport type { ReadResourceResult as McpReadResourceResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { ProductiveApi } from '@studiometa/productive-api';\nimport { fromHandlerContext } from '@studiometa/productive-core';\n\nimport type { ProductiveCredentials } from './auth.js';\nimport type { HandlerContext } from './handlers/types.js';\n\nimport { handleDeals } from './handlers/deals.js';\nimport { handlePeople } from './handlers/people.js';\nimport { handleProjects } from './handlers/projects.js';\nimport { handleSchemaOverview } from './handlers/schema.js';\nimport { handleServices } from './handlers/services.js';\nimport { handleSummaries } from './handlers/summaries.js';\nimport { handleTasks } from './handlers/tasks.js';\nimport { INSTRUCTIONS } from './instructions.js';\n\n/** MIME type used for all resource content */\nconst MIME_TYPE = 'application/json';\n\n/**\n * A single resource content item returned in resources/read responses\n */\nexport interface ResourceContent {\n uri: string;\n mimeType: string;\n text: string;\n}\n\n/**\n * Shape of a resources/read response (re-export of SDK type for consumers)\n */\nexport type ReadResourceResult = McpReadResourceResult;\n\n/**\n * Shape of a static resource descriptor (resources/list)\n */\nexport interface StaticResource {\n uri: string;\n name: string;\n description: string;\n mimeType: string;\n}\n\n/**\n * Shape of a resource template descriptor (resources/templates/list)\n */\nexport interface ResourceTemplate {\n uriTemplate: string;\n name: string;\n description: string;\n mimeType: string;\n}\n\n// ---------------------------------------------------------------------------\n// Static resource definitions\n// ---------------------------------------------------------------------------\n\n/**\n * Static resources that are always available without API credentials\n */\nexport const STATIC_RESOURCES: StaticResource[] = [\n {\n uri: 'productive://schema',\n name: 'Schema',\n description: 'Overview of all Productive.io resources, their actions and filters',\n mimeType: MIME_TYPE,\n },\n {\n uri: 'productive://instructions',\n name: 'Instructions',\n description: 'Server instructions and usage guide for the Productive.io MCP server',\n mimeType: MIME_TYPE,\n },\n];\n\n// ---------------------------------------------------------------------------\n// Dynamic resource definitions\n// ---------------------------------------------------------------------------\n\n/**\n * Dynamic resources that are computed at read time (require credentials)\n */\nexport const DYNAMIC_RESOURCES: StaticResource[] = [\n {\n uri: 'productive://summaries/my_day',\n name: 'My Day',\n description: \"Personal dashboard: open tasks, today's time entries, active timers\",\n mimeType: MIME_TYPE,\n },\n {\n uri: 'productive://summaries/team_pulse',\n name: 'Team Pulse',\n description: 'Team-wide time tracking activity for today',\n mimeType: MIME_TYPE,\n },\n];\n\n// ---------------------------------------------------------------------------\n// Resource template definitions\n// ---------------------------------------------------------------------------\n\n/**\n * Resource templates that accept URI parameters (require credentials)\n */\nexport const RESOURCE_TEMPLATES: ResourceTemplate[] = [\n {\n uriTemplate: 'productive://projects/{id}',\n name: 'Project',\n description: 'Details of a specific project by ID',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://tasks/{id}',\n name: 'Task',\n description: 'Details of a specific task by ID',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://people/{id}',\n name: 'Person',\n description: 'Details of a specific person by ID',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://deals/{id}',\n name: 'Deal',\n description: 'Details of a specific deal or budget by ID',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://projects/{id}/tasks',\n name: 'Project Tasks',\n description: 'All tasks belonging to a specific project',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://projects/{id}/services',\n name: 'Project Services',\n description: 'All services belonging to a specific project',\n mimeType: MIME_TYPE,\n },\n];\n\n// ---------------------------------------------------------------------------\n// URI pattern matching\n// ---------------------------------------------------------------------------\n\n/** Route patterns and their handler factories */\nconst URI_PATTERNS: Array<{\n pattern: RegExp;\n handler: (match: RegExpMatchArray, credentials: ProductiveCredentials) => Promise<unknown>;\n}> = [\n // Static resources (no credentials needed)\n {\n pattern: /^productive:\\/\\/schema$/,\n handler: async () => {\n const result = handleSchemaOverview();\n const text = result.content[0] as { text: string };\n return JSON.parse(text.text);\n },\n },\n {\n pattern: /^productive:\\/\\/instructions$/,\n handler: async () => ({ instructions: INSTRUCTIONS }),\n },\n\n // Dynamic summaries\n {\n pattern: /^productive:\\/\\/summaries\\/my_day$/,\n handler: async (_, credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleSummaries('my_day', {}, ctx);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/summaries\\/team_pulse$/,\n handler: async (_, credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleSummaries('team_pulse', {}, ctx);\n return extractJsonFromResult(result);\n },\n },\n\n // Project nested resources (before single project to avoid conflict)\n {\n pattern: /^productive:\\/\\/projects\\/([^/]+)\\/tasks$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials, { filter: { project_id: id } });\n const result = await handleTasks('list', { project_id: id }, ctx);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/projects\\/([^/]+)\\/services$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials, { filter: { project_id: id } });\n // handleServices uses CommonArgs; project_id is passed via ctx.filter\n const result = await handleServices('list', {}, ctx);\n return extractJsonFromResult(result);\n },\n },\n\n // Single entity resources\n {\n pattern: /^productive:\\/\\/projects\\/([^/]+)$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleProjects('get', { id }, ctx);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/tasks\\/([^/]+)$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleTasks('get', { id }, ctx);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/people\\/([^/]+)$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handlePeople('get', { id }, ctx, credentials);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/deals\\/([^/]+)$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleDeals('get', { id }, ctx);\n return extractJsonFromResult(result);\n },\n },\n];\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Build a HandlerContext from credentials, with optional filter overrides.\n */\nfunction buildHandlerContext(\n credentials: ProductiveCredentials,\n overrides: { filter?: Record<string, string> } = {},\n): HandlerContext {\n const api = new ProductiveApi({\n config: {\n apiToken: credentials.apiToken,\n organizationId: credentials.organizationId,\n userId: credentials.userId,\n baseUrl: process.env.PRODUCTIVE_BASE_URL,\n },\n });\n\n const execCtx = fromHandlerContext({ api }, { userId: credentials.userId });\n\n return {\n formatOptions: { compact: false },\n filter: overrides.filter,\n perPage: 50,\n includeHints: false,\n includeSuggestions: false,\n executor: () => execCtx,\n };\n}\n\n/**\n * Extract the parsed JSON data from a ToolResult.\n * Throws if the result is an error or not parseable.\n */\nfunction extractJsonFromResult(result: { content: unknown[]; isError?: boolean }): unknown {\n if (result.isError) {\n const text = (result.content[0] as { text: string }).text;\n throw new Error(text);\n }\n const text = (result.content[0] as { text: string }).text;\n try {\n return JSON.parse(text);\n } catch {\n return { text };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * List all static and dynamic resources (no credentials needed for static).\n */\nexport function listResources(): StaticResource[] {\n return [...STATIC_RESOURCES, ...DYNAMIC_RESOURCES];\n}\n\n/**\n * List all resource templates.\n */\nexport function listResourceTemplates(): ResourceTemplate[] {\n return RESOURCE_TEMPLATES;\n}\n\n/**\n * Read a resource by URI.\n *\n * Routes the URI to the appropriate handler. Throws on unknown URI.\n */\nexport async function readResource(\n uri: string,\n credentials: ProductiveCredentials,\n): Promise<ReadResourceResult> {\n for (const { pattern, handler } of URI_PATTERNS) {\n const match = uri.match(pattern);\n if (match) {\n const data = await handler(match, credentials);\n return {\n contents: [\n {\n uri,\n mimeType: MIME_TYPE,\n text: JSON.stringify(data, null, 2),\n },\n ],\n };\n }\n }\n\n throw new Error(\n `Unknown resource URI: ${uri}. ` +\n `Available static resources: ${STATIC_RESOURCES.map((r) => r.uri).join(', ')}. ` +\n `Available dynamic resources: ${DYNAMIC_RESOURCES.map((r) => r.uri).join(', ')}. ` +\n `Resource templates: ${RESOURCE_TEMPLATES.map((t) => t.uriTemplate).join(', ')}.`,\n );\n}\n","/**\n * Package version - injected from package.json at build time\n */\ndeclare const __VERSION__: string;\nexport const VERSION = __VERSION__;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"version-C8z9HRGX.js","names":[],"sources":["../src/instructions.ts","../src/resources.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 * MCP Resources handlers for Productive MCP Server\n *\n * Exposes Productive data via MCP resources/ capability so clients can browse\n * and read data without tool calls.\n *\n * Static resources (always available):\n * productive://schema — full resource schema overview\n * productive://instructions — server instructions / SKILL.md content\n *\n * Resource templates (parameterized, require API calls):\n * productive://projects/{id} — project details\n * productive://tasks/{id} — task details\n * productive://people/{id} — person details\n * productive://deals/{id} — deal details\n * productive://projects/{id}/tasks — tasks for a project\n * productive://projects/{id}/services — services for a project\n *\n * Dynamic resources (computed):\n * productive://summaries/my_day — personal dashboard\n * productive://summaries/team_pulse — team activity\n */\n\nimport type { ReadResourceResult as McpReadResourceResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { ProductiveApi } from '@studiometa/productive-api';\nimport { fromHandlerContext } from '@studiometa/productive-core';\n\nimport type { ProductiveCredentials } from './auth.js';\nimport type { HandlerContext } from './handlers/types.js';\n\nimport { handleDeals } from './handlers/deals.js';\nimport { handlePeople } from './handlers/people.js';\nimport { handleProjects } from './handlers/projects.js';\nimport { handleSchemaOverview } from './handlers/schema.js';\nimport { handleServices } from './handlers/services.js';\nimport { handleSummaries } from './handlers/summaries.js';\nimport { handleTasks } from './handlers/tasks.js';\nimport { INSTRUCTIONS } from './instructions.js';\n\n/** MIME type used for all resource content */\nconst MIME_TYPE = 'application/json';\n\n/**\n * A single resource content item returned in resources/read responses\n */\nexport interface ResourceContent {\n uri: string;\n mimeType: string;\n text: string;\n}\n\n/**\n * Shape of a resources/read response (re-export of SDK type for consumers)\n */\nexport type ReadResourceResult = McpReadResourceResult;\n\n/**\n * Shape of a static resource descriptor (resources/list)\n */\nexport interface StaticResource {\n uri: string;\n name: string;\n description: string;\n mimeType: string;\n}\n\n/**\n * Shape of a resource template descriptor (resources/templates/list)\n */\nexport interface ResourceTemplate {\n uriTemplate: string;\n name: string;\n description: string;\n mimeType: string;\n}\n\n// ---------------------------------------------------------------------------\n// Static resource definitions\n// ---------------------------------------------------------------------------\n\n/**\n * Static resources that are always available without API credentials\n */\nexport const STATIC_RESOURCES: StaticResource[] = [\n {\n uri: 'productive://schema',\n name: 'Schema',\n description: 'Overview of all Productive.io resources, their actions and filters',\n mimeType: MIME_TYPE,\n },\n {\n uri: 'productive://instructions',\n name: 'Instructions',\n description: 'Server instructions and usage guide for the Productive.io MCP server',\n mimeType: MIME_TYPE,\n },\n];\n\n// ---------------------------------------------------------------------------\n// Dynamic resource definitions\n// ---------------------------------------------------------------------------\n\n/**\n * Dynamic resources that are computed at read time (require credentials)\n */\nexport const DYNAMIC_RESOURCES: StaticResource[] = [\n {\n uri: 'productive://summaries/my_day',\n name: 'My Day',\n description: \"Personal dashboard: open tasks, today's time entries, active timers\",\n mimeType: MIME_TYPE,\n },\n {\n uri: 'productive://summaries/team_pulse',\n name: 'Team Pulse',\n description: 'Team-wide time tracking activity for today',\n mimeType: MIME_TYPE,\n },\n];\n\n// ---------------------------------------------------------------------------\n// Resource template definitions\n// ---------------------------------------------------------------------------\n\n/**\n * Resource templates that accept URI parameters (require credentials)\n */\nexport const RESOURCE_TEMPLATES: ResourceTemplate[] = [\n {\n uriTemplate: 'productive://projects/{id}',\n name: 'Project',\n description: 'Details of a specific project by ID',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://tasks/{id}',\n name: 'Task',\n description: 'Details of a specific task by ID',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://people/{id}',\n name: 'Person',\n description: 'Details of a specific person by ID',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://deals/{id}',\n name: 'Deal',\n description: 'Details of a specific deal or budget by ID',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://projects/{id}/tasks',\n name: 'Project Tasks',\n description: 'All tasks belonging to a specific project',\n mimeType: MIME_TYPE,\n },\n {\n uriTemplate: 'productive://projects/{id}/services',\n name: 'Project Services',\n description: 'All services belonging to a specific project',\n mimeType: MIME_TYPE,\n },\n];\n\n// ---------------------------------------------------------------------------\n// URI pattern matching\n// ---------------------------------------------------------------------------\n\n/** Route patterns and their handler factories */\nconst URI_PATTERNS: Array<{\n pattern: RegExp;\n handler: (match: RegExpMatchArray, credentials: ProductiveCredentials) => Promise<unknown>;\n}> = [\n // Static resources (no credentials needed)\n {\n pattern: /^productive:\\/\\/schema$/,\n handler: async () => {\n const result = handleSchemaOverview();\n const text = result.content[0] as { text: string };\n return JSON.parse(text.text);\n },\n },\n {\n pattern: /^productive:\\/\\/instructions$/,\n handler: async () => ({ instructions: INSTRUCTIONS }),\n },\n\n // Dynamic summaries\n {\n pattern: /^productive:\\/\\/summaries\\/my_day$/,\n handler: async (_, credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleSummaries('my_day', {}, ctx);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/summaries\\/team_pulse$/,\n handler: async (_, credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleSummaries('team_pulse', {}, ctx);\n return extractJsonFromResult(result);\n },\n },\n\n // Project nested resources (before single project to avoid conflict)\n {\n pattern: /^productive:\\/\\/projects\\/([^/]+)\\/tasks$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials, { filter: { project_id: id } });\n const result = await handleTasks('list', { project_id: id }, ctx);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/projects\\/([^/]+)\\/services$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials, { filter: { project_id: id } });\n // handleServices uses CommonArgs; project_id is passed via ctx.filter\n const result = await handleServices('list', {}, ctx);\n return extractJsonFromResult(result);\n },\n },\n\n // Single entity resources\n {\n pattern: /^productive:\\/\\/projects\\/([^/]+)$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleProjects('get', { id }, ctx);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/tasks\\/([^/]+)$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleTasks('get', { id }, ctx);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/people\\/([^/]+)$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handlePeople('get', { id }, ctx, credentials);\n return extractJsonFromResult(result);\n },\n },\n {\n pattern: /^productive:\\/\\/deals\\/([^/]+)$/,\n handler: async ([, id], credentials) => {\n const ctx = buildHandlerContext(credentials);\n const result = await handleDeals('get', { id }, ctx);\n return extractJsonFromResult(result);\n },\n },\n];\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Build a HandlerContext from credentials, with optional filter overrides.\n */\nfunction buildHandlerContext(\n credentials: ProductiveCredentials,\n overrides: { filter?: Record<string, string> } = {},\n): HandlerContext {\n const api = new ProductiveApi({\n config: {\n apiToken: credentials.apiToken,\n organizationId: credentials.organizationId,\n userId: credentials.userId,\n baseUrl: process.env.PRODUCTIVE_BASE_URL,\n },\n });\n\n const execCtx = fromHandlerContext({ api }, { userId: credentials.userId });\n\n return {\n formatOptions: { compact: false },\n filter: overrides.filter,\n perPage: 50,\n includeHints: false,\n includeSuggestions: false,\n executor: () => execCtx,\n };\n}\n\n/**\n * Extract the parsed JSON data from a ToolResult.\n * Throws if the result is an error or not parseable.\n */\nfunction extractJsonFromResult(result: { content: unknown[]; isError?: boolean }): unknown {\n if (result.isError) {\n const text = (result.content[0] as { text: string }).text;\n throw new Error(text);\n }\n const text = (result.content[0] as { text: string }).text;\n try {\n return JSON.parse(text);\n } catch {\n return { text };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * List all static and dynamic resources (no credentials needed for static).\n */\nexport function listResources(): StaticResource[] {\n return [...STATIC_RESOURCES, ...DYNAMIC_RESOURCES];\n}\n\n/**\n * List all resource templates.\n */\nexport function listResourceTemplates(): ResourceTemplate[] {\n return RESOURCE_TEMPLATES;\n}\n\n/**\n * Read a resource by URI.\n *\n * Routes the URI to the appropriate handler. Throws on unknown URI.\n */\nexport async function readResource(\n uri: string,\n credentials: ProductiveCredentials,\n): Promise<ReadResourceResult> {\n for (const { pattern, handler } of URI_PATTERNS) {\n const match = uri.match(pattern);\n if (match) {\n const data = await handler(match, credentials);\n return {\n contents: [\n {\n uri,\n mimeType: MIME_TYPE,\n text: JSON.stringify(data, null, 2),\n },\n ],\n };\n }\n }\n\n throw new Error(\n `Unknown resource URI: ${uri}. ` +\n `Available static resources: ${STATIC_RESOURCES.map((r) => r.uri).join(', ')}. ` +\n `Available dynamic resources: ${DYNAMIC_RESOURCES.map((r) => r.uri).join(', ')}. ` +\n `Resource templates: ${RESOURCE_TEMPLATES.map((t) => t.uriTemplate).join(', ')}.`,\n );\n}\n","/**\n * Package version - injected from package.json at build time\n */\ndeclare const __VERSION__: string;\nexport const VERSION = __VERSION__;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studiometa/productive-mcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.17",
|
|
4
4
|
"description": "MCP server for Productive.io API - Model Context Protocol integration for Claude Desktop",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@jitl/quickjs-singlefile-cjs-release-sync": "^0.32.0",
|
|
85
85
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
86
|
-
"@studiometa/productive-api": "0.10.
|
|
87
|
-
"@studiometa/productive-core": "0.10.
|
|
86
|
+
"@studiometa/productive-api": "0.10.17",
|
|
87
|
+
"@studiometa/productive-core": "0.10.17",
|
|
88
88
|
"h3": "^2.0.1-rc.22",
|
|
89
89
|
"quickjs-emscripten-core": "^0.32.0",
|
|
90
90
|
"zod": "4.3.6"
|