feat: integrate MCP tools with UI actions and improve environment variable inheritance

This commit is contained in:
lilong.129
2025-05-28 22:58:59 +08:00
parent 2fe5b14d63
commit 4ea08b0198
4 changed files with 81 additions and 12 deletions
+1 -1
View File
@@ -1 +1 @@
v5.0.0-beta-2505272139 v5.0.0-beta-2505282259
+5 -1
View File
@@ -110,10 +110,14 @@ func (h *MCPHost) connectToServer(ctx context.Context, serverName string, config
mcpClient, err = client.NewSSEMCPClient(cfg.Url, mcpClient, err = client.NewSSEMCPClient(cfg.Url,
client.WithHeaders(parseHeaders(cfg.Headers))) client.WithHeaders(parseHeaders(cfg.Headers)))
case STDIOServerConfig: case STDIOServerConfig:
env := make([]string, 0, len(cfg.Env)) // Start with current process environment variables
env := os.Environ()
// Add or override with config-specific environment variables
for k, v := range cfg.Env { for k, v := range cfg.Env {
env = append(env, fmt.Sprintf("%s=%s", k, v)) env = append(env, fmt.Sprintf("%s=%s", k, v))
} }
mcpClient, err = client.NewStdioMCPClient(cfg.Command, env, cfg.Args...) mcpClient, err = client.NewStdioMCPClient(cfg.Command, env, cfg.Args...)
if stdioClient, ok := mcpClient.(*client.Client); ok { if stdioClient, ok := mcpClient.(*client.Client); ok {
stderr, _ := client.GetStderr(stdioClient) stderr, _ := client.GetStderr(stdioClient)
+1
View File
@@ -825,6 +825,7 @@ func runStepMobileUI(s *SessionRunner, step IStep) (stepResult *StepResult, err
continue continue
} }
// call MCP tool to execute action
err = uiDriver.ExecuteAction(context.Background(), action) err = uiDriver.ExecuteAction(context.Background(), action)
actionResult.Elapsed = time.Since(actionStartTime).Milliseconds() actionResult.Elapsed = time.Since(actionStartTime).Milliseconds()
stepResult.Actions = append(stepResult.Actions, actionResult) stepResult.Actions = append(stepResult.Actions, actionResult)
+74 -10
View File
@@ -8,6 +8,7 @@ import (
"github.com/httprunner/httprunner/v5/internal/builtin" "github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/internal/config" "github.com/httprunner/httprunner/v5/internal/config"
"github.com/httprunner/httprunner/v5/uixt/ai"
"github.com/httprunner/httprunner/v5/uixt/option" "github.com/httprunner/httprunner/v5/uixt/option"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@@ -50,7 +51,13 @@ func preHandler_TapAbsXY(driver IDriver, options *option.ActionOptions, rawX, ra
// Call MCP action tool if anti-risk is enabled // Call MCP action tool if anti-risk is enabled
if options.AntiRisk { if options.AntiRisk {
// TODO arguments := getAntiRisk_SetTouchInfoList_Arguments(driver, []ai.PointF{
{X: rawX, Y: rawY},
})
if arguments != nil {
callMCPActionTool(driver, "evalpkgs",
string(option.ACTION_SetTouchInfoList), arguments)
}
} }
x, y = options.ApplyTapOffset(rawX, rawY) x, y = options.ApplyTapOffset(rawX, rawY)
@@ -94,6 +101,18 @@ func preHandler_Drag(driver IDriver, options *option.ActionOptions, rawFomX, raw
} }
fromX, fromY, toX, toY = options.ApplySwipeOffset(fromX, fromY, toX, toY) fromX, fromY, toX, toY = options.ApplySwipeOffset(fromX, fromY, toX, toY)
// Call MCP action tool if anti-risk is enabled
if options.AntiRisk {
arguments := getAntiRisk_SetTouchInfoList_Arguments(driver, []ai.PointF{
{X: fromX, Y: fromY},
{X: toX, Y: toY},
})
if arguments != nil {
callMCPActionTool(driver, "evalpkgs",
string(option.ACTION_SetTouchInfoList), arguments)
}
}
// mark UI operation // mark UI operation
if options.PreMarkOperation { if options.PreMarkOperation {
if markErr := MarkUIOperation(driver, option.ACTION_Drag, []float64{fromX, fromY, toX, toY}); markErr != nil { if markErr := MarkUIOperation(driver, option.ACTION_Drag, []float64{fromX, fromY, toX, toY}); markErr != nil {
@@ -114,6 +133,18 @@ func preHandler_Swipe(driver IDriver, actionType option.ActionName,
} }
fromX, fromY, toX, toY = options.ApplySwipeOffset(fromX, fromY, toX, toY) fromX, fromY, toX, toY = options.ApplySwipeOffset(fromX, fromY, toX, toY)
// Call MCP action tool if anti-risk is enabled
if options.AntiRisk {
arguments := getAntiRisk_SetTouchInfoList_Arguments(driver, []ai.PointF{
{X: fromX, Y: fromY},
{X: toX, Y: toY},
})
if arguments != nil {
callMCPActionTool(driver, "evalpkgs",
string(option.ACTION_SetTouchInfoList), arguments)
}
}
// save screenshot before action and mark UI operation // save screenshot before action and mark UI operation
if options.PreMarkOperation { if options.PreMarkOperation {
if markErr := MarkUIOperation(driver, actionType, []float64{fromX, fromY, toX, toY}); markErr != nil { if markErr := MarkUIOperation(driver, actionType, []float64{fromX, fromY, toX, toY}); markErr != nil {
@@ -170,18 +201,51 @@ func callMCPActionTool(driver IDriver,
serverName, actionType, arguments) serverName, actionType, arguments)
} }
// getAntiRisk_SetTouchInfo_Arguments gets arguments for SetTouchInfo MCP tool
func getAntiRisk_SetTouchInfo_Arguments(driver IDriver) map[string]interface{} { func getAntiRisk_SetTouchInfo_Arguments(driver IDriver) map[string]interface{} {
var deviceModel string arguments := getCommonMCPArguments(driver)
device := driver.GetDevice() return arguments
if adbDevice, ok := device.(*AndroidDevice); ok { }
var err error
deviceModel, err = adbDevice.Model() // getAntiRisk_SetTouchInfoList_Arguments gets arguments for SetTouchInfoList MCP tool
if err != nil { func getAntiRisk_SetTouchInfoList_Arguments(driver IDriver, points []ai.PointF) map[string]interface{} {
return nil arguments := getCommonMCPArguments(driver)
pointsList := make([]map[string]float64, len(points))
for i, point := range points {
pointsList[i] = map[string]float64{
"x": point.X,
"y": point.Y,
} }
} }
return map[string]interface{}{ arguments["points"] = pointsList
"deviceModel": deviceModel, arguments["clean"] = true
return arguments
}
// getCommonMCPArguments gets common arguments for MCP tools
func getCommonMCPArguments(driver IDriver) map[string]interface{} {
arguments := make(map[string]interface{})
device := driver.GetDevice()
// Get device model for Android devices
if adbDevice, ok := device.(*AndroidDevice); ok {
// Get device model
if deviceModel, err := adbDevice.Device.Model(); err == nil {
arguments["deviceModel"] = deviceModel
}
// Get device serial number
arguments["deviceSerial"] = adbDevice.Device.Serial()
} }
// Get current foreground app info
if appInfo, err := driver.ForegroundInfo(); err == nil {
arguments["packageName"] = appInfo.PackageName
}
return arguments
} }