react-native-mcp-kit 1.0.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.
Files changed (271) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +868 -0
  3. package/dist/babel/index.d.ts +3 -0
  4. package/dist/babel/index.d.ts.map +1 -0
  5. package/dist/babel/index.js +11 -0
  6. package/dist/babel/index.js.map +1 -0
  7. package/dist/babel/stripPlugin.d.ts +5 -0
  8. package/dist/babel/stripPlugin.d.ts.map +1 -0
  9. package/dist/babel/stripPlugin.js +100 -0
  10. package/dist/babel/stripPlugin.js.map +1 -0
  11. package/dist/babel/testIdPlugin.d.ts +5 -0
  12. package/dist/babel/testIdPlugin.d.ts.map +1 -0
  13. package/dist/babel/testIdPlugin.js +69 -0
  14. package/dist/babel/testIdPlugin.js.map +1 -0
  15. package/dist/client/contexts/McpContext/McpContext.d.ts +3 -0
  16. package/dist/client/contexts/McpContext/McpContext.d.ts.map +1 -0
  17. package/dist/client/contexts/McpContext/McpContext.js +6 -0
  18. package/dist/client/contexts/McpContext/McpContext.js.map +1 -0
  19. package/dist/client/contexts/McpContext/McpProvider.d.ts +3 -0
  20. package/dist/client/contexts/McpContext/McpProvider.d.ts.map +1 -0
  21. package/dist/client/contexts/McpContext/McpProvider.js +28 -0
  22. package/dist/client/contexts/McpContext/McpProvider.js.map +1 -0
  23. package/dist/client/contexts/McpContext/index.d.ts +4 -0
  24. package/dist/client/contexts/McpContext/index.d.ts.map +1 -0
  25. package/dist/client/contexts/McpContext/index.js +8 -0
  26. package/dist/client/contexts/McpContext/index.js.map +1 -0
  27. package/dist/client/contexts/McpContext/types.d.ts +12 -0
  28. package/dist/client/contexts/McpContext/types.d.ts.map +1 -0
  29. package/dist/client/contexts/McpContext/types.js +3 -0
  30. package/dist/client/contexts/McpContext/types.js.map +1 -0
  31. package/dist/client/contexts/McpTreeContext/McpTracker.d.ts +10 -0
  32. package/dist/client/contexts/McpTreeContext/McpTracker.d.ts.map +1 -0
  33. package/dist/client/contexts/McpTreeContext/McpTracker.js +101 -0
  34. package/dist/client/contexts/McpTreeContext/McpTracker.js.map +1 -0
  35. package/dist/client/contexts/McpTreeContext/McpTreeContext.d.ts +2 -0
  36. package/dist/client/contexts/McpTreeContext/McpTreeContext.d.ts.map +1 -0
  37. package/dist/client/contexts/McpTreeContext/McpTreeContext.js +6 -0
  38. package/dist/client/contexts/McpTreeContext/McpTreeContext.js.map +1 -0
  39. package/dist/client/contexts/McpTreeContext/McpTreeRegistry.d.ts +16 -0
  40. package/dist/client/contexts/McpTreeContext/McpTreeRegistry.d.ts.map +1 -0
  41. package/dist/client/contexts/McpTreeContext/McpTreeRegistry.js +96 -0
  42. package/dist/client/contexts/McpTreeContext/McpTreeRegistry.js.map +1 -0
  43. package/dist/client/contexts/McpTreeContext/index.d.ts +5 -0
  44. package/dist/client/contexts/McpTreeContext/index.d.ts.map +1 -0
  45. package/dist/client/contexts/McpTreeContext/index.js +10 -0
  46. package/dist/client/contexts/McpTreeContext/index.js.map +1 -0
  47. package/dist/client/contexts/McpTreeContext/types.d.ts +14 -0
  48. package/dist/client/contexts/McpTreeContext/types.d.ts.map +1 -0
  49. package/dist/client/contexts/McpTreeContext/types.js +3 -0
  50. package/dist/client/contexts/McpTreeContext/types.js.map +1 -0
  51. package/dist/client/core/McpClient.d.ts +25 -0
  52. package/dist/client/core/McpClient.d.ts.map +1 -0
  53. package/dist/client/core/McpClient.js +183 -0
  54. package/dist/client/core/McpClient.js.map +1 -0
  55. package/dist/client/hooks/useMcpModule.d.ts +4 -0
  56. package/dist/client/hooks/useMcpModule.d.ts.map +1 -0
  57. package/dist/client/hooks/useMcpModule.js +17 -0
  58. package/dist/client/hooks/useMcpModule.js.map +1 -0
  59. package/dist/client/hooks/useMcpState.d.ts +3 -0
  60. package/dist/client/hooks/useMcpState.d.ts.map +1 -0
  61. package/dist/client/hooks/useMcpState.js +20 -0
  62. package/dist/client/hooks/useMcpState.js.map +1 -0
  63. package/dist/client/hooks/useMcpTool.d.ts +4 -0
  64. package/dist/client/hooks/useMcpTool.d.ts.map +1 -0
  65. package/dist/client/hooks/useMcpTool.js +20 -0
  66. package/dist/client/hooks/useMcpTool.js.map +1 -0
  67. package/dist/client/index.d.ts +8 -0
  68. package/dist/client/index.d.ts.map +1 -0
  69. package/dist/client/index.js +15 -0
  70. package/dist/client/index.js.map +1 -0
  71. package/dist/client/models/types.d.ts +12 -0
  72. package/dist/client/models/types.d.ts.map +1 -0
  73. package/dist/client/models/types.js +3 -0
  74. package/dist/client/models/types.js.map +1 -0
  75. package/dist/client/utils/connection.d.ts +17 -0
  76. package/dist/client/utils/connection.d.ts.map +1 -0
  77. package/dist/client/utils/connection.js +71 -0
  78. package/dist/client/utils/connection.js.map +1 -0
  79. package/dist/client/utils/moduleRunner.d.ts +13 -0
  80. package/dist/client/utils/moduleRunner.d.ts.map +1 -0
  81. package/dist/client/utils/moduleRunner.js +59 -0
  82. package/dist/client/utils/moduleRunner.js.map +1 -0
  83. package/dist/index.d.ts +5 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +25 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/modules/alert/alert.d.ts +3 -0
  88. package/dist/modules/alert/alert.d.ts.map +1 -0
  89. package/dist/modules/alert/alert.js +50 -0
  90. package/dist/modules/alert/alert.js.map +1 -0
  91. package/dist/modules/alert/index.d.ts +2 -0
  92. package/dist/modules/alert/index.d.ts.map +1 -0
  93. package/dist/modules/alert/index.js +6 -0
  94. package/dist/modules/alert/index.js.map +1 -0
  95. package/dist/modules/components/components.d.ts +8 -0
  96. package/dist/modules/components/components.d.ts.map +1 -0
  97. package/dist/modules/components/components.js +315 -0
  98. package/dist/modules/components/components.js.map +1 -0
  99. package/dist/modules/components/index.d.ts +3 -0
  100. package/dist/modules/components/index.d.ts.map +1 -0
  101. package/dist/modules/components/index.js +6 -0
  102. package/dist/modules/components/index.js.map +1 -0
  103. package/dist/modules/components/types.d.ts +18 -0
  104. package/dist/modules/components/types.d.ts.map +1 -0
  105. package/dist/modules/components/types.js +3 -0
  106. package/dist/modules/components/types.js.map +1 -0
  107. package/dist/modules/components/utils.d.ts +18 -0
  108. package/dist/modules/components/utils.d.ts.map +1 -0
  109. package/dist/modules/components/utils.js +386 -0
  110. package/dist/modules/components/utils.js.map +1 -0
  111. package/dist/modules/console/console.d.ts +4 -0
  112. package/dist/modules/console/console.d.ts.map +1 -0
  113. package/dist/modules/console/console.js +176 -0
  114. package/dist/modules/console/console.js.map +1 -0
  115. package/dist/modules/console/index.d.ts +3 -0
  116. package/dist/modules/console/index.d.ts.map +1 -0
  117. package/dist/modules/console/index.js +6 -0
  118. package/dist/modules/console/index.js.map +1 -0
  119. package/dist/modules/console/types.d.ts +13 -0
  120. package/dist/modules/console/types.d.ts.map +1 -0
  121. package/dist/modules/console/types.js +3 -0
  122. package/dist/modules/console/types.js.map +1 -0
  123. package/dist/modules/device/device.d.ts +3 -0
  124. package/dist/modules/device/device.d.ts.map +1 -0
  125. package/dist/modules/device/device.js +182 -0
  126. package/dist/modules/device/device.js.map +1 -0
  127. package/dist/modules/device/index.d.ts +3 -0
  128. package/dist/modules/device/index.d.ts.map +1 -0
  129. package/dist/modules/device/index.js +6 -0
  130. package/dist/modules/device/index.js.map +1 -0
  131. package/dist/modules/device/types.d.ts +24 -0
  132. package/dist/modules/device/types.d.ts.map +1 -0
  133. package/dist/modules/device/types.js +3 -0
  134. package/dist/modules/device/types.js.map +1 -0
  135. package/dist/modules/errors/errors.d.ts +4 -0
  136. package/dist/modules/errors/errors.d.ts.map +1 -0
  137. package/dist/modules/errors/errors.js +133 -0
  138. package/dist/modules/errors/errors.js.map +1 -0
  139. package/dist/modules/errors/index.d.ts +3 -0
  140. package/dist/modules/errors/index.d.ts.map +1 -0
  141. package/dist/modules/errors/index.js +6 -0
  142. package/dist/modules/errors/index.js.map +1 -0
  143. package/dist/modules/errors/types.d.ts +12 -0
  144. package/dist/modules/errors/types.d.ts.map +1 -0
  145. package/dist/modules/errors/types.js +3 -0
  146. package/dist/modules/errors/types.js.map +1 -0
  147. package/dist/modules/fiberTree/fiberTree.d.ts +8 -0
  148. package/dist/modules/fiberTree/fiberTree.d.ts.map +1 -0
  149. package/dist/modules/fiberTree/fiberTree.js +337 -0
  150. package/dist/modules/fiberTree/fiberTree.js.map +1 -0
  151. package/dist/modules/fiberTree/index.d.ts +3 -0
  152. package/dist/modules/fiberTree/index.d.ts.map +1 -0
  153. package/dist/modules/fiberTree/index.js +6 -0
  154. package/dist/modules/fiberTree/index.js.map +1 -0
  155. package/dist/modules/fiberTree/types.d.ts +18 -0
  156. package/dist/modules/fiberTree/types.d.ts.map +1 -0
  157. package/dist/modules/fiberTree/types.js +3 -0
  158. package/dist/modules/fiberTree/types.js.map +1 -0
  159. package/dist/modules/fiberTree/utils.d.ts +18 -0
  160. package/dist/modules/fiberTree/utils.d.ts.map +1 -0
  161. package/dist/modules/fiberTree/utils.js +386 -0
  162. package/dist/modules/fiberTree/utils.js.map +1 -0
  163. package/dist/modules/i18next/i18next.d.ts +4 -0
  164. package/dist/modules/i18next/i18next.d.ts.map +1 -0
  165. package/dist/modules/i18next/i18next.js +133 -0
  166. package/dist/modules/i18next/i18next.js.map +1 -0
  167. package/dist/modules/i18next/index.d.ts +3 -0
  168. package/dist/modules/i18next/index.d.ts.map +1 -0
  169. package/dist/modules/i18next/index.js +6 -0
  170. package/dist/modules/i18next/index.js.map +1 -0
  171. package/dist/modules/i18next/types.d.ts +12 -0
  172. package/dist/modules/i18next/types.d.ts.map +1 -0
  173. package/dist/modules/i18next/types.js +3 -0
  174. package/dist/modules/i18next/types.js.map +1 -0
  175. package/dist/modules/index.d.ts +12 -0
  176. package/dist/modules/index.d.ts.map +1 -0
  177. package/dist/modules/index.js +26 -0
  178. package/dist/modules/index.js.map +1 -0
  179. package/dist/modules/navigation/index.d.ts +3 -0
  180. package/dist/modules/navigation/index.d.ts.map +1 -0
  181. package/dist/modules/navigation/index.js +6 -0
  182. package/dist/modules/navigation/index.js.map +1 -0
  183. package/dist/modules/navigation/navigation.d.ts +4 -0
  184. package/dist/modules/navigation/navigation.d.ts.map +1 -0
  185. package/dist/modules/navigation/navigation.js +240 -0
  186. package/dist/modules/navigation/navigation.js.map +1 -0
  187. package/dist/modules/navigation/types.d.ts +34 -0
  188. package/dist/modules/navigation/types.d.ts.map +1 -0
  189. package/dist/modules/navigation/types.js +3 -0
  190. package/dist/modules/navigation/types.js.map +1 -0
  191. package/dist/modules/network/index.d.ts +3 -0
  192. package/dist/modules/network/index.d.ts.map +1 -0
  193. package/dist/modules/network/index.js +6 -0
  194. package/dist/modules/network/index.js.map +1 -0
  195. package/dist/modules/network/network.d.ts +4 -0
  196. package/dist/modules/network/network.d.ts.map +1 -0
  197. package/dist/modules/network/network.js +276 -0
  198. package/dist/modules/network/network.js.map +1 -0
  199. package/dist/modules/network/types.d.ts +26 -0
  200. package/dist/modules/network/types.d.ts.map +1 -0
  201. package/dist/modules/network/types.js +3 -0
  202. package/dist/modules/network/types.js.map +1 -0
  203. package/dist/modules/reactQuery/index.d.ts +3 -0
  204. package/dist/modules/reactQuery/index.d.ts.map +1 -0
  205. package/dist/modules/reactQuery/index.js +6 -0
  206. package/dist/modules/reactQuery/index.js.map +1 -0
  207. package/dist/modules/reactQuery/reactQuery.d.ts +4 -0
  208. package/dist/modules/reactQuery/reactQuery.d.ts.map +1 -0
  209. package/dist/modules/reactQuery/reactQuery.js +160 -0
  210. package/dist/modules/reactQuery/reactQuery.js.map +1 -0
  211. package/dist/modules/reactQuery/types.d.ts +29 -0
  212. package/dist/modules/reactQuery/types.d.ts.map +1 -0
  213. package/dist/modules/reactQuery/types.js +3 -0
  214. package/dist/modules/reactQuery/types.js.map +1 -0
  215. package/dist/modules/screenshot/index.d.ts +3 -0
  216. package/dist/modules/screenshot/index.d.ts.map +1 -0
  217. package/dist/modules/screenshot/index.js +6 -0
  218. package/dist/modules/screenshot/index.js.map +1 -0
  219. package/dist/modules/screenshot/screenshot.d.ts +4 -0
  220. package/dist/modules/screenshot/screenshot.d.ts.map +1 -0
  221. package/dist/modules/screenshot/screenshot.js +89 -0
  222. package/dist/modules/screenshot/screenshot.js.map +1 -0
  223. package/dist/modules/screenshot/types.d.ts +5 -0
  224. package/dist/modules/screenshot/types.d.ts.map +1 -0
  225. package/dist/modules/screenshot/types.js +3 -0
  226. package/dist/modules/screenshot/types.js.map +1 -0
  227. package/dist/modules/storage/index.d.ts +3 -0
  228. package/dist/modules/storage/index.d.ts.map +1 -0
  229. package/dist/modules/storage/index.js +6 -0
  230. package/dist/modules/storage/index.js.map +1 -0
  231. package/dist/modules/storage/storage.d.ts +4 -0
  232. package/dist/modules/storage/storage.d.ts.map +1 -0
  233. package/dist/modules/storage/storage.js +124 -0
  234. package/dist/modules/storage/storage.js.map +1 -0
  235. package/dist/modules/storage/types.d.ts +11 -0
  236. package/dist/modules/storage/types.d.ts.map +1 -0
  237. package/dist/modules/storage/types.js +3 -0
  238. package/dist/modules/storage/types.js.map +1 -0
  239. package/dist/modules/tree/index.d.ts +2 -0
  240. package/dist/modules/tree/index.d.ts.map +1 -0
  241. package/dist/modules/tree/index.js +6 -0
  242. package/dist/modules/tree/index.js.map +1 -0
  243. package/dist/modules/tree/tree.d.ts +3 -0
  244. package/dist/modules/tree/tree.d.ts.map +1 -0
  245. package/dist/modules/tree/tree.js +274 -0
  246. package/dist/modules/tree/tree.js.map +1 -0
  247. package/dist/server/bridge.d.ts +24 -0
  248. package/dist/server/bridge.d.ts.map +1 -0
  249. package/dist/server/bridge.js +152 -0
  250. package/dist/server/bridge.js.map +1 -0
  251. package/dist/server/cli.d.ts +3 -0
  252. package/dist/server/cli.d.ts.map +1 -0
  253. package/dist/server/cli.js +17 -0
  254. package/dist/server/cli.js.map +1 -0
  255. package/dist/server/index.d.ts +4 -0
  256. package/dist/server/index.d.ts.map +1 -0
  257. package/dist/server/index.js +30 -0
  258. package/dist/server/index.js.map +1 -0
  259. package/dist/server/mcpServer.d.ts +19 -0
  260. package/dist/server/mcpServer.d.ts.map +1 -0
  261. package/dist/server/mcpServer.js +303 -0
  262. package/dist/server/mcpServer.js.map +1 -0
  263. package/dist/server/types.d.ts +12 -0
  264. package/dist/server/types.d.ts.map +1 -0
  265. package/dist/server/types.js +3 -0
  266. package/dist/server/types.js.map +1 -0
  267. package/dist/shared/protocol.d.ts +54 -0
  268. package/dist/shared/protocol.d.ts.map +1 -0
  269. package/dist/shared/protocol.js +8 -0
  270. package/dist/shared/protocol.js.map +1 -0
  271. package/package.json +95 -0
package/README.md ADDED
@@ -0,0 +1,868 @@
1
+ # react-native-mcp-kit
2
+
3
+ A bidirectional [MCP](https://modelcontextprotocol.io/) bridge that connects AI agents to running React Native apps. The server is a proxy — all business logic runs inside your RN app.
4
+
5
+ ```
6
+ AI Agent --stdio/MCP--> MCP Server (Node.js) --WebSocket--> RN App (device)
7
+ ```
8
+
9
+ ## Table of Contents
10
+
11
+ - [Features](#features)
12
+ - [Quick Start](#quick-start)
13
+ - [Modules](#modules)
14
+ - [alert](#alert)
15
+ - [fiberTree](#fibertree)
16
+ - [console](#console)
17
+ - [device](#device)
18
+ - [errors](#errors)
19
+ - [i18next](#i18next)
20
+ - [navigation](#navigation)
21
+ - [network](#network)
22
+ - [reactQuery](#reactquery)
23
+ - [screenshot](#screenshot)
24
+ - [storage](#storage)
25
+ - [Hooks](#hooks)
26
+ - [useMcpState](#usemcpstate)
27
+ - [useMcpTool](#usemcptool)
28
+ - [useMcpModule](#usemcpmodule)
29
+ - [Babel Plugins](#babel-plugins)
30
+ - [testIdPlugin](#testidplugin)
31
+ - [stripPlugin](#stripplugin)
32
+ - [Dev vs Production](#dev-vs-production)
33
+ - [MCP Server Tools](#mcp-server-tools)
34
+ - [Custom Modules](#custom-modules)
35
+ - [Debug Logging](#debug-logging)
36
+ - [API Reference](#api-reference)
37
+
38
+ ## Features
39
+
40
+ - **11 built-in modules** — navigation, fiber tree, screenshot, network, console, storage, device, errors, i18next, React Query, alerts
41
+ - **React fiber inspection** — walk the component tree, read props, invoke callbacks, call ref methods
42
+ - **Screenshots** — capture app screenshots via `@shopify/react-native-skia` with resize and JPEG compression
43
+ - **Developer hooks** — expose state and tools from any component with `useMcpState` and `useMcpTool`
44
+ - **Navigation history** — full log of screen transitions with timestamps and slice access
45
+ - **Modular** — register only the modules you need, or write your own with `description` for AI context
46
+ - **Zero production overhead** — Babel strip plugin removes all MCP code from prod builds
47
+ - **Babel testID plugin** — auto-adds `data-mcp-id` attributes for component identification
48
+
49
+ ## Quick Start
50
+
51
+ ### 1. Install
52
+
53
+ ```bash
54
+ yarn add react-native-mcp-kit
55
+ # or
56
+ npm install react-native-mcp-kit
57
+ ```
58
+
59
+ ### 2. Initialize in your app
60
+
61
+ ```typescript
62
+ import {
63
+ McpClient,
64
+ McpProvider,
65
+ consoleModule,
66
+ deviceModule,
67
+ fiberTreeModule,
68
+ navigationModule,
69
+ networkModule,
70
+ screenshotModule,
71
+ } from 'react-native-mcp-kit';
72
+ import { createRef } from 'react';
73
+ import { View } from 'react-native';
74
+
75
+ const rootRef = createRef<View>();
76
+ const navigationRef = createNavigationContainerRef();
77
+
78
+ // Initialize client (call once, before any module registration)
79
+ const client = McpClient.initialize({ debug: true });
80
+
81
+ // Register modules
82
+ client.registerModules([
83
+ consoleModule(),
84
+ deviceModule(),
85
+ fiberTreeModule({ rootRef }),
86
+ navigationModule(navigationRef),
87
+ networkModule(),
88
+ screenshotModule({ rootRef }),
89
+ ]);
90
+ ```
91
+
92
+ ### 3. Wrap your app with McpProvider
93
+
94
+ ```tsx
95
+ const App = () => {
96
+ return (
97
+ <View ref={rootRef} collapsable={false} style={{ flex: 1 }}>
98
+ <NavigationContainer ref={navigationRef}>
99
+ <McpProvider>{/* your app */}</McpProvider>
100
+ </NavigationContainer>
101
+ </View>
102
+ );
103
+ };
104
+ ```
105
+
106
+ ### 4. Configure the MCP server
107
+
108
+ Add to your project's `.mcp.json`:
109
+
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "react-native-mcp-kit": {
114
+ "command": "npx",
115
+ "args": ["react-native-mcp-kit"]
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ Or with a custom port:
122
+
123
+ ```json
124
+ {
125
+ "mcpServers": {
126
+ "react-native-mcp-kit": {
127
+ "command": "npx",
128
+ "args": ["react-native-mcp-kit", "--port", "8347"]
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ ### 5. Connect
135
+
136
+ 1. Start Metro and run your app
137
+ 2. The AI agent connects via MCP and can now inspect and interact with your app
138
+ 3. For Android emulator, run `adb reverse tcp:8347 tcp:8347` to forward the port
139
+
140
+ ## Modules
141
+
142
+ | Module | Factory | Description |
143
+ | ------------------------- | ------------------------------- | --------------------------------------------------------------- |
144
+ | [alert](#alert) | `alertModule()` | Show native alerts with custom buttons and styles |
145
+ | [fiberTree](#fibertree) | `fiberTreeModule({ rootRef })` | React fiber tree inspection, invoke callbacks, call ref methods |
146
+ | [console](#console) | `consoleModule(options?)` | Capture console.log/warn/error/info/debug |
147
+ | [device](#device) | `deviceModule()` | Device info, app state, keyboard, linking, reload |
148
+ | [errors](#errors) | `errorsModule(options?)` | Capture unhandled errors and promise rejections |
149
+ | [i18next](#i18next) | `i18nextModule(i18n)` | Translation inspection and language management |
150
+ | [navigation](#navigation) | `navigationModule(ref)` | Navigation state, history, navigate, push, pop, replace, reset |
151
+ | [network](#network) | `networkModule(options?)` | HTTP request/response interception |
152
+ | [reactQuery](#reactquery) | `reactQueryModule(queryClient)` | React Query cache inspection and management |
153
+ | [screenshot](#screenshot) | `screenshotModule({ rootRef })` | Capture screenshots via Skia |
154
+ | [storage](#storage) | `storageModule(...storages)` | Key-value storage inspection (MMKV, AsyncStorage, custom) |
155
+
156
+ ---
157
+
158
+ ### alert
159
+
160
+ Show native alert dialogs with custom buttons and styles.
161
+
162
+ ```typescript
163
+ client.registerModules([alertModule()]);
164
+ ```
165
+
166
+ | Tool | Description | Args |
167
+ | ------ | ----------------- | ---------------------------------------------------------- |
168
+ | `show` | Show alert dialog | `title?: string`, `message?: string`, `buttons?: Button[]` |
169
+
170
+ Buttons can be strings or objects with style:
171
+
172
+ ```typescript
173
+ // Simple
174
+ call(tool: "alert__show", args: '{"title": "Confirm", "buttons": ["Cancel", "OK"]}')
175
+
176
+ // With styles
177
+ call(tool: "alert__show", args: '{"title": "Delete?", "buttons": [{"text": "Cancel", "style": "cancel"}, {"text": "Delete", "style": "destructive"}]}')
178
+ ```
179
+
180
+ Button styles: `default`, `cancel`, `destructive`. Returns `{ button: string, index: number }`. Timeout: 60s.
181
+
182
+ ---
183
+
184
+ ### fiberTree
185
+
186
+ React fiber tree inspection with the ability to invoke callbacks and call ref methods.
187
+
188
+ ```typescript
189
+ client.registerModules([fiberTreeModule({ rootRef })]);
190
+ ```
191
+
192
+ **Inspection tools:**
193
+
194
+ | Tool | Description | Args |
195
+ | --------------- | ---------------------------- | -------------------------------------------------------------------- |
196
+ | `get_tree` | Get full component tree | `depth?: number` (default: 10) |
197
+ | `get_component` | Find a component | `name?`, `testID?`, `text?`, `mcpId?`, `within?`, `index?`, `depth?` |
198
+ | `find_all` | Find all matching components | `name?`, `testID?`, `text?`, `mcpId?`, `hasProps?`, `within?` |
199
+ | `get_props` | Get component props | same find params |
200
+ | `get_children` | Get component children | same find params, `depth?` |
201
+
202
+ **Interaction tools:**
203
+
204
+ | Tool | Description | Args |
205
+ | ----------------- | -------------------------- | --------------------------------------------------- |
206
+ | `invoke` | Call any callback prop | find params, `callback: string`, `args?: unknown[]` |
207
+ | `call_ref` | Call method on native ref | find params, `method: string`, `args?: unknown[]` |
208
+ | `get_ref_methods` | List available ref methods | find params |
209
+
210
+ **Finding components:**
211
+
212
+ Components can be found by `testID`, `name`, `text`, or `mcpId` (from the Babel testID plugin). Use `within` to scope the search to children of a specific component:
213
+
214
+ ```typescript
215
+ // Find by testID
216
+ call(tool: "fiber_tree__get_component", args: '{"testID": "login-button"}')
217
+
218
+ // Find by name within a parent
219
+ call(tool: "fiber_tree__get_component", args: '{"name": "Pressable", "within": "LoginForm"}')
220
+
221
+ // Use index for multiple matches (0-based)
222
+ call(tool: "fiber_tree__get_component", args: '{"name": "TextInput", "within": "LoginForm", "index": 1}')
223
+
224
+ // Nested within path with index
225
+ call(tool: "fiber_tree__get_component", args: '{"name": "Text", "within": "Button:1/Pressable"}')
226
+ ```
227
+
228
+ **Invoking callbacks:**
229
+
230
+ ```typescript
231
+ // Press a button
232
+ call(tool: "fiber_tree__invoke", args: '{"testID": "submit-btn", "callback": "onPress"}')
233
+
234
+ // Type text
235
+ call(tool: "fiber_tree__invoke", args: '{"mcpId": "Input:screens/Login:42", "callback": "onChangeText", "args": ["user@example.com"]}')
236
+
237
+ // Toggle checkbox with custom args
238
+ call(tool: "fiber_tree__invoke", args: '{"name": "Checkbox", "within": "TermsForm", "callback": "onPress", "args": [true]}')
239
+ ```
240
+
241
+ **Calling ref methods:**
242
+
243
+ ```typescript
244
+ // Focus an input
245
+ call(tool: "fiber_tree__call_ref", args: '{"testID": "email-input", "method": "focus"}')
246
+
247
+ // List available methods
248
+ call(tool: "fiber_tree__get_ref_methods", args: '{"testID": "email-input"}')
249
+ ```
250
+
251
+ ---
252
+
253
+ ### console
254
+
255
+ Intercepts console output with a ring buffer.
256
+
257
+ ```typescript
258
+ client.registerModules([consoleModule()]);
259
+
260
+ // With options
261
+ client.registerModules([
262
+ consoleModule({
263
+ maxEntries: 200,
264
+ levels: ['error', 'warn', 'log'],
265
+ stackTrace: ['error', 'warn'], // or true for all levels
266
+ }),
267
+ ]);
268
+ ```
269
+
270
+ | Tool | Description | Args |
271
+ | -------------- | ---------------- | ---------------------------------- |
272
+ | `get_logs` | Get all logs | `level?: string`, `limit?: number` |
273
+ | `get_errors` | Get error logs | `limit?: number` |
274
+ | `get_warnings` | Get warning logs | `limit?: number` |
275
+ | `get_info` | Get info logs | `limit?: number` |
276
+ | `get_debug` | Get debug logs | `limit?: number` |
277
+ | `clear_logs` | Clear all logs | — |
278
+
279
+ Serializes complex values: functions, class instances, circular refs, Errors, Dates, RegExp, Symbols.
280
+
281
+ ---
282
+
283
+ ### device
284
+
285
+ Device info and system APIs.
286
+
287
+ ```typescript
288
+ client.registerModules([deviceModule()]);
289
+ ```
290
+
291
+ | Tool | Description | Args |
292
+ | ------------------------ | ----------------------------------------------------------------------------------- | ------------------- |
293
+ | `get_device_info` | Comprehensive device info (platform, dimensions, pixel ratio, appearance, dev mode) | — |
294
+ | `get_platform` | Platform (OS, version, constants) | — |
295
+ | `get_dimensions` | Screen and window dimensions | — |
296
+ | `get_pixel_ratio` | Pixel density and font scale | — |
297
+ | `get_appearance` | Color scheme (light/dark) | — |
298
+ | `get_app_state` | App state (active/background/inactive) | — |
299
+ | `get_accessibility_info` | Accessibility settings | — |
300
+ | `get_keyboard_state` | Keyboard visibility and metrics | — |
301
+ | `dismiss_keyboard` | Dismiss keyboard | — |
302
+ | `open_url` | Open URL in appropriate app | `url: string` |
303
+ | `can_open_url` | Check if URL can be opened | `url: string` |
304
+ | `get_initial_url` | Get deep link that launched app | — |
305
+ | `open_settings` | Open app settings | — |
306
+ | `reload` | Reload app (dev only) | — |
307
+ | `vibrate` | Vibrate device | `duration?: number` |
308
+
309
+ ---
310
+
311
+ ### errors
312
+
313
+ Captures unhandled JS errors and promise rejections.
314
+
315
+ ```typescript
316
+ client.registerModules([errorsModule()]);
317
+
318
+ // With options
319
+ client.registerModules([errorsModule({ maxEntries: 100 })]);
320
+ ```
321
+
322
+ | Tool | Description | Args |
323
+ | -------------- | --------------------- | ------------------------------------------------------ |
324
+ | `get_errors` | Get captured errors | `source?: string`, `fatal?: boolean`, `limit?: number` |
325
+ | `get_fatal` | Get fatal errors only | `limit?: number` |
326
+ | `get_stats` | Error statistics | — |
327
+ | `clear_errors` | Clear all errors | — |
328
+
329
+ Error sources: `global` (ErrorUtils), `promise` (unhandled rejections). Deduplicates within 100ms window.
330
+
331
+ ---
332
+
333
+ ### i18next
334
+
335
+ Translation inspection and language management. Accepts an i18next instance.
336
+
337
+ ```typescript
338
+ import i18n from './i18n';
339
+
340
+ client.registerModules([i18nextModule(i18n)]);
341
+ ```
342
+
343
+ | Tool | Description | Args |
344
+ | ----------------- | ------------------------------------------------- | ---------------------------------------- |
345
+ | `get_info` | Current language, available languages, namespaces | — |
346
+ | `get_resource` | Get full translation resource | `language?`, `namespace?` |
347
+ | `get_keys` | List translation keys | `language?`, `namespace?` |
348
+ | `translate` | Translate a key | `key: string`, `options?: string` (JSON) |
349
+ | `search` | Search keys and values | `query: string`, `language?` |
350
+ | `change_language` | Change current language | `language: string` |
351
+
352
+ ```typescript
353
+ // Translate with interpolation
354
+ call(tool: "i18n__translate", args: '{"key": "welcome", "options": "{\"name\": \"John\"}"}')
355
+
356
+ // Search translations
357
+ call(tool: "i18n__search", args: '{"query": "password"}')
358
+ ```
359
+
360
+ ---
361
+
362
+ ### navigation
363
+
364
+ Full navigation control with history tracking. Accepts a React Navigation ref.
365
+
366
+ ```typescript
367
+ import { createNavigationContainerRef } from '@react-navigation/native';
368
+
369
+ const navigationRef = createNavigationContainerRef();
370
+
371
+ client.registerModules([navigationModule(navigationRef)]);
372
+ ```
373
+
374
+ | Tool | Description | Args |
375
+ | ------------------------- | ------------------------------------ | -------------------------------------------------- |
376
+ | `get_state` | Full navigation state tree | — |
377
+ | `get_current_route` | Current focused route | — |
378
+ | `get_current_route_state` | Current route with nested state | — |
379
+ | `get_history` | Log of all screen transitions | `offset?`, `limit?`, `full?: boolean` |
380
+ | `navigate` | Navigate to screen (reuses existing) | `screen: string`, `params?: object` |
381
+ | `push` | Push new screen onto stack | `screen: string`, `params?: object` |
382
+ | `pop` | Pop screens | `count?: number` |
383
+ | `pop_to` | Pop to specific screen | `screen: string`, `params?: object` |
384
+ | `pop_to_top` | Pop to first screen | — |
385
+ | `go_back` | Go back to previous screen | — |
386
+ | `replace` | Replace current screen | `screen: string`, `params?: object` |
387
+ | `reset` | Reset navigation state | `routes: Array<{name, params?}>`, `index?: number` |
388
+
389
+ **Navigation history:**
390
+
391
+ ```typescript
392
+ // Get simplified history (name, key, params, timestamp)
393
+ call(tool: "navigation__get_history")
394
+
395
+ // Get last 5 transitions
396
+ call(tool: "navigation__get_history", args: '{"limit": 5}')
397
+
398
+ // Get full navigation state for each transition
399
+ call(tool: "navigation__get_history", args: '{"full": true}')
400
+
401
+ // Slice: skip first 10, get next 5
402
+ call(tool: "navigation__get_history", args: '{"offset": 10, "limit": 5}')
403
+ ```
404
+
405
+ ---
406
+
407
+ ### network
408
+
409
+ Intercepts `fetch` and `XMLHttpRequest`. Captures request/response bodies, headers, status, duration.
410
+
411
+ ```typescript
412
+ client.registerModules([networkModule()]);
413
+
414
+ // With options
415
+ client.registerModules([
416
+ networkModule({
417
+ maxEntries: 200,
418
+ includeBodies: true,
419
+ ignoreUrls: ['https://analytics.example.com', /\.png$/],
420
+ }),
421
+ ]);
422
+ ```
423
+
424
+ | Tool | Description | Args |
425
+ | ---------------- | ------------------------------ | -------------------------------------- |
426
+ | `get_requests` | Get captured requests | `method?`, `status?`, `url?`, `limit?` |
427
+ | `get_request` | Find requests by URL substring | `url: string` |
428
+ | `get_pending` | Get in-flight requests | — |
429
+ | `get_errors` | Get failed requests | `limit?: number` |
430
+ | `get_stats` | Request statistics | — |
431
+ | `clear_requests` | Clear captured requests | — |
432
+
433
+ Auto-ignores WebSocket, Metro, and symbolicate URLs.
434
+
435
+ ---
436
+
437
+ ### reactQuery
438
+
439
+ React Query cache inspection and management. Accepts a `QueryClient` instance.
440
+
441
+ ```typescript
442
+ import { QueryClient } from '@tanstack/react-query';
443
+
444
+ const queryClient = new QueryClient();
445
+
446
+ client.registerModules([reactQueryModule(queryClient)]);
447
+ ```
448
+
449
+ | Tool | Description | Args |
450
+ | ------------- | ------------------------------- | ----------------------------- |
451
+ | `get_queries` | List all cached queries | `status?`, `key?` (substring) |
452
+ | `get_data` | Get cached data for a query | `key: string` (JSON format) |
453
+ | `get_stats` | Cache statistics | — |
454
+ | `invalidate` | Invalidate queries (mark stale) | `key?: string` |
455
+ | `refetch` | Refetch queries | `key?: string` |
456
+ | `remove` | Remove from cache | `key?: string` |
457
+ | `reset` | Reset to initial state | `key?: string` |
458
+
459
+ ```typescript
460
+ // Get data for a specific query
461
+ call(tool: "query__get_data", args: '{"key": "[\"users\",\"list\"]"}')
462
+
463
+ // Invalidate all user queries
464
+ call(tool: "query__invalidate", args: '{"key": "users"}')
465
+ ```
466
+
467
+ ---
468
+
469
+ ### screenshot
470
+
471
+ Capture screenshots of the app via `@shopify/react-native-skia`. Requires Skia as a peer dependency.
472
+
473
+ ```bash
474
+ yarn add @shopify/react-native-skia
475
+ ```
476
+
477
+ ```typescript
478
+ import { createRef } from 'react';
479
+ import { View } from 'react-native';
480
+
481
+ const rootRef = createRef<View>();
482
+
483
+ client.registerModules([screenshotModule({ rootRef })]);
484
+
485
+ // JSX — rootRef must have collapsable={false}
486
+ <View ref={rootRef} collapsable={false} style={{ flex: 1 }}>
487
+ {/* app */}
488
+ </View>
489
+ ```
490
+
491
+ | Tool | Description | Args |
492
+ | --------- | ------------------ | ----------------------------------------------------------------- |
493
+ | `capture` | Capture screenshot | `format?: 'jpeg'\|'png'`, `quality?: number`, `maxWidth?: number` |
494
+
495
+ Default: JPEG, quality 80, max width 600px (height scales proportionally). Images are resized via `Skia.Surface.Make` + `drawImageRectOptions` for optimal size.
496
+
497
+ ```typescript
498
+ // Default (JPEG, 600px wide)
499
+ call(tool: "screenshot__capture")
500
+
501
+ // High quality PNG
502
+ call(tool: "screenshot__capture", args: '{"format": "png", "quality": 100}')
503
+
504
+ // Smaller image
505
+ call(tool: "screenshot__capture", args: '{"maxWidth": 400, "quality": 50}')
506
+ ```
507
+
508
+ ---
509
+
510
+ ### storage
511
+
512
+ Key-value storage inspection. Supports multiple named storage instances with flexible adapters.
513
+
514
+ ```typescript
515
+ // Single storage
516
+ client.registerModules([storageModule({ name: 'app', adapter: myStorageAdapter })]);
517
+
518
+ // Multiple storages
519
+ client.registerModules([
520
+ storageModule({ name: 'app', adapter: appStorage }, { name: 'cache', adapter: cacheStorage }),
521
+ ]);
522
+ ```
523
+
524
+ **Adapter interface** — only `get` is required:
525
+
526
+ ```typescript
527
+ interface StorageAdapter {
528
+ get(key: string): string | undefined | null | Promise<string | undefined | null>;
529
+ set?(key: string, value: string): void | Promise<void>;
530
+ delete?(key: string): void | Promise<void>;
531
+ getAllKeys?(): string[] | Promise<string[]>;
532
+ }
533
+ ```
534
+
535
+ | Tool | Description | Args |
536
+ | --------------- | ------------------------ | -------------------------------------------------- |
537
+ | `get_item` | Get value by key | `key: string`, `storage?: string` |
538
+ | `set_item` | Set value | `key: string`, `value: string`, `storage?: string` |
539
+ | `delete_item` | Delete key | `key: string`, `storage?: string` |
540
+ | `list_keys` | List all keys | `storage?: string` |
541
+ | `get_all` | Get all key-value pairs | `storage?: string` |
542
+ | `list_storages` | List registered storages | — |
543
+
544
+ Works with MMKV, AsyncStorage, or any custom adapter.
545
+
546
+ ## Hooks
547
+
548
+ Hooks let you expose state and tools from React components.
549
+
550
+ ### useMcpState
551
+
552
+ Expose reactive state to the AI agent:
553
+
554
+ ```typescript
555
+ useMcpState(
556
+ key: string,
557
+ factory: () => unknown,
558
+ deps: DependencyList
559
+ ): void
560
+ ```
561
+
562
+ ```typescript
563
+ const UserProvider = ({ children }) => {
564
+ const [user, setUser] = useState(null);
565
+
566
+ useMcpState(
567
+ 'user',
568
+ () => ({
569
+ email: user?.email,
570
+ id: user?.id,
571
+ loggedIn: user !== null,
572
+ }),
573
+ [user]
574
+ );
575
+
576
+ // ...
577
+ };
578
+ ```
579
+
580
+ The agent reads state via `state_get` and `state_list` tools — no WebSocket roundtrip needed.
581
+
582
+ ### useMcpTool
583
+
584
+ Register a dynamic tool from a component:
585
+
586
+ ```typescript
587
+ useMcpTool(
588
+ name: string,
589
+ factory: () => ToolHandler,
590
+ deps: DependencyList
591
+ ): void
592
+ ```
593
+
594
+ ```typescript
595
+ const UserProvider = ({ children }) => {
596
+ const logout = useCallback(() => {
597
+ /* ... */
598
+ }, []);
599
+
600
+ useMcpTool(
601
+ 'logout',
602
+ () => ({
603
+ description: 'Log out the current user',
604
+ handler: () => {
605
+ logout();
606
+ return { success: true };
607
+ },
608
+ }),
609
+ [logout]
610
+ );
611
+
612
+ // ...
613
+ };
614
+ ```
615
+
616
+ Dynamic tools are accessible via `call(tool: "_dynamic_logout")` and appear in `list_tools` with a `(dynamic)` label.
617
+
618
+ ### useMcpModule
619
+
620
+ Register a full module from a component (tied to component lifecycle):
621
+
622
+ ```typescript
623
+ useMcpModule(
624
+ factory: () => McpModule,
625
+ deps: DependencyList
626
+ ): void
627
+ ```
628
+
629
+ ```typescript
630
+ const App = () => {
631
+ const queryClient = useQueryClient();
632
+
633
+ useMcpModule(() => reactQueryModule(queryClient), [queryClient]);
634
+
635
+ // ...
636
+ };
637
+ ```
638
+
639
+ ## Babel Plugins
640
+
641
+ ### testIdPlugin
642
+
643
+ Auto-adds `data-mcp-id` attributes to JSX components for reliable component identification.
644
+
645
+ ```javascript
646
+ // babel.config.js
647
+ module.exports = {
648
+ plugins: [
649
+ [
650
+ 'react-native-mcp-kit/babel/test-id-plugin',
651
+ {
652
+ attr: 'data-mcp-id', // attribute name (default)
653
+ separator: ':', // separator (default)
654
+ exclude: ['Fragment'], // components to skip
655
+ include: ['Button', 'Input'], // if set, only these get IDs
656
+ },
657
+ ],
658
+ ],
659
+ };
660
+ ```
661
+
662
+ Generated ID format: `ComponentName:filePath:line`
663
+
664
+ ```tsx
665
+ // Before
666
+ <LoginButton onPress={handleLogin} />
667
+
668
+ // After (dev build)
669
+ <LoginButton onPress={handleLogin} data-mcp-id="LoginButton:src/screens/Login:42" />
670
+ ```
671
+
672
+ ### stripPlugin
673
+
674
+ Removes all MCP code from production builds. Zero MCP code in the final bundle.
675
+
676
+ ```javascript
677
+ // babel.config.js
678
+ module.exports = (api) => {
679
+ const isDev = api.cache(() => process.env.NODE_ENV !== 'production');
680
+
681
+ return {
682
+ plugins: [
683
+ isDev && ['react-native-mcp-kit/babel/test-id-plugin'],
684
+ !isDev && ['react-native-mcp-kit/babel/strip-plugin'],
685
+ ].filter(Boolean),
686
+ };
687
+ };
688
+ ```
689
+
690
+ **What it removes:**
691
+
692
+ - All imports from `react-native-mcp-kit`
693
+ - `McpClient.initialize()`, `registerModule()`, `registerModules()` calls
694
+ - `useMcpState()`, `useMcpTool()`, `useMcpModule()` calls
695
+ - `<McpProvider>` JSX (replaced with children)
696
+ - `data-mcp-id` JSX attributes
697
+
698
+ With the strip plugin, you don't need `if (__DEV__)` guards — just write MCP code normally and it gets removed in production.
699
+
700
+ ## Dev vs Production
701
+
702
+ Two strategies for production safety:
703
+
704
+ 1. **Strip plugin** (Babel) — removes all MCP imports, calls, and JSX from the production bundle. No MCP code ships to users.
705
+ 2. **Without strip plugin** — MCP code stays but WebSocket connection to non-existent server is harmless.
706
+
707
+ ## MCP Server Tools
708
+
709
+ The server exposes 5 static tools (no dynamic registration needed):
710
+
711
+ | Tool | Description |
712
+ | ------------------- | ------------------------------------------------------------- |
713
+ | `call` | Universal proxy — calls any tool registered by the RN app |
714
+ | `list_tools` | Lists all available tools grouped by module with descriptions |
715
+ | `connection_status` | Check if the RN app is connected |
716
+ | `state_get` | Read state exposed by `useMcpState` |
717
+ | `state_list` | List all available state keys |
718
+
719
+ **Using `call`:**
720
+
721
+ ```
722
+ call(tool: "navigation__navigate", args: '{"screen": "Settings"}')
723
+ call(tool: "console__get_errors")
724
+ call(tool: "_dynamic_logout")
725
+ ```
726
+
727
+ The `tool` argument uses `module__method` format (double underscore). Dynamic tools from `useMcpTool` use the `_dynamic_` prefix.
728
+
729
+ The server includes instructions and tool annotations to help AI agents understand how to interact with the app.
730
+
731
+ ## Custom Modules
732
+
733
+ Create your own module by returning an `McpModule` object:
734
+
735
+ ```typescript
736
+ import { type McpModule } from 'react-native-mcp-kit';
737
+
738
+ const myModule = (): McpModule => {
739
+ return {
740
+ description: 'My custom module for AI agents',
741
+ name: 'myModule',
742
+ tools: {
743
+ greet: {
744
+ description: 'Returns a greeting',
745
+ handler: async (args) => {
746
+ const name = args.name as string;
747
+ return { message: `Hello, ${name}!` };
748
+ },
749
+ },
750
+ getStatus: {
751
+ description: 'Get current status',
752
+ handler: () => {
753
+ return { status: 'ok', timestamp: Date.now() };
754
+ },
755
+ timeout: 5000, // custom timeout in ms (default: 10s)
756
+ },
757
+ },
758
+ };
759
+ };
760
+
761
+ // Register
762
+ client.registerModules([myModule()]);
763
+ ```
764
+
765
+ **Module registration methods:**
766
+
767
+ ```typescript
768
+ // At init time
769
+ const client = McpClient.initialize();
770
+ client.registerModules([myModule()]);
771
+
772
+ // After init
773
+ McpClient.getInstance().registerModule(myModule());
774
+
775
+ // From a component (tied to lifecycle)
776
+ useMcpModule(() => myModule(), []);
777
+ ```
778
+
779
+ ## Debug Logging
780
+
781
+ Enable colored console output for all MCP communication:
782
+
783
+ ```typescript
784
+ McpClient.initialize({ debug: true });
785
+ ```
786
+
787
+ Output shows:
788
+
789
+ - `[rn-mcp-kit]` tag (bold purple)
790
+ - Colored module names (12 bold ANSI colors, assigned by registration order)
791
+ - Bold method names
792
+ - `→` incoming tool requests (cyan)
793
+ - `←` responses (green)
794
+ - `✕` errors (red)
795
+
796
+ Debug logs use the original `console.log` (captured before the console module intercepts), so they don't appear in the console module buffer.
797
+
798
+ ## API Reference
799
+
800
+ ### McpClient
801
+
802
+ ```typescript
803
+ // Initialize (creates singleton)
804
+ static initialize(options?: { debug?: boolean; host?: string; port?: number }): McpClient
805
+
806
+ // Get existing instance (throws if not initialized)
807
+ static getInstance(): McpClient
808
+
809
+ // Module registration
810
+ registerModule(module: McpModule): void
811
+ registerModules(modules: McpModule[]): void
812
+
813
+ // Dynamic tools
814
+ registerTool(name: string, tool: ToolHandler): void
815
+ unregisterTool(name: string): void
816
+
817
+ // State
818
+ setState(key: string, value: unknown): void
819
+ removeState(key: string): void
820
+
821
+ // Lifecycle
822
+ dispose(): void
823
+ enableDebug(enabled: boolean): void
824
+ ```
825
+
826
+ ### McpModule
827
+
828
+ ```typescript
829
+ interface McpModule {
830
+ description?: string;
831
+ name: string;
832
+ tools: Record<string, ToolHandler>;
833
+ }
834
+ ```
835
+
836
+ ### ToolHandler
837
+
838
+ ```typescript
839
+ interface ToolHandler {
840
+ description: string;
841
+ handler: (args: Record<string, unknown>) => unknown | Promise<unknown>;
842
+ inputSchema?: Record<string, unknown>;
843
+ timeout?: number; // per-tool timeout in ms (default: 10s)
844
+ }
845
+ ```
846
+
847
+ ## Symlink Setup (for local development)
848
+
849
+ If you're developing with the library linked locally via symlink/portal:
850
+
851
+ ```javascript
852
+ // metro.config.js
853
+ const mcpPath = require('path').resolve(__dirname, '../path-to/react-native-mcp-kit');
854
+
855
+ module.exports = {
856
+ watchFolders: [mcpPath],
857
+ resolver: {
858
+ nodeModulesPaths: [
859
+ path.resolve(__dirname, 'node_modules'),
860
+ path.resolve(mcpPath, 'node_modules'),
861
+ ],
862
+ },
863
+ };
864
+ ```
865
+
866
+ ## License
867
+
868
+ MIT