Mistral Vibe Upwork MCP Server Setup with OAuth — Why the Docs Are Wrong and How to Fix It
If you’ve tried to connect Mistral Vibe to the Upwork MCP server and hit a wall, you’ve probably read the official documentation on MCP servers and come away confused. It states:
Known limitation: the CLI does not yet support MCP servers that require OAuth authentication. Use the stdio or http transport with an API key or other static credential.
That statement is out of date. OAuth is fully implemented and working in Vibe today. The confusion stems from stale docs and a config gap that’s easy to miss. Here’s how to get the Upwork MCP server connected with OAuth in Vibe, what the docs get wrong, and why the fix is simpler than you think.
The documentation gap: what the docs say vs. what the code does
The Mistral docs claim OAuth for MCP servers isn’t supported. The actual code tells a different story. In the current Vibe repository (commit 6c79ef0, Sep 4, 2026), OAuth support is complete and production-ready:
vibe/core/auth/mcp_oauth.py— full PKCE authorization-code flow, loopback callback server, OS-keyring token storage, refresh-aware handling, dynamic client registration (DCR) supportvibe/cli/textual_ui/widgets/mcp_oauth_app.py— the textual UI widget for the login flow
So why the disconnect? The docs are stale, and there’s a subtle configuration detail that tripped up early attempts — including mine.
The actual blocker: missing auth block in .vibe/config.toml
If your Upwork MCP server shows as “enabled, no tools” in Vibe, it’s not because OAuth is unsupported. It’s because your [[mcp_servers]] entry is missing the [mcp_servers.auth] block entirely. When that block is absent, Vibe defaults to MCPStaticAuth (empty, no token). The code that would auto-promote a server to OAuth on a 401 response — _late_bound_oauth in vibe/app_server/_mcp_auth.py — explicitly excludes config-owned [[mcp_servers]] entries. The comment in the source is clear: “a static entry there is a decision.”
In practice, this means:
- Without
[mcp_servers.auth]: Vibe treats the server as static-credential only. Attempting to authenticate via/mcpbrowser will fail withMCP server 'upwork' is not configured for OAuth. - With
[mcp_servers.auth]oftype = "oauth": Vibe starts the OAuth flow when you select the server in the/mcpbrowser and the server connects fully.
The fix: three lines in .vibe/config.toml
Here’s the working configuration I’m using in my SEO strategy project:
[[mcp_servers]]
name = "upwork"
transport = "http"
url = "https://mcp.upwork.com/mcp"
[mcp_servers.auth]
type = "oauth"
scopes = []
That’s it. No client_id, no client_metadata_url. This relies on the Upwork MCP server supporting Dynamic Client Registration (RFC 7591) — and it does.
How Dynamic Client Registration (DCR) works here
DCR is the key to why this config is so minimal. Instead of requiring you to pre-register an OAuth client with Upwork and paste static credentials into your config, the Upwork MCP server:
- Accepts a DCR request from Vibe at OAuth flow start
- Returns a temporary
client_idandclient_secretfor that session - Uses those ephemeral credentials for the duration of the auth flow
- Stores the resulting tokens in your OS keyring (via the
keyringPython library)
The result: zero pre-registration, zero static secrets in your config. From the Vibe CLI, run /mcp to open the MCP server browser, select the upwork server, choose Authenticate in browser, complete the consent flow, and the server flips from [http] no tools ● enabled to [http] 48 tools ● connected with the full Upwork tool list:
upwork__find_jobsupwork__get_accountupwork__boost_profile- And the rest of the Upwork MCP catalog
Transport note: http vs. streamable-http
The docs mention transport types. In practice, both transport = "http" and transport = "streamable-http" route to the same code path in Vibe. From registry.py:_discover_server:
case "http" | "streamable-http":
Both hit _discover_http → streamable_http_client. The distinction is a config-schema discriminator, not a functional difference. Use http unless you have a specific reason not to.
Verification: it works
I applied the three-line auth block, then used the Vibe MCP browser to authenticate. From the Vibe CLI, run /mcp to open the MCP server browser, select the upwork server from the list, and choose Authenticate in browser. This launches your default browser to Upwork’s OAuth consent screen. Complete the consent flow there, and Vibe automatically receives the OAuth tokens and connects the server. No manual client registration, no static keys, no workarounds. DCR against Upwork’s MCP endpoint works with zero pre-registration.
Direct terminal usage with –enabled-tools
Once OAuth is configured and connected, you can also use Upwork MCP tools directly from the terminal without entering the full Vibe CLI. Pass a single-shot prompt with -p, restrict to the specific tool via --enabled-tools, and set --output text for clean output:
vibe -p "Call list_accounts and return ONLY the org_uid values, one per line, with no other text." \
--enabled-tools "upwork_upwork__list_accounts" \
--output text \
--workdir "$PWD" \
--trust
This pattern works for any Upwork MCP tool. Replace upwork_upwork__list_accounts with the tool you need (e.g., upwork_upwork__get_account, upwork_upwork__find_jobs, etc.) and adjust the prompt to match. The --trust flag allows the command to run non-interactively, and --output text strips the markdown formatting for easier parsing or scripting.
As documented in Mistral’s MCP server docs under “Browse”, the /mcp command opens an interactive MCP server browser that lists all configured servers and provides authentication options for each.
Separately, the Upwork MCP server also works headlessly via Claude Code 2.1.251+ (verified Aug 31, 2026), which handles its own OAuth internally. That path is independent of Vibe’s DCR implementation and remains a proven alternative if you hit edge cases.
What the docs should say
The current documentation limitation note should be updated to reflect reality:
OAuth is fully supported for MCP servers. For servers requiring OAuth, add a
[mcp_servers.auth]block withtype = "oauth"to your[[mcp_servers]]entry. Many MCP servers support Dynamic Client Registration (DCR), which requires no pre-registered client credentials. Use/mcpto open the MCP server browser, select your server, and choose Authenticate in browser to start the OAuth flow.
And for servers that don’t support DCR, you’d add the static client credentials:
[mcp_servers.auth]
type = "oauth"
client_id = "your-pre-registered-client-id"
client_secret = "your-client-secret" # if required by the server
scopes = ["scope1", "scope2"]
But for Upwork, the minimal DCR config above is all you need.
The seven-step check if your Upwork MCP server isn’t connecting
If you’re still seeing “no tools” after adding the auth block:
- Verify the config — ensure
name,transport,url, and[mcp_servers.auth]withtype = "oauth"are all present - Restart Vibe — config changes require a full restart to take effect
- Check
/mcp list— confirm the server appears with[http]prefix - Run
/mcpto open the MCP browser — select the upwork server and choose Authenticate in browser - Complete the consent flow — approve all requested permissions in your browser
- Check
/mcp listagain — the server should now show tool count > 0 (e.g.,[http] 48 tools ● connected) - Test a tool call — try
upwork__get_accountto verify connectivity
If step 4 fails with “not configured for OAuth”, double-check that the [mcp_servers.auth] block is directly under the [[mcp_servers]] entry for Upwork, not at the root level or under a different server. As noted in the official docs, the /mcp command provides the interactive browser interface for managing MCP server connections.
Why this matters for agency workflows
For my SEO strategy work, Upwork MCP access means:
- Freelancer discovery — programmatic access to find specialists for specific tasks (technical SEO audits, content writing, link building)
- Job automation — posting, updating, and managing job listings without leaving the CLI
- Profile integration — boosting visibility and managing proposals at scale
- Data-driven hiring — pulling freelancer metrics and past work to inform hiring decisions
Before this working OAuth setup, the only path was manual API key management or using the Upwork web interface. Now it’s a native part of the Vibe workflow: ask for a task, Vibe can query Upwork for the right freelancer, post the job, and manage the process end-to-end.
Bottom line
The Mistral docs are wrong on this one. OAuth for MCP servers isn’t a limitation — it’s fully implemented and working. The Upwork MCP server connects with three lines of config and Dynamic Client Registration. The confusion came from stale documentation and a config detail that’s easy to overlook.
If you’ve been holding off on MCP server integrations because of the “OAuth not supported” note, give it another try. The code has moved on.
Questions about your own Vibe or MCP setup? Find me on Mastodon at @jfrumau@mastodon.social. The .vibe/config.toml used as the basis for this post is available here.