time mcp server with rust and js

6 阅读10分钟

Cargo.toml

[package]
name = "time-mcp-server-rust"
version = "0.1.0"
edition = "2024"


[dependencies]
# Async runtime
tokio = { version = "1", features = ["full"] }

# Web framework
axum = { version = "0.7", features = ["macros"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["cors"] }

# Serialization
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

# Time handling
chrono = { version = "0.4", features = ["serde"] }
chrono-tz = "0.8"

# Utils
once_cell = "1.19"
anyhow = "1.0"

main.rs

use axum::{
    extract::{Query, State},
    http::StatusCode,
    response::{IntoResponse, Json as AxumJson},
    routing::{get, post},
    Router,
};
use chrono::{DateTime, TimeZone, Utc};
use chrono_tz::Tz;
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::collections::{HashMap, HashSet};
use std::env;
use std::sync::Arc;
use tower_http::cors::{Any, CorsLayer};

// --- 配置 ---
struct Config {
    port: u16,
    host: String,
    allowed_keys: HashSet<String>,
}

static CONFIG: Lazy<Config> = Lazy::new(|| {
    let key = env::var("TIME_SERVER_API_KEY").unwrap_or_else(|_| "default_key_123456".to_string());
    let mut keys = HashSet::new();
    keys.insert(key);

    Config {
        port: 8700,
        host: "0.0.0.0".to_string(),
        allowed_keys: keys,
    }
});

// --- MCP 协议结构 ---
#[allow(dead_code)]
#[derive(Deserialize, Debug)]
struct JsonRpcRequest {
    jsonrpc: String,
    id: Option<Value>,
    method: String,
    params: Option<Value>,
}

#[derive(Serialize)]
struct JsonRpcResponse {
    jsonrpc: String,
    id: Option<Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    result: Option<Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    error: Option<JsonRpcError>,
}

#[derive(Serialize)]
struct JsonRpcError {
    code: i32,
    message: String,
}

// --- 工具定义 ---

// 1. 获取当前时间
#[derive(Deserialize)]
struct GetCurrentTimeArgs {
    #[serde(default = "default_timezone")]
    timezone: String,
    #[serde(default = "default_format")]
    format: String,
}

fn default_timezone() -> String { "UTC".to_string() }
fn default_format() -> String { "iso".to_string() }

fn handle_get_current_time(args: Value) -> Result<Value, String> {
    let args: GetCurrentTimeArgs = serde_json::from_value(args).map_err(|e| e.to_string())?;
    
    let tz: Tz = args.timezone.parse().map_err(|_| format!("无效的时区: {}", args.timezone))?;
    let now = Utc::now().with_timezone(&tz);
    
    let formatted_time = match args.format.as_str() {
        "iso" => now.to_rfc3339(),
        "datetime" => now.format("%Y-%m-%d %H:%M:%S").to_string(),
        "timestamp" => now.timestamp().to_string(),
        "relative" => "刚刚".to_string(), // 简化处理,实际逻辑需对比现在
        _ => now.to_rfc3339(),
    };

    Ok(json!({
        "success": true,
        "timezone": args.timezone,
        "format": args.format,
        "time": formatted_time,
        "timestamp": now.timestamp(),
        "iso": now.to_rfc3339()
    }))
}

// 2. 时间差异
#[derive(Deserialize)]
struct TimeDiffArgs {
    from: String,
    to: String,
}

fn parse_time_str(s: &str) -> Result<DateTime<Utc>, String> {
    if s.chars().all(|c| c.is_ascii_digit()) {
        let ts = s.parse::<i64>().map_err(|_| "时间戳解析错误")?;
        Ok(Utc.timestamp_opt(ts, 0).single().unwrap())
    } else {
        DateTime::parse_from_rfc3339(s)
            .map(|d| d.with_timezone(&Utc))
            .or_else(|_| {
                // 尝试其他格式或返回错误
                 Err("时间解析错误".to_string())
            })
    }
}

fn handle_time_diff(args: Value) -> Result<Value, String> {
    let args: TimeDiffArgs = serde_json::from_value(args).map_err(|e| e.to_string())?;
    let from_time = parse_time_str(&args.from)?;
    let to_time = parse_time_str(&args.to)?;

    let diff = (to_time - from_time).num_seconds().abs();
    let days = diff / 86400;
    let hours = (diff % 86400) / 3600;
    let mins = (diff % 3600) / 60;
    let secs = diff % 60;

    Ok(json!({
        "success": true,
        "from": from_time.to_rfc3339(),
        "to": to_time.to_rfc3339(),
        "difference": {
            "seconds": diff,
            "minutes": diff / 60,
            "hours": diff / 3600,
            "days": days,
            "weeks": days / 7,
            "description": format!("{} 天 {} 小时 {} 分钟 {} 秒", days, hours, mins, secs)
        }
    }))
}

// 3. 时间戳转换
#[derive(Deserialize)]
struct TimestampConvertArgs {
    value: String,
    #[serde(default = "default_target_format")]
    target_format: String,
}

fn default_target_format() -> String { "datetime".to_string() }

fn handle_timestamp_convert(args: Value) -> Result<Value, String> {
    let args: TimestampConvertArgs = serde_json::from_value(args).map_err(|e| e.to_string())?;
    let date = parse_time_str(&args.value)?;

    let result = match args.target_format.as_str() {
        "iso" => date.to_rfc3339(),
        "datetime" => date.format("%Y-%m-%d %H:%M:%S").to_string(),
        "timestamp" => date.timestamp().to_string(),
        "human" => {
             let now = Utc::now();
             let diff = date.signed_duration_since(now);
             if diff.num_seconds().abs() < 60 {
                 "不到 1 分钟".to_string()
             } else {
                 format!("{} 分钟", diff.num_minutes().abs())
             }
        },
        _ => date.to_rfc3339(),
    };

    Ok(json!({
        "success": true,
        "input": args.value,
        "result": result,
        "parsed": date.to_rfc3339(),
        "timestamp": date.timestamp()
    }))
}

// 4. 相对时间
#[derive(Deserialize)]
struct RelativeTimeArgs {
    time: String,
    reference: Option<String>,
}

fn handle_relative_time(args: Value) -> Result<Value, String> {
    let args: RelativeTimeArgs = serde_json::from_value(args).map_err(|e| e.to_string())?;
    let target = parse_time_str(&args.time)?;
    let reference = match args.reference {
        Some(ref s) => parse_time_str(s)?,
        None => Utc::now(),
    };

    let diff = target.signed_duration_since(reference);
    let is_past = diff.num_seconds() < 0;
    let abs_secs = diff.num_seconds().abs();

    let description = if abs_secs < 60 {
        "刚刚".to_string()
    } else if abs_secs < 3600 {
        format!("{} 分钟{}", abs_secs / 60, if is_past { "前" } else { "后" })
    } else if abs_secs < 86400 {
        format!("{} 小时{}", abs_secs / 3600, if is_past { "前" } else { "后" })
    } else {
        format!("{} 天{}", abs_secs / 86400, if is_past { "前" } else { "后" })
    };

    Ok(json!({
        "success": true,
        "targetTime": target.to_rfc3339(),
        "referenceTime": reference.to_rfc3339(),
        "description": description,
        "isPast": is_past
    }))
}

// 5. 世界时间
#[derive(Deserialize)]
struct GetWorldTimeArgs {
    city: String,
}

fn handle_get_world_time(args: Value) -> Result<Value, String> {
    let args: GetWorldTimeArgs = serde_json::from_value(args).map_err(|e| e.to_string())?;
    
    let tz_map: HashMap<&str, &str> = [
        ("beijing", "Asia/Shanghai"), ("shanghai", "Asia/Shanghai"),
        ("london", "Europe/London"), ("newyork", "America/New_York"),
        // ... 此处省略完整映射,逻辑同 JS 代码
    ].iter().cloned().collect();

    let tz_str = tz_map.get(args.city.as_str()).ok_or("未知城市")?;
    let tz: Tz = tz_str.parse().map_err(|_| "时区错误")?;
    let now = Utc::now().with_timezone(&tz);

    Ok(json!({
        "success": true,
        "city": args.city,
        "timezone": tz_str,
        "time": now.format("%Y-%m-%d %H:%M:%S").to_string()
    }))
}

// 6. 创建提醒
#[derive(Deserialize)]
struct CreateReminderArgs {
    from: Option<String>,
    delay: DelaySpec,
}

#[derive(Deserialize)]
struct DelaySpec {
    value: i64,
    unit: String, // seconds, minutes, etc.
}

fn handle_create_reminder(args: Value) -> Result<Value, String> {
    let args: CreateReminderArgs = serde_json::from_value(args).map_err(|e| e.to_string())?;
    let start = match args.from {
        Some(ref s) if s != "now" => parse_time_str(s)?,
        _ => Utc::now(),
    };

    let delay_ms = match args.delay.unit.as_str() {
        "seconds" => args.delay.value * 1000,
        "minutes" => args.delay.value * 60 * 1000,
        "hours" => args.delay.value * 60 * 60 * 1000,
        "days" => args.delay.value * 24 * 60 * 60 * 1000,
        _ => return Err("无效单位".to_string()),
    };

    let reminder_time = start + chrono::Duration::milliseconds(delay_ms);

    Ok(json!({
        "success": true,
        "reminderTime": reminder_time.to_rfc3339()
    }))
}

// --- 服务器逻辑 ---

type AppState = Arc<HashSet<String>>;

#[tokio::main]
async fn main() {
    // 初始化配置
    let _config = &*CONFIG;
    
    // 共享状态 (API Keys)
    let state = Arc::new(CONFIG.allowed_keys.clone());

    // CORS 配置
    let cors = CorsLayer::new()
        .allow_origin(Any)
        .allow_methods(Any)
        .allow_headers(Any);

    let app = Router::new()
        .route("/health", get(health_check))
        .route("/mcp", post(mcp_handler))
        .route("/test", get(test_handler))
        .layer(cors)
        .with_state(state);

    let addr = format!("{}:{}", CONFIG.host, CONFIG.port);
    println!("=== 时间 MCP 服务器已启动 ===");
    println!("服务器地址: http://{}", addr);
    
    let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

// API Key 中间件逻辑 (在 Handler 中处理)
fn check_auth(key: Option<&String>, state: &HashSet<String>) -> Result<(), (StatusCode, String)> {
    match key {
        Some(k) if state.contains(k) => Ok(()),
        Some(_) => Err((StatusCode::FORBIDDEN, "无效的 API Key".to_string())),
        None => Err((StatusCode::UNAUTHORIZED, "缺少 API Key".to_string())),
    }
}

async fn health_check() -> impl IntoResponse {
    AxumJson(json!({
        "status": "ok",
        "server": "Time MCP Server (Rust)",
        "version": "1.0.0"
    }))
}

#[derive(Deserialize)]
struct TestQuery {
    key: String,
}

async fn test_handler(Query(query): Query<TestQuery>, State(state): State<AppState>) -> impl IntoResponse {
    if let Err((status, msg)) = check_auth(Some(&query.key), &state) {
        return (status, AxumJson(json!({ "error": msg })));
    }
    
    (StatusCode::OK, AxumJson(json!({
        "success": true,
        "message": "API Key 验证成功",
        "serverTime": Utc::now().to_rfc3339()
    })))
}

#[derive(Deserialize)]
struct McpQuery {
    key: String,
}

async fn mcp_handler(
    Query(query): Query<McpQuery>,
    State(state): State<AppState>,
    AxumJson(body): AxumJson<JsonRpcRequest>,
) -> impl IntoResponse {
    // 1. 验证 Key
    if let Err((status, msg)) = check_auth(Some(&query.key), &state) {
        return (status, AxumJson(json!({ "error": msg })));
    }

    // 2. 路由请求
    let result = match body.method.as_str() {
        // MCP 协议标准方法
        "initialize" => Ok(json!({
            "protocolVersion": "2024-11-05",
            "serverInfo": {
                "name": "Time MCP Server",
                "version": "1.0.0"
            },
            "capabilities": {
                "tools": {}
            }
        })),
        "initialized" => Ok(json!({})),
        "shutdown" => Ok(json!({})),
        // 工具相关方法
        "tools/list" => Ok(json!({
            "tools": [
                {
                    "name": "getCurrentTime",
                    "description": "获取当前时间",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "timezone": {
                                "type": "string",
                                "default": "UTC",
                                "description": "时区,例如 Asia/Shanghai"
                            },
                            "format": {
                                "type": "string",
                                "default": "iso",
                                "enum": ["iso", "datetime", "timestamp", "relative"],
                                "description": "时间格式"
                            }
                        }
                    }
                },
                {
                    "name": "timeDiff",
                    "description": "计算时间差异",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "from": {
                                "type": "string",
                                "description": "起始时间(ISO格式或时间戳)"
                            },
                            "to": {
                                "type": "string",
                                "description": "结束时间(ISO格式或时间戳)"
                            }
                        },
                        "required": ["from", "to"]
                    }
                },
                {
                    "name": "timestampConvert",
                    "description": "时间戳转换",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "value": {
                                "type": "string",
                                "description": "时间值(ISO格式或时间戳)"
                            },
                            "target_format": {
                                "type": "string",
                                "default": "datetime",
                                "enum": ["iso", "datetime", "timestamp", "human"],
                                "description": "目标格式"
                            }
                        },
                        "required": ["value"]
                    }
                },
                {
                    "name": "relativeTime",
                    "description": "相对时间",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "time": {
                                "type": "string",
                                "description": "目标时间(ISO格式或时间戳)"
                            },
                            "reference": {
                                "type": "string",
                                "description": "参考时间(可选,默认为当前时间)"
                            }
                        },
                        "required": ["time"]
                    }
                },
                {
                    "name": "getWorldTime",
                    "description": "世界时间",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "city": {
                                "type": "string",
                                "description": "城市名称,例如 beijing, london, newyork"
                            }
                        },
                        "required": ["city"]
                    }
                },
                {
                    "name": "createReminder",
                    "description": "创建提醒",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "from": {
                                "type": "string",
                                "description": "起始时间(可选,默认为now)"
                            },
                            "delay": {
                                "type": "object",
                                "properties": {
                                    "value": {
                                        "type": "integer",
                                        "description": "延迟数值"
                                    },
                                    "unit": {
                                        "type": "string",
                                        "enum": ["seconds", "minutes", "hours", "days"],
                                        "description": "时间单位"
                                    }
                                },
                                "required": ["value", "unit"]
                            }
                        },
                        "required": ["delay"]
                    }
                }
            ]
        })),
        "tools/call" => {
            // 解析工具调用
            let params = body.params.unwrap_or(json!({}));
            let tool_name = params["name"].as_str().unwrap_or("");
            let tool_args = params.get("arguments").cloned().unwrap_or(json!({}));

            let res = match tool_name {
                "getCurrentTime" => handle_get_current_time(tool_args),
                "timeDiff" => handle_time_diff(tool_args),
                "timestampConvert" => handle_timestamp_convert(tool_args),
                "relativeTime" => handle_relative_time(tool_args),
                "getWorldTime" => handle_get_world_time(tool_args),
                "createReminder" => handle_create_reminder(tool_args),
                _ => Err(format!("未知工具: {}", tool_name)),
            };

            res.map(|content| json!({
                "content": [{ "type": "text", "text": content.to_string() }]
            }))
        }
        _ => Err(format!("未知方法: {}", body.method)),
    };

    // 3. 构造响应
    let response = match result {
        Ok(res) => JsonRpcResponse {
            jsonrpc: "2.0".to_string(),
            id: body.id,
            result: Some(res),
            error: None,
        },
        Err(msg) => JsonRpcResponse {
            jsonrpc: "2.0".to_string(),
            id: body.id,
            result: None,
            error: Some(JsonRpcError { code: -32000, message: msg }),
        },
    };

    (StatusCode::OK, AxumJson(json!(response)))
}

mcpServers.json

{
  "mcpServers": {
    "time-streamable": {
      "type": "streamable",
      "name": "TimeServer",
      "description": "Get the current time in a specified timezone",
      "url": "http://127.0.0.1:8700/mcp?key=default_key_123456"
    }
  }
}


js 实现

package.json

{
  "name": "time_mcp_server_with_js",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "packageManager": "pnpm@10.13.0",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.25.3",
    "cors": "^2.8.5",
    "express": "^5.2.1",
    "zod": "^4.3.5"
  }
}

main.mjs

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { z } from "zod";
import express from "express";
import cors from "cors";


// 配置
const CONFIG = {
  port: 8700,
  host: '0.0.0.0',
  // 这里可以配置允许的 API Key,实际使用时可以从环境变量或数据库读取
  allowedKeys: new Set([
    process.env.TIME_SERVER_API_KEY || 'default_key_123456' // 默认 key,生产环境请修改
  ])
};


// 创建一个时间 MCP 服务器
const server = new McpServer({
  name: "TimeServer",
  version: "1.0.0"
});

// 工具 1: 获取当前时间
server.tool(
  "getCurrentTime",
  '获取当前时间,支持指定时区和格式化',
  {
    timezone: z.string().optional().default('UTC').describe('时区,例如: Asia/Shanghai, America/New_York, Europe/London'),
    format: z.string().optional().default('iso').describe('时间格式: iso, datetime, timestamp, relative')
  },
  async ({ timezone, format }) => {
    const date = new Date();
    let formattedTime;

    try {
      const options = { timeZone: timezone };
      const localDate = new Date(date.toLocaleString('en-US', options));

      switch (format) {
        case 'iso':
          formattedTime = localDate.toISOString();
          break;
        case 'datetime':
          formattedTime = localDate.toLocaleString('zh-CN', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit',
            timeZone: timezone
          });
          break;
        case 'timestamp':
          formattedTime = localDate.getTime().toString();
          break;
        case 'relative':
          const now = new Date();
          const diff = now.getTime() - localDate.getTime();
          if (diff < 60000) {
            formattedTime = '刚刚';
          } else if (diff < 3600000) {
            formattedTime = `${Math.floor(diff / 60000)} 分钟前`;
          } else if (diff < 86400000) {
            formattedTime = `${Math.floor(diff / 3600000)} 小时前`;
          } else {
            formattedTime = `${Math.floor(diff / 86400000)} 天前`;
          }
          break;
        default:
          formattedTime = localDate.toISOString();
      }

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: true,
            timezone: timezone,
            format: format,
            time: formattedTime,
            timestamp: localDate.getTime(),
            iso: localDate.toISOString()
          }, null, 2)
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: false,
            error: `无效的时区: ${timezone}`
          }, null, 2)
        }]
      };
    }
  }
);

// 工具 2: 获取时间差异
server.tool(
  "timeDiff",
  '计算两个时间点之间的差异',
  {
    from: z.string().describe('开始时间 (ISO 格式或时间戳)'),
    to: z.string().describe('结束时间 (ISO 格式或时间戳)')
  },
  async ({ from, to }) => {
    try {
      let fromTime, toTime;

      // 处理时间戳
      if (/^\d+$/.test(from)) {
        fromTime = new Date(parseInt(from));
      } else {
        fromTime = new Date(from);
      }

      if (/^\d+$/.test(to)) {
        toTime = new Date(parseInt(to));
      } else {
        toTime = new Date(to);
      }

      const diffMs = Math.abs(toTime.getTime() - fromTime.getTime());
      const diffSec = Math.floor(diffMs / 1000);
      const diffMin = Math.floor(diffSec / 60);
      const diffHour = Math.floor(diffMin / 60);
      const diffDay = Math.floor(diffHour / 24);
      const diffWeek = Math.floor(diffDay / 7);

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: true,
            from: fromTime.toISOString(),
            to: toTime.toISOString(),
            difference: {
              milliseconds: diffMs,
              seconds: diffSec,
              minutes: diffMin,
              hours: diffHour,
              days: diffDay,
              weeks: diffWeek,
              description: `${diffDay}${diffHour % 24} 小时 ${diffMin % 60} 分钟 ${diffSec % 60} 秒`
            }
          }, null, 2)
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: false,
            error: '时间解析错误,请检查输入格式'
          }, null, 2)
        }]
      };
    }
  }
);

// 工具 3: 时间戳转换
server.tool(
  "timestampConvert",
  '在时间戳、ISO 字符串和日期对象之间转换',
  {
    value: z.string().describe('要转换的值 (时间戳或 ISO 字符串)'),
    targetFormat: z.enum(['iso', 'datetime', 'timestamp', 'human']).default('datetime').describe('目标格式')
  },
  async ({ value, targetFormat }) => {
    try {
      let date;

      if (/^\d+$/.test(value)) {
        date = new Date(parseInt(value));
      } else {
        date = new Date(value);
      }

      let result;

      switch (targetFormat) {
        case 'iso':
          result = date.toISOString();
          break;
        case 'datetime':
          result = date.toLocaleString('zh-CN', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit',
            weekday: 'short'
          });
          break;
        case 'timestamp':
          result = date.getTime().toString();
          break;
        case 'human':
          const now = new Date();
          const diff = date.getTime() - now.getTime();
          const absDiff = Math.abs(diff);
          
          if (absDiff < 60000) {
            result = diff >= 0 ? '不到 1 分钟后' : '不到 1 分钟前';
          } else if (absDiff < 3600000) {
            const mins = Math.floor(absDiff / 60000);
            result = diff >= 0 ? `${mins} 分钟后` : `${mins} 分钟前`;
          } else if (absDiff < 86400000) {
            const hours = Math.floor(absDiff / 3600000);
            result = diff >= 0 ? `${hours} 小时后` : `${hours} 小时前`;
          } else if (absDiff < 604800000) {
            const days = Math.floor(absDiff / 86400000);
            result = diff >= 0 ? `${days} 天后` : `${days} 天前`;
          } else {
            result = date.toLocaleDateString('zh-CN');
          }
          break;
        default:
          result = date.toISOString();
      }

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: true,
            input: value,
            result: result,
            parsed: date.toISOString(),
            timestamp: date.getTime()
          }, null, 2)
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: false,
            error: '转换错误,请检查输入格式'
          }, null, 2)
        }]
      };
    }
  }
);

// 工具 4: 获取相对时间
server.tool(
  "relativeTime",
  '获取相对于当前时间的描述性时间',
  {
    time: z.string().describe('目标时间 (ISO 格式或时间戳)'),
    reference: z.string().optional().describe('参考时间,默认为当前时间')
  },
  async ({ time, reference }) => {
    try {
      let targetTime, refTime;

      if (/^\d+$/.test(time)) {
        targetTime = new Date(parseInt(time));
      } else {
        targetTime = new Date(time);
      }

      if (reference) {
        if (/^\d+$/.test(reference)) {
          refTime = new Date(parseInt(reference));
        } else {
          refTime = new Date(reference);
        }
      } else {
        refTime = new Date();
      }

      const diffMs = targetTime.getTime() - refTime.getTime();
      const diffSec = Math.floor(Math.abs(diffMs) / 1000);
      const diffMin = Math.floor(diffSec / 60);
      const diffHour = Math.floor(diffMin / 60);
      const diffDay = Math.floor(diffHour / 24);
      const diffWeek = Math.floor(diffDay / 7);
      const diffMonth = Math.floor(diffDay / 30);
      const diffYear = Math.floor(diffDay / 365);

      let description;
      let isPast = diffMs < 0;

      if (diffSec < 60) {
        description = isPast ? '刚刚' : '现在';
      } else if (diffMin < 60) {
        description = isPast ? `${diffMin} 分钟前` : `${diffMin} 分钟后`;
      } else if (diffHour < 24) {
        description = isPast ? `${diffHour} 小时前` : `${diffHour} 小时后`;
      } else if (diffDay < 7) {
        description = isPast ? `${diffDay} 天前` : `${diffDay} 天后`;
      } else if (diffWeek < 4) {
        description = isPast ? `${diffWeek} 周前` : `${diffWeek} 周后`;
      } else if (diffMonth < 12) {
        description = isPast ? `${diffMonth} 个月前` : `${diffMonth} 个月后`;
      } else {
        description = isPast ? `${diffYear} 年前` : `${diffYear} 年后`;
      }

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: true,
            targetTime: targetTime.toISOString(),
            referenceTime: refTime.toISOString(),
            differenceMs: diffMs,
            description: description,
            isFuture: diffMs > 0,
            isPast: diffMs < 0,
            isPresent: diffMs === 0
          }, null, 2)
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: false,
            error: '时间解析错误'
          }, null, 2)
        }]
      };
    }
  }
);

// 工具 5: 获取常用时区时间
server.tool(
  "getWorldTime",
  '获取世界各地主要城市当前时间',
  {
    city: z.enum([
      'beijing', 'shanghai', 'hongkong', 'taipei',
      'tokyo', 'seoul', 'singapore', 'mumbai',
      'dubai', 'moscow', 'istanbul', 'cairo',
      'london', 'paris', 'berlin', 'rome',
      'newyork', 'losangeles', 'chicago', 'toronto',
      'saopaulo', 'sydney', 'auckland', 'johannesburg'
    ]).describe('城市名称')
  },
  async ({ city }) => {
    const timezoneMap = {
      'beijing': 'Asia/Shanghai',
      'shanghai': 'Asia/Shanghai',
      'hongkong': 'Asia/Hong_Kong',
      'taipei': 'Asia/Taipei',
      'tokyo': 'Asia/Tokyo',
      'seoul': 'Asia/Seoul',
      'singapore': 'Asia/Singapore',
      'mumbai': 'Asia/Kolkata',
      'dubai': 'Asia/Dubai',
      'moscow': 'Europe/Moscow',
      'istanbul': 'Europe/Istanbul',
      'cairo': 'Africa/Cairo',
      'london': 'Europe/London',
      'paris': 'Europe/Paris',
      'berlin': 'Europe/Berlin',
      'rome': 'Europe/Rome',
      'newyork': 'America/New_York',
      'losangeles': 'America/Los_Angeles',
      'chicago': 'America/Chicago',
      'toronto': 'America/Toronto',
      'saopaulo': 'America/Sao_Paulo',
      'sydney': 'Australia/Sydney',
      'auckland': 'Pacific/Auckland',
      'johannesburg': 'Africa/Johannesburg'
    };

    const cityNames = {
      'beijing': '北京',
      'shanghai': '上海',
      'hongkong': '中国香港',
      'taipei': '台北',
      'tokyo': '东京',
      'seoul': '首尔',
      'singapore': '新加坡',
      'mumbai': '孟买',
      'dubai': '迪拜',
      'moscow': '莫斯科',
      'istanbul': '伊斯坦布尔',
      'cairo': '开罗',
      'london': '伦敦',
      'paris': '巴黎',
      'berlin': '柏林',
      'rome': '罗马',
      'newyork': '纽约',
      'losangeles': '洛杉矶',
      'chicago': '芝加哥',
      'toronto': '多伦多',
      'saopaulo': '圣保罗',
      'sydney': '悉尼',
      'auckland': '奥克兰',
      'johannesburg': '约翰内斯堡'
    };

    const timezone = timezoneMap[city];
    const date = new Date();
    const localDate = new Date(date.toLocaleString('en-US', { timeZone: timezone }));

    return {
      content: [{
        type: "text",
        text: JSON.stringify({
          success: true,
          city: city,
          cityName: cityNames[city],
          timezone: timezone,
          time: {
            full: localDate.toLocaleString('zh-CN', {
              year: 'numeric',
              month: '2-digit',
              day: '2-digit',
              hour: '2-digit',
              minute: '2-digit',
              second: '2-digit',
              weekday: 'long',
              timeZone: timezone
            }),
            iso: localDate.toISOString(),
            timestamp: localDate.getTime()
          }
        }, null, 2)
      }]
    };
  }
);

// 工具 6: 创建定时提醒
server.tool(
  "createReminder",
  '创建一个时间提醒,计算提醒时间',
  {
    from: z.string().optional().default('now').describe('开始时间,默认为当前时间'),
    delay: z.object({
      value: z.number().describe('延迟数值'),
      unit: z.enum(['seconds', 'minutes', 'hours', 'days', 'weeks']).describe('延迟单位')
    }).describe('延迟时间和单位')
  },
  async ({ from, delay }) => {
    try {
      let startTime;
      
      if (from === 'now') {
        startTime = new Date();
      } else if (/^\d+$/.test(from)) {
        startTime = new Date(parseInt(from));
      } else {
        startTime = new Date(from);
      }

      let delayMs;
      switch (delay.unit) {
        case 'seconds':
          delayMs = delay.value * 1000;
          break;
        case 'minutes':
          delayMs = delay.value * 60 * 1000;
          break;
        case 'hours':
          delayMs = delay.value * 60 * 60 * 1000;
          break;
        case 'days':
          delayMs = delay.value * 24 * 60 * 60 * 1000;
          break;
        case 'weeks':
          delayMs = delay.value * 7 * 24 * 60 * 60 * 1000;
          break;
      }

      const reminderTime = new Date(startTime.getTime() + delayMs);

      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: true,
            startTime: startTime.toISOString(),
            delay: delay,
            reminderTime: reminderTime.toISOString(),
            timestamp: reminderTime.getTime(),
            humanReadable: reminderTime.toLocaleString('zh-CN', {
              year: 'numeric',
              month: '2-digit',
              day: '2-digit',
              hour: '2-digit',
              minute: '2-digit',
              second: '2-digit'
            })
          }, null, 2)
        }]
      };
    } catch (error) {
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            success: false,
            error: '创建提醒失败'
          }, null, 2)
        }]
      };
    }
  }
);



async function main() {
  // 创建 Express 应用
  const app = express();
  app.use(cors());
  app.use(express.json());

  // API Key 验证中间件
  const apiKeyAuth = (req, res, next) => {
    // 从查询参数获取 key
    const apiKey = req.query.key;
    
    // 或者从请求头获取
    // const apiKey = req.headers['x-api-key'];
    
    if (!apiKey) {
      return res.status(401).json({
        success: false,
        error: "缺少 API Key",
        usage: "请使用 ?key=your_api_key 参数访问服务"
      });
    }

    if (!CONFIG.allowedKeys.has(apiKey)) {
      return res.status(403).json({
        success: false,
        error: "无效的 API Key",
        usage: "请使用正确的 API Key 访问服务"
      });
    }

    next();
  };

  // 创建 Streamable HTTP 传输
  const transport = new StreamableHTTPServerTransport();

  // 连接服务器到传输
  await server.connect(transport);

  // 设置路由,所有 MCP 请求都需要 API Key 验证
  app.use('/mcp', apiKeyAuth);
  
  app.post('/mcp', async (req, res, next) => {
    try {
      console.log(`收到 MCP 请求: ${req.method} ${req.url}`, {
        key: req.query.key,
        sessionId: transport.sessionId
      });
      
      await transport.handleRequest(req, res, req.body);
    } catch (error) {
      console.error('MCP 请求处理错误:', error);
      next(error);
    }
  });

  // 健康检查端点(不需要 API Key)
  app.get('/health', (req, res) => {
    res.json({
      status: 'ok',
      server: 'Time MCP Server',
      version: '1.0.0',
      transport: 'Streamable HTTP',
      sessionId: transport.sessionId,
      requiresKey: true,
      endpoints: {
        mcp: 'POST /mcp?key=your_api_key',
        health: 'GET /health'
      }
    });
  });

  // 测试端点(需要 API Key)
  app.get('/test', apiKeyAuth, (req, res) => {
    res.json({
      success: true,
      message: 'API Key 验证成功',
      serverTime: new Date().toISOString(),
      key: req.query.key.substring(0, 8) + '...' // 部分显示 key
    });
  });

  // 获取服务器信息(需要 API Key)
  app.get('/info', apiKeyAuth, (req, res) => {
    res.json({
      success: true,
      server: {
        name: 'Time MCP Server',
        version: '1.0.0',
        description: '提供时间相关功能的 MCP 服务器',
        tools: [
          'getCurrentTime - 获取当前时间',
          'timeDiff - 计算时间差异',
          'timestampConvert - 时间戳转换',
          'relativeTime - 获取相对时间',
          'getWorldTime - 获取世界各地时间',
          'createReminder - 创建定时提醒'
        ]
      },
      client: {
        ip: req.ip,
        key: req.query.key.substring(0, 8) + '...'
      }
    });
  });

  // 错误处理
  app.use((err, req, res, next) => {
    console.error('服务器错误:', err);
    res.status(500).json({
      success: false,
      error: '服务器内部错误',
      message: err.message
    });
  });

  // 404 处理
  app.use((req, res) => {
    res.status(404).json({
      success: false,
      error: '未找到端点',
      availableEndpoints: {
        'GET /health': '健康检查(无需 key)',
        'POST /mcp?key=your_key': 'MCP 服务端点',
        'GET /test?key=your_key': '测试 API Key',
        'GET /info?key=your_key': '获取服务器信息'
      }
    });
  });

  // 监听端口
  const { port, host } = CONFIG;

  app.listen(port, host, () => {
    console.log(`=== 时间 MCP 服务器已启动 ===`);
    console.log(`服务器地址: http://${host}:${port}`);
    console.log(`健康检查: http://${host}:${port}/health`);
    console.log(`MCP 端点: http://${host}:${port}/mcp?key=your_key`);
    console.log(`测试端点: http://${host}:${port}/test?key=your_key`);
    console.log(`服务器信息: http://${host}:${port}/info?key=your_key`);
    console.log(`\n配置信息:`);
    console.log(`- 端口: ${port}`);
    console.log(`- 需要 API Key: 是`);
    console.log(`- 允许的 Key 数量: ${CONFIG.allowedKeys.size}`);
    
    if (process.env.TIME_SERVER_API_KEY) {
      console.log(`- 环境变量 KEY: 已设置`);
    } else {
      console.log(`- 环境变量 KEY: 未设置,使用默认值`);
      console.log(`- 默认 KEY: ${Array.from(CONFIG.allowedKeys)[0]}`);
    }
    
    console.log(`\n使用方法:`);
    console.log(`1. 客户端连接 URL: http://${host}:${port}/mcp?key=your_key`);
    console.log(`2. 或设置环境变量 TIME_SERVER_API_KEY=your_key`);
    console.log(`\n可用工具:`);
    console.log('1. getCurrentTime - 获取当前时间');
    console.log('2. timeDiff - 计算时间差异');
    console.log('3. timestampConvert - 时间戳转换');
    console.log('4. relativeTime - 获取相对时间');
    console.log('5. getWorldTime - 获取世界各地时间');
    console.log('6. createReminder - 创建定时提醒');
    console.log(`\n服务器已准备好接收请求...`);
  });
}

main().catch(console.error);