mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-06 07:57:27 +08:00
feat: integrate MCP tools with UI actions and improve environment variable inheritance
This commit is contained in:
@@ -1 +1 @@
|
|||||||
v5.0.0-beta-2505272139
|
v5.0.0-beta-2505282259
|
||||||
|
|||||||
+5
-1
@@ -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)
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user