Authentication determines how your MCP server gets credentials to access external services. Choose the right pattern based on who provides the credentials and how they should be managed.
| Type | Who provides credentials | Example |
|---|
| OAuth | User authorizes via OAuth flow | Linear, GitHub, Slack |
| Credentials | User enters in Gumstack UI | OpenAI API key, custom tokens |
| None | Developer sets via env vars | Shared API keys, public APIs |
Auth type cannot be changed after server creation. Choose carefully!
OAuth
Best for services where users need to connect their own accounts. Gumstack handles the OAuth flow, token storage, and automatic refresh—you just implement the provider.
When registering an OAuth application with the third-party service (e.g., Linear, GitHub, Slack), set the redirect / callback URL to:
https://api.gumstack.com/auth/callback
This is the URL Gumstack uses to receive the authorization code after a user approves access.
Implement AuthProvider
Create a class that defines how to authenticate with your service:
import os
from mcp.gumstack import AuthProvider, TokenResponse
class LinearAuthProvider(AuthProvider):
name = "linear"
def get_url(self, redirect_uri: str, state: str) -> str:
client_id = os.environ["LINEAR_CLIENT_ID"]
return f"https://linear.app/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&state={state}&response_type=code&scope=read,write"
async def exchange(self, code: str, redirect_uri: str) -> TokenResponse:
# Exchange code for tokens with Linear API
return TokenResponse(
access_token=response["access_token"],
refresh_token=response.get("refresh_token"),
expires_in=response.get("expires_in")
)
async def refresh(self, refresh_token: str) -> TokenResponse:
# Refresh expired token
return TokenResponse(access_token=new_token)
async def get_nickname(self, access_token: str) -> str:
# Display name for connected account
return "user@company.com"
Register with GumstackHost
Register your auth provider so Gumstack can use it:
from mcp.gumstack import GumstackHost
host = GumstackHost(mcp)
host.register_auth(LinearAuthProvider())
host.run()
Access the user’s credentials in your tools:
@mcp.tool()
async def list_issues() -> list[Issue]:
creds = await get_credentials()
token = creds["access_token"]
# Call Linear API with token
Credentials
Best for services that use API keys or tokens that users provide themselves. Users enter their credentials in the Gumstack UI, and Gumstack securely stores and provides them to your server.
Define the fields you need in config.yaml:
auth:
type: cred
credentials:
- name: "api_key"
label: "API Key"
description: "Your OpenAI API key"
placeholder: "sk-..."
secret: true
Then access them in your tools:
@mcp.tool()
async def generate(prompt: str) -> str:
creds = await get_credentials()
api_key = creds["api_key"]
# Call OpenAI API
None (Environment Variables)
Best for shared API keys that you (the developer) provide, or for public APIs that don’t require user-specific credentials. You set the credentials once in the Gumstack dashboard, and they’re available to all users.
Set your credentials in the Gumstack dashboard under Environment Variables, then access them in your tools:
@mcp.tool()
def get_weather(city: str) -> Weather:
creds = get_credentials() # Note: sync, not async
api_key = creds["api_key"]
# Call weather API
With auth.type: none, get_credentials() is synchronous and reads directly
from environment variables.
Reserved Environment Variables
Gumstack reserves certain environment variable prefixes for internal use. These will be rejected if you try to use them: