Skip to main content

MorgenMCP

An unofficial MCP server for the Morgen calendar API.

Requirements

  • uv - Install with curl -LsSf https://astral.sh/uv/install.sh | sh, brew install uv, or winget install astral-sh.uv
  • mise (optional) - Install with curl https://mise.run | sh, brew install mise, or winget install jdx.mise. Convenient for local development: it puts the right Python on PATH in a plain shell and fails fast with setup instructions when MORGEN_API_KEY is unset. Everything works with uv alone — see Environment Setup.
  • A Morgen API key - Get one from Morgen Developer Portal
  • Python 3.12 or newer — Only needed when working from a clone (uv and mise provision this automatically from .python-version). End users running via uvx require no setup.

Installation

No installation required — MCP clients run the server directly via uvx (published on PyPI).

Most clients use the same mcpServers JSON shape. Add this entry to your client's MCP configuration:

{
  "mcpServers": {
    "morgen": {
      "command": "uvx",
      "args": ["morgenmcp"],
      "env": {
        "MORGEN_API_KEY": "your_api_key_here"
      }
    }
  }
}

The server speaks stdio, so no port or URL is involved. If your client asks for a command rather than JSON, it is uvx morgenmcp with MORGEN_API_KEY in the environment. If it cannot find uvx, see Troubleshooting.

To pin to a specific version, pass the version in args (e.g. ["morgenmcp==0.2.1"]). You can also run unreleased commits directly from GitHub: ["--from", "git+https://github.com/k3KAW8Pnf7mkmdSMPHz27/MorgenMCP@main", "morgenmcp"].

Claude Desktop

The config file lives at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or %APPDATA%\Claude\claude_desktop_config.json on Windows. Paste the block above, then restart Claude Desktop.

Available Tools

Tools across accounts, calendars, events, tasks, and tags — read-only and mutating:

  • Accounts & calendars: list_accounts, list_calendars, update_calendar_metadata
  • Events: list_events, create_event, update_event, delete_event, batch_update_events, batch_delete_events
  • Tasks: list_tasks, list_task_lists, get_task, create_task, update_task, move_task, complete_task, reopen_task, delete_task, batch_delete_tasks
  • Tags: list_tags, get_tag, create_tag, update_tag, delete_tag

Pass --read-only (or set MORGENMCP_READ_ONLY=1) to expose only the read-only tools. For the exact live list with schemas and annotations, connect any MCP client or run the MCP Inspector.

Configuration

MORGEN_API_KEY is required; everything else is optional. Each setting has an equivalent CLI flag, and the flag wins over the environment variable.

Environment variable CLI flag Default Description
MORGEN_API_KEY — (required) Morgen API key. The server refuses to start without it.
MORGENMCP_READ_ONLY --read-only off Truthy (1/true/yes/on) exposes only the read tools, disabling every mutating one.
MORGENMCP_TASKS_LIMIT --tasks-limit N 100 Default limit sent to /tasks/list. Integer 1–100.
MORGENMCP_TAGS_LIMIT --tags-limit N (unset) Default limit sent to /tags/list. Integer ≥ 1, no upper bound. Unset returns all tags.
MORGENMCP_DISPLAY_TZ — system local IANA timezone (e.g. America/Chicago) for rendering compact event times.
MORGENMCP_DATA_DIR — platform data dir Override the virtual-ID persistence directory.

An invalid limit fails at startup with a clear error rather than silently returning fewer results:

$ uv run morgenmcp --tasks-limit 500
morgenmcp: error: --tasks-limit must be <= 100 (got 500)

The two list limits are deliberately asymmetric, because Morgen documents the two endpoints differently: /tasks/list documents a default of 1 and a maximum of 100, while /tags/list documents neither and returns all tags when the parameter is omitted. A per-call limit argument on the tool always overrides both the flag and the environment variable.

Note: MORGENMCP_TASKS_LIMIT defaults to 100, which is MorgenMCP's own choice rather than Morgen's. /tasks/list returns a single task when limit is omitted — its documented default is 1, and the API docs tell callers to always set the parameter explicitly, so the server never leaves it to Morgen. This is only a fallback: the tool asks the model to pass a limit suited to the request, and a per-call value always wins. Set this variable to bound what a model can pull in one call, not to express a typical page size.

Troubleshooting

MORGEN_API_KEY is not set — the key goes in the env block of your MCP client's server entry, not in a shell profile: the client launches the server itself and does not inherit your terminal's environment. Get a key from the Morgen Developer Portal.

uvx: command not found, or the server never starts — desktop clients are launched by the OS, not by your shell, so they see a minimal PATH that usually excludes ~/.local/bin, /opt/homebrew/bin, and version-manager shims. Use an absolute path instead:

which uvx   # e.g. /opt/homebrew/bin/uvx
"command": "/opt/homebrew/bin/uvx"

Nothing appears in the client — check the client's MCP log. Both failures above surface there and nowhere else, because a stdio server's stderr goes to the client, not to a terminal.

Development

# Clone the repository
git clone https://github.com/k3KAW8Pnf7mkmdSMPHz27/MorgenMCP.git
cd MorgenMCP

# Install dependencies
uv sync --all-extras

# Run tests
uv run pytest

Environment Setup

The server reads MORGEN_API_KEY from the process environment — it does not load a .env file itself. Either of the following supplies it. Both keep the key in a gitignored file; neither is required if the variable is already exported in your shell.

With uv alone. Put the key in a .env file (already gitignored) and let uv load it:

echo 'MORGEN_API_KEY=your_api_key' > .env
UV_ENV_FILE=.env uv run morgenmcp

Export UV_ENV_FILE=.env in your shell profile to skip the prefix. uv run --env-file .env <cmd> works the same way for one-off commands.

If uv is itself installed through mise (a shim under ~/.local/share/mise/shims/uv), every uv call routes through mise, and mise refuses to run against this repo's untrusted mise.toml — so uv run fails until you mise trust. That is a property of that install, not of this project; a standalone uv (brew install uv) is unaffected.

With mise (optional, recommended if you already use it). This repo ships a mise.toml declaring MORGEN_API_KEY as required, so a missing key fails immediately with setup instructions instead of surfacing on the first tool call. mise set writes to a gitignored mise.local.toml, never the committed config:

mise trust
mise set --file mise.local.toml MORGEN_API_KEY=your_api_key
uv run morgenmcp

mise also puts the interpreter from .python-version on PATH in a plain shell, so a bare python3 in a clone is the right one — useful because the source requires Python 3.12 or newer (see Requirements).

Local Debugging with MCP Inspector

The MCP Inspector provides a web UI for testing tools and inspecting requests/responses:

npx @modelcontextprotocol/inspector uv run morgenmcp

Opens at http://localhost:6274

Releasing

Releases are managed via git tags:

git tag -a v0.2.1 -m "Release v0.2.1"
git push origin v0.2.1

Pushing a tag triggers the GitHub Actions release workflow, which runs tests, builds wheel and sdist distributions, creates a GitHub Release, and publishes to PyPI automatically.

Contributing

See AGENTS.md for environment setup, conventions, and the checks to run before handing off changes.

AI-assisted contributions are welcome and must be disclosed — see AI_POLICY.md, adapted from the Ghostty project's AI policy (MIT).

License

Apache 2.0 - See LICENSE and NOTICE for details.

Metadata

Release files for morgenmcp 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for morgenmcp 0.2.1
File Size Uploaded Provenance
morgenmcp-0.2.1.tar.gz 170.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for morgenmcp 0.2.1
File Interpreter ABI Platform
morgenmcp-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 227.5 kB

Release files / morgenmcp-0.2.1.tar.gz

Download URL morgenmcp-0.2.1.tar.gz
Size 170.6 kB
Tags Source
SHA-256 checksum
How to use checksums
f66419194481c2b0872655d7304048fdf9ea10442ade688cc442068f47cab282
BLAKE2b-256 checksum
How to use checksums
2395b28f1b03b33e83b68bb40f48e327ae68a4b35d10dc540568f4d6c79685ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / morgenmcp-0.2.1-py3-none-any.whl

Download URL morgenmcp-0.2.1-py3-none-any.whl
Size 56.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d2820cd61b8613daaa553dfbda13cae9e6809068283668200918c81acf926357
BLAKE2b-256 checksum
How to use checksums
de93c236a851f6f3530df1156cafe1a90c71afdc0c7588cb6893dcdbb6af9691
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for morgenmcp 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page