@findtime/mcp-server 3.25.7 → 3.25.9

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +104 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@findtime/mcp-server",
3
- "version": "3.25.7",
3
+ "version": "3.25.9",
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": {
package/server.js CHANGED
@@ -17,8 +17,19 @@ const SUPPORTED_PROTOCOL_VERSIONS = new Set([
17
17
 
18
18
  loadEnvironmentFiles();
19
19
 
20
- const PACKAGE_METADATA = safeReadJson(LOCAL_PACKAGE_PATH) || safeReadJson(REPO_PACKAGE_PATH) || {};
20
+ const LOCAL_PACKAGE_METADATA = safeReadJson(LOCAL_PACKAGE_PATH) || null;
21
+ const REPO_PACKAGE_METADATA = safeReadJson(REPO_PACKAGE_PATH) || null;
22
+ const PACKAGE_METADATA = LOCAL_PACKAGE_METADATA || REPO_PACKAGE_METADATA || {};
21
23
  const SERVER_VERSION = PACKAGE_METADATA.version || '0.0.0';
24
+ const MCP_PACKAGE_NAME = PACKAGE_METADATA.name || '@findtime/mcp-server';
25
+ const MCP_NPM_REGISTRY_LATEST_URL = `https://registry.npmjs.org/${encodeURIComponent(MCP_PACKAGE_NAME)}/latest`;
26
+ const MCP_NPM_URL = `https://www.npmjs.com/package/${MCP_PACKAGE_NAME}`;
27
+ const MCP_REGISTRY_URL = 'https://registry.modelcontextprotocol.io/?q=io.github.hkchao%2Ffindtime-mcp-server';
28
+ const MCP_INSTALL_MODE = determineInstallMode({
29
+ packageRoot: PACKAGE_ROOT,
30
+ localPackageMetadata: LOCAL_PACKAGE_METADATA,
31
+ repoPackageMetadata: REPO_PACKAGE_METADATA
32
+ });
22
33
  const DEFAULT_API_BASE_URL = firstNonEmpty(
23
34
  process.env.TIME_API_BASE_URL,
24
35
  process.env.FINDTIME_TIME_API_BASE_URL
@@ -35,7 +46,7 @@ const TIMEZONE_HELPERS_PATH = path.join(REPO_ROOT, 'slack-bot', 'timezone-helper
35
46
  const TOOL_DEFINITIONS = [
36
47
  {
37
48
  name: 'get_api_diagnostics',
38
- description: 'Return MCP and findtime Time API diagnostics, including package version, API base URL, auth configuration, and a live health check.',
49
+ description: 'Return MCP and findtime Time API diagnostics, including the running MCP version, latest published MCP version, API base URL, auth configuration, and a live health check.',
39
50
  inputSchema: {
40
51
  type: 'object',
41
52
  properties: {},
@@ -818,6 +829,61 @@ function createFindtimeMcpServer(options = {}) {
818
829
  }
819
830
  }
820
831
 
832
+ async function fetchLatestMcpVersion() {
833
+ const controller = new AbortController();
834
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
835
+
836
+ try {
837
+ const response = await fetchImpl(MCP_NPM_REGISTRY_LATEST_URL, {
838
+ method: 'GET',
839
+ headers: {
840
+ Accept: 'application/json'
841
+ },
842
+ signal: controller.signal
843
+ });
844
+
845
+ const rawBody = await response.text();
846
+ const parsedBody = tryParseJson(rawBody);
847
+
848
+ if (!response.ok) {
849
+ return {
850
+ ok: false,
851
+ status: response.status,
852
+ latestVersion: null
853
+ };
854
+ }
855
+
856
+ const latestVersion = parsedBody && typeof parsedBody.version === 'string'
857
+ ? parsedBody.version.trim()
858
+ : '';
859
+
860
+ if (!latestVersion) {
861
+ return {
862
+ ok: false,
863
+ status: response.status,
864
+ latestVersion: null
865
+ };
866
+ }
867
+
868
+ return {
869
+ ok: true,
870
+ status: response.status,
871
+ latestVersion
872
+ };
873
+ } catch (error) {
874
+ return {
875
+ ok: false,
876
+ status: null,
877
+ latestVersion: null,
878
+ networkError: error && error.name === 'AbortError'
879
+ ? `Request timed out after ${timeoutMs}ms`
880
+ : String(error && error.message ? error.message : error)
881
+ };
882
+ } finally {
883
+ clearTimeout(timeout);
884
+ }
885
+ }
886
+
821
887
  async function callTool(name, args = {}) {
822
888
  const tool = TOOL_DEFINITIONS_BY_NAME.get(name);
823
889
  if (!tool) {
@@ -826,13 +892,28 @@ function createFindtimeMcpServer(options = {}) {
826
892
 
827
893
  if (name === 'get_api_diagnostics') {
828
894
  const request = tool.buildRequest(args || {});
829
- const apiResponse = await fetchJson(name, request);
895
+ const [apiResponse, latestMcpVersionCheck] = await Promise.all([
896
+ fetchJson(name, request),
897
+ fetchLatestMcpVersion()
898
+ ]);
830
899
  const checkedAt = new Date().toISOString();
900
+ const latestVersion = latestMcpVersionCheck.latestVersion || null;
831
901
  const diagnostics = {
832
902
  ok: apiResponse.ok,
833
903
  tool: name,
834
904
  checkedAt,
835
905
  mcpVersion: SERVER_VERSION,
906
+ mcpLatestVersion: latestVersion,
907
+ mcpUpToDate: latestVersion ? latestVersion === SERVER_VERSION : null,
908
+ mcpLatestVersionCheck: latestVersion ? 'ok' : 'failed',
909
+ mcpLatestVersionSource: latestVersion ? 'npm' : 'unavailable',
910
+ mcpLatestVersionHint: latestVersion
911
+ ? null
912
+ : 'Could not verify the latest published MCP version automatically. Check the npm package page or Official MCP Registry listing directly.',
913
+ mcpInstallMode: MCP_INSTALL_MODE,
914
+ mcpExecutablePath: path.join(PACKAGE_ROOT, 'server.js'),
915
+ mcpRegistryUrl: MCP_REGISTRY_URL,
916
+ mcpNpmUrl: MCP_NPM_URL,
836
917
  apiBaseUrl,
837
918
  apiConfigured: Boolean(apiBaseUrl),
838
919
  apiAuthConfigured: Boolean(typeof apiKey === 'string' && apiKey.trim()),
@@ -854,6 +935,10 @@ function createFindtimeMcpServer(options = {}) {
854
935
  }
855
936
  }
856
937
 
938
+ if (!latestVersion && latestMcpVersionCheck.networkError) {
939
+ diagnostics.mcpLatestVersionNetworkError = latestMcpVersionCheck.networkError;
940
+ }
941
+
857
942
  return buildToolSuccessResult(name, diagnostics, {
858
943
  endpoint: request.path,
859
944
  url: apiResponse.url
@@ -1005,6 +1090,22 @@ function tryParseJson(value) {
1005
1090
  }
1006
1091
  }
1007
1092
 
1093
+ function determineInstallMode({ packageRoot, localPackageMetadata, repoPackageMetadata }) {
1094
+ if (repoPackageMetadata && repoPackageMetadata.name === 'world-time-ai') {
1095
+ return 'repo_checkout';
1096
+ }
1097
+
1098
+ if (localPackageMetadata && localPackageMetadata.name === '@findtime/mcp-server') {
1099
+ return 'npm_package';
1100
+ }
1101
+
1102
+ if (typeof packageRoot === 'string' && packageRoot.includes(`${path.sep}world-time-ai${path.sep}services${path.sep}mcp-server`)) {
1103
+ return 'repo_checkout';
1104
+ }
1105
+
1106
+ return 'package_install';
1107
+ }
1108
+
1008
1109
  function startStdioServer(options = {}) {
1009
1110
  const server = createFindtimeMcpServer(options);
1010
1111
  const messageBuffer = new ContentLengthMessageBuffer();