home / skills / picahq / skills / vercel-ai-sdk

vercel-ai-sdk skill

/skills/vercel-ai-sdk

This skill helps you integrate PICA MCP with your app, enabling dynamic tool calls and AI agent connectivity via stdio transport.

npx playbooks add skill picahq/skills --skill vercel-ai-sdk

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
6.3 KB
---
name: vercel-ai-sdk
description: Integrate PICA into an application via MCP. Use when adding PICA tools, connecting PICA to an AI agent, setting up PICA MCP with Vercel AI SDK, or when the user mentions PICA.
---

# PICA MCP Integration

PICA provides a unified API platform that connects AI agents to third-party services (CRMs, email, calendars, databases, etc.) through MCP tool calling.

## PICA MCP Server

PICA exposes its capabilities through an MCP server distributed as `@picahq/mcp`. It uses **stdio transport** — it runs as a local subprocess via `npx`.

### MCP Configuration

```json
{
  "mcpServers": {
    "pica": {
      "command": "npx",
      "args": ["@picahq/mcp"],
      "env": {
        "PICA_SECRET": "your-pica-secret-key"
      }
    }
  }
}
```

- **Package**: `@picahq/mcp` (run via `npx`, no install needed)
- **Auth**: `PICA_SECRET` environment variable (obtain from the PICA dashboard https://app.picaos.com/settings/api-keys)
- **Transport**: stdio (standard input/output)

### Environment Variable

Always store the PICA secret in an environment variable, never hardcode it:

```
PICA_SECRET=sk_test_...
```

Add it to `.env.local` (or equivalent) and document it in `.env.example`.

## Using PICA with Vercel AI SDK

The Vercel AI SDK provides MCP client support via the `@ai-sdk/mcp` package. Install it:

```bash
npm add @ai-sdk/mcp
```

### CRITICAL: Version alignment

`@ai-sdk/mcp`, `ai`, `@ai-sdk/react`, `@ai-sdk/openai`, `@ai-sdk/anthropic`, and all other `@ai-sdk/*` packages **must resolve to the same `@ai-sdk/provider-utils` major version**. If they don't, tool schemas created by the MCP client use different internal symbols than those expected by `streamText`, causing validation errors like:

```
Invalid input for tool ...: Type validation failed: Value: {}.
Error message: Cannot read properties of undefined (reading 'validate')
```

**How to diagnose:** look for multiple copies of `@ai-sdk/provider-utils`:

```bash
find node_modules -path "*/provider-utils/package.json" \
  -exec sh -c 'echo "$(dirname "{}"): $(node -e "console.log(require(\"{}\").version)")"' \;
```

If you see two different versions (e.g. `3.x` at root and `4.x` nested inside `@ai-sdk/mcp/node_modules/`), **upgrade all `@ai-sdk/*` and `ai` packages together** so they share a single version:

```bash
npm install ai@latest @ai-sdk/react@latest @ai-sdk/openai@latest @ai-sdk/anthropic@latest @ai-sdk/mcp@latest
```

You may also need to upgrade `react`/`react-dom` if peer dependency constraints require it.

### Before implementing: look up the latest docs

The Vercel AI SDK MCP API may change between versions. **Always search the bundled docs first** to get the current API before writing any code. For detailed instructions on where to find the docs and what to look for, see [vercel-ai-sdk-mcp-reference.md](vercel-ai-sdk-mcp-reference.md).

### Integration pattern

1. **Create an MCP client** using stdio transport pointed at `npx @picahq/mcp`
2. **Get tools** from the client — they are automatically converted to AI SDK tool format
3. **Pass tools** to `streamText()` or `generateText()`
4. **Enable multi-step execution** with `stopWhen: stepCountIs(N)` so the model can call tools and process results
5. **Close the MCP client** when the response is finished

When passing environment variables to the stdio transport, spread `process.env` so the subprocess inherits the full environment (PATH, etc.):

```typescript
env: {
  ...process.env as Record<string, string>,
  PICA_SECRET: process.env.PICA_SECRET!,
}
```

### Working example (API route)

```typescript
import {
  streamText,
  UIMessage,
  convertToModelMessages,
  stepCountIs,
} from 'ai';
import { createMCPClient } from '@ai-sdk/mcp';
import { Experimental_StdioMCPTransport as StdioMCPTransport } from '@ai-sdk/mcp/mcp-stdio';

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json();

  const mcpClient = await createMCPClient({
    transport: new StdioMCPTransport({
      command: 'npx',
      args: ['@picahq/mcp'],
      env: {
        ...process.env as Record<string, string>,
        PICA_SECRET: process.env.PICA_SECRET!,
      },
    }),
  });

  const tools = await mcpClient.tools();

  const result = streamText({
    model: yourModel,
    // convertToModelMessages is async as of [email protected]
    messages: await convertToModelMessages(messages),
    tools,
    stopWhen: stepCountIs(5),
    onFinish: async () => {
      await mcpClient.close();
    },
  });

  return result.toUIMessageStreamResponse({
    sendSources: true,
    sendReasoning: true,
  });
}
```

### UI rendering of PICA tool calls

PICA tools appear as **dynamic tool parts** in the AI SDK's `UIMessage` system (`type: "dynamic-tool"` with a `toolName` field). Standard AI SDK tools appear as `tool-invocation` (prefix `tool-`). Handle both in the message parts renderer:

```tsx
// In the message parts switch/map:
if (part.type.startsWith('tool-') || part.type === 'dynamic-tool') {
  const toolPart = part as any;
  // toolPart.toolName — the MCP tool name (e.g. "list_pica_integrations")
  // toolPart.state — "input-streaming" | "input-available" | "output-available" | "output-error"
  // toolPart.input — tool input parameters
  // toolPart.output — tool result (when state is "output-available")
}
```

Pass `toolPart.toolName` as the display title so Pica tools show their actual name rather than the generic part type.

## Checklist

When setting up PICA MCP in a project:

- [ ] `@ai-sdk/mcp` is installed
- [ ] **All `@ai-sdk/*` and `ai` packages share the same `@ai-sdk/provider-utils` version** (see Version alignment above)
- [ ] `PICA_SECRET` is set in `.env.local` (or equivalent)
- [ ] `.env.example` documents the `PICA_SECRET` variable
- [ ] MCP client uses stdio transport with `npx @picahq/mcp`
- [ ] Full `process.env` is spread into the transport's `env` option
- [ ] `convertToModelMessages` is awaited (async as of `[email protected]`)
- [ ] Multi-step execution is configured with `stopWhen: stepCountIs(N)`
- [ ] MCP client is closed after use (`onFinish` for streaming, `try/finally` for non-streaming)
- [ ] UI handles both `"tool-invocation"` and `"dynamic-tool"` parts for rendering tool calls

## Additional resources

- For Vercel AI SDK MCP specifics and where to find the latest docs, see [vercel-ai-sdk-mcp-reference.md](vercel-ai-sdk-mcp-reference.md)

Overview

This skill explains how to integrate PICA into an application via the MCP (MCP tool calling) workflow. It focuses on running the PICA MCP server as a local stdio subprocess, configuring the Vercel AI SDK MCP client, and handling tool calls in the UI. The guidance emphasizes secure secret handling and package version alignment to avoid runtime validation errors.

How this skill works

The skill shows how to launch the PICA MCP server using npx @picahq/mcp with stdio transport so your app can call PICA tools as subprocess tool providers. It covers creating an MCP client with @ai-sdk/mcp, fetching tools from the client, passing those tools into streamText/generateText, enabling multi-step tool execution, and closing the client when finished. UI guidance explains rendering dynamic PICA tool parts alongside standard AI SDK tools.

When to use it

  • Adding PICA tools to an AI agent or toolset.
  • Connecting PICA to a Vercel AI SDK-based app with MCP.
  • Implementing streaming tool execution and multi-step flows.
  • Setting up local development or serverless routes that spawn PICA as a subprocess.
  • Rendering PICA tool calls in the app UI alongside other AI SDK tools.

Best practices

  • Store PICA secret in an environment variable (PICA_SECRET); never hardcode secrets.
  • Run the MCP server via npx @picahq/mcp using stdio transport; spread process.env into the transport env.
  • Ensure all @ai-sdk/* and ai packages resolve to the same @ai-sdk/provider-utils major version to avoid schema/validation errors.
  • Await convertToModelMessages if using [email protected] or later and configure stopWhen: stepCountIs(N) for multi-step tool flows.
  • Always close the MCP client after use (onFinish for streaming or try/finally for non-streaming).

Example use cases

  • Serverless API route that streams model output and invokes PICA tools to access CRMs or calendars.
  • Agent that calls PICA integrations to read/write database records during a multi-step conversation.
  • Local development where you want to run PICA as a subprocess via npx without installing globally.
  • UI message renderer that displays dynamic PICA tool parts with input/output states alongside regular tool invocations.

FAQ

How do I provide the PICA secret to the MCP subprocess?

Set PICA_SECRET in your environment (e.g., .env.local) and spread process.env into the transport env so the subprocess inherits it, e.g., env: { ...process.env, PICA_SECRET: process.env.PICA_SECRET }.

Why am I seeing tool validation errors like 'Type validation failed: Value: {}'?

Those errors usually mean mismatched @ai-sdk/provider-utils versions across @ai-sdk/* and ai packages. Upgrade all @ai-sdk/* and ai packages together so they share a single provider-utils major version.