mcpField
M
mycal

mycal

Local
github.com/Junhui20Productivity3Updated 2d ago

About mycal

mycal is a Malaysia calendar API and MCP server for AI assistants, built for people who need state-aware holidays, school dates and business-day calculations. It also offers leave planning and data from named Malaysian government sources.

Key features

  1. 01State-specific public holidays
  2. 02Weekend and replacement-holiday rules
  3. 03Business-day calculations
  4. 04School terms, holidays and exams
  5. 05Leave and long-weekend planning

Use cases

  1. 01Check whether a date is a working day
  2. 02Count business days for a state
  3. 03Look up school and exam dates
  4. 04Plan leave around public holidays

MCP support

The MCP server exposes 13 calendar tools to MCP-compatible AI assistants, including holiday, business-day, school-calendar and leave-planning queries.

Configuration

Local server config is the same for every client. Copy it into your client’s MCP config file.

mcp.json · Universal config
{
"mcpServers": {
"junhui20-mycal": {
"command": "npx",
"args": [
"-y",
"@catlabtech/mycal-mcp-server"
]
}
}
}
Run commandnpx -y @catlabtech/mycal-mcp-server

Local servers need a runtime on your machine (e.g. Node.js 18+). Config file locations differ by client; see your client’s docs.

Packages
npm@catlabtech/mycal-mcp-server0.1.4

Tools

13

Saved tool list · updated 2w ago

ParameterTypeRequiredDescription
typeenumNofederal | state | islamic | islamic_state | replacement | adhoc
yearintegerYesYear (e.g. 2026)
monthintegerNo
statestringNoState code or alias (e.g. 'selangor', 'KL', 'penang')
statusenumNoconfirmed | tentative | announced | cancelled

Details

From the project README

Malaysia Calendar API

Malaysia's most complete calendar API — public holidays, school calendar, exam schedules, and MCP server for AI tools.

npm: mycal-core npm: mycal-sdk npm: mycal-mcp-server License: MIT Deploys on Cloudflare

Data source: Official government gazette (JPM BKPP), JAKIM, KPM, MPM. Not scraped from third-party websites.

Links

Packages

Published to npm under the @catlabtech scope:

PackagePurposeInstall
@catlabtech/mycal-coreShared types, Zod schemas, and calendar/business-day logicnpm install @catlabtech/mycal-core
@catlabtech/mycal-sdkTypeScript client SDK for the REST APInpm install @catlabtech/mycal-sdk
@catlabtech/mycal-mcp-serverMCP server exposing 13 calendar tools for AI agentsnpm install @catlabtech/mycal-mcp-server

Features

  • 50 public holidays for 2026 from official gazette (Warta Kerajaan) — federal + state-specific
  • 13 states + 3 Federal Territories with aliases (KL, JB, Penang, etc.)
  • Weekend-aware — Kedah/Kelantan/Terengganu use Fri-Sat (Kumpulan A), all others use Sat-Sun (Kumpulan B), with Johor's historical switch tracked
  • Cuti ganti (replacement holiday) auto-calculation per state weekend config
  • Business day calculator — per-state, holiday-aware
  • School calendar — terms, holidays, KPM cuti perayaan (Lampiran A/B/C)
  • Exam schedules — SPM, STPM, MUET, PT3
  • iCal subscription feeds — per-state .ics feeds
  • MCP Server for AI agents — 13 tools for Claude, ChatGPT, and other assistants
  • TypeScript SDK (@catlabtech/mycal-sdk) with typed responses
  • OpenAPI 3.1 spec + interactive docs
  • Trilingual — Bahasa Melayu, English, Chinese names (三语支持)

Quick Start

# Clone and install
git clone https://github.com/Junhui20/malaysia-calendar-api.git
cd malaysia-calendar-api
pnpm install

# Build shared packages
pnpm --filter @catlabtech/mycal-core build
pnpm --filter @catlabtech/mycal-sdk build

# Run API locally (http://localhost:8787)
cd packages/api && npx wrangler dev

# Run web site locally (http://localhost:4321)
pnpm --filter @mycal/web dev

# Validate data
pnpm validate

# Run tests
pnpm test

API Examples

Base URL: https://mycal-api.huijun00100101.workers.dev/v1

List holidays
# All holidays for Selangor in 2026
curl "https://mycal-api.huijun00100101.workers.dev/v1/holidays?year=2026&state=selangor"

# Islamic holidays only
curl "https://mycal-api.huijun00100101.workers.dev/v1/holidays?year=2026&type=islamic"

# March holidays for KL
curl "https://mycal-api.huijun00100101.workers.dev/v1/holidays?year=2026&state=KL&month=3"
Check a date
# Is March 21 a holiday/weekend/working day?
curl "https://mycal-api.huijun00100101.workers.dev/v1/holidays/check?date=2026-03-21&state=KL"

Response:

{
  "data": {
    "date": "2026-03-21",
    "dayOfWeek": "Saturday",
    "isHoliday": true,
    "isWeekend": true,
    "isWorkingDay": false,
    "isSchoolDay": false,
    "holidays": [
      {
        "id": "2026-hari-raya-aidilfitri-1",
        "name": { "ms": "Hari Raya Aidilfitri", "en": "Eid al-Fitr", "zh": "开斋节" },
        "type": "islamic",
        "status": "confirmed"
      }
    ]
  }
}
Business days
# Count working days in March for Selangor
curl "https://mycal-api.huijun00100101.workers.dev/v1/business-days?start=2026-03-01&end=2026-03-31&state=selangor"

# Add 10 business days to a date
curl "https://mycal-api.huijun00100101.workers.dev/v1/business-days/add?date=2026-03-01&days=10&state=selangor"
School calendar
# Is this a school day?
curl "https://mycal-api.huijun00100101.workers.dev/v1/school/is-school-day?date=2026-03-21&state=selangor"

# School holidays for Kumpulan B
curl "https://mycal-api.huijun00100101.workers.dev/v1/school/holidays?year=2026&group=B"

# Exam schedule
curl "https://mycal-api.huijun00100101.workers.dev/v1/school/exams?year=2026&type=spm"
Next holiday
# Next holiday for Penang
curl "https://mycal-api.huijun00100101.workers.dev/v1/holidays/next?state=penang"
State resolution
# Resolve alias
curl "https://mycal-api.huijun00100101.workers.dev/v1/states/resolve?q=kl"
# -> { "data": { "canonical": "kuala-lumpur", "group": "B" } }

Full API Reference

EndpointDescription
GET /v1/holidaysList holidays (filter by year, state, type, status, month)
GET /v1/holidays/checkIs this date a holiday/weekend/working day/school day?
GET /v1/holidays/todayToday's holiday status
GET /v1/holidays/nextNext upcoming holiday
GET /v1/holidays/betweenHolidays in date range
GET /v1/holidays/leave-optimizerSuggest annual-leave days to spend for the longest consecutive break
GET /v1/business-daysCount business days between dates
GET /v1/business-days/addAdd N business days to a date
GET /v1/statesAll 13 states + 3 FTs with weekend config
GET /v1/states/resolveResolve alias (KL, penang, jb) to canonical code
GET /v1/school/termsSchool term dates + day counts
GET /v1/school/holidaysSchool holidays + KPM cuti perayaan
GET /v1/school/examsSPM, STPM, MUET, PT3 schedule
GET /v1/school/is-school-dayIs this a school day?
GET /v1/feed/ical/:stateiCal subscription feed
GET /v1/feed/csv/:stateCSV/spreadsheet export of holidays
GET /v1/data/*Raw, cacheable open-data snapshots — manifest, states, holidays/:year, all (no API key required)
GET /v1/prayer-times/:zoneJAKIM prayer times for a zone (MYT-formatted); GET /v1/prayer-times/zones lists the zone directory
POST /v1/keysIssue an API key (admin-gated for now; GET /v1/keys/whoami checks the caller's tier)

See the full OpenAPI 3.1 spec for request/response schemas.

SDK Usage

import { MyCalClient } from "@catlabtech/mycal-sdk";

const cal = new MyCalClient();

// Check if a date is a working day
const result = await cal.check("2026-03-21", "selangor");
console.log(result.isWorkingDay); // false

// List holidays
const holidays = await cal.holidays({ year: 2026, state: "KL" });

// Business days
const workDays = await cal.businessDays("2026-03-01", "2026-03-31", "selangor");
console.log(workDays.businessDays); // 22

// School calendar
const terms = await cal.school.terms({ year: 2026, group: "B" });
const exams = await cal.school.exams({ year: 2026, type: "spm" });
const isSchool = await cal.school.isSchoolDay("2026-03-21", "selangor");

MCP Server

Connect the Malaysia Calendar API to Claude, ChatGPT, or any MCP-compatible AI assistant.

Setup with Claude Desktop / Claude Code

Add to your MCP configuration:

{
  "mcpServers": {
    "malaysia-calendar": {
      "command": "npx",
      "args": ["@catlabtech/mycal-mcp-server"]
    }
  }
}
Available Tools (13)
ToolDescription
get_malaysia_holidaysGet public holidays (filter by year, state, type)
check_malaysia_holidayCheck if a date is a holiday or working day
next_malaysia_holidayFind the next upcoming holiday
malaysia_business_daysCount working days between two dates
malaysia_long_weekendsFind long weekends (3+ days)
malaysia_leave_optimizerFind the most efficient leave days to take to maximise consecutive days off
list_malaysia_statesList all states with weekend config
resolve_malaysia_stateResolve alias (KL, JB) to canonical code
malaysia_holiday_changesRecent data changes
malaysia_school_termsSchool term dates and day counts
malaysia_school_holidaysSchool holidays (cuti penggal, cuti perayaan)
malaysia_examsSPM, STPM, MUET, PT3 exam schedule
malaysia_is_school_dayCheck if a date is a school day

State Codes

CodeAliasesGroupWeekend
johorjhr, jbBSat-Sun (was Fri-Sat 2014-2024)
kedahkd, kdhAFri-Sat
kelantankel, kbAFri-Sat
terengganutrg, ktAFri-Sat
perakprk, ipohBSat-Sun
pulau-pinangpenang, pgBSat-Sun
selangorsel, sgrBSat-Sun
negeri-sembilanns, n9BSat-Sun
melakamlk, malaccaBSat-Sun
pahangphg, kuantanBSat-Sun
perlispls, kangarBSat-Sun
sabahsbh, kkBSat-Sun
sarawakswk, kuchingBSat-Sun
kuala-lumpurklBSat-Sun
wp-putrajayaputrajaya, pjyBSat-Sun
wp-labuanlabuan, lbnBSat-Sun

State aliases are case-insensitive. Use GET /v1/states/resolve?q=kl to resolve any alias to the canonical code.

Project Structure

malaysia-calendar-api/
├── data/                        # JSON data files (source of truth / 数据源)
│   ├── holidays/
│   │   ├── 2024.json            # Holiday data per year
│   │   ├── 2025.json
│   │   └── 2026.json
│   ├── school/
│   │   ├── terms-2026.json      # School terms (Kumpulan A + B)
│   │   ├── holidays-2026.json   # School holidays + KPM cuti perayaan
│   │   └── exams-2026.json      # SPM, STPM, MUET, PT3 schedules
│   ├── states.json              # 13 states + 3 FT, aliases, weekend history
│   └── known-fixed-holidays.json
├── packages/
│   ├── core/                    # Shared business logic (types, schemas, utils)
│   │   └── src/
│   │       ├── types.ts         # Holiday, State, SchoolTerm, Exam interfaces
│   │       ├── schemas.ts       # Zod validation schemas
│   │       ├── filter.ts        # Query filtering logic
│   │       ├── replacement.ts   # Cuti ganti calculation
│   │       ├── state-resolver.ts
│   │       ├── business-days.ts
│   │       └── school.ts        # School term/holiday/exam logic
│   ├── api/                     # Hono API on Cloudflare Workers
│   ├── mcp-server/              # MCP Server (13 tools)
│   ├── sdk/                     # TypeScript client SDK (@catlabtech/mycal-sdk)
│   └── web/                     # Astro + Starlight — marketing site, demos, docs
├── scripts/
│   ├── validate-data.ts         # 5-layer data validation pipeline
│   └── sync-to-kv.ts           # JSON -> Cloudflare KV denormalization
├── openapi.yaml                 # OpenAPI 3.1 spec (spec-first)
├── pnpm-workspace.yaml
└── turbo.json

Data Sources

All data is sourced from official Malaysian government publications:

SourceDataURL
JPM BKPPFederal Gazette / Warta Kerajaan (public holidays)kabinet.gov.my
JAKIMTakwim Hijri-Miladi (Islamic calendar)e-solat.gov.my
KPMKalendar Akademik / school calendar (Lampiran A/B/C)moe.gov.my
MPMSTPM & MUET exam schedulesmpm.edu.my
State PortalsState-specific holidays (13 states)*.gov.my

Holiday data includes gazette references (e.g., P.U.(B) 305/2025) for traceability.

Deploy

Two parts deploy independently:

API → Cloudflare Workers
pnpm --filter @catlabtech/mycal-core build
cd packages/api && npx wrangler deploy
Website → Cloudflare Pages
pnpm --filter @catlabtech/mycal-core build
pnpm --filter @catlabtech/mycal-sdk build
pnpm --filter @mycal/web build

# Direct upload via wrangler (requires CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID)
cd packages/web
npx wrangler pages deploy dist --project-name=mycal-web

First-time Pages setup:

  1. Create a Pages project named mycal-web in the Cloudflare dashboard.
  2. Either connect the GitHub repo for automatic builds, or rely on the GitHub Actions workflow (.github/workflows/deploy.yml) to push via wrangler pages deploy.
  3. Required GitHub secrets: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID.
CI/CD

GitHub Actions handles:

  1. PR gate — Zod schema validation + cross-source checks on every PR
  2. Deploy — On merge to main: build and deploy API to Workers + Web to Pages in parallel
  3. Daily scrape — Government portal monitoring for updates
  4. Rukyah monitor — Islamic date confirmation tracking

Contributing

See CONTRIBUTING.md for how to:

  • Report a missing holiday or cuti peristiwa
  • Fix data errors
  • Add new features

License

MIT

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.