Portal
Provides authentication integration with the lab's Keycloak OIDC provider, allowing members to sign in to the portal without passwords and enabling MCP tokens to act with the signed-in member's permissions.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Portalwho am I on the portal?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
██████╗ ██████╗ ██████╗ ████████╗ █████╗ ██╗
██╔══██╗██╔═══██╗██╔══██╗╚══██╔══╝██╔══██╗██║
██████╔╝██║ ██║██████╔╝ ██║ ███████║██║
██╔═══╝ ██║ ██║██╔══██╗ ██║ ██╔══██║██║
██║ ╚██████╔╝██║ ██║ ██║ ██║ ██║███████╗
╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝WinLab Portal
The lab's internal apps on one Postgres: sign in with Keycloak, and everything you can click is also an MCP tool.
nextjs · postgres · docker · mcp
WinLab members book rooms, file receipts, sign documents and open the lab door through one portal. This is its rewrite: plain Postgres instead of a hosted backend, one app at a time, and every action an agent can call as well as a member can click.
> "Who am I on the portal?"
⚡ whoami {}
✓ { "name": "王小明", "username": "ming", "email": "ming@example.com" }What it does
Signs members in with the lab's Keycloak (OIDC); there are no passwords here.
Defines each action once: a page and its MCP tool run the same code, so neither can drift.
Serves MCP at
/mcp, with the portal itself as the OAuth 2.1 authorization server (Client ID Metadata Documents, plus dynamic registration for older clients).
Related MCP server: Heavenly Health Protocol
Deploy
With Docker Compose, on any machine with Docker:
curl -fsSLO https://raw.githubusercontent.com/NYCU-WinLab/portal/main/compose.yaml
curl -fsSL -o .env https://raw.githubusercontent.com/NYCU-WinLab/portal/main/.env.example
# set POSTGRES_PASSWORD, BETTER_AUTH_URL, BETTER_AUTH_SECRET and the KEYCLOAK_* keys in .env
docker compose up -dThis starts Postgres, runs the migrations once, then serves the portal from ghcr.io/nycu-winlab/portal on 127.0.0.1:3000.
Put a reverse proxy with TLS in front, at the host inBETTER_AUTH_URL. MCP clients only accept an HTTPS resource, and the Keycloak redirect URI must match it.
Use
In your Keycloak realm, create a confidential OpenID Connect client with the redirect URI
<BETTER_AUTH_URL>/api/auth/callback/keycloak, and put its ID and secret in.env.Open
BETTER_AUTH_URLand sign in.Make the first portal admin, once, after that member has signed in (later admins are added on /admins):
docker compose exec postgres psql -U portal -d portal -c \ "insert into admins (user_id, app) select id, 'portal' from users where username = '<their account>'"Add the MCP server to a client, for example
claude mcp add --transport http portal <BETTER_AUTH_URL>/mcp, approve it on the consent page, then ask it to callwhoami.
Configure
Set these in .env; .env.example documents every one.
Key | What it sets | Default |
| The database password, used by every service | required |
| The public URL; the MCP resource is | required |
| Signs sessions and OAuth queries | required |
| The realm URL, e.g. | required |
| The portal's Keycloak client | required |
| Image tag |
|
| Where web listens on the host |
|
| OTLP/HTTP endpoint for traces and error logs; off when empty | empty |
How it works
flowchart LR
member[Member] -->|browser| pages[Pages]
agent[MCP client] -->|bearer token| mcp["/mcp"]
pages --> actions[Actions]
mcp --> actions
actions --> pg[(Postgres)]
member -->|sign in| kc[Keycloak]
mcp -. verifies against .-> as[Portal OAuth server]Keycloak proves who a member is; the portal keeps its own session and is the authorization server for MCP, so the lab-wide realm never opens client registration. An MCP token carries the member's id and acts with exactly their permissions. Only lib/actions, lib/auth and lib/db may touch the database, and CI checks that every action is in the registry the MCP tools are built from.
Develop
bun install
cp .env.example .env.local # point DATABASE_URL at a local Postgres
bun run db:migrate
bun run devCI runs typecheck, lint, format, the design token check, the action registry check and a build, then builds the image and probes a real docker compose up. Schema changes go through bun run db:generate; see CLAUDE.md for the conventions.
Limitations
Only the sign-in, member record and MCP surface exist so far; the apps move over from portal.winlab.tw one at a time.
One instance: DPoP replay records are in Postgres, but nothing else has been tried with more than one web container.
Contributing
Issues and PRs welcome: start with CONTRIBUTING.md.
License
MIT · made in a lab whose door has its own MCP tool
This server cannot be deployed
Maintenance
Related MCP Connectors
Appreciate teammates, celebrate milestones, and run workspace ops from MCP clients via OAuth.
- WoWSQLOAuthcom.wowsql
Managed Postgres MCP: projects, SQL, docs search, and storage buckets via OAuth.
Hosted MCP server with managed OAuth for 15+ toolkits: Google Workspace, Fitbit, Oura, Kalshi, etc.
MCP Hub: AI service discovery, per-user OAuth, and multi-service workflow orchestration
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA self-hostable MCP permissions gateway for legal-tech systems that connects legal apps once and exposes only the tools each team member should use, enforcing a thin policy and audit layer over vendor APIs.MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI clients to securely access, query, and mutate normalized user-controlled health data (e.g., from Apple Health or Supabase) through a bounded set of MCP tools, with optional OAuth and sandboxed deployment.MIT

eq-mcp-gatewayofficial
FlicenseNot gradedqualityBmaintenanceA remote MCP server that lets MCP clients self-register over OAuth 2.1 and call read-only tools for organization identity, place and region browsing, dashboards, metrics, and ranking, forwarding the caller's own Auth0 token so each service still sees the real user. It also exposes a bearer pass-through surface for first-party apps holding an existing token.-- AlicenseNot gradedqualityBmaintenanceEnables MCP-capable agents to coordinate through shared Postgres-backed state, including registrations, tickets, memories, and discussions, over authenticated streamable HTTP.MIT