Scheduling with a client in another country is a small calculation you get wrong once a year, usually
in March. The MCP Timezone Planner answers it directly: ranked times where every participant is inside
their own working hours, the exact daily overlap, the dates the clocks change, and a
.ics file you can send. It reads no calendar and stores nothing but the contacts you give
it.
claude mcp add timezone -- npx -y @theluckystrike/mcp-timezone
Cursor and Claude Desktop take the same server as a config block:
{
"mcpServers": {
"timezone": {
"command": "npx",
"args": ["-y", "@theluckystrike/mcp-timezone"]
}
}
}
The npm publish is pending, so until it lands use the .mcpb bundle from the latest
release or a clone and build. Per client paths are on the
setup pages.
Take the pair a lot of European freelancers actually work: Warsaw and New York, both on 09:00 to 17:00 days. Ask what the shared window is and the honest answer depends on the date, because Europe and the United States change their clocks on different weekends.
| Date | Warsaw | New York | Shared window, UTC | Overlap |
|---|---|---|---|---|
| 2026-09-10 | UTC+2 | UTC-4 | 13:00 to 15:00 | 2 hours |
| 2026-03-16 | UTC+1 | UTC-4 | 13:00 to 16:00 | 3 hours |
On 16 March 2026 the United States has already moved to daylight time, on 8 March, and Europe has not,
until 29 March. For those three weeks the two cities are 5 hours apart rather than the usual 6, and the
shared working window is 50% wider: 3 hours instead of 2. A recurring call booked at the edge of the
window in that gap moves outside somebody's working day on 29 March. This is the single most useful
thing the server tells you, and it falls out of overlap because the window is computed on a
real date rather than from a stored offset.
overlap { places: ["Warsaw", "New York"], date: "2026-03-16" }
dst_changes { place: "Warsaw", year: 2026 }
-> the exact UTC instant, the offset before and after, and the local time either side
find_meeting_slots proposes times on a 30-minute grid where the whole meeting, start to
end, is inside every participant's own working window on their own local calendar day. Weekends in the
first participant's zone are skipped. Every candidate is scored by the worst participant's distance from
13:00 local, in hours, and sorted ascending.
The worst, not the average, on purpose. Averaging lets a slot that is pleasant for two people and 07:00 for the third outrank one that is 10:00 for everybody, which is how scheduling tools produce suggestions nobody accepts. A fairness of 0 would put the meeting at midday for all of them, and anything under about 2 is comfortable.
find_meeting_slots {
participants: [{name:"Me", zone:"Warsaw"},
{name:"Client", zone:"New York"},
{name:"Designer", zone:"London"}],
duration_minutes: 60, days: 5
}
-> 15 slots fit all 3. Best: 2026-09-07T13:30:00.000Z, fairness 3.00h
Me 15:30-16:30 | Client 09:30-10:30 | Designer 14:30-15:30
Three hours of fairness is not a ranking flaw, it is the truth about that pair: with 09:00 to 17:00 on both sides the shared window is only two hours wide, so somebody's meeting is always far from the middle of their day. The score says so instead of hiding it. Widen one person's hours and it improves. When nothing fits at all, the server says so and shows the windows rather than proposing a 06:00 call.
ics_create { title: "Kickoff with Acme", start: "2026-09-10 15:00", zone: "Warsaw",
duration_minutes: 45, attendees: ["maria@acme.com"] }
-> DTSTART 2026-09-10T13:00:00.000Z
The file carries UTC times and no VTIMEZONE block, deliberately: a hand written
VTIMEZONE with stale DST rules is the classic way an invite lands an hour off in somebody
else's calendar. A time with no offset is wall-clock time in from_zone, so
2026-09-10 15:00 with Warsaw means 15:00 in Warsaw. A wall time inside a spring-forward gap
does not exist and resolves to the instant right after the jump, which is what calendars do; an
ambiguous time in the autumn fold resolves to the first occurrence.
City and country names resolve through a built-in table of 510 entries covering more than 300 cities,
every commonly used country, US state shorthands and abbreviations like PST, IST and CET. Every entry is
checked against Intl.supportedValuesOf("timeZone") at startup, and an entry this Node build
cannot resolve is dropped with a line on stderr rather than silently answering with the wrong zone. An
unknown name is never guessed: it comes back as an error with suggestions. IANA ids always win, so
America/Denver is exactly that. No DST rules are stored here at all; every offset comes
from the ICU data inside your Node build, so the rules stay current as Node updates.
Working hours are the only calendar this server has. It does not read your existing meetings, does
not know public holidays unless you pass them to business_days, and does not model a
Friday-Saturday weekend. Saying so is cheaper than a wrong suggestion.
Free covers now, convert_time, overlap,
dst_changes and business_days without limit, slot searches for up to 3
participants over 5 days, 5 saved contacts and 3 .ics files a month. Pro ($19 once) removes
those limits and adds recurring slot search. Product page:
MCP Timezone Planner. Side by side with the alternatives:
timezone comparison.
No. It knows only the working hours you give it and the contacts you save. It writes .ics files; it never reads or connects to a calendar service, and it makes no network request at all, including for license activation.
It stores no DST rules of its own. Every offset is read from the ICU data inside your Node build via Intl, so it stays current as Node updates. That is why Warsaw and New York come out 5 hours apart between 8 and 29 March 2026 rather than the usual 6, which widens their shared working window from 2 hours to 3.
Because a real overlap can be two hours wide. Slots are scored by the worst participant's distance from 13:00 local, not the average, so a time that is pleasant for two people and 07:00 for a third never outranks one that is 10:00 for everybody. The score reports the cost so you can decide who absorbs it.
Yes. India at +05:30, Nepal at +05:45, Adelaide at +09:30 and Chatham are handled like any other zone. The slot grid is 30 minutes, so a half-hour zone produces starts on the hour and the half hour in local time.
Because a hand-written VTIMEZONE with stale DST rules is the common way an invite arrives an hour off. The file carries UTC times instead, which every calendar client resolves against its own current rules.