All posts
EngineeringBest practicesEcosystem

Developing with WebMCP in VSCode: Extensions, Snippets, and a Safe Workflow

Looking for WebMCP in VSCode? There’s no official extension yet. Here’s a practical setup: linting, JSON Schema helpers, snippets, and test tips to build reliable WebMCP tools fast.

Agent LayerOctober 17, 202610 min read

If you searched for “webmcp vscode”, you probably want a fast, safe way to write and maintain WebMCP tools in your editor. There isn’t a dedicated WebMCP VSCode extension today. You don’t need one to ship. By the end of this guide you’ll have a lightweight VSCode setup, copy‑paste snippets, and practices to keep your tools reliable in production.

TL;DR

  • There’s no official WebMCP VSCode extension. Use standard JavaScript/TypeScript, ESLint/Prettier, and JSON Schema tooling.
  • Always feature‑detect WebMCP: document.modelContext ?? navigator.modelContext.
  • Write tight JSON Schemas and descriptive tool copy; agents pick tools based on descriptions.
  • Guard sensitive actions with an in‑page confirmation step. Never pass secrets via tool params.
  • Check current browser/agent support on the public WebMCP ecosystem tracker and see a working flow in the Chrome developer guide.

Why “WebMCP VSCode” is a bit of a red herring

There’s no dedicated VSCode extension for WebMCP. The standard is intentionally simple: it’s just a JavaScript interface to register a tool (name, description, JSON Schema, execute). That’s good news. You can get an excellent authoring experience with off‑the‑shelf extensions:

  • TypeScript and JSDoc for types
  • ESLint + Prettier for consistency
  • JSON Schema editing and validation
  • Snippets for repeatable blocks (tool registration, schema templates)
  • Web dev servers and browser devtools for runtime checks

That setup gets you to production faster than waiting for a niche plugin.

If you want a guided walkthrough of registering tools and seeing a real agent call them, read the WebMCP demo walkthrough. For a deeper setup from scratch, see the WebMCP tutorial: setup, tools, and deployment.

A minimal, safe WebMCP tool in TypeScript

The core pattern is simple and works in plain JS or TS. This example registers a safe cart‑add tool with input validation and a guardrail for checkout.

// tools/cart.ts
// Feature-detect both addresses; some agents still check navigator.modelContext
const mc: any = (typeof document !== 'undefined' && (document as any).modelContext)
  ?? (typeof navigator !== 'undefined' && (navigator as any).modelContext)
  ?? null;

// Define your JSON Schema inline for fast iteration
const addToCartSchema = {
  type: 'object',
  additionalProperties: false,
  properties: {
    product_id: { type: 'string', minLength: 1, description: 'Internal product ID' },
    quantity: { type: 'integer', minimum: 1, default: 1 },
    variant: { type: 'string', description: 'Variant SKU or option key' }
  },
  required: ['product_id']
};

if (mc) {
  mc.registerTool({
    name: 'cart_add',
    description: 'Add a product to the cart. Use on product or list pages. Side effect: updates cart state.',
    inputSchema: addToCartSchema,
    execute: async (params: { product_id: string; quantity?: number; variant?: string }) => {
      // Bindings to your app's state/UI. Keep the result small and serialisable.
      const qty = params.quantity ?? 1;
      // Example: dispatch a client action or hit your internal cart API (same-origin, session-bound)
      await window.fetch('/cart/add', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ id: params.product_id, qty, variant: params.variant })
      });
      return { status: 'ok', added: { id: params.product_id, qty } };
    }
  });

  mc.registerTool({
    name: 'checkout_start',
    description: 'Begin checkout. Sensitive: requires explicit user confirmation on the page.',
    inputSchema: { type: 'object', additionalProperties: false, properties: {} },
    execute: async () => {
      // Guardrail: ask the human before sensitive actions (payments, account changes, deletion)
      const ok = window.confirm('An agent requested to start checkout. Continue?');
      if (!ok) return { status: 'cancelled' };
      window.location.href = '/checkout';
      return { status: 'redirected', to: '/checkout' };
    }
  });
}

Notes:

  • Tools run in the page with the user’s session. No backend keys are needed for agents.
  • Description quality matters: say when to use the tool, preconditions, and side effects.
  • Keep results tiny. Report what happened, not full page state.

You don’t need anything special, but these improve speed and quality.

  • ESLint: catch common JS/TS mistakes early.
  • Prettier: consistent diffs for JSON Schemas and code.
  • TypeScript: native in VSCode; enable “check JS” in JS projects with a jsconfig.json.
  • JSON Language Features: built‑in; gives schema syntax help and validation.
  • EditorConfig: keep formatting consistent across contributors.

Optional niceties:

  • Error Lens or Inline Error decorators: surface schema/type errors inline.
  • GitLens: track drift and review tool changes easily.
  • Live Server or your app’s dev server: quick reload to test tool discovery.

A tiny jsconfig.json that turns on type checking in JS files:

{
  "compilerOptions": {
    "checkJs": true,
    "target": "ES2020",
    "module": "ESNext"
  },
  "exclude": ["node_modules", "dist"]
}

Authoring JSON Schemas quickly

Tools rely on JSON Schema for inputs. A few patterns help:

  • Default conservative values. Use minimum/enum to constrain inputs.
  • additionalProperties: false to fail fast on agent mistakes.
  • Put short descriptions on each property. Some agents surface them.

A small helper to avoid typos and keep schemas close to code:

// tools/schemas.ts
export const moneySchema = {
  type: 'object',
  additionalProperties: false,
  properties: {
    currency: { type: 'string', minLength: 3, maxLength: 3 },
    amount_minor: { type: 'integer', minimum: 0 }
  },
  required: ['currency', 'amount_minor']
} as const;

Then reuse that schema in your tool’s inputSchema. You can keep schemas next to tools or in a shared module.

Snippets to speed up tool creation

Create a user snippet in VSCode (JavaScript or TypeScript) for a registerTool block. Example snippet body (TypeScript):

{
  "WebMCP Register Tool": {
    "prefix": "webmcp-tool",
    "body": [
      "const mc: any = (document as any).modelContext ?? (navigator as any).modelContext ?? null;",
      "if (mc) {",
      "  mc.registerTool({",
      "    name: \"${1:tool_name}\",",
      "    description: \"${2:When to use, preconditions, side effects}\",",
      "    inputSchema: ${3:{\n type: 'object', additionalProperties: false, properties: {}, required: [] \n}},",
      "    execute: async (params) => {",
      "      ${4:// TODO: implement} ",
      "      return { status: 'ok' };",
      "    }",
      "  });",
      "}"
    ]
  }
}

Paste that into your project’s .vscode/snippets or user snippets, then type webmcp-tool to scaffold a safe block.

Local dev workflow that doesn’t fight you

The goal is fast feedback: code, reload, inspect. WebMCP sits in the page, so your usual web dev loop works.

  • Run your web app in dev mode.
  • Load the page; open browser devtools Console.
  • Check that document.modelContext or navigator.modelContext is present and that your tools are registered without errors.
  • Use an agent that can call page tools (see support status below) to verify execution.

Here’s the sequence when an agent calls a tool you registered.

Agent discovers and calls a WebMCP tool in the page

To see this end‑to‑end in a real browser, the WebMCP in Chrome developer guide shows what works today and flags needed browser settings where applicable.

Browser and agent support, honestly

Support is evolving. Before you burn time debugging “why doesn’t my tool get called,” check the hand‑verified ecosystem tracker:

  • ChatGPT desktop app and ChatGPT Work: works today; they call page tools.
  • Chrome and Edge: origin trial; Brave behind a flag; Safari and Firefox don’t support it right now.
  • Several frameworks already work today (e.g., Vercel agent‑browser and Stagehand), others are behind flags or not supported.

Build with the feature detection shown above so your site stays safe on unsupported clients: it will just no‑op.

If you want examples of what’s feasible right now, the WebMCP example use cases post collects concrete patterns that run today.

Testing approaches that fit WebMCP

You can test tools at three levels:

  • Static: ESLint/type checks; schema correctness; description clarity (code review).
  • Runtime (local): open the page, ensure tools register; call execute manually in the console with a fake params object to simulate the agent call.
  • Agent‑driven: use an agent that supports WebMCP and attempt real intents. For reproducible guidance on this, read AI agent for website testing: what works today and how to ship it.

A quick manual poke in devtools:

// In browser console on your page
const mc = document.modelContext ?? navigator.modelContext;
const t = mc?.tools?.find?.(x => x.name === 'cart_add'); // some agents expose a registry for debugging; if not, call your execute directly
// If you hold a reference to execute in your module, you can invoke it directly:
window.cart_add?.({ product_id: 'sku_123', quantity: 2 });

If your build doesn’t expose tool functions globally (it shouldn’t in production), keep a local “dev only” export you can call from the console when NODE_ENV===“development”.

Organising tools in your codebase

Keep tools discoverable by humans:

  • One file per tool or per page template (product.ts, cart.ts, checkout.ts).
  • Co‑locate schemas with tools for simpler diffs.
  • Keep descriptions close to execute so they evolve together.
  • Name tools in snake_case (per spec) and keep names stable; agents may remember them.

A small index that registers all tools on route load:

// tools/index.ts
import './cart';
import './search';
import './account';
// Side effect: each file feature-detects and registers itself.

Writing descriptions agents actually use

Agents choose tools from the description. Treat it like a function docstring that must stand alone:

  • Start with “Do X”. Be explicit about context: “Use on product pages or when a product_id is known.”
  • List preconditions: “Requires an in‑stock product.”
  • State side effects: “Updates cart state.”
  • If sensitive, say it clearly: “Sensitive: requires user confirmation.”

Example:

const description = [
  'Search products by keyword. Use on any page. ',
  'Returns up to 10 matching IDs. No side effects.'
].join('');

Security and guardrails

Follow a few non‑negotiables:

  • Never pass secrets, API keys, payment tokens, or card data through tool params.
  • Require explicit user confirmation for sensitive actions (payments, account changes, deletion). Use an in‑page prompt.
  • Keep results small; don’t echo sensitive page state.

A confirmation prompt example is in the checkout_start tool above. This aligns with how tools run: in‑page, with the user’s current session.

What you can do without any extra platform

You can ship WebMCP tools directly in your app:

  • Write tools with registerTool and JSON Schemas.
  • Test with an agent that supports page tools.
  • Monitor errors in your usual frontend observability.

That’s enough to prove value and get real usage. If you want production niceties—keeping tools working as your UI shifts, seeing which agents call them, versioned configs, and built‑in guardrails—Agent Layer removes a lot of maintenance.

Where Agent Layer helps in VSCode‑centric teams

Agent Layer is one script tag you add to your site. You still author tools in your repo, but you get:

  • Drift detection: health checks flag when a UI change breaks a tool and suggest a new selector.
  • Guardrails: baked‑in user confirmations for sensitive tools.
  • Versioned configs with rollback.
  • Analytics: which agent called what, success/error, latency.
  • Test scenarios: write a user intent and check the expected tool fires.

For a practical sense of the tools to build first, read Essential WebMCP Tools for AI‑Ready Websites, and if you’re on WooCommerce or Shopify, see the platform‑specific guides for WooCommerce and Shopify.

Common pitfalls

  • Forgetting feature detection: registering blindly will throw on unsupported browsers/agents. Always use document.modelContext ?? navigator.modelContext.
  • Vague descriptions: agents won’t pick your tool if they can’t tell when to use it.
  • Over‑permissive schemas: missing required or allowing additionalProperties leads to brittle calls.
  • Large return payloads: agents need a concise result describing what happened.
  • Skipping guardrails: starting checkout or changing accounts without confirmation is risky.
  • Assuming universal support: verify with the ecosystem tracker before debugging ghosts.

A light checklist for your PRs

  • Tool name is snake_case and stable.
  • Description states use case, preconditions, side effects, and sensitivity.
  • inputSchema is strict: required set, additionalProperties false, enums/min/max where applicable.
  • execute is idempotent where possible; returns a tiny JSON status.
  • Sensitive paths prompt the user for confirmation in‑page.
  • Feature detection guards the register call.

Try it

If you want a quick sanity check, run the free agent‑readiness audit at agentlayer.tech. It flags missing WebMCP tools, invalid JSON‑LD, unlabeled forms, and more—and proposes concrete tools per page. To track where WebMCP works today, keep the ecosystem support tracker handy while you develop in VSCode.

Get started

Don't Be Invisible to Tomorrow's Buyers.

Make your platform executable for every AI assistant your customers already use. No engineering, no lock-in, no breakage.