@hapticpaper/mcp-server 1.0.31 → 1.0.32

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.
@@ -5,6 +5,7 @@ export class HapticPaperClient {
5
5
  constructor(config) {
6
6
  this.client = axios.create({
7
7
  baseURL: config.baseUrl,
8
+ timeout: 30000, // 30 second timeout to prevent indefinite hangs
8
9
  headers: {
9
10
  'Content-Type': 'application/json',
10
11
  },
@@ -23,9 +24,20 @@ export class HapticPaperClient {
23
24
  // Response interceptor to handle auth errors
24
25
  this.client.interceptors.response.use((response) => response, async (error) => {
25
26
  const originalRequest = error.config;
27
+ // Log errors for debugging (but not in production to avoid log spam)
28
+ if (process.env.NODE_ENV !== 'production') {
29
+ console.error('[HapticPaperClient] Request failed:', {
30
+ url: error.config?.url,
31
+ method: error.config?.method,
32
+ status: error.response?.status,
33
+ message: error.message,
34
+ code: error.code,
35
+ });
36
+ }
26
37
  if (error.response?.status === 401 && !originalRequest._retry && config.onAuthError) {
27
38
  originalRequest._retry = true;
28
39
  try {
40
+ console.error('[HapticPaperClient] Auth error, attempting token refresh');
29
41
  const newToken = await config.onAuthError();
30
42
  if (typeof newToken === 'string') {
31
43
  originalRequest.headers.Authorization = `Bearer ${newToken}`;
@@ -33,6 +45,7 @@ export class HapticPaperClient {
33
45
  }
34
46
  }
35
47
  catch (authError) {
48
+ console.error('[HapticPaperClient] Token refresh failed:', authError instanceof Error ? authError.message : String(authError));
36
49
  return Promise.reject(authError);
37
50
  }
38
51
  }
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { requireScopes } from "../auth/access.js";
3
3
  import { HAPTICPAPER_WIDGET_URI } from "../constants/widget.js";
4
+ import { handleToolError } from "./errorHandler.js";
4
5
  function oauthSecuritySchemes(scopes) {
5
6
  return [
6
7
  { type: 'oauth2', scopes },
@@ -106,10 +107,7 @@ export function registerAccountTools(server, client) {
106
107
  }
107
108
  }
108
109
  catch (err) {
109
- return {
110
- content: [{ type: 'text', text: `Error: ${err.message}` }],
111
- isError: true,
112
- };
110
+ return handleToolError(err, 'Account Tool');
113
111
  }
114
112
  };
115
113
  server.registerTool('account', {
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Formats errors from tool handlers into user-friendly messages
3
+ * and logs detailed error information for debugging
4
+ */
5
+ export function handleToolError(err, toolName) {
6
+ let errorMessage = 'An unexpected error occurred';
7
+ if (err.code === 'ECONNABORTED' || err.code === 'ETIMEDOUT') {
8
+ errorMessage = 'Request timed out. The backend service may be unavailable.';
9
+ console.error(`[${toolName}] Timeout error:`, err.message);
10
+ }
11
+ else if (err.response?.status === 401) {
12
+ errorMessage = 'Authentication failed. Your session may have expired. Please reconnect.';
13
+ console.error(`[${toolName}] Auth error:`, {
14
+ status: err.response.status,
15
+ data: err.response.data,
16
+ });
17
+ }
18
+ else if (err.response?.status === 403) {
19
+ errorMessage = 'Access denied. You may not have permission for this action.';
20
+ console.error(`[${toolName}] Permission error:`, {
21
+ status: err.response.status,
22
+ data: err.response.data,
23
+ });
24
+ }
25
+ else if (err.response?.status === 404) {
26
+ errorMessage = 'Resource not found.';
27
+ console.error(`[${toolName}] Not found error:`, {
28
+ status: err.response.status,
29
+ url: err.config?.url,
30
+ });
31
+ }
32
+ else if (err.response?.status >= 500) {
33
+ errorMessage = 'Backend service error. Please try again later.';
34
+ console.error(`[${toolName}] Server error:`, {
35
+ status: err.response.status,
36
+ data: err.response.data,
37
+ });
38
+ }
39
+ else if (err.message) {
40
+ errorMessage = err.message;
41
+ console.error(`[${toolName}] Error:`, err.message);
42
+ }
43
+ else {
44
+ console.error(`[${toolName}] Unknown error:`, err);
45
+ }
46
+ return {
47
+ content: [{ type: 'text', text: `Error: ${errorMessage}` }],
48
+ isError: true,
49
+ };
50
+ }
51
+ /**
52
+ * Logs successful tool invocations for debugging
53
+ */
54
+ export function logToolSuccess(toolName, action, details) {
55
+ if (process.env.NODE_ENV !== 'production') {
56
+ console.log(`[${toolName}] Success:`, { action, ...details });
57
+ }
58
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hapticpaper/mcp-server",
3
3
  "mcpName": "com.hapticpaper/mcp",
4
- "version": "1.0.31",
4
+ "version": "1.0.32",
5
5
  "description": "Official MCP Server for Haptic Paper - Connect your account to create human tasks from agentic pipelines.",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
package/server.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "subfolder": "packages/mcp-server"
26
26
  },
27
27
  "websiteUrl": "https://hapticpaper.com/developer",
28
- "version": "1.0.31",
28
+ "version": "1.0.32",
29
29
  "remotes": [
30
30
  {
31
31
  "type": "streamable-http",
@@ -37,7 +37,7 @@
37
37
  "registryType": "npm",
38
38
  "registryBaseUrl": "https://registry.npmjs.org",
39
39
  "identifier": "@hapticpaper/mcp-server",
40
- "version": "1.0.31",
40
+ "version": "1.0.32",
41
41
  "transport": {
42
42
  "type": "stdio"
43
43
  },