// ==UserScript== // @name Google AI Studio MCP Integration // @description Add (local) MCP support to Google AI Studio // @match https://aistudio.google.com/* // @grant GM_xmlhttpRequest // @grant GM.getValue // @grant GM.setValue // ==/UserScript== const tags = { chatTurn: "ms-chat-turn", functionCallChunk: "ms-function-call-chunk", functionDeclarationsDialog: "ms-edit-function-declarations-dialog", promptChunk: "ms-prompt-chunk", dialogActions: "mat-dialog-actions", }; /** * Get the first parent with the desired tag if possible. * @param {Element} element * @param {string} tagName * @returns {Element | null} */ function getParentWithTag(element, tagName) { let parent = element.parentElement; const upperTagName = tagName.toUpperCase(); while (parent) { if (parent.tagName === upperTagName) { return parent; } parent = parent.parentElement; } return null; } /** * Safely select an element using a CSS selector or raise an error. * @param {Element} element * @param {string} selector * @returns {HTMLElement} */ function safeQuerySelector(element, selector) { const selected = element.querySelector(selector); if (selected !== null) { // @ts-ignore return selected; } else { throw new Error(`Failed to select '${selector}' from '${element}'.`); } } /** * @param {String} html representing a single node. * @return {Element} */ function htmlToNode(html) { const template = document.createElement('template'); template.innerHTML = html; const numChildren = template.content.childElementCount; if (numChildren != 1) { throw new Error(`Expected exactly one child element, got ${numChildren}.`); } // @ts-ignore return template.content.firstChild; } /** * Parse a JSON-RPC message. * @param {string} payload */ function parseJsonRpcMessage(payload) { const parts = payload.trim().split("\n"); if (parts[0] != "event: message") { throw new Error(`Expected message event, got '${parts[0]}'.`); } if (parts.length != 2) { throw new Error(`Expected message to have two lines, got ${parts.length}.`); } if (!parts[1].startsWith("data: ")) { throw new Error(`Expected 'data: ' prefix, got '${parts[1]}'.`); } return JSON.parse(parts[1].substring(6).trim()); } /** * Set the value of a