metalab-mcp-client
v1.3.0
Published
MCP client for connecting to Metalab's MCP Gateway with OAuth 2.1 authentication
Maintainers
Readme
metalab-mcp-client
Connect your AI assistant to Metalab's MCP services - Figma, Notion, Jira, and more.
This package is a local OAuth 2.1 proxy that enables MCP clients (Claude Desktop, Claude Code, Windsurf, Cursor, etc.) to securely connect to Metalab's MCP Gateway. It handles authentication via Okta, manages tokens, and forwards your requests to backend services.
flowchart LR
A["Your AI Tool<br/>(Claude, etc.)"] -->|stdio| B["mcp-client<br/>(this package)"]
B -->|"HTTPS + OAuth"| C["MCP Gateway<br/>(Figma, Notion, Jira)"]Quick Start
# Run directly - zero config needed!
npx metalab-mcp-client
# Generate config for your MCP client
npx metalab-mcp-client config --client claudeOn first run, your browser will open for Okta authentication. Once authenticated, you can start using MCP tools in your AI assistant.
Installation
The package is published on npmjs.org (public, no authentication needed).
# Run directly with npx (recommended)
npx metalab-mcp-client
# Or install globally
npm install -g metalab-mcp-client
metalab-mcpNote on Package Name
This package was previously published as @metalabdesign/mcp-client. It was renamed to metalab-mcp-client (non-scoped) to avoid registry conflicts with project-level .npmrc files that redirect @metalabdesign packages to GitHub Packages.
If you're upgrading from the old package, update your MCP client configs to use metalab-mcp-client instead of @metalabdesign/mcp-client.
MCP Client Configuration
Claude Desktop (Recommended)
Option 1: Auto-generate config
npx metalab-mcp-client config --client claude --outputOption 2: Manual configuration
Add to your Claude Desktop config file:
| Platform | Config File Location |
| -------- | ----------------------------------------------------------------- |
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
{
"mcpServers": {
"metalab": {
"command": "npx",
"args": ["metalab-mcp-client"]
}
}
}With service tokens (for Figma, Notion, Jira, GitHub, Slack access):
{
"mcpServers": {
"metalab": {
"command": "npx",
"args": ["metalab-mcp-client"],
"env": {
"FIGMA_ACCESS_TOKEN": "figd_YOUR_TOKEN_HERE",
"NOTION_ACCESS_TOKEN": "secret_YOUR_TOKEN_HERE",
"JIRA_API_TOKEN": "YOUR_JIRA_API_TOKEN",
"JIRA_EMAIL": "[email protected]",
"JIRA_INSTANCE_URL": "https://company.atlassian.net",
"GITHUB_TOKEN": "ghp_YOUR_TOKEN_HERE",
"SLACK_MCP_XOXB_TOKEN": "xoxb-YOUR_BOT_TOKEN_HERE"
}
}
}
}Claude Code
Option 1: Use claude mcp add command (recommended)
# Basic installation
claude mcp add metalab --scope user -- npx metalab-mcp-client
# With service tokens
claude mcp add metalab --scope user \
-e "FIGMA_ACCESS_TOKEN=figd_YOUR_TOKEN" \
-e "NOTION_ACCESS_TOKEN=secret_YOUR_TOKEN" \
-e "JIRA_API_TOKEN=YOUR_JIRA_TOKEN" \
-e "[email protected]" \
-e "JIRA_INSTANCE_URL=https://company.atlassian.net" \
-e "GITHUB_TOKEN=ghp_YOUR_TOKEN" \
-e "SLACK_MCP_XOXB_TOKEN=xoxb-YOUR_TOKEN" \
-- npx metalab-mcp-clientOption 2: Manual configuration
Add to ~/.claude.json:
{
"mcpServers": {
"metalab": {
"command": "npx",
"args": ["metalab-mcp-client"],
"env": {
"FIGMA_ACCESS_TOKEN": "figd_YOUR_TOKEN_HERE"
}
}
}
}Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"metalab": {
"command": "npx",
"args": ["metalab-mcp-client"],
"env": {
"FIGMA_ACCESS_TOKEN": "figd_YOUR_TOKEN_HERE"
}
}
}
}Cursor
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"metalab": {
"command": "npx",
"args": ["metalab-mcp-client"],
"env": {
"FIGMA_ACCESS_TOKEN": "figd_YOUR_TOKEN_HERE"
}
}
}
}Cline (VS Code)
Add to .vscode/cline_mcp_settings.json in your project:
{
"mcpServers": {
"metalab": {
"command": "npx",
"args": ["metalab-mcp-client"],
"env": {
"FIGMA_ACCESS_TOKEN": "figd_YOUR_TOKEN_HERE"
}
}
}
}Using Development Environment
For testing against the dev gateway, add the --dev flag:
{
"mcpServers": {
"metalab-dev": {
"command": "npx",
"args": ["metalab-mcp-client", "--dev"]
}
}
}Service Tokens
Each MCP service requires a personal access token for authentication. The tokens you provide are forwarded to the respective service APIs.
| Service | Required Credentials | How to Provide |
| ---------- | -------------------------------- | ------------------------------------------------------ |
| Figma | Access Token | FIGMA_ACCESS_TOKEN env var or --figma-token flag |
| Notion | Integration Secret | NOTION_ACCESS_TOKEN env var or --notion-token flag |
| Jira | API Token + Email + Instance URL | See Jira section below |
| GitHub | Personal Access Token | GITHUB_TOKEN env var or --github-token flag |
| Slack | Bot or User Token | SLACK_MCP_XOXB_TOKEN env var or --slack-token flag |
Getting Your Figma Token
- Log in to your Figma account
- From the file browser, click your account menu (top-left corner) and select Settings
- Select the Security tab
- Scroll to Personal access tokens and click Generate new token
- Enter a descriptive name (e.g., "MCP Integration")
- Configure scopes (permissions):
- File content: Read-only (required for all MCP tools)
- No write permissions needed
- Copy the token immediately (starts with
figd_)
Important: The token only displays once after generation. If you navigate away, you'll need to create a new one.
Token format: figd_XXXXXXXXXXXXXXXXXXXXX
Required Scopes: The MCP tools only perform read operations (fetching design data, downloading images, searching nodes). Your token needs read access to files you want to work with.
Getting Your Notion Token
- Log in to your Notion workspace
- Go to the integrations dashboard at https://www.notion.so/profile/integrations
- Click + New integration
- Configure the integration:
- Name: Give it a descriptive name (e.g., "MCP Integration")
- Associated workspace: Select your workspace
- Capabilities (required permissions):
- Read content: Required for reading pages, databases, and blocks
- Read comments: Required for retrieving comments
- Insert content: Optional, for creating pages/blocks
- Update content: Optional, for updating pages/blocks
- Click Submit to create the integration
- Go to the Configuration tab and copy the Internal Integration Secret (starts with
secret_)
Important: Store your token securely using environment variables. Never commit it to version control.
Token format: secret_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Required Capabilities: At minimum, enable Read content and Read comments. Enable Insert content and Update content only if you need write operations.
Important: After creating the integration, you must share pages/databases with it:
- Open the page or database you want to access
- Click ••• (more menu) in the top-right corner
- Click + Add connections
- Search for and select your integration
Getting Your Jira Token
Jira requires three pieces of information:
- API Token: Generated from Atlassian
- Email: Your Atlassian account email (optional - auto-derived from Okta if not provided)
- Instance URL: Your Jira Cloud URL
Steps to get your API token:
- Go to https://id.atlassian.com/manage-profile/security/api-tokens
- Click Create API token (or Create API token with scopes for enhanced security)
- Give it a descriptive label (e.g., "Metalab MCP Access")
- Set the expiration (default is 1 year, max 365 days)
- If using scopes, select the Jira app and permissions:
- Read: Required for searching issues, viewing projects, boards, sprints
- Write: Optional, for creating/updating issues, transitions, comments
- Click Create and copy the token immediately
Important: You cannot recover the token after this step. Store it securely.
Required Permissions: The API token inherits your Jira account permissions. You can only access projects and issues that your account has access to. For read operations (search, view), standard user access is sufficient. For write operations (create, update, transition), you need the appropriate project permissions.
Configuration example:
{
"env": {
"JIRA_API_TOKEN": "ATATT3xFfGF0...",
"JIRA_EMAIL": "[email protected]",
"JIRA_INSTANCE_URL": "https://company.atlassian.net"
}
}Note: The JIRA_EMAIL is optional. If not provided, the gateway uses your authenticated Okta email.
Getting Your GitHub Token
GitHub tokens enable access to private repositories (guides/skills) and authenticated GitHub API calls for dev-context tools like get_recent_changes, get_pr_context, compare_branches, etc.
Required Repository Access
Your GitHub token must have read access to all repositories you want to work with:
| Use Case | Required Repo Access |
| ----------------- | ------------------------------------------------------------------------------- |
| Guides & Skills | metalabdesign/librarian-dev-ai-assistants |
| Dev Context Tools | Any repository you query (e.g., metalabdesign/web-app, yourorg/backend-api) |
Important: Dev context tools make API calls to whatever
owner/repoyou specify in the tool parameters. Your token must have access to those repositories.
Creating a Token
For Personal Access Tokens (Classic):
- Go to GitHub > Settings > Developer settings > Personal access tokens > Tokens (classic)
- Click Generate new token, then select Generate new token (classic)
- Give it a descriptive name in the "Note" field (e.g., "Metalab MCP Access")
- Set an expiration date (recommended for security)
- Select scopes:
repo- Full control of private repositories (read access to code, commits, PRs)- Or
public_repo- If only working with public repositories
- Click Generate token and copy it immediately
For Fine-Grained Personal Access Tokens (recommended):
- Go to GitHub > Settings > Developer settings > Personal access tokens > Fine-grained tokens
- Click Generate new token
- Give it a descriptive name (e.g., "Metalab MCP Access")
- Set an expiration date
- Select a resource owner (your user or an organization)
- Select repository access:
- All repositories (simplest, works with any repo)
- Or Only select repositories (more secure, but must include all repos you'll query)
- Set permissions:
- Contents: Read (for commits, branches, file content)
- Pull requests: Read (for PR context, reviews, comments)
- Metadata: Read (required by default)
- Click Generate token and copy it immediately
Token format: ghp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (classic) or github_pat_XXXXXX... (fine-grained)
Configuration example:
{
"env": {
"GITHUB_TOKEN": "ghp_YOUR_TOKEN_HERE"
}
}Or via CLI:
metalab-mcp --github-token ghp_YOUR_TOKEN_HEREGetting Your Slack Token
Slack tokens enable access to workspace channels, messages, threads, and search. Two types of tokens are supported:
- Bot tokens (xoxb-): For basic operations (list channels, read messages, post messages)
- User tokens (xoxp-): Required for search functionality
Important: When you provide a token, it's used for all operations. There is no per-operation fallback. If you need search, your user token must also have all other required scopes.
Option 1: Bot Token Only (No Search)
Use this if you don't need search functionality:
- Go to https://api.slack.com/apps
- Click Create New App > From scratch
- Give it a name and select your workspace
- Go to OAuth & Permissions in the sidebar
- Under Scopes > Bot Token Scopes, add the required scopes (see table below)
- Click Install to Workspace at the top
- Copy the Bot User OAuth Token (starts with
xoxb-)
Token format: xoxb-XXXXXXXXXXXXX-XXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXX
Option 2: User Token with Full Access (Including Search)
Use this if you need search functionality. The user token must have all scopes:
- In your Slack App settings, go to OAuth & Permissions
- Under User Token Scopes, add the required scopes (see table below)
- Click Install to Workspace (or Reinstall if already installed)
- Copy the User OAuth Token (starts with
xoxp-)
Required Scopes Reference
| Scope | Purpose | Bot Token | User Token |
|-------|---------|-----------|------------|
| channels:read | List public channels | Required | Required |
| channels:history | Read public channel messages | Required | Required |
| groups:read | List private channels | Required | Required |
| groups:history | Read private channel messages | Required | Required |
| users:read | List workspace users | Required | Required |
| search:read | Search messages across workspace | Not available | Required for search |
| im:read | List direct messages | Optional | Optional |
| im:history | Read direct messages | Optional | Optional |
| chat:write | Post messages | Optional (write) | Optional (write) |
| reactions:write | Add emoji reactions | Optional (write) | Optional (write) |
Note: Bot tokens cannot use search:read - this is a Slack API limitation. If you need search functionality, you must use a user token
Configuration example:
{
"env": {
"SLACK_MCP_XOXB_TOKEN": "xoxb-YOUR_BOT_TOKEN_HERE"
}
}Or via CLI:
metalab-mcp --slack-token xoxb-YOUR_TOKEN_HERECLI Reference
Commands
metalab-mcp (default)
Connect to the MCP Gateway.
metalab-mcp [options]| Option | Description | Default |
| ------------------------ | --------------------------------------- | ------------------------- |
| --gateway-url <url> | Explicit gateway URL (highest priority) | Auto-detected |
| --prod | Use production environment | Default |
| --dev | Use development environment | - |
| --profile <name> | AWS profile for SSM lookup | Default profile |
| --figma-token <token> | Figma access token | FIGMA_ACCESS_TOKEN env |
| --notion-token <token> | Notion access token | NOTION_ACCESS_TOKEN env |
| --jira-token <token> | Jira API token | JIRA_API_TOKEN env |
| --jira-email <email> | Jira account email | JIRA_EMAIL env |
| --jira-instance <url> | Jira instance URL | JIRA_INSTANCE_URL env |
| --github-token <token> | GitHub personal access token | GITHUB_TOKEN env |
| --slack-token <token> | Slack bot or user token | SLACK_MCP_XOXB_TOKEN env |
| --inspect | Run with MCP Inspector | false |
| -h, --help | Show help | - |
Examples:
# Basic usage (production, auto-detects gateway URL)
metalab-mcp
# Use development environment
metalab-mcp --dev
# With Figma token
metalab-mcp --figma-token figd_YOUR_TOKEN
# With MCP Inspector for debugging
metalab-mcp --inspect
# Using environment variables
FIGMA_ACCESS_TOKEN=figd_YOUR_TOKEN metalab-mcpmetalab-mcp config
Generate configuration for MCP clients.
metalab-mcp config [options]| Option | Description |
| ------------------------ | --------------------------------------------------------------------- |
| --client <name> | Target client: claude, claude-code, windsurf, cursor, cline |
| --output | Write directly to client's config file |
| --figma-token <token> | Include Figma token in config |
| --notion-token <token> | Include Notion token in config |
| --jira-token <token> | Include Jira token in config |
| --slack-token <token> | Include Slack token in config |
Examples:
# Interactive mode
metalab-mcp config
# Generate config for Claude Desktop
metalab-mcp config --client claude
# Write directly to Claude Desktop config
metalab-mcp config --client claude --output
# Include tokens in generated config
metalab-mcp config --client claude --figma-token figd_YOUR_TOKENGateway URL Resolution
The gateway URL is resolved in this priority order:
--gateway-urloption (highest priority)- AWS SSM Parameter Store (environment-specific path)
MCP_SERVER_URLenvironment variable- Hardcoded URL for the environment (fallback)
How It Works
Architecture
sequenceDiagram
participant Client as MCP Client<br/>(Claude, etc.)
participant Proxy as mcp-client<br/>(this package)
participant Gateway as MCP Gateway
participant Services as MCP Services<br/>(Figma, Notion, Jira)
Client->>Proxy: stdio
Note over Proxy: First request triggers<br/>OAuth authentication
Proxy->>Gateway: HTTPS + Bearer Token
Note over Gateway: Validates token,<br/>routes by tool prefix
Gateway->>Services: Forward request
Services-->>Gateway: Response
Gateway-->>Proxy: MCP response
Proxy-->>Client: stdioKey Features
- OAuth 2.1 with PKCE: Secure authentication via Okta with browser-based login
- Token Management: Automatically persists and refreshes access tokens
- Lazy Connection: Only connects to gateway when first MCP request is made
- Service Token Forwarding: Your personal tokens (Figma, Notion, Jira) are forwarded as HTTP headers
- Multiple Environments: Supports production and development gateways
- Automatic Session Recovery: Detects session expiration and reconnects automatically (see below)
Automatic Session Recovery
Gateway sessions expire after a period of inactivity (default: 1 hour). When this happens, the proxy automatically:
- Detects the session error (e.g., "session not found", "internal server error")
- Resets the connection and establishes a new session
- Retries the failed request once
This means you don't need to restart Claude Code when sessions expire - the proxy handles reconnection transparently.
Rate limiting: To prevent masking real server errors, only one reconnection attempt is allowed every 10 minutes. If errors persist after reconnection, subsequent requests will fail until the cooldown period passes.
Token Flow
flowchart LR
subgraph Client["mcp-client (with tokens)"]
Tokens["X-Figma-Token<br/>X-Notion-Token<br/>X-Jira-Token<br/>X-Slack-Token"]
end
subgraph Gateway["MCP Gateway (forwards)"]
Forward["Routes tokens<br/>to services"]
end
subgraph Services["MCP Services"]
Figma["Figma MCP"]
Notion["Notion MCP"]
Jira["Jira MCP"]
Slack["Slack MCP"]
end
Client -->|"Headers"| Gateway
Gateway --> Figma
Gateway --> Notion
Gateway --> Jira
Gateway --> SlackYour service tokens are included in every request to the gateway, which forwards them to the appropriate downstream service.
Security
- PKCE: Uses SHA-256 code challenge for OAuth 2.1
- Token Storage: Tokens stored with 0600 permissions (owner read/write only) in
~/.metalab/mcp-local-proxy/tokens/ - Localhost Binding: OAuth callback server binds to 127.0.0.1 only
- Gateway Protected: MCP Gateway requires Okta authentication
- Public Package: Safe because gateway still requires authentication
AWS SSO Integration
For automatic gateway URL discovery via SSM Parameter Store:
# Configure AWS SSO profile
aws configure sso --profile metalab-dev
# Log in
aws sso login --profile metalab-dev
# Now mcp-client will auto-detect the gateway URL
metalab-mcp --profile metalab-devSSM Parameter Paths:
- Production:
/mcp/gateway-url(us-east-1) - Development:
/mcp/gateway-url(us-east-2)
Troubleshooting
"No Figma/Notion/Jira access token available"
Cause: No token provided
Solution: Add the token to your MCP client config's env section or pass via CLI flag.
OAuth callback timeout (5 minutes)
Cause: Browser didn't complete authentication in time
Solutions:
- Ensure your browser opened the Okta login page
- Complete authentication within 5 minutes
- Check if port 9876 is available (or the port in your callback URL)
Token refresh fails
Cause: Refresh token expired or invalid
Solution: Clear stored tokens and re-authenticate:
rm -rf ~/.metalab/mcp-local-proxy/tokens/*Port already in use
Cause: Another process is using the OAuth callback port
Solutions:
- Kill the process using the port:
lsof -ti:9876 | xargs kill -9 - Use a different callback URL:
--callback-url http://localhost:9877/callback
Tools not showing up
Cause: No token configured for that service
Expected behavior: Tools only appear when you have a valid token for the service
Solution: Configure your personal token for the service you want to use
Development
Requirements
- Node.js 20 or later
- (Optional) AWS CLI for SSM-based gateway URL discovery
Building
# Install dependencies
pnpm install
# Build TypeScript
pnpm run build
# Watch mode
pnpm run devTesting Locally
# Build and run CLI
pnpm run build
node dist/bin/cli.js --dev --inspectPublishing
# Build and publish
pnpm run build
npm publish --access publicLicense
MIT
