{"_id":"@anode177/mcp-client","name":"@anode177/mcp-client","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@anode177/mcp-client","version":"1.0.0","description":"MCP client for connecting to Anode Android MCP Server. Enables AI assistants like Claude to control Android devices.","main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","bin":{"anode-mcp":"bin/acs-mcp.js"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup src/index.ts --format cjs,esm --dts","dev":"tsup src/index.ts --format cjs,esm --dts --watch","test":"vitest","lint":"eslint src/","prepublishOnly":"npm run build"},"keywords":["mcp","model-context-protocol","android","automation","anode","claude","ai","accessibility"],"author":{"name":"Anode Team","email":"support@anode.app"},"license":"MIT","homepage":"https://github.com/lsy1770/anode-mcp-client#readme","bugs":{"url":"https://github.com/lsy1770/anode-mcp-client/issues"},"repository":{"type":"git","url":"git+https://github.com/lsy1770/anode-mcp-client.git"},"dependencies":{"ws":"^8.16.0","eventsource":"^2.0.2"},"devDependencies":{"@types/node":"^20.10.0","@types/ws":"^8.5.10","@types/eventsource":"^1.1.15","tsup":"^8.0.1","typescript":"^5.3.0","vitest":"^1.1.0","eslint":"^8.56.0"},"engines":{"node":">=18.0.0"},"_id":"@anode177/mcp-client@1.0.0","gitHead":"2814d236959376852f3d6d3a61aee70d278aa48a","_nodeVersion":"22.17.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-zx0P4cN57asUfAiNiHawoWMBq+jSP6iVBJ/L7AFwbP8MbdI8WHEq2wpPCdaZlQ+J8VPRrrJ3woKKcDP6SR1i1A==","shasum":"c6b61d770b40fb6dd77988c11f6b01785fea5aa0","tarball":"https://registry.npmjs.org/@anode177/mcp-client/-/mcp-client-1.0.0.tgz","fileCount":8,"unpackedSize":51724,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCohyRqFHMX7eR9NjGdszH9wXq0Gb6A/rNt/Gs8PB6kywIhAK74UIYuhWxHDAsEKkMGt8GsvDrnrJUYANkUMurv15xp"}]},"_npmUser":{"name":"anode177","email":"2058951500@qq.com"},"directories":{},"maintainers":[{"name":"anode177","email":"2058951500@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-client_1.0.0_1769004446172_0.7626475540641673"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-21T14:07:26.094Z","1.0.0":"2026-01-21T14:07:26.303Z","modified":"2026-01-21T14:07:26.524Z"},"maintainers":[{"name":"anode177","email":"2058951500@qq.com"}],"description":"MCP client for connecting to Anode Android MCP Server. Enables AI assistants like Claude to control Android devices.","homepage":"https://github.com/lsy1770/anode-mcp-client#readme","keywords":["mcp","model-context-protocol","android","automation","anode","claude","ai","accessibility"],"repository":{"type":"git","url":"git+https://github.com/lsy1770/anode-mcp-client.git"},"author":{"name":"Anode Team","email":"support@anode.app"},"bugs":{"url":"https://github.com/lsy1770/anode-mcp-client/issues"},"license":"MIT","readme":"# @anode177/mcp-client\r\n\r\nA TypeScript/JavaScript client for connecting to Anode Android MCP Server.\r\n\r\nEnables AI assistants like Claude to control Android devices through the Model Context Protocol (MCP).\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @anode177/mcp-client\r\n```\r\n\r\n## Quick Start\r\n\r\n```typescript\r\nimport { McpClient } from '@anode177/mcp-client';\r\n\r\n// Create client\r\nconst client = new McpClient({\r\n  host: '192.168.1.100',  // Android device IP\r\n  transport: 'websocket'   // or 'http-sse'\r\n});\r\n\r\n// Connect\r\nawait client.connect();\r\nconsole.log('Connected to:', client.server?.name);\r\n\r\n// Use automation tools\r\nawait client.tap(500, 800);\r\nawait client.swipe(500, 1500, 500, 500, 300);\r\n\r\nconst screenshot = await client.captureScreen();\r\nconsole.log('Screenshot size:', screenshot.width, 'x', screenshot.height);\r\n\r\n// Disconnect\r\nawait client.disconnect();\r\n```\r\n\r\n## Configuration\r\n\r\n```typescript\r\nconst client = new McpClient({\r\n  host: '192.168.1.100',    // Required: Android device IP\r\n  wsPort: 8765,             // WebSocket port (default: 8765)\r\n  httpPort: 8766,           // HTTP/SSE port (default: 8766)\r\n  transport: 'websocket',   // 'websocket' or 'http-sse' (default: websocket)\r\n  autoReconnect: true,      // Auto reconnect on disconnect (default: true)\r\n  reconnectInterval: 3000,  // Reconnect interval in ms (default: 3000)\r\n  timeout: 30000            // Request timeout in ms (default: 30000)\r\n});\r\n```\r\n\r\n## Event Handling\r\n\r\n```typescript\r\nclient.on('connect', () => {\r\n  console.log('Connected!');\r\n});\r\n\r\nclient.on('disconnect', (reason) => {\r\n  console.log('Disconnected:', reason);\r\n});\r\n\r\nclient.on('error', (error) => {\r\n  console.error('Error:', error);\r\n});\r\n\r\nclient.on('notification', (notification) => {\r\n  console.log('Notification:', notification.method);\r\n});\r\n\r\nclient.on('stateChange', (state) => {\r\n  console.log('State:', state); // 'disconnected' | 'connecting' | 'connected' | 'error'\r\n});\r\n```\r\n\r\n## API Reference\r\n\r\n### Connection\r\n\r\n```typescript\r\nawait client.connect();           // Connect to server\r\nawait client.disconnect();        // Disconnect\r\nclient.isConnected;               // boolean\r\nclient.state;                     // ConnectionState\r\nclient.server;                    // ServerInfo | null\r\n```\r\n\r\n### Low-Level Methods\r\n\r\n```typescript\r\n// List all available tools\r\nconst { tools } = await client.listTools();\r\n\r\n// Call any tool\r\nconst result = await client.callTool('tool_name', { arg1: 'value' });\r\n\r\n// Send raw MCP request\r\nconst response = await client.request('method', { params });\r\n```\r\n\r\n### File Operations\r\n\r\n```typescript\r\n// Read file\r\nconst { content } = await client.fileRead('/sdcard/test.txt');\r\n\r\n// Write file\r\nawait client.fileWrite('/sdcard/test.txt', 'Hello World');\r\n\r\n// List directory\r\nconst { files } = await client.fileList('/sdcard/');\r\n\r\n// Check existence\r\nconst { exists } = await client.fileExists('/sdcard/test.txt');\r\n\r\n// Delete file\r\nawait client.fileDelete('/sdcard/test.txt');\r\n```\r\n\r\n### App Management\r\n\r\n```typescript\r\n// List installed apps\r\nconst { apps } = await client.appList();\r\n\r\n// Launch app\r\nawait client.appLaunch('com.example.app');\r\n\r\n// Get app info\r\nconst info = await client.appGetInfo('com.example.app');\r\n```\r\n\r\n### UI Automation\r\n\r\n```typescript\r\n// Click by selector\r\nawait client.uiClick('text(\"Button\")');\r\n\r\n// Long click\r\nawait client.uiLongClick('id(\"item\")');\r\n\r\n// Set text\r\nawait client.uiSetText('className(\"EditText\")', 'Hello');\r\n\r\n// Scroll\r\nawait client.uiScroll('down');\r\n\r\n// Find node\r\nconst { found, node } = await client.uiFindNode('text(\"Title\")');\r\n```\r\n\r\n### Gesture Operations\r\n\r\n```typescript\r\n// Tap\r\nawait client.tap(500, 800);\r\n\r\n// Swipe\r\nawait client.swipe(500, 1500, 500, 500, 300);\r\n\r\n// Long press\r\nawait client.longPress(500, 800, 1000);\r\n\r\n// Pinch (zoom)\r\nawait client.pinch(540, 960, 0.5);  // zoom out\r\nawait client.pinch(540, 960, 2.0);  // zoom in\r\n\r\n// Drag\r\nawait client.drag(100, 100, 500, 500, 500);\r\n```\r\n\r\n### Layout Analysis\r\n\r\n```typescript\r\n// Get root node\r\nconst { root } = await client.layoutGetRoot();\r\n\r\n// Find by ID\r\nconst { nodes } = await client.layoutFindById('com.app:id/button');\r\n\r\n// Find by text\r\nconst { nodes } = await client.layoutFindByText('Submit');\r\n\r\n// Find all clickable\r\nconst { nodes } = await client.layoutFindClickable();\r\n```\r\n\r\n### Image Operations\r\n\r\n```typescript\r\n// Capture screen\r\nconst { image, width, height } = await client.captureScreen('png', 90);\r\n\r\n// Find color\r\nconst { found, x, y } = await client.findColor('#FF0000');\r\n\r\n// Find image\r\nconst { found, x, y, similarity } = await client.findImage(templateBase64, 0.9);\r\n```\r\n\r\n### Device Information\r\n\r\n```typescript\r\n// Get screen size\r\nconst { width, height, density } = await client.deviceGetScreenSize();\r\n\r\n// Get current app\r\nconst { packageName, activityName } = await client.deviceGetCurrentApp();\r\n\r\n// Get screen state\r\nconst { isOn, isLocked } = await client.deviceGetScreenState();\r\n```\r\n\r\n## Complete Example\r\n\r\n```typescript\r\nimport { McpClient } from '@anode177/mcp-client';\r\n\r\nasync function automateApp() {\r\n  const client = new McpClient({\r\n    host: '192.168.1.100'\r\n  });\r\n\r\n  try {\r\n    // Connect\r\n    await client.connect();\r\n    console.log('Connected to', client.server?.name);\r\n\r\n    // Launch app\r\n    await client.appLaunch('com.example.myapp');\r\n    await sleep(2000);\r\n\r\n    // Find and click login button\r\n    const loginBtn = await client.layoutFindByText('Login');\r\n    if (loginBtn.nodes.length > 0) {\r\n      await client.uiClick('text(\"Login\")');\r\n    }\r\n\r\n    // Enter credentials\r\n    await client.uiSetText('id(\"username\")', 'myuser');\r\n    await client.uiSetText('id(\"password\")', 'mypass');\r\n\r\n    // Submit\r\n    await client.uiClick('text(\"Submit\")');\r\n    await sleep(3000);\r\n\r\n    // Take screenshot\r\n    const screenshot = await client.captureScreen();\r\n    console.log('Screenshot captured:', screenshot.width, 'x', screenshot.height);\r\n\r\n  } finally {\r\n    await client.disconnect();\r\n  }\r\n}\r\n\r\nfunction sleep(ms: number) {\r\n  return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\nautomateApp().catch(console.error);\r\n```\r\n\r\n## Transport Options\r\n\r\n### WebSocket (Recommended)\r\n\r\n- Real-time bidirectional communication\r\n- Lower latency\r\n- Better for automation scripts\r\n\r\n```typescript\r\nconst client = new McpClient({\r\n  host: '192.168.1.100',\r\n  transport: 'websocket',\r\n  wsPort: 8765\r\n});\r\n```\r\n\r\n### HTTP/SSE\r\n\r\n- Firewall friendly\r\n- Works through proxies\r\n- Good for web-based clients\r\n\r\n```typescript\r\nconst client = new McpClient({\r\n  host: '192.168.1.100',\r\n  transport: 'http-sse',\r\n  httpPort: 8766\r\n});\r\n```\r\n\r\n## License\r\n\r\nMIT\r\n","readmeFilename":"README.md","_rev":"1-4c832ce4b907059160f44d364beee663"}