@studiometa/productive-mcp 0.8.4 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +84 -412
  2. package/dist/auth.js +37 -36
  3. package/dist/auth.js.map +1 -1
  4. package/dist/crypto.js +100 -61
  5. package/dist/crypto.js.map +1 -1
  6. package/dist/formatters.d.ts +18 -2
  7. package/dist/formatters.d.ts.map +1 -1
  8. package/dist/handlers/attachments.d.ts +6 -0
  9. package/dist/handlers/attachments.d.ts.map +1 -0
  10. package/dist/handlers/bookings.d.ts +1 -1
  11. package/dist/handlers/bookings.d.ts.map +1 -1
  12. package/dist/handlers/budgets.d.ts +9 -0
  13. package/dist/handlers/budgets.d.ts.map +1 -0
  14. package/dist/handlers/comments.d.ts +1 -1
  15. package/dist/handlers/comments.d.ts.map +1 -1
  16. package/dist/handlers/companies.d.ts +6 -2
  17. package/dist/handlers/companies.d.ts.map +1 -1
  18. package/dist/handlers/deals.d.ts +6 -2
  19. package/dist/handlers/deals.d.ts.map +1 -1
  20. package/dist/handlers/discussions.d.ts +13 -0
  21. package/dist/handlers/discussions.d.ts.map +1 -0
  22. package/dist/handlers/help.d.ts.map +1 -1
  23. package/dist/handlers/index.d.ts.map +1 -1
  24. package/dist/handlers/pages.d.ts +13 -0
  25. package/dist/handlers/pages.d.ts.map +1 -0
  26. package/dist/handlers/people.d.ts +6 -2
  27. package/dist/handlers/people.d.ts.map +1 -1
  28. package/dist/handlers/projects.d.ts +6 -2
  29. package/dist/handlers/projects.d.ts.map +1 -1
  30. package/dist/handlers/reports.d.ts +1 -4
  31. package/dist/handlers/reports.d.ts.map +1 -1
  32. package/dist/handlers/resolve.d.ts +24 -0
  33. package/dist/handlers/resolve.d.ts.map +1 -0
  34. package/dist/handlers/services.d.ts +1 -1
  35. package/dist/handlers/services.d.ts.map +1 -1
  36. package/dist/handlers/tasks.d.ts +6 -2
  37. package/dist/handlers/tasks.d.ts.map +1 -1
  38. package/dist/handlers/time.d.ts +10 -2
  39. package/dist/handlers/time.d.ts.map +1 -1
  40. package/dist/handlers/timers.d.ts +1 -1
  41. package/dist/handlers/timers.d.ts.map +1 -1
  42. package/dist/handlers/types.d.ts +42 -3
  43. package/dist/handlers/types.d.ts.map +1 -1
  44. package/dist/handlers-BYE2INiR.js +2681 -0
  45. package/dist/handlers-BYE2INiR.js.map +1 -0
  46. package/dist/handlers.js +2 -5
  47. package/dist/hints.d.ts +16 -0
  48. package/dist/hints.d.ts.map +1 -1
  49. package/dist/http.js +139 -160
  50. package/dist/http.js.map +1 -1
  51. package/dist/index.js +74 -54
  52. package/dist/index.js.map +1 -1
  53. package/dist/oauth.js +285 -255
  54. package/dist/oauth.js.map +1 -1
  55. package/dist/schema.d.ts +17 -0
  56. package/dist/schema.d.ts.map +1 -1
  57. package/dist/server.js +67 -50
  58. package/dist/server.js.map +1 -1
  59. package/dist/stdio.js +85 -105
  60. package/dist/stdio.js.map +1 -1
  61. package/dist/tools.js +155 -145
  62. package/dist/tools.js.map +1 -1
  63. package/dist/version-Dj8VXyV0.js +29 -0
  64. package/dist/version-Dj8VXyV0.js.map +1 -0
  65. package/package.json +10 -10
  66. package/skills/SKILL.md +209 -13
  67. package/Dockerfile +0 -36
  68. package/dist/handlers.js.map +0 -1
  69. package/dist/index-CZpVCEu4.js +0 -1681
  70. package/dist/index-CZpVCEu4.js.map +0 -1
  71. package/dist/version-DLWm7CFT.js +0 -21
  72. package/dist/version-DLWm7CFT.js.map +0 -1
package/dist/http.js CHANGED
@@ -1,171 +1,150 @@
1
- import { createApp, createRouter, defineEventHandler, setResponseHeader, getHeader, readBody } from "h3";
2
- import { parseAuthHeader } from "./auth.js";
3
- import { e as executeToolWithCredentials } from "./index-CZpVCEu4.js";
4
- import { V as VERSION, I as INSTRUCTIONS } from "./version-DLWm7CFT.js";
5
- import { oauthMetadataHandler, registerHandler, authorizeGetHandler, authorizePostHandler, tokenHandler } from "./oauth.js";
1
+ import { n as INSTRUCTIONS, t as VERSION } from "./version-Dj8VXyV0.js";
2
+ import { t as executeToolWithCredentials } from "./handlers-BYE2INiR.js";
3
+ import "./handlers.js";
6
4
  import { TOOLS } from "./tools.js";
5
+ import { parseAuthHeader } from "./auth.js";
6
+ import { authorizeGetHandler, authorizePostHandler, oauthMetadataHandler, registerHandler, tokenHandler } from "./oauth.js";
7
+ import { createApp, createRouter, defineEventHandler, getHeader, readBody, setResponseHeader } from "h3";
8
+ /**
9
+ * HTTP transport handlers for Productive MCP Server
10
+ *
11
+ * This module contains the app/router creation logic for the HTTP transport.
12
+ * The actual server startup is in server.ts.
13
+ */
14
+ /**
15
+ * JSON-RPC error response
16
+ */
7
17
  function jsonRpcError(code, message, id = null) {
8
- return {
9
- jsonrpc: "2.0",
10
- error: { code, message },
11
- id
12
- };
18
+ return {
19
+ jsonrpc: "2.0",
20
+ error: {
21
+ code,
22
+ message
23
+ },
24
+ id
25
+ };
13
26
  }
27
+ /**
28
+ * JSON-RPC success response
29
+ */
14
30
  function jsonRpcSuccess(result, id = null) {
15
- return {
16
- jsonrpc: "2.0",
17
- result,
18
- id
19
- };
31
+ return {
32
+ jsonrpc: "2.0",
33
+ result,
34
+ id
35
+ };
20
36
  }
37
+ /**
38
+ * Handle the initialize JSON-RPC method
39
+ */
21
40
  function handleInitialize() {
22
- return {
23
- protocolVersion: "2024-11-05",
24
- serverInfo: {
25
- name: "productive-mcp",
26
- version: VERSION
27
- },
28
- capabilities: {
29
- tools: {}
30
- },
31
- instructions: INSTRUCTIONS
32
- };
41
+ return {
42
+ protocolVersion: "2024-11-05",
43
+ serverInfo: {
44
+ name: "productive-mcp",
45
+ version: VERSION
46
+ },
47
+ capabilities: { tools: {} },
48
+ instructions: INSTRUCTIONS
49
+ };
33
50
  }
51
+ /**
52
+ * Handle the tools/list JSON-RPC method
53
+ */
34
54
  function handleToolsList() {
35
- return { tools: TOOLS };
55
+ return { tools: TOOLS };
36
56
  }
57
+ /**
58
+ * Create the h3 application with all routes
59
+ */
37
60
  function createHttpApp() {
38
- const app = createApp();
39
- const router = createRouter();
40
- router.get("/.well-known/oauth-authorization-server", oauthMetadataHandler);
41
- router.post("/register", registerHandler);
42
- router.get("/authorize", authorizeGetHandler);
43
- router.post("/authorize", authorizePostHandler);
44
- router.post("/token", tokenHandler);
45
- router.get(
46
- "/.well-known/oauth-protected-resource",
47
- defineEventHandler((event) => {
48
- const host = event.node.req.headers.host || "localhost:3000";
49
- const protocol = event.node.req.headers["x-forwarded-proto"] || "http";
50
- const baseUrl = `${protocol}://${host}`;
51
- setResponseHeader(event, "Content-Type", "application/json");
52
- setResponseHeader(event, "Cache-Control", "public, max-age=3600");
53
- return {
54
- resource: `${baseUrl}/mcp`,
55
- authorization_servers: [baseUrl],
56
- scopes_supported: ["productive"],
57
- bearer_methods_supported: ["header"]
58
- };
59
- })
60
- );
61
- router.get(
62
- "/",
63
- defineEventHandler(() => {
64
- return { status: "ok", service: "productive-mcp", version: VERSION };
65
- })
66
- );
67
- router.get(
68
- "/health",
69
- defineEventHandler(() => {
70
- return { status: "ok" };
71
- })
72
- );
73
- router.post(
74
- "/mcp",
75
- defineEventHandler(async (event) => {
76
- const authHeader = getHeader(event, "authorization");
77
- const credentials = parseAuthHeader(authHeader);
78
- if (!credentials) {
79
- const host = event.node.req.headers.host || "localhost:3000";
80
- const protocol = event.node.req.headers["x-forwarded-proto"] || "http";
81
- const baseUrl = `${protocol}://${host}`;
82
- setResponseHeader(event, "Content-Type", "application/json");
83
- setResponseHeader(
84
- event,
85
- "WWW-Authenticate",
86
- `Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource"`
87
- );
88
- event.node.res.statusCode = 401;
89
- return jsonRpcError(
90
- -32001,
91
- "Authentication required. Provide Bearer token with base64(organizationId:apiToken:userId)"
92
- );
93
- }
94
- setResponseHeader(event, "Content-Type", "application/json");
95
- let body;
96
- try {
97
- body = await readBody(event);
98
- } catch {
99
- event.node.res.statusCode = 400;
100
- return jsonRpcError(-32700, "Parse error: Invalid JSON");
101
- }
102
- if (!body || typeof body !== "object") {
103
- event.node.res.statusCode = 400;
104
- return jsonRpcError(-32700, "Parse error: Invalid JSON");
105
- }
106
- const { method, params, id } = body;
107
- try {
108
- if (method === "initialize") {
109
- return jsonRpcSuccess(handleInitialize(), id ?? null);
110
- }
111
- if (method === "tools/list") {
112
- return jsonRpcSuccess(handleToolsList(), id ?? null);
113
- }
114
- if (method === "tools/call") {
115
- const { name, arguments: args } = params;
116
- const result = await executeToolWithCredentials(name, args || {}, credentials);
117
- return jsonRpcSuccess(result, id ?? null);
118
- }
119
- return jsonRpcError(-32601, `Method not found: ${method}`, id ?? null);
120
- } catch (error) {
121
- const message = error instanceof Error ? error.message : String(error);
122
- return jsonRpcError(-32603, `Internal error: ${message}`, id ?? null);
123
- }
124
- })
125
- );
126
- router.get(
127
- "/mcp/sse",
128
- defineEventHandler(async (event) => {
129
- const authHeader = getHeader(event, "authorization");
130
- const credentials = parseAuthHeader(authHeader);
131
- if (!credentials) {
132
- const host = event.node.req.headers.host || "localhost:3000";
133
- const protocol = event.node.req.headers["x-forwarded-proto"] || "http";
134
- const baseUrl = `${protocol}://${host}`;
135
- setResponseHeader(
136
- event,
137
- "WWW-Authenticate",
138
- `Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource"`
139
- );
140
- event.node.res.statusCode = 401;
141
- return { error: "Authentication required" };
142
- }
143
- setResponseHeader(event, "Content-Type", "text/event-stream");
144
- setResponseHeader(event, "Cache-Control", "no-cache");
145
- setResponseHeader(event, "Connection", "keep-alive");
146
- const sessionId = crypto.randomUUID();
147
- event.node.res.write(`event: session
148
- data: ${JSON.stringify({ sessionId })}
149
-
150
- `);
151
- const keepAlive = setInterval(() => {
152
- event.node.res.write(": keepalive\n\n");
153
- }, 3e4);
154
- event.node.req.on("close", () => {
155
- clearInterval(keepAlive);
156
- });
157
- return new Promise(() => {
158
- });
159
- })
160
- );
161
- app.use(router);
162
- return app;
61
+ const app = createApp();
62
+ const router = createRouter();
63
+ router.get("/.well-known/oauth-authorization-server", oauthMetadataHandler);
64
+ router.post("/register", registerHandler);
65
+ router.get("/authorize", authorizeGetHandler);
66
+ router.post("/authorize", authorizePostHandler);
67
+ router.post("/token", tokenHandler);
68
+ router.get("/.well-known/oauth-protected-resource", defineEventHandler((event) => {
69
+ const host = event.node.req.headers.host || "localhost:3000";
70
+ const baseUrl = `${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`;
71
+ setResponseHeader(event, "Content-Type", "application/json");
72
+ setResponseHeader(event, "Cache-Control", "public, max-age=3600");
73
+ return {
74
+ resource: `${baseUrl}/mcp`,
75
+ authorization_servers: [baseUrl],
76
+ scopes_supported: ["productive"],
77
+ bearer_methods_supported: ["header"]
78
+ };
79
+ }));
80
+ router.get("/", defineEventHandler(() => {
81
+ return {
82
+ status: "ok",
83
+ service: "productive-mcp",
84
+ version: VERSION
85
+ };
86
+ }));
87
+ router.get("/health", defineEventHandler(() => {
88
+ return { status: "ok" };
89
+ }));
90
+ router.post("/mcp", defineEventHandler(async (event) => {
91
+ const credentials = parseAuthHeader(getHeader(event, "authorization"));
92
+ if (!credentials) {
93
+ const host = event.node.req.headers.host || "localhost:3000";
94
+ const baseUrl = `${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`;
95
+ setResponseHeader(event, "Content-Type", "application/json");
96
+ setResponseHeader(event, "WWW-Authenticate", `Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource"`);
97
+ event.node.res.statusCode = 401;
98
+ return jsonRpcError(-32001, "Authentication required. Provide Bearer token with base64(organizationId:apiToken:userId)");
99
+ }
100
+ setResponseHeader(event, "Content-Type", "application/json");
101
+ let body;
102
+ try {
103
+ body = await readBody(event);
104
+ } catch {
105
+ event.node.res.statusCode = 400;
106
+ return jsonRpcError(-32700, "Parse error: Invalid JSON");
107
+ }
108
+ if (!body || typeof body !== "object") {
109
+ event.node.res.statusCode = 400;
110
+ return jsonRpcError(-32700, "Parse error: Invalid JSON");
111
+ }
112
+ const { method, params, id } = body;
113
+ try {
114
+ if (method === "initialize") return jsonRpcSuccess(handleInitialize(), id ?? null);
115
+ if (method === "tools/list") return jsonRpcSuccess(handleToolsList(), id ?? null);
116
+ if (method === "tools/call") {
117
+ const { name, arguments: args } = params;
118
+ return jsonRpcSuccess(await executeToolWithCredentials(name, args || {}, credentials), id ?? null);
119
+ }
120
+ return jsonRpcError(-32601, `Method not found: ${method}`, id ?? null);
121
+ } catch (error) {
122
+ return jsonRpcError(-32603, `Internal error: ${error instanceof Error ? error.message : String(error)}`, id ?? null);
123
+ }
124
+ }));
125
+ router.get("/mcp/sse", defineEventHandler(async (event) => {
126
+ if (!parseAuthHeader(getHeader(event, "authorization"))) {
127
+ const host = event.node.req.headers.host || "localhost:3000";
128
+ setResponseHeader(event, "WWW-Authenticate", `Bearer resource_metadata="${`${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`}/.well-known/oauth-protected-resource"`);
129
+ event.node.res.statusCode = 401;
130
+ return { error: "Authentication required" };
131
+ }
132
+ setResponseHeader(event, "Content-Type", "text/event-stream");
133
+ setResponseHeader(event, "Cache-Control", "no-cache");
134
+ setResponseHeader(event, "Connection", "keep-alive");
135
+ const sessionId = crypto.randomUUID();
136
+ event.node.res.write(`event: session\ndata: ${JSON.stringify({ sessionId })}\n\n`);
137
+ const keepAlive = setInterval(() => {
138
+ event.node.res.write(": keepalive\n\n");
139
+ }, 3e4);
140
+ event.node.req.on("close", () => {
141
+ clearInterval(keepAlive);
142
+ });
143
+ return new Promise(() => {});
144
+ }));
145
+ app.use(router);
146
+ return app;
163
147
  }
164
- export {
165
- createHttpApp,
166
- handleInitialize,
167
- handleToolsList,
168
- jsonRpcError,
169
- jsonRpcSuccess
170
- };
171
- //# sourceMappingURL=http.js.map
148
+ export { createHttpApp, handleInitialize, handleToolsList, jsonRpcError, jsonRpcSuccess };
149
+
150
+ //# sourceMappingURL=http.js.map
package/dist/http.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","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"],"names":[],"mappings":"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"}
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":"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"}
package/dist/index.js CHANGED
@@ -1,61 +1,81 @@
1
1
  #!/usr/bin/env node
2
+ import { n as INSTRUCTIONS, t as VERSION } from "./version-Dj8VXyV0.js";
3
+ import "./handlers-BYE2INiR.js";
4
+ import { getAvailablePrompts, getAvailableTools, handlePrompt, handleToolCall } from "./stdio.js";
2
5
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
5
- import { V as VERSION, I as INSTRUCTIONS } from "./version-DLWm7CFT.js";
6
- import { getAvailableTools, getAvailablePrompts, handlePrompt, handleToolCall } from "./stdio.js";
7
+ import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
8
+ /**
9
+ * Productive MCP Server - Stdio Transport
10
+ *
11
+ * This is the local execution mode using stdio transport.
12
+ * For remote HTTP deployment, use server.ts instead.
13
+ *
14
+ * Usage:
15
+ * npx @studiometa/productive-mcp
16
+ *
17
+ * Or in Claude Desktop config:
18
+ * {
19
+ * "mcpServers": {
20
+ * "productive": {
21
+ * "command": "npx",
22
+ * "args": ["@studiometa/productive-mcp"]
23
+ * }
24
+ * }
25
+ * }
26
+ */
27
+ /**
28
+ * Create and configure the MCP server
29
+ */
7
30
  function createStdioServer() {
8
- const server = new Server(
9
- {
10
- name: "productive-mcp",
11
- version: VERSION
12
- },
13
- {
14
- capabilities: {
15
- tools: {},
16
- prompts: {}
17
- },
18
- instructions: INSTRUCTIONS
19
- }
20
- );
21
- server.setRequestHandler(ListToolsRequestSchema, async () => {
22
- return { tools: getAvailableTools() };
23
- });
24
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
25
- return { prompts: getAvailablePrompts() };
26
- });
27
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
28
- return handlePrompt(request.params.name);
29
- });
30
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
31
- const { name, arguments: args } = request.params;
32
- try {
33
- return await handleToolCall(name, args || {});
34
- } catch (error) {
35
- const message = error instanceof Error ? error.message : String(error);
36
- return {
37
- content: [{ type: "text", text: `Error: ${message}` }],
38
- isError: true
39
- };
40
- }
41
- });
42
- return server;
31
+ const server = new Server({
32
+ name: "productive-mcp",
33
+ version: VERSION
34
+ }, {
35
+ capabilities: {
36
+ tools: {},
37
+ prompts: {}
38
+ },
39
+ instructions: INSTRUCTIONS
40
+ });
41
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
42
+ return { tools: getAvailableTools() };
43
+ });
44
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
45
+ return { prompts: getAvailablePrompts() };
46
+ });
47
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
48
+ return handlePrompt(request.params.name);
49
+ });
50
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
51
+ const { name, arguments: args } = request.params;
52
+ try {
53
+ return await handleToolCall(name, args || {});
54
+ } catch (error) {
55
+ return {
56
+ content: [{
57
+ type: "text",
58
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
59
+ }],
60
+ isError: true
61
+ };
62
+ }
63
+ });
64
+ return server;
43
65
  }
66
+ /**
67
+ * Start the stdio server
68
+ */
44
69
  async function startStdioServer() {
45
- const server = createStdioServer();
46
- const transport = new StdioServerTransport();
47
- await server.connect(transport);
48
- console.error(`Productive MCP server v${VERSION} running on stdio`);
70
+ const server = createStdioServer();
71
+ const transport = new StdioServerTransport();
72
+ await server.connect(transport);
73
+ console.error(`Productive MCP server v${VERSION} running on stdio`);
49
74
  }
50
- const isMainModule = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("/productive-mcp") || process.argv[1]?.endsWith("\\productive-mcp");
51
- if (isMainModule) {
52
- startStdioServer().catch((error) => {
53
- console.error("Fatal error:", error);
54
- process.exit(1);
55
- });
56
- }
57
- export {
58
- createStdioServer,
59
- startStdioServer
60
- };
61
- //# sourceMappingURL=index.js.map
75
+ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("/productive-mcp") || process.argv[1]?.endsWith("\\productive-mcp")) startStdioServer().catch((error) => {
76
+ console.error("Fatal error:", error);
77
+ process.exit(1);
78
+ });
79
+ export { createStdioServer, startStdioServer };
80
+
81
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","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);\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"],"names":[],"mappings":";;;;;;AAsCO,SAAS,oBAA4B;AAC1C,QAAM,SAAS,IAAI;AAAA,IACjB;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IAAA;AAAA,IAEX;AAAA,MACE,cAAc;AAAA,QACZ,OAAO,CAAA;AAAA,QACP,SAAS,CAAA;AAAA,MAAC;AAAA,MAEZ,cAAc;AAAA,IAAA;AAAA,EAChB;AAIF,SAAO,kBAAkB,wBAAwB,YAAY;AAC3D,WAAO,EAAE,OAAO,oBAAkB;AAAA,EACpC,CAAC;AAGD,SAAO,kBAAkB,0BAA0B,YAAY;AAC7D,WAAO,EAAE,SAAS,sBAAoB;AAAA,EACxC,CAAC;AAGD,SAAO,kBAAkB,wBAAwB,OAAO,YAAY;AAClE,WAAO,aAAa,QAAQ,OAAO,IAAI;AAAA,EACzC,CAAC;AAGD,SAAO,kBAAkB,uBAAuB,OAAO,YAAY;AACjE,UAAM,EAAE,MAAM,WAAW,KAAA,IAAS,QAAQ;AAE1C,QAAI;AACF,aAAO,MAAM,eAAe,MAAO,QAAoC,CAAA,CAAE;AAAA,IAC3E,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,OAAO,IAAI;AAAA,QACrD,SAAS;AAAA,MAAA;AAAA,IAEb;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAKA,eAAsB,mBAAkC;AACtD,QAAM,SAAS,kBAAA;AACf,QAAM,YAAY,IAAI,qBAAA;AACtB,QAAM,OAAO,QAAQ,SAAS;AAC9B,UAAQ,MAAM,0BAA0B,OAAO,mBAAmB;AACpE;AAGA,MAAM,eACJ,YAAY,QAAQ,UAAU,QAAQ,KAAK,CAAC,CAAC,MAC7C,QAAQ,KAAK,CAAC,GAAG,SAAS,iBAAiB,KAC3C,QAAQ,KAAK,CAAC,GAAG,SAAS,kBAAkB;AAE9C,IAAI,cAAc;AAChB,mBAAA,EAAmB,MAAM,CAAC,UAAU;AAClC,YAAQ,MAAM,gBAAgB,KAAK;AACnC,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;"}
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);\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,oBAA4B;CAC1C,MAAM,SAAS,IAAI,OACjB;EACE,MAAM;EACN,SAAS;EACV,EACD;EACE,cAAc;GACZ,OAAO,EAAE;GACT,SAAS,EAAE;GACZ;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,KAAK;GACxC;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"}