Guides

Give an agent running on Vercel your production errors (Vercel Connect)

Create a Vercel Connect connector for runheed.com (Runheed publishes OAuth discovery and dynamic client registration, so Connect registers its own client), link it to your project, then pass connectAuthProvider to the AI SDK MCP client pointed at https://runheed.com/api/mcp. The agent gets all twelve Runheed tools, and no Runheed key lives in your environment variables.

Create the connector

From your project directory, with the Vercel CLI signed in:

terminalbash
vercel connect create runheed.com
# note the connector UID it prints, then link it to this project:
vercel connect attach <connector-uid>
vercel link && vercel env pull   # VERCEL_OIDC_TOKEN for local development

Connect reads https://runheed.com/.well-known/oauth-authorization-server, registers a client with the callback https://connect.vercel.com/callback, and uses PKCE. Runheed issues refresh tokens, and a revoke in Vercel calls Runheed's revocation endpoint, so the agent key is ended on both sides.

Call the tools from an AI SDK route

app/api/triage/route.tstypescript
import { createMCPClient } from '@ai-sdk/mcp';
import { connectAuthProvider, ConsentRequiredError } from '@vercel/connect/ai-sdk';
import { generateText, stepCountIs } from 'ai';

export async function POST(request: Request) {
  // The person whose Runheed account the agent reads: take the id from your own session.
  const userId = 'owner';
  let mcp: Awaited<ReturnType<typeof createMCPClient>> | undefined;
  try {
    mcp = await createMCPClient({
      transport: {
        type: 'http',
        url: 'https://runheed.com/api/mcp',
        authProvider: connectAuthProvider('<connector-uid>', { subject: { type: 'user', id: userId }, scopes: ['errors'] }, { redirectUrl: new URL('/', request.url).toString() }),
      },
    });
    const { text } = await generateText({
      model: 'openai/gpt-5.6-sol', // any AI Gateway model id
      tools: await mcp.tools(),
      prompt: 'Check project health, read the error to fix first and summarize the cause and the likely fix.',
      stopWhen: stepCountIs(6),
    });
    return Response.json({ text });
  } catch (error) {
    if (error instanceof ConsentRequiredError) return Response.redirect(error.url, 303);
    throw error;
  } finally {
    await mcp?.close();
  }
}

The first call for a user redirects to the Runheed sign-in and consent page (choose Read only there if the agent should only look). After that, Connect hands the client a current token on every request.

A headless bot instead of a signed-in user

Runheed's OAuth acts as a person, so a scheduled job or bot with no user can use an API-key connector instead: create an agent key at https://runheed.com/dashboard/settings (tick Read only if it should only read), store it in Connect as an API key connector, and send it as the bearer token.

lib/runheed.tstypescript
import { getToken } from '@vercel/connect';
import { createMCPClient } from '@ai-sdk/mcp';

const key = await getToken('<api-key-connector-uid>', { subject: { type: 'app' } });
const mcp = await createMCPClient({
  transport: { type: 'http', url: 'https://runheed.com/api/mcp', headers: { Authorization: `Bearer ${key}` } },
});

Questions

Which tools does the agent get?
All twelve: recent errors, search (including what a release introduced), one error in full, its context, trends, project health, resolve, ignore, unignore, and the setup tools for projects and test events.
Can it change anything?
Only error status (resolve, ignore, unignore) and new projects or test events. Choose Read only on the consent page, or create a read-only agent key, to allow reading alone.
Does the deployed app need a Runheed key in its environment?
No. With the OAuth connector, Connect stores the grant and gives the client short-lived tokens; your project authenticates to Connect with its Vercel OIDC token.

Related