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
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden and discloses key behavioral traits: it requires a Chrome extension connection and navigates the active tab. However, it lacks details on error handling, timeouts, or what happens if the URL is invalid, leaving gaps for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized with two sentences: the first states purpose and usage, the second notes requirements. The route reference note is somewhat extraneous but not wasteful, keeping it efficient and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations, no output schema, and a simple parameter, the description covers purpose and prerequisites adequately. However, for a navigation tool that mutates browser state, it could better explain behavioral aspects like success indicators or common errors to enhance completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents the 'url' parameter fully. The description does not add meaning beyond this, such as examples of valid URLs or constraints not in the schema, meeting the baseline for high coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('navigates') and resource ('current active browser tab to a new URL'), distinguishing it from sibling tools like browser.screenshot or ui.interact by focusing on URL navigation rather than visual capture or UI interaction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit usage contexts ('automated testing, navigation flows, or redirecting to specific pages') and a prerequisite ('Requires Chrome extension to be connected'), but does not specify when not to use it or name alternatives among siblings like api.request for non-browser navigation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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