#
tokens: 12366/50000 21/21 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── assets
│   ├── claude-installed.png
│   ├── claude-open.gif
│   ├── claude-use.png
│   └── cursor.png
├── Dockerfile
├── LICENSE
├── package.json
├── pnpm-lock.yaml
├── README.MD
├── smithery.yaml
├── src
│   ├── constants
│   │   └── api.ts
│   ├── handlers
│   │   ├── application.ts
│   │   ├── automation.ts
│   │   ├── browser.ts
│   │   └── group.ts
│   ├── index.ts
│   ├── types
│   │   ├── application.ts
│   │   ├── browser.ts
│   │   ├── group.ts
│   │   ├── handlerWrapper.ts
│   │   └── schemas.ts
│   └── utils
│       ├── browserBase.ts
│       ├── handlerWrapper.ts
│       ├── requestBuilder.ts
│       └── toolRegister.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
.pnpm-store/

# Build output
dist/
build/
out/
.output/

# IDE and editor files
.idea/
.vscode/
*.swp
*.swo
.DS_Store
*.sublime-workspace
*.sublime-project

# Environment variables
.env
.env.local
.env.*.local
.env.development
.env.test
.env.production

# Cache and temporary files
.cache/
.temp/
.tmp/
coverage/
*.log
.eslintcache

# System files
Thumbs.db
.DS_Store
*.pem

# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# Local files
*.local

# Testing
coverage/
.nyc_output/

# Typescript
*.tsbuildinfo 
```

--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------

```markdown
# AdsPower LocalAPI MCP Server

A Model Context Protocol server that AdsPower browser LocalAPI. This server enables LLMs to interact with start browser, create browser, update browser fingerprint config ...


## Usage with Claude Desktop

Talk to LLMs to create browser: `Create an Android UA browser using Chrome 134`

![Claude desktop](https://github.com/AdsPower/local-api-mcp-typescript/blob/main/assets/claude-use.png)

Talk to LLMs to create browser: `Help me with random UA, random fingerprint, random cookie generation, create 3 browsers, use 134 cores, and open them`

![Claude desktop](https://github.com/AdsPower/local-api-mcp-typescript/blob/main/assets/claude-open.gif)

## How to use?

### Requirements

- [AdsPower](https://www.adspower.com/?source=github)

- Node version 18 or greater

### Installation

To use with Claude Desktop, add the server config:

On macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` On Windows: `%APPDATA%/Claude/claude_desktop_config.json`

#### MacOS / Linux
```bash
{
  "mcpServers": {
    "adspower-local-api": {
      "command": "npx",
      "args": ["-y", "local-api-mcp-typescript"]
    }
  }
}
```

#### Windows
```bash
{
  "mcpServers": {
    "adspower-local-api": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "local-api-mcp-typescript"]
    }
  }
}
```

![Claude desktop MCP](https://github.com/AdsPower/local-api-mcp-typescript/blob/main/assets/claude-installed.png)

or use in Cursor
![Cursor](./assets/cursor.png)

## Development

```bash
# git clone 
git clone https://github.com/AdsPower/local-api-mcp-typescript.git

# install package
cd local-api-mcp-typescript && npx pnpm i

# build
npm run build
```

```bash
# Add the server to your claude_desktop_config.json
"mcpServers": {
  "adspower-local-api": {
        "command": "node",
        "args": [
            "<Replace Your Project Path>/local-api-mcp-typescript/build/index.js"
        ]
    }
}
```

## Components

### Tools

- **open_browser**
  - Open the browser
  - Inputs: 
    - `serialNumber` (string, optional): The serial number of the browser to open
    - `userId` (string, optional): The browser id of the browser to open

- **close_browser**
  - Close the browser
  - Input: 
    - `userId` (string): The browser id of the browser to stop

- **create_browser**
  - Create a browser
  - Inputs:
    - `groupId` (string): The group id for the browser
    - `domainName` (string, optional): The domain name
    - `openUrls` (string[], optional): URLs to open
    - `cookie` (string, optional): Browser cookie
    - `username` (string, optional): Username
    - `password` (string, optional): Password
    - `system` (string, optional): System type
    - `name` (string, optional): Browser name
    - `country` (string, optional): Country
    - `sysAppCateId` (string, optional): System application category id
    - `storageStrategy` (number, optional): Storage strategy
    - `userProxyConfig` (object): Proxy configuration
    - `fingerprintConfig` (object, optional): Browser fingerprint configuration

- **update_browser**
  - Update the browser
  - Inputs: Same as create_browser, plus:
    - `userId` (string): The user id of the browser to update

- **delete_browser**
  - Delete the browser
  - Input:
    - `userIds` (string[]): The user ids of the browsers to delete

- **get_browser_list**
  - Get the list of browsers
  - Inputs:
    - `groupId` (string, optional): The group id of the browser
    - `size` (number, optional): The size of the page
    - `id` (string, optional): The id of the browser
    - `serialNumber` (string, optional): The serial number of the browser
    - `sort` (enum, optional): Sort field ('serial_number' | 'last_open_time' | 'created_time')
    - `order` (enum, optional): Sort order ('asc' | 'desc')

- **get-opened_browser**
  - Get the list of opened browsers
  - No inputs required

- **move_browser**
  - Move browsers to a group
  - Inputs:
    - `groupId` (string): The target group id
    - `userIds` (string[]): The browser ids to move

- **create_group**
  - Create a browser group
  - Inputs:
    - `groupName` (string): The name of the group to create
    - `remark` (string, optional): The remark of the group

- **update_group**
  - Update the browser group
  - Inputs:
    - `groupId` (string): The id of the group to update
    - `groupName` (string): The new name of the group
    - `remark` (string | null, optional): The new remark of the group, set null to clear

- **get_group_list**
  - Get the list of groups
  - Inputs:
    - `name` (string, optional): The name of the group
    - `size` (number, optional): The size of the page

- **get-application_list**
  - Get the list of applications
  - Input:
    - `size` (number, optional): The size of the page

### Advanced Configuration Types

#### UserProxyConfig
- `proxy_soft` (enum): The proxy soft type ('brightdata', 'brightauto', 'oxylabsauto', etc.)
- `proxy_type` (enum, optional): Proxy type ('http', 'https', 'socks5', 'no_proxy')
- `proxy_host` (string, optional): Proxy host
- `proxy_port` (string, optional): Proxy port
- `proxy_user` (string, optional): Proxy username
- `proxy_password` (string, optional): Proxy password
- `proxy_url` (string, optional): Proxy URL
- `global_config` (enum, optional): Global config ('0' | '1')

#### FingerprintConfig
- `automatic_timezone` (enum, optional): Automatic timezone ('0' | '1')
- `timezone` (string, optional): Timezone
- `language` (string[], optional): Languages
- `flash` (string, optional): Flash version
- `fonts` (string[], optional): Font list
- `webrtc` (enum, optional): WebRTC setting ('disabled' | 'forward' | 'proxy' | 'local')
- `browser_kernel_config` (object, optional):
  - `version` (string, optional): Browser version
  - `type` (enum, optional): Browser type ('chrome' | 'firefox')
- `random_ua` (object, optional):
  - `ua_version` (string[], optional): User agent versions
  - `ua_system_version` (enum[], optional): System versions
- `tls_switch` (enum, optional): TLS switch ('0' | '1')
- `tls` (string, optional): TLS configuration
```

--------------------------------------------------------------------------------
/src/types/application.ts:
--------------------------------------------------------------------------------

```typescript
export interface GetApplicationListParams {
    size?: number;
} 
```

--------------------------------------------------------------------------------
/src/types/group.ts:
--------------------------------------------------------------------------------

```typescript
export interface CreateGroupParams {
    groupName: string;
    remark?: string;
}

export interface UpdateGroupParams {
    groupId: string;
    groupName: string;
    remark?: string | null;
}

export interface GetGroupListParams {
    groupName?: string;
    size?: number;
    page?: number;
} 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
    "compilerOptions": {
        "target": "ESNext",
        "module": "CommonJS",
        "moduleResolution": "Node",
        "outDir": "./build",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules"]
}

```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
# Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml

startCommand:
  type: stdio
  configSchema:
    # JSON Schema defining the configuration options for the MCP.
    type: object
    properties: {}
  commandFunction:
    # A JS function that produces the CLI command based on the given config to start the MCP on stdio.
    |-
    (config) => ({
      command: 'node',
      args: ['build/index.js'],
      env: {}
    })
  exampleConfig: {}

```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
# Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
FROM node:lts-alpine

WORKDIR /app

# Install dependencies
COPY package.json pnpm-lock.yaml ./

# Use npm install if pnpm is not available
RUN npm install --ignore-scripts

# Copy remaining source files
COPY tsconfig.json ./
COPY src ./src

# Build the project (transpiling TypeScript to JavaScript)
RUN npm run build

# Expose no ports as MCP runs via stdio; if needed, expose port here

# Set entrypoint
ENTRYPOINT ["node", "build/index.js"]

```

--------------------------------------------------------------------------------
/src/types/handlerWrapper.ts:
--------------------------------------------------------------------------------

```typescript
export function wrapHandler(handler: Function) {
    return async (params: any) => {
        try {
            const result = await handler(params);
            return {
                content: [{
                    type: 'text',
                    text: result
                }]
            };
        } catch (error) {
            return {
                content: [{
                    type: 'text',
                    text: error instanceof Error ? error.message : String(error)
                }]
            };
        }
    };
} 
```

--------------------------------------------------------------------------------
/src/handlers/application.ts:
--------------------------------------------------------------------------------

```typescript
import axios from 'axios';
import { LOCAL_API_BASE, API_ENDPOINTS } from '../constants/api.js';
import type { GetApplicationListParams } from '../types/application.js';

export const applicationHandlers = {
    async getApplicationList({ size }: GetApplicationListParams) {
        const params = new URLSearchParams();
        if (size) {
            params.set('page_size', size.toString());
        }

        const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.GET_APPLICATION_LIST}`, { params });
        return `Application list: ${JSON.stringify(response.data.data.list, null, 2)}`;
    }
}; 
```

--------------------------------------------------------------------------------
/src/constants/api.ts:
--------------------------------------------------------------------------------

```typescript
export const LOCAL_API_BASE = 'http://127.0.0.1:50325';

export const API_ENDPOINTS = {
    START_BROWSER: '/api/v1/browser/start',
    CLOSE_BROWSER: '/api/v1/browser/stop',
    CREATE_BROWSER: '/api/v1/user/create',
    GET_BROWSER_LIST: '/api/v1/user/list',
    GET_GROUP_LIST: '/api/v1/group/list',
    GET_APPLICATION_LIST: '/api/v1/application/list',
    UPDATE_BROWSER: '/api/v1/user/update',
    DELETE_BROWSER: '/api/v1/user/delete',
    GET_OPENED_BROWSER: '/api/v1/browser/local-active',
    CREATE_GROUP: '/api/v1/group/create',
    UPDATE_GROUP: '/api/v1/group/update',
    MOVE_BROWSER: '/api/v1/user/regroup'
} as const; 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "local-api-mcp-typescript",
  "version": "1.0.6",
  "main": "index.js",
  "type": "commonjs",
  "bin": {
    "adspower-local-api-mcp": "./build/index.js"
  },
  "scripts": {
    "build": "tsc",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "files": [
    "build"
  ],
  "keywords": [
    "adspower",
    "local-api",
    "mcp",
    "typescript"
  ],
  "author": "AdsPower",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.7.0",
    "axios": "^1.8.4",
    "playwright": "^1.51.1",
    "zod": "^3.24.2"
  },
  "devDependencies": {
    "@types/node": "^22.13.13",
    "typescript": "^5.8.2"
  },
  "engines": {
    "node": ">=18.0.0"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/AdsPower/local-api-mcp-typescript.git"
  },
  "bugs": {
    "url": "https://github.com/AdsPower/local-api-mcp-typescript/issues"
  },
  "homepage": "https://github.com/AdsPower/local-api-mcp-typescript#readme"
}

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { registerTools } from './utils/toolRegister.js';
// import { getScreenshot } from './handlers/automation.js';
// Create server instance
const server = new McpServer({
    name: 'adspower-local-api',
    version: '1.0.6',
    capabilities: {
        resources: {},
        tools: {},
    },
});

// Register all tools
registerTools(server);

// Resources
// server.resource('get-screenshot', 'Get the screenshot of the page', async (uri, extra) => {
//     const filename = uri.toString().split("://")[1];
//     const screenshot = getScreenshot(filename);
//     if (!screenshot) {
//         return {
//             contents: [],
//             mimeType: 'text/plain',
//         };
//     }
//     return {
//         contents: [{
//             uri: filename,
//             blob: screenshot,
//             mimeType: 'image/png',
//         }],
//     };
// });

async function main() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.error('AdsPower Local Api MCP Server running on stdio');
}

main().catch((error) => {
    console.error('Fatal error in main():', error);
    process.exit(1);
});

```

--------------------------------------------------------------------------------
/src/utils/browserBase.ts:
--------------------------------------------------------------------------------

```typescript
import { Browser, Page, chromium } from 'playwright';

class BrowserBase {
    private browser: Browser | null;
    private page: Page | null;
    private screenshots: Map<string, string>;

    constructor() {
        this.browser = null;
        this.page = null;
        this.screenshots = new Map();
    }

    get browserInstance() {
        return this.browser;
    }

    get pageInstance() {
        return this.page;
    }

    set pageInstance(page: Page | null) {
        this.page = page;
    }

    get screenshotsInstance() {
        return this.screenshots;
    }

    checkConnected() {
        const error = new Error('Browser not connected, please connect browser first');
        if (!this.browser) {
            throw error;
        }
        if (!this.browser.isConnected()) {
            throw error;
        }
        if (!this.page) {
            throw error;
        }
    }
    
    async connectBrowserWithWs(wsUrl: string) {
        this.browser = await chromium.connectOverCDP(wsUrl);
        const defaultContext = this.browser.contexts()[0];
        this.page = defaultContext.pages()[0];
        await this.page.bringToFront().catch((error) => {
            console.error('Failed to bring page to front', error);
        });
    }

    async resetBrowser() {
        this.browser = null;
        this.page = null;
    }
}

export default new BrowserBase();

```

--------------------------------------------------------------------------------
/src/utils/handlerWrapper.ts:
--------------------------------------------------------------------------------

```typescript
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
import browser from './browserBase.js';

export function wrapHandler(handler: Function) {
    return async (params: any): Promise<CallToolResult> => {
        try {
            const content = await handler(params);
            if (typeof content === 'string') {
                return {
                    content: [{
                        type: 'text' as const,
                        text: content
                    }]
                };
            }
            return {
                content
            };
        } catch (error) {
            let errorMessage = error instanceof Error ? error.message : String(error);
            if (
                errorMessage.includes("Target page, context or browser has been closed") ||
                errorMessage.includes("Target closed") ||
                errorMessage.includes("Browser has been disconnected") ||
                errorMessage.includes("Protocol error") ||
                errorMessage.includes("Connection closed")
            ) {
                await browser.resetBrowser();
                errorMessage = `Browser connection error: ${errorMessage}. Connection has been reset - please retry the operation.`;
            }
            return {
                content: [{
                    type: 'text' as const,
                    text: errorMessage
                }]
            };
        }
    };
} 
```

--------------------------------------------------------------------------------
/src/types/browser.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from 'zod';
import { schemas } from './schemas.js';

// 从已有的 schema 中导出类型
export type CreateBrowserParams = z.infer<typeof schemas.createBrowserSchema>;
export type UpdateBrowserParams = z.infer<typeof schemas.updateBrowserSchema>;
export type OpenBrowserParams = z.infer<typeof schemas.openBrowserSchema>;
export type CloseBrowserParams = z.infer<typeof schemas.closeBrowserSchema>;
export type DeleteBrowserParams = z.infer<typeof schemas.deleteBrowserSchema>;
export type GetBrowserListParams = z.infer<typeof schemas.getBrowserListSchema>;
export type MoveBrowserParams = z.infer<typeof schemas.moveBrowserSchema>;
export type CreateAutomationParams = z.infer<typeof schemas.createAutomationSchema>;
export type NavigateParams = z.infer<typeof schemas.navigateSchema>;
export type ScreenshotParams = z.infer<typeof schemas.screenshotSchema>;
export type ClickElementParams = z.infer<typeof schemas.clickElementSchema>;
export type FillInputParams = z.infer<typeof schemas.fillInputSchema>;
export type SelectOptionParams = z.infer<typeof schemas.selectOptionSchema>;
export type HoverElementParams = z.infer<typeof schemas.hoverElementSchema>;
export type ScrollElementParams = z.infer<typeof schemas.scrollElementSchema>;
export type PressKeyParams = z.infer<typeof schemas.pressKeySchema>;
export type EvaluateScriptParams = z.infer<typeof schemas.evaluateScriptSchema>;
export type DragElementParams = z.infer<typeof schemas.dragElementSchema>;
export type IframeClickElementParams = z.infer<typeof schemas.iframeClickElementSchema>;
```

--------------------------------------------------------------------------------
/src/utils/requestBuilder.ts:
--------------------------------------------------------------------------------

```typescript
import { CreateBrowserParams, UpdateBrowserParams } from '../types/browser.js';

export function buildRequestBody(params: CreateBrowserParams | UpdateBrowserParams): Record<string, any> {
    const requestBody: Record<string, any> = {};

    const basicFields: Record<string, string> = {
        domainName: 'domain_name',
        openUrls: 'open_urls',
        cookie: 'cookie',
        username: 'username',
        password: 'password',
        groupId: 'group_id',
        name: 'name',
        country: 'country',
        sysAppCateId: 'sys_app_cate_id',
        userId: 'user_id'
    };
    Object.entries(basicFields).forEach(([paramKey, key]) => {
        const value = params[paramKey as keyof typeof params];
        if (value !== undefined) {
            requestBody[key] = value;
        }
    });

    if (params.userProxyConfig) {
        const proxyConfig = buildNestedConfig(params.userProxyConfig);
        if (Object.keys(proxyConfig).length > 0) {
            requestBody.user_proxy_config = proxyConfig;
        }
    }

    if (params.fingerprintConfig) {
        const fpConfig = buildNestedConfig(params.fingerprintConfig);
        if (Object.keys(fpConfig).length > 0) {
            requestBody.fingerprint_config = fpConfig;
        }
    }

    if (params.storageStrategy !== undefined) {
        requestBody.storage_strategy = params.storageStrategy;
    }

    return requestBody;
}

function buildNestedConfig(config: Record<string, any>): Record<string, any> {
    const result: Record<string, any> = {};

    Object.entries(config).forEach(([key, value]) => {
        if (value !== undefined) {
            if (typeof value === 'object' && value !== null) {
                const nestedConfig = buildNestedConfig(value);
                if (Object.keys(nestedConfig).length > 0) {
                    result[key] = nestedConfig;
                }
            } else {
                result[key] = value;
            }
        }
    });

    return result;
} 
```

--------------------------------------------------------------------------------
/src/handlers/group.ts:
--------------------------------------------------------------------------------

```typescript
import axios from 'axios';
import { LOCAL_API_BASE, API_ENDPOINTS } from '../constants/api.js';
import type {
    CreateGroupParams,
    UpdateGroupParams,
    GetGroupListParams
} from '../types/group.js';

export const groupHandlers = {
    async createGroup({ groupName, remark }: CreateGroupParams) {
        const requestBody: Record<string, string> = {
            group_name: groupName
        };
        
        if (remark !== undefined) {
            requestBody.remark = remark;
        }

        const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.CREATE_GROUP}`, requestBody);
        
        if (response.data.code === 0) {
            return `Group created successfully with name: ${groupName}${remark ? `, remark: ${remark}` : ''}`;
        }
        throw new Error(`Failed to create group: ${response.data.msg}`);
    },

    async updateGroup({ groupId, groupName, remark }: UpdateGroupParams) {
        const requestBody: Record<string, any> = {
            group_id: groupId,
            group_name: groupName
        };
        
        if (remark !== undefined) {
            requestBody.remark = remark;
        }

        const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.UPDATE_GROUP}`, requestBody);
        
        if (response.data.code === 0) {
            return `Group updated successfully with id: ${groupId}, name: ${groupName}${remark !== undefined ? `, remark: ${remark === null ? '(cleared)' : remark}` : ''}`;
        }
        throw new Error(`Failed to update group: ${response.data.msg}`);
    },

    async getGroupList({ groupName, size, page }: GetGroupListParams) {
        const params = new URLSearchParams();
        if (groupName) {
            params.set('group_name', groupName);
        }
        if (size) {
            params.set('page_size', size.toString());
        }
        if (page) {
            params.set('page', page.toString());
        }

        const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.GET_GROUP_LIST}`, { params });
        return `Group list: ${JSON.stringify(response.data.data.list, null, 2)}`;
    }
}; 
```

--------------------------------------------------------------------------------
/src/utils/toolRegister.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { browserHandlers } from '../handlers/browser.js';
import { groupHandlers } from '../handlers/group.js';
import { applicationHandlers } from '../handlers/application.js';
import { schemas } from '../types/schemas.js';
import { wrapHandler } from './handlerWrapper.js';
import { automationHandlers } from '../handlers/automation.js';

export function registerTools(server: McpServer) {
    // Browser tools
    server.tool('open-browser', 'Open the browser, both environment and profile mean browser', schemas.openBrowserSchema.shape, 
        wrapHandler(browserHandlers.openBrowser));
    
    server.tool('close-browser', 'Close the browser', schemas.closeBrowserSchema.shape,
        wrapHandler(browserHandlers.closeBrowser));
    
    server.tool('create-browser', 'Create a browser', schemas.createBrowserSchema.shape,
        wrapHandler(browserHandlers.createBrowser));
    
    server.tool('update-browser', 'Update the browser', schemas.updateBrowserSchema.shape,
        wrapHandler(browserHandlers.updateBrowser));
    
    server.tool('delete-browser', 'Delete the browser', schemas.deleteBrowserSchema.shape,
        wrapHandler(browserHandlers.deleteBrowser));
    
    server.tool('get-browser-list', 'Get the list of browsers', schemas.getBrowserListSchema.shape,
        wrapHandler(browserHandlers.getBrowserList));
    
    server.tool('get-opened-browser', 'Get the list of opened browsers', schemas.emptySchema.shape,
        wrapHandler(browserHandlers.getOpenedBrowser));
    
    server.tool('move-browser', 'Move browsers to a group', schemas.moveBrowserSchema.shape,
        wrapHandler(browserHandlers.moveBrowser));

    // Group tools
    server.tool('create-group', 'Create a browser group', schemas.createGroupSchema.shape,
        wrapHandler(groupHandlers.createGroup));
    
    server.tool('update-group', 'Update the browser group', schemas.updateGroupSchema.shape,
        wrapHandler(groupHandlers.updateGroup));
    
    server.tool('get-group-list', 'Get the list of groups', schemas.getGroupListSchema.shape,
        wrapHandler(groupHandlers.getGroupList));

    // Application tools
    server.tool('get-application-list', 'Get the list of applications', schemas.getApplicationListSchema.shape,
        wrapHandler(applicationHandlers.getApplicationList));
    
    // Automation tools
    server.tool('connect-browser-with-ws', 'Connect the browser with the ws url', schemas.createAutomationSchema.shape,
        wrapHandler(automationHandlers.connectBrowserWithWs));
    
    server.tool('open-new-page', 'Open a new page', schemas.emptySchema.shape,
        wrapHandler(automationHandlers.openNewPage));
        
    server.tool('navigate', 'Navigate to the url', schemas.navigateSchema.shape,
        wrapHandler(automationHandlers.navigate));

    server.tool('screenshot', 'Get the screenshot of the page', schemas.screenshotSchema.shape,
        wrapHandler(automationHandlers.screenshot));

    server.tool('get-page-visible-text', 'Get the visible text content of the page', schemas.emptySchema.shape,
        wrapHandler(automationHandlers.getPageVisibleText));

    server.tool('get-page-html', 'Get the html content of the page', schemas.emptySchema.shape,
        wrapHandler(automationHandlers.getPageHtml));

    server.tool('click-element', 'Click the element', schemas.clickElementSchema.shape,
        wrapHandler(automationHandlers.clickElement));

    server.tool('fill-input', 'Fill the input', schemas.fillInputSchema.shape,
        wrapHandler(automationHandlers.fillInput));

    server.tool('select-option', 'Select the option', schemas.selectOptionSchema.shape,
        wrapHandler(automationHandlers.selectOption));

    server.tool('hover-element', 'Hover the element', schemas.hoverElementSchema.shape,
        wrapHandler(automationHandlers.hoverElement));

    server.tool('scroll-element', 'Scroll the element', schemas.scrollElementSchema.shape,
        wrapHandler(automationHandlers.scrollElement));

    server.tool('press-key', 'Press the key', schemas.pressKeySchema.shape,
        wrapHandler(automationHandlers.pressKey));

    server.tool('evaluate-script', 'Evaluate the script', schemas.evaluateScriptSchema.shape,
        wrapHandler(automationHandlers.evaluateScript));

    server.tool('drag-element', 'Drag the element', schemas.dragElementSchema.shape,
        wrapHandler(automationHandlers.dragElement));

    server.tool('iframe-click-element', 'Click the element in the iframe', schemas.iframeClickElementSchema.shape,
        wrapHandler(automationHandlers.iframeClickElement));
} 
```

--------------------------------------------------------------------------------
/src/handlers/browser.ts:
--------------------------------------------------------------------------------

```typescript
import axios from 'axios';
import { LOCAL_API_BASE, API_ENDPOINTS } from '../constants/api.js';
import { buildRequestBody } from '../utils/requestBuilder.js';
import type { 
    OpenBrowserParams,
    CloseBrowserParams,
    CreateBrowserParams,
    UpdateBrowserParams,
    DeleteBrowserParams,
    GetBrowserListParams,
    MoveBrowserParams
} from '../types/browser.js';

export const browserHandlers = {
    async openBrowser({ serialNumber, userId, ipTab, launchArgs, clearCacheAfterClosing, cdpMask }: OpenBrowserParams) {
        const params = new URLSearchParams();
        if (serialNumber) {
            params.set('serial_number', serialNumber);
        }
        if (userId) {
            params.set('user_id', userId);
        }
        if (ipTab) {
            params.set('open_tabs', ipTab);
        }
        if (launchArgs) {
            params.set('launch_args', launchArgs);
        }
        if (clearCacheAfterClosing) {
            params.set('clear_cache_after_closing', clearCacheAfterClosing);
        }
        if (cdpMask) {
            params.set('cdp_mask', cdpMask);
        }
        params.set('open_tabs', '0');

        const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.START_BROWSER}`, { params });
        if (response.data.code === 0) {
            return `Browser opened successfully with: ${Object.entries(response.data.data).map(([key, value]) => {
                if (value && typeof value === 'object') {
                    return Object.entries(value).map(([key, value]) => `ws.${key}: ${value}`).join('\n');
                }
                return `${key}: ${value}`;
            }).join('\n')}`;
        }
        throw new Error(`Failed to open browser: ${response.data.msg}`);
    },

    async closeBrowser({ userId }: CloseBrowserParams) {
        const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.CLOSE_BROWSER}`, {
            params: { user_id: userId }
        });
        return 'Browser closed successfully';
    },

    async createBrowser(params: CreateBrowserParams) {
        const requestBody = buildRequestBody(params);
        const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.CREATE_BROWSER}`, requestBody);
        
        if (response.data.code === 0) {
            return `Browser created successfully with: ${Object.entries(response.data.data).map(([key, value]) => `${key}: ${value}`).join('\n')}`;
        }
        throw new Error(`Failed to create browser: ${response.data.msg}`);
    },

    async updateBrowser(params: UpdateBrowserParams) {
        const requestBody = buildRequestBody({
            ...params
        });
        requestBody.user_id = params.userId;

        const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.UPDATE_BROWSER}`, requestBody);
        
        if (response.data.code === 0) {
            return `Browser updated successfully with: ${Object.entries(response.data.data).map(([key, value]) => `${key}: ${value}`).join('\n')}`;
        }
        throw new Error(`Failed to update browser: ${response.data.msg}`);
    },

    async deleteBrowser({ userIds }: DeleteBrowserParams) {
        const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.DELETE_BROWSER}`, {
            user_ids: userIds
        });
        
        if (response.data.code === 0) {
            return `Browsers deleted successfully: ${userIds.join(', ')}`;
        }
        throw new Error(`Failed to delete browsers: ${response.data.msg}`);
    },

    async getBrowserList(params: GetBrowserListParams) {
        const { groupId, size, id, serialNumber, sort, order, page } = params;
        const urlParams = new URLSearchParams();
        if (size) {
            urlParams.set('page_size', size.toString());
        }
        if (page) {
            urlParams.set('page', page.toString());
        }
        if (id) {
            urlParams.set('user_id', id);
        }
        if (groupId) {
            urlParams.set('group_id', groupId);
        }
        if (serialNumber) {
            urlParams.set('serial_number', serialNumber);
        }
        if (sort) {
            urlParams.set('user_sort', JSON.stringify({
                [sort]: order || 'asc',
            }));
        }

        const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.GET_BROWSER_LIST}`, { params: urlParams });
        return `Browser list: ${JSON.stringify(response.data.data.list, null, 2)}`;
    },

    async getOpenedBrowser() {
        const response = await axios.get(`${LOCAL_API_BASE}${API_ENDPOINTS.GET_OPENED_BROWSER}`);
        
        if (response.data.code === 0) {
            return `Opened browser list: ${JSON.stringify(response.data.data.list, null, 2)}`;
        }
        throw new Error(`Failed to get opened browsers: ${response.data.msg}`);
    },

    async moveBrowser({ groupId, userIds }: MoveBrowserParams) {
        const response = await axios.post(`${LOCAL_API_BASE}${API_ENDPOINTS.MOVE_BROWSER}`, {
            group_id: groupId,
            user_ids: userIds
        });

        if (response.data.code === 0) {
            return `Browsers moved successfully to group ${groupId}: ${userIds.join(', ')}`;
        }
        throw new Error(`Failed to move browsers: ${response.data.msg}`);
    }
}; 
```

--------------------------------------------------------------------------------
/src/handlers/automation.ts:
--------------------------------------------------------------------------------

```typescript
import path from 'path';
import os from 'os';
import type { CreateAutomationParams, NavigateParams, ScreenshotParams, ClickElementParams, FillInputParams, SelectOptionParams, HoverElementParams, ScrollElementParams, PressKeyParams, EvaluateScriptParams, DragElementParams, IframeClickElementParams } from '../types/browser.js';
import browser from '../utils/browserBase.js';

const defaultDownloadsPath = path.join(os.homedir(), 'Downloads');

export const automationHandlers = {
    async connectBrowserWithWs({ wsUrl }: CreateAutomationParams) {
        try {
            await browser.connectBrowserWithWs(wsUrl);
            return `Browser connected successfully with: ${wsUrl}`;
        } catch (error) {
            return `Failed to connect browser with: ${error?.toString()}`;
        }
    },
    async openNewPage() {
        browser.checkConnected();
        const newPage = await browser.pageInstance!.context().newPage();
        browser.pageInstance = newPage;
        return `New page opened successfully`;
    },
    async navigate({ url }: NavigateParams) {
        browser.checkConnected();
        await browser.pageInstance!.goto(url);
        return `Navigated to ${url} successfully`;
    },
    async screenshot({ savePath, isFullPage }: ScreenshotParams) {
        browser.checkConnected();
        const filename = `screenshot-${Date.now()}-${Math.random().toString(36).substring(2, 15)}.png`;
        const outputPath = path.join(savePath || defaultDownloadsPath, filename);
        const screenshot = await browser.pageInstance!.screenshot({ path: outputPath, fullPage: isFullPage });
        const screenshotBase64 = screenshot.toString('base64');
        browser.screenshotsInstance.set(filename, screenshotBase64);
        return [{
            type: 'image' as const,
            data: screenshotBase64,
            mimeType: 'image/png'
        }];
    },
    async getPageVisibleText() {
        browser.checkConnected();
        try {
            const visibleText = await browser.pageInstance!.evaluate(() => {
                const walker = document.createTreeWalker(
                    document.body,
                    NodeFilter.SHOW_TEXT,
                    {
                        acceptNode: (node) => {
                            const style = window.getComputedStyle(
                                node.parentElement!
                            );
                            return style.display !== 'none' &&
                                style.visibility !== 'hidden'
                                ? NodeFilter.FILTER_ACCEPT
                                : NodeFilter.FILTER_REJECT;
                        },
                    }
                );
                let text = '';
                let node;
                while ((node = walker.nextNode())) {
                    const trimmedText = node.textContent?.trim();
                    if (trimmedText) {
                        text += trimmedText + '\n';
                    }
                }
                return text.trim();
            });
            return `Visible text content:\n${visibleText}`;
        } catch (error) {
            return `Failed to get visible text content: ${(error as Error).message}`;
        }
    },
    async getPageHtml() {
        browser.checkConnected();
        const html = await browser.pageInstance!.content();
        return html;
    },
    async clickElement({ selector }: ClickElementParams) {
        browser.checkConnected();
        await browser.pageInstance!.click(selector);
        return `Clicked element with selector: ${selector} successfully`;
    },
    async iframeClickElement({ selector, iframeSelector }: IframeClickElementParams) {
        const frame = browser.pageInstance!.frameLocator(iframeSelector);
        if (!frame) {
            return `Iframe not found: ${iframeSelector}`;
        }
        
        await frame.locator(selector).click();
        return `Clicked element ${selector} inside iframe ${iframeSelector} successfully`;
    },
    async fillInput({ selector, text }: FillInputParams) {
        browser.checkConnected();
        await browser.pageInstance!.waitForSelector(selector);
        await browser.pageInstance!.fill(selector, text);
        return `Filled input with selector: ${selector} with text: ${text} successfully`;
    },
    async selectOption({ selector, value }: SelectOptionParams) {
        browser.checkConnected();
        await browser.pageInstance!.waitForSelector(selector);
        await browser.pageInstance!.selectOption(selector, value);
        return `Selected option with selector: ${selector} with value: ${value} successfully`;
    },
    async hoverElement({ selector }: HoverElementParams) {
        browser.checkConnected();
        await browser.pageInstance!.waitForSelector(selector);
        await browser.pageInstance!.hover(selector);
        return `Hovered element with selector: ${selector} successfully`;
    },
    async scrollElement({ selector }: ScrollElementParams) {
        browser.checkConnected();
        await browser.pageInstance!.waitForSelector(selector);
        await browser.pageInstance!.evaluate((selector) => {
            const element = document.querySelector(selector);
            if (element) {
                element.scrollIntoView({ behavior: 'smooth' });
            }
        }, selector);
        return `Scrolled element with selector: ${selector} successfully`;
    },
    async pressKey({ key, selector }: PressKeyParams) {
        browser.checkConnected();
        if (selector) {
            await browser.pageInstance!.waitForSelector(selector);
            await browser.pageInstance!.focus(selector);
        }
        await browser.pageInstance!.keyboard.press(key);
        return `Pressed key: ${key} successfully`;
    },
    async evaluateScript({ script }: EvaluateScriptParams) {
        browser.checkConnected();
        const result = await browser.pageInstance!.evaluate(script);
        return result;
    },
    async dragElement({ selector, targetSelector }: DragElementParams) {
        browser.checkConnected();
        const sourceElement = await browser.pageInstance!.waitForSelector(selector);
        const targetElement = await browser.pageInstance!.waitForSelector(targetSelector);
        
        const sourceBound = await sourceElement.boundingBox();
        const targetBound = await targetElement.boundingBox();
        
        if (!sourceBound || !targetBound) {
            return `Could not get element positions for drag operation`;
        }

        await browser.pageInstance!.mouse.move(
            sourceBound.x + sourceBound.width / 2,
            sourceBound.y + sourceBound.height / 2
        );
        await browser.pageInstance!.mouse.down();
        await browser.pageInstance!.mouse.move(
            targetBound.x + targetBound.width / 2,
            targetBound.y + targetBound.height / 2
        );
        await browser.pageInstance!.mouse.up();
        return `Dragged element with selector: ${selector} to ${targetSelector} successfully`;
    }
}

export const getScreenshot = (filename: string) => {
    return browser.screenshotsInstance.get(filename);
}

```

--------------------------------------------------------------------------------
/src/types/schemas.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from 'zod';

// Proxy Config Schema
const userProxyConfigSchema = z.object({
    proxy_soft: z.enum([
        'brightdata', 'brightauto', 'oxylabsauto', '922S5auto',
        'ipideeauto', 'ipfoxyauto', '922S5auth', 'kookauto',
        'ssh', 'other', 'no_proxy'
    ]).describe('The proxy soft of the browser'),
    proxy_type: z.enum(['http', 'https', 'socks5', 'no_proxy']).optional(),
    proxy_host: z.string().optional().describe('The proxy host of the browser, eg: 127.0.0.1'),
    proxy_port: z.string().optional().describe('The proxy port of the browser, eg: 8080'),
    proxy_user: z.string().optional().describe('The proxy user of the browser, eg: user'),
    proxy_password: z.string().optional().describe('The proxy password of the browser, eg: password'),
    proxy_url: z.string().optional().describe('The proxy url of the browser, eg: http://127.0.0.1:8080'),
    global_config: z.enum(['0', '1']).optional().describe('The global config of the browser, default is 0')
}).describe('The user proxy config of the browser');

// Browser Kernel Config Schema
const browserKernelConfigSchema = z.object({
    version: z.union([
        z.literal("92"), z.literal("99"), z.literal("102"),
        z.literal("105"), z.literal("108"), z.literal("111"),
        z.literal("114"), z.literal("115"), z.literal("116"),
        z.literal("117"), z.literal("118"), z.literal("119"),
        z.literal("120"), z.literal("121"), z.literal("122"),
        z.literal("123"), z.literal("124"), z.literal("125"),
        z.literal("126"), z.literal("127"), z.literal("128"),
        z.literal("129"), z.literal("130"), z.literal("131"),
        z.literal("132"), z.literal("133"), z.literal("134"),
        z.literal("ua_auto")
    ]).optional().describe('The version of the browser, default is ua_auto'),
    type: z.enum(['chrome', 'firefox']).optional().describe('The type of the browser, default is chrome')
}).optional().describe('The browser kernel config of the browser, default is version: ua_auto, type: chrome');

// Random UA Config Schema
const randomUaConfigSchema = z.object({
    ua_version: z.array(z.string()).optional(),
    ua_system_version: z.array(
        z.enum([
            'Android 9', 'Android 10', 'Android 11', 'Android 12', 'Android 13',
            'iOS 14', 'iOS 15',
            'Windows 7', 'Windows 8', 'Windows 10', 'Windows 11',
            'Mac OS X 10', 'Mac OS X 11', 'Mac OS X 12', 'Mac OS X 13',
            'Linux'
        ])
    ).optional().describe('The ua system version of the browser, eg: ["Android 9", "iOS 14"]')
}).optional().describe('The random ua config of the browser, default is ua_version: [], ua_system_version: []');

// Fingerprint Config Schema
const fingerprintConfigSchema = z.object({
    automatic_timezone: z.enum(['0', '1']).optional().describe('The automatic timezone of the browser, default is 0'),
    timezone: z.string().optional().describe('The timezone of the browser, eg: Asia/Shanghai'),
    language: z.array(z.string()).optional().describe('The language of the browser, eg: ["en-US", "zh-CN"]'),
    flash: z.enum(['block', 'allow']).optional().describe('The flash of the browser, default is disabled'),
    fonts: z.array(z.string()).optional().describe('The fonts of the browser, eg: ["Arial", "Times New Roman"]'),
    webrtc: z.enum(['disabled', 'forward', 'proxy', 'local']).optional().describe('The webrtc of the browser, default is disabled'),
    browser_kernel_config: browserKernelConfigSchema,
    random_ua: randomUaConfigSchema,
    tls_switch: z.enum(['0', '1']).optional().describe('The tls switch of the browser, default is 0'),
    tls: z.string().optional().describe('The tls of the browser, if tls_switch is 1, you can set the tls of the browser, eg: "0xC02C,0xC030"')
}).optional().describe('The fingerprint config of the browser, default is automatic_timezone: 0, timezone: "", language: [], flash: "", fonts: [], webrtc: disabled, browser_kernel_config: ua_auto, random_ua: ua_version: [], ua_system_version: [], tls_switch: 0, tls: ""');

export const schemas = {
    // Browser Related Schema
    createBrowserSchema: z.object({
        domainName: z.string().optional().describe('The domain name of the browser, eg: facebook.com'),
        openUrls: z.array(z.string()).optional().describe('The open urls of the browser, eg: ["https://www.google.com"]'),
        cookie: z.string().optional().describe('The cookie of the browser, eg: "[{\"domain\":\".baidu.com\",\"expirationDate\":\"\",\"name\":\"\",\"path\":\"/\",\"sameSite\":\"unspecified\",\"secure\":true,\"value\":\"\",\"id\":1}]"'),
        username: z.string().optional().describe('The username of the browser, eg: "user"'),
        password: z.string().optional().describe('The password of the browser, eg: "password"'),
        groupId: z.string()
            .regex(/^\d+$/, "Group ID must be a numeric string")
            .describe('The group id of the browser, must be a numeric string (e.g., "123"). You can use the get-group-list tool to get the group list or create a new group, or default is 0'),
        name: z.string().optional().describe('The name of the browser, eg: "My Browser"'),
        country: z.string().optional().describe('The country of the browser, eg: "CN"'),
        sysAppCateId: z.string().optional().describe('The sys app cate id of the browser, you can use the get-application-list tool to get the application list'),
        userProxyConfig: userProxyConfigSchema,
        fingerprintConfig: fingerprintConfigSchema,
        storageStrategy: z.number().optional().describe('The storage strategy of the browser, default is 0')
    }),

    updateBrowserSchema: z.object({
        domainName: z.string().optional().describe('The domain name of the browser, eg: facebook.com'),
        openUrls: z.array(z.string()).optional().describe('The open urls of the browser, eg: ["https://www.google.com"]'),
        cookie: z.string().optional().describe('The cookie of the browser, eg: "[{\"domain\":\".baidu.com\",\"expirationDate\":\"\",\"name\":\"\",\"path\":\"/\",\"sameSite\":\"unspecified\",\"secure\":true,\"value\":\"\",\"id\":1}]"'),
        username: z.string().optional().describe('The username of the browser, eg: "user"'),
        password: z.string().optional().describe('The password of the browser, eg: "password"'),
        groupId: z.string().optional().describe('The group id of the browser, must be a numeric string (e.g., "123"). You can use the get-group-list tool to get the group list or create a new group'),
        name: z.string().optional().describe('The name of the browser, eg: "My Browser"'),
        country: z.string().optional().describe('The country of the browser, eg: "CN"'),
        sysAppCateId: z.string().optional().describe('The sys app cate id of the browser, you can use the get-application-list tool to get the application list'),
        userProxyConfig: userProxyConfigSchema.optional(),
        fingerprintConfig: fingerprintConfigSchema.optional(),
        storageStrategy: z.number().optional().describe('The storage strategy of the browser, default is 0'),
        userId: z.string().describe('The user id of the browser to update, it is required when you want to update the browser')
    }),

    openBrowserSchema: z.object({
        serialNumber: z.string().optional().describe('The serial number of the browser to open'),
        userId: z.string().optional().describe('The browser id of the browser to open'),
        ipTab: z.enum(['0', '1']).optional().describe('The ip tab of the browser, 0 is not use ip tab, 1 is use ip tab, default is 0'),
        launchArgs: z.string().optional().describe(`The launch args of the browser, use chrome launch args, eg: ${JSON.stringify(["--blink-settings=imagesEnabled=false", "--disable-notifications"])}, or vista url, eg: ${JSON.stringify(["https://www.adspower.net"])}`),
        clearCacheAfterClosing: z.enum(['0', '1']).optional().describe('The clear cache after closing of the browser, 0 is not clear cache after closing, 1 is clear cache after closing, default is 0'),
        cdpMask: z.enum(['0', '1']).optional().describe('The cdp mask of the browser, 0 is not use cdp mask, 1 is use cdp mask, default is 0'),
    }).strict(),

    closeBrowserSchema: z.object({
        userId: z.string().describe('The browser id of the browser to stop, it is required when you want to stop the browser')
    }).strict(),

    deleteBrowserSchema: z.object({
        userIds: z.array(z.string()).describe('The user ids of the browsers to delete, it is required when you want to delete the browser')
    }).strict(),

    getBrowserListSchema: z.object({
        groupId: z.string()
            .regex(/^\d+$/, "Group ID must be a numeric string")
            .optional()
            .describe('The group id of the browser, must be a numeric string (e.g., "123"). You can use the get-group-list tool to get the group list'),
        size: z.number().optional().describe('The size of the page, max is 100, if get more than 100, you need to use the page to get the next page, default is 10'),
        page: z.number().optional().describe('The page of the browser, default is 1'),
        id: z.string().optional().describe('The id of the browser'),
        serialNumber: z.string().optional().describe('The serial number of the browser'),
        sort: z.enum(['serial_number', 'last_open_time', 'created_time']).optional()
            .describe('The sort of the browser'),
        order: z.enum(['asc', 'desc']).optional()
            .describe('The order of the browser')
    }).strict(),

    moveBrowserSchema: z.object({
        groupId: z.string()
            .regex(/^\d+$/, "Group ID must be a numeric string")
            .describe('The target group id, must be a numeric string (e.g., "123"). You can use the get-group-list tool to get the group list'),
        userIds: z.array(z.string()).describe('The browser ids to move')
    }).strict(),

    // Group Related Schema
    createGroupSchema: z.object({
        groupName: z.string().describe('The name of the group to create'),
        remark: z.string().optional().describe('The remark of the group')
    }).strict(),

    updateGroupSchema: z.object({
        groupId: z.string()
            .regex(/^\d+$/, "Group ID must be a numeric string")
            .describe('The id of the group to update, must be a numeric string (e.g., "123"). You can use the get-group-list tool to get the group list'),
        groupName: z.string().describe('The new name of the group'),
        remark: z.string().nullable().optional().describe('The new remark of the group')
    }).strict(),

    getGroupListSchema: z.object({
        groupName: z.string().optional().describe('The name of the group to search, use like to search, often used group name to find the group id, so eg: "test" will search "test" and "test1"'),
        size: z.number().optional().describe('The size of the page, max is 100, if get more than 100, you need to use the page to get the next page, default is 10'),
        page: z.number().optional().describe('The page of the group, default is 1')
    }).strict(),

    // Application Related Schema
    getApplicationListSchema: z.object({
        size: z.number().optional().describe('The size of the page')
    }).strict(),

    // Empty Schema
    emptySchema: z.object({}).strict(),

    // Automation Related Schema
    createAutomationSchema: z.object({
        userId: z.string().optional().describe('The browser id of the browser to connect'),
        serialNumber: z.string().optional().describe('The serial number of the browser to connect'),
        wsUrl: z.string().describe('The ws url of the browser, get from the open-browser tool content `ws.puppeteer`')
    }).strict(),

    navigateSchema: z.object({
        url: z.string().describe('The url to navigate to')
    }).strict(),

    screenshotSchema: z.object({
        savePath: z.string().optional().describe('The path to save the screenshot'),
        isFullPage: z.boolean().optional().describe('The is full page of the screenshot')
    }).strict(),

    clickElementSchema: z.object({
        selector: z.string().describe('The selector of the element to click, find from the page source code')
    }).strict(),

    fillInputSchema: z.object({
        selector: z.string().describe('The selector of the input to fill, find from the page source code'),
        text: z.string().describe('The text to fill in the input')
    }).strict(),

    selectOptionSchema: z.object({
        selector: z.string().describe('The selector of the option to select, find from the page source code'),
        value: z.string().describe('The value of the option to select')
    }).strict(),

    hoverElementSchema: z.object({
        selector: z.string().describe('The selector of the element to hover, find from the page source code')
    }).strict(),

    scrollElementSchema: z.object({
        selector: z.string().describe('The selector of the element to scroll, find from the page source code, Simulates a user navigating page by scrolling, usually finding element in the bottom of the page')
    }).strict(),

    pressKeySchema: z.object({
        key: z.string().describe('The key to press, eg: "Enter"'),
        selector: z.string().optional().describe('The selector of the element to press the key, find from the page source code')
    }).strict(),

    evaluateScriptSchema: z.object({
        script: z.string().describe('The script to evaluate, eg: "document.querySelector(\'#username\').value = \'test\'"')
    }).strict(),

    dragElementSchema: z.object({
        selector: z.string().describe('The selector of the element to drag, find from the page source code'),
        targetSelector: z.string().describe('The selector of the element to drag to, find from the page source code'),
    }).strict(),

    iframeClickElementSchema: z.object({
        selector: z.string().describe('The selector of the element to click, find from the page source code'),
        iframeSelector: z.string().describe('The selector of the iframe to click, find from the page source code')
    }).strict(),
};
```