Skip to main content
Glama
index.ts6.42 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { McpAgent } from "agents/mcp"; import { z } from "zod"; import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; import relativeTime from "dayjs/plugin/relativeTime"; import weekOfYear from "dayjs/plugin/weekOfYear"; import isoWeek from "dayjs/plugin/isoWeek"; // ---- Day.js setup ---- dayjs.extend(utc); dayjs.extend(timezone); dayjs.extend(relativeTime); dayjs.extend(weekOfYear); dayjs.extend(isoWeek); // ---- MCP Agent ---- export class MyMCP extends McpAgent { // core MCP server server = new McpServer({ name: "time-mcp-remote", version: "1.0.0", }); // called once when the MCP server starts up async init() { // current_time this.server.tool( "current_time", { format: z .enum([ "h:mm A", "h:mm:ss A", "YYYY-MM-DD HH:mm:ss", "YYYY-MM-DD", "YYYY-MM", "MM/DD/YYYY", "MM/DD/YY", "YYYY/MM/DD", "YYYY/MM", ]) .default("YYYY-MM-DD HH:mm:ss"), timezone: z .string() .describe("IANA timezone, e.g. Europe/Amsterdam") .optional(), }, async ({ format, timezone }) => { const utcTime = dayjs.utc(); let localTz: string; try { localTz = timezone ?? dayjs.tz.guess(); } catch { localTz = timezone ?? "UTC"; } const localTime = dayjs().tz(localTz); return { content: [ { type: "text", text: `Current UTC time is ${utcTime.format( format )}, and the time in ${localTz} is ${localTime.format(format)}.`, }, ], }; } ); // relative_time this.server.tool( "relative_time", { time: z .string() .describe("Time to compare with now. Format: YYYY-MM-DD HH:mm:ss"), }, async ({ time }) => { const result = dayjs(time).fromNow(); return { content: [{ type: "text", text: result }], }; } ); // days_in_month this.server.tool( "days_in_month", { date: z .string() .describe("Date to inspect (YYYY-MM-DD). If omitted, use current month.") .optional(), }, async ({ date }) => { const days = date ? dayjs(date).daysInMonth() : dayjs().daysInMonth(); return { content: [ { type: "text", text: `The number of days in month is ${days}.`, }, ], }; } ); // get_timestamp this.server.tool( "get_timestamp", { time: z .string() .describe("Time to get timestamp for, parsed as UTC (YYYY-MM-DD HH:mm:ss.SSS)") .optional(), }, async ({ time }) => { const ts = time ? dayjs.utc(time).valueOf() : dayjs().valueOf(); const text = time ? `The timestamp of ${time} (parsed as UTC) is ${ts} ms.` : `The current timestamp is ${ts} ms.`; return { content: [{ type: "text", text }], }; } ); // convert_time this.server.tool( "convert_time", { sourceTimezone: z .string() .describe("Source timezone (IANA), e.g. Europe/Amsterdam"), targetTimezone: z .string() .describe("Target timezone (IANA), e.g. Asia/Tokyo"), time: z .string() .describe("Date and time (24h). e.g. 2025-03-23 12:30:00"), }, async ({ sourceTimezone, targetTimezone, time }) => { const sourceTime = dayjs.tz(time, sourceTimezone); const targetTime = sourceTime.tz(targetTimezone); const formatString = "YYYY-MM-DD HH:mm:ss"; const diffHours = targetTime.diff(sourceTime, "hour"); return { content: [ { type: "text", text: `Current time in ${sourceTimezone} is ${sourceTime.format( formatString )}, and the time in ${targetTimezone} is ${targetTime.format( formatString )}. The time difference is ${diffHours} hours.`, }, ], }; } ); // get_week_year this.server.tool( "get_week_year", { date: z .string() .describe("Date to use, e.g. 2025-03-23. If omitted, uses current date.") .optional(), }, async ({ date }) => { const d = date ? dayjs(date) : dayjs(); const week = d.week(); const isoWeekNum = d.isoWeek(); return { content: [ { type: "text", text: `The week of the year is ${week}, and the isoWeek of the year is ${isoWeekNum}.`, }, ], }; } ); } } // ---- Cloudflare Worker entrypoint ---- // This exposes your MCP server over SSE (/sse) and HTTP (/mcp), // which matches the pattern from Cloudflare’s own examples. :contentReference[oaicite:1]{index=1} export default { async fetch(request: Request, env: any, ctx: ExecutionContext): Promise<Response> { const url = new URL(request.url); // SSE transport (works with MCP Inspector + mcp-remote) if (url.pathname === "/sse" || url.pathname === "/sse/message") { // @ts-ignore: MyMCP is bound as a Durable Object via wrangler config return MyMCP.serveSSE("/sse").fetch(request, env, ctx); } // Streamable HTTP transport (2025 MCP standard) if (url.pathname.startsWith("/mcp")) { // @ts-ignore return MyMCP.serve("/mcp").fetch(request, env, ctx); } // Optional health endpoint if (url.pathname === "/" || url.pathname === "/health") { return new Response( JSON.stringify({ name: "time-mcp-remote", version: "1.0.0", transports: { sse: "/sse", http: "/mcp" }, status: "ok", timestamp: new Date().toISOString(), }), { status: 200, headers: { "content-type": "application/json" }, } ); } return new Response("Not found", { status: 404 }); }, };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CultriX-Github/mcp-timeserver'

If you have feedback or need assistance with the MCP directory API, please join our Discord server