npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@anode177/mcp-client

v1.0.0

Published

MCP client for connecting to Anode Android MCP Server. Enables AI assistants like Claude to control Android devices.

Readme

@anode177/mcp-client

A TypeScript/JavaScript client for connecting to Anode Android MCP Server.

Enables AI assistants like Claude to control Android devices through the Model Context Protocol (MCP).

Installation

npm install @anode177/mcp-client

Quick Start

import { McpClient } from '@anode177/mcp-client';

// Create client
const client = new McpClient({
  host: '192.168.1.100',  // Android device IP
  transport: 'websocket'   // or 'http-sse'
});

// Connect
await client.connect();
console.log('Connected to:', client.server?.name);

// Use automation tools
await client.tap(500, 800);
await client.swipe(500, 1500, 500, 500, 300);

const screenshot = await client.captureScreen();
console.log('Screenshot size:', screenshot.width, 'x', screenshot.height);

// Disconnect
await client.disconnect();

Configuration

const client = new McpClient({
  host: '192.168.1.100',    // Required: Android device IP
  wsPort: 8765,             // WebSocket port (default: 8765)
  httpPort: 8766,           // HTTP/SSE port (default: 8766)
  transport: 'websocket',   // 'websocket' or 'http-sse' (default: websocket)
  autoReconnect: true,      // Auto reconnect on disconnect (default: true)
  reconnectInterval: 3000,  // Reconnect interval in ms (default: 3000)
  timeout: 30000            // Request timeout in ms (default: 30000)
});

Event Handling

client.on('connect', () => {
  console.log('Connected!');
});

client.on('disconnect', (reason) => {
  console.log('Disconnected:', reason);
});

client.on('error', (error) => {
  console.error('Error:', error);
});

client.on('notification', (notification) => {
  console.log('Notification:', notification.method);
});

client.on('stateChange', (state) => {
  console.log('State:', state); // 'disconnected' | 'connecting' | 'connected' | 'error'
});

API Reference

Connection

await client.connect();           // Connect to server
await client.disconnect();        // Disconnect
client.isConnected;               // boolean
client.state;                     // ConnectionState
client.server;                    // ServerInfo | null

Low-Level Methods

// List all available tools
const { tools } = await client.listTools();

// Call any tool
const result = await client.callTool('tool_name', { arg1: 'value' });

// Send raw MCP request
const response = await client.request('method', { params });

File Operations

// Read file
const { content } = await client.fileRead('/sdcard/test.txt');

// Write file
await client.fileWrite('/sdcard/test.txt', 'Hello World');

// List directory
const { files } = await client.fileList('/sdcard/');

// Check existence
const { exists } = await client.fileExists('/sdcard/test.txt');

// Delete file
await client.fileDelete('/sdcard/test.txt');

App Management

// List installed apps
const { apps } = await client.appList();

// Launch app
await client.appLaunch('com.example.app');

// Get app info
const info = await client.appGetInfo('com.example.app');

UI Automation

// Click by selector
await client.uiClick('text("Button")');

// Long click
await client.uiLongClick('id("item")');

// Set text
await client.uiSetText('className("EditText")', 'Hello');

// Scroll
await client.uiScroll('down');

// Find node
const { found, node } = await client.uiFindNode('text("Title")');

Gesture Operations

// Tap
await client.tap(500, 800);

// Swipe
await client.swipe(500, 1500, 500, 500, 300);

// Long press
await client.longPress(500, 800, 1000);

// Pinch (zoom)
await client.pinch(540, 960, 0.5);  // zoom out
await client.pinch(540, 960, 2.0);  // zoom in

// Drag
await client.drag(100, 100, 500, 500, 500);

Layout Analysis

// Get root node
const { root } = await client.layoutGetRoot();

// Find by ID
const { nodes } = await client.layoutFindById('com.app:id/button');

// Find by text
const { nodes } = await client.layoutFindByText('Submit');

// Find all clickable
const { nodes } = await client.layoutFindClickable();

Image Operations

// Capture screen
const { image, width, height } = await client.captureScreen('png', 90);

// Find color
const { found, x, y } = await client.findColor('#FF0000');

// Find image
const { found, x, y, similarity } = await client.findImage(templateBase64, 0.9);

Device Information

// Get screen size
const { width, height, density } = await client.deviceGetScreenSize();

// Get current app
const { packageName, activityName } = await client.deviceGetCurrentApp();

// Get screen state
const { isOn, isLocked } = await client.deviceGetScreenState();

Complete Example

import { McpClient } from '@anode177/mcp-client';

async function automateApp() {
  const client = new McpClient({
    host: '192.168.1.100'
  });

  try {
    // Connect
    await client.connect();
    console.log('Connected to', client.server?.name);

    // Launch app
    await client.appLaunch('com.example.myapp');
    await sleep(2000);

    // Find and click login button
    const loginBtn = await client.layoutFindByText('Login');
    if (loginBtn.nodes.length > 0) {
      await client.uiClick('text("Login")');
    }

    // Enter credentials
    await client.uiSetText('id("username")', 'myuser');
    await client.uiSetText('id("password")', 'mypass');

    // Submit
    await client.uiClick('text("Submit")');
    await sleep(3000);

    // Take screenshot
    const screenshot = await client.captureScreen();
    console.log('Screenshot captured:', screenshot.width, 'x', screenshot.height);

  } finally {
    await client.disconnect();
  }
}

function sleep(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

automateApp().catch(console.error);

Transport Options

WebSocket (Recommended)

  • Real-time bidirectional communication
  • Lower latency
  • Better for automation scripts
const client = new McpClient({
  host: '192.168.1.100',
  transport: 'websocket',
  wsPort: 8765
});

HTTP/SSE

  • Firewall friendly
  • Works through proxies
  • Good for web-based clients
const client = new McpClient({
  host: '192.168.1.100',
  transport: 'http-sse',
  httpPort: 8766
});

License

MIT