Content
# mcp-oauth
MCP Server + WebAPI (`apps/api-mcp`) and OAuth Server (`apps/oauth`),
Web Frontend (`apps/web`) monorepo.
Access from Claude to MCP Server and manage normal web apps on the same OAuth authentication platform.
OAuth 2.1 compliant (PKCE + DCR + Refresh Token Rotation).
**Production Environment**: https://web.h-kawai-tech.workers.dev/
## Structure
```
apps/
api-mcp/ - MCP Server + Web API + BFF (Cloudflare Workers + Hono)
oauth/ - OAuth 2.1 Authentication/Authorization Server (Cloudflare Workers + Hono)
web/ - Web Frontend (React Router v7 SPA)
packages/
database/ - Drizzle ORM + Cloudflare D1 (DB_OAUTH / DB_API_MCP)
types/ - Common type definitions (Result<T>)
constants/ - Common constants (OAUTH_PATHS / API_MCP_PATHS / WEB_PATHS)
utils/ - Common utilities (only for multiple app spanning)
```
## Local Development Setup
### 1. Install Dependencies
```bash
pnpm install
```
### 2. Secret Settings
Create `apps/oauth/.dev.vars` and `apps/api-mcp/.dev.vars` (already in .gitignore).
Set the **same** `JWT_SECRET` in both files.
```bash
# Generate and copy JWT_SECRET
openssl rand -base64 32
```
```bash
# apps/oauth/.dev.vars
JWT_SECRET=<generated value above>
# apps/api-mcp/.dev.vars
JWT_SECRET=<same value>
```
### 3. Local DB Migration
```bash
# OAuth Server DB (users / oauth_clients / authorization_codes / refresh_tokens)
pnpm -F @mcp-oauth/oauth db:migrate:local
# api-mcp DB
pnpm -F @mcp-oauth/api-mcp db:migrate:local
```
> If migration SQL does not exist, generate it first:
> ```bash
> pnpm -F @mcp-oauth/database db:generate:oauth
> pnpm -F @mcp-oauth/database db:generate:mcp
> ```
### 4. Initial Data Seeding
```bash
pnpm -F @mcp-oauth/database db:seed
# Seeded contents:
# User: admin@example.com / password
# OAuth Client: web-client
```
### 5. Web Environment Variables
Create `apps/web/.env.local` (already in .gitignore):
```bash
VITE_API_BASE_URL=http://localhost:30001
VITE_OAUTH_BASE_URL=http://localhost:30002
VITE_WEB_BASE_URL=http://localhost:30000
```
### 6. Start
```bash
pnpm dev
# web → http://localhost:30000
# api-mcp → http://localhost:30001
# oauth → http://localhost:30002
```
Open `http://localhost:30000` in your browser and log in with `admin@example.com` / `password` to complete.
## Commands
```bash
# Development
pnpm dev # Start all apps
pnpm -F @mcp-oauth/api-mcp dev # Only api-mcp
pnpm -F @mcp-oauth/oauth dev # Only OAuth Server
pnpm -F @mcp-oauth/web dev # Only Web Frontend
# Build and Quality Check
pnpm build && pnpm format && pnpm lint:check
# DB Migration (SQL file generation)
pnpm -F @mcp-oauth/database db:generate:oauth
pnpm -F @mcp-oauth/database db:generate:mcp
# Apply DB Migration
pnpm -F @mcp-oauth/oauth db:migrate:local # Local D1
pnpm -F @mcp-oauth/oauth db:migrate:remote # Cloudflare D1 (production)
pnpm -F @mcp-oauth/api-mcp db:migrate:local
pnpm -F @mcp-oauth/api-mcp db:migrate:remote
# Seed data
pnpm -F @mcp-oauth/database db:seed
# Deployment
pnpm -F @mcp-oauth/oauth deploy
pnpm -F @mcp-oauth/api-mcp deploy
pnpm -F @mcp-oauth/web deploy
```
## Infrastructure Configuration
```mermaid
graph TB
subgraph Clients["Clients"]
Browser["🌐 Browser <br/> (apps/web SPA)"]
Claude["🤖 Claude <br/> (MCP Client)"]
end
subgraph CF["☁️ Cloudflare"]
subgraph Workers["Workers"]
Web["apps/web<br/>React Router v7<br/>Static Assets"]
ApiMcp["apps/api-mcp<br/>MCP Server + BFF<br/>Hono + @hono/mcp"]
OAuth["apps/oauth<br/>OAuth 2.1 Server<br/>Hono + JWT(HS256)"]
end
subgraph D1["D1 (SQLite)"]
ApiMcpDB[("api-mcp-db<br/>app-specific data")]
OAuthDB[("oauth-db<br/>users / clients<br/>codes / tokens")]
end
end
subgraph Ext["External APIs (no key required)"]
Frankfurter["Frankfurter<br/>Exchange Rates"]
CoinGecko["CoinGecko<br/>Cryptocurrency"]
end
Browser -->|asset delivery| Web
Browser -->|Hono RPC /api/* <br/> /api/auth/token <br/> /api/auth/logout| ApiMcp
Browser -->|/authorize <br/> /logout| OAuth
Claude -->|GET/POST /mcp JWT Bearer| ApiMcp
ApiMcp -->|Service Binding| OAuth
ApiMcp --- ApiMcpDB
OAuth --- OAuthDB
ApiMcp -->|fetch| Frankfurter
ApiMcp -->|fetch| CoinGecko
style Browser fill:#dbeafe,stroke:#3b82f6
style Claude fill:#ede9fe,stroke:#7c3aed
style Web fill:#dcfce7,stroke:#16a34a
style ApiMcp fill:#dbeafe,stroke:#2563eb
style OAuth fill:#fce7f3,stroke:#db2777
style ApiMcpDB fill:#fef9c3,stroke:#ca8a04
style OAuthDB fill:#fef9c3,stroke:#ca8a04
style Frankfurter fill:#dcfce7,stroke:#16a34a
style CoinGecko fill:#dcfce7,stroke:#16a34a
```
## Endpoints
### OAuth Server (`apps/oauth`)
| Method | Path | Description |
|---------|------|------|
| GET | `/.well-known/oauth-authorization-server` | Discovery metadata |
| POST | `/register` | DCR (Claude executes automatically on first connection) |
| GET | `/authorize` | Login screen or consent screen (HTML) |
| POST | `/authorize/login` | Login processing and OAuth session cookie issuance |
| POST | `/authorize/consent` | Consent processing and authorization code issuance |
| POST | `/token` | Authorization code to token exchange / refresh |
| GET | `/logout` | OAuth session cookie deletion and redirect |
### api-mcp Server (`apps/api-mcp`)
| Method | Path | Authentication | Description |
|---------|------|------|------|
| GET | `/.well-known/oauth-protected-resource` | Not required | Discovery metadata |
| GET/POST | `/mcp` | JWT required | MCP endpoint (Streamable HTTP) |
| POST | `/api/auth/token` | Not required | Authorization code to token exchange BFF |
| POST | `/api/auth/refresh` | Cookie | Access token update BFF |
| POST | `/api/auth/logout` | Cookie | Logout BFF |
| GET | `/api/fx/rate` | JWT required | Exchange rates (USD/JPY, etc.) |
| GET | `/api/fx/convert` | JWT required | Currency conversion |
| GET | `/api/fx/history` | JWT required | Exchange rate history |
| GET | `/api/crypto/price` | JWT required | Cryptocurrency prices (BTC, etc.) |
| GET | `/api/crypto/market` | JWT required | Market data (market capitalization and fluctuation rate) |
| GET | `/api/crypto/history` | JWT required | Cryptocurrency history |
### MCP Primitives
| Type | Name | Description |
|------|------|------|
| Tool | `get_fx_rate` | Latest exchange rate between two currencies |
| Tool | `convert_currency` | Currency conversion of amount |
| Tool | `get_fx_history` | Get exchange rate transition for a specified period |
| Tool | `get_crypto_price` | Current price of cryptocurrency |
| Tool | `get_crypto_market` | Market data such as market capitalization and 24h fluctuation rate |
| Tool | `get_crypto_history` | OHLC chart data |
| Prompt | `daily_market_brief` | Summarize today's overview of major currencies and cryptocurrencies |
| Prompt | `crypto_deep_dive` | Analyze one brand from multiple perspectives |
### Web Screen (`apps/web`)
| Path | Screen | Authentication | Description |
|------|------|------|------|
| `/` | Dashboard | Required | Exchange and cryptocurrency rate display and logout |
| `/login` | Login start | Not required | PKCE generation → Redirect to OAuth server |
| `/auth/callback` | Callback | Not required | Authorization code reception → Token acquisition → Redirect to `/` |
## Tech Stack
- **Runtime**: Cloudflare Workers
- **Backend Framework**: Hono v4 (Hono RPC for type-safe API communication)
- **Frontend**: React Router v7 SPA (SSR: false) + Tailwind CSS v4
- **Database**: Cloudflare D1 (SQLite) + Drizzle ORM
- **Auth**: OAuth 2.1 + PKCE + DCR (JWT / HS256, access token 5 minutes)
- **Build**: Turborepo + pnpm workspaces
- **Lint/Format**: Biome
## Documents
| File | Content |
|---------|------|
| [docs/01-overview.md](./docs/01-overview.md) | System overview |
| [docs/02-oauth-flow.md](./docs/02-oauth-flow.md) | OAuth flow (PKCE + DCR + logout) |
| [docs/03-endpoints.md](./docs/03-endpoints.md) | Endpoint list and SPA implementation guide |
| [docs/04-database.md](./docs/04-database.md) | DB design |
| [docs/05-screens.md](./docs/05-screens.md) | Screen design (Tailwind CSS) |
| [docs/06-jwt-tokens.md](./docs/06-jwt-tokens.md) | JWT token design |
| [docs/07-implementation-plan.md](./docs/07-implementation-plan.md) | Implementation plan and checklist |
`docs/learning/` — OAuth flow and specification learning notes
Connection Info
You Might Also Like
Vibe-Trading
Vibe-Trading: Your Personal Trading Agent
ai-berkshire
Berkshire in the AI Era: A Value Investment Research Framework Based on...
hexstrike-ai
HexStrike AI is an AI-powered MCP cybersecurity automation platform with 150+ tools.
Train-in-Silence
The first Task-Aware MCP server and automated VRAM calculator for LLM...
stacklit
108,000 lines of code. 4,000 tokens of index. One command makes any repo...
AppClaw
AI-powered mobile automation agent — describe what you want in plain...