@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 +16 -7
- package/SKILL.md +2 -0
- package/examples/claude-desktop-config.json +5 -4
- package/examples/cline-mcp.json +5 -4
- package/examples/codex-mcp.json +5 -4
- package/examples/cursor-mcp.json +5 -4
- package/examples/windsurf-mcp.json +5 -4
- package/package.json +1 -8
- package/server.js +139 -1
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
|
|
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
|
|
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
|
-
|
|
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": "
|
|
6
|
-
"args": [
|
|
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
|
}
|
package/examples/cline-mcp.json
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"findtime": {
|
|
4
4
|
"type": "stdio",
|
|
5
|
-
"command": "
|
|
6
|
-
"args": [
|
|
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
|
}
|
package/examples/codex-mcp.json
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"findtime": {
|
|
4
4
|
"type": "stdio",
|
|
5
|
-
"command": "
|
|
6
|
-
"args": [
|
|
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
|
}
|
package/examples/cursor-mcp.json
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"findtime": {
|
|
4
4
|
"type": "stdio",
|
|
5
|
-
"command": "
|
|
6
|
-
"args": [
|
|
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": "
|
|
6
|
-
"args": [
|
|
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.
|
|
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([
|