vlt / affordances
  • Quickstart
  • Concepts
  • Guides
  • Reference
  • For agents
  • Why Affordances
  • Quickstart
  • Benchmarks

Concepts
  • Overview
  • Actions
  • State
  • Expose
  • Guards and confirm
  • Deltas
  • Plugins

Guides
  • Overview
  • React and WebMCP
  • MCP
  • Lint
  • Security

Plugins
  • Overview

Reference
  • Overview
  • Protocol
  • Options
  • CLI
  • Connect a client
  • Authentication
  • As a library
  1. Guides
  2. /
  3. MCP

MCP

@affordances/mcp turns any Affordances site into two MCP tools, for Claude, Cursor, and other MCP clients.

@affordances/mcp is a stdio MCP server that speaks Affordances to one site:

Terminal
vlx @affordances/mcp https://store.example.comnpx @affordances/mcp https://store.example.compnpm dlx @affordances/mcp https://store.example.comyarn dlx @affordances/mcp https://store.example.combunx @affordances/mcp https://store.example.comdeno run -A npm:@affordances/mcp https://store.example.com

It doesn't flatten the site into one tool per action. It gives the model two generic tools and lets it move through pages like a person would.

ToolInputReturns
affordances_openpathThe page's graph: entities, actions with input schemas, and nav
affordances_callpath, action, input?, confirm?The delta: changed entities, output, action changes, and a redirect

affordances_open is marked read-only. affordances_call's description tells the model that confirm actions answer confirm_required first, and to resend with confirm: true only after the user approves the summary.

Connect a client

claude_desktop_config.json
{
  "mcpServers": {
    "store": {
      "command": "vlx",
      "args": ["@affordances/mcp", "https://store.example.com"]
    }
  }
}

Cursor and other clients take the same command and arguments.

Authentication

Pass a bearer token with --token, or set AFFORDANCES_TOKEN:

Terminal
vlx @affordances/mcp https://store.example.com --token "$STORE_TOKEN"npx @affordances/mcp https://store.example.com --token "$STORE_TOKEN"pnpm dlx @affordances/mcp https://store.example.com --token "$STORE_TOKEN"yarn dlx @affordances/mcp https://store.example.com --token "$STORE_TOKEN"bunx @affordances/mcp https://store.example.com --token "$STORE_TOKEN"deno run -A npm:@affordances/mcp https://store.example.com --token "$STORE_TOKEN"

The token is sent as Authorization: Bearer on every request, and your auth resolver decides what session it maps to. The bridge never handles passwords.

Without a token, it keeps the cookies the site sets, like a browser would, and sends the site's own Origin with them. That's enough for flows where an action starts a session, such as an anonymous cart.

The bridge only requests paths on the site it was started with. A path that resolves to another origin is refused.

As a library

TypeScript
import { createClient, createServer } from '@affordances/mcp'

const store = createClient('https://store.example.com', { token })
const graph = await store.open('/products/heavyweight-tee')
const delta = await store.call('/products/heavyweight-tee', 'addToCart', { sku: 'TEE-BLK-M' })

createClient returns index(), open(path), and call(path, action, input, confirm), each validated against the protocol's schemas. createServer(site, options) returns the McpServer the CLI connects to stdio, for embedding in your own transport.


PreviousReact and WebMCPNextLint

On this page

  • Connect a client
  • Authentication
  • As a library
Edit this page

Make your app agent-operable

Give every page a graph and every server action an agent path: HTTP, WebMCP, and MCP, with the same session and the same checks. One command sets it up.

Read the quickstart