Skip to main content
Glama
BrowserGenie

BrowserGenie MCP Server

by BrowserGenie

tab_to_next

Simulate Tab key navigation by moving focus to the next focusable element. Returns details of the previous and current focused elements, and indicates if focus wrapped around.

Instructions

Simulate Tab key navigation and track focus movement. Returns previous and current focused element info, and whether focus wrapped around.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
directionNoTab directionnext
shiftNoHold Shift for reverse tab order
tabIdNoTarget tab ID (defaults to currently active tab)
apiKeyNoAPI key for authentication if enabled

Implementation Reference

  • The tool handler for 'tab_to_next'. It sends a 'tab_to_next' command via WebSocket bridge to the Chrome extension, passing optional direction and shift params. The extension then simulates Tab key navigation and returns focus movement info including previous/current focused elements and whether focus wrapped around.
    server.tool(
      'tab_to_next',
      'Simulate Tab key navigation and track focus movement. Returns previous and current focused element info, and whether focus wrapped around.',
      {
        direction: z.enum(['next', 'previous']).optional().default('next').describe('Tab direction'),
        shift: z.boolean().optional().describe('Hold Shift for reverse tab order'),
        tabId: z.number().optional().describe('Target tab ID (defaults to currently active tab)'),
        apiKey: z.string().optional().describe('API key for authentication if enabled'),
      },
      async ({ direction, shift, tabId, apiKey }) => {
        const result = await bridge.sendCommand({
          command: 'tab_to_next',
          params: { direction, shift },
          tabId,
          apiKey,
          timeout: LONG_TIMEOUT,
        });
        if (!result.success) {
          return { content: [{ type: 'text', text: `Error: ${result.error?.message}` }], isError: true };
        }
        return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] };
      }
    );
  • src/tools/qa.ts:64-86 (registration)
    The tool is registered via server.tool('tab_to_next', ...) inside the registerQaTools function. This is called from registerAllTools in src/tools/index.ts which is invoked from createServer in src/server.ts.
    server.tool(
      'tab_to_next',
      'Simulate Tab key navigation and track focus movement. Returns previous and current focused element info, and whether focus wrapped around.',
      {
        direction: z.enum(['next', 'previous']).optional().default('next').describe('Tab direction'),
        shift: z.boolean().optional().describe('Hold Shift for reverse tab order'),
        tabId: z.number().optional().describe('Target tab ID (defaults to currently active tab)'),
        apiKey: z.string().optional().describe('API key for authentication if enabled'),
      },
      async ({ direction, shift, tabId, apiKey }) => {
        const result = await bridge.sendCommand({
          command: 'tab_to_next',
          params: { direction, shift },
          tabId,
          apiKey,
          timeout: LONG_TIMEOUT,
        });
        if (!result.success) {
          return { content: [{ type: 'text', text: `Error: ${result.error?.message}` }], isError: true };
        }
        return { content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }] };
      }
    );
  • The WebSocketBridge.sendCommand() method is the helper that sends the 'tab_to_next' command over WebSocket to the Chrome extension and awaits the response.
      async sendCommand(cmd: BridgeCommand): Promise<BridgeResponse> {
        if (!this.isConnected()) {
          return {
            success: false,
            error: {
              code: 'NOT_CONNECTED',
              message: 'Chrome extension is not connected. Ensure the extension is installed, enabled, and the browser is running.',
            },
          };
        }
    
        const id = crypto.randomUUID();
        const timeout = cmd.timeout ?? DEFAULT_TIMEOUT;
    
        return new Promise<BridgeResponse>((resolve, reject) => {
          const timer = setTimeout(() => {
            this.pending.delete(id);
            resolve({
              success: false,
              error: {
                code: 'TIMEOUT',
                message: `Command '${cmd.command}' timed out after ${timeout}ms`,
              },
            });
          }, timeout);
    
          this.pending.set(id, { resolve, reject, timer });
    
          const message = {
            id,
            type: 'request',
            command: cmd.command,
            params: cmd.params,
            tabId: cmd.tabId,
            apiKey: cmd.apiKey,
            timestamp: Date.now(),
          };
    
          this.client!.send(JSON.stringify(message));
        });
      }
    
      private rejectAllPending(reason: string): void {
        for (const [id, pending] of this.pending) {
          clearTimeout(pending.timer);
          pending.resolve({
            success: false,
            error: {
              code: 'CONNECTION_LOST',
              message: reason,
            },
          });
        }
        this.pending.clear();
      }
    
      async close(): Promise<void> {
        this.rejectAllPending('Server shutting down');
        if (this.client) {
          this.client.close();
          this.client = null;
        }
        return new Promise((resolve) => {
          this.wss.close(() => resolve());
        });
      }
    }
  • Input schema for 'tab_to_next': optional direction (enum 'next'/'previous', default 'next'), optional shift (boolean), optional tabId (number), optional apiKey (string).
    {
      direction: z.enum(['next', 'previous']).optional().default('next').describe('Tab direction'),
      shift: z.boolean().optional().describe('Hold Shift for reverse tab order'),
      tabId: z.number().optional().describe('Target tab ID (defaults to currently active tab)'),
      apiKey: z.string().optional().describe('API key for authentication if enabled'),
    },
Behavior2/5

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

No annotations are provided, so the description must fully disclose behavior. It mentions returns but does not explicitly state that focus actually moves (side effect) or any other behavioral traits like permissions, rate limits, or whether it is read-only. This leaves significant gaps for an agent.

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 a single concise sentence with no wasted words. It could be slightly improved by structuring the behavior and return separately, but it is still efficient and clear.

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?

No output schema exists, so the description should explain return values. It mentions previous/current focus info and wrap status, which is adequate but lacks detail on format or structure. Given the complexity (4 parameters), it is minimally complete.

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 coverage is 100%, with each parameter having a description. The tool description adds no additional meaning beyond what the schema already provides, so baseline 3 is appropriate.

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 tool simulates Tab key navigation and tracks focus movement, specifying the return info. It distinguishes from siblings like press_key (general key press) and get_tab_order (tab order retrieval) by focusing on simulation and tracking.

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

Usage Guidelines3/5

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

The description implies usage for tab navigation and focus tracking but provides no explicit guidance on when to use this tool versus alternatives such as press_key or record_focus_path. No when-not or context is given.

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/BrowserGenie/mcp'

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