No description
  • Go 98.8%
  • Makefile 1.2%
Find a file
Wolfhound d7fa65b776
All checks were successful
Go Format and Build / fmt-and-build (push) Successful in 3m18s
test: transport middleware + format coverage
internal/mcd/transport (12 tests):
  - DefaultHeaders: common headers apply when not per-request set;
    per-request headers win when both are present.
  - AuthBearer: sets Bearer with current token; skips when empty.
  - AuthRefresh: pass-through on 2xx; refresh+retry exactly once on
    401 with the new bearer; surfaces ErrAuthExpired wrapping the
    underlying refresh error when refresh itself fails; calls the
    onRefresh persistence callback exactly once.
  - StatusError: 503 → ErrUpstream, 400 → ErrUpstream4xx, raw 401
    (without AuthRefresh in chain) → ErrAuthExpired.
  - Chain: verifies left-to-right outward call order via a tracer
    middleware (A-in → B-in → base → B-out → A-out).
  - HTTPDoer: JSON parsing populates resp.JSON; body marshaling
    handles map[string]any correctly.

internal/mcd (7 tests):
  - FormatMenu: name resolution via productLookup + en-US
    strings/lookup (3 ITEMs resolve correctly; CHOICE types filtered;
    items sorted alphabetically; nil-returns on missing channels and
    unresolvable names).
  - FormatRestaurants: nationalStoreNumber → ID; cityTown/postalZip/
    stateProvince mapping; DRIVETHRU and MOBILEORDERS facility flags.
  - FormatCartTotal: displayDataLookup name resolution and totals
    parsing.
  - centsToPrice / PriceToCents: round-trip across $0.00, $5.79,
    $1250.00; PriceToCents("not a price") → 0.

All three packages plus render (12 tests from Phase 2) — 31 tests
total. No external deps; httptest backs the transport tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 04:36:43 -04:00
.forgejo/workflows fix: correct path 2025-12-06 11:06:13 -05:00
cmd/mc-mcp feat: implement OAuth 2.1 authorization server for MCP connectors 2026-03-22 05:13:38 -04:00
configs refactor: remove Cloudflare Email Worker and email forwarding infrastructure 2026-03-22 19:47:39 -04:00
docs/mcdonalds-api feat: API docs, fix loyalty + locale, polish instructions 2026-05-23 04:34:08 -04:00
internal test: transport middleware + format coverage 2026-05-23 04:36:43 -04:00
.gitignore refactor: remove Cloudflare Email Worker and email forwarding infrastructure 2026-03-22 19:47:39 -04:00
CLAUDE.md feat: cart system, preferences, and schema cleanup (rework baseline) 2026-05-23 04:12:24 -04:00
go.mod feat: implement OAuth 2.1 authorization server for MCP connectors 2026-03-22 05:13:38 -04:00
go.sum feat: implement OAuth 2.1 authorization server for MCP connectors 2026-03-22 05:13:38 -04:00
Makefile feat: cart system, preferences, and schema cleanup (rework baseline) 2026-05-23 04:12:24 -04:00
README.md feat: multi-user architecture with per-user auth and Cloudflare Email Worker 2026-03-22 03:48:27 -04:00

McDonald's MCP Server

A Model Context Protocol (MCP) server for accessing McDonald's API, written in Go using the official MCP SDK. Supports single-user (stdio) and multi-user (HTTP) modes.

Features

  • Two operating modes: Single-user stdio for local MCP clients, multi-user HTTP for self-hosted deployments
  • Simple authentication: Login via magic link paste -- no extra infrastructure required
  • PostgreSQL Database: Stores authentication tokens, users, and can track orders/menu items
  • Dual Transport: Supports both stdio (for MCP clients) and HTTP modes
  • Token Management: Automatic token refresh with fallback to re-authentication
  • Optional automated auth: Cloudflare Email Worker for hands-free magic link capture (advanced)

Prerequisites

  • Go 1.23 or higher
  • PostgreSQL database
  • McDonald's account email

Installation

  1. Clone the repository:
git clone https://forge.wolfhound.dev/wolfhound/mc-mcp.git
cd mc-mcp
  1. Install dependencies:
make deps
# or manually: go mod download && go mod tidy
  1. Create your configuration:
cp configs/.env.example .env
# Edit .env with your settings
  1. Build the server:
make build
# or manually: go build -o bin/mc-mcp ./cmd/mc-mcp

Configuration

Create a .env file with the following settings:

PostgreSQL Configuration

POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DATABASE=mcdonalds
POSTGRES_USERNAME=postgres
POSTGRES_PASSWORD=your_password
POSTGRES_SSLMODE=disable

Single-User Stdio Configuration

Used when MULTI_USER_ENABLED=false (the default):

MCD_ACCESS_TOKEN=your_access_token
MCD_REFRESH_TOKEN=your_refresh_token
MCD_EMAIL=your-mcdonalds-account@example.com

Multi-User HTTP Configuration

MULTI_USER_ENABLED=true
HTTP_ENABLED=true
ADMIN_TOKEN=your_admin_token_here

Server Configuration

HTTP_ENABLED=false
HTTP_HOST=localhost
HTTP_PORT=8080

# Logging level: DEBUG, INFO, WARNING, ERROR, CRITICAL
LOG_LEVEL=INFO

Database Setup

The server automatically creates all necessary tables on startup using GORM migrations. Tables include:

  • users: User accounts and API keys (multi-user mode)
  • accounts: Stores McDonald's OAuth tokens
  • pending_logins: In-progress authentication flows
  • orders: Order history
  • order_items: Individual items in orders
  • menu_items: Menu item catalog
  • locations: Restaurant locations
  • email_logs: Email processing history
  • nutrition_infos: Nutritional information

Usage

Running in Stdio Mode (for MCP Clients)

This is the default mode for use with Claude Desktop or other MCP clients:

make run
# or manually: ./bin/mc-mcp

Running in Multi-User HTTP Mode

For self-hosted multi-user deployments:

make run-http
# or manually: HTTP_ENABLED=true MULTI_USER_ENABLED=true ./bin/mc-mcp

The server will be available at:

  • MCP endpoint: http://localhost:8080/mcp
  • Health check: http://localhost:8080/health
  • API routes: http://localhost:8080/api/...

Authentication Flow

Single-user mode

  1. Server connects to PostgreSQL and runs migrations
  2. Loads MCD_ACCESS_TOKEN and MCD_REFRESH_TOKEN from environment
  3. If tokens expire, use the login MCP tool to trigger a magic link email, then use paste_magic_link with the link from your email

This is the default and recommended auth flow for multi-user mode. No extra infrastructure is needed beyond the Go server and PostgreSQL.

  1. Admin creates a user via POST /api/users with the admin token
  2. User receives an API key (shown once)
  3. User calls the login MCP tool (or POST /api/auth/login) to trigger a McDonald's magic link email
  4. User checks their email, copies the magic link URL
  5. User calls the paste_magic_link MCP tool (or POST /api/auth/magic-link) with the link
  6. Server completes authentication, caches the client -- user is now active

Auth only needs to happen when tokens expire, so the manual paste flow is simple and sufficient for most deployments.

Available MCP Tools

The server provides the following tools for interacting with McDonald's API:

1. login

Initiate the McDonald's login flow. Triggers a magic link email to the user's registered address.

Arguments: None

Complete authentication by pasting the magic link URL received via email.

Arguments:

  • magic_link (string, required): The full magic link URL from the McDonald's email

3. auth_status

Check the current authentication status.

Arguments: None

4. get_offers

Get available McDonald's offers and deals.

Arguments: None

5. get_restaurants

Find McDonald's restaurants near a location.

Arguments:

  • latitude (float, required): Latitude coordinate
  • longitude (float, required): Longitude coordinate
  • radius (int, optional): Search radius in miles (default: 10)

Example:

{
  "latitude": 40.7128,
  "longitude": -74.0060,
  "radius": 5
}

6. get_menu

Get the menu for a specific McDonald's restaurant.

Arguments:

  • restaurant_id (string, required): McDonald's restaurant ID

Example:

{
  "restaurant_id": "12345"
}

7. get_account

Get the current McDonald's account information.

Arguments: None

8. get_orders

Get the user's McDonald's order history.

Arguments: None

Development

Project Structure

mc-mcp/
├── cmd/
│   └── mc-mcp/          # Main application entry point
│       └── main.go
├── internal/            # Private application code
│   ├── api/             # HTTP middleware and REST handlers
│   ├── auth/            # Authentication and user management
│   ├── config/          # Configuration management
│   ├── database/        # Database models and initialization
│   ├── mcd/             # McDonald's API client
│   └── server/          # MCP server and tool handlers
├── worker/              # Cloudflare Email Worker (optional)
├── configs/             # Configuration files
│   └── .env.example
├── bin/                 # Compiled binaries (created by build)
├── go.mod
├── go.sum
├── Makefile
└── README.md

Adding New Tools

To add a new MCP tool:

  1. Add the API method to internal/mcd/client.go (and response types to types.go)
  2. Define an args struct in internal/server/server.go
  3. Add a closure in registerMcDonaldsTools() using getClient() to resolve the per-user client

Makefile Commands

  • make build - Build the application
  • make run - Build and run (stdio mode)
  • make run-http - Build and run (HTTP mode)
  • make test - Run tests
  • make clean - Remove build artifacts
  • make deps - Download and tidy dependencies
  • make fmt - Format code
  • make lint - Run linter
  • make worker-deploy - Deploy Cloudflare Email Worker (optional)
  • make help - Show all available commands

Advanced: Automated Email Capture (Cloudflare Email Worker)

For deployments where you want fully automated authentication without manual paste, you can optionally set up the Cloudflare Email Worker. This is not required -- the paste-the-link flow described above works without any extra infrastructure.

What it does

The worker catches emails forwarded to *@EMAIL_DOMAIN, extracts the McDonald's magic link token, and POSTs it to the server's webhook endpoint. This completes the login flow automatically without the user needing to paste anything.

Prerequisites

  • A domain with Cloudflare Email Routing configured
  • Cloudflare Workers enabled on your account
  • Node.js (for deploying with wrangler)

Setup

  1. Add the following to your .env:
EMAIL_DOMAIN=mcp.yourdomain.com
WEBHOOK_SECRET=a_shared_secret_between_worker_and_server
REGISTRATION_ENABLED=false  # Set to true to allow self-service registration
  1. Configure the worker:
cd worker
cp wrangler.toml.example wrangler.toml  # if applicable
# Edit wrangler.toml with your domain and webhook URL
  1. Deploy the worker:
make worker-deploy
# or manually: cd worker && npx wrangler deploy
  1. Set up Cloudflare Email Routing to forward *@EMAIL_DOMAIN to the worker.

Automated auth flow

  1. Admin creates user via POST /api/users -- user gets an API key and an assigned email address at the EMAIL_DOMAIN
  2. User sets up forwarding from their McDonald's email to the assigned address
  3. User calls login -- magic link email is sent to their McDonald's address
  4. Email is forwarded to the assigned address, worker catches it, extracts the token, POSTs to /api/webhooks/email
  5. Auth completes automatically

Configuration reference

Variable Required for Worker Description
EMAIL_DOMAIN Yes Domain configured for Cloudflare Email Routing
WEBHOOK_SECRET Yes Shared secret between the worker and the Go server
REGISTRATION_ENABLED No Allow self-service user registration (default: false)

Troubleshooting

"Authentication expired"

  • Use the login tool to trigger a new magic link, then paste_magic_link to complete auth
  • Check database connection
  • Verify tokens in the accounts table

Database connection errors

  • Ensure PostgreSQL is running
  • Verify connection credentials in .env
  • Check that the database exists

Dependencies

License

[Add your license here]

Contributing

[Add contribution guidelines here]

Acknowledgments

  • Based on the Python implementation at BuyMeMcDonalds
  • Uses the official Model Context Protocol Go SDK maintained by Google and Anthropic