@nbakka/mcp-appium 1.0.23 → 1.0.24
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/package.json +1 -1
- package/src/lib/server.js +66 -0
package/package.json
CHANGED
package/src/lib/server.js
CHANGED
|
@@ -142,6 +142,72 @@ server.tool(
|
|
|
142
142
|
}
|
|
143
143
|
);
|
|
144
144
|
|
|
145
|
+
// Get visible text elements including duplicates
|
|
146
|
+
server.tool(
|
|
147
|
+
"get_visible_text_elements",
|
|
148
|
+
"Get all visible texts from screen XML including duplicates",
|
|
149
|
+
{},
|
|
150
|
+
async () => {
|
|
151
|
+
if (!state.sessionId) return { content: [{ type: "text", text: "No active session" }] };
|
|
152
|
+
try {
|
|
153
|
+
const response = await axios.get(`${APPIUM_URL}/session/${state.sessionId}/source`);
|
|
154
|
+
const xml = response.data;
|
|
155
|
+
|
|
156
|
+
const parsed = await parseStringPromise(xml, { explicitArray: false, mergeAttrs: true });
|
|
157
|
+
|
|
158
|
+
function collectTexts(node, texts = []) {
|
|
159
|
+
if (!node) return texts;
|
|
160
|
+
|
|
161
|
+
if (Array.isArray(node)) {
|
|
162
|
+
node.forEach(child => collectTexts(child, texts));
|
|
163
|
+
return texts;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (node.text && node.text.trim() !== "") {
|
|
167
|
+
texts.push(node.text.trim());
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (node.node) collectTexts(node.node, texts);
|
|
171
|
+
else if (node.child) collectTexts(node.child, texts);
|
|
172
|
+
else {
|
|
173
|
+
for (const key in node) {
|
|
174
|
+
if (typeof node[key] === "object") {
|
|
175
|
+
collectTexts(node[key], texts);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return texts;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const allTexts = collectTexts(parsed);
|
|
183
|
+
return { content: [{ type: "json", json: allTexts }] };
|
|
184
|
+
} catch (e) {
|
|
185
|
+
return { content: [{ type: "text", text: `Error fetching or parsing XML: ${e.message}` }] };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// Click element by text with optional index (default 0)
|
|
191
|
+
server.tool(
|
|
192
|
+
"click_by_text",
|
|
193
|
+
"Click element by visible text with optional index",
|
|
194
|
+
{
|
|
195
|
+
text: z.string(),
|
|
196
|
+
index: z.number().optional().default(0),
|
|
197
|
+
},
|
|
198
|
+
async ({ text, index }) => {
|
|
199
|
+
if (!state.sessionId) return { content: [{ type: "text", text: "No active session" }] };
|
|
200
|
+
try {
|
|
201
|
+
const xpath = `(//*[normalize-space(@text)='${text}'])[${index + 1}]`;
|
|
202
|
+
const findResp = await axios.post(`${APPIUM_URL}/session/${state.sessionId}/element`, { using: "xpath", value: xpath });
|
|
203
|
+
const elementId = extractElementId(findResp.data.value);
|
|
204
|
+
await axios.post(`${APPIUM_URL}/session/${state.sessionId}/element/${elementId}/click`);
|
|
205
|
+
return { content: [{ type: "text", text: `Clicked element with text: "${text}" at index ${index}` }] };
|
|
206
|
+
} catch (e) {
|
|
207
|
+
return { content: [{ type: "text", text: `Error clicking element: ${e.message}` }] };
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
);
|
|
145
211
|
|
|
146
212
|
|
|
147
213
|
|