diff --git a/internal/version/VERSION b/internal/version/VERSION index 5fdf39fe..0850db1b 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0-beta-2505211624 +v5.0.0-beta-2505211637 diff --git a/mcphost/mcp_server.go b/mcphost/mcp_server.go index bfadadaa..6020b809 100644 --- a/mcphost/mcp_server.go +++ b/mcphost/mcp_server.go @@ -102,13 +102,26 @@ func (ums *MCPServer4XTDriver) addTools() { ums.handlerMap[selectDeviceTool.Name] = ums.handleSelectDevice // ListPackages Tool - listPackagesTool := mcp.NewTool("list_packages", - mcp.WithDescription("List all the apps/packages on the device."), + listPackagesParams := append( + []mcp.ToolOption{mcp.WithDescription("List all the apps/packages on the device.")}, + commonToolOptions..., ) + listPackagesTool := mcp.NewTool("list_packages", listPackagesParams...) ums.mcpServer.AddTool(listPackagesTool, ums.handleListPackages) ums.tools = append(ums.tools, listPackagesTool) ums.handlerMap[listPackagesTool.Name] = ums.handleListPackages + // LaunchApp Tool + launchAppParams := append( + []mcp.ToolOption{mcp.WithDescription("Launch an app on mobile device. Use this to open a specific app. You can find the package name of the app by calling list_packages.")}, + commonToolOptions..., + ) + launchAppParams = append(launchAppParams, generateMCPOptions(types.AppLaunchRequest{})...) + launchAppTool := mcp.NewTool("launch_app", launchAppParams...) + ums.mcpServer.AddTool(launchAppTool, ums.handleLaunchApp) + ums.tools = append(ums.tools, launchAppTool) + ums.handlerMap[launchAppTool.Name] = ums.handleLaunchApp + // TapXY Tool tapParams := append( []mcp.ToolOption{mcp.WithDescription("Taps on the device screen at the given coordinates.")}, @@ -203,6 +216,27 @@ func (ums *MCPServer4XTDriver) handleListPackages(ctx context.Context, request m return mcp.NewToolResultText(fmt.Sprintf("Device packages: %v", apps)), nil } +// handleLaunchApp handles the launch_app tool call. +func (ums *MCPServer4XTDriver) handleLaunchApp(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + driverExt, err := ums.setupXTDriver(ctx, request.Params.Arguments) + if err != nil { + return nil, err + } + var appLaunchReq types.AppLaunchRequest + if err := mapToStruct(request.Params.Arguments, &appLaunchReq); err != nil { + return mcp.NewToolResultError("parse parameters error: " + err.Error()), nil + } + packageName := appLaunchReq.PackageName + if packageName == "" { + return mcp.NewToolResultError("package_name is required"), nil + } + err = driverExt.AppLaunch(packageName) + if err != nil { + return mcp.NewToolResultError("Launch app failed: " + err.Error()), nil + } + return mcp.NewToolResultText(fmt.Sprintf("Launched app success: %s", packageName)), nil +} + // handleTapXY handles the tap_xy tool call. func (ums *MCPServer4XTDriver) handleTapXY(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { driverExt, err := ums.setupXTDriver(ctx, request.Params.Arguments) @@ -281,6 +315,7 @@ func (ums *MCPServer4XTDriver) setupXTDriver(_ context.Context, args map[string] platform, _ := args["platform"].(string) serial, _ := args["serial"].(string) if platform == "" { + log.Warn().Msg("platform is not set, using android as default") platform = "android" } diff --git a/server/app.go b/server/app.go index a958b2ba..ac7ead1e 100644 --- a/server/app.go +++ b/server/app.go @@ -5,6 +5,7 @@ import ( "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/v5/uixt" + "github.com/httprunner/httprunner/v5/uixt/types" ) func (r *Router) foregroundAppHandler(c *gin.Context) { @@ -50,7 +51,7 @@ func (r *Router) appInfoHandler(c *gin.Context) { } func (r *Router) clearAppHandler(c *gin.Context) { - var appClearReq AppClearRequest + var appClearReq types.AppClearRequest if err := c.ShouldBindJSON(&appClearReq); err != nil { RenderErrorValidateRequest(c, err) return @@ -69,7 +70,7 @@ func (r *Router) clearAppHandler(c *gin.Context) { } func (r *Router) launchAppHandler(c *gin.Context) { - var appLaunchReq AppLaunchRequest + var appLaunchReq types.AppLaunchRequest if err := c.ShouldBindJSON(&appLaunchReq); err != nil { RenderErrorValidateRequest(c, err) return @@ -87,7 +88,7 @@ func (r *Router) launchAppHandler(c *gin.Context) { } func (r *Router) terminalAppHandler(c *gin.Context) { - var appTerminalReq AppTerminalRequest + var appTerminalReq types.AppTerminalRequest if err := c.ShouldBindJSON(&appTerminalReq); err != nil { RenderErrorValidateRequest(c, err) return diff --git a/server/model.go b/server/model.go index 4a3e8492..b3b5f61b 100644 --- a/server/model.go +++ b/server/model.go @@ -24,18 +24,6 @@ type KeycodeRequest struct { Keycode int `json:"keycode" binding:"required"` } -type AppClearRequest struct { - PackageName string `json:"packageName" binding:"required"` -} - -type AppLaunchRequest struct { - PackageName string `json:"packageName" binding:"required"` -} - -type AppTerminalRequest struct { - PackageName string `json:"packageName" binding:"required"` -} - type AppInstallRequest struct { AppUrl string `json:"appUrl" binding:"required"` MappingUrl string `json:"mappingUrl"` diff --git a/uixt/types/request.go b/uixt/types/request.go index c9bd59bc..1ea75c17 100644 --- a/uixt/types/request.go +++ b/uixt/types/request.go @@ -14,3 +14,15 @@ type DragRequest struct { Duration float64 `json:"duration" desc:"Swipe duration in milliseconds (optional)"` PressDuration float64 `json:"press_duration" desc:"Press duration in milliseconds (optional)"` } + +type AppClearRequest struct { + PackageName string `json:"packageName" binding:"required"` +} + +type AppLaunchRequest struct { + PackageName string `json:"packageName" binding:"required" desc:"The package name of the app to launch"` +} + +type AppTerminalRequest struct { + PackageName string `json:"packageName" binding:"required"` +}