From 247368c7c6a6c76e4ff1cf81c9882bb658abf446 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Fri, 21 Nov 2025 17:59:42 +0000 Subject: [PATCH] feat: add Appium MCP Server documentation and tests - Add comprehensive test suite for Appium MCP Server configuration - Document MCP server marketplace item structure - Provide guidance for adding new MCP servers to marketplace - Include example configuration for Appium MCP Server Addresses #9479 --- docs/marketplace-mcp-servers.md | 211 ++++++++++++ .../__tests__/appium-mcp-server.spec.ts | 308 ++++++++++++++++++ 2 files changed, 519 insertions(+) create mode 100644 docs/marketplace-mcp-servers.md create mode 100644 src/services/marketplace/__tests__/appium-mcp-server.spec.ts diff --git a/docs/marketplace-mcp-servers.md b/docs/marketplace-mcp-servers.md new file mode 100644 index 0000000000..faf9e9db2d --- /dev/null +++ b/docs/marketplace-mcp-servers.md @@ -0,0 +1,211 @@ +# Adding MCP Servers to the Roo Code Marketplace + +## Overview + +The Roo Code Marketplace provides a centralized location for discovering and installing MCP (Model Context Protocol) servers. This document describes how MCP servers are configured and provides guidance for requesting new servers to be added. + +## MCP Server Configuration Structure + +MCP servers in the marketplace are defined with the following structure: + +```typescript +interface McpMarketplaceItem { + id: string // Unique identifier for the server + name: string // Display name + description: string // Brief description of functionality + author?: string // Author/organization name + authorUrl?: string // Link to author's website or GitHub + url: string // Repository URL + type: "mcp" // Item type (always "mcp" for servers) + tags?: string[] // Searchable tags + prerequisites?: string[] // Installation requirements + content: string | McpInstallationMethod[] // Server configuration + parameters?: McpParameter[] // Configurable parameters +} +``` + +### Basic MCP Server Configuration + +For a simple MCP server that runs via NPX: + +```json +{ + "id": "example-mcp", + "name": "Example MCP Server", + "description": "An example MCP server for demonstration", + "url": "https://github.com/example/example-mcp", + "type": "mcp", + "content": "{\"command\": \"npx\", \"args\": [\"-y\", \"@example/mcp-server\"]}" +} +``` + +### MCP Server with Parameters + +For servers that require configuration: + +```json +{ + "id": "configurable-mcp", + "name": "Configurable MCP Server", + "description": "MCP server with user-configurable options", + "url": "https://github.com/example/configurable-mcp", + "type": "mcp", + "content": "{\"command\": \"npx\", \"args\": [\"-y\", \"@example/mcp-server\"], \"env\": {\"API_KEY\": \"{{API_KEY}}\"}}", + "parameters": [ + { + "name": "API Key", + "key": "API_KEY", + "placeholder": "Enter your API key", + "optional": false + } + ] +} +``` + +### Multiple Installation Methods + +For servers with different installation options: + +```json +{ + "id": "multi-install-mcp", + "name": "Multi-Install MCP Server", + "description": "MCP server with multiple installation methods", + "url": "https://github.com/example/multi-mcp", + "type": "mcp", + "content": [ + { + "name": "NPX (Recommended)", + "content": "{\"command\": \"npx\", \"args\": [\"-y\", \"@example/mcp\"]}" + }, + { + "name": "Docker", + "content": "{\"command\": \"docker\", \"args\": [\"run\", \"-p\", \"3000:3000\", \"example/mcp:latest\"]}", + "prerequisites": ["Docker installed and running"] + }, + { + "name": "Global Install", + "content": "{\"command\": \"example-mcp\", \"args\": []}", + "prerequisites": ["Install globally first: npm install -g @example/mcp"] + } + ] +} +``` + +## Example: Appium MCP Server Configuration + +The Appium MCP Server, as requested in issue #9479, would be configured as follows: + +```json +{ + "id": "appium-mcp", + "name": "Appium MCP Server", + "description": "MCP server for Mobile Development and Automation | iOS, Android, Simulator, Emulator, and Real Devices", + "author": "Appium Contributors", + "authorUrl": "https://github.com/appium", + "url": "https://github.com/appium/appium-mcp", + "type": "mcp", + "tags": ["mobile", "automation", "ios", "android", "testing", "appium"], + "prerequisites": [ + "Node.js 16+ and npm installed", + "Appium installed globally or locally", + "Platform-specific requirements (Xcode for iOS, Android SDK for Android)" + ], + "content": "{\"command\": \"npx\", \"args\": [\"-y\", \"@appium/mcp-server\"], \"env\": {\"APPIUM_HOST\": \"localhost\", \"APPIUM_PORT\": \"4723\"}}", + "parameters": [ + { + "name": "Appium Host", + "key": "APPIUM_HOST", + "placeholder": "localhost", + "optional": true + }, + { + "name": "Appium Port", + "key": "APPIUM_PORT", + "placeholder": "4723", + "optional": true + } + ] +} +``` + +## MCP Server Capabilities + +When documenting an MCP server for the marketplace, include information about its capabilities: + +### Tools + +List the tools/commands the server exposes: + +- `launch_app` - Launch a mobile application +- `find_element` - Find UI elements +- `take_screenshot` - Capture device screen +- etc. + +### Resources + +List the resources available: + +- `device_list` - Available devices +- `session_info` - Current session details +- etc. + +### Prompts + +List any pre-configured prompts: + +- `test_login_flow` - Automate login testing +- `validate_ui_elements` - Check UI consistency +- etc. + +## How to Request a New MCP Server + +To request a new MCP server be added to the marketplace: + +1. **Open an Issue**: Create a GitHub issue in the Roo Code repository +2. **Provide Information**: + - Server name and description + - GitHub repository URL + - Installation command (NPX, Docker, etc.) + - Any required configuration parameters + - Prerequisites for installation + - List of capabilities (tools, resources, prompts) +3. **Include Examples**: Provide example use cases or documentation links +4. **Test the Server**: Confirm the server works with the MCP protocol + +## Technical Implementation + +The marketplace items are fetched from a remote API endpoint managed by the Roo Code team. The actual configuration data is stored server-side and retrieved by the extension at runtime. + +### API Endpoints + +- Modes: `https://api.roocode.com/api/marketplace/modes` +- MCP Servers: `https://api.roocode.com/api/marketplace/mcps` + +### Local Testing + +For development and testing, you can mock MCP server configurations using the test framework as shown in `src/services/marketplace/__tests__/appium-mcp-server.spec.ts`. + +## Best Practices + +1. **Clear Naming**: Use descriptive, unique IDs and names +2. **Comprehensive Descriptions**: Explain what the server does and its use cases +3. **Document Prerequisites**: List all requirements for successful installation +4. **Provide Parameters**: Allow users to configure server behavior +5. **Tag Appropriately**: Use relevant tags for discoverability +6. **Test Thoroughly**: Ensure the server configuration works before submission + +## Security Considerations + +- Never include sensitive information (API keys, passwords) in the configuration +- Use parameter placeholders for user-specific values +- Verify server authenticity through official repository URLs +- Review server permissions and capabilities before installation + +## Support + +For questions about adding MCP servers to the marketplace: + +- Open a GitHub issue with the "enhancement" label +- Join the community discussions +- Refer to the MCP protocol documentation diff --git a/src/services/marketplace/__tests__/appium-mcp-server.spec.ts b/src/services/marketplace/__tests__/appium-mcp-server.spec.ts new file mode 100644 index 0000000000..b6d47952aa --- /dev/null +++ b/src/services/marketplace/__tests__/appium-mcp-server.spec.ts @@ -0,0 +1,308 @@ +// npx vitest services/marketplace/__tests__/appium-mcp-server.spec.ts + +import { SimpleInstaller } from "../SimpleInstaller" +import { MarketplaceItem } from "@roo-code/types" +import * as fs from "fs/promises" +import * as path from "path" +import * as vscode from "vscode" +import { vi, describe, it, expect, beforeEach } from "vitest" + +// Mock fs module +vi.mock("fs/promises") + +// Mock vscode module +vi.mock("vscode", () => ({ + workspace: { + workspaceFolders: [ + { + uri: { + fsPath: "/test/workspace", + }, + }, + ], + }, +})) + +describe("Appium MCP Server Installation", () => { + let installer: SimpleInstaller + const mockFs = fs as any + const mockContext = { + globalStorageUri: { fsPath: "/test/global" }, + storageUri: { fsPath: "/test/storage" }, + } as any + + beforeEach(() => { + vi.clearAllMocks() + installer = new SimpleInstaller(mockContext, undefined) + // Mock file operations + mockFs.access.mockResolvedValue(undefined) + mockFs.writeFile.mockResolvedValue(undefined) + mockFs.readFile.mockResolvedValue("{}") + mockFs.mkdir.mockResolvedValue(undefined) + }) + + describe("Appium MCP Server Configuration", () => { + it("should define Appium MCP Server marketplace item correctly", () => { + // This is the expected configuration for Appium MCP Server + const appiumMcpItem: MarketplaceItem = { + id: "appium-mcp", + name: "Appium MCP Server", + description: + "MCP server for Mobile Development and Automation | iOS, Android, Simulator, Emulator, and Real Devices", + author: "Appium Contributors", + authorUrl: "https://github.com/appium", + url: "https://github.com/appium/appium-mcp", + type: "mcp", + tags: ["mobile", "automation", "ios", "android", "testing", "appium"], + content: JSON.stringify({ + command: "npx", + args: ["-y", "@appium/mcp-server"], + env: { + APPIUM_HOST: "localhost", + APPIUM_PORT: "4723", + }, + }), + prerequisites: [ + "Node.js 16+ and npm installed", + "Appium installed globally or locally", + "Platform-specific requirements (Xcode for iOS, Android SDK for Android)", + ], + } + + // Validate the structure + expect(appiumMcpItem.id).toBe("appium-mcp") + expect(appiumMcpItem.type).toBe("mcp") + expect(appiumMcpItem.name).toBe("Appium MCP Server") + expect(appiumMcpItem.url).toBe("https://github.com/appium/appium-mcp") + expect(appiumMcpItem.tags).toContain("mobile") + expect(appiumMcpItem.tags).toContain("automation") + expect(appiumMcpItem.prerequisites).toBeDefined() + expect(appiumMcpItem.prerequisites?.length).toBeGreaterThan(0) + }) + + it("should support alternative Appium MCP installation methods", () => { + // Alternative installation method using multiple configurations + const appiumMcpWithMethods: MarketplaceItem = { + id: "appium-mcp", + name: "Appium MCP Server", + description: "MCP server for Mobile Development and Automation", + url: "https://github.com/appium/appium-mcp", + type: "mcp", + content: [ + { + name: "Default (NPX)", + content: JSON.stringify({ + command: "npx", + args: ["-y", "@appium/mcp-server"], + }), + }, + { + name: "Docker", + content: JSON.stringify({ + command: "docker", + args: ["run", "-p", "4723:4723", "appium/appium-mcp:latest"], + }), + prerequisites: ["Docker installed and running"], + }, + { + name: "Global NPM Install", + content: JSON.stringify({ + command: "appium-mcp", + args: [], + }), + prerequisites: ["Install globally first: npm install -g @appium/mcp-server"], + }, + ], + } + + // Validate multiple installation methods + expect(Array.isArray(appiumMcpWithMethods.content)).toBe(true) + if (Array.isArray(appiumMcpWithMethods.content)) { + expect(appiumMcpWithMethods.content).toHaveLength(3) + expect(appiumMcpWithMethods.content[0].name).toBe("Default (NPX)") + expect(appiumMcpWithMethods.content[1].name).toBe("Docker") + expect(appiumMcpWithMethods.content[2].name).toBe("Global NPM Install") + } + }) + }) + + describe("Installing Appium MCP Server", () => { + it("should install Appium MCP Server to project configuration", async () => { + const appiumMcpItem: MarketplaceItem = { + id: "appium-mcp", + name: "Appium MCP Server", + description: "MCP server for Mobile Development and Automation", + url: "https://github.com/appium/appium-mcp", + type: "mcp", + content: JSON.stringify({ + command: "npx", + args: ["-y", "@appium/mcp-server"], + env: { + APPIUM_HOST: "localhost", + APPIUM_PORT: "4723", + }, + }), + } + + // Mock existing MCP configuration + mockFs.readFile.mockResolvedValue( + JSON.stringify({ + mcpServers: { + "existing-server": { + command: "node", + args: ["server.js"], + }, + }, + }), + ) + + const result = await installer.installItem(appiumMcpItem, { + target: "project", + }) + + expect(result.filePath).toContain("mcp.json") + expect(mockFs.writeFile).toHaveBeenCalled() + + // Verify the written content includes Appium MCP + const writtenContent = mockFs.writeFile.mock.calls[0][1] + const writtenData = JSON.parse(writtenContent) + expect(writtenData.mcpServers["appium-mcp"]).toBeDefined() + expect(writtenData.mcpServers["appium-mcp"].command).toBe("npx") + expect(writtenData.mcpServers["appium-mcp"].args).toContain("-y") + expect(writtenData.mcpServers["appium-mcp"].args).toContain("@appium/mcp-server") + expect(writtenData.mcpServers["appium-mcp"].env.APPIUM_HOST).toBe("localhost") + expect(writtenData.mcpServers["appium-mcp"].env.APPIUM_PORT).toBe("4723") + }) + + it("should install Appium MCP Server with parameters", async () => { + const appiumMcpItem: MarketplaceItem = { + id: "appium-mcp", + name: "Appium MCP Server", + description: "MCP server for Mobile Development and Automation", + url: "https://github.com/appium/appium-mcp", + type: "mcp", + content: JSON.stringify({ + command: "npx", + args: ["-y", "@appium/mcp-server"], + env: { + APPIUM_HOST: "{{APPIUM_HOST}}", + APPIUM_PORT: "{{APPIUM_PORT}}", + PLATFORM_NAME: "{{PLATFORM_NAME}}", + }, + }), + parameters: [ + { + name: "Appium Host", + key: "APPIUM_HOST", + placeholder: "localhost", + optional: false, + }, + { + name: "Appium Port", + key: "APPIUM_PORT", + placeholder: "4723", + optional: false, + }, + { + name: "Platform", + key: "PLATFORM_NAME", + placeholder: "iOS or Android", + optional: true, + }, + ], + } + + const result = await installer.installItem(appiumMcpItem, { + target: "project", + parameters: { + APPIUM_HOST: "127.0.0.1", + APPIUM_PORT: "4444", + PLATFORM_NAME: "iOS", + }, + }) + + expect(result.filePath).toContain("mcp.json") + expect(mockFs.writeFile).toHaveBeenCalled() + + // Verify parameters were properly substituted + const writtenContent = mockFs.writeFile.mock.calls[0][1] + const writtenData = JSON.parse(writtenContent) + expect(writtenData.mcpServers["appium-mcp"].env.APPIUM_HOST).toBe("127.0.0.1") + expect(writtenData.mcpServers["appium-mcp"].env.APPIUM_PORT).toBe("4444") + expect(writtenData.mcpServers["appium-mcp"].env.PLATFORM_NAME).toBe("iOS") + }) + + it("should handle Appium MCP Server with multiple capabilities", () => { + // Test configuration with advanced Appium capabilities + const appiumMcpAdvanced: MarketplaceItem = { + id: "appium-mcp", + name: "Appium MCP Server", + description: "MCP server for Mobile Development and Automation", + url: "https://github.com/appium/appium-mcp", + type: "mcp", + content: JSON.stringify({ + command: "npx", + args: ["-y", "@appium/mcp-server"], + env: { + APPIUM_HOST: "localhost", + APPIUM_PORT: "4723", + CAPABILITIES: JSON.stringify({ + platformName: "iOS", + platformVersion: "15.0", + deviceName: "iPhone 13", + automationName: "XCUITest", + app: "/path/to/app.ipa", + }), + }, + }), + } + + // Parse and validate the capabilities + const content = JSON.parse(appiumMcpAdvanced.content as string) + const capabilities = JSON.parse(content.env.CAPABILITIES) + + expect(capabilities.platformName).toBe("iOS") + expect(capabilities.deviceName).toBe("iPhone 13") + expect(capabilities.automationName).toBe("XCUITest") + }) + }) + + describe("Appium MCP Server Features", () => { + it("should support mobile automation tools and commands", () => { + // Define expected Appium MCP capabilities + const expectedTools = [ + "launch_app", + "install_app", + "uninstall_app", + "find_element", + "click_element", + "send_keys", + "swipe", + "scroll", + "take_screenshot", + "get_device_info", + "get_orientation", + "set_orientation", + "start_recording", + "stop_recording", + "push_file", + "pull_file", + "get_logs", + "execute_script", + ] + + // This represents what the MCP server should expose + const appiumMcpCapabilities = { + tools: expectedTools, + resources: ["device_list", "app_list", "session_info", "element_tree"], + prompts: ["test_login_flow", "validate_ui_elements", "perform_gesture", "capture_performance_metrics"], + } + + expect(appiumMcpCapabilities.tools).toContain("launch_app") + expect(appiumMcpCapabilities.tools).toContain("find_element") + expect(appiumMcpCapabilities.tools).toContain("take_screenshot") + expect(appiumMcpCapabilities.resources).toContain("device_list") + expect(appiumMcpCapabilities.prompts).toContain("test_login_flow") + }) + }) +})