Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7ac9edb
Add WorkOS MCP auth gateway
dodeja Jun 12, 2026
af83ade
Update MCP OAuth gateway for connected clients
dodeja Jun 19, 2026
d0e0827
chore: Auto-generate Postman collection from openapi.json [skip ci]
github-actions[bot] Jun 19, 2026
d978a1a
Regenerate SDK auth docs
dodeja Jun 19, 2026
32ee482
fix(mcp): make WorkOS auth gateway spec-compliant (RFC 9728/8414/6750)
dodeja Jun 19, 2026
4a64050
chore: migrate lint/format from Biome to oxlint + oxfmt
dodeja Jun 19, 2026
6905311
docs: correct agent instructions to cover the MCP gateway and SDK
dodeja Jun 19, 2026
a2c8a9c
fix(ci): run SDK lint only on Node 24 (oxlint/oxfmt need Node 20+)
dodeja Jun 19, 2026
3b1977e
fix(mcp): map connected-client resolver outages to retryable 5xx
dodeja Jun 19, 2026
58dd5d0
docs(mcp): use Token scheme for API keys, reserve Bearer for OAuth
dodeja Jun 19, 2026
f2051aa
feat(mcp): add AS-metadata discovery redirect for non-PRM clients
dodeja Jun 19, 2026
50008a1
docs(mcp): standardize connector URL on root origin; add WorkOS setup…
dodeja Jun 19, 2026
13e3851
docs(mcp): add local dev guide for Claude Desktop tool testing
dodeja Jun 19, 2026
92059f3
docs(mcp): add Path 3 — testing the real WorkOS OAuth (MCP auth) locally
dodeja Jun 19, 2026
4309413
fix(mcp): only advertise OAuth discovery when WorkOS is configured
dodeja Jun 19, 2026
78273f3
fix(mcp): default OAuth test client to /mcp; make runbook smoke test …
dodeja Jun 19, 2026
57d51cf
docs(mcp): present the root origin as the canonical MCP endpoint
dodeja Jun 19, 2026
a1936c7
docs(mcp): show only the root connector URL, drop alias mentions
dodeja Jun 19, 2026
f48ccff
fix(mcp): gate OAuth discovery on AuthKit being enabled, not just con…
dodeja Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .env.local.example
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
# Local MCP gateway env for `vercel dev`. Copy to `.env.local` and edit.
# See packages/mcp/LOCAL_DEV.md for the full local testing guide.

# --- Passthrough mode (default; for tool testing via Claude → mcp-remote) ---
# Point at your local t49 server (Rails default :3000). Drop it to use prod.
T49_API_BASE_URL=http://localhost:3000/v2
# Leave T49_MCP_AUTHKIT_ENABLED unset so `Token <api-key>` passes straight through.

# --- Full WorkOS OAuth (optional; requires an HTTPS tunnel + local t49 resolve) ---
# T49_MCP_AUTHKIT_ENABLED=true
# WORKOS_AUTHORIZATION_SERVER_URL=https://<your-tenant>.authkit.app
# WORKOS_MCP_RESOURCE=https://<your-https-tunnel-url> # must equal the WorkOS Resource Indicator
# T49_CONNECTED_CLIENTS_RESOLVE_SECRET=<must match your local t49>

# --- Optional hardening / observability ---
# T49_MCP_ALLOWED_HOSTS=localhost:4000
# SENTRY_ENABLED=false
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ jobs:
test -z "$(git status --porcelain -- docs/sdk/reference)"
- name: Test SDK
run: npm test -- --run
- name: Lint SDK (Biome)
# oxlint/oxfmt require Node 20+; lint is static so it only needs one
# modern runtime. Build/test still cover the full matrix for consumers.
- name: Lint SDK (oxlint + oxfmt)
if: matrix.node-version == 24
run: npm run lint

mcp:
Expand All@@ -58,5 +61,5 @@ jobs:
run: npm run build --workspace @terminal49/mcp
- name: Test MCP
run: npm run test --workspace @terminal49/mcp -- --run --coverage
- name: Lint MCP (Biome)
- name: Lint MCP (oxlint + oxfmt)
run: npm run lint --workspace @terminal49/mcp
86 changes: 67 additions & 19 deletions AGENTS.md
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,92 @@
# Documentation Agent Instructions
# Terminal49 API Repository — Agent Instructions

> **This is a public repository.** Do not commit API keys, internal URLs, customer data, or any proprietary information. Use placeholders in all examples.
> **This is a public repository.** Do not commit API keys, secrets, internal URLs, customer data, or any proprietary information. Use placeholders in all examples (e.g. `Token YOUR_API_KEY`).

These instructions guide automated changes for the Terminal49 docs in this repository.
This repo is **not docs-only**. It contains three things that ship independently:

**For detailed writing standards, voice, terminology, and content guidelines, see [WRITING_GUIDE.md](WRITING_GUIDE.md).**
1. **Documentation** (`docs/`) — the Mintlify site and the OpenAPI source of truth.
2. **The Terminal49 MCP server + OAuth gateway** (`api/`, `packages/mcp/`) — deployed to **mcp.terminal49.com** on Vercel.
3. **The Terminal49 TypeScript SDK** (`sdks/typescript-sdk/`) — published to npm as `@terminal49/sdk`.

It is an **npm workspaces monorepo** (`packages/*`, `sdks/*`), Node 24. The root `package-lock.json` is the authoritative lockfile; `npm ci` (root) and Vercel both install from it.

> `CLAUDE.md` / `claude.md` are symlinks to this file. Edit `AGENTS.md` to change agent instructions.

For detailed docs writing standards, voice, and terminology, see [WRITING_GUIDE.md](WRITING_GUIDE.md) and [agent.md](agent.md).

---

## Project Structure

### Documentation (`docs/`)
- `docs/` holds the Mintlify site content and configuration.
- `docs/api-docs/`, `docs/datasync/`, `docs/sdk/`, `docs/mcp/`, and `docs/updates/` contain MDX pages grouped by product area.
- `docs/api-docs/`, `docs/datasync/`, `docs/sdk/`, `docs/mcp/`, `docs/updates/` contain MDX pages grouped by product area.
- `docs/docs.json` defines navigation, branding, and tabs.
- `docs/openapi.json` is the source of truth for API reference content.
- `docs/images/` and `assets/images/` store images used by MDX pages.
- `Terminal49-API.postman_collection.json` is generated from the OpenAPI spec — do not edit manually.

### MCP gateway (`api/`) — Vercel serverless functions
- `api/mcp.ts` — the MCP endpoint (Streamable HTTP transport, stateless). Handles caller auth: WorkOS AuthKit token resolution, env-token + client-secret mode, and pass-through.
- `api/oauth-protected-resource.ts` — RFC 9728 Protected Resource Metadata (`/.well-known/oauth-protected-resource`).
- `vercel.json` — routes (`/mcp`, `/.well-known/*`), function config, install/build commands. This is what deploys to mcp.terminal49.com.
- These import the server from `packages/mcp/src/`.

### MCP server (`packages/mcp/`) — `@terminal49/mcp`
- `src/server.ts` — `createTerminal49McpServer()`, built on `@modelcontextprotocol/sdk` (`McpServer`, `registerTool`/`registerResource`). Used by both the stdio entry (`src/index.ts`) and the `api/` HTTP gateway.
- `src/resource.ts` — **single source of truth** for the OAuth `resource` identifier. Both the PRM endpoint and the `WWW-Authenticate` challenge resolve through it so they can never diverge (RFC 9728). Do not reintroduce per-file resource derivation.
- `src/tools/`, `src/resources/` — MCP tools and resources.
- `tests/`, `src/**/*.test.ts` — vitest.

### TypeScript SDK (`sdks/typescript-sdk/`) — `@terminal49/sdk`
- `src/` — the client (JSON:API, openapi-fetch). `src/generated/**` is generated — **do not hand-edit**.

---

## Scope

- Primary docs live in `docs/` (MDX pages, `docs/docs.json`, and `docs/openapi.json`).
- Do not edit generated files unless explicitly asked (e.g., `Terminal49-API.postman_collection.json`).
- **Docs** live in `docs/` (MDX, `docs/docs.json`, `docs/openapi.json`).
- **Code** in `api/`, `packages/mcp/`, and `sdks/typescript-sdk/` is editable, but it is **deployed, public-facing infrastructure** — run the tests and lint before considering a change done.
- **Do not hand-edit generated files** unless explicitly asked:
- `Terminal49-API.postman_collection.json` (from `docs/openapi.json`)
- `sdks/typescript-sdk/src/generated/**` (from `docs/openapi.json` via `openapi-typescript`)
- `docs/sdk/reference/**` (generated SDK docs; CI checks they are up to date)

---

## Build and Development Commands

- Preview docs locally: `cd docs && mintlify dev`
- Generate Postman collection: `openapi2postmanv2 -s docs/openapi.json -o Terminal49-API.postman_collection.json -p -O folderStrategy=Tags`
### Docs
- Preview locally: `cd docs && mintlify dev`
- Lint the OpenAPI spec: `spectral lint --ruleset .spectral.mjs docs/openapi.json`
- Regenerate Postman: `openapi2postmanv2 -s docs/openapi.json -o Terminal49-API.postman_collection.json -p -O folderStrategy=Tags`

### Code (npm workspaces)
- Install: `npm ci` (root)
- Test: `npm run test --workspace @terminal49/mcp -- --run` · `npm run test --workspace @terminal49/sdk -- --run` (vitest)
- Typecheck / build: `npm run build --workspace @terminal49/mcp` · `--workspace @terminal49/sdk` (tsc). `api/` is typechecked by the root config: `npx tsc --noEmit -p tsconfig.json`.
- **Lint/format: oxlint + oxfmt** (migrated off Biome). `npm run lint --workspace <pkg>`; auto-format with `npm run format --workspace <pkg>` (oxfmt). Config: `.oxlintrc.json` + `.oxfmtrc.json` per package. The SDK lint also runs `oxfmt --check`; MCP is lint-only.
- CI (`.github/workflows/ci.yml`) runs build + test + lint for both packages.
- Running the MCP server locally + testing tool calls with Claude Desktop (stdio and gateway paths): [packages/mcp/LOCAL_DEV.md](packages/mcp/LOCAL_DEV.md). Gateway env template: `.env.local.example`.

---

## MCP Auth Gateway notes

## When Updating API Reference
- The gateway is an OAuth 2.1 **Resource Server**; **WorkOS** is the Authorization Server. Follow the MCP authorization spec (RFC 9728 / 8414 / 8707 / 6750).
- Token validation is delegated to the Terminal49 backend (`/connected-clients/resolve`); the backend must enforce the token audience. The gateway must not weaken the `WWW-Authenticate` challenge, the PRM document, or the resource resolver without checking the spec.
- Config is via env (`WORKOS_*`, `T49_MCP_*`). Never log tokens; return generic auth errors to clients and keep detail in server logs.
- The canonical connector URL and OAuth resource identifier is the **root origin** `https://mcp.terminal49.com` (pin `WORKOS_MCP_RESOURCE`); don't use the `/mcp` path in client config. Production/client setup (WorkOS dashboard, env vars, ChatGPT + Claude specifics) is in [packages/mcp/WORKOS_MCP_SETUP.md](packages/mcp/WORKOS_MCP_SETUP.md).

- If you change API behavior or schemas, update `docs/openapi.json` first.
- Regenerate the Postman collection with:
`openapi2postmanv2 -s docs/openapi.json -o Terminal49-API.postman_collection.json -p -O folderStrategy=Tags`
---

## Commit and Pull Request Guidelines

- Commit history favors conventional prefixes such as `docs:` and `chore:`.
- Do not manually edit `Terminal49-API.postman_collection.json`; update `docs/openapi.json` and regenerate.
- PRs should include a short summary, linked issue/ticket if available, and screenshots for doc UI changes.
- Commit history favors conventional prefixes: `docs:`, `chore:`, `feat:`, `fix:`.
- Keep docs changes, gateway/SDK code changes, and tooling changes in **separate commits** so reviews stay focused.
- Do not manually edit generated files; update the source and regenerate.
- PRs: short summary, linked issue/ticket if available, screenshots for doc UI changes.

## Security

- Never commit real API keys; use placeholders like `Token YOUR_API_KEY` in examples.
- Postman deployment uses repository secrets; keep local credentials in your environment only.
- Never commit real API keys or secrets; use placeholders like `Token YOUR_API_KEY`.
- The MCP gateway is public-facing — treat auth, the resource resolver, and the discovery endpoints as security-sensitive. Keep local credentials in your environment only.
Loading
Loading