Solid / SolidStart
onMount plus onCleanup maps directly onto register and abort.
Component
// src/components/WebMcp.tsx
import { onCleanup, onMount, createSignal } from "solid-js";
import { useNavigate } from "@solidjs/router";
import contentstack from "@contentstack/delivery-sdk";
import { createContentstackWebMcp, isWebMcpSupported } from "@timbenniks/contentstack-webmcp";
import { contentTypes } from "~/content-types";
const stack = contentstack.stack({
apiKey: import.meta.env.VITE_CONTENTSTACK_API_KEY,
deliveryToken: import.meta.env.VITE_CONTENTSTACK_DELIVERY_TOKEN,
environment: import.meta.env.VITE_CONTENTSTACK_ENVIRONMENT,
});
export function WebMcp() {
const navigate = useNavigate();
const [registered, setRegistered] = createSignal<string[]>([]);
onMount(async () => {
if (!isWebMcpSupported()) return;
const controller = new AbortController();
onCleanup(() => controller.abort());
const webmcp = createContentstackWebMcp({ mode: "direct", stack, contentTypes });
setRegistered(
await webmcp.register({
signal: controller.signal,
navigate: (path) => navigate(path),
})
);
});
return null;
}Mount it once in your root layout, above the router outlet, so it survives navigation.
TIP
Register onCleanup before awaiting. Registering it after the await puts it outside the owner's synchronous tracking scope, and it will never run.
SolidStart
SolidStart renders on the server, so keep the init in a component that only runs in the browser. isWebMcpSupported() already returns false when there is no document, so the guard above is enough — but placing it in onMount avoids constructing the stack during SSR at all.
// src/app.tsx
import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
import { WebMcp } from "~/components/WebMcp";
export default function App() {
return (
<Router
root={(props) => (
<>
<WebMcp />
{props.children}
</>
)}
>
<FileRoutes />
</Router>
);
}Proxy mode
SolidStart API routes speak Web Request/Response:
// src/routes/api/contentstack/[...path].ts
import type { APIEvent } from "@solidjs/start/server";
import contentstack from "@contentstack/delivery-sdk";
import { createContentstackWebMcpProxyHandler } from "@timbenniks/contentstack-webmcp/server";
import { contentTypes } from "~/content-types";
const stack = contentstack.stack({
apiKey: process.env.CONTENTSTACK_API_KEY!,
deliveryToken: process.env.CONTENTSTACK_DELIVERY_TOKEN!,
environment: process.env.CONTENTSTACK_ENVIRONMENT!,
});
const handler = createContentstackWebMcpProxyHandler({ stack, contentTypes });
export const GET = ({ request }: APIEvent) => handler(request);Then drop the stack from the component config and set mode: "proxy".
Plain Solid (no Start)
Use location.assign for navigate if you have no router, and see Vanilla JS / HTML for the bundler setup.