---
title: OAuth MCP Servers
description: Configure OAuth-authenticated MCP servers with the v0 Platform API v2
type: guide
---

# OAuth MCP Servers



Use OAuth MCP servers when an MCP provider requires a user authorization flow before v0 can call its tools. The Platform API stores the MCP server configuration, creates a provider authorization URL, stores tokens from the OAuth callback, and redirects back to your application.

## 1. Register the OAuth client [#1-register-the-oauth-client]

Register v0 as an OAuth client with your MCP provider.

Use this redirect URI for Platform API OAuth flows:

```txt
https://api.v0.app/v2/mcp-servers/oauth/callback
```

If the provider supports Client ID Metadata Documents, use this URL as the client ID:

```txt
https://v0.app/api/chat/integrations/oauth/client-metadata.json
```

If the provider requires dynamic client registration or a manually registered OAuth app, use the provider's registration flow and save the resulting client ID and optional client secret.

## 2. Create the MCP server [#2-create-the-mcp-server]

Create the MCP server with `auth` set to `oauth`. The `resource` value is usually the MCP server URL and is sent as an RFC 8707 resource indicator during authorization.

<CustomCodeBlock languages="['TypeScript', 'cURL']" defaultLanguage="TypeScript">
  <CodeVariant
    language="TypeScript"
    title="TypeScript Example"
    code="`import { v0 } from 'v0-sdk'

const server = await v0.mcpServers.create({
  name: 'Linear',
  url: 'https://mcp.linear.app/mcp',
  enabled: true,
  auth: 'oauth',
  scope: 'user',
  oauthConfig: {
    authorizationUrl: 'https://linear.app/oauth/authorize',
    tokenUrl: 'https://api.linear.app/oauth/token',
    clientId: 'your-client-id',
    scopes: ['read'],
    usePKCE: true,
    resource: 'https://mcp.linear.app/mcp',
  },
})

console.log(server.id)`"
  />

  <CodeVariant
    language="cURL"
    title="cURL Example"
    code="`curl -X POST &#x22;https://api.v0.app/v2/mcp-servers&#x22; \\
  -H &#x22;Authorization: Bearer $V0_API_KEY&#x22; \\
  -H &#x22;Content-Type: application/json&#x22; \\
  -d '{
    &#x22;name&#x22;: &#x22;Linear&#x22;,
    &#x22;url&#x22;: &#x22;https://mcp.linear.app/mcp&#x22;,
    &#x22;enabled&#x22;: true,
    &#x22;auth&#x22;: &#x22;oauth&#x22;,
    &#x22;scope&#x22;: &#x22;user&#x22;,
    &#x22;oauthConfig&#x22;: {
      &#x22;authorizationUrl&#x22;: &#x22;https://linear.app/oauth/authorize&#x22;,
      &#x22;tokenUrl&#x22;: &#x22;https://api.linear.app/oauth/token&#x22;,
      &#x22;clientId&#x22;: &#x22;your-client-id&#x22;,
      &#x22;scopes&#x22;: [&#x22;read&#x22;],
      &#x22;usePKCE&#x22;: true,
      &#x22;resource&#x22;: &#x22;https://mcp.linear.app/mcp&#x22;
    }
  }'`"
  />
</CustomCodeBlock>

The server is created disconnected. The API response redacts secret values and returns only the authentication type.

## 3. Create an authorization URL [#3-create-an-authorization-url]

Create an authorization URL for the MCP server and redirect the user to it from your application. The `returnUrl` is an absolute URL in your application.

<CustomCodeBlock languages="['TypeScript', 'cURL']" defaultLanguage="TypeScript">
  <CodeVariant
    language="TypeScript"
    title="TypeScript Example"
    code="`import { redirect } from 'next/navigation'
import { v0 } from 'v0-sdk'

const authorization = await v0.mcpServers.createOAuthAuthorizationUrl({
  mcpServerId: 'mcp_123',
  returnUrl: 'https://your-app.example.com/oauth/v0-mcp/callback',
})

redirect(authorization.url)`"
  />

  <CodeVariant
    language="cURL"
    title="cURL Example"
    code="`curl -X POST &#x22;https://api.v0.app/v2/mcp-servers/mcp_123/oauth/authorize&#x22; \\
  -H &#x22;Authorization: Bearer $V0_API_KEY&#x22; \\
  -H &#x22;Content-Type: application/json&#x22; \\
  -d '{
    &#x22;returnUrl&#x22;: &#x22;https://your-app.example.com/oauth/v0-mcp/callback&#x22;
  }'`"
  />
</CustomCodeBlock>

The authorization URL expires after 5 minutes.

## 4. Handle the return URL [#4-handle-the-return-url]

After the user authorizes with the MCP provider, v0 stores the OAuth tokens and redirects to your `returnUrl`.

On success, v0 appends:

```txt
?oauth_success=true&mcpServerId=mcp_123
```

On failure, v0 appends:

```txt
?error=access_denied&error_description=The+user+denied+access&mcpServerId=mcp_123
```

After authorization, v0 can attach the stored OAuth token when it calls the MCP server. If the token expires and the provider issued a refresh token, v0 refreshes it automatically.

## 5. Use the server in chats [#5-use-the-server-in-chats]

Pass the MCP server ID when creating a chat or sending a message.

<CustomCodeBlock languages="['TypeScript', 'cURL']" defaultLanguage="TypeScript">
  <CodeVariant
    language="TypeScript"
    title="TypeScript Example"
    code="`import { v0 } from 'v0-sdk'

const chat = await v0.chats.create({
  prompt: 'Use Linear context to summarize my active issues',
  mcpServerIds: ['mcp_123'],
})

await v0.chats.messages.send({
  chatId: chat.id,
  prompt: 'Create a project plan from those issues',
  mcpServerIds: ['mcp_123'],
})`"
  />

  <CodeVariant
    language="cURL"
    title="cURL Example"
    code="`curl -X POST &#x22;https://api.v0.app/v2/chats&#x22; \\
  -H &#x22;Authorization: Bearer $V0_API_KEY&#x22; \\
  -H &#x22;Content-Type: application/json&#x22; \\
  -d '{
    &#x22;prompt&#x22;: &#x22;Use Linear context to summarize my active issues&#x22;,
    &#x22;mcpServerIds&#x22;: [&#x22;mcp_123&#x22;]
  }'

curl -X POST &#x22;https://api.v0.app/v2/chats/chat_123/messages&#x22; \\
  -H &#x22;Authorization: Bearer $V0_API_KEY&#x22; \\
  -H &#x22;Content-Type: application/json&#x22; \\
  -d '{
    &#x22;prompt&#x22;: &#x22;Create a project plan from those issues&#x22;,
    &#x22;mcpServerIds&#x22;: [&#x22;mcp_123&#x22;]
  }'`"
  />
</CustomCodeBlock>

If the user has not authorized the server yet, v0 will not load its tools for the chat.

## Updating OAuth configuration [#updating-oauth-configuration]

Use `v0.mcpServers.update()` to replace the stored OAuth configuration.

<CustomCodeBlock languages="['TypeScript', 'cURL']" defaultLanguage="TypeScript">
  <CodeVariant
    language="TypeScript"
    title="TypeScript Example"
    code="`import { v0 } from 'v0-sdk'

await v0.mcpServers.update({
  mcpServerId: 'mcp_123',
  auth: 'oauth',
  oauthConfig: {
    authorizationUrl: 'https://auth.example.com/oauth/authorize',
    tokenUrl: 'https://auth.example.com/oauth/token',
    clientId: 'updated-client-id',
    scopes: ['read', 'write'],
    usePKCE: true,
    resource: 'https://mcp.example.com/mcp',
  },
})`"
  />

  <CodeVariant
    language="cURL"
    title="cURL Example"
    code="`curl -X PATCH &#x22;https://api.v0.app/v2/mcp-servers/mcp_123&#x22; \\
  -H &#x22;Authorization: Bearer $V0_API_KEY&#x22; \\
  -H &#x22;Content-Type: application/json&#x22; \\
  -d '{
    &#x22;auth&#x22;: &#x22;oauth&#x22;,
    &#x22;oauthConfig&#x22;: {
      &#x22;authorizationUrl&#x22;: &#x22;https://auth.example.com/oauth/authorize&#x22;,
      &#x22;tokenUrl&#x22;: &#x22;https://auth.example.com/oauth/token&#x22;,
      &#x22;clientId&#x22;: &#x22;updated-client-id&#x22;,
      &#x22;scopes&#x22;: [&#x22;read&#x22;, &#x22;write&#x22;],
      &#x22;usePKCE&#x22;: true,
      &#x22;resource&#x22;: &#x22;https://mcp.example.com/mcp&#x22;
    }
  }'`"
  />
</CustomCodeBlock>

If the provider changes client IDs, scopes, or token endpoints, create a new authorization URL and have the user authorize the MCP server again.
