@hyperweb/telescope 1.15.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 (382) hide show
  1. package/README.md +1529 -0
  2. package/main/build.js +183 -0
  3. package/main/builder.js +229 -0
  4. package/main/bundle.js +162 -0
  5. package/main/bundler.js +100 -0
  6. package/main/cli.js +71 -0
  7. package/main/cmds.js +28 -0
  8. package/main/commands/download.js +122 -0
  9. package/main/commands/generate.js +151 -0
  10. package/main/commands/install.js +143 -0
  11. package/main/commands/transpile.js +197 -0
  12. package/main/contracts/generate.js +31 -0
  13. package/main/contracts/install.js +107 -0
  14. package/main/contracts/message-composer.js +31 -0
  15. package/main/contracts/react-query.js +31 -0
  16. package/main/contracts/recoil.js +31 -0
  17. package/main/file.js +20 -0
  18. package/main/generators/create-aggregated-lcd-client.js +87 -0
  19. package/main/generators/create-all-stargate-clients.js +96 -0
  20. package/main/generators/create-amino-converters.js +43 -0
  21. package/main/generators/create-bundle.js +83 -0
  22. package/main/generators/create-cosmwasm-bundle.js +15 -0
  23. package/main/generators/create-custom-stargate-clients.js +100 -0
  24. package/main/generators/create-helpers.js +119 -0
  25. package/main/generators/create-index.js +75 -0
  26. package/main/generators/create-lcd-client-all.js +116 -0
  27. package/main/generators/create-lcd-client-scoped.js +89 -0
  28. package/main/generators/create-lcd-clients.js +78 -0
  29. package/main/generators/create-mcp-server.js +1853 -0
  30. package/main/generators/create-mobx-bundle.js +52 -0
  31. package/main/generators/create-msg-funcs.js +132 -0
  32. package/main/generators/create-pinia-store-bundle.js +50 -0
  33. package/main/generators/create-pinia-store.js +90 -0
  34. package/main/generators/create-query-funcs.js +133 -0
  35. package/main/generators/create-react-query-bundle.js +103 -0
  36. package/main/generators/create-registries.js +49 -0
  37. package/main/generators/create-root-readme.js +259 -0
  38. package/main/generators/create-rpc-msg-client-all.js +135 -0
  39. package/main/generators/create-rpc-msg-client-scoped.js +114 -0
  40. package/main/generators/create-rpc-msg-clients.js +116 -0
  41. package/main/generators/create-rpc-ops-bundle.js +119 -0
  42. package/main/generators/create-rpc-query-client-all.js +137 -0
  43. package/main/generators/create-rpc-query-client-scoped.js +110 -0
  44. package/main/generators/create-rpc-query-clients.js +198 -0
  45. package/main/generators/create-sdk-module-stargate-clients.js +95 -0
  46. package/main/generators/create-stargate-clients.js +96 -0
  47. package/main/generators/create-types.js +164 -0
  48. package/main/generators/customize-utils.js +50 -0
  49. package/main/helpers/__test__/internalTimestamp.js +49 -0
  50. package/main/helpers/__test__/internalTimestampBigint.js +45 -0
  51. package/main/helpers/binary-coder.js +535 -0
  52. package/main/helpers/decimals.js +111 -0
  53. package/main/helpers/external-comet.js +52 -0
  54. package/main/helpers/external-icjs.js +36 -0
  55. package/main/helpers/external.js +31 -0
  56. package/main/helpers/grpc-gateway.js +348 -0
  57. package/main/helpers/grpc-web.js +14 -0
  58. package/main/helpers/helper-func-types-interface.js +106 -0
  59. package/main/helpers/helper-func-types.js +93 -0
  60. package/main/helpers/index.js +38 -0
  61. package/main/helpers/internal-for-bigint.js +259 -0
  62. package/main/helpers/internal.js +240 -0
  63. package/main/helpers/json-safe.js +12 -0
  64. package/main/helpers/mobx.js +80 -0
  65. package/main/helpers/pinia-endpoint.js +20 -0
  66. package/main/helpers/react-query-hooks-icjs.js +223 -0
  67. package/main/helpers/react-query-hooks.js +258 -0
  68. package/main/helpers/react-query.js +93 -0
  69. package/main/helpers/registry-helper.js +229 -0
  70. package/main/helpers/types-helper.js +165 -0
  71. package/main/helpers/utf8-helper.js +146 -0
  72. package/main/helpers/varint.js +486 -0
  73. package/main/helpers/vue-query-hooks.js +226 -0
  74. package/main/imports.js +416 -0
  75. package/main/index.js +24 -0
  76. package/main/parse.js +194 -0
  77. package/main/prompt.js +64 -0
  78. package/main/protod/bufbuild.js +87 -0
  79. package/main/protod/config.js +30 -0
  80. package/main/protod/git-repo.js +58 -0
  81. package/main/protod/index.js +17 -0
  82. package/main/protod/recursive.js +134 -0
  83. package/main/protod/types.js +2 -0
  84. package/main/protod/utils.js +91 -0
  85. package/main/telescope.js +10 -0
  86. package/main/types.js +2 -0
  87. package/main/utils/common-create-bundle.js +29 -0
  88. package/main/utils/contracts.js +39 -0
  89. package/main/utils/files.js +138 -0
  90. package/main/utils/index.js +163 -0
  91. package/main/utils/unused.js +73 -0
  92. package/module/build.js +176 -0
  93. package/module/builder.js +222 -0
  94. package/module/bundle.js +128 -0
  95. package/module/bundler.js +96 -0
  96. package/module/cli.js +44 -0
  97. package/module/cmds.js +22 -0
  98. package/module/commands/download.js +94 -0
  99. package/module/commands/generate.js +123 -0
  100. package/module/commands/install.js +141 -0
  101. package/module/commands/transpile.js +169 -0
  102. package/module/contracts/generate.js +29 -0
  103. package/module/contracts/install.js +105 -0
  104. package/module/contracts/message-composer.js +29 -0
  105. package/module/contracts/react-query.js +29 -0
  106. package/module/contracts/recoil.js +29 -0
  107. package/module/file.js +18 -0
  108. package/module/generators/create-aggregated-lcd-client.js +83 -0
  109. package/module/generators/create-all-stargate-clients.js +92 -0
  110. package/module/generators/create-amino-converters.js +39 -0
  111. package/module/generators/create-bundle.js +79 -0
  112. package/module/generators/create-cosmwasm-bundle.js +11 -0
  113. package/module/generators/create-custom-stargate-clients.js +96 -0
  114. package/module/generators/create-helpers.js +112 -0
  115. package/module/generators/create-index.js +45 -0
  116. package/module/generators/create-lcd-client-all.js +89 -0
  117. package/module/generators/create-lcd-client-scoped.js +62 -0
  118. package/module/generators/create-lcd-clients.js +74 -0
  119. package/module/generators/create-mcp-server.js +1849 -0
  120. package/module/generators/create-mobx-bundle.js +25 -0
  121. package/module/generators/create-msg-funcs.js +128 -0
  122. package/module/generators/create-pinia-store-bundle.js +23 -0
  123. package/module/generators/create-pinia-store.js +86 -0
  124. package/module/generators/create-query-funcs.js +129 -0
  125. package/module/generators/create-react-query-bundle.js +76 -0
  126. package/module/generators/create-registries.js +45 -0
  127. package/module/generators/create-root-readme.js +255 -0
  128. package/module/generators/create-rpc-msg-client-all.js +108 -0
  129. package/module/generators/create-rpc-msg-client-scoped.js +87 -0
  130. package/module/generators/create-rpc-msg-clients.js +112 -0
  131. package/module/generators/create-rpc-ops-bundle.js +92 -0
  132. package/module/generators/create-rpc-query-client-all.js +110 -0
  133. package/module/generators/create-rpc-query-client-scoped.js +83 -0
  134. package/module/generators/create-rpc-query-clients.js +198 -0
  135. package/module/generators/create-sdk-module-stargate-clients.js +91 -0
  136. package/module/generators/create-stargate-clients.js +92 -0
  137. package/module/generators/create-types.js +137 -0
  138. package/module/generators/customize-utils.js +46 -0
  139. package/module/helpers/__test__/internalTimestamp.js +39 -0
  140. package/module/helpers/__test__/internalTimestampBigint.js +38 -0
  141. package/module/helpers/binary-coder.js +531 -0
  142. package/module/helpers/decimals.js +108 -0
  143. package/module/helpers/external-comet.js +49 -0
  144. package/module/helpers/external-icjs.js +33 -0
  145. package/module/helpers/external.js +28 -0
  146. package/module/helpers/grpc-gateway.js +345 -0
  147. package/module/helpers/grpc-web.js +11 -0
  148. package/module/helpers/helper-func-types-interface.js +102 -0
  149. package/module/helpers/helper-func-types.js +89 -0
  150. package/module/helpers/index.js +22 -0
  151. package/module/helpers/internal-for-bigint.js +255 -0
  152. package/module/helpers/internal.js +236 -0
  153. package/module/helpers/json-safe.js +9 -0
  154. package/module/helpers/mobx.js +77 -0
  155. package/module/helpers/pinia-endpoint.js +17 -0
  156. package/module/helpers/react-query-hooks-icjs.js +219 -0
  157. package/module/helpers/react-query-hooks.js +254 -0
  158. package/module/helpers/react-query.js +89 -0
  159. package/module/helpers/registry-helper.js +225 -0
  160. package/module/helpers/types-helper.js +161 -0
  161. package/module/helpers/utf8-helper.js +143 -0
  162. package/module/helpers/varint.js +483 -0
  163. package/module/helpers/vue-query-hooks.js +222 -0
  164. package/module/imports.js +382 -0
  165. package/module/index.js +8 -0
  166. package/module/parse.js +185 -0
  167. package/module/prompt.js +58 -0
  168. package/module/protod/bufbuild.js +76 -0
  169. package/module/protod/config.js +27 -0
  170. package/module/protod/git-repo.js +54 -0
  171. package/module/protod/index.js +1 -0
  172. package/module/protod/recursive.js +125 -0
  173. package/module/protod/types.js +1 -0
  174. package/module/protod/utils.js +77 -0
  175. package/module/telescope.js +8 -0
  176. package/module/types.js +1 -0
  177. package/module/utils/common-create-bundle.js +25 -0
  178. package/module/utils/contracts.js +33 -0
  179. package/module/utils/files.js +106 -0
  180. package/module/utils/index.js +143 -0
  181. package/module/utils/unused.js +47 -0
  182. package/package.json +115 -0
  183. package/src/build.ts +255 -0
  184. package/src/builder.ts +302 -0
  185. package/src/bundle.ts +160 -0
  186. package/src/bundler.ts +153 -0
  187. package/src/cli.js +51 -0
  188. package/src/cmds.js +25 -0
  189. package/src/commands/download.ts +120 -0
  190. package/src/commands/generate.ts +156 -0
  191. package/src/commands/install.ts +154 -0
  192. package/src/commands/transpile.ts +198 -0
  193. package/src/contracts/generate.ts +33 -0
  194. package/src/contracts/install.ts +118 -0
  195. package/src/contracts/message-composer.ts +34 -0
  196. package/src/contracts/react-query.ts +33 -0
  197. package/src/contracts/recoil.ts +32 -0
  198. package/src/file.js +20 -0
  199. package/src/generators/create-aggregated-lcd-client.ts +133 -0
  200. package/src/generators/create-all-stargate-clients.ts +121 -0
  201. package/src/generators/create-amino-converters.ts +62 -0
  202. package/src/generators/create-bundle.ts +97 -0
  203. package/src/generators/create-cosmwasm-bundle.ts +17 -0
  204. package/src/generators/create-custom-stargate-clients.ts +128 -0
  205. package/src/generators/create-helpers.ts +196 -0
  206. package/src/generators/create-index.ts +72 -0
  207. package/src/generators/create-lcd-client-all.ts +139 -0
  208. package/src/generators/create-lcd-client-scoped.ts +109 -0
  209. package/src/generators/create-lcd-clients.ts +108 -0
  210. package/src/generators/create-mcp-server.ts +1902 -0
  211. package/src/generators/create-mobx-bundle.ts +31 -0
  212. package/src/generators/create-msg-funcs.ts +219 -0
  213. package/src/generators/create-pinia-store-bundle.ts +35 -0
  214. package/src/generators/create-pinia-store.ts +121 -0
  215. package/src/generators/create-query-funcs.ts +224 -0
  216. package/src/generators/create-react-query-bundle.ts +111 -0
  217. package/src/generators/create-registries.ts +70 -0
  218. package/src/generators/create-root-readme.ts +316 -0
  219. package/src/generators/create-rpc-msg-client-all.ts +167 -0
  220. package/src/generators/create-rpc-msg-client-scoped.ts +147 -0
  221. package/src/generators/create-rpc-msg-clients.ts +165 -0
  222. package/src/generators/create-rpc-ops-bundle.ts +155 -0
  223. package/src/generators/create-rpc-query-client-all.ts +173 -0
  224. package/src/generators/create-rpc-query-client-scoped.ts +142 -0
  225. package/src/generators/create-rpc-query-clients.ts +304 -0
  226. package/src/generators/create-sdk-module-stargate-clients.ts +120 -0
  227. package/src/generators/create-stargate-clients.ts +123 -0
  228. package/src/generators/create-types.ts +236 -0
  229. package/src/generators/customize-utils.ts +54 -0
  230. package/src/helpers/__test__/internalTimestamp.test.ts +79 -0
  231. package/src/helpers/__test__/internalTimestamp.ts +58 -0
  232. package/src/helpers/__test__/internalTimestampBigint.test.ts +78 -0
  233. package/src/helpers/__test__/internalTimestampBigint.ts +58 -0
  234. package/src/helpers/binary-coder.ts +533 -0
  235. package/src/helpers/decimals.ts +108 -0
  236. package/src/helpers/external-comet.ts +49 -0
  237. package/src/helpers/external-icjs.ts +33 -0
  238. package/src/helpers/external.ts +28 -0
  239. package/src/helpers/grpc-gateway.ts +345 -0
  240. package/src/helpers/grpc-web.ts +11 -0
  241. package/src/helpers/helper-func-types-interface.ts +104 -0
  242. package/src/helpers/helper-func-types.ts +91 -0
  243. package/src/helpers/index.ts +22 -0
  244. package/src/helpers/internal-for-bigint.ts +257 -0
  245. package/src/helpers/internal.ts +238 -0
  246. package/src/helpers/json-safe.ts +11 -0
  247. package/src/helpers/mobx.ts +77 -0
  248. package/src/helpers/pinia-endpoint.ts +17 -0
  249. package/src/helpers/react-query-hooks-icjs.ts +223 -0
  250. package/src/helpers/react-query-hooks.ts +266 -0
  251. package/src/helpers/react-query.ts +101 -0
  252. package/src/helpers/registry-helper.ts +227 -0
  253. package/src/helpers/types-helper.ts +169 -0
  254. package/src/helpers/utf8-helper.ts +143 -0
  255. package/src/helpers/varint.ts +483 -0
  256. package/src/helpers/vue-query-hooks.ts +224 -0
  257. package/src/imports.ts +499 -0
  258. package/src/index.ts +12 -0
  259. package/src/parse.ts +243 -0
  260. package/src/prompt.js +65 -0
  261. package/src/protod/bufbuild.spec.ts +80 -0
  262. package/src/protod/bufbuild.ts +95 -0
  263. package/src/protod/config.ts +30 -0
  264. package/src/protod/git-repo.ts +74 -0
  265. package/src/protod/index.ts +1 -0
  266. package/src/protod/recursive.spec.ts +164 -0
  267. package/src/protod/recursive.ts +180 -0
  268. package/src/protod/test-data/.protod.config.json +42 -0
  269. package/src/protod/test-data/buf.lock +23 -0
  270. package/src/protod/test-data/buf.yaml +25 -0
  271. package/src/protod/test-data/buf2.yaml +20 -0
  272. package/src/protod/test-data/cosmos/buf.lock +23 -0
  273. package/src/protod/test-data/cosmos/crypto/secp256k1/keys.proto +38 -0
  274. package/src/protod/test-data/model.proto +101 -0
  275. package/src/protod/types.ts +55 -0
  276. package/src/protod/utils.spec.ts +68 -0
  277. package/src/protod/utils.ts +90 -0
  278. package/src/telescope.js +9 -0
  279. package/src/types.ts +46 -0
  280. package/src/utils/common-create-bundle.ts +62 -0
  281. package/src/utils/contracts.ts +37 -0
  282. package/src/utils/files.ts +145 -0
  283. package/src/utils/index.ts +150 -0
  284. package/src/utils/unused.ts +52 -0
  285. package/types/build.d.ts +41 -0
  286. package/types/builder.d.ts +50 -0
  287. package/types/bundle.d.ts +30 -0
  288. package/types/bundler.d.ts +31 -0
  289. package/types/cli.d.ts +1 -0
  290. package/types/cmds.d.ts +11 -0
  291. package/types/commands/download.d.ts +5 -0
  292. package/types/commands/generate.d.ts +2 -0
  293. package/types/commands/install.d.ts +2 -0
  294. package/types/commands/transpile.d.ts +4 -0
  295. package/types/contracts/generate.d.ts +2 -0
  296. package/types/contracts/install.d.ts +2 -0
  297. package/types/contracts/message-composer.d.ts +2 -0
  298. package/types/contracts/react-query.d.ts +2 -0
  299. package/types/contracts/recoil.d.ts +2 -0
  300. package/types/file.d.ts +2 -0
  301. package/types/generators/create-aggregated-lcd-client.d.ts +2 -0
  302. package/types/generators/create-all-stargate-clients.d.ts +3 -0
  303. package/types/generators/create-amino-converters.d.ts +3 -0
  304. package/types/generators/create-bundle.d.ts +3 -0
  305. package/types/generators/create-combined-stargate-clients.d.ts +3 -0
  306. package/types/generators/create-cosmwasm-bundle.d.ts +2 -0
  307. package/types/generators/create-custom-stargate-clients.d.ts +3 -0
  308. package/types/generators/create-helpers.d.ts +2 -0
  309. package/types/generators/create-index.d.ts +2 -0
  310. package/types/generators/create-lcd-client-all.d.ts +3 -0
  311. package/types/generators/create-lcd-client-scoped.d.ts +3 -0
  312. package/types/generators/create-lcd-clients.d.ts +3 -0
  313. package/types/generators/create-mcp-server.d.ts +3 -0
  314. package/types/generators/create-mobx-bundle.d.ts +2 -0
  315. package/types/generators/create-msg-funcs.d.ts +3 -0
  316. package/types/generators/create-pinia-store-bundle.d.ts +2 -0
  317. package/types/generators/create-pinia-store.d.ts +3 -0
  318. package/types/generators/create-query-funcs.d.ts +3 -0
  319. package/types/generators/create-react-query-bundle.d.ts +2 -0
  320. package/types/generators/create-registries.d.ts +3 -0
  321. package/types/generators/create-root-readme.d.ts +2 -0
  322. package/types/generators/create-rpc-msg-client-all.d.ts +3 -0
  323. package/types/generators/create-rpc-msg-client-scoped.d.ts +3 -0
  324. package/types/generators/create-rpc-msg-clients.d.ts +3 -0
  325. package/types/generators/create-rpc-ops-bundle.d.ts +2 -0
  326. package/types/generators/create-rpc-query-client-all.d.ts +3 -0
  327. package/types/generators/create-rpc-query-client-scoped.d.ts +3 -0
  328. package/types/generators/create-rpc-query-clients.d.ts +3 -0
  329. package/types/generators/create-scoped-stargate-clients.d.ts +3 -0
  330. package/types/generators/create-sdk-module-stargate-clients.d.ts +3 -0
  331. package/types/generators/create-stargate-clients.d.ts +3 -0
  332. package/types/generators/create-types.d.ts +3 -0
  333. package/types/generators/create-unified-stargate-clients.d.ts +3 -0
  334. package/types/generators/customize-utils.d.ts +2 -0
  335. package/types/helpers/__test__/internalTimestamp.d.ts +21 -0
  336. package/types/helpers/__test__/internalTimestampBigint.d.ts +20 -0
  337. package/types/helpers/binary-coder.d.ts +2 -0
  338. package/types/helpers/decimals.d.ts +1 -0
  339. package/types/helpers/external-comet.d.ts +1 -0
  340. package/types/helpers/external-icjs.d.ts +1 -0
  341. package/types/helpers/external.d.ts +1 -0
  342. package/types/helpers/generated-type.d.ts +1 -0
  343. package/types/helpers/grpc-gateway.d.ts +1 -0
  344. package/types/helpers/grpc-web.d.ts +1 -0
  345. package/types/helpers/helper-func-types-interface.d.ts +2 -0
  346. package/types/helpers/helper-func-types.d.ts +2 -0
  347. package/types/helpers/index.d.ts +22 -0
  348. package/types/helpers/internal-for-bigint.d.ts +2 -0
  349. package/types/helpers/internal.d.ts +2 -0
  350. package/types/helpers/internalForBigInt.d.ts +1 -0
  351. package/types/helpers/json-safe.d.ts +1 -0
  352. package/types/helpers/mobx.d.ts +1 -0
  353. package/types/helpers/pinia-endpoint.d.ts +1 -0
  354. package/types/helpers/react-query-hooks-icjs.d.ts +2 -0
  355. package/types/helpers/react-query-hooks.d.ts +2 -0
  356. package/types/helpers/react-query.d.ts +2 -0
  357. package/types/helpers/registry-helper.d.ts +2 -0
  358. package/types/helpers/types-helper.d.ts +2 -0
  359. package/types/helpers/types.d.ts +1 -0
  360. package/types/helpers/utf8-helper.d.ts +1 -0
  361. package/types/helpers/varint.d.ts +1 -0
  362. package/types/helpers/vue-query-hooks.d.ts +2 -0
  363. package/types/helpers/vue-query.d.ts +2 -0
  364. package/types/imports.d.ts +17 -0
  365. package/types/index.d.ts +6 -0
  366. package/types/parse.d.ts +15 -0
  367. package/types/prompt.d.ts +3 -0
  368. package/types/protod/bufbuild.d.ts +6 -0
  369. package/types/protod/config.d.ts +7 -0
  370. package/types/protod/git-repo.d.ts +11 -0
  371. package/types/protod/index.d.ts +1 -0
  372. package/types/protod/proto-download.d.ts +2 -0
  373. package/types/protod/recursive.d.ts +4 -0
  374. package/types/protod/types.d.ts +49 -0
  375. package/types/protod/utils.d.ts +11 -0
  376. package/types/telescope.d.ts +2 -0
  377. package/types/types.d.ts +43 -0
  378. package/types/utils/common-create-bundle.d.ts +18 -0
  379. package/types/utils/contracts.d.ts +6 -0
  380. package/types/utils/files.d.ts +5 -0
  381. package/types/utils/index.d.ts +16 -0
  382. package/types/utils/unused.d.ts +5 -0
@@ -0,0 +1,1902 @@
1
+ import { TelescopeBuilder } from '../builder';
2
+ import { Bundler } from '../bundler';
3
+ import { writeFileSync, mkdirSync, cpSync, existsSync } from 'fs';
4
+ import { join, dirname, basename } from 'path';
5
+
6
+ export const plugin = (
7
+ builder: TelescopeBuilder,
8
+ bundler: Bundler
9
+ ) => {
10
+ // Early return if MCP server is not enabled
11
+ if (!builder.options.mcpServer?.enabled) {
12
+ return;
13
+ }
14
+
15
+ // Use the output directory name instead of bundle base
16
+ const outputDirName = basename(builder.outPath);
17
+ const packageName = outputDirName || bundler.bundle.base;
18
+ const parentDir = dirname(builder.outPath);
19
+ const mcpServerPath = join(parentDir, `${packageName}-mcp`);
20
+
21
+ // Ensure MCP server directory exists
22
+ mkdirSync(mcpServerPath, { recursive: true });
23
+ mkdirSync(join(mcpServerPath, 'src'), { recursive: true });
24
+ mkdirSync(join(mcpServerPath, 'src', 'prompts'), { recursive: true });
25
+ mkdirSync(join(mcpServerPath, 'src', 'telescope-examples'), { recursive: true });
26
+
27
+ // Generate package.json for MCP server
28
+ const packageJson = generateMcpPackageJson(packageName);
29
+ writeFileSync(
30
+ join(mcpServerPath, 'package.json'),
31
+ JSON.stringify(packageJson, null, 2)
32
+ );
33
+
34
+ // Generate main MCP server file
35
+ const indexContent = `#!/usr/bin/env node
36
+
37
+ import { readFileSync } from 'node:fs';
38
+ import { dirname, resolve } from 'node:path';
39
+ import { fileURLToPath } from 'node:url';
40
+
41
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
42
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
43
+ import { z } from 'zod';
44
+
45
+ // Get package.json version
46
+ const __filename = fileURLToPath(import.meta.url);
47
+ const __dirname = dirname(__filename);
48
+ const packageJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf8'));
49
+ const VERSION = packageJson.version;
50
+
51
+ async function main() {
52
+ const server = new McpServer({
53
+ name: '${packageName} MCP Server',
54
+ version: VERSION,
55
+ });
56
+
57
+ // Add prompts for AI agents
58
+ server.prompt(
59
+ 'codegen-usage',
60
+ 'Guide for using telescope generated code',
61
+ async () => {
62
+ const promptPath = resolve(__dirname, 'prompts/codegen-usage.md');
63
+ const content = readFileSync(promptPath, 'utf-8');
64
+ return {
65
+ messages: [{
66
+ role: 'user',
67
+ content: {
68
+ type: 'text',
69
+ text: content
70
+ }
71
+ }]
72
+ };
73
+ }
74
+ );
75
+
76
+ server.prompt(
77
+ 'agent-guidelines',
78
+ 'Guidelines for MCP agents using ${packageName}',
79
+ async () => {
80
+ const promptPath = resolve(__dirname, 'prompts/agent-guidelines.md');
81
+ const content = readFileSync(promptPath, 'utf-8');
82
+ return {
83
+ messages: [{
84
+ role: 'user',
85
+ content: {
86
+ type: 'text',
87
+ text: content
88
+ }
89
+ }]
90
+ };
91
+ }
92
+ );
93
+
94
+ // Register blockchain function generator tool
95
+ server.tool(
96
+ 'create-blockchain-function',
97
+ 'Create custom blockchain functions by referencing telescope examples and generated code',
98
+ {
99
+ task: z.string().describe('The blockchain task to implement (e.g., "get balance", "check staking rewards", "query validators")').optional(),
100
+ chainName: z.string().describe('The blockchain name (e.g., cosmos, osmosis, injective)').optional(),
101
+ functionType: z.enum(['query', 'transaction', 'react-hook', 'utility']).describe('Type of function to create').optional(),
102
+ customRequirements: z.string().describe('Any specific requirements or modifications needed').optional()
103
+ },
104
+ async (args) => {
105
+ try {
106
+ const { task = 'get account balance', chainName = 'cosmos', functionType = 'query', customRequirements } = args;
107
+
108
+ // Read available examples
109
+ const examplesPath = resolve(__dirname, 'telescope-examples');
110
+ let availableExamples: string[] = [];
111
+
112
+ try {
113
+ const fs = await import('fs');
114
+ availableExamples = fs.readdirSync(examplesPath)
115
+ .filter(file => file.endsWith('.ts'))
116
+ .map(file => file.replace('.ts', ''));
117
+ } catch (error) {
118
+ // If examples directory doesn't exist, provide default list
119
+ availableExamples = [
120
+ 'config-example', 'useBalance', 'useBalanceFunc', 'getBalance',
121
+ 'useAssets', 'useStakingData', 'useValidators', 'useVoting',
122
+ 'useVotingData', 'useContractInfo', 'useQueryContract',
123
+ 'useCodeDetails', 'useMyContracts', 'useGrants', 'useSendData',
124
+ 'useTotalAssets', 'useBalanceReact'
125
+ ];
126
+ }
127
+
128
+ const examplesList = availableExamples.map(example => \`- **\${example}.ts**: Reference implementation\`).join('\\n');
129
+
130
+ const relevantExamples = getRelevantExamples(task, availableExamples)
131
+ .map(example => \`- **\${example}**: \${getExampleDescription(example)}\`)
132
+ .join('\\n');
133
+
134
+ const codeBlockStart = '\`\`\`';
135
+ const codeBlockEnd = '\`\`\`';
136
+
137
+ const response = [
138
+ '# Blockchain Function Generator',
139
+ '',
140
+ \`## Task: \${task}\`,
141
+ \`## Chain: \${chainName}\`,
142
+ \`## Function Type: \${functionType}\`,
143
+ customRequirements ? \`## Custom Requirements: \${customRequirements}\` : '',
144
+ '',
145
+ '## Instructions for Implementation',
146
+ '',
147
+ '### Step 1: Review Available Examples',
148
+ 'The following example files are available in \`src/telescope-examples/\`:',
149
+ '',
150
+ examplesList,
151
+ '',
152
+ '### Step 2: Identify Relevant Examples',
153
+ \`Based on your task "\${task}", you should primarily reference:\`,
154
+ '',
155
+ relevantExamples,
156
+ '',
157
+ '### Step 3: Implementation Pattern',
158
+ '',
159
+ \`**For Query Functions (\${functionType === 'query' ? 'SELECTED' : 'Available'}):**\`,
160
+ \`\${codeBlockStart}typescript\`,
161
+ "import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';",
162
+ '',
163
+ 'export const customQueryFunction = async (params: QueryParams) => {',
164
+ \` const rpcEndpoint = 'https://\${chainName}-rpc.quickapi.com:443';\`,
165
+ ' ',
166
+ ' try {',
167
+ ' const result = await getBalance(rpcEndpoint, params);',
168
+ ' return {',
169
+ ' success: true,',
170
+ ' data: result,',
171
+ ' };',
172
+ ' } catch (error) {',
173
+ ' return {',
174
+ ' success: false,',
175
+ ' error: (error as Error).message,',
176
+ ' };',
177
+ ' }',
178
+ '};',
179
+ codeBlockEnd,
180
+ '',
181
+ \`**For React Hooks (\${functionType === 'react-hook' ? 'SELECTED' : 'Available'}):**\`,
182
+ \`\${codeBlockStart}typescript\`,
183
+ "import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';",
184
+ "import { defaultContext } from '@tanstack/react-query';",
185
+ '',
186
+ 'export const useCustomHook = (params: HookParams) => {',
187
+ \` const rpcEndpoint = 'https://\${chainName}-rpc.quickapi.com:443';\`,
188
+ ' ',
189
+ ' return useGetBalance({',
190
+ ' request: params,',
191
+ ' options: {',
192
+ ' enabled: !!params.address,',
193
+ ' context: defaultContext,',
194
+ ' },',
195
+ ' clientResolver: rpcEndpoint,',
196
+ ' });',
197
+ '};',
198
+ codeBlockEnd,
199
+ '',
200
+ '### Step 4: Configuration Setup',
201
+ 'Always include proper chain configuration. Reference \`config-example.ts\`:',
202
+ '',
203
+ \`\${codeBlockStart}typescript\`,
204
+ 'import { assetLists, chains } from "@chain-registry/v2";',
205
+ '',
206
+ \`export const targetChainName = '\${chainName}';\`,
207
+ \`export const rpcEndpoint = 'https://\${chainName}-rpc.quickapi.com:443';\`,
208
+ 'export const chain = chains.find((chain) => chain.chainName === targetChainName);',
209
+ 'export const assetList = assetLists.find((assetList) => assetList.chainName === targetChainName);',
210
+ codeBlockEnd,
211
+ '',
212
+ '### Step 5: Error Handling & Best Practices',
213
+ '- Always wrap async calls in try-catch blocks',
214
+ '- Validate input parameters before making requests',
215
+ '- Handle network timeouts and connection errors',
216
+ '- Convert base units to human-readable amounts (uatom → ATOM)',
217
+ '- Include proper TypeScript types',
218
+ '',
219
+ '### Step 6: Testing Your Function',
220
+ \`\${codeBlockStart}typescript\`,
221
+ '// Example usage',
222
+ 'const result = await customQueryFunction({',
223
+ " address: 'cosmos1...',",
224
+ " denom: 'uatom'",
225
+ '});',
226
+ '',
227
+ 'if (result.success) {',
228
+ " console.log('Result:', result.data);",
229
+ '} else {',
230
+ " console.error('Error:', result.error);",
231
+ '}',
232
+ codeBlockEnd,
233
+ '',
234
+ '## Additional Resources',
235
+ '',
236
+ '- **Full codebase reference**: \`src/telescope/\` directory contains all generated types and functions',
237
+ '- **Configuration examples**: \`src/telescope-examples/config-example.ts\`',
238
+ '- **Chain registry data**: \`src/prompts/chains.json\`',
239
+ '- **Usage guidelines**: Use the \`codegen-usage\` and \`agent-guidelines\` prompts for detailed instructions',
240
+ '',
241
+ '## Next Steps',
242
+ '',
243
+ '1. Review the suggested example files above',
244
+ '2. Copy and modify the relevant pattern for your use case',
245
+ '3. Test your implementation with proper error handling',
246
+ '4. Ensure proper TypeScript types are used',
247
+ '',
248
+ 'The examples in \`telescope-examples/\` are production-ready patterns that you can adapt for any blockchain task.'
249
+ ].filter(line => line !== '').join('\\n');
250
+
251
+ return {
252
+ content: [{
253
+ type: "text",
254
+ text: response
255
+ }]
256
+ };
257
+
258
+ } catch (error) {
259
+ return {
260
+ content: [{
261
+ type: "text",
262
+ text: \`Error generating blockchain function guidance: \${(error as Error).message}\`
263
+ }]
264
+ };
265
+ }
266
+ }
267
+ );
268
+
269
+ const transport = new StdioServerTransport();
270
+ await server.connect(transport);
271
+ console.log('${packageName} MCP server started on stdio');
272
+ }
273
+
274
+ // Helper functions for example recommendations
275
+ function getRelevantExamples(task: string, availableExamples: string[]): string[] {
276
+ const taskLower = task.toLowerCase();
277
+ const relevantExamples: string[] = [];
278
+
279
+ // Balance-related tasks
280
+ if (taskLower.includes('balance')) {
281
+ relevantExamples.push('useBalance', 'useBalanceFunc', 'getBalance');
282
+ if (taskLower.includes('react')) {
283
+ relevantExamples.push('useBalanceReact');
284
+ }
285
+ }
286
+
287
+ // Staking-related tasks
288
+ if (taskLower.includes('staking') || taskLower.includes('delegate') || taskLower.includes('validator')) {
289
+ relevantExamples.push('useStakingData', 'useValidators');
290
+ }
291
+
292
+ // Governance/voting tasks
293
+ if (taskLower.includes('voting') || taskLower.includes('proposal') || taskLower.includes('governance')) {
294
+ relevantExamples.push('useVoting', 'useVotingData');
295
+ }
296
+
297
+ // Assets/portfolio tasks
298
+ if (taskLower.includes('asset') || taskLower.includes('portfolio') || taskLower.includes('total')) {
299
+ relevantExamples.push('useAssets', 'useTotalAssets');
300
+ }
301
+
302
+ // Contract-related tasks
303
+ if (taskLower.includes('contract') || taskLower.includes('cosmwasm')) {
304
+ relevantExamples.push('useContractInfo', 'useQueryContract', 'useCodeDetails', 'useMyContracts');
305
+ }
306
+
307
+ // Transaction/sending tasks
308
+ if (taskLower.includes('send') || taskLower.includes('transaction') || taskLower.includes('transfer')) {
309
+ relevantExamples.push('useSendData', 'getBalance');
310
+ }
311
+
312
+ // Authorization tasks
313
+ if (taskLower.includes('grant') || taskLower.includes('authorization') || taskLower.includes('authz')) {
314
+ relevantExamples.push('useGrants');
315
+ }
316
+
317
+ // Always include config as it's fundamental
318
+ relevantExamples.unshift('config-example');
319
+
320
+ // Remove duplicates and ensure examples exist
321
+ return [...new Set(relevantExamples)].filter(example =>
322
+ availableExamples.includes(example)
323
+ );
324
+ }
325
+
326
+ function getExampleDescription(example: string): string {
327
+ const descriptions: Record<string, string> = {
328
+ 'config-example': 'Chain configuration and RPC endpoints setup',
329
+ 'useBalance': 'React hook for querying account balance',
330
+ 'useBalanceFunc': 'Direct function for balance queries',
331
+ 'useBalanceReact': 'React hook with BigNumber for balance queries',
332
+ 'getBalance': 'Basic balance query with transaction examples',
333
+ 'useAssets': 'Query all token balances for an account',
334
+ 'useStakingData': 'Comprehensive staking information (delegations, rewards, validators)',
335
+ 'useValidators': 'Query active validators with sorting',
336
+ 'useVoting': 'Active governance proposals in voting period',
337
+ 'useVotingData': 'All governance proposals with categorization',
338
+ 'useContractInfo': 'Smart contract information queries',
339
+ 'useQueryContract': 'Execute smart contract queries',
340
+ 'useCodeDetails': 'Contract code information and metadata',
341
+ 'useMyContracts': 'Contracts created by specific address',
342
+ 'useGrants': 'Authorization grants (granter/grantee)',
343
+ 'useSendData': 'Prepare transaction data for token transfers',
344
+ 'useTotalAssets': 'Portfolio summary with total asset calculations'
345
+ };
346
+
347
+ return descriptions[example] || 'Blockchain utility function';
348
+ }
349
+
350
+ main().catch((error) => {
351
+ console.error('Fatal error in main()', error);
352
+ process.exit(1);
353
+ });
354
+ `;
355
+
356
+ writeFileSync(
357
+ join(mcpServerPath, 'src', 'index.ts'),
358
+ indexContent
359
+ );
360
+
361
+ // Generate telescope loader utility
362
+ const telescopeLoaderCode = generateTelescopeLoader(packageName);
363
+ writeFileSync(
364
+ join(mcpServerPath, 'src', 'telescope-loader.ts'),
365
+ telescopeLoaderCode
366
+ );
367
+
368
+ // Generate TypeScript configuration
369
+ const tsConfig = generateTsConfig();
370
+ writeFileSync(
371
+ join(mcpServerPath, 'tsconfig.json'),
372
+ JSON.stringify(tsConfig, null, 2)
373
+ );
374
+
375
+ // Generate README
376
+ const readme = generateReadme(packageName);
377
+ writeFileSync(
378
+ join(mcpServerPath, 'README.md'),
379
+ readme
380
+ );
381
+
382
+ // Generate comprehensive prompts and guidelines
383
+ generateComprehensivePrompts(mcpServerPath, packageName);
384
+
385
+ // Generate telescope examples
386
+ generateTelescopeExamples(mcpServerPath, packageName);
387
+
388
+ // Copy entire telescope generated codebase for AI reference (excluded from build)
389
+ copyTelescopeCodebase(builder, mcpServerPath, packageName);
390
+ };
391
+
392
+ function generateMcpPackageJson(packageName: string) {
393
+
394
+ return {
395
+ name: `@${packageName}/mcp-server`,
396
+ version: "0.1.0",
397
+ description: `MCP server for ${packageName} blockchain interactions`,
398
+ main: "dist/index.js",
399
+ type: "module",
400
+ bin: {
401
+ [`@${packageName}/mcp-server`]: "./dist/index.js"
402
+ },
403
+ scripts: {
404
+ build: "rimraf dist && tsc",
405
+ clean: "rimraf dist",
406
+ test: "vitest",
407
+ inspector: "npm run build && npm exec @modelcontextprotocol/inspector node dist/index.js",
408
+ format: "biome check --write",
409
+ lint: "biome check"
410
+ },
411
+ dependencies: {
412
+ "@modelcontextprotocol/sdk": "^1.7.0",
413
+ "zod": "^3.24.2"
414
+ },
415
+ devDependencies: {
416
+ "@biomejs/biome": "1.9.4",
417
+ "@types/node": "^22.13.10",
418
+ "rimraf": "^6.0.1",
419
+ "typescript": "^5.8.2",
420
+ "vitest": "^3.1.1"
421
+ },
422
+ files: ["dist"],
423
+ publishConfig: {
424
+ access: "public"
425
+ }
426
+ };
427
+ }
428
+
429
+ function generateMcpServerCode(builder: TelescopeBuilder, bundler: Bundler) {
430
+ const outputDirName = basename(builder.outPath);
431
+ const packageName = outputDirName || bundler.bundle.base;
432
+
433
+ return `#!/usr/bin/env node
434
+
435
+ import { readFileSync } from 'node:fs';
436
+ import { dirname, resolve } from 'node:path';
437
+ import { fileURLToPath } from 'node:url';
438
+
439
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
440
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
441
+ import { z } from 'zod';
442
+
443
+ // NOTE: Tool imports are commented out since they are excluded from build
444
+ // Uncomment and modify these imports if you want to include tools in your build
445
+ /*
446
+ import { getBalanceTool } from './tools/getBalance.js';
447
+ import { getBalanceReactTool } from './tools/useBalance.js';
448
+ */
449
+
450
+ // Get package.json version
451
+ const __filename = fileURLToPath(import.meta.url);
452
+ const __dirname = dirname(__filename);
453
+ const packageJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf8'));
454
+ const VERSION = packageJson.version;
455
+
456
+ async function main() {
457
+ const server = new McpServer({
458
+ name: '${packageName} MCP Server',
459
+ version: VERSION,
460
+ });
461
+
462
+ // Add prompts for AI agents
463
+ server.prompt(
464
+ 'codegen-usage',
465
+ 'Guide for using telescope generated code',
466
+ async () => {
467
+ const promptPath = resolve(__dirname, 'prompts/codegen-usage.md');
468
+ const content = readFileSync(promptPath, 'utf-8');
469
+ return {
470
+ messages: [{
471
+ role: 'user',
472
+ content: {
473
+ type: 'text',
474
+ text: content
475
+ }
476
+ }]
477
+ };
478
+ }
479
+ );
480
+
481
+ server.prompt(
482
+ 'agent-guidelines',
483
+ 'Guidelines for MCP agents using ${packageName}',
484
+ async () => {
485
+ const promptPath = resolve(__dirname, 'prompts/agent-guidelines.md');
486
+ const content = readFileSync(promptPath, 'utf-8');
487
+ return {
488
+ messages: [{
489
+ role: 'user',
490
+ content: {
491
+ type: 'text',
492
+ text: content
493
+ }
494
+ }]
495
+ };
496
+ }
497
+ );
498
+
499
+ // NOTE: Tool registrations are commented out since tool functions are not imported
500
+ // Uncomment and modify these registrations if you want to include tools in your build
501
+ /*
502
+ // Register tools
503
+ server.tool('get-balance', 'Get account balance for a specific token', {
504
+ address: z.string().describe('The account address'),
505
+ chainName: z.string().describe('The blockchain name (e.g., cosmos, osmosis)').optional(),
506
+ denom: z.string().describe('The token denomination (e.g., uatom, uosmo)').optional()
507
+ }, getBalanceTool);
508
+
509
+ server.tool('get-balance-react', 'Get balance using React hook pattern', {
510
+ address: z.string().describe('The account address'),
511
+ chainName: z.string().describe('The blockchain name').optional(),
512
+ displayDenom: z.string().describe('The display denomination').optional()
513
+ }, getBalanceReactTool);
514
+ */
515
+
516
+ const transport = new StdioServerTransport();
517
+ await server.connect(transport);
518
+ console.log('${packageName} MCP server started on stdio');
519
+ }
520
+
521
+ main().catch((error) => {
522
+ console.error('Fatal error in main()', error);
523
+ process.exit(1);
524
+ });
525
+ `;
526
+ }
527
+
528
+ function generateTsConfig() {
529
+ return {
530
+ compilerOptions: {
531
+ target: "ES2022",
532
+ module: "ESNext",
533
+ moduleResolution: "node",
534
+ outDir: "./dist",
535
+ rootDir: "./src",
536
+ strict: true,
537
+ esModuleInterop: true,
538
+ skipLibCheck: true,
539
+ forceConsistentCasingInFileNames: true,
540
+ declaration: true,
541
+ declarationMap: true,
542
+ sourceMap: true,
543
+ allowSyntheticDefaultImports: true,
544
+ resolveJsonModule: true
545
+ },
546
+ include: ["src/**/*"],
547
+ exclude: ["node_modules", "dist", "src/telescope/**/*", "src/telescope-examples/**/*"]
548
+ };
549
+ }
550
+
551
+ function generateReadme(packageName: string) {
552
+
553
+ return `# ${packageName.charAt(0).toUpperCase() + packageName.slice(1)} MCP Server
554
+
555
+ This MCP server provides AI agents with tools to interact with blockchain through generated TypeScript clients.
556
+
557
+ **Note**: This MCP server contains a complete copy of the telescope generated codebase in \`src/telescope/\` for AI agents to reference, but uses mock implementations for demonstration. The telescope code is excluded from the build process.
558
+
559
+ ## Installation
560
+
561
+ \`\`\`bash
562
+ cd ${packageName}-mcp
563
+ npm install
564
+ npm run build
565
+ \`\`\`
566
+
567
+ ## Usage with AI Agents
568
+
569
+ Add this configuration to your AI agent's MCP settings:
570
+
571
+ \`\`\`json
572
+ {
573
+ "mcpServers": {
574
+ "${packageName}-mcp-server": {
575
+ "command": "node",
576
+ "args": ["/path/to/${packageName}-mcp/dist/index.js"]
577
+ }
578
+ }
579
+ }
580
+ \`\`\`
581
+
582
+ ## Available Features
583
+
584
+ This MCP server provides:
585
+
586
+ - **Comprehensive Examples**: Reference implementations in \`src/telescope-examples/\`
587
+ - **Function Generator Tool**: AI-powered tool that creates custom blockchain functions based on user requirements
588
+ - **AI Guidance**: Prompt files to help AI agents understand blockchain development
589
+ - **Complete Codebase**: Full telescope-generated code in \`src/telescope/\` for reference
590
+
591
+ **Note**: The MCP server uses a meta-tool approach - instead of predefined tools, it instructs agents to create custom functions by referencing the comprehensive examples.
592
+
593
+ ## Development
594
+
595
+ \`\`\`bash
596
+ npm run build # Build the server
597
+ npm run inspector # Run MCP inspector for testing
598
+ npm run clean # Clean dist directory
599
+ \`\`\`
600
+
601
+ ## Directory Structure
602
+
603
+ \`\`\`
604
+ ${packageName}-mcp/
605
+ ├── src/
606
+ │ ├── telescope/ # 📚 Telescope generated code (reference only, excluded from build)
607
+ │ │ ├── cosmos/ # Full cosmos SDK modules
608
+ │ │ │ ├── bank/ # Balance queries, transfers
609
+ │ │ │ ├── staking/ # Validator operations
610
+ │ │ │ └── ... # Other cosmos modules
611
+ │ │ ├── osmosis/ # Osmosis DEX functionality
612
+ │ │ ├── ibc/ # Inter-blockchain communication
613
+ │ │ └── index.ts # Main exports
614
+ │ ├── telescope-examples/ # 📖 Usage examples and patterns (excluded from build)
615
+ │ │ ├── config-example.ts # Chain configuration setup
616
+ │ │ ├── useBalance.ts # Balance query React hooks
617
+ │ │ ├── useBalanceFunc.ts # Direct balance functions
618
+ │ │ ├── getBalance.ts # Balance queries with examples
619
+ │ │ ├── useAssets.ts # Multi-token balance queries
620
+ │ │ ├── useStakingData.ts # Staking and delegation info
621
+ │ │ ├── useValidators.ts # Validator queries
622
+ │ │ ├── useVoting.ts # Governance proposals
623
+ │ │ ├── useContractInfo.ts # Smart contract queries
624
+ │ │ ├── useMyContracts.ts # User's contract list
625
+ │ │ ├── useGrants.ts # Authorization grants
626
+ │ │ └── useSendData.ts # Transaction preparation
627
+ │ ├── prompts/ # 🤖 Agent instruction files
628
+ │ │ ├── codegen-usage.md # Telescope usage guide
629
+ │ │ ├── agent-guidelines.md # Best practices for agents
630
+ │ │ └── chains.json # Chain registry data
631
+ │ ├── index.ts # MCP server with function generator tool
632
+ │ └── telescope-loader.ts # Utility for dynamic code loading
633
+ ├── dist/ # Compiled JavaScript (excludes telescope/ and telescope-examples/)
634
+ └── package.json
635
+ \`\`\`
636
+
637
+ The \`src/telescope/\` and \`src/telescope-examples/\` directories contain reference code for AI agents but are excluded from the TypeScript build process.
638
+
639
+ Generated by [Telescope](https://github.com/hyperweb-io/telescope) 🔭
640
+ `;
641
+ }
642
+
643
+ function copyTelescopeCodebase(builder: TelescopeBuilder, mcpServerPath: string, packageName: string) {
644
+ const sourcePath = builder.outPath;
645
+ const destPath = join(mcpServerPath, 'src', 'telescope');
646
+
647
+ // Copy the entire telescope generated directory
648
+ if (existsSync(sourcePath)) {
649
+ // Skip copy if destination already exists (avoids Windows file permission issues)
650
+ if (existsSync(destPath)) {
651
+ console.log(`Telescope codebase already exists at ${destPath}, skipping copy to avoid Windows file permission issues`);
652
+ return;
653
+ }
654
+
655
+ console.log(`Copying telescope codebase from ${sourcePath} to ${destPath}`);
656
+
657
+ // Ensure parent directory exists
658
+ mkdirSync(dirname(destPath), { recursive: true });
659
+
660
+ // Copy without removing destination first
661
+ try {
662
+ cpSync(sourcePath, destPath, { recursive: true, force: true });
663
+ } catch (error) {
664
+ console.warn(`Warning: Could not copy telescope codebase: ${error}`);
665
+ console.log('MCP server will still function, but AI agents will have limited code references');
666
+ // Don't throw error - let MCP server generation continue
667
+ }
668
+ } else {
669
+ console.warn(`Source path ${sourcePath} does not exist, skipping telescope codebase copy`);
670
+ }
671
+ }
672
+
673
+ // Removed retry logic - no longer needed since we skip copy if destination exists
674
+
675
+ function generateTelescopeLoader(packageName: string) {
676
+ return `import { readFileSync } from 'node:fs';
677
+ import { resolve, dirname } from 'node:path';
678
+ import { fileURLToPath } from 'node:url';
679
+
680
+ const __filename = fileURLToPath(import.meta.url);
681
+ const __dirname = dirname(__filename);
682
+
683
+ /**
684
+ * Load telescope generated modules dynamically
685
+ * This utility helps MCP tools access the telescope codebase
686
+ */
687
+ export class TelescopeLoader {
688
+ private basePath: string;
689
+
690
+ constructor() {
691
+ this.basePath = resolve(__dirname, 'telescope');
692
+ }
693
+
694
+ /**
695
+ * Get available modules in the telescope codebase
696
+ */
697
+ getAvailableModules(): string[] {
698
+ // This would typically read the directory structure
699
+ // For now, return common cosmos modules
700
+ return [
701
+ 'cosmos/bank/v1beta1',
702
+ 'cosmos/staking/v1beta1',
703
+ 'cosmos/gov/v1beta1',
704
+ 'cosmos/distribution/v1beta1',
705
+ 'cosmwasm/wasm/v1',
706
+ 'ibc/core/client/v1',
707
+ 'osmosis/gamm/v1beta1'
708
+ ];
709
+ }
710
+
711
+ /**
712
+ * Load module documentation/examples
713
+ */
714
+ loadModuleInfo(modulePath: string) {
715
+ try {
716
+ const infoPath = resolve(this.basePath, modulePath, 'README.md');
717
+ return readFileSync(infoPath, 'utf-8');
718
+ } catch (error) {
719
+ return \`Module documentation not found for \${modulePath}\`;
720
+ }
721
+ }
722
+
723
+ /**
724
+ * Get module schema information
725
+ */
726
+ getModuleSchema(modulePath: string) {
727
+ // Return basic schema info for the module
728
+ return {
729
+ module: modulePath,
730
+ package: '${packageName}',
731
+ queries: ['getBalance', 'getAllBalances'],
732
+ mutations: ['send', 'delegate'],
733
+ types: ['Coin', 'MsgSend', 'MsgDelegate']
734
+ };
735
+ }
736
+ }
737
+
738
+ export const telescopeLoader = new TelescopeLoader();
739
+ `;
740
+ }
741
+
742
+ function generateComprehensivePrompts(mcpServerPath: string, packageName: string) {
743
+ // Generate codegen-usage.md
744
+ const codegenUsageContent = `# Codegen Usage Guide
745
+
746
+ ## Overview
747
+ This guide provides instructions for MCP agents on how to use the telescope generated code in the ${packageName} package.
748
+
749
+ ## Category of Functions
750
+
751
+ ### 1. **.rpc.func** - Direct Function Calls
752
+ These are direct async functions that make RPC calls to blockchain nodes. Use these for:
753
+ - Server-side operations
754
+ - Node.js scripts
755
+ - Direct blockchain queries outside React
756
+
757
+ **Import Pattern**:
758
+ \`\`\`typescript
759
+ import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';
760
+ import { send } from '${packageName}/cosmos/bank/v1beta1/tx.rpc.func';
761
+ \`\`\`
762
+
763
+ **Usage Examples**:
764
+
765
+ **Query Balance**:
766
+ \`\`\`typescript
767
+ import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';
768
+
769
+ // Basic balance query
770
+ const { balance } = await getBalance(rpcEndpoint, {
771
+ address: "cosmos1...",
772
+ denom: "uatom"
773
+ });
774
+
775
+ // With error handling
776
+ try {
777
+ const { balance } = await getBalance(rpcEndpoint, { address, denom });
778
+ const atomAmount = Number(balance?.amount || 0) / Math.pow(10, 6); // Convert uatom to ATOM
779
+ return atomAmount;
780
+ } catch (error) {
781
+ console.error('Error fetching balance:', error);
782
+ return null;
783
+ }
784
+ \`\`\`
785
+
786
+ ### 2. **.rpc.react** - React Hooks
787
+ These are React hooks for frontend applications. They provide:
788
+ - Automatic caching and refetching
789
+ - Loading states
790
+ - Error handling
791
+ - Integration with React Query
792
+
793
+ **Import Pattern**:
794
+ \`\`\`typescript
795
+ import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
796
+ import { useSend } from '${packageName}/cosmos/bank/v1beta1/tx.rpc.react';
797
+ \`\`\`
798
+
799
+ ## Chain Configuration Setup
800
+
801
+ ### Import Chain Registry Data
802
+ \`\`\`typescript
803
+ import { assetLists, chains } from "@chain-registry/v2";
804
+ \`\`\`
805
+
806
+ ### Basic Configuration
807
+ \`\`\`typescript
808
+ // Define your target chain
809
+ export const defaultChainName = 'cosmos'; // or 'osmosis', 'injective', etc.
810
+
811
+ // Find chain info from registry
812
+ export const defaultChain = chains.find((chain) => chain.chainName === defaultChainName);
813
+
814
+ // Get RPC endpoint
815
+ export const defaultRpcEndpoint = defaultChain?.apis?.rpc?.[0]?.address || 'http://localhost:26657';
816
+ \`\`\`
817
+
818
+ ## Detailed Examples Reference
819
+
820
+ ### Using src/telescope-examples Directory
821
+ When you need more specific implementation details or complex use cases, reference the example files in \`src/telescope-examples/\`. These are real-world examples for production usage.
822
+
823
+ ### Using src/tools Directory
824
+ The \`src/tools/\` directory contains MCP tool implementations that demonstrate how to use the telescope-examples in MCP tools. These tools show patterns for:
825
+ - Importing functions from telescope-examples
826
+ - Handling errors and returning proper MCP responses
827
+ - Working with blockchain data in MCP context
828
+
829
+ Each tool in \`src/tools/\` corresponds to functionality in \`src/telescope-examples/\` and shows how to bridge the gap between React hooks/utility functions and MCP tool implementations.
830
+
831
+ ## Important Notes
832
+
833
+ ### Function Categories Usage
834
+ - **Use .rpc.func** for: Server-side scripts, CLI tools, backend services
835
+ - **Use .rpc.react** for: React applications, frontend components with state management
836
+
837
+ ### Error Handling Patterns
838
+ \`\`\`typescript
839
+ // For .rpc.func
840
+ try {
841
+ const result = await getBalance(rpcEndpoint, { address, denom });
842
+ return result;
843
+ } catch (error) {
844
+ if (error.message.includes('not found')) {
845
+ return null; // Handle account not found
846
+ }
847
+ throw error; // Re-throw other errors
848
+ }
849
+ \`\`\`
850
+ `;
851
+
852
+ writeFileSync(join(mcpServerPath, 'src', 'prompts', 'codegen-usage.md'), codegenUsageContent);
853
+
854
+ // Generate agent-guidelines.md
855
+ const agentGuidelinesContent = `# MCP Agent Guidelines
856
+
857
+ ## Overview
858
+ These guidelines help MCP agents provide helpful, accurate, and safe blockchain interactions using the ${packageName} library.
859
+
860
+ ## General Principles
861
+
862
+ ### 1. Safety First
863
+ - **Never expose private keys or mnemonics**
864
+ - **Always validate addresses before operations**
865
+ - **Warn users about irreversible operations**
866
+ - **Explain risks (slashing, unbonding periods, etc.)**
867
+
868
+ ### 2. User-Friendly Communication
869
+ - **Convert base units to human-readable amounts** (uatom → ATOM)
870
+ - **Use clear, non-technical language when possible**
871
+ - **Provide context for blockchain-specific concepts**
872
+ - **Show approximate USD values when helpful**
873
+
874
+ ### 3. Accuracy and Reliability
875
+ - **Always handle errors gracefully**
876
+ - **Provide accurate information about fees and timing**
877
+ - **Double-check calculations and conversions**
878
+ - **Verify data freshness and warn about stale data**
879
+
880
+ ## Response Patterns
881
+
882
+ ### When User Asks About Balances
883
+ \`\`\`
884
+ ✅ Good Response:
885
+ "You have 12.5 ATOM (12,500,000 uatom) in your wallet. This is worth approximately $150 USD at current prices. You also have 0.05 ATOM available to pay for transaction fees."
886
+
887
+ ❌ Poor Response:
888
+ "Balance: 12500000"
889
+ \`\`\`
890
+
891
+ ## Data Formatting Guidelines
892
+
893
+ ### Amounts
894
+ Always convert from base units:
895
+ \`\`\`typescript
896
+ // Good
897
+ const atomAmount = parseInt(balance.amount) / 1_000_000;
898
+ return \`$\{atomAmount} ATOM\`;
899
+
900
+ // Bad
901
+ return \`$\{balance.amount} uatom\`;
902
+ \`\`\`
903
+
904
+ ### Addresses
905
+ Abbreviate long addresses for readability:
906
+ \`\`\`typescript
907
+ const formatAddress = (addr: string) => {
908
+ return \`$\{addr.slice(0, 10)}...$\{addr.slice(-4)}\`;
909
+ };
910
+ // cosmos1abc123...xyz9
911
+ \`\`\`
912
+
913
+ ## Security Guidelines
914
+
915
+ ### Address Validation
916
+ \`\`\`typescript
917
+ const validateCosmosAddress = (address: string): boolean => {
918
+ return address.startsWith('cosmos1') && address.length === 45;
919
+ };
920
+ \`\`\`
921
+
922
+ ### Amount Validation
923
+ \`\`\`typescript
924
+ const validateAmount = (amount: string): boolean => {
925
+ const num = parseFloat(amount);
926
+ return !isNaN(num) && num > 0 && num < 1e15; // Reasonable limits
927
+ };
928
+ \`\`\`
929
+ `;
930
+
931
+ writeFileSync(join(mcpServerPath, 'src', 'prompts', 'agent-guidelines.md'), agentGuidelinesContent);
932
+
933
+ // Copy chains.json from chain-registry (this is a large static file)
934
+ const chainsJsonContent = `[
935
+ {
936
+ "$schema": "../chain.schema.json",
937
+ "chainName": "cosmos",
938
+ "status": "live",
939
+ "networkType": "mainnet",
940
+ "prettyName": "Cosmos Hub",
941
+ "chainId": "cosmoshub-4",
942
+ "bech32Prefix": "cosmos",
943
+ "daemonName": "gaiad",
944
+ "nodeHome": "$HOME/.gaia",
945
+ "slip44": 118,
946
+ "apis": {
947
+ "rpc": [
948
+ {
949
+ "address": "https://cosmos-rpc.quickapi.com:443"
950
+ }
951
+ ],
952
+ "rest": [
953
+ {
954
+ "address": "https://cosmos-rest.quickapi.com:443"
955
+ }
956
+ ]
957
+ }
958
+ },
959
+ {
960
+ "chainName": "osmosis",
961
+ "status": "live",
962
+ "networkType": "mainnet",
963
+ "prettyName": "Osmosis",
964
+ "chainId": "osmosis-1",
965
+ "bech32Prefix": "osmo",
966
+ "daemonName": "osmosisd",
967
+ "nodeHome": "$HOME/.osmosisd",
968
+ "slip44": 118,
969
+ "apis": {
970
+ "rpc": [
971
+ {
972
+ "address": "https://osmosis-rpc.quickapi.com:443"
973
+ }
974
+ ],
975
+ "rest": [
976
+ {
977
+ "address": "https://osmosis-rest.quickapi.com:443"
978
+ }
979
+ ]
980
+ }
981
+ },
982
+ {
983
+ "chainName": "injective",
984
+ "status": "live",
985
+ "networkType": "mainnet",
986
+ "prettyName": "Injective",
987
+ "chainId": "injective-1",
988
+ "bech32Prefix": "inj",
989
+ "daemonName": "injectived",
990
+ "nodeHome": "$HOME/.injectived",
991
+ "slip44": 60,
992
+ "apis": {
993
+ "rpc": [
994
+ {
995
+ "address": "https://injective-rpc.quickapi.com:443"
996
+ }
997
+ ],
998
+ "rest": [
999
+ {
1000
+ "address": "https://injective-rest.quickapi.com:443"
1001
+ }
1002
+ ]
1003
+ }
1004
+ }
1005
+ ]`;
1006
+
1007
+ writeFileSync(join(mcpServerPath, 'src', 'prompts', 'chains.json'), chainsJsonContent);
1008
+ }
1009
+
1010
+ function generateTelescopeExamples(mcpServerPath: string, packageName: string) {
1011
+ const exampleFiles = [
1012
+ {
1013
+ name: 'config-example.ts',
1014
+ content: `import { assetLists, chains } from "@chain-registry/v2";
1015
+
1016
+ /**
1017
+ * mainnet: 'cosmos'
1018
+ * testnet: 'cosmoshub-testnet'
1019
+ * mainnet rpc: 'https://cosmos-rpc.quickapi.com:443'
1020
+ * testnet rpc: 'https://rpc.testnet.cosmos.network:443'
1021
+ */
1022
+ export const defaultChainName = 'cosmos'
1023
+ export const defaultRpcEndpoint = 'https://cosmos-rpc.quickapi.com:443'
1024
+
1025
+ export const defaultChain = chains.find((chain) => chain.chainName === defaultChainName)
1026
+
1027
+ export const defaultAssetList = assetLists.find((assetList) => assetList.chainName === defaultChainName)
1028
+ `
1029
+ },
1030
+ {
1031
+ name: 'useBalance.ts',
1032
+ content: `import { useChain } from '@interchain-kit/react';
1033
+ import { defaultContext } from '@tanstack/react-query';
1034
+ import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
1035
+
1036
+ export const useBalance = (
1037
+ chainName: string,
1038
+ enabled: boolean = true,
1039
+ displayDenom?: string
1040
+ ) => {
1041
+ const { address, assetList } = useChain(chainName);
1042
+
1043
+ let denom = assetList?.assets[0].base!;
1044
+ for (const asset of assetList?.assets || []) {
1045
+ if (asset.display.toLowerCase() === displayDenom?.toLowerCase()) {
1046
+ denom = asset.base;
1047
+ break;
1048
+ }
1049
+ }
1050
+
1051
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443'; // Use dynamic endpoint
1052
+
1053
+ const isReady = !!address && !!rpcEndpoint;
1054
+
1055
+ const balanceQuery = useGetBalance({
1056
+ request: {
1057
+ denom,
1058
+ address: address || '',
1059
+ },
1060
+ options: {
1061
+ enabled: isReady && enabled,
1062
+ select: ({ balance }) => balance,
1063
+ context: defaultContext,
1064
+ },
1065
+ clientResolver: rpcEndpoint,
1066
+ customizedQueryKey: ['balance', address, denom],
1067
+ });
1068
+
1069
+ return {
1070
+ balance: balanceQuery.data,
1071
+ isLoading: balanceQuery.isFetching,
1072
+ };
1073
+ };
1074
+ `
1075
+ },
1076
+ {
1077
+ name: 'useBalanceReact.ts',
1078
+ content: `import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
1079
+ import { defaultRpcEndpoint as rpcEndpoint } from '@/config';
1080
+ import BigNumber from 'bignumber.js';
1081
+ import { defaultAssetList } from '@/config';
1082
+ import { defaultContext } from '@tanstack/react-query';
1083
+
1084
+ export default function useBalance({ address }: { address: string }) {
1085
+ const coin = defaultAssetList?.assets[0];
1086
+
1087
+ const denom = coin!.base!;
1088
+
1089
+ const COIN_DISPLAY_EXPONENT = coin!.denomUnits.find(
1090
+ (unit) => unit.denom === coin!.display
1091
+ )?.exponent as number;
1092
+
1093
+ const {
1094
+ data: balance,
1095
+ isSuccess: isBalanceLoaded,
1096
+ isLoading: isFetchingBalance,
1097
+ refetch: refetchBalance,
1098
+ } = useGetBalance({
1099
+ request: {
1100
+ address: address || '',
1101
+ denom,
1102
+ },
1103
+ options: {
1104
+ context: defaultContext,
1105
+ enabled: !!address,
1106
+ select: ({ balance }) =>
1107
+ new BigNumber(balance?.amount ?? 0).multipliedBy(
1108
+ 10 ** -COIN_DISPLAY_EXPONENT
1109
+ ),
1110
+ staleTime: 0,
1111
+ },
1112
+ clientResolver: rpcEndpoint,
1113
+ });
1114
+
1115
+ return {
1116
+ balance,
1117
+ isBalanceLoaded,
1118
+ isFetchingBalance,
1119
+ refetchBalance,
1120
+ };
1121
+ }
1122
+ `
1123
+ },
1124
+ {
1125
+ name: 'useBalanceFunc.ts',
1126
+ content: `import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';
1127
+ import { defaultRpcEndpoint } from '@/config';
1128
+
1129
+ export const useBalanceFunc = async (address: string, denom: string) => {
1130
+ try {
1131
+ const { balance } = await getBalance(defaultRpcEndpoint, {
1132
+ address,
1133
+ denom,
1134
+ });
1135
+
1136
+ return {
1137
+ balance: balance?.amount || '0',
1138
+ denom: balance?.denom || denom,
1139
+ };
1140
+ } catch (error) {
1141
+ console.error('Error fetching balance:', error);
1142
+ return {
1143
+ balance: '0',
1144
+ denom,
1145
+ };
1146
+ }
1147
+ };
1148
+ `
1149
+ },
1150
+ {
1151
+ name: 'getBalance.ts',
1152
+ content: `import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';
1153
+ import { send } from '${packageName}/cosmos/bank/v1beta1/tx.rpc.func';
1154
+ import { MsgSend } from '${packageName}/cosmos/bank/v1beta1/tx';
1155
+
1156
+ const main = async () => {
1157
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1158
+ const denom = 'uatom';
1159
+ const address = 'cosmos1...'; // Your address here
1160
+
1161
+ // Query balance
1162
+ const { balance } = await getBalance(rpcEndpoint, {
1163
+ address,
1164
+ denom,
1165
+ });
1166
+
1167
+ console.log(\`Balance: \${balance?.amount} \${denom}\`);
1168
+
1169
+ // Example: Send transaction (requires signer setup)
1170
+ /*
1171
+ const fee = {
1172
+ amount: [{ denom, amount: '5000' }],
1173
+ gas: '200000',
1174
+ };
1175
+
1176
+ const token = {
1177
+ amount: '1000000',
1178
+ denom,
1179
+ };
1180
+
1181
+ const msg = MsgSend.fromPartial({
1182
+ fromAddress: address,
1183
+ toAddress: 'cosmos1recipient...',
1184
+ amount: [token],
1185
+ });
1186
+
1187
+ // const tx = await send(signer, address, msg, fee, 'Payment');
1188
+ */
1189
+ };
1190
+
1191
+ main().catch(console.error);
1192
+ `
1193
+ },
1194
+ {
1195
+ name: 'useAssets.ts',
1196
+ content: `import { useMemo } from 'react';
1197
+ import { useChain } from '@interchain-kit/react';
1198
+ import { defaultContext } from '@tanstack/react-query';
1199
+ import BigNumber from 'bignumber.js';
1200
+ import { useGetAllBalances } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
1201
+ import { Coin } from '${packageName}/types';
1202
+
1203
+ export const useAssets = (chainName: string) => {
1204
+ const { address } = useChain(chainName);
1205
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1206
+
1207
+ const isReady = !!address && !!rpcEndpoint;
1208
+
1209
+ const allBalancesQuery = useGetAllBalances({
1210
+ request: {
1211
+ address: address || '',
1212
+ pagination: {
1213
+ key: new Uint8Array(),
1214
+ offset: 0n,
1215
+ limit: 100n,
1216
+ countTotal: true,
1217
+ reverse: false,
1218
+ },
1219
+ resolveDenom: false,
1220
+ },
1221
+ options: {
1222
+ enabled: isReady,
1223
+ select: ({ balances }) => balances || [],
1224
+ context: defaultContext,
1225
+ },
1226
+ clientResolver: rpcEndpoint,
1227
+ customizedQueryKey: ['allBalances', address],
1228
+ });
1229
+
1230
+ const data = useMemo(() => {
1231
+ if (!allBalancesQuery.data) return;
1232
+
1233
+ const assets = allBalancesQuery.data.map(({ amount, denom }) => ({
1234
+ symbol: denom.toUpperCase(),
1235
+ displayAmount: new BigNumber(amount).dividedBy(1e6).toString(),
1236
+ amount,
1237
+ denom,
1238
+ }));
1239
+
1240
+ return { assets };
1241
+ }, [allBalancesQuery.data]);
1242
+
1243
+ return {
1244
+ data,
1245
+ isLoading: allBalancesQuery.isLoading,
1246
+ refetch: allBalancesQuery.refetch
1247
+ };
1248
+ };
1249
+ `
1250
+ },
1251
+ {
1252
+ name: 'useStakingData.ts',
1253
+ content: `import { useMemo } from 'react';
1254
+ import { useChain } from '@interchain-kit/react';
1255
+ import BigNumber from 'bignumber.js';
1256
+ import {
1257
+ BondStatus,
1258
+ bondStatusToJSON,
1259
+ } from '${packageName}/cosmos/staking/v1beta1/staking';
1260
+ import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
1261
+ import {
1262
+ useGetDelegatorValidators,
1263
+ useGetDelegatorDelegations,
1264
+ useGetValidators,
1265
+ useGetParams as useStakingParams,
1266
+ useGetPool,
1267
+ } from '${packageName}/cosmos/staking/v1beta1/query.rpc.react';
1268
+ import {
1269
+ useGetDelegationTotalRewards,
1270
+ useGetParams as useDistributionParams,
1271
+ } from '${packageName}/cosmos/distribution/v1beta1/query.rpc.react';
1272
+ import { useGetAnnualProvisions } from '${packageName}/cosmos/mint/v1beta1/query.rpc.react';
1273
+ import { defaultContext } from '@tanstack/react-query';
1274
+
1275
+ export const useStakingData = (chainName: string) => {
1276
+ const { address, assetList } = useChain(chainName);
1277
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1278
+
1279
+ const coin = assetList?.assets[0];
1280
+ const denom = coin?.base || 'uatom';
1281
+
1282
+ const isDataQueryEnabled = !!address && !!rpcEndpoint;
1283
+
1284
+ const balanceQuery = useGetBalance({
1285
+ request: {
1286
+ address: address || '',
1287
+ denom,
1288
+ },
1289
+ options: {
1290
+ context: defaultContext,
1291
+ enabled: isDataQueryEnabled,
1292
+ select: ({ balance }) => balance?.amount || '0',
1293
+ refetchOnMount: 'always',
1294
+ },
1295
+ clientResolver: rpcEndpoint,
1296
+ });
1297
+
1298
+ const validatorsQuery = useGetValidators({
1299
+ request: {
1300
+ status: bondStatusToJSON(BondStatus.BOND_STATUS_BONDED),
1301
+ pagination: {
1302
+ key: new Uint8Array(),
1303
+ offset: 0n,
1304
+ limit: 200n,
1305
+ countTotal: true,
1306
+ reverse: false,
1307
+ },
1308
+ },
1309
+ options: {
1310
+ context: defaultContext,
1311
+ enabled: isDataQueryEnabled,
1312
+ select: ({ validators }) => {
1313
+ return validators.sort((a, b) =>
1314
+ new BigNumber(b.tokens).minus(a.tokens).toNumber(),
1315
+ );
1316
+ },
1317
+ },
1318
+ clientResolver: rpcEndpoint,
1319
+ customizedQueryKey: ['validators', chainName],
1320
+ });
1321
+
1322
+ const delegationsQuery = useGetDelegatorDelegations({
1323
+ request: {
1324
+ delegatorAddr: address || '',
1325
+ pagination: {
1326
+ key: new Uint8Array(),
1327
+ offset: 0n,
1328
+ limit: 100n,
1329
+ countTotal: true,
1330
+ reverse: false,
1331
+ },
1332
+ },
1333
+ options: {
1334
+ context: defaultContext,
1335
+ enabled: isDataQueryEnabled,
1336
+ select: ({ delegationResponses }) => delegationResponses,
1337
+ },
1338
+ clientResolver: rpcEndpoint,
1339
+ });
1340
+
1341
+ const rewardsQuery = useGetDelegationTotalRewards({
1342
+ request: {
1343
+ delegatorAddress: address || '',
1344
+ },
1345
+ options: {
1346
+ context: defaultContext,
1347
+ enabled: isDataQueryEnabled,
1348
+ select: (data) => data,
1349
+ },
1350
+ clientResolver: rpcEndpoint,
1351
+ });
1352
+
1353
+ const allQueries = {
1354
+ balance: balanceQuery,
1355
+ validators: validatorsQuery,
1356
+ delegations: delegationsQuery,
1357
+ rewards: rewardsQuery,
1358
+ };
1359
+
1360
+ const isLoading = Object.values(allQueries).some(
1361
+ ({ isLoading }) => isLoading,
1362
+ );
1363
+
1364
+ const data = useMemo(() => {
1365
+ if (isLoading) return;
1366
+
1367
+ return {
1368
+ balance: balanceQuery.data,
1369
+ validators: validatorsQuery.data,
1370
+ delegations: delegationsQuery.data,
1371
+ rewards: rewardsQuery.data,
1372
+ };
1373
+ }, [isLoading, balanceQuery.data, validatorsQuery.data, delegationsQuery.data, rewardsQuery.data]);
1374
+
1375
+ const refetch = () => {
1376
+ Object.values(allQueries).forEach((query) => query.refetch());
1377
+ };
1378
+
1379
+ return { data, isLoading, refetch };
1380
+ };
1381
+ `
1382
+ },
1383
+ {
1384
+ name: 'useValidators.ts',
1385
+ content: `import { useMemo } from 'react';
1386
+ import { BondStatus, bondStatusToJSON } from '${packageName}/cosmos/staking/v1beta1/staking';
1387
+ import { useGetValidators } from '${packageName}/cosmos/staking/v1beta1/query.rpc.react';
1388
+ import { defaultContext } from '@tanstack/react-query';
1389
+ import BigNumber from 'bignumber.js';
1390
+
1391
+ export const useValidators = (chainName: string) => {
1392
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1393
+
1394
+ const validatorsQuery = useGetValidators({
1395
+ request: {
1396
+ status: bondStatusToJSON(BondStatus.BOND_STATUS_BONDED),
1397
+ pagination: {
1398
+ key: new Uint8Array(),
1399
+ offset: 0n,
1400
+ limit: 200n,
1401
+ countTotal: true,
1402
+ reverse: false,
1403
+ },
1404
+ },
1405
+ options: {
1406
+ context: defaultContext,
1407
+ enabled: !!rpcEndpoint,
1408
+ select: ({ validators }) => {
1409
+ return validators
1410
+ .sort((a, b) => new BigNumber(b.tokens).minus(a.tokens).toNumber())
1411
+ .map((validator) => ({
1412
+ operatorAddress: validator.operatorAddress,
1413
+ moniker: validator.description?.moniker || '',
1414
+ tokens: validator.tokens,
1415
+ delegatorShares: validator.delegatorShares,
1416
+ commission: validator.commission?.commissionRates?.rate || '0',
1417
+ status: validator.status,
1418
+ jailed: validator.jailed,
1419
+ }));
1420
+ },
1421
+ },
1422
+ clientResolver: rpcEndpoint,
1423
+ customizedQueryKey: ['validators', chainName],
1424
+ });
1425
+
1426
+ return {
1427
+ data: validatorsQuery.data,
1428
+ isLoading: validatorsQuery.isLoading,
1429
+ refetch: validatorsQuery.refetch,
1430
+ };
1431
+ };
1432
+ `
1433
+ },
1434
+ {
1435
+ name: 'useVoting.ts',
1436
+ content: `import { useMemo } from 'react';
1437
+ import { useGetProposals } from '${packageName}/cosmos/gov/v1beta1/query.rpc.react';
1438
+ import { ProposalStatus, proposalStatusToJSON } from '${packageName}/cosmos/gov/v1beta1/gov';
1439
+ import { defaultContext } from '@tanstack/react-query';
1440
+
1441
+ export const useVoting = (chainName: string) => {
1442
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1443
+
1444
+ const proposalsQuery = useGetProposals({
1445
+ request: {
1446
+ proposalStatus: proposalStatusToJSON(ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD),
1447
+ voter: '',
1448
+ depositor: '',
1449
+ pagination: {
1450
+ key: new Uint8Array(),
1451
+ offset: 0n,
1452
+ limit: 50n,
1453
+ countTotal: true,
1454
+ reverse: true,
1455
+ },
1456
+ },
1457
+ options: {
1458
+ context: defaultContext,
1459
+ enabled: !!rpcEndpoint,
1460
+ select: ({ proposals }) => proposals,
1461
+ },
1462
+ clientResolver: rpcEndpoint,
1463
+ customizedQueryKey: ['proposals', chainName],
1464
+ });
1465
+
1466
+ const data = useMemo(() => {
1467
+ if (!proposalsQuery.data) return;
1468
+
1469
+ return {
1470
+ proposals: proposalsQuery.data.map((proposal) => ({
1471
+ proposalId: proposal.proposalId.toString(),
1472
+ title: proposal.content?.title || '',
1473
+ description: proposal.content?.description || '',
1474
+ status: proposal.status,
1475
+ submitTime: proposal.submitTime,
1476
+ votingStartTime: proposal.votingStartTime,
1477
+ votingEndTime: proposal.votingEndTime,
1478
+ })),
1479
+ };
1480
+ }, [proposalsQuery.data]);
1481
+
1482
+ return {
1483
+ data,
1484
+ isLoading: proposalsQuery.isLoading,
1485
+ refetch: proposalsQuery.refetch,
1486
+ };
1487
+ };
1488
+ `
1489
+ },
1490
+ {
1491
+ name: 'useVotingData.ts',
1492
+ content: `import { useMemo } from 'react';
1493
+ import { useChain } from '@interchain-kit/react';
1494
+ import {
1495
+ useGetProposals,
1496
+ useGetVote,
1497
+ useGetTallyResult,
1498
+ } from '${packageName}/cosmos/gov/v1beta1/query.rpc.react';
1499
+ import { ProposalStatus, proposalStatusToJSON } from '${packageName}/cosmos/gov/v1beta1/gov';
1500
+ import { defaultContext } from '@tanstack/react-query';
1501
+
1502
+ export const useVotingData = (chainName: string) => {
1503
+ const { address } = useChain(chainName);
1504
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1505
+
1506
+ const isEnabled = !!rpcEndpoint;
1507
+
1508
+ const proposalsQuery = useGetProposals({
1509
+ request: {
1510
+ proposalStatus: proposalStatusToJSON(ProposalStatus.PROPOSAL_STATUS_UNSPECIFIED),
1511
+ voter: '',
1512
+ depositor: '',
1513
+ pagination: {
1514
+ key: new Uint8Array(),
1515
+ offset: 0n,
1516
+ limit: 100n,
1517
+ countTotal: true,
1518
+ reverse: true,
1519
+ },
1520
+ },
1521
+ options: {
1522
+ context: defaultContext,
1523
+ enabled: isEnabled,
1524
+ select: ({ proposals }) => proposals,
1525
+ },
1526
+ clientResolver: rpcEndpoint,
1527
+ customizedQueryKey: ['allProposals', chainName],
1528
+ });
1529
+
1530
+ const activeProposals = useMemo(() => {
1531
+ return proposalsQuery.data?.filter(
1532
+ (proposal) => proposal.status === ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD
1533
+ ) || [];
1534
+ }, [proposalsQuery.data]);
1535
+
1536
+ const data = useMemo(() => {
1537
+ if (!proposalsQuery.data) return;
1538
+
1539
+ const categorized = {
1540
+ active: activeProposals,
1541
+ passed: proposalsQuery.data.filter(
1542
+ (p) => p.status === ProposalStatus.PROPOSAL_STATUS_PASSED
1543
+ ),
1544
+ rejected: proposalsQuery.data.filter(
1545
+ (p) => p.status === ProposalStatus.PROPOSAL_STATUS_REJECTED
1546
+ ),
1547
+ failed: proposalsQuery.data.filter(
1548
+ (p) => p.status === ProposalStatus.PROPOSAL_STATUS_FAILED
1549
+ ),
1550
+ };
1551
+
1552
+ return {
1553
+ proposals: proposalsQuery.data,
1554
+ categorized,
1555
+ activeCount: categorized.active.length,
1556
+ };
1557
+ }, [proposalsQuery.data, activeProposals]);
1558
+
1559
+ return {
1560
+ data,
1561
+ isLoading: proposalsQuery.isLoading,
1562
+ refetch: proposalsQuery.refetch,
1563
+ };
1564
+ };
1565
+ `
1566
+ },
1567
+ {
1568
+ name: 'useContractInfo.ts',
1569
+ content: `import { defaultContext } from '@tanstack/react-query';
1570
+ import { useGetContractInfo } from '${packageName}/cosmwasm/wasm/v1/query.rpc.react';
1571
+
1572
+ export const useContractInfo = ({
1573
+ contractAddress,
1574
+ enabled = true,
1575
+ }: {
1576
+ contractAddress: string;
1577
+ enabled?: boolean;
1578
+ }) => {
1579
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1580
+
1581
+ return useGetContractInfo({
1582
+ request: {
1583
+ address: contractAddress,
1584
+ },
1585
+ options: {
1586
+ enabled: !!contractAddress && !!rpcEndpoint && enabled,
1587
+ context: defaultContext,
1588
+ },
1589
+ clientResolver: rpcEndpoint,
1590
+ });
1591
+ };
1592
+ `
1593
+ },
1594
+ {
1595
+ name: 'useQueryContract.ts',
1596
+ content: `import { defaultContext } from '@tanstack/react-query';
1597
+ import { useGetSmartContractState } from '${packageName}/cosmwasm/wasm/v1/query.rpc.react';
1598
+
1599
+ export const useQueryContract = ({
1600
+ contractAddress,
1601
+ queryMsg,
1602
+ enabled = true,
1603
+ }: {
1604
+ contractAddress: string;
1605
+ queryMsg: object;
1606
+ enabled?: boolean;
1607
+ }) => {
1608
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1609
+
1610
+ return useGetSmartContractState({
1611
+ request: {
1612
+ address: contractAddress,
1613
+ queryData: new TextEncoder().encode(JSON.stringify(queryMsg)),
1614
+ },
1615
+ options: {
1616
+ enabled: !!contractAddress && !!queryMsg && !!rpcEndpoint && enabled,
1617
+ context: defaultContext,
1618
+ select: ({ data }) => {
1619
+ if (data) {
1620
+ return JSON.parse(new TextDecoder().decode(data));
1621
+ }
1622
+ return null;
1623
+ },
1624
+ },
1625
+ clientResolver: rpcEndpoint,
1626
+ });
1627
+ };
1628
+ `
1629
+ },
1630
+ {
1631
+ name: 'useCodeDetails.ts',
1632
+ content: `import { defaultContext } from '@tanstack/react-query';
1633
+ import { useGetCode } from '${packageName}/cosmwasm/wasm/v1/query.rpc.react';
1634
+
1635
+ export const useCodeDetails = ({
1636
+ codeId,
1637
+ enabled = true,
1638
+ }: {
1639
+ codeId: string | number;
1640
+ enabled?: boolean;
1641
+ }) => {
1642
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1643
+
1644
+ return useGetCode({
1645
+ request: {
1646
+ codeId: BigInt(codeId),
1647
+ },
1648
+ options: {
1649
+ enabled: !!codeId && !!rpcEndpoint && enabled,
1650
+ context: defaultContext,
1651
+ },
1652
+ clientResolver: rpcEndpoint,
1653
+ });
1654
+ };
1655
+ `
1656
+ },
1657
+ {
1658
+ name: 'useMyContracts.ts',
1659
+ content: `import { useMemo } from 'react';
1660
+ import { useChain } from '@interchain-kit/react';
1661
+ import { useGetContractsByCreator } from '${packageName}/cosmwasm/wasm/v1/query.rpc.react';
1662
+ import { defaultContext } from '@tanstack/react-query';
1663
+
1664
+ export const useMyContracts = (chainName: string) => {
1665
+ const { address } = useChain(chainName);
1666
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1667
+
1668
+ const contractsQuery = useGetContractsByCreator({
1669
+ request: {
1670
+ creatorAddress: address || '',
1671
+ pagination: {
1672
+ key: new Uint8Array(),
1673
+ offset: 0n,
1674
+ limit: 100n,
1675
+ countTotal: true,
1676
+ reverse: false,
1677
+ },
1678
+ },
1679
+ options: {
1680
+ enabled: !!address && !!rpcEndpoint,
1681
+ context: defaultContext,
1682
+ select: ({ contractAddresses }) => contractAddresses,
1683
+ },
1684
+ clientResolver: rpcEndpoint,
1685
+ });
1686
+
1687
+ const data = useMemo(() => {
1688
+ if (!contractsQuery.data) return;
1689
+
1690
+ return {
1691
+ contracts: contractsQuery.data.map((address) => ({
1692
+ address,
1693
+ label: \`Contract \${address.slice(0, 8)}...\`,
1694
+ })),
1695
+ count: contractsQuery.data.length,
1696
+ };
1697
+ }, [contractsQuery.data]);
1698
+
1699
+ return {
1700
+ data,
1701
+ isLoading: contractsQuery.isLoading,
1702
+ refetch: contractsQuery.refetch,
1703
+ };
1704
+ };
1705
+ `
1706
+ },
1707
+ {
1708
+ name: 'useGrants.ts',
1709
+ content: `import { useMemo } from 'react';
1710
+ import { useChain } from '@interchain-kit/react';
1711
+ import { useGetGranterGrants, useGetGranteeGrants } from '${packageName}/cosmos/authz/v1beta1/query.rpc.react';
1712
+ import { defaultContext } from '@tanstack/react-query';
1713
+
1714
+ export const useGrants = (chainName: string) => {
1715
+ const { address } = useChain(chainName);
1716
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1717
+
1718
+ const granterQuery = useGetGranterGrants({
1719
+ request: {
1720
+ granter: address || '',
1721
+ pagination: {
1722
+ key: new Uint8Array(),
1723
+ offset: 0n,
1724
+ limit: 100n,
1725
+ countTotal: true,
1726
+ reverse: false,
1727
+ },
1728
+ },
1729
+ options: {
1730
+ enabled: !!address && !!rpcEndpoint,
1731
+ context: defaultContext,
1732
+ select: ({ grants }) => grants,
1733
+ },
1734
+ clientResolver: rpcEndpoint,
1735
+ });
1736
+
1737
+ const granteeQuery = useGetGranteeGrants({
1738
+ request: {
1739
+ grantee: address || '',
1740
+ pagination: {
1741
+ key: new Uint8Array(),
1742
+ offset: 0n,
1743
+ limit: 100n,
1744
+ countTotal: true,
1745
+ reverse: false,
1746
+ },
1747
+ },
1748
+ options: {
1749
+ enabled: !!address && !!rpcEndpoint,
1750
+ context: defaultContext,
1751
+ select: ({ grants }) => grants,
1752
+ },
1753
+ clientResolver: rpcEndpoint,
1754
+ });
1755
+
1756
+ const data = useMemo(() => {
1757
+ return {
1758
+ granterGrants: granterQuery.data || [],
1759
+ granteeGrants: granteeQuery.data || [],
1760
+ };
1761
+ }, [granterQuery.data, granteeQuery.data]);
1762
+
1763
+ const isLoading = granterQuery.isLoading || granteeQuery.isLoading;
1764
+
1765
+ return {
1766
+ data,
1767
+ isLoading,
1768
+ refetch: () => {
1769
+ granterQuery.refetch();
1770
+ granteeQuery.refetch();
1771
+ },
1772
+ };
1773
+ };
1774
+ `
1775
+ },
1776
+ {
1777
+ name: 'useSendData.ts',
1778
+ content: `import { useMemo } from 'react';
1779
+ import { useChain } from '@interchain-kit/react';
1780
+ import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
1781
+ import { defaultContext } from '@tanstack/react-query';
1782
+ import BigNumber from 'bignumber.js';
1783
+
1784
+ export const useSendData = (chainName: string) => {
1785
+ const { address, assetList } = useChain(chainName);
1786
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1787
+
1788
+ const coin = assetList?.assets[0];
1789
+ const denom = coin?.base || 'uatom';
1790
+ const exponent = coin?.denomUnits?.find(unit => unit.denom === coin.display)?.exponent || 6;
1791
+
1792
+ const balanceQuery = useGetBalance({
1793
+ request: {
1794
+ address: address || '',
1795
+ denom,
1796
+ },
1797
+ options: {
1798
+ enabled: !!address && !!rpcEndpoint,
1799
+ context: defaultContext,
1800
+ select: ({ balance }) => {
1801
+ const amount = balance?.amount || '0';
1802
+ const displayAmount = new BigNumber(amount).dividedBy(Math.pow(10, exponent));
1803
+ return {
1804
+ amount,
1805
+ displayAmount: displayAmount.toString(),
1806
+ denom: balance?.denom || denom,
1807
+ };
1808
+ },
1809
+ },
1810
+ clientResolver: rpcEndpoint,
1811
+ });
1812
+
1813
+ const data = useMemo(() => {
1814
+ if (!balanceQuery.data) return;
1815
+
1816
+ return {
1817
+ balance: balanceQuery.data,
1818
+ canSend: new BigNumber(balanceQuery.data.amount).isGreaterThan(0),
1819
+ fee: {
1820
+ amount: '5000',
1821
+ displayAmount: new BigNumber('5000').dividedBy(Math.pow(10, exponent)).toString(),
1822
+ denom,
1823
+ },
1824
+ };
1825
+ }, [balanceQuery.data, denom, exponent]);
1826
+
1827
+ return {
1828
+ data,
1829
+ isLoading: balanceQuery.isLoading,
1830
+ refetch: balanceQuery.refetch,
1831
+ };
1832
+ };
1833
+ `
1834
+ },
1835
+ {
1836
+ name: 'useTotalAssets.ts',
1837
+ content: `import { useMemo } from 'react';
1838
+ import { useChain } from '@interchain-kit/react';
1839
+ import { useGetAllBalances } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
1840
+ import { defaultContext } from '@tanstack/react-query';
1841
+ import BigNumber from 'bignumber.js';
1842
+
1843
+ export const getPagination = (limit: bigint) => ({
1844
+ key: new Uint8Array(),
1845
+ offset: 0n,
1846
+ limit,
1847
+ countTotal: true,
1848
+ reverse: false,
1849
+ });
1850
+
1851
+ export const useTotalAssets = (chainName: string) => {
1852
+ const { address, assetList } = useChain(chainName);
1853
+ const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
1854
+
1855
+ const allBalancesQuery = useGetAllBalances({
1856
+ request: {
1857
+ address: address || '',
1858
+ pagination: getPagination(100n),
1859
+ resolveDenom: false,
1860
+ },
1861
+ options: {
1862
+ enabled: !!address && !!rpcEndpoint,
1863
+ select: ({ balances }) => balances || [],
1864
+ context: defaultContext,
1865
+ },
1866
+ clientResolver: rpcEndpoint,
1867
+ customizedQueryKey: ['totalAssets', address],
1868
+ });
1869
+
1870
+ const data = useMemo(() => {
1871
+ if (!allBalancesQuery.data) return;
1872
+
1873
+ const totalValue = allBalancesQuery.data.reduce((sum, balance) => {
1874
+ return sum.plus(balance.amount);
1875
+ }, new BigNumber(0));
1876
+
1877
+ return {
1878
+ balances: allBalancesQuery.data,
1879
+ totalCount: allBalancesQuery.data.length,
1880
+ totalValue: totalValue.toString(),
1881
+ nonZeroBalances: allBalancesQuery.data.filter(
1882
+ balance => new BigNumber(balance.amount).isGreaterThan(0)
1883
+ ),
1884
+ };
1885
+ }, [allBalancesQuery.data]);
1886
+
1887
+ return {
1888
+ data,
1889
+ isLoading: allBalancesQuery.isLoading,
1890
+ refetch: allBalancesQuery.refetch,
1891
+ };
1892
+ };
1893
+ `
1894
+ }
1895
+ ];
1896
+
1897
+ // Write all example files
1898
+ exampleFiles.forEach(({ name, content }) => {
1899
+ writeFileSync(join(mcpServerPath, 'src', 'telescope-examples', name), content);
1900
+ });
1901
+ }
1902
+