Skip to main content
Glama
kriscendobot

minion.town

by kriscendobot

minion.town πŸ™οΈ

A toy MCP (Model Context Protocol) server with OAuth 2.1 authentication and authorization, built to validate one design: an MCP server that has an excellent local developer experience and a clean path to AWS β€” with the same code running in both places, differing only by configuration.

It's a tiny "minion town": three MCP tools, each gated by an OAuth scope.

Full design rationale: designs/mcp-oauth.md. AWS deploy: infra/README.md.

Quickstart (local, no cloud, no Docker)

cp .env.example .env
npm install
npm run dev          # mock OAuth server (:9000) + MCP server (:3000), hot-reload

In another terminal, run the full OAuth + MCP flow:

npm run client                 # PKCE flow β†’ every tool succeeds
npm run client -- read-only    # omit the write scope β†’ summon_minion is denied
β†’ running OAuth flow (scope: mcp:tools mcp:minions:read mcp:minions:write)
βœ“ got access token (eyJraWQiOiI0NjY5…)
tools: minion_status, list_minions, summon_minion
minion_status: βœ“ πŸ™οΈ  minion.town has 0 minion(s).
summon_minion: βœ“ ✨ Summoned Bob (minion-1) to do "guard the gate".
list_minions:  βœ“ β€’ Bob β€” guard the gate

Run the end-to-end authN/authZ tests (real mock AS + real middleware, nothing about the auth path is stubbed):

npm test

Related MCP server: Keycard Hello MCP Server

The tools and their scopes

Tool

Scope required

Does

minion_status

mcp:tools

count minions in town

list_minions

mcp:minions:read

list the roster

summon_minion

mcp:minions:write

summon a new minion

A token only carrying mcp:tools mcp:minions:read can list but cannot summon β€” authorization is enforced from the token's scopes.

How it works (one paragraph)

The MCP server is an OAuth 2.1 resource server. Unauthenticated requests get 401 + WWW-Authenticate pointing at RFC 9728 Protected Resource Metadata, which advertises the authorization server. The client runs PKCE auth-code with an RFC 8707 resource parameter; the server validates the JWT's signature, issuer, expiry, and audience (so a token for another server is rejected), then maps the token's scopes β†’ which tools it may call. Locally the authorization server is oauth2-mock-server; on AWS it's Amazon Cognito. The server code is identical; only src/config.ts reads different env vars. Built on @modelcontextprotocol/sdk and grounded in the MCP authorization spec (2025-06-18 + Nov 2025 update).

Layout

src/        MCP resource server (config seam, verifier, scope→tool map, tools, HTTP)
dev/        local dev harness: mock OAuth AS + browserless PKCE client
test/       end-to-end authN/authZ tests
infra/      AWS CDK deploy (App Runner + Cognito + Route53/ACM) β€” documented path
designs/    the design document

Security

No secrets are committed. .env is gitignored; AWS secrets are injected by the platform. See designs/mcp-oauth.md Β§ Threat-model notes.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A remote MCP server implementation that demonstrates authentication and authorization capabilities using OAuth 2.1. This is a workshop project for learning how to build secure MCP servers with user authentication.
    16,000 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server demonstrating OAuth 2.0 authentication with Keycard's Security Token Service, providing tools for displaying the Keycard logo and retrieving authenticated user information.
    13 npm
    1
    Apache 2.0