spekoai-mcp
Model Context Protocol server for SpekoAI — a thin wrapper
over the spekoai Python SDK that exposes
voice-AI session and usage tools to MCP clients (Claude Desktop, Cursor, etc.).
A hosted version is available at https://mcp.speko.ai. You can also run it
locally over stdio for development.
Tools
| Tool | Description |
|---|---|
get_usage_summary | Get usage summary for the current billing period. |
The tool surface mirrors spekoai.AsyncSpekoAI — more tools land here as
the SDK grows.
Local development (stdio)
uv run --with spekoai-mcp -- spekoai-mcp --stdio
Set SPEKOAI_API_KEY (and optionally SPEKOAI_BASE_URL) in the environment.
Wire into Claude Desktop's MCP config:
{
"mcpServers": {
"spekoai": {
"command": "uv",
"args": ["run", "--with", "spekoai-mcp", "--", "spekoai-mcp", "--stdio"],
"env": { "SPEKOAI_API_KEY": "sk_test_..." }
}
}
}
HTTP (production)
HTTP mode requires OAuth. Set:
SPEKOAI_OAUTH_ISSUERSPEKOAI_OAUTH_CLIENT_IDSPEKOAI_OAUTH_CLIENT_SECRETSPEKOAI_MCP_BASE_URL(defaults tohttps://mcp.speko.ai)
Then:
uv run spekoai-mcp # HTTP on 0.0.0.0:8080
uv run spekoai-mcp --host 127.0.0.1 --port 9000
The server fails to start in HTTP mode if OAuth env vars are missing — this prevents accidentally serving an unauthenticated public endpoint.
Deriving the OAuth env vars
The SpekoAI platform is its own OAuth 2.1 / OIDC issuer (Better Auth's
@better-auth/oauth-provider plugin, see apps/server/src/lib/auth.ts).
The endpoints live under /api/auth/oauth2/* on the dashboard origin,
which rewrites through to the server.
For a deployment where the dashboard is https://platform.speko.ai:
SPEKOAI_OAUTH_ISSUER=https://platform.speko.ai/api/auth/oauth2
SPEKOAI_MCP_BASE_URL=https://mcp.speko.ai
Note: two different "issuer" values. FastMCP's OAuthProxy appends
/authorize and /token to SPEKOAI_OAUTH_ISSUER, so this env var must
end at the /oauth2 segment — no trailing slash. That is not the OIDC
spec iss claim. The OIDC spec issuer (and the iss value inside tokens
emitted by the platform) is https://platform.speko.ai/api/auth — one
segment shorter, matching where Better Auth mounts the discovery document.
Same host, different paths.
To mint SPEKOAI_OAUTH_CLIENT_ID / SPEKOAI_OAUTH_CLIENT_SECRET, register
the MCP server as an OAuth client against the platform. From a checkout of
github.com/SpekoAI/platform, with apps/server/.env pointing at the
target database:
bun --env-file=apps/server/.env \
apps/server/scripts/register-oauth-client.ts \
--name "SpekoAI MCP (staging)" \
--redirect-uri https://mcp-staging.speko.dev/auth/callback
The redirect URI must match FastMCP OAuthProxy's callback path, which is
/auth/callback (not /oauth/callback). Platform-staging will reject the
upstream authorize request with invalid_redirect if the registered URI
doesn't match.
The script prints:
{ "client_id": "...", "client_secret": "..." }
The secret is returned once — store it somewhere durable (Cloud Run secret, 1Password, etc.). You can also hit the public endpoint directly:
curl -X POST https://platform-staging.speko.dev/api/auth/oauth2/register \
-H "Content-Type: application/json" \
-H "Origin: https://platform-staging.speko.dev" \
-H "Cookie: __Secure-better-auth.session_token=<paste_your_cookie_val>" \
-d '{
"client_name": "SpekoAI MCP (staging)",
"redirect_uris": ["https://mcp-staging.speko.dev/auth/callback"],
"token_endpoint_auth_method": "client_secret_basic",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "openid profile email"
}'
allowUnauthenticatedClientRegistration: true only opens registration for
public clients (token_endpoint_auth_method: "none", PKCE-only).
Registering a confidential client via the public endpoint requires a
logged-in user session — hence the Cookie and Origin headers above.
Authenticate at the dashboard, grab the session cookie from DevTools, then
POST. Client secrets are stored hashed, so a DB breach doesn't leak
plaintext.
If you already have a client row and only need to tweak its redirect URIs (e.g. adding a local MCP Inspector callback for testing), patch the row directly — the public endpoint is create-only:
UPDATE oauth_client
SET redirect_uris = array_append(redirect_uris, 'https://mcp-staging.speko.dev/auth/callback')
WHERE client_id = '<client-id>';
Once the MCP client is registered, add its client_id to
SPEKOAI_TRUSTED_CLIENT_IDS on the server so users skip the consent screen
for this first-party client. OAuth 2.1 requires PKCE, which FastMCP
OAuthProxy performs automatically.