@studiometa/productive-mcp 0.10.6 → 0.10.8
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/formatters.d.ts +4 -0
- package/dist/formatters.d.ts.map +1 -1
- package/dist/handlers/custom-fields.d.ts +26 -0
- package/dist/handlers/custom-fields.d.ts.map +1 -0
- package/dist/handlers/help.d.ts.map +1 -1
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/pre-validation-guards.d.ts +64 -0
- package/dist/handlers/pre-validation-guards.d.ts.map +1 -0
- package/dist/handlers/schema.d.ts.map +1 -1
- package/dist/handlers/valid-includes.d.ts.map +1 -1
- package/dist/{handlers-BvwBrRHp.js → handlers-t95fhdps.js} +2844 -2349
- package/dist/handlers-t95fhdps.js.map +1 -0
- package/dist/handlers.js +1 -1
- package/dist/hints.d.ts +4 -0
- package/dist/hints.d.ts.map +1 -1
- package/dist/http.d.ts +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +13 -4
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -5
- package/dist/index.js.map +1 -1
- package/dist/resources.d.ts +81 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/schema.d.ts +4 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/{handlers-Cha6_ulB.js → stdio-Bi1Lvp8O.js} +97 -2
- package/dist/stdio-Bi1Lvp8O.js.map +1 -0
- package/dist/stdio.js +2 -99
- package/dist/version-DpBFJ7eV.js +236 -0
- package/dist/version-DpBFJ7eV.js.map +1 -0
- package/package.json +3 -3
- package/skills/SKILL.md +168 -59
- package/dist/handlers-BvwBrRHp.js.map +0 -1
- package/dist/handlers-Cha6_ulB.js.map +0 -1
- package/dist/stdio.js.map +0 -1
- package/dist/version-KdH6s_ty.js +0 -29
- package/dist/version-KdH6s_ty.js.map +0 -1
package/dist/hints.d.ts
CHANGED
|
@@ -74,6 +74,10 @@ export declare function getPageHints(pageId: string): ContextualHints;
|
|
|
74
74
|
* Generate hints for a discussion
|
|
75
75
|
*/
|
|
76
76
|
export declare function getDiscussionHints(discussionId: string, pageId?: string): ContextualHints;
|
|
77
|
+
/**
|
|
78
|
+
* Generate hints for a custom field definition
|
|
79
|
+
*/
|
|
80
|
+
export declare function getCustomFieldHints(fieldId: string): ContextualHints;
|
|
77
81
|
/**
|
|
78
82
|
* Generate hints for a timer
|
|
79
83
|
*/
|
package/dist/hints.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hints.d.ts","sourceRoot":"","sources":["../src/hints.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,CAAC,EAAE,YAAY,EAAE,CAAC;IACnC,cAAc,CAAC,EAAE,UAAU,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,
|
|
1
|
+
{"version":3,"file":"hints.d.ts","sourceRoot":"","sources":["../src/hints.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,CAAC,EAAE,YAAY,EAAE,CAAC;IACnC,cAAc,CAAC,EAAE,UAAU,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAsEhF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CA8DlE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CA6D5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAyChE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,eAAe,GAAG,IAAI,CAkBxB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAqDlE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAmDlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,eAAe,CA0CjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,EACxB,aAAa,CAAC,EAAE,MAAM,GACrB,eAAe,CA4BjB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,GACtB,eAAe,CAqCjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CA6BrF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAqD5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CA+CzF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAyBpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CA4BlF"}
|
package/dist/http.d.ts
CHANGED
package/dist/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAOL,KAAK,GAAG,EACT,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAOL,KAAK,GAAG,EACT,MAAM,IAAI,CAAC;AAgBZ;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,MAAM,GAAG,MAAM,GAAG,IAAW;;;;;;;EAM5F;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,GAAE,MAAM,GAAG,MAAM,GAAG,IAAW;;;;EAMhF;AAED;;GAEG;AACH,wBAAgB,gBAAgB;;;;;;;;;;;EAa/B;AAED;;GAEG;AACH,wBAAgB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE9B;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,GAAG,CA0LnC"}
|
package/dist/http.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as executeToolWithCredentials } from "./handlers-
|
|
3
|
-
import "./handlers.js";
|
|
1
|
+
import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-DpBFJ7eV.js";
|
|
2
|
+
import { t as executeToolWithCredentials } from "./handlers-t95fhdps.js";
|
|
4
3
|
import { TOOLS } from "./tools.js";
|
|
5
4
|
import { parseAuthHeader } from "./auth.js";
|
|
6
5
|
import { authorizeGetHandler, authorizePostHandler, oauthMetadataHandler, registerHandler, tokenHandler } from "./oauth.js";
|
|
@@ -44,7 +43,10 @@ function handleInitialize() {
|
|
|
44
43
|
name: "productive-mcp",
|
|
45
44
|
version: VERSION
|
|
46
45
|
},
|
|
47
|
-
capabilities: {
|
|
46
|
+
capabilities: {
|
|
47
|
+
tools: {},
|
|
48
|
+
resources: {}
|
|
49
|
+
},
|
|
48
50
|
instructions: INSTRUCTIONS
|
|
49
51
|
};
|
|
50
52
|
}
|
|
@@ -117,6 +119,13 @@ function createHttpApp() {
|
|
|
117
119
|
const { name, arguments: args } = params;
|
|
118
120
|
return jsonRpcSuccess(await executeToolWithCredentials(name, args || {}, credentials), id ?? null);
|
|
119
121
|
}
|
|
122
|
+
if (method === "resources/list") return jsonRpcSuccess({ resources: listResources() }, id ?? null);
|
|
123
|
+
if (method === "resources/templates/list") return jsonRpcSuccess({ resourceTemplates: listResourceTemplates() }, id ?? null);
|
|
124
|
+
if (method === "resources/read") {
|
|
125
|
+
const { uri } = params ?? {};
|
|
126
|
+
if (!uri) return jsonRpcError(-32602, "Invalid params: uri is required", id ?? null);
|
|
127
|
+
return jsonRpcSuccess(await readResource(uri, credentials), id ?? null);
|
|
128
|
+
}
|
|
120
129
|
return jsonRpcError(-32601, `Method not found: ${method}`, id ?? null);
|
|
121
130
|
} catch (error) {
|
|
122
131
|
return jsonRpcError(-32603, `Internal error: ${error instanceof Error ? error.message : String(error)}`, id ?? null);
|
package/dist/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","names":[],"sources":["../src/http.ts"],"sourcesContent":["/**\n * HTTP transport handlers for Productive MCP Server\n *\n * This module contains the app/router creation logic for the HTTP transport.\n * The actual server startup is in server.ts.\n */\n\nimport {\n createApp,\n createRouter,\n defineEventHandler,\n readBody,\n getHeader,\n setResponseHeader,\n type App,\n} from 'h3';\n\nimport { parseAuthHeader } from './auth.js';\nimport { executeToolWithCredentials } from './handlers.js';\nimport { INSTRUCTIONS } from './instructions.js';\nimport {\n oauthMetadataHandler,\n registerHandler,\n authorizeGetHandler,\n authorizePostHandler,\n tokenHandler,\n} from './oauth.js';\nimport { TOOLS } from './tools.js';\nimport { VERSION } from './version.js';\n\n/**\n * JSON-RPC error response\n */\nexport function jsonRpcError(code: number, message: string, id: string | number | null = null) {\n return {\n jsonrpc: '2.0',\n error: { code, message },\n id,\n };\n}\n\n/**\n * JSON-RPC success response\n */\nexport function jsonRpcSuccess(result: unknown, id: string | number | null = null) {\n return {\n jsonrpc: '2.0',\n result,\n id,\n };\n}\n\n/**\n * Handle the initialize JSON-RPC method\n */\nexport function handleInitialize() {\n return {\n protocolVersion: '2024-11-05',\n serverInfo: {\n name: 'productive-mcp',\n version: VERSION,\n },\n capabilities: {\n tools: {},\n },\n instructions: INSTRUCTIONS,\n };\n}\n\n/**\n * Handle the tools/list JSON-RPC method\n */\nexport function handleToolsList() {\n return { tools: TOOLS };\n}\n\n/**\n * Create the h3 application with all routes\n */\nexport function createHttpApp(): App {\n const app = createApp();\n const router = createRouter();\n\n // OAuth 2.0 endpoints for Claude Desktop integration (MCP auth spec)\n router.get('/.well-known/oauth-authorization-server', oauthMetadataHandler);\n router.post('/register', registerHandler); // Dynamic Client Registration (RFC 7591)\n router.get('/authorize', authorizeGetHandler);\n router.post('/authorize', authorizePostHandler);\n router.post('/token', tokenHandler);\n\n // OAuth Protected Resource Metadata (RFC 9728 / MCP spec 2025-03-26)\n // This endpoint tells clients where to find the authorization server\n router.get(\n '/.well-known/oauth-protected-resource',\n defineEventHandler((event) => {\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n setResponseHeader(event, 'Cache-Control', 'public, max-age=3600');\n\n return {\n resource: `${baseUrl}/mcp`,\n authorization_servers: [baseUrl],\n scopes_supported: ['productive'],\n bearer_methods_supported: ['header'],\n };\n }),\n );\n\n // Health check endpoint\n router.get(\n '/',\n defineEventHandler(() => {\n return { status: 'ok', service: 'productive-mcp', version: VERSION };\n }),\n );\n\n router.get(\n '/health',\n defineEventHandler(() => {\n return { status: 'ok' };\n }),\n );\n\n // MCP endpoint - handles JSON-RPC over HTTP\n router.post(\n '/mcp',\n defineEventHandler(async (event) => {\n // Parse authorization header\n const authHeader = getHeader(event, 'authorization');\n const credentials = parseAuthHeader(authHeader);\n\n if (!credentials) {\n // RFC 6750: Return WWW-Authenticate header to trigger OAuth flow\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n setResponseHeader(\n event,\n 'WWW-Authenticate',\n `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`,\n );\n event.node.res.statusCode = 401;\n return jsonRpcError(\n -32001,\n 'Authentication required. Provide Bearer token with base64(organizationId:apiToken:userId)',\n );\n }\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n\n // Parse JSON-RPC request\n let body: { method?: string; params?: unknown; id?: string | number };\n try {\n body = await readBody(event);\n } catch {\n event.node.res.statusCode = 400;\n return jsonRpcError(-32700, 'Parse error: Invalid JSON');\n }\n\n if (!body || typeof body !== 'object') {\n event.node.res.statusCode = 400;\n return jsonRpcError(-32700, 'Parse error: Invalid JSON');\n }\n\n const { method, params, id } = body;\n\n try {\n if (method === 'initialize') {\n return jsonRpcSuccess(handleInitialize(), id ?? null);\n }\n\n if (method === 'tools/list') {\n return jsonRpcSuccess(handleToolsList(), id ?? null);\n }\n\n if (method === 'tools/call') {\n const { name, arguments: args } = params as {\n name: string;\n arguments?: Record<string, unknown>;\n };\n const result = await executeToolWithCredentials(name, args || {}, credentials);\n return jsonRpcSuccess(result, id ?? null);\n }\n\n // Unknown method\n return jsonRpcError(-32601, `Method not found: ${method}`, id ?? null);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return jsonRpcError(-32603, `Internal error: ${message}`, id ?? null);\n }\n }),\n );\n\n // SSE endpoint for server-sent events (optional, for streaming responses)\n router.get(\n '/mcp/sse',\n defineEventHandler(async (event) => {\n const authHeader = getHeader(event, 'authorization');\n const credentials = parseAuthHeader(authHeader);\n\n if (!credentials) {\n // RFC 6750: Return WWW-Authenticate header to trigger OAuth flow\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(\n event,\n 'WWW-Authenticate',\n `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`,\n );\n event.node.res.statusCode = 401;\n return { error: 'Authentication required' };\n }\n\n // Set SSE headers\n setResponseHeader(event, 'Content-Type', 'text/event-stream');\n setResponseHeader(event, 'Cache-Control', 'no-cache');\n setResponseHeader(event, 'Connection', 'keep-alive');\n\n // Generate session ID and send it\n const sessionId = crypto.randomUUID();\n\n // Send initial session event\n event.node.res.write(`event: session\\ndata: ${JSON.stringify({ sessionId })}\\n\\n`);\n\n // Keep connection alive\n const keepAlive = setInterval(() => {\n event.node.res.write(': keepalive\\n\\n');\n }, 30000);\n\n // Clean up on close\n event.node.req.on('close', () => {\n clearInterval(keepAlive);\n });\n\n // Don't end the response - keep it open for SSE\n return new Promise(() => {});\n }),\n );\n\n app.use(router);\n return app;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiCA,SAAgB,aAAa,MAAc,SAAiB,KAA6B,MAAM;AAC7F,QAAO;EACL,SAAS;EACT,OAAO;GAAE;GAAM;GAAS;EACxB;EACD;;;;;AAMH,SAAgB,eAAe,QAAiB,KAA6B,MAAM;AACjF,QAAO;EACL,SAAS;EACT;EACA;EACD;;;;;AAMH,SAAgB,mBAAmB;AACjC,QAAO;EACL,iBAAiB;EACjB,YAAY;GACV,MAAM;GACN,SAAS;GACV;EACD,cAAc,EACZ,OAAO,EAAE,EACV;EACD,cAAc;EACf;;;;;AAMH,SAAgB,kBAAkB;AAChC,QAAO,EAAE,OAAO,OAAO;;;;;AAMzB,SAAgB,gBAAqB;CACnC,MAAM,MAAM,WAAW;CACvB,MAAM,SAAS,cAAc;AAG7B,QAAO,IAAI,2CAA2C,qBAAqB;AAC3E,QAAO,KAAK,aAAa,gBAAgB;AACzC,QAAO,IAAI,cAAc,oBAAoB;AAC7C,QAAO,KAAK,cAAc,qBAAqB;AAC/C,QAAO,KAAK,UAAU,aAAa;AAInC,QAAO,IACL,yCACA,oBAAoB,UAAU;EAC5B,MAAM,OAAO,MAAM,KAAK,IAAI,QAAQ,QAAQ;EAE5C,MAAM,UAAU,GADC,MAAM,KAAK,IAAI,QAAQ,wBAAwB,OACpC,KAAK;AAEjC,oBAAkB,OAAO,gBAAgB,mBAAmB;AAC5D,oBAAkB,OAAO,iBAAiB,uBAAuB;AAEjE,SAAO;GACL,UAAU,GAAG,QAAQ;GACrB,uBAAuB,CAAC,QAAQ;GAChC,kBAAkB,CAAC,aAAa;GAChC,0BAA0B,CAAC,SAAS;GACrC;GACD,CACH;AAGD,QAAO,IACL,KACA,yBAAyB;AACvB,SAAO;GAAE,QAAQ;GAAM,SAAS;GAAkB,SAAS;GAAS;GACpE,CACH;AAED,QAAO,IACL,WACA,yBAAyB;AACvB,SAAO,EAAE,QAAQ,MAAM;GACvB,CACH;AAGD,QAAO,KACL,QACA,mBAAmB,OAAO,UAAU;EAGlC,MAAM,cAAc,gBADD,UAAU,OAAO,gBAAgB,CACL;AAE/C,MAAI,CAAC,aAAa;GAEhB,MAAM,OAAO,MAAM,KAAK,IAAI,QAAQ,QAAQ;GAE5C,MAAM,UAAU,GADC,MAAM,KAAK,IAAI,QAAQ,wBAAwB,OACpC,KAAK;AAEjC,qBAAkB,OAAO,gBAAgB,mBAAmB;AAC5D,qBACE,OACA,oBACA,6BAA6B,QAAQ,wCACtC;AACD,SAAM,KAAK,IAAI,aAAa;AAC5B,UAAO,aACL,QACA,4FACD;;AAGH,oBAAkB,OAAO,gBAAgB,mBAAmB;EAG5D,IAAI;AACJ,MAAI;AACF,UAAO,MAAM,SAAS,MAAM;UACtB;AACN,SAAM,KAAK,IAAI,aAAa;AAC5B,UAAO,aAAa,QAAQ,4BAA4B;;AAG1D,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,SAAM,KAAK,IAAI,aAAa;AAC5B,UAAO,aAAa,QAAQ,4BAA4B;;EAG1D,MAAM,EAAE,QAAQ,QAAQ,OAAO;AAE/B,MAAI;AACF,OAAI,WAAW,aACb,QAAO,eAAe,kBAAkB,EAAE,MAAM,KAAK;AAGvD,OAAI,WAAW,aACb,QAAO,eAAe,iBAAiB,EAAE,MAAM,KAAK;AAGtD,OAAI,WAAW,cAAc;IAC3B,MAAM,EAAE,MAAM,WAAW,SAAS;AAKlC,WAAO,eADQ,MAAM,2BAA2B,MAAM,QAAQ,EAAE,EAAE,YAAY,EAChD,MAAM,KAAK;;AAI3C,UAAO,aAAa,QAAQ,qBAAqB,UAAU,MAAM,KAAK;WAC/D,OAAO;AAEd,UAAO,aAAa,QAAQ,mBADZ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IACZ,MAAM,KAAK;;GAEvE,CACH;AAGD,QAAO,IACL,YACA,mBAAmB,OAAO,UAAU;AAIlC,MAAI,CAFgB,gBADD,UAAU,OAAO,gBAAgB,CACL,EAE7B;GAEhB,MAAM,OAAO,MAAM,KAAK,IAAI,QAAQ,QAAQ;AAI5C,qBACE,OACA,oBACA,6BALc,GADC,MAAM,KAAK,IAAI,QAAQ,wBAAwB,OACpC,KAAK,OAKM,wCACtC;AACD,SAAM,KAAK,IAAI,aAAa;AAC5B,UAAO,EAAE,OAAO,2BAA2B;;AAI7C,oBAAkB,OAAO,gBAAgB,oBAAoB;AAC7D,oBAAkB,OAAO,iBAAiB,WAAW;AACrD,oBAAkB,OAAO,cAAc,aAAa;EAGpD,MAAM,YAAY,OAAO,YAAY;AAGrC,QAAM,KAAK,IAAI,MAAM,yBAAyB,KAAK,UAAU,EAAE,WAAW,CAAC,CAAC,MAAM;EAGlF,MAAM,YAAY,kBAAkB;AAClC,SAAM,KAAK,IAAI,MAAM,kBAAkB;KACtC,IAAM;AAGT,QAAM,KAAK,IAAI,GAAG,eAAe;AAC/B,iBAAc,UAAU;IACxB;AAGF,SAAO,IAAI,cAAc,GAAG;GAC5B,CACH;AAED,KAAI,IAAI,OAAO;AACf,QAAO"}
|
|
1
|
+
{"version":3,"file":"http.js","names":[],"sources":["../src/http.ts"],"sourcesContent":["/**\n * HTTP transport handlers for Productive MCP Server\n *\n * This module contains the app/router creation logic for the HTTP transport.\n * The actual server startup is in server.ts.\n */\n\nimport {\n createApp,\n createRouter,\n defineEventHandler,\n readBody,\n getHeader,\n setResponseHeader,\n type App,\n} from 'h3';\n\nimport { parseAuthHeader } from './auth.js';\nimport { executeToolWithCredentials } from './handlers.js';\nimport { INSTRUCTIONS } from './instructions.js';\nimport {\n oauthMetadataHandler,\n registerHandler,\n authorizeGetHandler,\n authorizePostHandler,\n tokenHandler,\n} from './oauth.js';\nimport { listResources, listResourceTemplates, readResource } from './resources.js';\nimport { TOOLS } from './tools.js';\nimport { VERSION } from './version.js';\n\n/**\n * JSON-RPC error response\n */\nexport function jsonRpcError(code: number, message: string, id: string | number | null = null) {\n return {\n jsonrpc: '2.0',\n error: { code, message },\n id,\n };\n}\n\n/**\n * JSON-RPC success response\n */\nexport function jsonRpcSuccess(result: unknown, id: string | number | null = null) {\n return {\n jsonrpc: '2.0',\n result,\n id,\n };\n}\n\n/**\n * Handle the initialize JSON-RPC method\n */\nexport function handleInitialize() {\n return {\n protocolVersion: '2024-11-05',\n serverInfo: {\n name: 'productive-mcp',\n version: VERSION,\n },\n capabilities: {\n tools: {},\n resources: {},\n },\n instructions: INSTRUCTIONS,\n };\n}\n\n/**\n * Handle the tools/list JSON-RPC method\n */\nexport function handleToolsList() {\n return { tools: TOOLS };\n}\n\n/**\n * Create the h3 application with all routes\n */\nexport function createHttpApp(): App {\n const app = createApp();\n const router = createRouter();\n\n // OAuth 2.0 endpoints for Claude Desktop integration (MCP auth spec)\n router.get('/.well-known/oauth-authorization-server', oauthMetadataHandler);\n router.post('/register', registerHandler); // Dynamic Client Registration (RFC 7591)\n router.get('/authorize', authorizeGetHandler);\n router.post('/authorize', authorizePostHandler);\n router.post('/token', tokenHandler);\n\n // OAuth Protected Resource Metadata (RFC 9728 / MCP spec 2025-03-26)\n // This endpoint tells clients where to find the authorization server\n router.get(\n '/.well-known/oauth-protected-resource',\n defineEventHandler((event) => {\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n setResponseHeader(event, 'Cache-Control', 'public, max-age=3600');\n\n return {\n resource: `${baseUrl}/mcp`,\n authorization_servers: [baseUrl],\n scopes_supported: ['productive'],\n bearer_methods_supported: ['header'],\n };\n }),\n );\n\n // Health check endpoint\n router.get(\n '/',\n defineEventHandler(() => {\n return { status: 'ok', service: 'productive-mcp', version: VERSION };\n }),\n );\n\n router.get(\n '/health',\n defineEventHandler(() => {\n return { status: 'ok' };\n }),\n );\n\n // MCP endpoint - handles JSON-RPC over HTTP\n router.post(\n '/mcp',\n defineEventHandler(async (event) => {\n // Parse authorization header\n const authHeader = getHeader(event, 'authorization');\n const credentials = parseAuthHeader(authHeader);\n\n if (!credentials) {\n // RFC 6750: Return WWW-Authenticate header to trigger OAuth flow\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n setResponseHeader(\n event,\n 'WWW-Authenticate',\n `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`,\n );\n event.node.res.statusCode = 401;\n return jsonRpcError(\n -32001,\n 'Authentication required. Provide Bearer token with base64(organizationId:apiToken:userId)',\n );\n }\n\n setResponseHeader(event, 'Content-Type', 'application/json');\n\n // Parse JSON-RPC request\n let body: { method?: string; params?: unknown; id?: string | number };\n try {\n body = await readBody(event);\n } catch {\n event.node.res.statusCode = 400;\n return jsonRpcError(-32700, 'Parse error: Invalid JSON');\n }\n\n if (!body || typeof body !== 'object') {\n event.node.res.statusCode = 400;\n return jsonRpcError(-32700, 'Parse error: Invalid JSON');\n }\n\n const { method, params, id } = body;\n\n try {\n if (method === 'initialize') {\n return jsonRpcSuccess(handleInitialize(), id ?? null);\n }\n\n if (method === 'tools/list') {\n return jsonRpcSuccess(handleToolsList(), id ?? null);\n }\n\n if (method === 'tools/call') {\n const { name, arguments: args } = params as {\n name: string;\n arguments?: Record<string, unknown>;\n };\n const result = await executeToolWithCredentials(name, args || {}, credentials);\n return jsonRpcSuccess(result, id ?? null);\n }\n\n if (method === 'resources/list') {\n return jsonRpcSuccess({ resources: listResources() }, id ?? null);\n }\n\n if (method === 'resources/templates/list') {\n return jsonRpcSuccess({ resourceTemplates: listResourceTemplates() }, id ?? null);\n }\n\n if (method === 'resources/read') {\n const { uri } = (params as { uri: string }) ?? {};\n if (!uri) {\n return jsonRpcError(-32602, 'Invalid params: uri is required', id ?? null);\n }\n const result = await readResource(uri, credentials);\n return jsonRpcSuccess(result, id ?? null);\n }\n\n // Unknown method\n return jsonRpcError(-32601, `Method not found: ${method}`, id ?? null);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return jsonRpcError(-32603, `Internal error: ${message}`, id ?? null);\n }\n }),\n );\n\n // SSE endpoint for server-sent events (optional, for streaming responses)\n router.get(\n '/mcp/sse',\n defineEventHandler(async (event) => {\n const authHeader = getHeader(event, 'authorization');\n const credentials = parseAuthHeader(authHeader);\n\n if (!credentials) {\n // RFC 6750: Return WWW-Authenticate header to trigger OAuth flow\n const host = event.node.req.headers.host || 'localhost:3000';\n const protocol = event.node.req.headers['x-forwarded-proto'] || 'http';\n const baseUrl = `${protocol}://${host}`;\n\n setResponseHeader(\n event,\n 'WWW-Authenticate',\n `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`,\n );\n event.node.res.statusCode = 401;\n return { error: 'Authentication required' };\n }\n\n // Set SSE headers\n setResponseHeader(event, 'Content-Type', 'text/event-stream');\n setResponseHeader(event, 'Cache-Control', 'no-cache');\n setResponseHeader(event, 'Connection', 'keep-alive');\n\n // Generate session ID and send it\n const sessionId = crypto.randomUUID();\n\n // Send initial session event\n event.node.res.write(`event: session\\ndata: ${JSON.stringify({ sessionId })}\\n\\n`);\n\n // Keep connection alive\n const keepAlive = setInterval(() => {\n event.node.res.write(': keepalive\\n\\n');\n }, 30000);\n\n // Clean up on close\n event.node.req.on('close', () => {\n clearInterval(keepAlive);\n });\n\n // Don't end the response - keep it open for SSE\n return new Promise(() => {});\n }),\n );\n\n app.use(router);\n return app;\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAkBnE;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CA4E1C;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAKtD"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import "./handlers-
|
|
4
|
-
import {
|
|
2
|
+
import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-DpBFJ7eV.js";
|
|
3
|
+
import "./handlers-t95fhdps.js";
|
|
4
|
+
import { a as handlePrompt, n as getAvailableTools, s as handleToolCall, t as getAvailablePrompts } from "./stdio-Bi1Lvp8O.js";
|
|
5
5
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
-
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import { getConfig } from "@studiometa/productive-api";
|
|
8
9
|
/**
|
|
9
10
|
* Productive MCP Server - Stdio Transport
|
|
10
11
|
*
|
|
@@ -34,7 +35,8 @@ function createStdioServer() {
|
|
|
34
35
|
}, {
|
|
35
36
|
capabilities: {
|
|
36
37
|
tools: {},
|
|
37
|
-
prompts: {}
|
|
38
|
+
prompts: {},
|
|
39
|
+
resources: {}
|
|
38
40
|
},
|
|
39
41
|
instructions: INSTRUCTIONS
|
|
40
42
|
});
|
|
@@ -47,6 +49,22 @@ function createStdioServer() {
|
|
|
47
49
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
48
50
|
return handlePrompt(request.params.name, request.params.arguments);
|
|
49
51
|
});
|
|
52
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
53
|
+
return { resources: listResources() };
|
|
54
|
+
});
|
|
55
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
|
|
56
|
+
return { resourceTemplates: listResourceTemplates() };
|
|
57
|
+
});
|
|
58
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
59
|
+
const { uri } = request.params;
|
|
60
|
+
const config = await getConfig();
|
|
61
|
+
if (!config.organizationId || !config.apiToken) throw new Error("Productive.io credentials not configured. Use the \"productive_configure\" tool or set PRODUCTIVE_ORG_ID and PRODUCTIVE_API_TOKEN environment variables.");
|
|
62
|
+
return readResource(uri, {
|
|
63
|
+
organizationId: config.organizationId,
|
|
64
|
+
apiToken: config.apiToken,
|
|
65
|
+
userId: config.userId
|
|
66
|
+
});
|
|
67
|
+
});
|
|
50
68
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
51
69
|
const { name, arguments: args } = request.params;
|
|
52
70
|
try {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Productive MCP Server - Stdio Transport\n *\n * This is the local execution mode using stdio transport.\n * For remote HTTP deployment, use server.ts instead.\n *\n * Usage:\n * npx @studiometa/productive-mcp\n *\n * Or in Claude Desktop config:\n * {\n * \"mcpServers\": {\n * \"productive\": {\n * \"command\": \"npx\",\n * \"args\": [\"@studiometa/productive-mcp\"]\n * }\n * }\n * }\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ListPromptsRequestSchema,\n GetPromptRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\n\nimport { INSTRUCTIONS } from './instructions.js';\nimport { getAvailableTools, getAvailablePrompts, handleToolCall, handlePrompt } from './stdio.js';\nimport { VERSION } from './version.js';\n\n/**\n * Create and configure the MCP server\n */\nexport function createStdioServer(): Server {\n const server = new Server(\n {\n name: 'productive-mcp',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n prompts: {},\n },\n instructions: INSTRUCTIONS,\n },\n );\n\n // List available tools (including stdio-only configuration tools)\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools: getAvailableTools() };\n });\n\n // List available prompts\n server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return { prompts: getAvailablePrompts() };\n });\n\n // Get prompt\n server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n return handlePrompt(request.params.name, request.params.arguments as Record<string, string>);\n });\n\n // Handle tool calls\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n return await handleToolCall(name, (args as Record<string, unknown>) || {});\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text', text: `Error: ${message}` }],\n isError: true,\n };\n }\n });\n\n return server;\n}\n\n/**\n * Start the stdio server\n */\nexport async function startStdioServer(): Promise<void> {\n const server = createStdioServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(`Productive MCP server v${VERSION} running on stdio`);\n}\n\n// Start server when run directly\nconst isMainModule =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith('/productive-mcp') ||\n process.argv[1]?.endsWith('\\\\productive-mcp');\n\nif (isMainModule) {\n startStdioServer().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n });\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Productive MCP Server - Stdio Transport\n *\n * This is the local execution mode using stdio transport.\n * For remote HTTP deployment, use server.ts instead.\n *\n * Usage:\n * npx @studiometa/productive-mcp\n *\n * Or in Claude Desktop config:\n * {\n * \"mcpServers\": {\n * \"productive\": {\n * \"command\": \"npx\",\n * \"args\": [\"@studiometa/productive-mcp\"]\n * }\n * }\n * }\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ListPromptsRequestSchema,\n GetPromptRequestSchema,\n ListResourcesRequestSchema,\n ListResourceTemplatesRequestSchema,\n ReadResourceRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { getConfig } from '@studiometa/productive-api';\n\nimport { INSTRUCTIONS } from './instructions.js';\nimport { listResources, listResourceTemplates, readResource } from './resources.js';\nimport { getAvailableTools, getAvailablePrompts, handleToolCall, handlePrompt } from './stdio.js';\nimport { VERSION } from './version.js';\n\n/**\n * Create and configure the MCP server\n */\nexport function createStdioServer(): Server {\n const server = new Server(\n {\n name: 'productive-mcp',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n prompts: {},\n resources: {},\n },\n instructions: INSTRUCTIONS,\n },\n );\n\n // List available tools (including stdio-only configuration tools)\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools: getAvailableTools() };\n });\n\n // List available prompts\n server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return { prompts: getAvailablePrompts() };\n });\n\n // Get prompt\n server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n return handlePrompt(request.params.name, request.params.arguments as Record<string, string>);\n });\n\n // List available resources (static + dynamic)\n server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return { resources: listResources() };\n });\n\n // List resource templates (parameterized URIs)\n server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {\n return { resourceTemplates: listResourceTemplates() };\n });\n\n // Read a resource by URI\n server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const { uri } = request.params;\n\n // Get credentials from config (same as tool calls)\n const config = await getConfig();\n if (!config.organizationId || !config.apiToken) {\n throw new Error(\n 'Productive.io credentials not configured. Use the \"productive_configure\" tool or set PRODUCTIVE_ORG_ID and PRODUCTIVE_API_TOKEN environment variables.',\n );\n }\n\n return readResource(uri, {\n organizationId: config.organizationId,\n apiToken: config.apiToken,\n userId: config.userId,\n });\n });\n\n // Handle tool calls\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n return await handleToolCall(name, (args as Record<string, unknown>) || {});\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text', text: `Error: ${message}` }],\n isError: true,\n };\n }\n });\n\n return server;\n}\n\n/**\n * Start the stdio server\n */\nexport async function startStdioServer(): Promise<void> {\n const server = createStdioServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(`Productive MCP server v${VERSION} running on stdio`);\n}\n\n// Start server when run directly\nconst isMainModule =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith('/productive-mcp') ||\n process.argv[1]?.endsWith('\\\\productive-mcp');\n\nif (isMainModule) {\n startStdioServer().catch((error) => {\n console.error('Fatal error:', error);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,SAAgB,oBAA4B;CAC1C,MAAM,SAAS,IAAI,OACjB;EACE,MAAM;EACN,SAAS;EACV,EACD;EACE,cAAc;GACZ,OAAO,EAAE;GACT,SAAS,EAAE;GACX,WAAW,EAAE;GACd;EACD,cAAc;EACf,CACF;AAGD,QAAO,kBAAkB,wBAAwB,YAAY;AAC3D,SAAO,EAAE,OAAO,mBAAmB,EAAE;GACrC;AAGF,QAAO,kBAAkB,0BAA0B,YAAY;AAC7D,SAAO,EAAE,SAAS,qBAAqB,EAAE;GACzC;AAGF,QAAO,kBAAkB,wBAAwB,OAAO,YAAY;AAClE,SAAO,aAAa,QAAQ,OAAO,MAAM,QAAQ,OAAO,UAAoC;GAC5F;AAGF,QAAO,kBAAkB,4BAA4B,YAAY;AAC/D,SAAO,EAAE,WAAW,eAAe,EAAE;GACrC;AAGF,QAAO,kBAAkB,oCAAoC,YAAY;AACvE,SAAO,EAAE,mBAAmB,uBAAuB,EAAE;GACrD;AAGF,QAAO,kBAAkB,2BAA2B,OAAO,YAAY;EACrE,MAAM,EAAE,QAAQ,QAAQ;EAGxB,MAAM,SAAS,MAAM,WAAW;AAChC,MAAI,CAAC,OAAO,kBAAkB,CAAC,OAAO,SACpC,OAAM,IAAI,MACR,2JACD;AAGH,SAAO,aAAa,KAAK;GACvB,gBAAgB,OAAO;GACvB,UAAU,OAAO;GACjB,QAAQ,OAAO;GAChB,CAAC;GACF;AAGF,QAAO,kBAAkB,uBAAuB,OAAO,YAAY;EACjE,MAAM,EAAE,MAAM,WAAW,SAAS,QAAQ;AAE1C,MAAI;AACF,UAAO,MAAM,eAAe,MAAO,QAAoC,EAAE,CAAC;WACnE,OAAO;AAEd,UAAO;IACL,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,UAFlB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;KAEf,CAAC;IACtD,SAAS;IACV;;GAEH;AAEF,QAAO;;;;;AAMT,eAAsB,mBAAkC;CACtD,MAAM,SAAS,mBAAmB;CAClC,MAAM,YAAY,IAAI,sBAAsB;AAC5C,OAAM,OAAO,QAAQ,UAAU;AAC/B,SAAQ,MAAM,0BAA0B,QAAQ,mBAAmB;;AASrE,IAJE,OAAO,KAAK,QAAQ,UAAU,QAAQ,KAAK,QAC3C,QAAQ,KAAK,IAAI,SAAS,kBAAkB,IAC5C,QAAQ,KAAK,IAAI,SAAS,mBAAmB,CAG7C,mBAAkB,CAAC,OAAO,UAAU;AAClC,SAAQ,MAAM,gBAAgB,MAAM;AACpC,SAAQ,KAAK,EAAE;EACf"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Resources handlers for Productive MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Exposes Productive data via MCP resources/ capability so clients can browse
|
|
5
|
+
* and read data without tool calls.
|
|
6
|
+
*
|
|
7
|
+
* Static resources (always available):
|
|
8
|
+
* productive://schema — full resource schema overview
|
|
9
|
+
* productive://instructions — server instructions / SKILL.md content
|
|
10
|
+
*
|
|
11
|
+
* Resource templates (parameterized, require API calls):
|
|
12
|
+
* productive://projects/{id} — project details
|
|
13
|
+
* productive://tasks/{id} — task details
|
|
14
|
+
* productive://people/{id} — person details
|
|
15
|
+
* productive://deals/{id} — deal details
|
|
16
|
+
* productive://projects/{id}/tasks — tasks for a project
|
|
17
|
+
* productive://projects/{id}/services — services for a project
|
|
18
|
+
*
|
|
19
|
+
* Dynamic resources (computed):
|
|
20
|
+
* productive://summaries/my_day — personal dashboard
|
|
21
|
+
* productive://summaries/team_pulse — team activity
|
|
22
|
+
*/
|
|
23
|
+
import type { ReadResourceResult as McpReadResourceResult } from '@modelcontextprotocol/sdk/types.js';
|
|
24
|
+
import type { ProductiveCredentials } from './auth.js';
|
|
25
|
+
/**
|
|
26
|
+
* A single resource content item returned in resources/read responses
|
|
27
|
+
*/
|
|
28
|
+
export interface ResourceContent {
|
|
29
|
+
uri: string;
|
|
30
|
+
mimeType: string;
|
|
31
|
+
text: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Shape of a resources/read response (re-export of SDK type for consumers)
|
|
35
|
+
*/
|
|
36
|
+
export type ReadResourceResult = McpReadResourceResult;
|
|
37
|
+
/**
|
|
38
|
+
* Shape of a static resource descriptor (resources/list)
|
|
39
|
+
*/
|
|
40
|
+
export interface StaticResource {
|
|
41
|
+
uri: string;
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
mimeType: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Shape of a resource template descriptor (resources/templates/list)
|
|
48
|
+
*/
|
|
49
|
+
export interface ResourceTemplate {
|
|
50
|
+
uriTemplate: string;
|
|
51
|
+
name: string;
|
|
52
|
+
description: string;
|
|
53
|
+
mimeType: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Static resources that are always available without API credentials
|
|
57
|
+
*/
|
|
58
|
+
export declare const STATIC_RESOURCES: StaticResource[];
|
|
59
|
+
/**
|
|
60
|
+
* Dynamic resources that are computed at read time (require credentials)
|
|
61
|
+
*/
|
|
62
|
+
export declare const DYNAMIC_RESOURCES: StaticResource[];
|
|
63
|
+
/**
|
|
64
|
+
* Resource templates that accept URI parameters (require credentials)
|
|
65
|
+
*/
|
|
66
|
+
export declare const RESOURCE_TEMPLATES: ResourceTemplate[];
|
|
67
|
+
/**
|
|
68
|
+
* List all static and dynamic resources (no credentials needed for static).
|
|
69
|
+
*/
|
|
70
|
+
export declare function listResources(): StaticResource[];
|
|
71
|
+
/**
|
|
72
|
+
* List all resource templates.
|
|
73
|
+
*/
|
|
74
|
+
export declare function listResourceTemplates(): ResourceTemplate[];
|
|
75
|
+
/**
|
|
76
|
+
* Read a resource by URI.
|
|
77
|
+
*
|
|
78
|
+
* Routes the URI to the appropriate handler. Throws on unknown URI.
|
|
79
|
+
*/
|
|
80
|
+
export declare function readResource(uri: string, credentials: ProductiveCredentials): Promise<ReadResourceResult>;
|
|
81
|
+
//# sourceMappingURL=resources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,IAAI,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAKtG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAevD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAAc,EAa5C,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAAc,EAa7C,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,EAqChD,CAAC;AAsJF;;GAEG;AACH,wBAAgB,aAAa,IAAI,cAAc,EAAE,CAEhD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,gBAAgB,EAAE,CAE1D;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,qBAAqB,GACjC,OAAO,CAAC,kBAAkB,CAAC,CAuB7B"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare const ResourceSchema: z.ZodEnum<{
|
|
|
17
17
|
comments: "comments";
|
|
18
18
|
time: "time";
|
|
19
19
|
tasks: "tasks";
|
|
20
|
+
custom_fields: "custom_fields";
|
|
20
21
|
services: "services";
|
|
21
22
|
deals: "deals";
|
|
22
23
|
bookings: "bookings";
|
|
@@ -31,8 +32,8 @@ export declare const ResourceSchema: z.ZodEnum<{
|
|
|
31
32
|
batch: "batch";
|
|
32
33
|
workflows: "workflows";
|
|
33
34
|
reports: "reports";
|
|
34
|
-
summaries: "summaries";
|
|
35
35
|
search: "search";
|
|
36
|
+
summaries: "summaries";
|
|
36
37
|
}>;
|
|
37
38
|
/**
|
|
38
39
|
* Actions available for resources
|
|
@@ -166,6 +167,7 @@ export declare const ProductiveToolInputSchema: z.ZodObject<{
|
|
|
166
167
|
comments: "comments";
|
|
167
168
|
time: "time";
|
|
168
169
|
tasks: "tasks";
|
|
170
|
+
custom_fields: "custom_fields";
|
|
169
171
|
services: "services";
|
|
170
172
|
deals: "deals";
|
|
171
173
|
bookings: "bookings";
|
|
@@ -180,8 +182,8 @@ export declare const ProductiveToolInputSchema: z.ZodObject<{
|
|
|
180
182
|
batch: "batch";
|
|
181
183
|
workflows: "workflows";
|
|
182
184
|
reports: "reports";
|
|
183
|
-
summaries: "summaries";
|
|
184
185
|
search: "search";
|
|
186
|
+
summaries: "summaries";
|
|
185
187
|
}>;
|
|
186
188
|
action: z.ZodEnum<{
|
|
187
189
|
list: "list";
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,CAAC,EAAoB,KAAK,kBAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGlF,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAMhF;;;GAGG;AACH,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,CAAC,EAAoB,KAAK,kBAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGlF,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAMhF;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;EAAoB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;EAAkB,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAAuB,CAAC;AAMrD;;GAEG;AACH,eAAO,MAAM,OAAO,aAIgC,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,aAAa,aAKvB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,aAKxB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,aAGqD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,cAAc,aAGuD,CAAC;AAEnF;;GAEG;AACH,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,SAAS,aAIuC,CAAC;AAE9D;;GAEG;AACH,eAAO,MAAM,gBAAgB,aAKiE,CAAC;AAE/F;;GAEG;AACH,eAAO,MAAM,SAAS,2BAKiC,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,YAAY,2BAMsC,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,YAAY,6BAKtB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,UAAU,aAMpB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,wCAKxB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,YAAY,6BAKtB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,YAAY,yBAItB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,SAAS,aAAkD,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,UAAU,aAIqB,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,SAAS,aAGgB,CAAC;AAMvC;;GAEG;AACH,eAAO,MAAM,YAAY,uDAGsB,CAAC;AAMhD;;;GAGG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqFpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAM5E;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAErE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAE7F;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,mBAAmB,CAAC,GAAG,MAAM,CAOnF"}
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as VERSION } from "./version-
|
|
3
|
-
import "./handlers-
|
|
2
|
+
import { t as VERSION } from "./version-DpBFJ7eV.js";
|
|
3
|
+
import "./handlers-t95fhdps.js";
|
|
4
4
|
import { createHttpApp } from "./http.js";
|
|
5
5
|
import { toNodeListener } from "h3";
|
|
6
6
|
import { createServer } from "node:http";
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { t as executeToolWithCredentials } from "./handlers-t95fhdps.js";
|
|
2
|
+
import { STDIO_ONLY_TOOLS, TOOLS } from "./tools.js";
|
|
3
|
+
import { getConfig, setConfig } from "@studiometa/productive-api";
|
|
1
4
|
const PROMPT_DEFINITIONS = [
|
|
2
5
|
{
|
|
3
6
|
name: "end-of-day",
|
|
@@ -251,6 +254,98 @@ function getPromptMessages(name, args) {
|
|
|
251
254
|
default: throw new Error(`Unknown prompt: ${name}`);
|
|
252
255
|
}
|
|
253
256
|
}
|
|
254
|
-
|
|
257
|
+
/**
|
|
258
|
+
* Get all available tools (including stdio-only configuration tools)
|
|
259
|
+
*/
|
|
260
|
+
function getAvailableTools() {
|
|
261
|
+
return [...TOOLS, ...STDIO_ONLY_TOOLS];
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Get available prompts
|
|
265
|
+
*/
|
|
266
|
+
function getAvailablePrompts() {
|
|
267
|
+
return [{
|
|
268
|
+
name: "setup_productive",
|
|
269
|
+
description: "Interactive setup for Productive.io credentials",
|
|
270
|
+
arguments: []
|
|
271
|
+
}, ...PROMPT_DEFINITIONS];
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Handle the setup_productive prompt
|
|
275
|
+
*/
|
|
276
|
+
async function handleSetupPrompt() {
|
|
277
|
+
const config = await getConfig();
|
|
278
|
+
return { messages: [{
|
|
279
|
+
role: "user",
|
|
280
|
+
content: {
|
|
281
|
+
type: "text",
|
|
282
|
+
text: !!(config.organizationId && config.apiToken) ? "I have already configured Productive.io credentials. Would you like to update them?" : "I need to configure my Productive.io credentials. Please help me set up:\n1. Organization ID\n2. API Token\n3. User ID (optional)"
|
|
283
|
+
}
|
|
284
|
+
}] };
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Handle the productive_configure tool
|
|
288
|
+
*/
|
|
289
|
+
async function handleConfigureTool(args) {
|
|
290
|
+
const { organizationId, apiToken, userId } = args;
|
|
291
|
+
await setConfig("organizationId", organizationId);
|
|
292
|
+
await setConfig("apiToken", apiToken);
|
|
293
|
+
if (userId) await setConfig("userId", userId);
|
|
294
|
+
return { content: [{
|
|
295
|
+
type: "text",
|
|
296
|
+
text: JSON.stringify({
|
|
297
|
+
success: true,
|
|
298
|
+
message: "Productive.io credentials configured successfully",
|
|
299
|
+
configured: {
|
|
300
|
+
organizationId,
|
|
301
|
+
userId: userId || "not set",
|
|
302
|
+
apiToken: "***" + apiToken.slice(-4)
|
|
303
|
+
}
|
|
304
|
+
}, null, 2)
|
|
305
|
+
}] };
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Handle the productive_get_config tool
|
|
309
|
+
*/
|
|
310
|
+
async function handleGetConfigTool() {
|
|
311
|
+
const currentConfig = await getConfig();
|
|
312
|
+
return { content: [{
|
|
313
|
+
type: "text",
|
|
314
|
+
text: JSON.stringify({
|
|
315
|
+
organizationId: currentConfig.organizationId || "not configured",
|
|
316
|
+
userId: currentConfig.userId || "not configured",
|
|
317
|
+
apiToken: currentConfig.apiToken ? "***" + currentConfig.apiToken.slice(-4) : "not configured",
|
|
318
|
+
configured: !!(currentConfig.organizationId && currentConfig.apiToken)
|
|
319
|
+
}, null, 2)
|
|
320
|
+
}] };
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Handle a tool call request
|
|
324
|
+
*/
|
|
325
|
+
async function handleToolCall(name, args) {
|
|
326
|
+
if (name === "productive_configure") return handleConfigureTool(args);
|
|
327
|
+
if (name === "productive_get_config") return handleGetConfigTool();
|
|
328
|
+
const config = await getConfig();
|
|
329
|
+
if (!config.organizationId || !config.apiToken) return {
|
|
330
|
+
content: [{
|
|
331
|
+
type: "text",
|
|
332
|
+
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."
|
|
333
|
+
}],
|
|
334
|
+
isError: true
|
|
335
|
+
};
|
|
336
|
+
return executeToolWithCredentials(name, args, {
|
|
337
|
+
organizationId: config.organizationId,
|
|
338
|
+
apiToken: config.apiToken,
|
|
339
|
+
userId: config.userId
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Handle a prompt request
|
|
344
|
+
*/
|
|
345
|
+
async function handlePrompt(name, args) {
|
|
346
|
+
if (name === "setup_productive") return handleSetupPrompt();
|
|
347
|
+
return getPromptMessages(name, args);
|
|
348
|
+
}
|
|
349
|
+
export { handlePrompt as a, handleGetConfigTool as i, getAvailableTools as n, handleSetupPrompt as o, handleConfigureTool as r, handleToolCall as s, getAvailablePrompts as t };
|
|
255
350
|
|
|
256
|
-
//# sourceMappingURL=
|
|
351
|
+
//# sourceMappingURL=stdio-Bi1Lvp8O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio-Bi1Lvp8O.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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"}
|
package/dist/stdio.js
CHANGED
|
@@ -1,100 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
import "./
|
|
3
|
-
import { n as PROMPT_DEFINITIONS, t as getPromptMessages } from "./handlers-Cha6_ulB.js";
|
|
4
|
-
import { STDIO_ONLY_TOOLS, TOOLS } from "./tools.js";
|
|
5
|
-
import { getConfig, setConfig } from "@studiometa/productive-api";
|
|
6
|
-
/**
|
|
7
|
-
* Get all available tools (including stdio-only configuration tools)
|
|
8
|
-
*/
|
|
9
|
-
function getAvailableTools() {
|
|
10
|
-
return [...TOOLS, ...STDIO_ONLY_TOOLS];
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Get available prompts
|
|
14
|
-
*/
|
|
15
|
-
function getAvailablePrompts() {
|
|
16
|
-
return [{
|
|
17
|
-
name: "setup_productive",
|
|
18
|
-
description: "Interactive setup for Productive.io credentials",
|
|
19
|
-
arguments: []
|
|
20
|
-
}, ...PROMPT_DEFINITIONS];
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Handle the setup_productive prompt
|
|
24
|
-
*/
|
|
25
|
-
async function handleSetupPrompt() {
|
|
26
|
-
const config = await getConfig();
|
|
27
|
-
return { messages: [{
|
|
28
|
-
role: "user",
|
|
29
|
-
content: {
|
|
30
|
-
type: "text",
|
|
31
|
-
text: !!(config.organizationId && config.apiToken) ? "I have already configured Productive.io credentials. Would you like to update them?" : "I need to configure my Productive.io credentials. Please help me set up:\n1. Organization ID\n2. API Token\n3. User ID (optional)"
|
|
32
|
-
}
|
|
33
|
-
}] };
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Handle the productive_configure tool
|
|
37
|
-
*/
|
|
38
|
-
async function handleConfigureTool(args) {
|
|
39
|
-
const { organizationId, apiToken, userId } = args;
|
|
40
|
-
await setConfig("organizationId", organizationId);
|
|
41
|
-
await setConfig("apiToken", apiToken);
|
|
42
|
-
if (userId) await setConfig("userId", userId);
|
|
43
|
-
return { content: [{
|
|
44
|
-
type: "text",
|
|
45
|
-
text: JSON.stringify({
|
|
46
|
-
success: true,
|
|
47
|
-
message: "Productive.io credentials configured successfully",
|
|
48
|
-
configured: {
|
|
49
|
-
organizationId,
|
|
50
|
-
userId: userId || "not set",
|
|
51
|
-
apiToken: "***" + apiToken.slice(-4)
|
|
52
|
-
}
|
|
53
|
-
}, null, 2)
|
|
54
|
-
}] };
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Handle the productive_get_config tool
|
|
58
|
-
*/
|
|
59
|
-
async function handleGetConfigTool() {
|
|
60
|
-
const currentConfig = await getConfig();
|
|
61
|
-
return { content: [{
|
|
62
|
-
type: "text",
|
|
63
|
-
text: JSON.stringify({
|
|
64
|
-
organizationId: currentConfig.organizationId || "not configured",
|
|
65
|
-
userId: currentConfig.userId || "not configured",
|
|
66
|
-
apiToken: currentConfig.apiToken ? "***" + currentConfig.apiToken.slice(-4) : "not configured",
|
|
67
|
-
configured: !!(currentConfig.organizationId && currentConfig.apiToken)
|
|
68
|
-
}, null, 2)
|
|
69
|
-
}] };
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Handle a tool call request
|
|
73
|
-
*/
|
|
74
|
-
async function handleToolCall(name, args) {
|
|
75
|
-
if (name === "productive_configure") return handleConfigureTool(args);
|
|
76
|
-
if (name === "productive_get_config") return handleGetConfigTool();
|
|
77
|
-
const config = await getConfig();
|
|
78
|
-
if (!config.organizationId || !config.apiToken) return {
|
|
79
|
-
content: [{
|
|
80
|
-
type: "text",
|
|
81
|
-
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."
|
|
82
|
-
}],
|
|
83
|
-
isError: true
|
|
84
|
-
};
|
|
85
|
-
return executeToolWithCredentials(name, args, {
|
|
86
|
-
organizationId: config.organizationId,
|
|
87
|
-
apiToken: config.apiToken,
|
|
88
|
-
userId: config.userId
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Handle a prompt request
|
|
93
|
-
*/
|
|
94
|
-
async function handlePrompt(name, args) {
|
|
95
|
-
if (name === "setup_productive") return handleSetupPrompt();
|
|
96
|
-
return getPromptMessages(name, args);
|
|
97
|
-
}
|
|
1
|
+
import "./handlers-t95fhdps.js";
|
|
2
|
+
import { a as handlePrompt, i as handleGetConfigTool, n as getAvailableTools, o as handleSetupPrompt, r as handleConfigureTool, s as handleToolCall, t as getAvailablePrompts } from "./stdio-Bi1Lvp8O.js";
|
|
98
3
|
export { getAvailablePrompts, getAvailableTools, handleConfigureTool, handleGetConfigTool, handlePrompt, handleSetupPrompt, handleToolCall };
|
|
99
|
-
|
|
100
|
-
//# sourceMappingURL=stdio.js.map
|