Skip to main content
Glama
mcnamee

elvanto-mcp

by mcnamee

elvanto-mcp

Summary

A personal, self-hosted MCP server for your Elvanto account. It runs as a single AWS Lambda behind a free Function URL — nothing is running (or billing) between requests, and continuous deployment ships every push to main straight to AWS.

For a couple of calls a week the AWS cost is effectively $0 (Lambda, DynamoDB and SSM sit comfortably inside the always-free tier; the only guaranteed spend is CloudWatch log storage, i.e. cents per month).

Related MCP server: mcp-connect

Usage

Once connected, ask Claude things like:

  • "Ask Elvanto when I'm next rostered on at church."

  • "Use the Elvanto tool to check which songs will be played this Sunday."

  • "Check Elvanto to tell me who's rostered on the band this week."

  • "Ask Elvanto for my upcoming roster."

  • "Use the Elvanto MCP to submit an unavailability for 19–23 June, reason: Away."

These map onto five tools:

Tool

What it answers

get_my_upcoming_roster

"When am I next on?" / "My upcoming roster" — services you're rostered on, soonest first

get_service_songs

"Songs this Sunday" — song list per service for a date (defaults to upcoming Sunday)

get_service_roster

"Who's on the band this week?" — everyone rostered for a date, filterable by department

list_upcoming_services

Upcoming published services

add_unavailability

Registers an all-day, non-repeating, all-locations unavailability (see caveat below)

Unavailability caveat: Elvanto's public API documents no unavailability endpoint. The tool attempts unavailabilities/add and, if your account rejects it, responds with a clear message and the exact details to enter manually. Everything else uses documented endpoints (services/getAll, people/search).

"You" are identified automatically as the logged-in Elvanto user (OAuth mode), or by the optional person-email parameter (API-key mode).

Requirements

  • An Elvanto account, plus ONE of two credential modes:

    • Elvanto OAuth (recommended — works without admin access): ask a church admin to register an OAuth application once (Elvanto → Settings → Integrations → API, register application) and give you its Client ID and Client Secret. The app itself grants nothing — access is created only when you later sign in to Elvanto through this server, and every request then runs with your own member permissions.

    • API key (admins only): Elvanto → Settings → Account Settings → API.

  • An AWS account, with the AWS CLI configured locally and the SAM CLI installed (brew install aws-sam-cli).

  • A GitHub repository (for continuous deployment) and a Claude plan that supports custom connectors.

Installation

All commands assume region ap-southeast-2; change it in samconfig.toml and the commands if you prefer another.

Local: run and test

npm ci
npm run check      # typecheck + unit tests
npm test           # tests only
npm run build      # bundle sanity check
sam build          # bundle exactly as production does

The unit tests cover the OAuth flow, the MCP endpoint and the Elvanto response parsing with a stubbed Elvanto API — no credentials needed.

Production: manual deploy

1. Create the setup password parameter (once — secrets never touch git):

aws ssm put-parameter --region ap-southeast-2 --type SecureString \
  --name /elvanto-mcp/oauth-password --value 'A_STRONG_PASSWORD_YOU_CHOOSE'

The setup password is what protects your data during connector approval — pick a strong one.

2. Deploy:

npm ci && npm run check
sam build && sam deploy

The stack output McpEndpoint is your connector URL, e.g. https://abc123.lambda-url.ap-southeast-2.on.aws/mcp.

If your church isn't in Australia/Sydney, deploy with sam deploy --parameter-overrides ChurchTimezone=Pacific/Auckland.

3a. Elvanto credentials — OAuth mode (no admin access needed):

Give your church admin the callback URL https://YOUR_FUNCTION_URL/elvanto/callback and ask them to register an OAuth application with it (Elvanto → Settings → Integrations → API). Then store the credentials they give you:

aws ssm put-parameter --region ap-southeast-2 --type SecureString \
  --name /elvanto-mcp/elvanto-client-id --value 'CLIENT_ID_FROM_ADMIN'

aws ssm put-parameter --region ap-southeast-2 --type SecureString \
  --name /elvanto-mcp/elvanto-client-secret --value 'CLIENT_SECRET_FROM_ADMIN'

Finally, open https://YOUR_FUNCTION_URL/elvanto/connect in a browser, enter your setup password, and sign in to Elvanto once. The server stores your Elvanto session (auto-refreshed from then on) and identifies "you" automatically — no person-email needed.

3b. Elvanto credentials — API-key mode (admins only):

aws ssm put-parameter --region ap-southeast-2 --type SecureString \
  --name /elvanto-mcp/elvanto-api-key --value 'YOUR_ELVANTO_API_KEY'

aws ssm put-parameter --region ap-southeast-2 --type SecureString \
  --name /elvanto-mcp/person-email --value 'you@example.com'

person-email must match the email on your Elvanto profile; it tells the server who "me" is, since an API key is account-wide.

Production: continuous deployment (GitHub Actions + OIDC)

One-time bootstrap of the deploy role — no AWS keys are ever stored in GitHub (replace the repo name):

aws cloudformation deploy --region ap-southeast-2 \
  --template-file infra/github-oidc.yaml \
  --stack-name elvanto-mcp-github-oidc \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameter-overrides GitHubRepo=YOUR_GITHUB_USER/elvanto-mcp

(If your AWS account already has the GitHub OIDC provider, add CreateOidcProvider=false.)

Then in the GitHub repo → Settings → Secrets and variables → Actions → Variables, set:

  • AWS_ROLE_ARN — the DeployRoleArn output of the stack above

  • AWS_REGION — optional, defaults to ap-southeast-2

  • CHURCH_TIMEZONE — optional, e.g. Pacific/Auckland

Every push to main now runs typecheck + tests, then sam deploy (.github/workflows/deploy.yml).

Integration: Claude

  • Claude (web/desktop/mobile): Settings → ConnectorsAdd custom connector, paste the McpEndpoint URL. Claude discovers the OAuth endpoints, registers itself and opens the approval page — enter your setup password. Done.

  • Claude Code:

    claude mcp add --transport http elvanto https://YOUR_URL/mcp

Integration: ChatGPT

ChatGPT custom connectors (Settings → Connectors → Advanced → Developer mode) use a different OAuth callback domain, which this server blocks by default. To allow it, redeploy with:

sam deploy --parameter-overrides AllowedRedirectHosts=chatgpt.com,openai.com

then add the McpEndpoint URL as a connector in ChatGPT and approve with the same setup password.

Technical Detail

Claude (custom connector)
   │  OAuth 2.1: dynamic registration + PKCE + password-gated consent
   ▼
Lambda Function URL  ──►  Hono router on Lambda (Node 22, ARM)
   ├── /.well-known/*          OAuth discovery metadata
   ├── /oauth/*                register / authorize / token (Claude-facing)
   ├── /elvanto/connect        one-time Elvanto sign-in (password-gated)
   └── /mcp                    MCP Streamable HTTP (stateless JSON)
                │
                ├── DynamoDB (elvanto-mcp-oauth): hashed tokens, TTL-expired,
                │      plus the server's own Elvanto OAuth session
                ├── SSM SecureString: setup password + Elvanto credentials
                └── api.elvanto.com/v1 (HTTPS; Bearer user token or API key)

AWS services used:

Service

Role

Cost at this usage

Lambda (ARM, 512 MB) + Function URL

The entire server; URL is free, no API Gateway needed

Free tier

DynamoDB (on-demand)

OAuth clients, codes and hashed tokens, auto-expired via TTL

Free tier

SSM Parameter Store (SecureString)

Setup password + Elvanto credentials (OAuth client or API key)

Free

CloudWatch Logs (30-day retention)

Error logs only

Cents/month

IAM + GitHub OIDC

Keyless continuous deployment

Free

Code layout:

Security

  • Your Elvanto credentials never leave AWS. The client secret / API key live in SSM SecureStrings (KMS-encrypted), readable only by the Lambda role, and are never included in MCP responses. Claude only ever sees tool output (roster/song data).

  • OAuth mode is least-privilege by construction: the server acts as you in Elvanto, so it can never see more than your own member account can. The one-time sign-in at /elvanto/connect is password-gated and CSRF-protected with single-use state tokens, so nobody else can bind an Elvanto session to your server.

  • OAuth 2.1 for the connector: dynamic client registration, authorization code + PKCE (S256 required), single-use codes, refresh-token rotation.

  • Consent is password-gated. Registering a client grants nothing; the authorize page requires your setup password, with a lockout after 20 failed attempts per hour.

  • Redirect URIs are restricted to claude.ai / claude.com / anthropic.com (HTTPS only) unless you opt in to more, so tokens can't be sent to arbitrary sites.

  • Tokens are stored as SHA-256 hashes in DynamoDB with TTLs — a leaked table can't be replayed. Expiry is enforced on read, not just by DynamoDB TTL.

  • CD uses GitHub OIDC — no long-lived AWS keys in GitHub, and the deploy role is scoped to this stack's resources and the main branch only.

Troubleshooting

  • "Missing SSM parameter(s)" in tool output → the parameters weren't created in the same region as the stack.

  • "Not connected to Elvanto yet" → OAuth mode needs the one-time sign-in: open /elvanto/connect on the Function URL and log in.

  • "Elvanto session has expired" → repeat the /elvanto/connect sign-in (e.g. after the church admin revoked the app, or a long idle period).

  • No person found → API-key mode: person-email doesn't match your Elvanto profile email.

  • Connector auth loop → remove and re-add the connector; if you redeployed to a fresh stack the DynamoDB table (registered clients) was reset.

  • Logs: sam logs -n McpFunction --stack-name elvanto-mcp --tail (tool inputs/outputs are not logged; only errors are).

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mcnamee/elvanto-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server