# TimeEdit MCP Server

MCP server for TimeEdit `.ics` schedules.

The server accepts a TimeEdit ICS link at startup, downloads/parses events, and caches results for up to 24 hours.

Useful for connecting MCP clients (like Claude) to TimeEdit schedules, enabling you to ask for info regarding exam halls, lecture dates, etc. without manual calendar browsing.

## Get your .ics link

![How to find the TimeEdit .ics link](assets/image.png)

1. Go to your institution's TimeEdit page and find the calendar you want to query.
2. Look for the "Subscribe" option (see image).
3. Copy the provided `.ics` URL (it should end with `.ics`)

**Note:** This is the URL you will provide as an argument at startup.

## Quick start (PyPI)

Install `uv` first: https://docs.astral.sh/uv/getting-started/installation/

Add this to `claude_desktop_config.json` (no source checkout needed):

```json
{
  "mcpServers": {
    "timeedit-mcp": {
      "command": "uvx",
      "args": ["timeedit-mcp"],
      "env": {
        "TIMEEDIT_ICS_URL": "https://...your-timeedit-link....ics",
        "TIMEEDIT_OUTPUT_TIMEZONE": "Europe/Stockholm"
      }
    }
  }
}
```

## Development (from source)

```bash
git clone git@github.com:ekvanox/timeedit-mcp.git
cd timeedit-mcp
uv sync
uv run main.py --ics-url "https://...your-timeedit-link....ics"

# Alternative with env vars
# TIMEEDIT_ICS_URL="https://...your-timeedit-link....ics" TIMEEDIT_OUTPUT_TIMEZONE="Europe/Stockholm" uv run main.py
```

## Docker

The container uses `uv` for dependency installation and startup.
Docker uses an HTTP entrypoint on port `8888`.

```bash
docker build -t timeedit-mcp .
docker run -d --name timeedit-mcp --restart unless-stopped \
  -p 8888:8888 \
  -e TIMEEDIT_ICS_URL="https://...your-timeedit-link....ics" \
  -e TIMEEDIT_OUTPUT_TIMEZONE="Europe/Stockholm" \
  timeedit-mcp
```

## Connect to Claude Desktop (MCP server)

1. Open `~/Library/Application Support/Claude/claude_desktop_config.json`
2. Add this server entry:

```json
{
  "mcpServers": {
    "timeedit-mcp": {
      "command": "uv",
      "args": ["run", "/PATH/TO/PROJECT/timeedit-mcp/main.py"],
      "env": {
        "TIMEEDIT_ICS_URL": "https://...your-timeedit-link....ics",
        "TIMEEDIT_OUTPUT_TIMEZONE": "Europe/Stockholm"
      }
    }
  }
}
```

3. Restart Claude Desktop.

## Claude skill

This repo includes a ready-to-use skill file at `SKILL.md`.

### Easiest way to add it to Claude

1. Create a skill folder named `timeedit-mcp` under your Claude skills directory.
2. Copy this repo's `SKILL.md` into that folder as `SKILL.md`.
3. Restart Claude (or reload customizations) so it picks up the new skill.

Typical location on macOS:
- `~/.claude/skills/timeedit-mcp/SKILL.md`

## Available MCP tools

### Response format

All tools return [TOON data](https://github.com/toon-format/toon) (token efficient JSON alternative).



### Tool reference

| Endpoint | Input | Output |
|---|---|---|
| `list_programs` | <ul><li>include_program_id (optional)</li></ul> | <ul><li>name</li><li>event_count</li><li>course_count</li><li>id (optional)</li></ul> |
| `list_courses_for_program` | <ul><li>program_query (name substring or exact id)</li><li>limit (optional)</li></ul> | <ul><li>course</li><li>codes</li><li>programs</li><li>event_count</li></ul> |
| `search_courses_fuzzy` | <ul><li>query (free-text)</li><li>limit (optional)</li></ul> | <ul><li>score</li><li>course</li><li>codes</li><li>programs</li><li>event_count</li></ul> |
| `list_events_for_course` | <ul><li>course_query</li><li>start_date / end_date (optional, YYYY-MM-DD)</li><li>group_query (optional)</li><li>limit (optional)</li><li>include_uid (optional)</li><li>include_program_id (optional)</li></ul> | <ul><li>start / end (configured timezone)</li><li>location</li><li>url</li><li>course_code</li><li>course_codes</li><li>groups</li><li>course_names</li><li>event_type</li><li>programs</li><li>summary</li><li>uid (optional)</li></ul> |
| `list_events_for_program` | <ul><li>program_query (name or id)</li><li>start_date / end_date (optional, YYYY-MM-DD)</li><li>group_query (optional)</li><li>limit (optional)</li><li>include_uid (optional)</li><li>include_program_id (optional)</li></ul> | <ul><li>start / end (configured timezone)</li><li>location</li><li>url</li><li>course_code</li><li>course_codes</li><li>groups</li><li>course_names</li><li>event_type</li><li>programs</li><li>summary</li><li>uid (optional)</li></ul> |
| `list_events_filtered` | <ul><li>at least one of: text_query, location_query, course_query, program_query, group_query</li><li>start_date / end_date (optional, YYYY-MM-DD)</li><li>limit (optional)</li><li>include_uid (optional)</li><li>include_program_id (optional)</li></ul> | <ul><li>start / end (configured timezone)</li><li>location</li><li>url</li><li>course_code</li><li>course_codes</li><li>groups</li><li>course_names</li><li>event_type</li><li>programs</li><li>summary</li><li>uid (optional)</li></ul> |

## Notes

- Cache is stored under `~/.cache/timeedit-mcp/`.
- Cache TTL is max 24 hours.
- Event times default to the server system timezone. Override with `--output-timezone IANA_NAME` (e.g. `--output-timezone Europe/Stockholm`) or set the `TIMEEDIT_OUTPUT_TIMEZONE` environment variable at server startup.

## License

MIT. See [LICENSE](LICENSE).
