@findtime/mcp-server 3.25.14 → 3.25.16

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
@@ -14,6 +14,7 @@ Published surfaces:
14
14
  ## Tool surface
15
15
 
16
16
  - `answer_time_question`
17
+ - `get_findtime_help`
17
18
  - `time_snapshot`
18
19
  - `get_current_time`
19
20
  - `get_dst_schedule`
@@ -49,7 +50,7 @@ Optional environment variables:
49
50
  - `TIME_API_BASE_URL`
50
51
  - `TIME_API_TIMEOUT_MS`
51
52
  - `FINDTIME_MCP_CLIENT_TYPE`
52
- - `FINDTIME_MCP_TOOL_MODE=answer-only` to expose only `answer_time_question` and `get_api_diagnostics` for enterprise bots that should route every natural-language request through the answer API.
53
+ - `FINDTIME_MCP_TOOL_MODE=answer-only` to expose only `answer_time_question`, `get_findtime_help`, and `get_api_diagnostics` for enterprise bots that should route every natural-language request through the answer API.
53
54
  - `FINDTIME_MCP_CLIENT_ID` or `FINDTIME_MCP_INSTALL_ID` to provide a stable client identifier. If omitted, the server creates one locally under the user's state directory.
54
55
  - `FINDTIME_MCP_INSTRUMENTATION_ENABLED=false` to opt out of anonymous usage telemetry.
55
56
  - `FINDTIME_MCP_USAGE_TELEMETRY_URL` to override the default telemetry endpoint.
@@ -123,15 +124,16 @@ Best meeting time between New York, Sydney, and Mumbai?
123
124
 
124
125
  ## Local development
125
126
 
126
- Run the server directly from the public repo root:
127
+ Run the workspace version directly:
127
128
 
128
129
  ```bash
129
- npm start
130
+ npm run mcp:start
130
131
  ```
131
132
 
132
133
  The server attempts to load `.env.development.local`, `.env.development`, `.env.local`, and `.env` from:
133
134
 
134
135
  - the current working directory
136
+ - `services/mcp-server`
135
137
  - the repo root
136
138
 
137
139
  ## Tests
@@ -139,13 +141,13 @@ The server attempts to load `.env.development.local`, `.env.development`, `.env.
139
141
  Protocol and transport tests:
140
142
 
141
143
  ```bash
142
- npm test
144
+ npm run test:mcp-server
143
145
  ```
144
146
 
145
147
  Live production-parity smoke tests:
146
148
 
147
149
  ```bash
148
- npm run test:smoke
150
+ npm run test:mcp-server:smoke
149
151
  ```
150
152
 
151
153
  The smoke suite checks:
@@ -167,7 +169,7 @@ The canonical public source for this package now lives in:
167
169
  - npm: `@findtime/mcp-server`
168
170
  - Official MCP Registry: `https://registry.modelcontextprotocol.io/?q=io.github.hkchao%2Ffindtime-mcp-server`
169
171
 
170
- 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.
171
173
 
172
174
  Standard publish flow in the public repo:
173
175
 
@@ -177,4 +179,11 @@ npm pack --dry-run
177
179
  npm publish --access public
178
180
  ```
179
181
 
180
- 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.
package/SKILL.md CHANGED
@@ -81,6 +81,7 @@ FINDTIME_MCP_TOOL_MODE=answer-only
81
81
  In answer-only mode, the MCP server exposes only:
82
82
 
83
83
  - `answer_time_question`
84
+ - `get_findtime_help`
84
85
  - `get_api_diagnostics`
85
86
 
86
87
  Use this mode when the bot should route all natural-language time requests through the answer API first.
@@ -99,6 +100,7 @@ Examples:
99
100
 
100
101
  Use specific tools when the agent has already parsed the task into structured inputs:
101
102
 
103
+ - `get_findtime_help`: examples of supported intents, answer API usage, ambiguity handling, and enterprise deployment guidance
102
104
  - `get_current_time`: current local time for a known city, country, timezone, or location
103
105
  - `convert_time`: convert a known date/time from one place or timezone to another
104
106
  - `get_dst_schedule`: DST status and transition dates
@@ -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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@findtime/mcp-server",
3
- "version": "3.25.14",
3
+ "version": "3.25.16",
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": {
@@ -31,14 +31,7 @@
31
31
  "publishConfig": {
32
32
  "access": "public"
33
33
  },
34
- "repository": {
35
- "type": "git",
36
- "url": "git+https://github.com/hkchao/findtime-mcp-server.git"
37
- },
38
34
  "homepage": "https://findtime.io/developers/mcp/",
39
- "bugs": {
40
- "url": "https://github.com/hkchao/findtime-mcp-server/issues"
41
- },
42
35
  "keywords": [
43
36
  "mcp",
44
37
  "model-context-protocol",
package/server.js CHANGED
@@ -49,7 +49,7 @@ const DEFAULT_API_KEY = firstNonEmpty(
49
49
  process.env.FINDTIME_TIME_API_KEY
50
50
  );
51
51
  const TIMEZONE_HELPERS_PATH = path.join(REPO_ROOT, 'slack-bot', 'timezone-helpers.js');
52
- const ANSWER_ONLY_TOOL_NAMES = new Set(['answer_time_question', 'get_api_diagnostics']);
52
+ const ANSWER_ONLY_TOOL_NAMES = new Set(['answer_time_question', 'get_findtime_help', 'get_api_diagnostics']);
53
53
 
54
54
  const TOOL_DEFINITIONS = [
55
55
  {
@@ -105,6 +105,18 @@ const TOOL_DEFINITIONS = [
105
105
  return { path: '/health', params: new URLSearchParams() };
106
106
  }
107
107
  },
108
+ {
109
+ name: 'get_findtime_help',
110
+ description: 'Return enterprise-friendly findtime.io MCP usage help, including supported time-intelligence intents, answer API examples, ambiguity handling examples, and recommended answer-only deployment guidance.',
111
+ inputSchema: {
112
+ type: 'object',
113
+ properties: {},
114
+ additionalProperties: false
115
+ },
116
+ buildRequest() {
117
+ return null;
118
+ }
119
+ },
108
120
  {
109
121
  name: 'time_snapshot',
110
122
  description: 'Return the production time snapshot payload for one location or a list of locations.',
@@ -405,6 +417,119 @@ function getVisibleToolDefinitions() {
405
417
  return TOOL_DEFINITIONS.filter((tool) => ANSWER_ONLY_TOOL_NAMES.has(tool.name));
406
418
  }
407
419
 
420
+ function buildFindtimeHelpPayload() {
421
+ return {
422
+ ok: true,
423
+ tool: 'get_findtime_help',
424
+ recommendedTool: 'answer_time_question',
425
+ 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.',
427
+ install: {
428
+ command: 'npx',
429
+ args: ['-y', '@findtime/mcp-server'],
430
+ requiredEnv: ['FINDTIME_TIME_API_KEY'],
431
+ recommendedEnterpriseEnv: {
432
+ FINDTIME_TIME_API_BASE_URL: 'https://time-api.findtime.io',
433
+ FINDTIME_MCP_CLIENT_TYPE: 'company-bot',
434
+ FINDTIME_MCP_TOOL_MODE: 'answer-only'
435
+ }
436
+ },
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 timezone is Auckland in?',
446
+ notes: 'Returns the canonical IANA timezone plus the current abbreviation.'
447
+ },
448
+ {
449
+ intent: 'timezone_abbreviation_lookup',
450
+ example: 'What timezone abbreviation is Auckland?',
451
+ notes: 'Returns the current abbreviation plus the canonical IANA timezone.'
452
+ },
453
+ {
454
+ intent: 'time_conversion',
455
+ example: 'If it is 3:30pm in London, what time is it in Sydney?',
456
+ notes: 'Include local dates because conversions often cross calendar days.'
457
+ },
458
+ {
459
+ intent: 'time_conversion',
460
+ example: 'What is 5pm San Francisco time in Tokyo?',
461
+ notes: 'Natural-language conversion works for common city and timezone phrasing.'
462
+ },
463
+ {
464
+ intent: 'dst_status',
465
+ example: 'Is Mexico City on DST?',
466
+ notes: 'Returns DST status and transition context when available.'
467
+ },
468
+ {
469
+ intent: 'overlap_hours',
470
+ example: 'What working hours overlap for San Francisco, Berlin, and Tokyo?',
471
+ notes: 'Useful for distributed-team availability and handoff planning.'
472
+ },
473
+ {
474
+ intent: 'meeting_time_search',
475
+ example: 'Find a good meeting time for San Francisco, Berlin, and Sydney.',
476
+ notes: 'Returns ranked meeting windows and tradeoffs across participants.'
477
+ },
478
+ {
479
+ intent: 'abbreviation_disambiguation',
480
+ example: 'What does CST mean for a customer in China versus a customer in Chicago?',
481
+ notes: 'Timezone abbreviations are aliases, not canonical identifiers.'
482
+ },
483
+ {
484
+ intent: 'location_disambiguation',
485
+ example: 'What time is it in Victoria?',
486
+ notes: 'Ambiguous place names should return clarification or country-aware choices instead of silent guessing.'
487
+ }
488
+ ],
489
+ ambiguityExamples: [
490
+ {
491
+ query: 'What time is it in Springfield?',
492
+ expectedBehavior: 'Ask for clarification or provide likely matches because many cities share this name.'
493
+ },
494
+ {
495
+ query: 'Convert 9am CST to London.',
496
+ expectedBehavior: 'Clarify whether CST means China Standard Time, Central Standard Time, Cuba Standard Time, or another regional meaning when context is insufficient.'
497
+ },
498
+ {
499
+ query: 'Schedule a meeting for Paris and Sydney next Friday.',
500
+ expectedBehavior: 'Resolve Paris, France unless context suggests otherwise; include date and local-time tradeoffs.'
501
+ }
502
+ ],
503
+ answerApiPattern: {
504
+ tool: 'answer_time_question',
505
+ arguments: {
506
+ query: 'Best meeting time for San Francisco, Berlin, and Sydney next week',
507
+ userTimezone: 'America/Los_Angeles',
508
+ locale: 'en-US'
509
+ }
510
+ },
511
+ failurePolicy: [
512
+ 'If a findtime.io MCP call fails, say the MCP call failed and include the visible error.',
513
+ 'Do not present fallback timezone or DST calculations as if they came from findtime.io MCP.',
514
+ 'For high-stakes scheduling, retry or ask the user before using fallback reasoning.'
515
+ ]
516
+ };
517
+ }
518
+
519
+ function formatFindtimeHelpText(help) {
520
+ const lines = [
521
+ 'findtime.io Time Help',
522
+ '',
523
+ 'Try asking:',
524
+ ...help.intents.map((entry) => `- ${entry.example}`),
525
+ '',
526
+ 'If a place or timezone is ambiguous, findtime.io will ask for clarification. For example:',
527
+ ...help.ambiguityExamples.map((entry) => `- ${entry.query} -> ${entry.expectedBehavior}`),
528
+ ];
529
+
530
+ return lines.join('\n');
531
+ }
532
+
408
533
  function safeReadJson(filePath) {
409
534
  try {
410
535
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
@@ -1097,6 +1222,19 @@ function createFindtimeMcpServer(options = {}) {
1097
1222
  throw invalidParamsError(`Unknown tool: ${name}`);
1098
1223
  }
1099
1224
 
1225
+ if (name === 'get_findtime_help') {
1226
+ const help = buildFindtimeHelpPayload();
1227
+ return {
1228
+ content: [
1229
+ {
1230
+ type: 'text',
1231
+ text: formatFindtimeHelpText(help)
1232
+ }
1233
+ ],
1234
+ structuredContent: help
1235
+ };
1236
+ }
1237
+
1100
1238
  if (name === 'get_api_diagnostics') {
1101
1239
  const request = tool.buildRequest(args || {});
1102
1240
  const [apiResponse, latestMcpVersionCheck] = await Promise.all([