intervals-icu-mcp

module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2026 License: MIT

README

intervals-icu-mcp

A Model Context Protocol (MCP) server for Intervals.icu, built in Go. Supports stdio (default) and streamable HTTP transport modes.

Requirements

  • Go 1.25 or later
  • golangci-lint (for linting)
  • A GitHub OAuth App (required for streamable transport authentication)

Configuration

Set the following environment variables before running the server:

Variable Required Description
INTERVALS_API_KEY Yes Your Intervals.icu API key (used for Basic auth)
INTERVALS_ATHLETE_ID Yes Your Intervals.icu athlete ID (e.g., i12345)
GITHUB_CLIENT_SECRET No GitHub OAuth app client secret (fallback when --github-client-secret flag is empty)
JWT_SECRET No HMAC-SHA256 signing key for JWT tokens (fallback when --jwt-secret flag is empty)

Usage

Run the MCP server (stdio transport, default):

go run ./src/...

Run with streamable HTTP transport (requires OAuth flags):

go run ./src/... --transport streamable --address 127.0.0.1:8080 \
  --github-client-id <your-github-client-id> \
  --github-client-secret <your-github-client-secret> \
  --auth-issuer http://localhost:8080 \
  --allowed-users your-github-username

The MCP endpoint is served at /mcp (not configurable). When using the streamable transport, the endpoint is served behind a middleware stack that provides:

  • Panic recovery (returns 500 on unhandled panics)
  • Request ID propagation (X-Request-ID header)
  • Structured request logging
  • Per-IP rate limiting (100 requests/second, burst 200, sliding window)
  • Max request body size (1 MB)
  • CORS (configurable origins via --allowed-origins as full URLs, GET/POST/DELETE/OPTIONS methods)
  • Expose-Headers (Access-Control-Expose-Headers: Mcp-Session-Id for CORS responses)
  • Gzip compression
Flag Default Description
--transport stdio Transport type: stdio or streamable
--address 127.0.0.1:8080 Listen address for streamable HTTP transport (e.g., 127.0.0.1:8080 or :9000)
--allowed-origins (empty) Comma-separated list of allowed CORS origins as full URLs (e.g., http://localhost:3000,https://example.com)
--github-client-id (empty) GitHub OAuth app client ID (required for streamable)
--github-client-secret (empty) GitHub OAuth app client secret (required for streamable; falls back to GITHUB_CLIENT_SECRET env var)
--allowed-users (empty) Comma-separated allowed GitHub usernames (empty = allow all authenticated users)
--jwt-secret (empty) HMAC-SHA256 signing key for JWT tokens (auto-generated if empty; falls back to JWT_SECRET env var)
--auth-issuer (empty) Issuer URL for the OAuth authorization server (required for streamable). Must be a full URL with http/https scheme
Authentication (streamable transport)

OAuth 2.1 authentication is mandatory for the streamable HTTP transport. The server acts as both an OAuth Authorization Server (proxying to GitHub for identity) and a Resource Server (validating JWTs on /mcp). Stdio transport does not use authentication.

Create a GitHub OAuth App at GitHub Settings > Developer settings > OAuth Apps, with the callback URL set to <your-issuer-url>/oauth/callback.

OAuth endpoints exposed in streamable mode:

Endpoint Method Description
/.well-known/oauth-protected-resource GET Protected resource metadata (RFC 9728)
/.well-known/oauth-authorization-server GET Authorization server metadata (RFC 8414)
/oauth/authorize GET Start OAuth authorization flow (redirects to GitHub)
/oauth/callback GET GitHub OAuth callback
/oauth/token POST Token exchange (authorization_code and refresh_token grants)
/oauth/register POST Dynamic client registration (RFC 7591, rate-limited to 2 req/s burst 5)

Print version:

go run ./src/... -version
go run ./src/... -v

Build with version injection:

go build -ldflags "-X github.com/0xalexb/hjarta-di.Version=1.0.0 -X github.com/0xalexb/hjarta-di.DIVersion=0.5.0 -X github.com/0xalexb/hjarta-di.CompiledAt=$(date -u +%Y-%m-%dT%H:%M:%SZ)" -o intervals-icu-mcp ./src/

MCP Tools

Tool Description Arguments
version Returns application build information including version, DI version, and compilation time. None
get_athlete_profile Returns the athlete profile from Intervals.icu. None
get_activities Lists activities in a date range. oldest (required), newest (optional)
get_activity_details Returns details for a specific activity. activity_id (required)
get_events Lists events in a date range. oldest (required), newest (required)
create_event Creates a new event. name, start_date_local, category (required); type, description, moving_time, distance, training_load (optional)
update_event Updates an existing event. event_id (required); name, description, start_date_local, category, type, moving_time, distance, training_load (optional)
delete_event Deletes an event by ID. event_id (required)
get_power_curve Returns power curve data by activity type. type (required), newest (optional)
get_wellness Returns wellness data for a specific date. date (required)
get_wellness_trend Returns wellness data over a date range. oldest (required), newest (required)

Docker

Pull the latest image:

docker pull ghcr.io/0xalexb/intervals-icu-mcp:latest

Run in streamable mode (default CMD):

docker run --rm -p 8080:8080 \
  -e INTERVALS_API_KEY=... \
  -e INTERVALS_ATHLETE_ID=... \
  -e GITHUB_CLIENT_SECRET=... \
  -e JWT_SECRET=... \
  ghcr.io/0xalexb/intervals-icu-mcp:latest \
  --github-client-id <id> \
  --auth-issuer https://mcp.example.com

Run in stdio mode (for MCP clients that manage the process):

docker run -i --rm \
  -e INTERVALS_API_KEY=... \
  -e INTERVALS_ATHLETE_ID=... \
  ghcr.io/0xalexb/intervals-icu-mcp:latest \
  --transport stdio

Available tags: X.Y.Z (exact), X.Y (minor track), latest.

Development

go build ./src/...
go test ./src/...
golangci-lint run ./src/...

Local Docker builds via the Makefile:

make build VERSION=dev          # native-platform image
make push VERSION=v0.2.0        # multi-arch push to GHCR (requires docker login ghcr.io)
make test
make lint

Directories

Path Synopsis
src
Package main is the entry point for the intervals-icu-mcp server.
Package main is the entry point for the intervals-icu-mcp server.
app
Package app provides the MCP server, its DI module, and lifecycle management.
Package app provides the MCP server, its DI module, and lifecycle management.
app/api
Package api provides HTTP routing configuration for the MCP server.
Package api provides HTTP routing configuration for the MCP server.
app/api/rest
Package rest provides OAuth 2.1 HTTP handlers for the MCP server.
Package rest provides OAuth 2.1 HTTP handlers for the MCP server.
app/auth
Package auth provides OAuth 2.1 authentication for the MCP server's streamable HTTP transport.
Package auth provides OAuth 2.1 authentication for the MCP server's streamable HTTP transport.
app/clients/github
Package github provides an HTTP client for the GitHub OAuth and user API endpoints.
Package github provides an HTTP client for the GitHub OAuth and user API endpoints.
app/clients/intervals
Package intervals provides an HTTP client for the Intervals.icu API.
Package intervals provides an HTTP client for the Intervals.icu API.
app/tools
Package tools contains MCP tool registrations for the intervals.icu MCP server.
Package tools contains MCP tool registrations for the intervals.icu MCP server.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL