PageSourceSearch

https://wonosobo.terobosan.my.id/.webmcp/bridge.js

js terobosan.my.id collected 2026-10-06 12:55:21 UTC 4,558 bytes, 96 lines download raw bytes

1(function () {
2  'use strict';
3  function readConfig() {
4    var element = document.currentScript;
5    var dataset = element && element.dataset ? element.dataset : {};
6    var packsRaw = typeof dataset.packs === 'string' && dataset.packs.length > 0 ? dataset.packs : 'site,page';
7    var packs = packsRaw.split(',').map(function (part) { return part.trim(); }).filter(function (part) { return part.length > 0; });
8    var mcpUrl = typeof dataset.mcpUrl === 'string' && dataset.mcpUrl.length > 0 ? dataset.mcpUrl : '/mcp';
9    return { packs: packs, mcpUrl: mcpUrl };
10  }
11  function textResult(payload) {
12    return { content: [{ type: 'text', text: JSON.stringify(payload) }] };
13  }
14  function head(limit, value) {
15    return (value || '').trim().slice(0, limit);
16  }
17  function collectHeadings() {
18    return Array.prototype.slice.call(document.querySelectorAll('h1, h2'), 0, 10).map(function (node) {
19      return { level: node.tagName.toLowerCase(), text: head(200, node.textContent) };
20    });
21  }
22  function collectArticleLinks() {
23    return Array.prototype.slice.call(document.querySelectorAll('a[href]'), 0, 200)
24      .map(function (node) { return { title: head(120, node.textContent), href: node.getAttribute('href') || '' }; })
25      .filter(function (link) { return link.title.length > 0 && link.href.length > 0 && link.href.charAt(0) === '/'; })
26      .slice(0, 20);
27  }
28  function pageMetadata() {
29    function meta(name) {
30      var node = document.querySelector('meta[name="' + name + '"]');
31      return node ? node.getAttribute('content') || '' : '';
32    }
33    var canonical = document.querySelector('link[rel="canonical"]');
34    return {
35      title: head(200, document.title),
36      canonical: canonical ? canonical.getAttribute('href') || '' : '',
37      description: head(300, meta('description')),
38      headings: collectHeadings(),
39      articleLinks: collectArticleLinks(),
40    };
41  }
42  function pageImages() {
43    var nodes = document.images ? document.images : [];
44    var images = Array.prototype.slice.call(nodes, 0, 20).map(function (image) {
45      return { src: image.currentSrc || image.src || '', alt: head(200, image.alt) };
46    });
47    return { imageCount: nodes.length, images: images, signatureVerified: false };
48  }
49  var config = readConfig();
50  var surface = document.modelContext;
51  if (!surface || typeof surface.registerTool !== 'function') return;
52  function safeRegister(tool) {
53    try { surface.registerTool(tool); } catch (error) { /* one bad tool never breaks the page */ }
54  }
55  var rpcId = 0;
56  function nextId() { rpcId += 1; return rpcId; }
57  function postRpc(payload) {
58    return fetch(config.mcpUrl, {
59      method: 'POST',
60      credentials: 'same-origin',
61      headers: { 'content-type': 'application/json', accept: 'application/json' },
62      body: JSON.stringify(payload),
63    }).then(function (response) { return response.json(); });
64  }
65  if (config.packs.indexOf('page') !== -1) {
66    safeRegister({
67      name: 'get_page_metadata',
68      description: 'Read this page title, canonical URL, meta description, headings, and article links. Runs entirely in the browser with no server round trip.',
69      inputSchema: { type: 'object', properties: {}, additionalProperties: false },
70      execute: async function () { return textResult(pageMetadata()); },
71    });
72    safeRegister({
73      name: 'list_page_images',
74      description: 'List up to 20 images on this page with their current source and alt text. Reports markup only, never fetches or verifies pixels.',
75      inputSchema: { type: 'object', properties: {}, additionalProperties: false },
76      execute: async function () { return textResult(pageImages()); },
77    });
78  }
79  if (config.packs.indexOf('site') !== -1) {
80    postRpc({ jsonrpc: '2.0', id: nextId(), method: 'tools/list', params: {} }).then(function (data) {
81      var tools = data && data.result && Array.isArray(data.result.tools) ? data.result.tools : [];
82      tools.forEach(function (tool) {
83        safeRegister({
84          name: tool.name,
85          description: tool.description,
86          inputSchema: tool.inputSchema,
87          execute: async function (args) {
88            var response = await postRpc({ jsonrpc: '2.0', id: nextId(), method: 'tools/call', params: { name: tool.name, arguments: args || {} } });
89            if (response.error) throw new Error(response.error.message || 'mcp_error');
90            return response.result;
91          },
92        });
93      });
94    }).catch(function () { /* MCP server unreachable: the page pack still works */ });
95  }
96})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.