mcp101
README.md
# mcp101
[](https://github.com/1995parham-learning/mcp101/actions/workflows/ci.yaml)
A hands-on sample [MCP](https://modelcontextprotocol.io) server built with
[FastMCP](https://gofastmcp.com), used to try out the Model Context Protocol —
basic tools first, then a real-world **Google OAuth** example that calls Google
APIs on a user's behalf.
It accompanies the `MCP Tooling` learning note.
## Layout
| File | What it is |
| --- | --- |
| `src/mcp101/server.py` | Minimal **no-auth** server — `add`, `greet`, a `time://now` resource, a `summarize` prompt. Runs with zero credentials. Start here. |
| `src/mcp101/google_server.py` | **Google OAuth** server — authenticates the user with Google and lists their calendars via the Calendar API. |
| `src/mcp101/github_server.py` | **GitHub OAuth** server — authenticates the user with GitHub and lists their repos. Quickest auth demo to set up. |
## Requirements
- Python >= 3.11
- [uv](https://docs.astral.sh/uv/)
- [just](https://github.com/casey/just) (optional, for the shortcuts below)
- Node.js (only for the MCP Inspector)
## Quick start (no auth)
```bash
just install # or: uv sync
just run # stdio transport, for Claude Desktop / Cursor
just run-http # streamable HTTP on http://localhost:8000/mcp
```
Test it visually with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
```bash
just inspect # npx @modelcontextprotocol/inspector uv run mcp101
```
Wire it into Claude Desktop (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"mcp101": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/mcp101", "mcp101"]
}
}
}
```
## Google OAuth demo
This is the part worth understanding: it does not just *log you in*, it *acts as
you* against Google. FastMCP's `GoogleProvider` is an `OAuthProxy` (Google has no
Dynamic Client Registration), so FastMCP brokers the OAuth flow, encrypts and
stores the upstream Google token server-side, and hands the MCP client only a
reference token. Inside a tool, `get_access_token().token` gives you the real
Google access token to call Google with — and the proxy refreshes it transparently.
### 1. Create Google credentials
1. [Google Cloud Console](https://console.cloud.google.com) → **APIs & Services → OAuth consent screen** — configure it (External; add yourself as a test user while in "Testing" mode).
2. **APIs & Services → Credentials → Create Credentials → OAuth client ID** → application type **Web application**.
3. Add an **Authorized redirect URI** that matches **exactly**: `http://localhost:8000/auth/callback`.
4. **APIs & Services → Library** → enable **Google Calendar API**.
5. Copy the **Client ID** (`...apps.googleusercontent.com`) and **Client Secret** (`GOCSPX-...`).
### 2. Configure and run
```bash
cp .env.example .env # then fill in the two Google values
set -a; source .env; set +a
just run-google # or: uv run mcp101-google
```
Connect with the Inspector (HTTP transport, URL `http://localhost:8000/mcp`). It
will bounce you through Google's consent screen, then `whoami` and `list_calendars`
will work.
### Scopes
Requested in `google_server.py`:
- `openid`, `.../auth/userinfo.email` — identity
- `.../auth/calendar.readonly` — read the user's calendars
Prefer `.readonly` scopes unless you need write access.
### Gotchas
- **Restricted scopes** (Gmail, Drive contents) need Google's app-verification review for non-test users. In "Testing" mode you are limited to explicitly added test users.
- **Tokens are per-user and in-memory** in this demo. For production, configure persistent encrypted token storage and stable JWT signing keys, or tokens die on restart and everyone re-consents.
- The **redirect URI must match exactly** between Google and `BASE_URL` — a trailing slash mismatch will fail the flow.
## GitHub OAuth demo
The same OAuthProxy mechanics as the Google demo, but a GitHub OAuth App takes a
minute to create and needs **no verification review** — so this is the fastest way
to see real on-behalf-of-user API calls.
### 1. Create a GitHub OAuth App
1. GitHub → **Settings → Developer settings → OAuth Apps → New OAuth App**.
2. **Homepage URL**: `http://localhost:8000`.
3. **Authorization callback URL** (must match exactly): `http://localhost:8000/auth/callback`.
4. Register, then **Generate a new client secret**. Copy the **Client ID** (`Iv1...`) and secret.
### 2. Configure and run
```bash
cp .env.example .env # fill in the two GITHUB_ values
set -a; source .env; set +a
just run-github # or: uv run mcp101-github
```
Connect with the Inspector (Streamable HTTP, URL `http://localhost:8000/mcp`). After
the GitHub consent screen, `whoami` returns your profile and `list_repos` lists your
repositories.
Requested scopes (in `github_server.py`): `read:user`, `user:email`, `public_repo`.
## Docker
The image defaults to the basic server over streamable HTTP — sensible for a
container / Kubernetes deployment (stdio only makes sense for local desktop clients).
```bash
docker build -t mcp101 .
docker run --rm -p 8000:8000 mcp101 # basic server on :8000/mcp
```
Run the Google demo instead by overriding the command and passing credentials:
```bash
docker run --rm -p 8000:8000 \
-e GOOGLE_CLIENT_ID=...apps.googleusercontent.com \
-e GOOGLE_CLIENT_SECRET=GOCSPX-... \
-e BASE_URL=https://your-public-host \
mcp101 mcp101-google
```
For Kubernetes, expose port `8000`, set `BASE_URL` to the externally reachable URL,
and remember the Google **Authorized redirect URI** must be `<BASE_URL>/auth/callback`.
For anything beyond a demo, also configure persistent encrypted token storage and
stable JWT signing keys (see the gotchas above).
## CI
`.github/workflows/ci.yaml` runs on every push/PR to `main`:
- `ruff format --check` and `ruff check` (lint)
- an import smoke test for both servers
- a `docker build` to validate the image
## License
MIT
TDQS
A3.6/5.0
Scored across 2 tools
Disambiguation5/5
The two tools serve entirely different purposes—arithmetic and greeting—so there is no risk of confusion or overlap.
Naming Consistency5/5
Both tool names are single verbs in imperative form, following a consistent and predictable pattern.
Tool Count3/5
With only 2 tools, the server is on the lower end of the appropriate range; it feels thin but not unreasonable for a small utility server.
Completeness2/5
The tools cover two unrelated capabilities with no clear domain, leaving significant gaps for any coherent purpose beyond these trivial operations.
Maintenance
ActivityMaintained
ResponsivenessSyncing