deep_link
Open any URL or deep link in a mobile app on iOS and Android to verify navigation and functionality.
Instructions
Ouvre une URL ou un deep link dans l'app (ex: myapp://profile, https://example.com). Fonctionne sur iOS et Android.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL ou deep link à ouvrir (ex: myapp://home, https://example.com/page) |
Implementation Reference
- src/tools/deep-link.ts:16-48 (handler)The registerDeepLink function registers the 'deep_link' tool on the MCP server. The handler resolves the active device, validates the URL format, then dispatches to iosOpenUrl (via simctl) or androidOpenUrl (via adb) based on platform. Results are logged and returned as text content.
export function registerDeepLink(server: McpServer): void { server.tool( "deep_link", "Ouvre une URL ou un deep link dans l'app (ex: myapp://profile, https://example.com). Fonctionne sur iOS et Android.", { url: z.string().describe("URL ou deep link à ouvrir (ex: myapp://home, https://example.com/page)"), }, async ({ url }) => { const result = await resolveDevice(); if ("error" in result) return { content: [{ type: "text", text: result.error }], isError: true }; const dev = result.device; try { validateUrl(url); if (dev.platform === "ios") { await iosOpenUrl(dev.id, url); } else { await androidOpenUrl(url); } const platform = dev.platform === "ios" ? "🍎" : "🤖"; const successMsg = `${platform} URL ouverte : ${url}`; logAction("deep_link", successMsg, false, dev.platform, dev.id, dev.name); return { content: [{ type: "text", text: successMsg }] }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); logAction("deep_link", `Erreur: ${msg}`, true, dev.platform, dev.id, dev.name); return { content: [{ type: "text", text: `Erreur deep_link: ${msg}` }], isError: true }; } } ); } - src/tools/deep-link.ts:8-14 (schema)URL validation: regex check (scheme://path format), max length 2048 chars, and control character rejection. Used by the handler before dispatching to platform tools.
const URL_REGEX = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/\S+$/; function validateUrl(url: string): void { if (url.length > 2048) throw new Error("URL trop longue (max 2048 caractères)."); if (/[\x00-\x1F\x7F]/.test(url)) throw new Error("URL contient des caractères de contrôle invalides."); if (!URL_REGEX.test(url)) throw new Error(`URL invalide : "${url}". Format attendu : scheme://path (ex: https://example.com, myapp://home)`); } - src/platforms/ios/simctl.ts:164-169 (helper)iOS implementation: runs 'xcrun simctl openurl <udid> <url>' to open a deep link on an iOS simulator. Validates UDID and URL before execution.
export async function iosOpenUrl(deviceUdid: string, url: string): Promise<void> { validateUdid(deviceUdid); if (/[\x00-\x1F\x7F]/.test(url)) throw new Error("URL contient des caractères de contrôle."); if (url.startsWith("-")) throw new Error("URL invalide : ne peut pas commencer par \"-\"."); await simctl(["openurl", deviceUdid, url]); } - src/platforms/android/adb.ts:375-380 (helper)Android implementation: uses 'adb shell am start -a android.intent.action.VIEW -d <url>' to open a deep link. Validates URL to prevent intent flag injection.
export async function androidOpenUrl(url: string): Promise<void> { // Validate URL to prevent intent flag injection (url starting with "-" would be parsed as a flag by am) if (url.startsWith("-")) throw new Error(`URL invalide : ne peut pas commencer par "-".`); if (/[\x00-\x1F\x7F]/.test(url)) throw new Error("URL contient des caractères de contrôle."); await adb(["shell", "am", "start", "-a", "android.intent.action.VIEW", "-d", url]); } - src/index.ts:54-55 (registration)Tool registration: registerDeepLink(server) is called in the Navigation section of the main server setup, importing from ./tools/deep-link.js.
// Navigation registerDeepLink(server);