MorgenMCP
An unofficial MCP server for the Morgen calendar API.
Installation
Run MorgenMCP locally from PyPI, without cloning this repository.
- Install uv:
brew install uvon macOS, orwinget install astral-sh.uvon Windows. For Linux and other installation methods, follow the uv link. - Get an API key from the Morgen Developer Portal.
- Choose your client below. uv manages the required Python version (3.12 or newer).
| Client | Setup |
|---|---|
| Claude Desktop | Extension bundle or configuration file |
| Claude Code | CLI command |
| Cursor | Install button and configuration |
| VS Code | Install button and configuration |
| Other MCP clients | Generic stdio configuration |
The server uses stdio: your client starts uvx morgenmcp; no server URL or
port is needed. If it cannot find uvx, use its absolute path as described in
Troubleshooting.
Claude Desktop
You can install MorgenMCP as a desktop extension bundle or configure it manually.
Desktop extension (.mcpb)
- Download the
morgenmcp-X.Y.Z.mcpbbundle from the latest GitHub Release. - Verify the download against its signed Sigstore provenance.
- Open the
.mcpbfile in Claude Desktop. - Enter your API key when prompted in the extension settings (and optionally enable Read-only mode).
Claude displays an installation warning that developer info has not been verified by Anthropic; this is expected for community extensions. Then verify the connection.
Manual configuration
Open Settings → Developer → Edit Config. The file is
~/Library/Application Support/Claude/claude_desktop_config.json on macOS,
or %APPDATA%\Claude\claude_desktop_config.json on Windows.
Merge the generic configuration into the file, replace
your_api_key_here with your key, and restart Claude Desktop. Preserve any
other servers already configured. Then verify the connection.
Claude Code
Replace the placeholder and run this command in your terminal:
claude mcp add --scope user --env MORGEN_API_KEY=your_api_key_here --transport stdio morgen -- uvx morgenmcp
This adds MorgenMCP to your personal configuration across projects. The key is
stored in that configuration; entering it literally can also leave it in shell
history. Use your shell's private-input mechanism if needed. In Claude Code,
run /mcp to check the server status, then
verify the connection.
See the Claude Code MCP guide for scopes and environment-variable configuration.
Cursor
The button opens Cursor with a proposed local server configuration. Replace
your_api_key_here in the server's env configuration with your Morgen key
before using it. The button contains only a placeholder; never put a real key
in a shared install link.
For manual setup, open Cursor Settings → Tools & MCP, or edit your personal
~/.cursor/mcp.json. Merge the generic configuration,
replace the key placeholder, and enable the server. Keep credentials in your
personal configuration rather than a committed project file. Then
verify the connection.
See Cursor's MCP documentation and install-link format.
VS Code
The button opens VS Code's installation flow with a password input for your Morgen API key. Review the configuration and install it in your user profile. If the browser does not open the app, use the manual setup below.
Run MCP: Open User Configuration from the Command Palette and merge this configuration, preserving any existing servers and inputs:
{
"inputs": [
{
"type": "promptString",
"id": "morgen-api-key",
"description": "Morgen API key",
"password": true
}
],
"servers": {
"morgen": {
"type": "stdio",
"command": "uvx",
"args": [
"morgenmcp"
],
"env": {
"MORGEN_API_KEY": "${input:morgen-api-key}"
}
}
}
}
Start morgen from the MCP configuration editor and enter your key when
prompted. Then verify the connection.
These input prompts are supported in VS Code's Local harness; servers requiring interactive inputs are not forwarded to Copilot harness sessions. See the VS Code configuration reference for supported credential options in your session.
Other MCP clients
Merge this into your client's MCP configuration and replace the key placeholder:
{
"mcpServers": {
"morgen": {
"command": "uvx",
"args": [
"morgenmcp"
],
"env": {
"MORGEN_API_KEY": "your_api_key_here"
}
}
}
}
If your client asks for separate fields, use command uvx, arguments
morgenmcp, and environment variable MORGEN_API_KEY. Follow your client's
configuration format; not every client uses the mcpServers wrapper.
Verify the connection
Ask your assistant: “List my Morgen calendars.” Check that it invokes
list_accounts and/or list_calendars and returns your calendars. You can
also try “What is on my Morgen calendar today?”
If startup fails or the tools do not appear, see Troubleshooting.
Read-only mode and version pinning
To expose only read tools, change args to
["morgenmcp", "--read-only"]. For the Claude Code command, append
--read-only after uvx morgenmcp.
To pin a release, use ["morgenmcp==0.2.1"] (replace the version with your
chosen release). To run an unreleased commit, use
["--from", "git+https://github.com/k3KAW8Pnf7mkmdSMPHz27/MorgenMCP@main", "morgenmcp"].
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.
Compact event lines
list_events with compact=true (and every event resource)
returns one line per event instead of a JSON object, to save tokens:
Jul 23 08:00-11:00 CDT (America/Chicago): Deep work block [oAxAjaC task]
Jul 23 05:00-06:00 CDT (America/Chicago): Morning walk [c0HsnEl routine]
Jul 23 11:00-14:00 CDT (America/Chicago): Contractor visit [suqNbDi free]
Jul 23 14:00-14:30 CDT (America/Chicago): Dentist [l1_gFD6]
The optional kind tag, inside the ID brackets, tells a client what it is looking at:
| tag | meaning |
|---|---|
task |
Linked to a Morgen task — a flexible intention, usually movable. |
routine |
A Morgen Routine occurrence: a recurring block you check off. |
flexible |
Morgen auto-scheduled this block, so it can be moved. |
free |
Does not mark you busy — informational, not an obligation. |
| (no tag) | An ordinary busy commitment. |
task, routine and flexible are mutually exclusive; free combines with
any of them as a comma-joined pair with no space, e.g. [oAxAjaC task,free].
Event titles may themselves contain {} or [], so match the trailing
[<id>( <tag>)?] anchored at the end of the line. The tag sits inside the
brackets precisely so a title cannot spoof it.
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_LIMITdefaults to100, which is MorgenMCP's own choice rather than Morgen's./tasks/listreturns a single task whenlimitis 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 alimitsuited 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 — provide the key through your client's setup
above: the env block, VS Code password prompt, or Claude Code configuration.
Desktop clients may 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
Use Python 3.12 or newer. uv provisions the version pinned in
.python-version for this checkout. mise is optional;
see Environment Setup if you already use it.
# 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
uvis itself installed through mise (a shim under~/.local/share/mise/shims/uv), everyuvcall routes through mise, and mise refuses to run against this repo's untrustedmise.toml— souv runfails until youmise trust. That is a property of that install, not of this project; a standaloneuv(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 Development).
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
After main-branch CI (including desktop bundle checks) passes, Conventional
Commits determine the next release: feat: bumps minor and fix: bumps patch.
Breaking changes (! or BREAKING CHANGE:) bump minor below 1.0 and major
thereafter; start 1.0 with a deliberate manual release. Other commits do not
release. Use these prefixes on PR titles when squash merging.
The automation creates an annotated tag and dispatches release.yml using
GITHUB_TOKEN. Manual stable tag pushes also work. If dispatch or publication
fails after tagging, retry with gh workflow run release.yml --ref vX.Y.Z
instead of creating another version.
Stable vX.Y.Z tags trigger the GitHub Actions release workflow, which runs
tests, builds wheel and sdist distributions and a desktop bundle, and requires
verified Sigstore provenance for every release artifact before publishing to
PyPI and GitHub Releases. The workflow uses the existing pypi environment
and PyPI trusted publishing. Verified files are retained as an Actions artifact
for 30 days if publication needs recovery.
Verify a release download
Release assets include provenance.sigstore.json and SHA256SUMS. With a recent
GitHub CLI, replace vX.Y.Z below with your release:
REPO=k3KAW8Pnf7mkmdSMPHz27/MorgenMCP
TAG=vX.Y.Z
COMMIT="$(gh api "repos/$REPO/commits/$TAG" --jq .sha)"
gh release download "$TAG" --repo "$REPO" --dir release-download \
--pattern '*.mcpb' --pattern provenance.sigstore.json
gh attestation verify "release-download/morgenmcp-${TAG#v}.mcpb" \
--bundle release-download/provenance.sigstore.json \
--repo "$REPO" --signer-workflow "$REPO/.github/workflows/release.yml" \
--source-ref "refs/tags/$TAG" --source-digest "$COMMIT" \
--cert-oidc-issuer https://token.actions.githubusercontent.com \
--predicate-type https://slsa.dev/provenance/v1 --deny-self-hosted-runners
Proceed only if verification succeeds. Use a separately reviewed commit SHA
for COMMIT if you want to pin it independently of the current GitHub tag.
The same command can verify a downloaded wheel, source archive, or checksums file.
Sigstore verifies build provenance; it does not confer Anthropic-verified
publisher status in Claude Desktop. The manual provenance-trial.yml workflow
exercises signing, verification, and tamper rejection without publishing a release.
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
Metadata
Release files for morgenmcp 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| morgenmcp-0.4.0.tar.gz | 191.8 kB | Without provenance | Details for morgenmcp-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| morgenmcp-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for morgenmcp-0.4.0-py3-none-any.whl |
Total release size: 254.1 kB
Release files / morgenmcp-0.4.0.tar.gz
| Download URL | morgenmcp-0.4.0.tar.gz |
|---|---|
| Size | 191.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
266745f3baf1d825cfc4c3e1e38c1ab7e5308d4197eb70ed2c3e742f90b05adf
|
|
BLAKE2b-256 checksum How to use checksums |
31c45effed771004a089df832bbbd15a20a87bff9c4eb71e0e27b42a05155abc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","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.4.0-py3-none-any.whl
| Download URL | morgenmcp-0.4.0-py3-none-any.whl |
|---|---|
| Size | 62.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
642082cdf9ca89122ebae8aaa8ede83d0b73e1f09a132f64cda71a8305608bdd
|
|
BLAKE2b-256 checksum How to use checksums |
f36fe2f6d0d0f229d8b78ba4917d4e4a5a24e8cfda8de872e5cbc0572b1546c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","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.4.0
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.