@wdio/mcp 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -426,6 +426,7 @@ All session types support `reporting` labels that appear in the BrowserStack Aut
426
426
  | `scroll` | Scroll in a direction (up/down) by specified pixels. Browser-only. |
427
427
  | `execute_script` | Execute arbitrary JavaScript in the browser, or Appium mobile commands on devices |
428
428
  | `switch_tab` | Switch to a different browser tab by handle or 0-based index. Browser-only. |
429
+ | `switch_frame` | Switch into an iframe by CSS/XPath selector, or back to the top-level frame if no selector is given. Browser-only. |
429
430
 
430
431
  ### Element Interaction (Web & Mobile)
431
432
 
package/lib/server.js CHANGED
@@ -46,7 +46,7 @@ var package_default = {
46
46
  type: "git",
47
47
  url: "git://github.com/webdriverio/mcp.git"
48
48
  },
49
- version: "3.2.5",
49
+ version: "3.3.0",
50
50
  description: "MCP server with WebdriverIO for browser and mobile app automation (iOS/Android via Appium)",
51
51
  main: "./lib/server.js",
52
52
  module: "./lib/server.js",
@@ -3152,7 +3152,8 @@ function getAppiumServerConfig(overrides) {
3152
3152
  return {
3153
3153
  hostname: overrides?.hostname || process.env.APPIUM_URL || "127.0.0.1",
3154
3154
  port: overrides?.port || Number(process.env.APPIUM_URL_PORT) || 4723,
3155
- path: overrides?.path || process.env.APPIUM_PATH || "/"
3155
+ path: overrides?.path || process.env.APPIUM_PATH || "/",
3156
+ protocol: overrides?.protocol || process.env.APPIUM_PROTOCOL || "http"
3156
3157
  };
3157
3158
  }
3158
3159
  function buildIOSCapabilities(appPath, options) {
@@ -3235,12 +3236,12 @@ var LocalAppiumProvider = class {
3235
3236
  name = "local-appium";
3236
3237
  getConnectionConfig(options) {
3237
3238
  const appiumConfig = options.appiumConfig;
3238
- const config = getAppiumServerConfig({
3239
+ return getAppiumServerConfig({
3239
3240
  hostname: appiumConfig?.host,
3240
3241
  port: appiumConfig?.port,
3241
- path: appiumConfig?.path
3242
+ path: appiumConfig?.path,
3243
+ protocol: appiumConfig?.protocol
3242
3244
  });
3243
- return { protocol: "http", ...config };
3244
3245
  }
3245
3246
  buildCapabilities(options) {
3246
3247
  const platform2 = options.platform;
@@ -3538,7 +3539,8 @@ var startSessionToolDefinition = {
3538
3539
  appiumConfig: z14.object({
3539
3540
  host: z14.string().optional(),
3540
3541
  port: z14.number().optional(),
3541
- path: z14.string().optional()
3542
+ path: z14.string().optional(),
3543
+ protocol: z14.string().optional()
3542
3544
  }).optional().describe("Appium server connection (local provider only)"),
3543
3545
  browserstackLocal: z14.union([coerceBoolean, z14.literal("external")]).optional().default(false).describe('Enable BrowserStack Local tunnel routing (BrowserStack only, default: false). true = auto-start tunnel before session and stop on close. "external" = tunnel already running externally, set local: true in capabilities only.'),
3544
3546
  navigationUrl: z14.string().optional().describe("URL to navigate to after starting"),
@@ -3823,9 +3825,39 @@ var switchTabTool = async ({ handle, index }) => {
3823
3825
  }
3824
3826
  };
3825
3827
 
3828
+ // src/tools/switch-frame.tool.ts
3829
+ init_state();
3830
+ import { z as z16 } from "zod";
3831
+ var switchFrameToolDefinition = {
3832
+ name: "switch_frame",
3833
+ description: "Switches into an iframe by CSS or XPath selector, or back to the top-level frame if no selector is given. Required before interacting with elements inside iframes \u2014 click, set_value, and get_elements only see the current frame context. Browser-only.",
3834
+ inputSchema: {
3835
+ selector: z16.string().optional().describe(
3836
+ "CSS/XPath selector for the iframe element. Omit to switch back to the top-level frame."
3837
+ )
3838
+ }
3839
+ };
3840
+ var switchFrameTool = async ({
3841
+ selector
3842
+ }) => {
3843
+ try {
3844
+ const browser = getBrowser();
3845
+ if (!selector) {
3846
+ await browser.switchFrame(null);
3847
+ return { content: [{ type: "text", text: "Switched back to top-level frame" }] };
3848
+ }
3849
+ const iframe = await browser.$(selector);
3850
+ await iframe.waitForExist({ timeout: 5e3 });
3851
+ await browser.switchFrame(iframe);
3852
+ return { content: [{ type: "text", text: `Switched to iframe: ${selector}` }] };
3853
+ } catch (e) {
3854
+ return { isError: true, content: [{ type: "text", text: `Error switching frame: ${e}` }] };
3855
+ }
3856
+ };
3857
+
3826
3858
  // src/tools/browserstack.tool.ts
3827
3859
  import { existsSync as existsSync2, createReadStream } from "fs";
3828
- import { z as z16 } from "zod";
3860
+ import { z as z17 } from "zod";
3829
3861
  var BS_API = "https://api-cloud.browserstack.com";
3830
3862
  function getAuth() {
3831
3863
  const user = process.env.BROWSERSTACK_USERNAME;
@@ -3844,9 +3876,9 @@ var listAppsToolDefinition = {
3844
3876
  name: "list_apps",
3845
3877
  description: "List apps uploaded to BrowserStack App Automate. Reads BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY from environment.",
3846
3878
  inputSchema: {
3847
- sortBy: z16.enum(["app_name", "uploaded_at"]).optional().default("uploaded_at").describe("Sort order for results"),
3879
+ sortBy: z17.enum(["app_name", "uploaded_at"]).optional().default("uploaded_at").describe("Sort order for results"),
3848
3880
  organizationWide: coerceBoolean.optional().default(false).describe("List apps uploaded by all users in the organization (uses recent_group_apps endpoint). Defaults to false (own uploads only)."),
3849
- limit: z16.number().int().min(1).optional().default(20).describe("Maximum number of apps to return (only applies when organizationWide is true, default 20)")
3881
+ limit: z17.number().int().min(1).optional().default(20).describe("Maximum number of apps to return (only applies when organizationWide is true, default 20)")
3850
3882
  }
3851
3883
  };
3852
3884
  var listAppsTool = async ({ sortBy = "uploaded_at", organizationWide = false, limit = 20 }) => {
@@ -3876,8 +3908,8 @@ var uploadAppToolDefinition = {
3876
3908
  name: "upload_app",
3877
3909
  description: "Upload a local .apk or .ipa to BrowserStack App Automate. Returns a bs:// URL for use in start_session.",
3878
3910
  inputSchema: {
3879
- path: z16.string().describe("Absolute path to the .apk or .ipa file"),
3880
- customId: z16.string().optional().describe("Optional custom ID for the app (used to reference it later)")
3911
+ path: z17.string().describe("Absolute path to the .apk or .ipa file"),
3912
+ customId: z17.string().optional().describe("Optional custom ID for the app (used to reference it later)")
3881
3913
  }
3882
3914
  };
3883
3915
  var uploadAppTool = async ({ path, customId }) => {
@@ -3930,14 +3962,14 @@ var screenshotTool = async () => {
3930
3962
  };
3931
3963
 
3932
3964
  // src/tools/accessibility.tool.ts
3933
- import { z as z17 } from "zod";
3965
+ import { z as z18 } from "zod";
3934
3966
  var accessibilityToolDefinition = {
3935
3967
  name: "get_accessibility_tree",
3936
3968
  description: "Returns the page accessibility tree with roles, names, and selectors. Browser-only. Supports filtering by ARIA roles and pagination via limit/offset.",
3937
3969
  inputSchema: {
3938
- limit: z17.number().optional().default(0).describe("Maximum number of nodes to return (0 = no limit)"),
3939
- offset: z17.number().optional().default(0).describe("Number of nodes to skip for pagination"),
3940
- roles: z17.array(z17.string()).optional().describe('Filter by ARIA roles, e.g. ["button", "link", "heading"]')
3970
+ limit: z18.number().optional().default(0).describe("Maximum number of nodes to return (0 = no limit)"),
3971
+ offset: z18.number().optional().default(0).describe("Number of nodes to skip for pagination"),
3972
+ roles: z18.array(z18.string()).optional().describe('Filter by ARIA roles, e.g. ["button", "link", "heading"]')
3941
3973
  }
3942
3974
  };
3943
3975
  var accessibilityTool = async ({ limit = 0, offset = 0, roles }) => {
@@ -3984,12 +4016,12 @@ var getContextsTool = async () => {
3984
4016
  };
3985
4017
 
3986
4018
  // src/tools/app-state.tool.ts
3987
- import { z as z18 } from "zod";
4019
+ import { z as z19 } from "zod";
3988
4020
  var appStateToolDefinition = {
3989
4021
  name: "get_app_state",
3990
4022
  description: "Returns the current state of a mobile app: not installed, not running, background, or foreground. Mobile-only.",
3991
4023
  inputSchema: {
3992
- bundleId: z18.string().describe('App bundle ID (iOS) or package name (Android), e.g. "com.example.app"')
4024
+ bundleId: z19.string().describe('App bundle ID (iOS) or package name (Android), e.g. "com.example.app"')
3993
4025
  }
3994
4026
  };
3995
4027
  var appStateTool = async ({ bundleId }) => {
@@ -4001,12 +4033,12 @@ var appStateTool = async ({ bundleId }) => {
4001
4033
  };
4002
4034
 
4003
4035
  // src/tools/get-cookies.tool.ts
4004
- import { z as z19 } from "zod";
4036
+ import { z as z20 } from "zod";
4005
4037
  var getCookiesToolDefinition = {
4006
4038
  name: "get_cookies",
4007
4039
  description: "Returns all cookies for the current session, or a single cookie by name. Use to verify auth state, session tokens, or feature flags after login flows.",
4008
4040
  inputSchema: {
4009
- name: z19.string().optional().describe("Cookie name to retrieve a specific cookie. If omitted, returns all cookies.")
4041
+ name: z20.string().optional().describe("Cookie name to retrieve a specific cookie. If omitted, returns all cookies.")
4010
4042
  }
4011
4043
  };
4012
4044
  var getCookiesTool = async ({ name }) => {
@@ -4063,6 +4095,7 @@ function createServer() {
4063
4095
  registerTool(emulateDeviceToolDefinition, emulateDeviceTool);
4064
4096
  registerTool(navigateToolDefinition, withRecording("navigate", navigateTool));
4065
4097
  registerTool(switchTabToolDefinition, switchTabTool);
4098
+ registerTool(switchFrameToolDefinition, switchFrameTool);
4066
4099
  registerTool(scrollToolDefinition, withRecording("scroll", scrollTool));
4067
4100
  registerTool(clickToolDefinition, withRecording("click_element", clickTool));
4068
4101
  registerTool(setValueToolDefinition, withRecording("set_value", setValueTool));