Skip to main content
Glama
Winds-AI

autonomous-frontend-browser-tools

browser.navigate

Directs the browser to load a specified URL for automated testing, navigation flows, or page redirection. Requires Chrome extension connection.

Instructions

Navigates the current active browser tab to a new URL. Use for automated testing, navigation flows, or redirecting to specific pages. Requires Chrome extension to be connected.

Route Reference: ROUTES_FILE_PATH variable is not set so make sure you know the routes to use

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesThe URL to navigate to (must be a valid URL including protocol, e.g., 'https://example.com')

Implementation Reference

  • MCP tool registration for 'browser.navigate', including schema (url: string), description, and inline handler that POSTs to browser-connector /navigate-tab endpoint.
    server.tool(
      "browser.navigate",
      generateNavigateToolDescription(),
      {
        url: z
          .string()
          .describe(
            `The URL to navigate to (must be a valid URL including protocol, e.g., 'https://example.com')`
          ),
      },
      async (params) => {
        return await withServerConnection(async () => {
          try {
            const { url } = params;
    
            // Validate URL format
            try {
              new URL(url);
            } catch (e) {
              return {
                content: [
                  {
                    type: "text",
                    text: `Invalid URL format: ${url}. Please provide a complete URL including protocol (e.g., 'https://example.com')`,
                  },
                ],
                isError: true,
              };
            }
    
            const targetUrl = `http://${discoveredHost}:${discoveredPort}/navigate-tab`;
            const requestPayload = {
              url: url,
            };
    
            console.log(`MCP Tool: Navigating browser tab to ${url}`);
    
            const response = await fetch(targetUrl, {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
              },
              body: JSON.stringify(requestPayload),
            });
    
            const result = await response.json();
    
            if (response.ok && result.success) {
              return {
                content: [
                  {
                    type: "text",
                    text: `✅ Successfully navigated browser tab to: ${url}`,
                  },
                ],
              };
            } else {
              return {
                content: [
                  {
                    type: "text",
                    text: `Failed to navigate browser tab: ${
                      result.error || "Unknown error"
                    }`,
                  },
                ],
                isError: true,
              };
            }
          } catch (error: any) {
            const errorMessage =
              error instanceof Error ? error.message : String(error);
            return {
              content: [
                {
                  type: "text",
                  text: `Failed to navigate browser tab: ${errorMessage}`,
                },
              ],
              isError: true,
            };
          }
        });
      }
    );
  • Core handler for POST /navigate-tab: validates URL, sends WebSocket message to Chrome extension via buildNavigationMessage, awaits 'navigation-response' via parseNavigationResponse, returns success/error.
    async navigateTab(
      req: express.Request,
      res: express.Response
    ): Promise<void> {
      if ((process.env.LOG_LEVEL || "info").toLowerCase() === "debug") {
        console.log("[debug] navigateTab handler", req.body);
      }
      logInfo("Browser Connector: Received navigateTab request");
      logDebug("Browser Connector: Request body:", req.body);
    
      const { url } = req.body;
    
      if (!url) {
        res.status(400).json({ error: "Missing URL parameter" });
        return;
      }
    
      if (!this.activeConnection) {
        res.status(503).json({ error: "Chrome extension not connected" });
        return;
      }
    
      try {
        logDebug("Browser Connector: Sending navigation request to extension");
    
        // Create a promise that will resolve when we get the navigation response
        const navigationPromise = new Promise<{
          success: boolean;
          error?: string;
        }>((resolve, reject) => {
          const requestId = Date.now().toString();
    
          // Set up a one-time message handler for this navigation request
          const messageHandler = (
            message: string | Buffer | ArrayBuffer | Buffer[]
          ) => {
            try {
              const data = JSON.parse(message.toString());
    
              // Parse navigation response using tool helper (statically imported)
              const parsed = parseNavigationResponse(data, requestId);
              if (parsed) {
                // Remove this listener once we get a response
                this.activeConnection?.removeListener("message", messageHandler);
    
                if (parsed.success) {
                  resolve({ success: true });
                } else {
                  resolve({ success: false, error: parsed.error });
                }
              }
            } catch (error) {
              // Ignore parsing errors for other messages
            }
          };
    
          // Add temporary message handler
          this.activeConnection?.on("message", messageHandler);
    
          // Send navigation request to extension (using tool builder - statically imported)
          this.activeConnection?.send(buildNavigationMessage({ url }, requestId));
    
          // Set timeout
          setTimeout(() => {
            this.activeConnection?.removeListener("message", messageHandler);
            reject(new Error("Navigation timeout"));
          }, 10000); // 10 second timeout
        });
    
        const result = await navigationPromise;
    
        if (result.success) {
          logInfo("Browser Connector: Navigation completed successfully");
          res.json({ success: true, url: url });
        } else {
          console.error(
            "[error] Browser Connector: Navigation failed:",
            result.error
          );
          res.status(500).json({ error: result.error || "Navigation failed" });
        }
      } catch (error) {
        console.error(
          "[error] Browser Connector: Error during navigation:",
          error
        );
        res.status(500).json({
          error:
            error instanceof Error
              ? error.message
              : "An unknown error occurred during navigation",
        });
      }
    }
  • Helpers for navigation: buildNavigationMessage creates WS payload {type: 'navigate-tab', url, requestId}; parseNavigationResponse validates incoming 'navigation-response'.
    export function buildNavigationMessage(
      req: { url: string },
      requestId: string
    ) {
      return JSON.stringify({
        type: "navigate-tab",
        url: req.url,
        requestId,
      });
    }
    
    /**
     * Narrow and validate the navigation response coming back over WebSocket.
     */
    export function parseNavigationResponse(
      data: any,
      expectedRequestId: string
    ): NavigationResult | undefined {
      if (
        data &&
        data.type === "navigation-response" &&
        data.requestId === expectedRequestId
      ) {
        if (data.success) {
          return { success: true };
        }
        return { success: false, error: data.error };
      }
      return undefined;
  • Chrome extension background script handler for 'NAVIGATE_TAB' message: executes chrome.tabs.update(targetTabId, {url: message.url}) to perform the actual navigation.
    if (message.type === "NAVIGATE_TAB" && message.url) {
      console.log("Background: Received navigation request:", message);
    
      const targetTabId =
        message.tabId || chrome.devtools?.inspectedWindow?.tabId;
    
      if (!targetTabId) {
        console.error("Background: No target tab ID available for navigation");
        sendResponse({ success: false, error: "No target tab ID available" });
        return true;
      }
    
      // Navigate the tab to the specified URL
      chrome.tabs.update(targetTabId, { url: message.url }, (tab) => {
        if (chrome.runtime.lastError) {
          console.error(
            "Background: Navigation failed:",
            chrome.runtime.lastError
          );
          sendResponse({
            success: false,
            error: chrome.runtime.lastError.message,
          });
        } else {
          console.log("Background: Navigation successful to:", message.url);
          // Update our cache with the new URL
          tabUrls.set(targetTabId, message.url);
          sendResponse({ success: true, url: message.url });
        }
      });
      return true; // Required to use sendResponse asynchronously

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Winds-AI/Frontend-development-MCP-tools-public'

If you have feedback or need assistance with the MCP directory API, please join our Discord server