Skip to content

Experimental · Unofficial

Built by Tim Benniks. This is not an official Contentstack product and is not supported by Contentstack.

Architecture

Overview

flowchart TB
  subgraph browser [Browser tab — any framework]
    Agent[Browser agent]
    Core["@timbenniks/contentstack-webmcp core"]
    Adapter["Optional /react, /next"]
  end
  subgraph site [Customer site]
    ProxyAPI["Proxy routes /server"]
    DirectSDK["Delivery SDK in the browser tab"]
  end
  subgraph cs [Contentstack]
    CDA[Content Delivery API]
  end
  Agent --> Core
  Adapter -.->|thin wrapper| Core
  Core -.->|"proxy mode"| ProxyAPI
  Core -->|"direct mode (default)"| DirectSDK
  ProxyAPI --> CDA
  DirectSDK --> CDA

Package layering

LayerExport pathDepends onPurpose
Core@timbenniks/contentstack-webmcpdelivery-sdk (peer)Tool factory, registration, browser detection
Server@timbenniks/contentstack-webmcp/serverdelivery-sdkFramework-agnostic proxy handlers
Serializers@timbenniks/contentstack-webmcp/serializersnoneEntry to markdown/summary transforms
React@timbenniks/contentstack-webmcp/reactreact (peer)Hook and provider wrapper
Next.js@timbenniks/contentstack-webmcp/nextnext (peer)App Router route re-exports over /server

Why a companion package?

The Delivery SDK plugin API intercepts CDA HTTP requests. WebMCP operates at a different layer:

typescript
// Delivery SDK plugin — shapes HTTP traffic
class CrossStackPlugin {
  onRequest(request) {
    return request;
  }
  async onResponse(request, response, data) {
    return response;
  }
}

// WebMCP — shapes browser capabilities
document.modelContext.registerTool({
  name: "contentstack_search_entries",
  description: "...",
  inputSchema: {/* JSON Schema */},
  execute: async (input) => {
    /* structured result */
  },
});

Plugins cannot register browser tools, define JSON schemas for agents, or manage browser lifecycle. A companion package is the correct abstraction.

Request flow (proxy mode)

1. Browser agent calls contentstack_search_entries
2. Tool execute handler → fetch("/api/contentstack/search?query=...")
3. Server proxy handler → Delivery SDK → CDA
4. JSON response → MCP text content → agent

Shared CDA layer

Both the browser direct client and server proxy handlers use src/cda/queries.ts:

  • searchEntries
  • getEntryByUrl
  • getEntryByUid
  • listContentTypes

Custom queries extend this via createCdaClient() or customRoutes.

Progressive enhancement

isWebMcpEnabled()     → env kill switch
isWebMcpSupported()   → feature detect document.modelContext
registerToolSafely()  → try/catch per tool
AbortSignal           → cleanup on route change / pagehide

Unsupported browsers: complete no-op, zero console errors.

Released under the MIT License.