Warning
Experimental. This extension is experimental and not yet ready for production use. It is built on top of WebMCP, which is itself an experimental, early-stage proposal. Both the underlying specification and this extension's API may change or break at any time without notice. Use at your own risk.
Architecture
The extension has two independent flows: emitting tools at page render time and ingesting usage events at call time. They share only the tool registry.
Emitting tools (frontend render)
ToolProvider(s) one small PHP class per tool
│ manifest($cObj, $processedData) → Manifest | null
▼
ToolRegistry::collect() drops providers that return null
│ list<Manifest>
▼
ToolManifestProcessor TYPO3 data processor
│ JSON: { endpoint, tools:[…] } (JSON_HEX_* escaped)
▼
<script id="webmcp-config"> rendered once per page by your template
│
▼
webmcp.js runtime reads the block, feature-detects ModelContext
│ per tool: picks the primitive interpreter (or imports moduleUrl)
▼
document.modelContext.registerTool() agent can now discover & call the tool
Key classes:
\Neoblack\– the contract each tool implements. TaggedWebmcp\ Tool\ Tool Provider Interface webmcp.tool(autoconfigured).\Neoblack\/Webmcp\ Tool\ Manifest \Neoblack\– the serialisable tool description and its behaviour selector.Webmcp\ Tool\ Primitive \Neoblack\– collects manifests for the current request and exposesWebmcp\ Registry\ Tool Registry toolfor the analytics whitelist.Names () \Neoblack\– serialises the manifests into the page's JSON block.Webmcp\ Data Processing\ Tool Manifest Processor Resources/– the generic runtime holding all four primitive interpreters and the escape-hatch loader.Public/ Java Script/ webmcp. js
Ingesting usage events (call time)
webmcp.js ──POST /webmcp-event──► EventMiddleware
navigator.sendBeacon │ same-origin guard (Sec-Fetch-Site)
{ tool, client } │ RateLimiter::allow(ip, limit)
│ tool ∈ ToolRegistry::toolNames() ?
▼
EventRepository::log(tool, client, ts)
│
▼
tx_neoblackwebmcp_event (append-only)
Backend: DashboardController ──► StatisticsService ──► EventRepository
(System > WebMCP module) aggregates by tool / client / day
Key classes:
\Neoblack\– the public ingest endpoint. Inert when analytics is disabled; passes unknown tools down the stack so it can coexist with other handlers.Webmcp\ Middleware\ Event Middleware \Neoblack\– fixed-window limiter keyed on a hashed IP + window number (no plaintext IP stored).Webmcp\ Security\ Rate Limiter \Neoblack\– the only class that writes/reads the event table.Webmcp\ Domain\ Repository\ Event Repository \Neoblack\– aggregates rows into the DTOs the backend module renders.Webmcp\ Service\ Statistics Service \Neoblack\– thin backend controller; reads the filter, delegates, renders.Webmcp\ Controller\ Dashboard Controller
Why the two flows are decoupled
The middleware runs early, before the frontend page is resolved, so it cannot
rely on a rendered manifest. It therefore validates incoming events against
Tool — the context-free provider names — rather than
against the per-page manifest. This is why
Tool
must be stable and must equal the
Manifest name.