webmcp-vue

Vue composables for exposing typed tools through document.modelContext.
317
Install
npm install webmcp-vue
Latest Version:0.0.2
Vue:3
License:MIT
Last Updated:Sep 22, 2026
Links: GitHub  ·  npm
Maintainer: handtrix

webmcp-vue

CI npm version npm downloads license Vue 3 TypeScript

Vue 3 composables for exposing typed, callable tools on document.modelContext, aligned with WebMCP.

Inspired by and ported from agentcathq/webmcp-react.

See the API reference for the complete public API, or try the live playground.

Skills

Requirements

  • Vue 3
  • A browser that supports WebMCP, or the built-in development polyfill
  • Optionally, a Standard Schema-compatible validator such as Zod, Valibot, or ArkType

Install

pnpm add webmcp-vue zod

Zod is optional. Install only the Standard Schema-compatible validator you want to use, or use JSON Schema directly.

Quick start

Wrap the part of the application that declares tools with WebMCPProvider, then call useMcpTool in a descendant component.

<!-- App.vue -->
<script setup lang="ts">
import { WebMCPProvider } from 'webmcp-vue'
import SearchTool from './SearchTool.vue'
</script>

<template>
  <WebMCPProvider name="my-app" version="1.0">
    <SearchTool />
    <RouterView />
  </WebMCPProvider>
</template>
<!-- SearchTool.vue -->
<script setup lang="ts">
import { useMcpTool } from 'webmcp-vue'
import { z } from 'zod'

useMcpTool({
  name: 'search',
  title: 'Search catalog',
  description: 'Search the product catalog by query.',
  input: z.object({ query: z.string() }),
  annotations: { readOnlyHint: true },
  handler: async ({ query }, { signal }) => {
    const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal })
    const products = await response.json()

    return {
      content: [{ type: 'text', text: JSON.stringify(products) }],
    }
  },
})
</script>

<template>
  <slot />
</template>

The tool is registered while SearchTool is mounted and is removed when it unmounts. Agents discover and invoke it through document.modelContext.

To update a registered tool, pass a Vue reactive() config object to useMcpTool. Changes to its name, metadata, schemas, annotations, or allowed origins unregister the old tool and register the new definition.

Schemas and validation

Pass a Standard Schema validator as input. Its validate method runs before the handler, and the handler receives its parsed output with inferred TypeScript types.

Zod, Valibot, ArkType, and other compatible libraries work without adapters:

useMcpTool({
  name: 'set-theme',
  description: 'Set the active color theme.',
  input: z.object({ theme: z.enum(['light', 'dark']) }),
  handler: async ({ theme }) => ({
    content: [{ type: 'text', text: `Theme changed to ${theme}` }],
  }),
})

If the validator implements Standard JSON Schema, its input schema is also exposed to WebMCP clients. Schema conversion is optional; validation still works without it.

Raw JSON Schema

Use inputSchema when you do not use a validator:

useMcpTool({
  name: 'calculate',
  description: 'Add two numbers.',
  inputSchema: {
    type: 'object',
    properties: {
      left: { type: 'number' },
      right: { type: 'number' },
    },
    required: ['left', 'right'],
  },
  handler: async ({ left, right }) => ({
    content: [{ type: 'text', text: String(Number(left) + Number(right)) }],
  }),
})

Raw JSON Schema describes the tool to WebMCP clients. It is not validated by the polyfill, matching native WebMCP; validate untrusted input in the handler or use a Standard Schema validator.

Execution state and local calls

useMcpTool returns reactive execution state plus execute and reset:

const { state, execute, reset } = useMcpTool({
  name: 'greet',
  description: 'Greet a person.',
  input: z.object({ name: z.string() }),
  handler: async ({ name }) => ({
    content: [{ type: 'text', text: `Hello ${name}` }],
  }),
})

await execute({ name: 'Ada' })
console.log(state.lastResult)
reset()

state contains:

  • isExecuting: whether one or more executions are active
  • lastResult: the most recent successful result
  • error: the most recent validation, handler, or registration error
  • executionCount: successful executions since the last reset

execute(input, { signal }) rejects on errors. Agent-initiated failures are returned as WebMCP error results. Each invocation receives an AbortSignal; pass it to cancellable work such as fetch.

Tool options

Option Purpose
name Required unique identifier: 1–128 characters from A-Z, a-z, 0-9, _, ., or -.
title Optional human-readable tool title.
description Required explanation for agents.
input / output Standard Schema validators.
inputSchema / outputSchema Raw JSON Schema objects.
annotations WebMCP hints: readOnlyHint and untrustedContentHint.
exposedTo Potentially trustworthy origins permitted to access the tool.
onSuccess / onError Callbacks after a successful execution or any non-cancellation error.

Use either input/output or inputSchema/outputSchema for a tool, not both.

Browser and SSR behavior

WebMCPProvider is safe to render during SSR: registration happens only after client mount. On browsers without native document.modelContext, it installs a lightweight, same-document polyfill and removes it when the final provider unmounts. Native WebMCP is never replaced.

Use useWebMCPStatus() inside the provider when the UI needs to know whether a WebMCP API is available:

const { available } = useWebMCPStatus()

In development, useMcpTool() and useWebMCPStatus() warn when called outside the provider. Place the provider above every component that declares or checks a tool.

License

MIT

Version History

Version Released Vue License
0.0.2 ^3.0.0 MIT
0.0.1 ^3.0.0 MIT