refactor: move server models to uixt/types

This commit is contained in:
lilong.129
2025-05-20 14:21:18 +08:00
parent 2f48a92f7f
commit 5066c64368
6 changed files with 52 additions and 29 deletions

View File

@@ -1 +1 @@
v5.0.0-beta-2505201326
v5.0.0-beta-2505201421

View File

@@ -1,4 +1,4 @@
package server
package mcphost
import (
"context"
@@ -12,6 +12,7 @@ import (
"github.com/httprunner/httprunner/v5/internal/version"
"github.com/httprunner/httprunner/v5/uixt"
"github.com/httprunner/httprunner/v5/uixt/option"
"github.com/httprunner/httprunner/v5/uixt/types"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/rs/zerolog/log"
@@ -20,7 +21,8 @@ import (
// MCPServer4XTDriver wraps a MCPServer to expose XTDriver functionality via MCP protocol.
type MCPServer4XTDriver struct {
mcpServer *server.MCPServer
driverCache sync.Map // key is serial, value is *XTDriver
driverCache sync.Map // key is serial, value is *XTDriver
tools []mcp.Tool // 本地维护的工具列表
}
// NewMCPServer creates a new MCP server for XTDriver and registers all tools.
@@ -50,9 +52,10 @@ func (ums *MCPServer4XTDriver) addTools() {
[]mcp.ToolOption{mcp.WithDescription("Taps on the device screen at the given coordinates.")},
commonToolOptions...,
)
tapParams = append(tapParams, generateMCPOptions(TapRequest{})...)
tapParams = append(tapParams, generateMCPOptions(types.TapRequest{})...)
tapXYTool := mcp.NewTool("tap_xy", tapParams...)
ums.mcpServer.AddTool(tapXYTool, ums.handleTapXY)
ums.tools = append(ums.tools, tapXYTool)
log.Info().Str("name", tapXYTool.Name).Msg("Register tool")
// Swipe Tool
@@ -60,9 +63,10 @@ func (ums *MCPServer4XTDriver) addTools() {
[]mcp.ToolOption{mcp.WithDescription("Swipes on the device screen from one point to another.")},
commonToolOptions...,
)
swipeParams = append(swipeParams, generateMCPOptions(DragRequest{})...)
swipeParams = append(swipeParams, generateMCPOptions(types.DragRequest{})...)
swipeTool := mcp.NewTool("swipe", swipeParams...)
ums.mcpServer.AddTool(swipeTool, ums.handleSwipe)
ums.tools = append(ums.tools, swipeTool)
log.Info().Str("name", swipeTool.Name).Msg("Register tool")
// ScreenShot Tool
@@ -70,6 +74,7 @@ func (ums *MCPServer4XTDriver) addTools() {
mcp.WithDescription("Takes a screenshot of the device screen and returns it as a base64 encoded string."),
)
ums.mcpServer.AddTool(screenShotTool, ums.handleScreenShot)
ums.tools = append(ums.tools, screenShotTool)
log.Info().Str("name", screenShotTool.Name).Msg("Register tool")
}
@@ -79,7 +84,7 @@ func (ums *MCPServer4XTDriver) handleTapXY(ctx context.Context, request mcp.Call
if err != nil {
return nil, err
}
var tapReq TapRequest
var tapReq types.TapRequest
if err := mapToStruct(request.Params.Arguments, &tapReq); err != nil {
return mcp.NewToolResultError("parse parameters error: " + err.Error()), nil
}
@@ -103,7 +108,7 @@ func (ums *MCPServer4XTDriver) handleSwipe(ctx context.Context, request mcp.Call
if err != nil {
return nil, err
}
var swipeReq DragRequest
var swipeReq types.DragRequest
if err := mapToStruct(request.Params.Arguments, &swipeReq); err != nil {
return mcp.NewToolResultError("parse parameters error: " + err.Error()), nil
}
@@ -253,3 +258,18 @@ var commonToolOptions = []mcp.ToolOption{
mcp.WithString("platform", mcp.Required(), mcp.Description("Device platform: android/ios/browser")),
mcp.WithString("serial", mcp.Required(), mcp.Description("Device serial/udid/browser id")),
}
// ListTools 返回所有注册的 mcp.Tool
func (s *MCPServer4XTDriver) ListTools() []mcp.Tool {
return s.tools
}
// GetTool 根据名称返回 mcp.Tool 指针
func (s *MCPServer4XTDriver) GetTool(name string) *mcp.Tool {
for i := range s.tools {
if s.tools[i].Name == name {
return &s.tools[i]
}
}
return nil
}

View File

@@ -4,12 +4,6 @@ import (
"github.com/httprunner/httprunner/v5/uixt/option"
)
type TapRequest struct {
X float64 `json:"x" binding:"required" desc:"X coordinate (0.0~1.0 for percent, or absolute pixel value)"`
Y float64 `json:"y" binding:"required" desc:"Y coordinate (0.0~1.0 for percent, or absolute pixel value)"`
Duration float64 `json:"duration" desc:"Tap duration in seconds (optional)"`
}
type uploadRequest struct {
X float64 `json:"x"`
Y float64 `json:"y"`
@@ -17,15 +11,6 @@ type uploadRequest struct {
FileFormat string `json:"file_format"`
}
type DragRequest struct {
FromX float64 `json:"from_x" binding:"required" desc:"Starting X-coordinate (percentage, 0.0 to 1.0)"`
FromY float64 `json:"from_y" binding:"required" desc:"Starting Y-coordinate (percentage, 0.0 to 1.0)"`
ToX float64 `json:"to_x" binding:"required" desc:"Ending X-coordinate (percentage, 0.0 to 1.0)"`
ToY float64 `json:"to_y" binding:"required" desc:"Ending Y-coordinate (percentage, 0.0 to 1.0)"`
Duration float64 `json:"duration" desc:"Swipe duration in milliseconds (optional)"`
PressDuration float64 `json:"press_duration" desc:"Press duration in milliseconds (optional)"`
}
type InputRequest struct {
Text string `json:"text" binding:"required"`
Frequency int `json:"frequency"` // only iOS

View File

@@ -4,10 +4,11 @@ import (
"github.com/gin-gonic/gin"
"github.com/httprunner/httprunner/v5/uixt"
"github.com/httprunner/httprunner/v5/uixt/option"
"github.com/httprunner/httprunner/v5/uixt/types"
)
func (r *Router) tapHandler(c *gin.Context) {
var tapReq TapRequest
var tapReq types.TapRequest
if err := c.ShouldBindJSON(&tapReq); err != nil {
RenderErrorValidateRequest(c, err)
return
@@ -30,7 +31,7 @@ func (r *Router) tapHandler(c *gin.Context) {
}
func (r *Router) rightClickHandler(c *gin.Context) {
var rightClickReq TapRequest
var rightClickReq types.TapRequest
if err := c.ShouldBindJSON(&rightClickReq); err != nil {
RenderErrorValidateRequest(c, err)
return
@@ -117,7 +118,7 @@ func (r *Router) scrollHandler(c *gin.Context) {
}
func (r *Router) doubleTapHandler(c *gin.Context) {
var tapReq TapRequest
var tapReq types.TapRequest
if err := c.ShouldBindJSON(&tapReq); err != nil {
RenderErrorValidateRequest(c, err)
return
@@ -137,7 +138,7 @@ func (r *Router) doubleTapHandler(c *gin.Context) {
}
func (r *Router) dragHandler(c *gin.Context) {
var dragReq DragRequest
var dragReq types.DragRequest
if err := c.ShouldBindJSON(&dragReq); err != nil {
RenderErrorValidateRequest(c, err)
return

View File

@@ -8,6 +8,7 @@ import (
"net/http/httptest"
"testing"
"github.com/httprunner/httprunner/v5/uixt/types"
"github.com/stretchr/testify/assert"
)
@@ -17,14 +18,14 @@ func TestTapHandler(t *testing.T) {
tests := []struct {
name string
path string
tapReq TapRequest
tapReq types.TapRequest
wantStatus int
wantResp HttpResponse
}{
{
name: "tap abs xy",
path: fmt.Sprintf("/api/v1/android/%s/ui/tap", "4622ca24"),
tapReq: TapRequest{
tapReq: types.TapRequest{
X: 500,
Y: 800,
Duration: 0,
@@ -39,7 +40,7 @@ func TestTapHandler(t *testing.T) {
{
name: "tap relative xy",
path: fmt.Sprintf("/api/v1/android/%s/ui/tap", "4622ca24"),
tapReq: TapRequest{
tapReq: types.TapRequest{
X: 0.5,
Y: 0.6,
Duration: 0,

16
uixt/types/request.go Normal file
View File

@@ -0,0 +1,16 @@
package types
type TapRequest struct {
X float64 `json:"x" binding:"required" desc:"X coordinate (0.0~1.0 for percent, or absolute pixel value)"`
Y float64 `json:"y" binding:"required" desc:"Y coordinate (0.0~1.0 for percent, or absolute pixel value)"`
Duration float64 `json:"duration" desc:"Tap duration in seconds (optional)"`
}
type DragRequest struct {
FromX float64 `json:"from_x" binding:"required" desc:"Starting X-coordinate (percentage, 0.0 to 1.0)"`
FromY float64 `json:"from_y" binding:"required" desc:"Starting Y-coordinate (percentage, 0.0 to 1.0)"`
ToX float64 `json:"to_x" binding:"required" desc:"Ending X-coordinate (percentage, 0.0 to 1.0)"`
ToY float64 `json:"to_y" binding:"required" desc:"Ending Y-coordinate (percentage, 0.0 to 1.0)"`
Duration float64 `json:"duration" desc:"Swipe duration in milliseconds (optional)"`
PressDuration float64 `json:"press_duration" desc:"Press duration in milliseconds (optional)"`
}