timezest-mcp 1.0.1 → 1.0.4

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/README.md CHANGED
@@ -28,8 +28,8 @@ Add this entry to the `mcpServers` section:
28
28
  {
29
29
  "mcpServers": {
30
30
  "timezest": {
31
- "command": "npx",
32
- "args": ["-y", "timezest-mcp@latest"],
31
+ "command": "cmd",
32
+ "args": ["/c", "npx", "-y", "timezest-mcp@latest"],
33
33
  "env": {
34
34
  "TIMEZEST_API_KEY": "YOUR_API_KEY_HERE",
35
35
  "TIMEZEST_DEFAULT_TZ": "America/Chicago"
@@ -43,7 +43,7 @@ Add this entry to the `mcpServers` section:
43
43
  If you use the terminal-based **Claude Code**, run this single command to add the server globally:
44
44
 
45
45
  ```bash
46
- claude mcp add-json timezest "{\"type\": \"stdio\", \"command\": \"npx\", \"args\": [\"-y\", \"timezest-mcp@latest\"], \"env\": {\"TIMEZEST_API_KEY\": \"YOUR_API_KEY_HERE\", \"TIMEZEST_DEFAULT_TZ\": \"America/Chicago\"}}"
46
+ claude mcp add-json timezest "{\"type\": \"stdio\", \"command\": \"cmd\", \"args\": [\"/c\", \"npx\", \"-y\", \"timezest-mcp@latest\"], \"env\": {\"TIMEZEST_API_KEY\": \"YOUR_API_KEY_HERE\", \"TIMEZEST_DEFAULT_TZ\": \"America/Chicago\"}}"
47
47
  ```
48
48
 
49
49
  ---
package/build/client.js CHANGED
@@ -17,15 +17,27 @@ export class TimeZestClient {
17
17
  headers: { Authorization: `Bearer ${this.apiKey}` }
18
18
  });
19
19
  const data = response.data;
20
+ // Handle both flat arrays and wrapped responses (e.g., { scheduling_requests: [...] })
21
+ let items;
20
22
  if (Array.isArray(data)) {
21
- results.push(...data);
22
- if (data.length < 50)
23
- break; // TimeZest pagination limit
23
+ items = data;
24
+ }
25
+ else if (data && typeof data === 'object') {
26
+ // Find the first array value in the response object
27
+ const arrayValue = Object.values(data).find(v => Array.isArray(v));
28
+ if (arrayValue) {
29
+ items = arrayValue;
30
+ }
31
+ else {
32
+ throw new Error(`Unexpected API response format from ${endpoint}: ${JSON.stringify(data).slice(0, 200)}`);
33
+ }
24
34
  }
25
35
  else {
26
- // Unexpected format
27
- break;
36
+ throw new Error(`Unexpected API response format from ${endpoint}: ${typeof data}`);
28
37
  }
38
+ results.push(...items);
39
+ if (items.length < 50)
40
+ break;
29
41
  page++;
30
42
  }
31
43
  return results;
@@ -41,17 +53,22 @@ export class TimeZestClient {
41
53
  return this.appointmentTypes;
42
54
  }
43
55
  catch (error) {
44
- console.error('Error fetching appointment types:', error);
45
- return new Map();
56
+ const status = error?.response?.status;
57
+ const msg = error?.response?.data?.message || error?.message || String(error);
58
+ throw new Error(`TimeZest API error fetching appointment types (HTTP ${status || 'unknown'}): ${msg}`);
46
59
  }
47
60
  }
48
61
  /**
49
- * Fetches the standard 45-day window (14 days back, 30 forward) by created_at.
62
+ * Fetches scheduling requests for a configurable window by created_at.
63
+ * Falls back to env vars TIMEZEST_WINDOW_DAYS_BACK / TIMEZEST_WINDOW_DAYS_FORWARD,
64
+ * then to 14 / 30 defaults.
50
65
  */
51
- async getStandardWindowRequests() {
66
+ async getSchedulingRequests(daysBack, daysForward) {
67
+ const back = daysBack ?? parseInt(process.env.TIMEZEST_WINDOW_DAYS_BACK || '14', 10);
68
+ const forward = daysForward ?? parseInt(process.env.TIMEZEST_WINDOW_DAYS_FORWARD || '30', 10);
52
69
  const now = new Date();
53
- const start = subDays(now, 14);
54
- const end = addDays(now, 30);
70
+ const start = subDays(now, back);
71
+ const end = addDays(now, forward);
55
72
  // API limits filters to created_at
56
73
  const params = {
57
74
  created_at_after: getUnixTime(start),
@@ -61,8 +78,9 @@ export class TimeZestClient {
61
78
  return await this.fetchAllPages('/scheduling_requests', params);
62
79
  }
63
80
  catch (error) {
64
- console.error('Error fetching scheduling requests:', error);
65
- return [];
81
+ const status = error?.response?.status;
82
+ const msg = error?.response?.data?.message || error?.message || String(error);
83
+ throw new Error(`TimeZest API error fetching scheduling requests (HTTP ${status || 'unknown'}): ${msg}`);
66
84
  }
67
85
  }
68
86
  }
package/build/index.js CHANGED
@@ -116,10 +116,23 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
116
116
  }));
117
117
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
118
118
  const { name, arguments: args } = request.params;
119
- const appointmentTypes = await client.getAppointmentTypes();
120
- const rawRequests = await client.getStandardWindowRequests();
119
+ let appointmentTypes;
120
+ let all;
121
121
  const tz = args?.timezone || process.env.TIMEZEST_DEFAULT_TZ || 'America/Chicago';
122
- const all = rawRequests.map(r => transformAppointment(r, appointmentTypes, tz));
122
+ try {
123
+ appointmentTypes = await client.getAppointmentTypes();
124
+ // Determine fetch window from tool-specific args
125
+ const daysBack = args?.days_back;
126
+ const daysForward = args?.days_forward;
127
+ const rawRequests = await client.getSchedulingRequests(daysBack, daysForward);
128
+ all = rawRequests.map(r => transformAppointment(r, appointmentTypes, tz));
129
+ }
130
+ catch (error) {
131
+ return {
132
+ content: [{ type: "text", text: `Error: ${error.message}` }],
133
+ isError: true
134
+ };
135
+ }
123
136
  switch (name) {
124
137
  case "get_todays_appointments": {
125
138
  const today = new Date();
@@ -12,9 +12,11 @@ export function filterByDateRange(appointments, startDate, endDate) {
12
12
  const start = parseISO(startDate);
13
13
  const end = parseISO(endDate);
14
14
  return appointments.filter(a => {
15
- if (!a.start_time)
15
+ // Use start_time for scheduled appointments, fall back to created_at for pending
16
+ const dateStr = a.start_time || a.created_at;
17
+ if (!dateStr)
16
18
  return false;
17
- const date = parseISO(a.start_time);
19
+ const date = parseISO(dateStr);
18
20
  return isWithinInterval(date, { start, end });
19
21
  });
20
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "timezest-mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "description": "MCP Server for TimeZest scheduling API — brings appointments, pending requests, and ticket-linked schedules to Claude.",
5
5
  "main": "build/index.js",
6
6
  "author": "Sagar Kalra",