https://github.com/workos/pipes-mcp
A sample MCP server with human-approved, provider-scoped access to third-party APIs using WorkOS Pipes.
https://github.com/workos/pipes-mcp
Last synced: 6 days ago
JSON representation
A sample MCP server with human-approved, provider-scoped access to third-party APIs using WorkOS Pipes.
- Host: GitHub
- URL: https://github.com/workos/pipes-mcp
- Owner: workos
- License: mit
- Created: 2026-03-12T18:58:11.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-04-28T18:34:51.000Z (about 2 months ago)
- Last Synced: 2026-04-28T20:29:05.017Z (about 2 months ago)
- Language: TypeScript
- Homepage: https://workos.com/docs/pipes
- Size: 171 KB
- Stars: 22
- Watchers: 1
- Forks: 2
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# Pipes MCP Template
A starter template for building an MCP server with human-approved, provider-scoped access to third-party APIs using [WorkOS Pipes](https://workos.com/docs/pipes). It shows one way to let AI assistants securely interact with services like Linear, Notion, Snowflake, and more with a human in the loop, without trying to prescribe the full deployment story or how approval requests should be delivered.
## What's included
- **Human-in-the-loop approval flow** — AI assistants request access, humans approve via a browser-based consent screen
- **Provider-scoped authority** — humans select exactly which integrations to authorize (not all-or-nothing)
- **Unified authority grants** — broad and per-request approvals share one `AuthorityGrant` model
- **Time-limited sessions** — authority expires after 5 minutes, configurable
- **Read/write gating** — read and write operations are gated separately
- **Approval polling** — assistants poll for results and receive user instructions
## The approval flow
```mermaid
sequenceDiagram
participant AI as AI Assistant
participant Server as This Server
participant Human as Human
AI->>Server: request_elevated_access
(reason, providers)
Server-->>AI: approval URL + request ID
AI->>Human: "Open this URL"
Human->>Server: select providers
Human->>Server: add notes (optional)
Human->>Server: approve / deny
AI->>Server: check_access_request
Server-->>AI: approved + providers
Server-->>AI: user instructions
AI->>Server: call_integration_api
Server-->>AI: API response
```
Broad authority and per-request approval now use the same underlying grant record:
- `kind: "broad"` grants temporary session authority for selected providers
- `kind: "request"` approves one exact API call and is consumed on execution
## Authorization structure
Every MCP request is authenticated first, then authorized from the current Pipes session and grant state:
1. `app/[transport]/route.ts` requires AuthKit authentication for every MCP request.
2. `lib/mcp/with-authkit.ts` verifies the bearer token, loads the WorkOS user, and loads or creates a Redis-backed `PipesSession` keyed by `sid + organizationId`.
3. Effective MCP scopes are derived from the session's current broad authority, not directly from JWT claims.
4. `request_elevated_access` creates pending `AuthorityGrant` records:
- broad grants request temporary `read` or `write` authority for selected providers
- request grants store the exact `url`, `method`, and optional `body` for one API call
5. The approval UI resolves that grant:
- approved broad grants become `session.activeGrant`
- approved request grants stay in Redis as single-use approved grants
6. `call_integration_api` enforces access by either:
- checking the active broad grant for read/write level and provider access
- or consuming a matching approved request grant bound to the same `sid`, `userId`, and `organizationId`
## Quick start
### Prerequisites
- Node.js 20+
- [pnpm](https://pnpm.io/)
- Redis
- A [WorkOS](https://workos.com) account with AuthKit and Pipes configured
### 1. Install dependencies
```bash
pnpm install
```
### 2. Start Redis
Redis is required for session and approval state storage.
```bash
# macOS (Homebrew)
brew install redis
brew services start redis
# Docker
docker run -d -p 6379:6379 redis
# Or run directly
redis-server
```
Verify it's running:
```bash
redis-cli ping
# PONG
```
### 3. Configure environment
```bash
cp .env.local.example .env.local
```
Fill in your values:
```bash
WORKOS_API_KEY=sk_test_...
WORKOS_CLIENT_ID=client_...
WORKOS_COOKIE_PASSWORD=
WORKOS_REDIRECT_URI=http://localhost:5711/callback
AUTHKIT_DOMAIN=auth.workos.com
REDIS_URL=redis://127.0.0.1:6379
```
Optional tuning:
```bash
SESSION_TTL_MS=604800000 # Session store TTL (default: 7 days)
SESSION_AUTHORITY_TTL_MS=300000 # Authority expiry (default: 5 minutes)
```
### 4. Start the dev server
```bash
pnpm dev
```
The server starts at `http://localhost:5711`.
## Connecting an MCP client
Point your MCP client (Claude Code, Claude Desktop, Cursor, etc.) at the server URL. The server uses Streamable HTTP transport at `http://localhost:5711/mcp`.
## Adding a new provider
1. Add a new provider module in `lib/mcp/providers/` that exports a `ProviderDefinition`
2. Implement `matchesUrl`, `buildHeaders`, and, if needed, `isWriteOperation` for provider-specific write detection
3. Register the provider in `lib/mcp/providers/index.ts`
4. Update `lib/mcp/token-injection.ts` only if the provider needs auth behavior beyond the default Bearer token injection
5. Configure the integration in your WorkOS dashboard
The `call_integration_api` tool auto-detects the provider from the API URL domain and injects the correct authentication headers.
## Redis keys
| Key pattern | Data | TTL |
|-------------|------|-----|
| `pipes:mcp:session:{sid}:{orgId}` | Stored session record with active broad, pending broad, and active request grant IDs | Default 7 days; may be deleted earlier if idle |
| `pipes:mcp:authority-grant:{id}` | Unified broad/request grant record in `pending`, `approved`, or `denied` state | Up to 5 min; preserved as remaining grant lifetime after resolution |
| `pipes:mcp:approval-token:{jti}` | One-time approval-token consumption guard (not the encrypted token itself) | Remaining approval-token lifetime, up to 5 min |
## Development
```bash
pnpm dev # Start dev server (Turbopack)
pnpm typecheck # Type check
pnpm lint # Lint (Biome)
pnpm format # Format (Biome)
```
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on how to contribute to this project.
## License
MIT License. See [LICENSE](LICENSE) for details.