@@ -169,13 +169,20 @@ const graph = buildGraph([
169169 { /* WebMCP API: Expose client-side tools to browser AI agents */ }
170170 <script is:inline >
171171 (function() {
172- const mc = document.modelContext || (typeof navigator !== "undefined" && navigator.modelContext);
173- if (mc && typeof mc.registerTool === "function") {
174- try {
175- const controller = new AbortController();
176- mc.registerTool({
172+ var registered = false;
173+ var controller = typeof AbortController !== "undefined" ? new AbortController() : null;
174+
175+ function registerCodingCatWebMcp() {
176+ if (registered) return;
177+ var mc = document.modelContext || (typeof navigator !== "undefined" && navigator.modelContext);
178+ if (!mc || typeof mc.registerTool !== "function") return;
179+ registered = true;
180+ var opts = controller ? { signal: controller.signal } : undefined;
181+
182+ var tools = [
183+ {
177184 name: "search_content",
178- description: "Search CodingCat.dev tutorials, articles, podcasts , guests, and sponsors",
185+ description: "Search CodingCat.dev courses, podcasts, blog posts , guests, and sponsors",
179186 annotations: {
180187 readOnlyHint: true,
181188 untrustedContentHint: true,
@@ -185,25 +192,100 @@ const graph = buildGraph([
185192 properties: {
186193 query: {
187194 type: "string",
188- description: "Search keyword, technical topic, or library name (e.g. Astro, React, Sanity, TypeScript)",
195+ description: "Search keyword, technical topic, or library name (for example: Astro, React, Sanity, TypeScript, Cloudflare )",
189196 },
190197 },
191198 required: ["query"],
192199 },
193- execute: async ({ query }) => {
200+ execute: async function(input) {
194201 try {
195- const res = await fetch("/api/search?q=" + encodeURIComponent(query));
202+ var q = (input && input.query) ? String(input.query) : "";
203+ var res = await fetch("/api/search?q=" + encodeURIComponent(q));
196204 if (!res.ok) throw new Error("Search failed with status " + res.status);
197205 return await res.json();
198206 } catch (err) {
199207 return { error: String(err) };
200208 }
201209 },
202- }, { signal: controller.signal });
203- } catch (e) {
204- console.debug("WebMCP registration error:", e);
210+ },
211+ {
212+ name: "ask_agent_aj",
213+ description: "Ask Agent AJ technical questions about CodingCat.dev courses, podcast episodes, blog posts, and transcripts",
214+ annotations: {
215+ readOnlyHint: true,
216+ untrustedContentHint: true,
217+ },
218+ inputSchema: {
219+ type: "object",
220+ properties: {
221+ prompt: {
222+ type: "string",
223+ description: "Natural language question for Agent AJ",
224+ },
225+ },
226+ required: ["prompt"],
227+ },
228+ execute: async function(input) {
229+ try {
230+ var prompt = (input && input.prompt) ? String(input.prompt) : "";
231+ var res = await fetch("/api/chat", {
232+ method: "POST",
233+ headers: { "Content-Type": "application/json" },
234+ body: JSON.stringify({ messages: [{ role: "user", content: prompt }] }),
235+ });
236+ if (!res.ok) throw new Error("Chat failed with status " + res.status);
237+ return await res.json();
238+ } catch (err) {
239+ return { error: String(err) };
240+ }
241+ },
242+ },
243+ {
244+ name: "browse_pillar",
245+ description: "Navigate to a primary CodingCat.dev content pillar (courses, podcasts, blog, topics, or sponsorships)",
246+ annotations: {
247+ readOnlyHint: true,
248+ untrustedContentHint: false,
249+ },
250+ inputSchema: {
251+ type: "object",
252+ properties: {
253+ pillar: {
254+ type: "string",
255+ enum: ["courses", "podcasts", "blog", "topics", "sponsorships"],
256+ description: "Target content pillar to open",
257+ },
258+ },
259+ required: ["pillar"],
260+ },
261+ execute: async function(input) {
262+ var pillar = (input && input.pillar) ? String(input.pillar) : "courses";
263+ var target = "/" + pillar.replace(/^\/+/, "");
264+ window.location.assign(target);
265+ return { navigatedTo: target };
266+ },
267+ },
268+ ];
269+
270+ for (var i = 0; i < tools.length; i++) {
271+ try {
272+ Promise.resolve(mc.registerTool(tools[i], opts)).catch(function() {});
273+ } catch (e) {
274+ console.debug("WebMCP registration error:", e);
275+ }
205276 }
206277 }
278+
279+ registerCodingCatWebMcp();
280+ if (typeof document !== "undefined") {
281+ document.addEventListener("DOMContentLoaded", registerCodingCatWebMcp, { once: true });
282+ }
283+ if (typeof window !== "undefined") {
284+ window.addEventListener("load", registerCodingCatWebMcp, { once: true });
285+ window.addEventListener("pagehide", function() {
286+ if (controller) controller.abort();
287+ }, { once: true });
288+ }
207289 })();
208290 </script >
209291 { /* Per-page head extras: rel=prev/next, feed alternates, preloads. */ }
0 commit comments