@studiometa/productive-mcp 0.10.8 → 0.10.10

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 (65) hide show
  1. package/README.md +9 -7
  2. package/dist/auth.js +2 -0
  3. package/dist/auth.js.map +1 -1
  4. package/dist/crypto.js +2 -0
  5. package/dist/crypto.js.map +1 -1
  6. package/dist/errors.d.ts.map +1 -1
  7. package/dist/handlers/activities.d.ts +99 -3
  8. package/dist/handlers/activities.d.ts.map +1 -1
  9. package/dist/handlers/attachments.d.ts +99 -3
  10. package/dist/handlers/attachments.d.ts.map +1 -1
  11. package/dist/handlers/bookings.d.ts +99 -3
  12. package/dist/handlers/bookings.d.ts.map +1 -1
  13. package/dist/handlers/comments.d.ts +99 -3
  14. package/dist/handlers/comments.d.ts.map +1 -1
  15. package/dist/handlers/companies.d.ts +99 -3
  16. package/dist/handlers/companies.d.ts.map +1 -1
  17. package/dist/handlers/custom-fields.d.ts +99 -3
  18. package/dist/handlers/custom-fields.d.ts.map +1 -1
  19. package/dist/handlers/deals.d.ts +99 -3
  20. package/dist/handlers/deals.d.ts.map +1 -1
  21. package/dist/handlers/discussions.d.ts +99 -3
  22. package/dist/handlers/discussions.d.ts.map +1 -1
  23. package/dist/handlers/help.d.ts.map +1 -1
  24. package/dist/handlers/pages.d.ts +99 -3
  25. package/dist/handlers/pages.d.ts.map +1 -1
  26. package/dist/handlers/projects.d.ts +99 -3
  27. package/dist/handlers/projects.d.ts.map +1 -1
  28. package/dist/handlers/schema.d.ts.map +1 -1
  29. package/dist/handlers/services.d.ts +99 -3
  30. package/dist/handlers/services.d.ts.map +1 -1
  31. package/dist/handlers/tasks.d.ts +99 -3
  32. package/dist/handlers/tasks.d.ts.map +1 -1
  33. package/dist/handlers/time.d.ts +99 -3
  34. package/dist/handlers/time.d.ts.map +1 -1
  35. package/dist/handlers/timers.d.ts +99 -3
  36. package/dist/handlers/timers.d.ts.map +1 -1
  37. package/dist/handlers/types.d.ts +1 -0
  38. package/dist/handlers/types.d.ts.map +1 -1
  39. package/dist/{handlers-t95fhdps.js → handlers-vtRpc-Lx.js} +101 -25
  40. package/dist/handlers-vtRpc-Lx.js.map +1 -0
  41. package/dist/handlers.js +1 -1
  42. package/dist/http-CVE4qtko.js +6541 -0
  43. package/dist/http-CVE4qtko.js.map +1 -0
  44. package/dist/http.d.ts +12 -7
  45. package/dist/http.d.ts.map +1 -1
  46. package/dist/http.js +2 -159
  47. package/dist/index.js +4 -3
  48. package/dist/oauth.d.ts +9 -9
  49. package/dist/oauth.d.ts.map +1 -1
  50. package/dist/oauth.js +41 -149
  51. package/dist/oauth.js.map +1 -1
  52. package/dist/schema.d.ts +62 -62
  53. package/dist/server.js +6 -5
  54. package/dist/server.js.map +1 -1
  55. package/dist/{stdio-Bi1Lvp8O.js → stdio-BFK9AcdQ.js} +9 -3
  56. package/dist/{stdio-Bi1Lvp8O.js.map → stdio-BFK9AcdQ.js.map} +1 -1
  57. package/dist/stdio.d.ts +4 -4
  58. package/dist/stdio.js +1 -2
  59. package/dist/tools.js +4 -2
  60. package/dist/tools.js.map +1 -1
  61. package/dist/{version-DpBFJ7eV.js → version-Cy8UEAT1.js} +13 -7
  62. package/dist/{version-DpBFJ7eV.js.map → version-Cy8UEAT1.js.map} +1 -1
  63. package/package.json +10 -18
  64. package/dist/handlers-t95fhdps.js.map +0 -1
  65. package/dist/http.js.map +0 -1
package/dist/http.d.ts CHANGED
@@ -4,7 +4,9 @@
4
4
  * This module contains the app/router creation logic for the HTTP transport.
5
5
  * The actual server startup is in server.ts.
6
6
  */
7
- import { type App } from 'h3';
7
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
9
+ import { H3 } from 'h3';
8
10
  /**
9
11
  * JSON-RPC error response
10
12
  */
@@ -35,6 +37,7 @@ export declare function handleInitialize(): {
35
37
  };
36
38
  capabilities: {
37
39
  tools: {};
40
+ prompts: {};
38
41
  resources: {};
39
42
  };
40
43
  instructions: string;
@@ -44,6 +47,7 @@ export declare function handleInitialize(): {
44
47
  */
45
48
  export declare function handleToolsList(): {
46
49
  tools: {
50
+ description?: string | undefined;
47
51
  inputSchema: {
48
52
  [x: string]: unknown;
49
53
  type: "object";
@@ -52,8 +56,6 @@ export declare function handleToolsList(): {
52
56
  } | undefined;
53
57
  required?: string[] | undefined;
54
58
  };
55
- name: string;
56
- description?: string | undefined;
57
59
  outputSchema?: {
58
60
  [x: string]: unknown;
59
61
  type: "object";
@@ -70,7 +72,7 @@ export declare function handleToolsList(): {
70
72
  openWorldHint?: boolean | undefined;
71
73
  } | undefined;
72
74
  execution?: {
73
- taskSupport?: "optional" | "required" | "forbidden" | undefined;
75
+ taskSupport?: "forbidden" | "optional" | "required" | undefined;
74
76
  } | undefined;
75
77
  _meta?: {
76
78
  [x: string]: unknown;
@@ -79,13 +81,16 @@ export declare function handleToolsList(): {
79
81
  src: string;
80
82
  mimeType?: string | undefined;
81
83
  sizes?: string[] | undefined;
82
- theme?: "light" | "dark" | undefined;
84
+ theme?: "dark" | "light" | undefined;
83
85
  }[] | undefined;
86
+ name: string;
84
87
  title?: string | undefined;
85
88
  }[];
86
89
  };
90
+ export declare function createHttpMcpServer(): Server;
91
+ export declare function createHttpMcpTransport(): Promise<StreamableHTTPServerTransport>;
87
92
  /**
88
- * Create the h3 application with all routes
93
+ * Create the H3 application with all routes
89
94
  */
90
- export declare function createHttpApp(): App;
95
+ export declare function createHttpApp(): H3;
91
96
  //# sourceMappingURL=http.d.ts.map
@@ -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;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"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAYnG,OAAO,EAAE,EAAE,EAA+B,MAAM,IAAI,CAAC;AAmBrD;;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;;;;;;;;;;;;EAc/B;AAED;;GAEG;AACH,wBAAgB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAE9B;AA6DD,wBAAgB,mBAAmB,IAAI,MAAM,CAwD5C;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,6BAA6B,CAAC,CAUrF;AAuBD;;GAEG;AACH,wBAAgB,aAAa,IAAI,EAAE,CA2FlC"}
package/dist/http.js CHANGED
@@ -1,159 +1,2 @@
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";
3
- import { TOOLS } from "./tools.js";
4
- import { parseAuthHeader } from "./auth.js";
5
- import { authorizeGetHandler, authorizePostHandler, oauthMetadataHandler, registerHandler, tokenHandler } from "./oauth.js";
6
- import { createApp, createRouter, defineEventHandler, getHeader, readBody, setResponseHeader } from "h3";
7
- /**
8
- * HTTP transport handlers for Productive MCP Server
9
- *
10
- * This module contains the app/router creation logic for the HTTP transport.
11
- * The actual server startup is in server.ts.
12
- */
13
- /**
14
- * JSON-RPC error response
15
- */
16
- function jsonRpcError(code, message, id = null) {
17
- return {
18
- jsonrpc: "2.0",
19
- error: {
20
- code,
21
- message
22
- },
23
- id
24
- };
25
- }
26
- /**
27
- * JSON-RPC success response
28
- */
29
- function jsonRpcSuccess(result, id = null) {
30
- return {
31
- jsonrpc: "2.0",
32
- result,
33
- id
34
- };
35
- }
36
- /**
37
- * Handle the initialize JSON-RPC method
38
- */
39
- function handleInitialize() {
40
- return {
41
- protocolVersion: "2024-11-05",
42
- serverInfo: {
43
- name: "productive-mcp",
44
- version: VERSION
45
- },
46
- capabilities: {
47
- tools: {},
48
- resources: {}
49
- },
50
- instructions: INSTRUCTIONS
51
- };
52
- }
53
- /**
54
- * Handle the tools/list JSON-RPC method
55
- */
56
- function handleToolsList() {
57
- return { tools: TOOLS };
58
- }
59
- /**
60
- * Create the h3 application with all routes
61
- */
62
- function createHttpApp() {
63
- const app = createApp();
64
- const router = createRouter();
65
- router.get("/.well-known/oauth-authorization-server", oauthMetadataHandler);
66
- router.post("/register", registerHandler);
67
- router.get("/authorize", authorizeGetHandler);
68
- router.post("/authorize", authorizePostHandler);
69
- router.post("/token", tokenHandler);
70
- router.get("/.well-known/oauth-protected-resource", defineEventHandler((event) => {
71
- const host = event.node.req.headers.host || "localhost:3000";
72
- const baseUrl = `${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`;
73
- setResponseHeader(event, "Content-Type", "application/json");
74
- setResponseHeader(event, "Cache-Control", "public, max-age=3600");
75
- return {
76
- resource: `${baseUrl}/mcp`,
77
- authorization_servers: [baseUrl],
78
- scopes_supported: ["productive"],
79
- bearer_methods_supported: ["header"]
80
- };
81
- }));
82
- router.get("/", defineEventHandler(() => {
83
- return {
84
- status: "ok",
85
- service: "productive-mcp",
86
- version: VERSION
87
- };
88
- }));
89
- router.get("/health", defineEventHandler(() => {
90
- return { status: "ok" };
91
- }));
92
- router.post("/mcp", defineEventHandler(async (event) => {
93
- const credentials = parseAuthHeader(getHeader(event, "authorization"));
94
- if (!credentials) {
95
- const host = event.node.req.headers.host || "localhost:3000";
96
- const baseUrl = `${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`;
97
- setResponseHeader(event, "Content-Type", "application/json");
98
- setResponseHeader(event, "WWW-Authenticate", `Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource"`);
99
- event.node.res.statusCode = 401;
100
- return jsonRpcError(-32001, "Authentication required. Provide Bearer token with base64(organizationId:apiToken:userId)");
101
- }
102
- setResponseHeader(event, "Content-Type", "application/json");
103
- let body;
104
- try {
105
- body = await readBody(event);
106
- } catch {
107
- event.node.res.statusCode = 400;
108
- return jsonRpcError(-32700, "Parse error: Invalid JSON");
109
- }
110
- if (!body || typeof body !== "object") {
111
- event.node.res.statusCode = 400;
112
- return jsonRpcError(-32700, "Parse error: Invalid JSON");
113
- }
114
- const { method, params, id } = body;
115
- try {
116
- if (method === "initialize") return jsonRpcSuccess(handleInitialize(), id ?? null);
117
- if (method === "tools/list") return jsonRpcSuccess(handleToolsList(), id ?? null);
118
- if (method === "tools/call") {
119
- const { name, arguments: args } = params;
120
- return jsonRpcSuccess(await executeToolWithCredentials(name, args || {}, credentials), id ?? null);
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
- }
129
- return jsonRpcError(-32601, `Method not found: ${method}`, id ?? null);
130
- } catch (error) {
131
- return jsonRpcError(-32603, `Internal error: ${error instanceof Error ? error.message : String(error)}`, id ?? null);
132
- }
133
- }));
134
- router.get("/mcp/sse", defineEventHandler(async (event) => {
135
- if (!parseAuthHeader(getHeader(event, "authorization"))) {
136
- const host = event.node.req.headers.host || "localhost:3000";
137
- setResponseHeader(event, "WWW-Authenticate", `Bearer resource_metadata="${`${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`}/.well-known/oauth-protected-resource"`);
138
- event.node.res.statusCode = 401;
139
- return { error: "Authentication required" };
140
- }
141
- setResponseHeader(event, "Content-Type", "text/event-stream");
142
- setResponseHeader(event, "Cache-Control", "no-cache");
143
- setResponseHeader(event, "Connection", "keep-alive");
144
- const sessionId = crypto.randomUUID();
145
- event.node.res.write(`event: session\ndata: ${JSON.stringify({ sessionId })}\n\n`);
146
- const keepAlive = setInterval(() => {
147
- event.node.res.write(": keepalive\n\n");
148
- }, 3e4);
149
- event.node.req.on("close", () => {
150
- clearInterval(keepAlive);
151
- });
152
- return new Promise(() => {});
153
- }));
154
- app.use(router);
155
- return app;
156
- }
157
- export { createHttpApp, handleInitialize, handleToolsList, jsonRpcError, jsonRpcSuccess };
158
-
159
- //# sourceMappingURL=http.js.map
1
+ import { a as handleToolsList, i as handleInitialize, n as createHttpMcpServer, o as jsonRpcError, r as createHttpMcpTransport, s as jsonRpcSuccess, t as createHttpApp } from "./http-CVE4qtko.js";
2
+ export { createHttpApp, createHttpMcpServer, createHttpMcpTransport, handleInitialize, handleToolsList, jsonRpcError, jsonRpcSuccess };
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-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";
2
+ import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-Cy8UEAT1.js";
3
+ import { a as handlePrompt, n as getAvailableTools, s as handleToolCall, t as getAvailablePrompts } from "./stdio-BFK9AcdQ.js";
5
4
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
6
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
6
  import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
8
7
  import { getConfig } from "@studiometa/productive-api";
8
+ //#region src/index.ts
9
9
  /**
10
10
  * Productive MCP Server - Stdio Transport
11
11
  *
@@ -94,6 +94,7 @@ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith
94
94
  console.error("Fatal error:", error);
95
95
  process.exit(1);
96
96
  });
97
+ //#endregion
97
98
  export { createStdioServer, startStdioServer };
98
99
 
99
100
  //# sourceMappingURL=index.js.map
package/dist/oauth.d.ts CHANGED
@@ -20,7 +20,7 @@
20
20
  *
21
21
  * MCP clients MUST check this endpoint first for server capabilities.
22
22
  */
23
- export declare const oauthMetadataHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, {
23
+ export declare const oauthMetadataHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, {
24
24
  issuer: string;
25
25
  authorization_endpoint: string;
26
26
  token_endpoint: string;
@@ -40,7 +40,7 @@ export declare const oauthMetadataHandler: import("h3").EventHandler<import("h3"
40
40
  * Since we use stateless tokens, we accept any registration and return
41
41
  * a generated client_id.
42
42
  */
43
- export declare const registerHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
43
+ export declare const registerHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
44
44
  error: string;
45
45
  error_description: string;
46
46
  client_id?: undefined;
@@ -50,25 +50,25 @@ export declare const registerHandler: import("h3").EventHandler<import("h3").Eve
50
50
  grant_types?: undefined;
51
51
  response_types?: undefined;
52
52
  } | {
53
+ error?: undefined;
54
+ error_description?: undefined;
53
55
  client_id: string;
54
56
  client_name: string;
55
57
  redirect_uris: string[];
56
58
  token_endpoint_auth_method: string;
57
59
  grant_types: string[];
58
60
  response_types: string[];
59
- error?: undefined;
60
- error_description?: undefined;
61
61
  }>>;
62
62
  /**
63
63
  * Authorization endpoint - shows login form
64
64
  * GET /authorize
65
65
  */
66
- export declare const authorizeGetHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, string | Promise<void>>;
66
+ export declare const authorizeGetHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, string | import("h3").HTTPResponse>;
67
67
  /**
68
68
  * Authorization endpoint - process login
69
69
  * POST /authorize
70
70
  */
71
- export declare const authorizePostHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<string>>;
71
+ export declare const authorizePostHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<string | import("h3").HTTPResponse>>;
72
72
  /**
73
73
  * Token endpoint - exchange code for access token
74
74
  * POST /token
@@ -77,7 +77,7 @@ export declare const authorizePostHandler: import("h3").EventHandler<import("h3"
77
77
  * - authorization_code grant (with PKCE validation)
78
78
  * - refresh_token grant
79
79
  */
80
- export declare const tokenHandler: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
80
+ export declare const tokenHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
81
81
  error: string;
82
82
  error_description: string;
83
83
  access_token?: undefined;
@@ -85,11 +85,11 @@ export declare const tokenHandler: import("h3").EventHandler<import("h3").EventH
85
85
  expires_in?: undefined;
86
86
  refresh_token?: undefined;
87
87
  } | {
88
+ error?: undefined;
89
+ error_description?: undefined;
88
90
  access_token: string;
89
91
  token_type: string;
90
92
  expires_in: number;
91
93
  refresh_token: string;
92
- error?: undefined;
93
- error_description?: undefined;
94
94
  }>>;
95
95
  //# sourceMappingURL=oauth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAeH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;EAyB/B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;GAoC1B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,qFA+C9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,8EAyD/B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;GA+FvB,CAAC"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;EAyB/B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;GAoC1B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,0GA+C9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,mHA0D/B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;GA2FvB,CAAC"}
package/dist/oauth.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { createAuthToken } from "./auth.js";
2
2
  import { createAuthCode, decodeAuthCode } from "./crypto.js";
3
- import { defineEventHandler, getQuery, readBody, sendRedirect, setResponseHeader } from "h3";
3
+ import { defineHandler, getQuery, redirect } from "h3";
4
4
  import { createHash } from "node:crypto";
5
+ //#region src/oauth.ts
5
6
  /**
6
7
  * OAuth 2.0 endpoints for Claude Desktop integration
7
8
  *
@@ -24,11 +25,11 @@ import { createHash } from "node:crypto";
24
25
  *
25
26
  * MCP clients MUST check this endpoint first for server capabilities.
26
27
  */
27
- const oauthMetadataHandler = defineEventHandler((event) => {
28
- const host = event.node.req.headers.host || "localhost:3000";
29
- const baseUrl = `${event.node.req.headers["x-forwarded-proto"] || "http"}://${host}`;
30
- setResponseHeader(event, "Content-Type", "application/json");
31
- setResponseHeader(event, "Cache-Control", "public, max-age=3600");
28
+ var oauthMetadataHandler = defineHandler((event) => {
29
+ const host = event.req.headers.get("host") || "localhost:3000";
30
+ const baseUrl = `${event.req.headers.get("x-forwarded-proto") || "http"}://${host}`;
31
+ event.res.headers.set("Content-Type", "application/json");
32
+ event.res.headers.set("Cache-Control", "public, max-age=3600");
32
33
  return {
33
34
  issuer: baseUrl,
34
35
  authorization_endpoint: `${baseUrl}/authorize`,
@@ -50,13 +51,13 @@ const oauthMetadataHandler = defineEventHandler((event) => {
50
51
  * Since we use stateless tokens, we accept any registration and return
51
52
  * a generated client_id.
52
53
  */
53
- const registerHandler = defineEventHandler(async (event) => {
54
- setResponseHeader(event, "Content-Type", "application/json");
54
+ var registerHandler = defineHandler(async (event) => {
55
+ event.res.headers.set("Content-Type", "application/json");
55
56
  let body;
56
57
  try {
57
- body = await readBody(event);
58
+ body = await event.req.json();
58
59
  } catch {
59
- event.node.res.statusCode = 400;
60
+ event.res.status = 400;
60
61
  return {
61
62
  error: "invalid_request",
62
63
  error_description: "Invalid JSON body"
@@ -68,7 +69,7 @@ const registerHandler = defineEventHandler(async (event) => {
68
69
  name: clientName,
69
70
  ts: Date.now()
70
71
  })).toString("base64url");
71
- event.node.res.statusCode = 201;
72
+ event.res.status = 201;
72
73
  return {
73
74
  client_id: clientId,
74
75
  client_name: clientName,
@@ -82,7 +83,7 @@ const registerHandler = defineEventHandler(async (event) => {
82
83
  * Authorization endpoint - shows login form
83
84
  * GET /authorize
84
85
  */
85
- const authorizeGetHandler = defineEventHandler((event) => {
86
+ var authorizeGetHandler = defineHandler((event) => {
86
87
  const query = getQuery(event);
87
88
  const clientId = query.client_id;
88
89
  const redirectUri = query.redirect_uri;
@@ -91,8 +92,8 @@ const authorizeGetHandler = defineEventHandler((event) => {
91
92
  const codeChallengeMethod = query.code_challenge_method;
92
93
  const scope = query.scope;
93
94
  if (!redirectUri) {
94
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
95
- event.node.res.statusCode = 400;
95
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
96
+ event.res.status = 400;
96
97
  return renderErrorPage("Missing required parameter: redirect_uri");
97
98
  }
98
99
  if (!codeChallenge) {
@@ -100,16 +101,16 @@ const authorizeGetHandler = defineEventHandler((event) => {
100
101
  errorUrl.searchParams.set("error", "invalid_request");
101
102
  errorUrl.searchParams.set("error_description", "code_challenge is required");
102
103
  if (state) errorUrl.searchParams.set("state", state);
103
- return sendRedirect(event, errorUrl.toString());
104
+ return redirect(errorUrl.toString());
104
105
  }
105
106
  if (codeChallengeMethod && codeChallengeMethod !== "S256") {
106
107
  const errorUrl = new URL(redirectUri);
107
108
  errorUrl.searchParams.set("error", "invalid_request");
108
109
  errorUrl.searchParams.set("error_description", "Only S256 code_challenge_method is supported");
109
110
  if (state) errorUrl.searchParams.set("state", state);
110
- return sendRedirect(event, errorUrl.toString());
111
+ return redirect(errorUrl.toString());
111
112
  }
112
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
113
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
113
114
  return renderLoginForm({
114
115
  clientId,
115
116
  redirectUri,
@@ -123,11 +124,12 @@ const authorizeGetHandler = defineEventHandler((event) => {
123
124
  * Authorization endpoint - process login
124
125
  * POST /authorize
125
126
  */
126
- const authorizePostHandler = defineEventHandler(async (event) => {
127
- const { orgId, apiToken, userId, redirectUri, state, codeChallenge, codeChallengeMethod } = await readBody(event);
127
+ var authorizePostHandler = defineHandler(async (event) => {
128
+ const formData = await event.req.formData();
129
+ const { orgId, apiToken, userId, redirectUri, state, codeChallenge, codeChallengeMethod } = Object.fromEntries(formData.entries());
128
130
  if (!redirectUri) {
129
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
130
- event.node.res.statusCode = 400;
131
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
132
+ event.res.status = 400;
131
133
  return renderErrorPage("Missing redirect_uri parameter");
132
134
  }
133
135
  try {
@@ -135,15 +137,15 @@ const authorizePostHandler = defineEventHandler(async (event) => {
135
137
  const isLocalhost = uri.hostname === "localhost" || uri.hostname === "127.0.0.1";
136
138
  const isHttps = uri.protocol === "https:";
137
139
  if (!isLocalhost && !isHttps) {
138
- event.node.res.statusCode = 400;
140
+ event.res.status = 400;
139
141
  return renderErrorPage("redirect_uri must be HTTPS or localhost");
140
142
  }
141
143
  } catch {
142
- event.node.res.statusCode = 400;
144
+ event.res.status = 400;
143
145
  return renderErrorPage("Invalid redirect_uri format");
144
146
  }
145
147
  if (!orgId || !apiToken) {
146
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
148
+ event.res.headers.set("Content-Type", "text/html; charset=utf-8");
147
149
  return renderLoginForm({
148
150
  redirectUri,
149
151
  state,
@@ -162,8 +164,7 @@ const authorizePostHandler = defineEventHandler(async (event) => {
162
164
  const redirectUrl = new URL(redirectUri);
163
165
  redirectUrl.searchParams.set("code", code);
164
166
  if (state) redirectUrl.searchParams.set("state", state);
165
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
166
- return renderSuccessPage(redirectUrl.toString());
167
+ return redirect(redirectUrl.toString());
167
168
  });
168
169
  /**
169
170
  * Token endpoint - exchange code for access token
@@ -173,32 +174,31 @@ const authorizePostHandler = defineEventHandler(async (event) => {
173
174
  * - authorization_code grant (with PKCE validation)
174
175
  * - refresh_token grant
175
176
  */
176
- const tokenHandler = defineEventHandler(async (event) => {
177
- setResponseHeader(event, "Content-Type", "application/json");
177
+ var tokenHandler = defineHandler(async (event) => {
178
+ event.res.headers.set("Content-Type", "application/json");
178
179
  let body;
179
- if ((event.node.req.headers["content-type"] || "").includes("application/x-www-form-urlencoded")) {
180
- const rawBody = await readBody(event);
181
- if (typeof rawBody === "string") body = Object.fromEntries(new URLSearchParams(rawBody));
182
- else body = rawBody;
183
- } else body = await readBody(event);
180
+ if ((event.req.headers.get("content-type") || "").includes("application/x-www-form-urlencoded")) {
181
+ const rawText = await event.req.text();
182
+ body = Object.fromEntries(new URLSearchParams(rawText));
183
+ } else body = await event.req.json();
184
184
  const { grant_type, code, code_verifier, refresh_token } = body;
185
185
  if (grant_type === "refresh_token") return handleRefreshToken(event, refresh_token);
186
186
  if (grant_type !== "authorization_code") {
187
- event.node.res.statusCode = 400;
187
+ event.res.status = 400;
188
188
  return {
189
189
  error: "unsupported_grant_type",
190
190
  error_description: "Supported grant types: authorization_code, refresh_token"
191
191
  };
192
192
  }
193
193
  if (!code) {
194
- event.node.res.statusCode = 400;
194
+ event.res.status = 400;
195
195
  return {
196
196
  error: "invalid_request",
197
197
  error_description: "Missing authorization code"
198
198
  };
199
199
  }
200
200
  if (!code_verifier) {
201
- event.node.res.statusCode = 400;
201
+ event.res.status = 400;
202
202
  return {
203
203
  error: "invalid_request",
204
204
  error_description: "Missing code_verifier (PKCE required)"
@@ -208,7 +208,7 @@ const tokenHandler = defineEventHandler(async (event) => {
208
208
  const payload = decodeAuthCode(code);
209
209
  if (payload.codeChallenge) {
210
210
  if (createS256Challenge(code_verifier) !== payload.codeChallenge) {
211
- event.node.res.statusCode = 400;
211
+ event.res.status = 400;
212
212
  return {
213
213
  error: "invalid_grant",
214
214
  error_description: "Invalid code_verifier"
@@ -230,7 +230,7 @@ const tokenHandler = defineEventHandler(async (event) => {
230
230
  }, 86400 * 30)
231
231
  };
232
232
  } catch (error) {
233
- event.node.res.statusCode = 400;
233
+ event.res.status = 400;
234
234
  return {
235
235
  error: "invalid_grant",
236
236
  error_description: error instanceof Error ? error.message : "Invalid authorization code"
@@ -242,7 +242,7 @@ const tokenHandler = defineEventHandler(async (event) => {
242
242
  */
243
243
  function handleRefreshToken(event, refreshToken) {
244
244
  if (!refreshToken) {
245
- event.node.res.statusCode = 400;
245
+ event.res.status = 400;
246
246
  return {
247
247
  error: "invalid_request",
248
248
  error_description: "Missing refresh_token"
@@ -265,7 +265,7 @@ function handleRefreshToken(event, refreshToken) {
265
265
  }, 86400 * 30)
266
266
  };
267
267
  } catch (error) {
268
- event.node.res.statusCode = 400;
268
+ event.res.status = 400;
269
269
  return {
270
270
  error: "invalid_grant",
271
271
  error_description: error instanceof Error ? error.message : "Invalid refresh token"
@@ -457,115 +457,6 @@ function renderLoginForm(params) {
457
457
  </html>`;
458
458
  }
459
459
  /**
460
- * Render success page with auto-redirect
461
- */
462
- function renderSuccessPage(redirectUrl) {
463
- return `<!DOCTYPE html>
464
- <html lang="en">
465
- <head>
466
- <meta charset="UTF-8">
467
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
468
- <meta http-equiv="refresh" content="2;url=${escapeHtml(redirectUrl)}">
469
- <title>Connected - Productive MCP</title>
470
- <style>
471
- * {
472
- box-sizing: border-box;
473
- margin: 0;
474
- padding: 0;
475
- }
476
- body {
477
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
478
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
479
- min-height: 100vh;
480
- display: flex;
481
- align-items: center;
482
- justify-content: center;
483
- padding: 20px;
484
- }
485
- .container {
486
- background: white;
487
- border-radius: 16px;
488
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
489
- padding: 40px;
490
- width: 100%;
491
- max-width: 420px;
492
- text-align: center;
493
- }
494
- .success-icon {
495
- width: 64px;
496
- height: 64px;
497
- margin: 0 auto 24px;
498
- background: linear-gradient(135deg, #10b981 0%, #059669 100%);
499
- border-radius: 50%;
500
- display: flex;
501
- align-items: center;
502
- justify-content: center;
503
- }
504
- .success-icon svg {
505
- width: 32px;
506
- height: 32px;
507
- stroke: white;
508
- }
509
- h1 {
510
- color: #1a1a2e;
511
- font-size: 24px;
512
- margin-bottom: 8px;
513
- }
514
- .message {
515
- color: #666;
516
- font-size: 14px;
517
- margin-bottom: 24px;
518
- }
519
- .spinner {
520
- width: 24px;
521
- height: 24px;
522
- border: 3px solid #e5e7eb;
523
- border-top-color: #667eea;
524
- border-radius: 50%;
525
- animation: spin 1s linear infinite;
526
- margin: 0 auto 16px;
527
- }
528
- @keyframes spin {
529
- to { transform: rotate(360deg); }
530
- }
531
- .redirect-text {
532
- color: #9ca3af;
533
- font-size: 13px;
534
- margin-bottom: 16px;
535
- }
536
- .manual-link {
537
- color: #667eea;
538
- text-decoration: none;
539
- font-size: 14px;
540
- }
541
- .manual-link:hover {
542
- text-decoration: underline;
543
- }
544
- </style>
545
- </head>
546
- <body>
547
- <div class="container">
548
- <div class="success-icon">
549
- <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
550
- <path d="M20 6L9 17L4 12" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
551
- </svg>
552
- </div>
553
- <h1>Successfully Connected!</h1>
554
- <p class="message">Your Productive.io credentials have been verified.</p>
555
- <div class="spinner"></div>
556
- <p class="redirect-text">Redirecting to Claude Desktop...</p>
557
- <a href="${escapeHtml(redirectUrl)}" class="manual-link">Click here if not redirected automatically</a>
558
- </div>
559
- <script>
560
- // Redirect after a short delay (backup for meta refresh)
561
- setTimeout(function() {
562
- window.location.href = ${JSON.stringify(redirectUrl)};
563
- }, 2000);
564
- <\/script>
565
- </body>
566
- </html>`;
567
- }
568
- /**
569
460
  * Render error page
570
461
  */
571
462
  function renderErrorPage(message) {
@@ -616,6 +507,7 @@ function renderErrorPage(message) {
616
507
  function escapeHtml(str) {
617
508
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
618
509
  }
510
+ //#endregion
619
511
  export { authorizeGetHandler, authorizePostHandler, oauthMetadataHandler, registerHandler, tokenHandler };
620
512
 
621
513
  //# sourceMappingURL=oauth.js.map