android-mcp-toolkit 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -11
- package/dist/index.js +55 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Android MCP Toolkit for AI Agents
|
|
2
2
|
|
|
3
|
-
Small MCP server with
|
|
3
|
+
Small MCP server with three tools:
|
|
4
4
|
- Fast SVG → Android VectorDrawable conversion (cached, file or inline).
|
|
5
5
|
- adb logcat reader with package/pid/tag filters for quick crash triage.
|
|
6
|
+
- Translation length difference estimator to flag risky length deltas before layout breaks.
|
|
6
7
|
|
|
7
8
|
## Why this exists
|
|
8
9
|
**The Mission: Bringing Native Android to the AI Agent Era**
|
|
@@ -72,6 +73,10 @@ While the AI ecosystem flourishes with web-first tools, Android development ofte
|
|
|
72
73
|
- Inputs: `timeoutMs` (default `5000`, max `15000`).
|
|
73
74
|
- Behavior: Runs `adb logcat -c` to clear buffers before a new scenario.
|
|
74
75
|
|
|
76
|
+
- `estimate-text-length-difference`
|
|
77
|
+
- Inputs: `sourceText` (original), `translatedText` (to compare), `tolerancePercent` (default `30`, max `500`).
|
|
78
|
+
- Behavior: Measures grapheme length of both strings, computes percent change, and reports whether it exceeds the tolerance (useful to catch translation length blowups that could break layouts).
|
|
79
|
+
|
|
75
80
|
## Roadmap (planned)
|
|
76
81
|
- Additional MCP tools for Android assets (e.g., batch conversions, validations, optimizers).
|
|
77
82
|
- Optional resource prompts for common Android drawables/templates.
|
|
@@ -83,15 +88,11 @@ While the AI ecosystem flourishes with web-first tools, Android development ofte
|
|
|
83
88
|
|
|
84
89
|
## Quick start
|
|
85
90
|
- `npm install`
|
|
86
|
-
- `npm
|
|
91
|
+
- `npm run build`
|
|
92
|
+
- `node dist/index.js` (stdio MCP server)
|
|
87
93
|
|
|
88
94
|
## Run via npx
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
## Run with Docker
|
|
92
|
-
- Build: `docker build -t svg-to-drawable-mcp .`
|
|
93
|
-
- Run: `docker run --rm -it svg-to-drawable-mcp`
|
|
94
|
-
- The container prints to stdio; point your MCP client at `docker run --rm -i svg-to-drawable-mcp`.
|
|
95
|
+
- Global: `npx android-mcp-toolkit`
|
|
95
96
|
|
|
96
97
|
## Use in Cursor (MCP config)
|
|
97
98
|
Add to your Cursor settings JSON:
|
|
@@ -101,17 +102,20 @@ Add to your Cursor settings JSON:
|
|
|
101
102
|
"figma-desktop": {
|
|
102
103
|
"url": "http://127.0.0.1:3845/mcp"
|
|
103
104
|
},
|
|
104
|
-
"
|
|
105
|
+
"android-mcp-toolkit": {
|
|
105
106
|
"command": "npx",
|
|
106
107
|
"args": [
|
|
107
108
|
"-y",
|
|
108
|
-
"
|
|
109
|
+
"android-mcp-toolkit"
|
|
109
110
|
]
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
```
|
|
114
|
-
|
|
115
|
+
The npx call downloads the published package; no local path required.
|
|
116
|
+
|
|
117
|
+
Quick install via Cursor deep link:
|
|
118
|
+
- `cursor://anysphere.cursor-deeplink/mcp/install?name=android-mcp-toolkit&config=eyJjb21tYW5kIjoibnB4IC15IGFuZHJvaWQtbWNwLXRvb2xraXQifQ%3D%3D`
|
|
115
119
|
|
|
116
120
|
## Examples
|
|
117
121
|
- Input SVG: `sample_svg.svg`
|
package/dist/index.js
CHANGED
|
@@ -1460,16 +1460,68 @@ var require_logcatTool = __commonJS({
|
|
|
1460
1460
|
}
|
|
1461
1461
|
});
|
|
1462
1462
|
|
|
1463
|
+
// src/tools/textLengthTool.js
|
|
1464
|
+
var require_textLengthTool = __commonJS({
|
|
1465
|
+
"src/tools/textLengthTool.js"(exports2, module2) {
|
|
1466
|
+
var z = require("zod/v4");
|
|
1467
|
+
var textLengthToolInstructions2 = [
|
|
1468
|
+
"Use estimate-text-length-difference to compare original vs translated text lengths and flag large deltas.",
|
|
1469
|
+
"Configure tolerancePercent to set the allowed absolute percentage difference (default 30%).",
|
|
1470
|
+
"The tool reports both lengths, percent change, and whether the change exceeds tolerance."
|
|
1471
|
+
].join("\n");
|
|
1472
|
+
var lengthDiffInputSchema = z.object({
|
|
1473
|
+
sourceText: z.string().min(1).describe("Original text before translation"),
|
|
1474
|
+
translatedText: z.string().min(1).describe("Translated text to compare against the original"),
|
|
1475
|
+
tolerancePercent: z.number().min(1).max(500).default(30).describe("Allowed absolute percent difference between lengths before flagging risk")
|
|
1476
|
+
});
|
|
1477
|
+
function measureLength(text) {
|
|
1478
|
+
return Array.from(text).length;
|
|
1479
|
+
}
|
|
1480
|
+
function registerTextLengthTool2(server2) {
|
|
1481
|
+
server2.registerTool(
|
|
1482
|
+
"estimate-text-length-difference",
|
|
1483
|
+
{
|
|
1484
|
+
title: "Estimate text length difference",
|
|
1485
|
+
description: "Compare original and translated text lengths to detect layout risk; configurable tolerancePercent (default 30%).",
|
|
1486
|
+
inputSchema: lengthDiffInputSchema
|
|
1487
|
+
},
|
|
1488
|
+
async (params) => {
|
|
1489
|
+
const sourceLength = measureLength(params.sourceText);
|
|
1490
|
+
const translatedLength = measureLength(params.translatedText);
|
|
1491
|
+
const delta = translatedLength - sourceLength;
|
|
1492
|
+
const percentChange = sourceLength === 0 ? null : delta / sourceLength * 100;
|
|
1493
|
+
const exceeds = percentChange === null ? translatedLength > 0 : Math.abs(percentChange) > params.tolerancePercent;
|
|
1494
|
+
const direction = delta === 0 ? "no change" : delta > 0 ? "longer" : "shorter";
|
|
1495
|
+
const verdict = percentChange === null && translatedLength === 0 ? "\u2705 Both texts are empty; no length risk." : percentChange === null ? "\u26A0\uFE0F Source length is 0; percent change undefined and translated text is present." : exceeds ? "\u26A0\uFE0F Length difference exceeds tolerance (layout risk likely)." : "\u2705 Length difference within tolerance.";
|
|
1496
|
+
const summary = [
|
|
1497
|
+
verdict,
|
|
1498
|
+
`Source length: ${sourceLength}`,
|
|
1499
|
+
`Translated length: ${translatedLength}`,
|
|
1500
|
+
percentChange === null ? `Change: N/A (source length is 0; direction: ${direction})` : `Change: ${percentChange.toFixed(2)}% (${direction})`,
|
|
1501
|
+
`Tolerance: \xB1${params.tolerancePercent}%`
|
|
1502
|
+
].join("\n");
|
|
1503
|
+
return { content: [{ type: "text", text: summary }] };
|
|
1504
|
+
}
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
module2.exports = {
|
|
1508
|
+
registerTextLengthTool: registerTextLengthTool2,
|
|
1509
|
+
textLengthToolInstructions: textLengthToolInstructions2
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
});
|
|
1513
|
+
|
|
1463
1514
|
// src/index.js
|
|
1464
1515
|
var { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
1465
1516
|
var { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
1466
1517
|
var { registerSvgTool, svgToolInstructions } = require_svgTool();
|
|
1467
1518
|
var { registerLogcatTool, logcatToolInstructions } = require_logcatTool();
|
|
1468
|
-
var
|
|
1519
|
+
var { registerTextLengthTool, textLengthToolInstructions } = require_textLengthTool();
|
|
1520
|
+
var serverInstructions = [svgToolInstructions, logcatToolInstructions, textLengthToolInstructions].join("\n");
|
|
1469
1521
|
var server = new McpServer(
|
|
1470
1522
|
{
|
|
1471
1523
|
name: "svg-to-android-drawable",
|
|
1472
|
-
version: "1.
|
|
1524
|
+
version: "1.2.0"
|
|
1473
1525
|
},
|
|
1474
1526
|
{
|
|
1475
1527
|
capabilities: { logging: {} },
|
|
@@ -1478,6 +1530,7 @@ var server = new McpServer(
|
|
|
1478
1530
|
);
|
|
1479
1531
|
registerSvgTool(server);
|
|
1480
1532
|
registerLogcatTool(server);
|
|
1533
|
+
registerTextLengthTool(server);
|
|
1481
1534
|
async function main() {
|
|
1482
1535
|
const transport = new StdioServerTransport();
|
|
1483
1536
|
await server.connect(transport);
|