MCP server for live Charlotte Area Transit System (CATS) bus and light rail data, built on the agency's public GTFS-Realtime feeds
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Documented (README)
claude mcp add queenscoach -- uvx queenscoach{
"mcpServers": {
"queenscoach": {
"command": "uvx",
"args": ["queenscoach"],
"env": {
"QUEENSCOACH_GOOGLE_CLIENT_SECRET": "<queenscoach_google_client_secret>",
"QUEENSCOACH_PUBLIC_URL": "<queenscoach_public_url>"
}
}
}
}QUEENSCOACH_GOOGLE_CLIENT_SECRETQUEENSCOACH_PUBLIC_URLMCP Servers overview
<!-- mcp-name: io.github.ajwann/queenscoach -->
# QueensCoach ♔
[](https://github.com/ajwann/queenscoach/actions/workflows/ci.yml)
**QueensCoach** is an MCP server for live **Charlotte Area Transit System (CATS)** bus
and light rail data, built on the agency's public GTFS-Realtime feeds. It runs over
**stdio**, launched by the MCP client that uses it, or over **HTTP** with Google OAuth
in front of it, for a hosted server. Both transports serve the same three tools.
## Hosted server
A public instance runs on Google Cloud Run. Sign in with any Google account:
```
https://queenscoach.adamwanninger.com/mcp
```
**There is zero guarantee of uptime.** The hosted server is provided as-is. It may be
slow, down, switched off by its spending cap, or retired without notice. For anything
you rely on, run your own: over [stdio](#stdio), or on your own Google Cloud project
with [`deploy/GCP.md`](deploy/GCP.md).
Signing in tells the server your Google account's email address, which is used only
to decide whether to admit you, and is never stored. The tokens it issues record
your account's opaque Google ID and nothing else about you. The
[privacy policy](https://adamwanninger.com/privacy/) and
[terms of service](https://adamwanninger.com/terms/) cover the hosted server.
### Adding it to Claude
Claude calls a remote MCP server a **connector**. Custom connectors are available on
Claude's paid plans.
1. Open **Settings → Connectors**. On the web that's
[claude.ai/settings/connectors](https://claude.ai/settings/connectors); in the
desktop app, Settings then Connectors.
2. Click **Add custom connector** at the bottom of the list.
3. Give it a name, `QueensCoach`, and paste the URL above as the remote MCP server
URL. Leave the advanced OAuth fields empty: this server registers your client
automatically.
4. Click **Add**, then **Connect** on the connector that appears. A browser window
opens for the Google sign-in; approve it and it closes itself.
5. In a chat, open the tools menu and check that QueensCoach is enabled. Its three
tools then appear.
The connector belongs to your Claude account, so it follows you across web, desktop,
and mobile. To disconnect, remove it from that same Connectors page; that revokes the
tokens this server issued.
### Adding it to Claude Code
```bash
claude mcp add --transport http queenscoach https://queenscoach.adamwanninger.com/mcp
```
Then run `/mcp`, pick `queenscoach`, and choose **Authenticate**, which opens the same
Google sign-in. `/mcp` shows the connection's state afterwards. A server added this way
loads when Claude Code next starts.
### Any other client
Any MCP client that supports remote servers over streamable HTTP with OAuth works:
give it the same URL and it discovers the rest.
## Tools
| Tool | Purpose |
| --- | --- |
| `find_vehicle` | Locate one bus/train by vehicle number, or every vehicle on a route, and return GPS coordinates. |
| `list_vehicles` | Current GPS coordinates of every bus and train in service. |
| `get_arrivals` | Estimated arrival times at a specific stop or station. |
### `find_vehicle`
| Argument | Type | Notes |
| --- | --- | --- |
| `vehicle` | string | Vehicle number as shown on the bus/train, e.g. `2301`, `LRV307`. |
| `route` | string | Route to locate: `9`, `501`, `Blue Line`, `Mt. Holly Road`. |
| `mode` | `bus` \| `train` | Optional filter. |
At least one of `vehicle` or `route` is required. Returns position, heading, speed,
occupancy, headsign, and the next scheduled stop.
### `list_vehicles`
| Argument | Type | Notes |
| --- | --- | --- |
| `mode` | `bus` \| `train` | Optional filter. |
| `route` | string | Optional single-route filter. |
| `limit` | integer | Max vehicles to return (default and cap: 250). |
Includes `countsByMode` and `totalInService` so the total is visible even when the
list is truncated.
### `get_arrivals`
| Argument | Type | Notes |
| --- | --- | --- |
| `stop` | string | **Required.** Stop id (`02400`), stop code, or part of a stop name (`CTC Station`). |
| `route` | string | Optional route filter. |
| `mode` | `bus` \| `train` | Optional filter. |
| `limit` | integer | Max arrivals (default 10, cap 50). |
Returns minutes away, predicted and scheduled times, schedule deviation, the vehicle
number, and that vehicle's live position. When a name query is ambiguous, the best
match is used and the runners-up are listed under `otherStopsMatchingQuery`. Service
alerts affecting the stop or its routes are attached when present.
## Install
Requires Python 3.11+.
```bash
pip install queenscoach
```
Or run it without installing anything, which is how most MCP clients launch it:
```bash
uvx queenscoach
```
From a clone instead, to hack on it or to run the HTTP transport from source:
```bash
python3 -m venv .venv
.venv/bin/pip install . # '.[gcp]' adds the Firestore token store
```
## Transports
Pick one with `--transport` or `QUEENSCOACH_TRANSPORT`; the default is `stdio`.
```bash
queenscoach # stdio (default)
queenscoach --transport http --port 8000 # streamable HTTP + Google OAuth
```
### stdio
For a server the client launches itself. No authentication: the client already owns
the process.
Register it with Claude Code:
```bash
claude mcp add queenscoach -- uvx queenscoach
```
Or in an MCP client config file:
```json
{
"mcpServers": {
"queenscoach": {
"command": "uvx",
"args": ["queenscoach"]
}
}
}
```
An installed copy works just as well, given an absolute path
(`/absolute/path/to/.venv/bin/queenscoach`): MCP clients rarely share your shell's
`PATH`. `python -m queenscoach` runs the same server, so any interpreter with the
package installed works as the command.
stdout carries MCP protocol traffic only; all diagnostics go to stderr.
### HTTP with Google OAuth
For a hosted server anyone with the URL can reach. Every request to `/mcp` needs a
bearer token, and the only way to get one is to sign in with a Google account that is
on the allow list.
**How the sign-in works.** MCP clients register themselves dynamically and expect an
authorization server at the MCP server's own origin. Google offers neither dynamic
registration nor tokens audience-restricted to a third-party resource, so this server
is its own OAuth 2.1 authorization server and delegates only the login to Google:
```
MCP client <--OAuth--> queenscoach <--OAuth--> Google
```
Google's answer is used exactly once, to learn which account signed in. That email is
checked against the allow list, and only then does this server mint its own tokens.
Google's tokens are never handed to the client.
**One-time setup in Google Cloud.** At
[console.cloud.google.com/auth/clients](https://console.cloud.google.com/auth/clients),
create an **OAuth client** of type **Web application** and add one authorized
redirect URI:
```
https://your-public-url/auth/google/callback
```
It must match `QUEENSCOACH_PUBLIC_URL` exactly. The server logs the URI it expects at startup.
Copy the client ID and secret into the environment below.
**Run it.** `.env.example` lists every setting; the shell form is:
```bash
export QUEENSCOACH_GOOGLE_CLIENT_ID=...apps.googleusercontent.com
export QUEENSCOACH_GOOGLE_CLIENT_SECRET=...
export QUEENSCOACH_ALLOWED_EMAILS=you@example.com
export QUEENSCOACH_PUBLIC_URL=https://queenscoach.example.com
queenscoach --transport http --port 8000
```
Then point a client at `https://queenscoach.example.com/mcp`; it discovers the rest and opens
a browser for the Google sign-in. In Claude Code:
```bash
claude mcp add --transport http queenscoach https://queenscoach.example.com/mcp
```
**Access is denied by default.** Startup fails unless `QUEENSCOACH_ALLOWED_EMAILS`,
`QUEENSCOACH_ALLOWED_DOMAINS`, or an explicit `QUEENSCOACH_ALLOW_ANY_GOOGLE_ACCOUNT=true` says who
may get in, so a misconfigured deployment is unreachable rather than open to every
Google account on the internet. Unverified Google addresses are always refused.
**Endpoints.**
| Path | Purpose |
| --- | --- |
| `/mcp` | The MCP endpoint. Requires `Authorization: Bearer <token>`. |
| `/.well-known/oauth-protected-resource/mcp` | Points clients at the authorization server. |
| `/.well-known/oauth-authorization-server` | This server's OAuth metadata. |
| `/register` | Dynamic client registration (RFC 7591). |
| `/authorize`, `/token`, `/revoke` | The OAuth endpoints. |
| `/auth/google/callback` | Where Google returns the user. |
[`scripts/install.sh`](scripts/install.sh) does a whole deployment: a system
user under `/opt`, a Cloudflare tunnel and its DNS record created over the API,
both systemd units, and a verification pass. No port forwarding, so it works
behind CGNAT or a locked router. See [`deploy/`](deploy/README.md).
[`scripts/deploy-gcp.sh`](scripts/deploy-gcp.sh) does the same on **Google Cloud
Run**, in your own GCP project: the project itself, Firestore for sign-ins, the
client secret in Secret Manager, a container built by Cloud Build, a monthly
budget with an optional hard spend cap, and the same verification pass. It scales
to zero, so a personal server costs next to nothing. See
[`deploy/GCP.md`](deploy/GCP.md).
**Deployment notes.**
- By default the server speaks plain HTTP and expects a tunnel or proxy to
terminate TLS, which is what the install script sets up. Setting
`QUEENSCOACH_TLS_CERT` and `QUEENSCOACH_TLS_KEY` instead makes it serve HTTPS itself, for a
deployment with nothing in front of it.
- `QUEENSCOACH_PUBLIC_URL` is what clients dial and is this server's OAuth issuer
identifier, so it must be the external URL, not the bind address.
- Token state is in memory by default and therefore per-process: restarting
invalidates outstanding tokens. `QUEENSCOACH_TOKEN_STORE=firestore` keeps it in
Firestore instead (install the `gcp` extra: `pip install 'queenscoach[gcp]'`), so
What people ask about queenscoach
What is ajwann/queenscoach?
+
ajwann/queenscoach is mcp servers for the Claude AI ecosystem. MCP server for live Charlotte Area Transit System (CATS) bus and light rail data, built on the agency's public GTFS-Realtime feeds It has 0 GitHub stars and its last recorded update is dated 2026-09-12.
How do I install queenscoach?
+
You can install queenscoach by cloning the repository (https://github.com/ajwann/queenscoach) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is ajwann/queenscoach safe to use?
+
Our security agent has analyzed ajwann/queenscoach and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains ajwann/queenscoach?
+
ajwann/queenscoach is maintained by ajwann. The last recorded GitHub activity is dated 2026-09-12, with 0 open issues.
Are there alternatives to queenscoach?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy queenscoach to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/ajwann-queenscoach)<a href="https://claudewave.com/repo/ajwann-queenscoach"><img src="https://claudewave.com/api/badge/ajwann-queenscoach" alt="Featured on ClaudeWave: ajwann/queenscoach" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!
The fastest path to AI-powered full stack observability, even for lean teams.