@findtime/mcp-server 3.25.15 → 3.25.17

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
@@ -124,15 +124,16 @@ Best meeting time between New York, Sydney, and Mumbai?
124
124
 
125
125
  ## Local development
126
126
 
127
- Run the server directly from the public repo root:
127
+ Run the workspace version directly:
128
128
 
129
129
  ```bash
130
- npm start
130
+ npm run mcp:start
131
131
  ```
132
132
 
133
133
  The server attempts to load `.env.development.local`, `.env.development`, `.env.local`, and `.env` from:
134
134
 
135
135
  - the current working directory
136
+ - `services/mcp-server`
136
137
  - the repo root
137
138
 
138
139
  ## Tests
@@ -140,13 +141,13 @@ The server attempts to load `.env.development.local`, `.env.development`, `.env.
140
141
  Protocol and transport tests:
141
142
 
142
143
  ```bash
143
- npm test
144
+ npm run test:mcp-server
144
145
  ```
145
146
 
146
147
  Live production-parity smoke tests:
147
148
 
148
149
  ```bash
149
- npm run test:smoke
150
+ npm run test:mcp-server:smoke
150
151
  ```
151
152
 
152
153
  The smoke suite checks:
@@ -168,7 +169,7 @@ The canonical public source for this package now lives in:
168
169
  - npm: `@findtime/mcp-server`
169
170
  - Official MCP Registry: `https://registry.modelcontextprotocol.io/?q=io.github.hkchao%2Ffindtime-mcp-server`
170
171
 
171
- Publish and version updates should happen from this public repo.
172
+ Publish and version updates should happen from that public repo, not from this private app repo.
172
173
 
173
174
  Standard publish flow in the public repo:
174
175
 
@@ -178,4 +179,11 @@ npm pack --dry-run
178
179
  npm publish --access public
179
180
  ```
180
181
 
181
- Use the workflow in `.github/workflows/publish.yml` for repo-backed publishes.
182
+ The equivalent local verification checks in this repo are:
183
+
184
+ ```bash
185
+ npm run test:mcp-server
186
+ npm run mcp:pack
187
+ ```
188
+
189
+ Treat this repo as the implementation source that originally produced the MCP package, not as the canonical public release source.
@@ -2,12 +2,13 @@
2
2
  "mcpServers": {
3
3
  "findtime": {
4
4
  "type": "stdio",
5
- "command": "npx",
6
- "args": ["-y", "@findtime/mcp-server"],
5
+ "command": "node",
6
+ "args": [
7
+ "/absolute/path/to/findtime-io-mcp/services/mcp-server/src/server.js"
8
+ ],
7
9
  "env": {
8
10
  "FINDTIME_MCP_CLIENT_TYPE": "claude-desktop",
9
- "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io",
10
- "FINDTIME_TIME_API_KEY": "YOUR_FINDTIME_SECRET_KEY"
11
+ "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io"
11
12
  }
12
13
  }
13
14
  }
@@ -2,12 +2,13 @@
2
2
  "mcpServers": {
3
3
  "findtime": {
4
4
  "type": "stdio",
5
- "command": "npx",
6
- "args": ["-y", "@findtime/mcp-server"],
5
+ "command": "node",
6
+ "args": [
7
+ "/absolute/path/to/findtime-io-mcp/services/mcp-server/src/server.js"
8
+ ],
7
9
  "env": {
8
10
  "FINDTIME_MCP_CLIENT_TYPE": "cline",
9
- "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io",
10
- "FINDTIME_TIME_API_KEY": "YOUR_FINDTIME_SECRET_KEY"
11
+ "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io"
11
12
  }
12
13
  }
13
14
  }
@@ -2,12 +2,13 @@
2
2
  "mcpServers": {
3
3
  "findtime": {
4
4
  "type": "stdio",
5
- "command": "npx",
6
- "args": ["-y", "@findtime/mcp-server"],
5
+ "command": "node",
6
+ "args": [
7
+ "/absolute/path/to/findtime-io-mcp/services/mcp-server/src/server.js"
8
+ ],
7
9
  "env": {
8
10
  "FINDTIME_MCP_CLIENT_TYPE": "codex",
9
- "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io",
10
- "FINDTIME_TIME_API_KEY": "YOUR_FINDTIME_SECRET_KEY"
11
+ "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io"
11
12
  }
12
13
  }
13
14
  }
@@ -2,12 +2,13 @@
2
2
  "mcpServers": {
3
3
  "findtime": {
4
4
  "type": "stdio",
5
- "command": "npx",
6
- "args": ["-y", "@findtime/mcp-server"],
5
+ "command": "node",
6
+ "args": [
7
+ "/absolute/path/to/findtime-io-mcp/services/mcp-server/src/server.js"
8
+ ],
7
9
  "env": {
8
10
  "FINDTIME_MCP_CLIENT_TYPE": "cursor",
9
- "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io",
10
- "FINDTIME_TIME_API_KEY": "YOUR_FINDTIME_SECRET_KEY"
11
+ "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io"
11
12
  }
12
13
  }
13
14
  }
@@ -2,12 +2,13 @@
2
2
  "mcpServers": {
3
3
  "findtime": {
4
4
  "type": "stdio",
5
- "command": "npx",
6
- "args": ["-y", "@findtime/mcp-server"],
5
+ "command": "node",
6
+ "args": [
7
+ "/absolute/path/to/findtime-io-mcp/services/mcp-server/src/server.js"
8
+ ],
7
9
  "env": {
8
10
  "FINDTIME_MCP_CLIENT_TYPE": "windsurf",
9
- "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io",
10
- "FINDTIME_TIME_API_KEY": "YOUR_FINDTIME_SECRET_KEY"
11
+ "FINDTIME_TIME_API_BASE_URL": "https://time-api.findtime.io"
11
12
  }
12
13
  }
13
14
  }
@@ -0,0 +1,252 @@
1
+ 'use strict';
2
+
3
+ const HELP_ALIASES = ['help', '?', '/help', '/findtime help', '/findtime ?'];
4
+
5
+ const HELP_INTENTS = [
6
+ {
7
+ id: 'current_time',
8
+ label: 'Current time',
9
+ notes: 'Returns local date/time, timezone, UTC offset, and DST context when relevant.',
10
+ examples: {
11
+ default: ['What time is it now in Tokyo?', 'now in Tokyo, Sydney, Dubai'],
12
+ slack: ['/findtime now in Tokyo Sydney Dubai'],
13
+ discord: ['now in Tokyo, Paris, and Vancouver'],
14
+ chrome: ['now in Tokyo Sydney Dubai'],
15
+ mcp: ['What time is it now in Tokyo?']
16
+ }
17
+ },
18
+ {
19
+ id: 'timezone_lookup',
20
+ label: 'Timezone lookup',
21
+ notes: 'Returns the canonical IANA timezone plus the current abbreviation.',
22
+ examples: {
23
+ default: ['What timezone is Auckland in?', 'Tokyo time zone'],
24
+ slack: ['/findtime Tokyo time zone'],
25
+ discord: ['Tokyo time zone'],
26
+ chrome: ['Singapore time zone'],
27
+ mcp: ['What timezone is Auckland in?']
28
+ }
29
+ },
30
+ {
31
+ id: 'timezone_abbreviation_lookup',
32
+ label: 'Timezone abbreviation',
33
+ notes: 'Returns the current abbreviation plus the canonical IANA timezone.',
34
+ examples: {
35
+ default: ['What timezone abbreviation is Auckland?', 'What does CST mean?'],
36
+ slack: ['/findtime what does CST mean?'],
37
+ discord: ['what does CST mean?'],
38
+ chrome: ['timezone in Dubai'],
39
+ mcp: ['What timezone abbreviation is Auckland?']
40
+ }
41
+ },
42
+ {
43
+ id: 'time_conversion',
44
+ label: 'Time conversion',
45
+ notes: 'Includes local dates because conversions often cross calendar days.',
46
+ examples: {
47
+ default: ['If it is 3:30pm in London, what time is it in Sydney?', 'What is 5pm San Francisco time in Tokyo?', '9am New York to Berlin'],
48
+ slack: ['/findtime 3pm London to NYC'],
49
+ discord: ['8pm PST to London and Tokyo'],
50
+ chrome: ['3pm London to NYC', '9am PST to IST'],
51
+ mcp: ['If it is 3:30pm in London, what time is it in Sydney?', 'What is 5pm San Francisco time in Tokyo?']
52
+ }
53
+ },
54
+ {
55
+ id: 'dst_status',
56
+ label: 'Daylight saving',
57
+ notes: 'Returns DST status and transition context when available.',
58
+ examples: {
59
+ default: ['Is Mexico City on DST?', 'Does London observe daylight saving?', 'When do clocks change in New York?'],
60
+ slack: ['/findtime does London observe daylight saving?'],
61
+ discord: ['does London observe daylight saving?'],
62
+ chrome: ['does Sydney observe daylight saving?', 'DST in New York'],
63
+ mcp: ['Is Mexico City on DST?']
64
+ }
65
+ },
66
+ {
67
+ id: 'overlap_hours',
68
+ label: 'Overlap hours',
69
+ notes: 'Useful for distributed-team availability, handoff planning, and group coordination.',
70
+ examples: {
71
+ default: ['What working hours overlap for San Francisco, Berlin, and Tokyo?', 'working hours overlap for New York and London'],
72
+ slack: ['/findtime working hours overlap for San Francisco Berlin Tokyo'],
73
+ discord: ['when are New York and Sydney both free?'],
74
+ chrome: ['new york london tokyo'],
75
+ mcp: ['What working hours overlap for San Francisco, Berlin, and Tokyo?']
76
+ }
77
+ },
78
+ {
79
+ id: 'meeting_time_search',
80
+ label: 'Meeting time search',
81
+ notes: 'Returns ranked meeting windows and tradeoffs across participants.',
82
+ examples: {
83
+ default: ['Find a good meeting time for San Francisco, Berlin, and Sydney.', 'Best meeting time for San Francisco, Berlin, and Sydney next week', 'find the best meeting times between Helsinki and Osaka'],
84
+ slack: ['/findtime find a good meeting time for San Francisco Berlin Sydney'],
85
+ discord: ['best time for Los Angeles, Berlin, and Seoul'],
86
+ chrome: ['meeting Helsinki Dubai Chicago Taipei'],
87
+ mcp: ['Find a good meeting time for San Francisco, Berlin, and Sydney.']
88
+ }
89
+ },
90
+ {
91
+ id: 'abbreviation_disambiguation',
92
+ label: 'Abbreviation disambiguation',
93
+ notes: 'Timezone abbreviations are aliases, not canonical identifiers.',
94
+ examples: {
95
+ default: ['What does CST mean for a customer in China versus a customer in Chicago?', 'Convert 9am CST to London'],
96
+ slack: ['/findtime Convert 9am CST to London'],
97
+ discord: ['9am CST to London'],
98
+ chrome: ['EST to GMT'],
99
+ mcp: ['What does CST mean for a customer in China versus a customer in Chicago?']
100
+ }
101
+ },
102
+ {
103
+ id: 'location_disambiguation',
104
+ label: 'Location disambiguation',
105
+ notes: 'Ambiguous place names should return clarification or country-aware choices instead of silent guessing.',
106
+ examples: {
107
+ default: ['What time is it in Victoria?', 'What time is it in Springfield?'],
108
+ slack: ['/findtime what time is it in Victoria?'],
109
+ discord: ['what time is it in Victoria?'],
110
+ chrome: ['time in Victoria'],
111
+ mcp: ['What time is it in Victoria?']
112
+ }
113
+ }
114
+ ];
115
+
116
+ const HELP_SURFACES = {
117
+ default: {
118
+ title: 'Ask about time anywhere',
119
+ summary: 'Convert times, compare cities, check current time, inspect time zones, resolve ambiguity, or find a meeting slot.'
120
+ },
121
+ slack: {
122
+ title: 'Use /findtime for time intelligence',
123
+ summary: 'Convert times, compare teammates, check time zones, and find meeting windows directly in Slack.'
124
+ },
125
+ discord: {
126
+ title: 'Coordinate across time zones',
127
+ summary: 'Convert raid times, compare party locations, check current time, or find a time that works for your group.',
128
+ commandAliases: ['/findtime', '/ft']
129
+ },
130
+ telegram: {
131
+ title: 'Ask findtime.io about time',
132
+ summary: 'Convert times, check cities, inspect time zones, and coordinate across locations from Telegram.'
133
+ },
134
+ chrome: {
135
+ title: 'What you can do',
136
+ summary: 'Convert times, open live pages on findtime.io, and plan across cities from the browser.'
137
+ },
138
+ mcp: {
139
+ title: 'findtime.io Time Help',
140
+ summary: 'Use findtime.io MCP for accurate timezone, DST, conversion, overlap-hours, and cross-timezone meeting-time intelligence.'
141
+ }
142
+ };
143
+
144
+ const AMBIGUITY_EXAMPLES = [
145
+ {
146
+ query: 'What time is it in Springfield?',
147
+ expectedBehavior: 'Ask for clarification or provide likely matches because many cities share this name.'
148
+ },
149
+ {
150
+ query: 'Convert 9am CST to London.',
151
+ expectedBehavior: 'Clarify whether CST means China Standard Time, Central Standard Time, Cuba Standard Time, or another regional meaning when context is insufficient.'
152
+ },
153
+ {
154
+ query: 'Schedule a meeting for Paris and Sydney next Friday.',
155
+ expectedBehavior: 'Resolve Paris, France unless context suggests otherwise; include date and local-time tradeoffs.'
156
+ }
157
+ ];
158
+
159
+ const FAILURE_POLICY = [
160
+ 'If a findtime.io MCP call fails, say the MCP call failed and include the visible error.',
161
+ 'Do not present fallback timezone or DST calculations as if they came from findtime.io MCP.',
162
+ 'For high-stakes scheduling, retry or ask the user before using fallback reasoning.'
163
+ ];
164
+
165
+ function normalizeSurface(surface) {
166
+ const normalized = String(surface || '').trim().toLowerCase();
167
+ if (normalized === 'discord-bot') return 'discord';
168
+ if (normalized === 'slack-bot') return 'slack';
169
+ if (normalized === 'telegram-bot') return 'telegram';
170
+ if (normalized === 'web-chat' || normalized === 'webapp' || normalized === 'web') return 'default';
171
+ return HELP_SURFACES[normalized] ? normalized : 'default';
172
+ }
173
+
174
+ function examplesForSurface(intent, surface) {
175
+ const key = normalizeSurface(surface);
176
+ const examples = intent.examples || {};
177
+ return examples[key] || examples.default || [];
178
+ }
179
+
180
+ function flattenExamples(surface = 'default', { max = 12 } = {}) {
181
+ const examples = [];
182
+ for (const intent of HELP_INTENTS) {
183
+ for (const example of examplesForSurface(intent, surface)) {
184
+ if (!examples.includes(example)) examples.push(example);
185
+ if (examples.length >= max) return examples;
186
+ }
187
+ }
188
+ return examples;
189
+ }
190
+
191
+ function mergeExamples(primary = [], secondary = [], { max = 18 } = {}) {
192
+ const examples = [];
193
+ for (const example of [...primary, ...secondary]) {
194
+ if (!examples.includes(example)) examples.push(example);
195
+ if (examples.length >= max) return examples;
196
+ }
197
+ return examples;
198
+ }
199
+
200
+ function buildHelpPayload({ surface = 'default', includeAllIntents = false } = {}) {
201
+ const normalizedSurface = normalizeSurface(surface);
202
+ const surfaceMeta = HELP_SURFACES[normalizedSurface] || HELP_SURFACES.default;
203
+ const defaultSuggestions = flattenExamples('default', { max: 18 });
204
+ const surfaceSuggestions = normalizedSurface === 'default'
205
+ ? []
206
+ : flattenExamples(normalizedSurface, { max: 6 });
207
+ const suggestions = normalizedSurface === 'default'
208
+ ? defaultSuggestions
209
+ : mergeExamples(surfaceSuggestions, defaultSuggestions, { max: 18 });
210
+
211
+ return {
212
+ version: 'answer-help.v1',
213
+ surface: normalizedSurface,
214
+ title: surfaceMeta.title,
215
+ summary: surfaceMeta.summary,
216
+ commandAliases: surfaceMeta.commandAliases || [],
217
+ aliases: HELP_ALIASES,
218
+ suggestions,
219
+ surfaceSuggestions,
220
+ defaultSuggestions,
221
+ intents: HELP_INTENTS.map((intent) => ({
222
+ intent: intent.id,
223
+ label: intent.label,
224
+ notes: intent.notes,
225
+ examples: includeAllIntents
226
+ ? mergeExamples(examplesForSurface(intent, normalizedSurface), examplesForSurface(intent, 'default'), { max: 6 })
227
+ : mergeExamples(examplesForSurface(intent, normalizedSurface), examplesForSurface(intent, 'default'), { max: 2 }),
228
+ surfaceExamples: normalizedSurface === 'default' ? [] : examplesForSurface(intent, normalizedSurface),
229
+ defaultExamples: examplesForSurface(intent, 'default'),
230
+ example: (examplesForSurface(intent, normalizedSurface)[0] || examplesForSurface(intent, 'default')[0] || '')
231
+ })),
232
+ ambiguityExamples: AMBIGUITY_EXAMPLES,
233
+ failurePolicy: FAILURE_POLICY
234
+ };
235
+ }
236
+
237
+ function isHelpQuery(value) {
238
+ const normalized = String(value || '').trim().replace(/\s+/g, ' ').toLowerCase();
239
+ return HELP_ALIASES.includes(normalized);
240
+ }
241
+
242
+ module.exports = {
243
+ HELP_ALIASES,
244
+ HELP_INTENTS,
245
+ HELP_SURFACES,
246
+ AMBIGUITY_EXAMPLES,
247
+ FAILURE_POLICY,
248
+ normalizeSurface,
249
+ flattenExamples,
250
+ buildHelpPayload,
251
+ isHelpQuery
252
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@findtime/mcp-server",
3
- "version": "3.25.15",
3
+ "version": "3.25.17",
4
4
  "mcpName": "io.github.hkchao/findtime-mcp-server",
5
5
  "description": "Production-parity MCP server for the findtime.io Time API",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "type": "commonjs",
11
11
  "files": [
12
12
  "server.js",
13
+ "help-catalog.cjs",
13
14
  "README.md",
14
15
  "SKILL.md",
15
16
  "examples"
@@ -31,14 +32,7 @@
31
32
  "publishConfig": {
32
33
  "access": "public"
33
34
  },
34
- "repository": {
35
- "type": "git",
36
- "url": "git+https://github.com/hkchao/findtime-mcp-server.git"
37
- },
38
35
  "homepage": "https://findtime.io/developers/mcp/",
39
- "bugs": {
40
- "url": "https://github.com/hkchao/findtime-mcp-server/issues"
41
- },
42
36
  "keywords": [
43
37
  "mcp",
44
38
  "model-context-protocol",
package/server.js CHANGED
@@ -417,13 +417,47 @@ function getVisibleToolDefinitions() {
417
417
  return TOOL_DEFINITIONS.filter((tool) => ANSWER_ONLY_TOOL_NAMES.has(tool.name));
418
418
  }
419
419
 
420
+ function loadHelpCatalog() {
421
+ const candidatePaths = [
422
+ path.join(PACKAGE_ROOT, 'help-catalog.cjs'),
423
+ path.join(REPO_ROOT, 'src', 'shared', 'findtimeHelpCatalog.cjs')
424
+ ];
425
+ for (const catalogPath of candidatePaths) {
426
+ try {
427
+ return require(catalogPath);
428
+ } catch (_error) {
429
+ // Try the next candidate. Published MCP packages use PACKAGE_ROOT.
430
+ }
431
+ }
432
+ return {
433
+ buildHelpPayload: () => ({
434
+ version: 'answer-help.v1',
435
+ surface: 'mcp',
436
+ title: 'findtime.io Time Help',
437
+ summary: 'Use findtime.io MCP for accurate timezone, DST, conversion, overlap-hours, and cross-timezone meeting-time intelligence.',
438
+ suggestions: [
439
+ 'What time is it now in Tokyo?',
440
+ 'What timezone is Auckland in?',
441
+ 'If it is 3:30pm in London, what time is it in Sydney?',
442
+ 'What working hours overlap for San Francisco, Berlin, and Tokyo?',
443
+ 'Find a good meeting time for San Francisco, Berlin, and Sydney.'
444
+ ],
445
+ intents: [],
446
+ ambiguityExamples: [],
447
+ failurePolicy: []
448
+ })
449
+ };
450
+ }
451
+
420
452
  function buildFindtimeHelpPayload() {
453
+ const help = loadHelpCatalog().buildHelpPayload({ surface: 'mcp', includeAllIntents: true });
421
454
  return {
455
+ ...help,
422
456
  ok: true,
423
457
  tool: 'get_findtime_help',
424
458
  recommendedTool: 'answer_time_question',
425
459
  recommendedMode: 'FINDTIME_MCP_TOOL_MODE=answer-only',
426
- summary: 'Use findtime.io MCP for accurate timezone, DST, conversion, overlap-hours, and cross-timezone meeting-time intelligence. In enterprise bots, route natural-language questions through answer_time_question.',
460
+ summary: `${help.summary} In enterprise bots, route natural-language questions through answer_time_question.`,
427
461
  install: {
428
462
  command: 'npx',
429
463
  args: ['-y', '@findtime/mcp-server'],
@@ -434,62 +468,6 @@ function buildFindtimeHelpPayload() {
434
468
  FINDTIME_MCP_TOOL_MODE: 'answer-only'
435
469
  }
436
470
  },
437
- intents: [
438
- {
439
- intent: 'current_time',
440
- example: 'What time is it now in Tokyo?',
441
- notes: 'Returns local date/time, timezone, UTC offset, and DST context when relevant.'
442
- },
443
- {
444
- intent: 'timezone_lookup',
445
- example: 'What is the IANA timezone for San Francisco?',
446
- notes: 'Use IANA timezone IDs as canonical identifiers.'
447
- },
448
- {
449
- intent: 'time_conversion',
450
- example: 'Convert 3pm next Tuesday in New York to London, Berlin, and Singapore.',
451
- notes: 'Include local dates because conversions often cross calendar days.'
452
- },
453
- {
454
- intent: 'dst_status',
455
- example: 'Is Mexico City on DST?',
456
- notes: 'Returns DST status and transition context when available.'
457
- },
458
- {
459
- intent: 'overlap_hours',
460
- example: 'What working hours overlap for San Francisco, Berlin, and Tokyo?',
461
- notes: 'Useful for distributed-team availability and handoff planning.'
462
- },
463
- {
464
- intent: 'meeting_time_search',
465
- example: 'Find a good 45-minute meeting time next week for San Francisco, Berlin, and Sydney.',
466
- notes: 'Returns ranked meeting windows and tradeoffs across participants.'
467
- },
468
- {
469
- intent: 'abbreviation_disambiguation',
470
- example: 'What does CST mean for a customer in China versus a customer in Chicago?',
471
- notes: 'Timezone abbreviations are aliases, not canonical identifiers.'
472
- },
473
- {
474
- intent: 'location_disambiguation',
475
- example: 'What time is it in Victoria?',
476
- notes: 'Ambiguous place names should return clarification or country-aware choices instead of silent guessing.'
477
- }
478
- ],
479
- ambiguityExamples: [
480
- {
481
- query: 'What time is it in Springfield?',
482
- expectedBehavior: 'Ask for clarification or provide likely matches because many cities share this name.'
483
- },
484
- {
485
- query: 'Convert 9am CST to London.',
486
- expectedBehavior: 'Clarify whether CST means China Standard Time, Central Standard Time, Cuba Standard Time, or another regional meaning when context is insufficient.'
487
- },
488
- {
489
- query: 'Schedule a meeting for Paris and Sydney next Friday.',
490
- expectedBehavior: 'Resolve Paris, France unless context suggests otherwise; include date and local-time tradeoffs.'
491
- }
492
- ],
493
471
  answerApiPattern: {
494
472
  tool: 'answer_time_question',
495
473
  arguments: {
@@ -497,15 +475,24 @@ function buildFindtimeHelpPayload() {
497
475
  userTimezone: 'America/Los_Angeles',
498
476
  locale: 'en-US'
499
477
  }
500
- },
501
- failurePolicy: [
502
- 'If a findtime.io MCP call fails, say the MCP call failed and include the visible error.',
503
- 'Do not present fallback timezone or DST calculations as if they came from findtime.io MCP.',
504
- 'For high-stakes scheduling, retry or ask the user before using fallback reasoning.'
505
- ]
478
+ }
506
479
  };
507
480
  }
508
481
 
482
+ function formatFindtimeHelpText(help) {
483
+ const lines = [
484
+ 'findtime.io Time Help',
485
+ '',
486
+ 'Try asking:',
487
+ ...help.intents.map((entry) => `- ${entry.example}`),
488
+ '',
489
+ 'If a place or timezone is ambiguous, findtime.io will ask for clarification. For example:',
490
+ ...help.ambiguityExamples.map((entry) => `- ${entry.query} -> ${entry.expectedBehavior}`),
491
+ ];
492
+
493
+ return lines.join('\n');
494
+ }
495
+
509
496
  function safeReadJson(filePath) {
510
497
  try {
511
498
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
@@ -1199,14 +1186,15 @@ function createFindtimeMcpServer(options = {}) {
1199
1186
  }
1200
1187
 
1201
1188
  if (name === 'get_findtime_help') {
1189
+ const help = buildFindtimeHelpPayload();
1202
1190
  return {
1203
1191
  content: [
1204
1192
  {
1205
1193
  type: 'text',
1206
- text: `get_findtime_help response\n${JSON.stringify(buildFindtimeHelpPayload(), null, 2)}`
1194
+ text: formatFindtimeHelpText(help)
1207
1195
  }
1208
1196
  ],
1209
- structuredContent: buildFindtimeHelpPayload()
1197
+ structuredContent: help
1210
1198
  };
1211
1199
  }
1212
1200