@unclick/mcp-server 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. package/dist/abn-tool.d.ts +3 -0
  2. package/dist/abn-tool.d.ts.map +1 -0
  3. package/dist/abn-tool.js +89 -0
  4. package/dist/abn-tool.js.map +1 -0
  5. package/dist/abuseipdb-tool.d.ts +4 -0
  6. package/dist/abuseipdb-tool.d.ts.map +1 -0
  7. package/dist/abuseipdb-tool.js +129 -0
  8. package/dist/abuseipdb-tool.js.map +1 -0
  9. package/dist/alphavantage-tool.d.ts +7 -0
  10. package/dist/alphavantage-tool.d.ts.map +1 -0
  11. package/dist/alphavantage-tool.js +208 -0
  12. package/dist/alphavantage-tool.js.map +1 -0
  13. package/dist/amber-tool.d.ts +4 -0
  14. package/dist/amber-tool.d.ts.map +1 -0
  15. package/dist/amber-tool.js +114 -0
  16. package/dist/amber-tool.js.map +1 -0
  17. package/dist/australiapost-tool.d.ts +4 -0
  18. package/dist/australiapost-tool.d.ts.map +1 -0
  19. package/dist/australiapost-tool.js +130 -0
  20. package/dist/australiapost-tool.js.map +1 -0
  21. package/dist/bandsintown-tool.d.ts +4 -0
  22. package/dist/bandsintown-tool.d.ts.map +1 -0
  23. package/dist/bandsintown-tool.js +76 -0
  24. package/dist/bandsintown-tool.js.map +1 -0
  25. package/dist/bungie-tool.d.ts +5 -0
  26. package/dist/bungie-tool.d.ts.map +1 -0
  27. package/dist/bungie-tool.js +138 -0
  28. package/dist/bungie-tool.js.map +1 -0
  29. package/dist/calculator-tool.d.ts +6 -0
  30. package/dist/calculator-tool.d.ts.map +1 -0
  31. package/dist/calculator-tool.js +196 -0
  32. package/dist/calculator-tool.js.map +1 -0
  33. package/dist/carboninterface-tool.d.ts +5 -0
  34. package/dist/carboninterface-tool.d.ts.map +1 -0
  35. package/dist/carboninterface-tool.js +143 -0
  36. package/dist/carboninterface-tool.js.map +1 -0
  37. package/dist/chessdotcom-tool.d.ts +6 -0
  38. package/dist/chessdotcom-tool.d.ts.map +1 -0
  39. package/dist/chessdotcom-tool.js +183 -0
  40. package/dist/chessdotcom-tool.js.map +1 -0
  41. package/dist/client.js +1 -1
  42. package/dist/clockify-tool.d.ts +2 -0
  43. package/dist/clockify-tool.d.ts.map +1 -0
  44. package/dist/clockify-tool.js +155 -0
  45. package/dist/clockify-tool.js.map +1 -0
  46. package/dist/coingecko-tool.d.ts +7 -0
  47. package/dist/coingecko-tool.d.ts.map +1 -0
  48. package/dist/coingecko-tool.js +176 -0
  49. package/dist/coingecko-tool.js.map +1 -0
  50. package/dist/coinmarketcap-tool.d.ts +6 -0
  51. package/dist/coinmarketcap-tool.d.ts.map +1 -0
  52. package/dist/coinmarketcap-tool.js +168 -0
  53. package/dist/coinmarketcap-tool.js.map +1 -0
  54. package/dist/color-tool.d.ts +6 -0
  55. package/dist/color-tool.d.ts.map +1 -0
  56. package/dist/color-tool.js +391 -0
  57. package/dist/color-tool.js.map +1 -0
  58. package/dist/connectors/bluesky.d.ts +3 -0
  59. package/dist/connectors/bluesky.d.ts.map +1 -0
  60. package/dist/connectors/bluesky.js +26 -0
  61. package/dist/connectors/bluesky.js.map +1 -0
  62. package/dist/connectors/discogs.d.ts +3 -0
  63. package/dist/connectors/discogs.d.ts.map +1 -0
  64. package/dist/connectors/discogs.js +18 -0
  65. package/dist/connectors/discogs.js.map +1 -0
  66. package/dist/connectors/discord.d.ts +3 -0
  67. package/dist/connectors/discord.d.ts.map +1 -0
  68. package/dist/connectors/discord.js +18 -0
  69. package/dist/connectors/discord.js.map +1 -0
  70. package/dist/connectors/guardian.d.ts +3 -0
  71. package/dist/connectors/guardian.d.ts.map +1 -0
  72. package/dist/connectors/guardian.js +18 -0
  73. package/dist/connectors/guardian.js.map +1 -0
  74. package/dist/connectors/index.d.ts +39 -0
  75. package/dist/connectors/index.d.ts.map +1 -0
  76. package/dist/connectors/index.js +23 -0
  77. package/dist/connectors/index.js.map +1 -0
  78. package/dist/connectors/lastfm.d.ts +3 -0
  79. package/dist/connectors/lastfm.d.ts.map +1 -0
  80. package/dist/connectors/lastfm.js +18 -0
  81. package/dist/connectors/lastfm.js.map +1 -0
  82. package/dist/connectors/mastodon.d.ts +3 -0
  83. package/dist/connectors/mastodon.d.ts.map +1 -0
  84. package/dist/connectors/mastodon.js +26 -0
  85. package/dist/connectors/mastodon.js.map +1 -0
  86. package/dist/connectors/newsapi.d.ts +3 -0
  87. package/dist/connectors/newsapi.d.ts.map +1 -0
  88. package/dist/connectors/newsapi.js +18 -0
  89. package/dist/connectors/newsapi.js.map +1 -0
  90. package/dist/connectors/ptv.d.ts +3 -0
  91. package/dist/connectors/ptv.d.ts.map +1 -0
  92. package/dist/connectors/ptv.js +26 -0
  93. package/dist/connectors/ptv.js.map +1 -0
  94. package/dist/connectors/reddit.d.ts +3 -0
  95. package/dist/connectors/reddit.d.ts.map +1 -0
  96. package/dist/connectors/reddit.js +28 -0
  97. package/dist/connectors/reddit.js.map +1 -0
  98. package/dist/connectors/seatgeek.d.ts +3 -0
  99. package/dist/connectors/seatgeek.d.ts.map +1 -0
  100. package/dist/connectors/seatgeek.js +18 -0
  101. package/dist/connectors/seatgeek.js.map +1 -0
  102. package/dist/connectors/shopify.d.ts +3 -0
  103. package/dist/connectors/shopify.d.ts.map +1 -0
  104. package/dist/connectors/shopify.js +38 -0
  105. package/dist/connectors/shopify.js.map +1 -0
  106. package/dist/connectors/slack.d.ts +3 -0
  107. package/dist/connectors/slack.d.ts.map +1 -0
  108. package/dist/connectors/slack.js +18 -0
  109. package/dist/connectors/slack.js.map +1 -0
  110. package/dist/connectors/telegram.d.ts +3 -0
  111. package/dist/connectors/telegram.d.ts.map +1 -0
  112. package/dist/connectors/telegram.js +18 -0
  113. package/dist/connectors/telegram.js.map +1 -0
  114. package/dist/connectors/ticketmaster.d.ts +3 -0
  115. package/dist/connectors/ticketmaster.d.ts.map +1 -0
  116. package/dist/connectors/ticketmaster.js +18 -0
  117. package/dist/connectors/ticketmaster.js.map +1 -0
  118. package/dist/connectors/twitch.d.ts +3 -0
  119. package/dist/connectors/twitch.d.ts.map +1 -0
  120. package/dist/connectors/twitch.js +26 -0
  121. package/dist/connectors/twitch.js.map +1 -0
  122. package/dist/connectors/xero.d.ts +3 -0
  123. package/dist/connectors/xero.d.ts.map +1 -0
  124. package/dist/connectors/xero.js +36 -0
  125. package/dist/connectors/xero.js.map +1 -0
  126. package/dist/connectors/yelp.d.ts +3 -0
  127. package/dist/connectors/yelp.d.ts.map +1 -0
  128. package/dist/connectors/yelp.js +18 -0
  129. package/dist/connectors/yelp.js.map +1 -0
  130. package/dist/datetime-tool.d.ts +8 -0
  131. package/dist/datetime-tool.d.ts.map +1 -0
  132. package/dist/datetime-tool.js +263 -0
  133. package/dist/datetime-tool.js.map +1 -0
  134. package/dist/deezer-tool.d.ts +7 -0
  135. package/dist/deezer-tool.d.ts.map +1 -0
  136. package/dist/deezer-tool.js +142 -0
  137. package/dist/deezer-tool.js.map +1 -0
  138. package/dist/discogs-tool.d.ts +7 -0
  139. package/dist/discogs-tool.d.ts.map +1 -0
  140. package/dist/discogs-tool.js +138 -0
  141. package/dist/discogs-tool.js.map +1 -0
  142. package/dist/domain-tool.d.ts +4 -0
  143. package/dist/domain-tool.d.ts.map +1 -0
  144. package/dist/domain-tool.js +155 -0
  145. package/dist/domain-tool.js.map +1 -0
  146. package/dist/ebird-tool.d.ts +5 -0
  147. package/dist/ebird-tool.d.ts.map +1 -0
  148. package/dist/ebird-tool.js +128 -0
  149. package/dist/ebird-tool.js.map +1 -0
  150. package/dist/email-tool.d.ts +8 -0
  151. package/dist/email-tool.d.ts.map +1 -0
  152. package/dist/email-tool.js +376 -0
  153. package/dist/email-tool.js.map +1 -0
  154. package/dist/espn-tool.d.ts +8 -0
  155. package/dist/espn-tool.d.ts.map +1 -0
  156. package/dist/espn-tool.js +147 -0
  157. package/dist/espn-tool.js.map +1 -0
  158. package/dist/eventbrite-tool.d.ts +7 -0
  159. package/dist/eventbrite-tool.d.ts.map +1 -0
  160. package/dist/eventbrite-tool.js +134 -0
  161. package/dist/eventbrite-tool.js.map +1 -0
  162. package/dist/feedly-tool.d.ts +2 -0
  163. package/dist/feedly-tool.d.ts.map +1 -0
  164. package/dist/feedly-tool.js +152 -0
  165. package/dist/feedly-tool.js.map +1 -0
  166. package/dist/foursquare-tool.d.ts +6 -0
  167. package/dist/foursquare-tool.d.ts.map +1 -0
  168. package/dist/foursquare-tool.js +102 -0
  169. package/dist/foursquare-tool.js.map +1 -0
  170. package/dist/fpl-tool.d.ts +8 -0
  171. package/dist/fpl-tool.d.ts.map +1 -0
  172. package/dist/fpl-tool.js +195 -0
  173. package/dist/fpl-tool.js.map +1 -0
  174. package/dist/genius-tool.d.ts +5 -0
  175. package/dist/genius-tool.d.ts.map +1 -0
  176. package/dist/genius-tool.js +62 -0
  177. package/dist/genius-tool.js.map +1 -0
  178. package/dist/guardian-tool.d.ts +6 -0
  179. package/dist/guardian-tool.d.ts.map +1 -0
  180. package/dist/guardian-tool.js +124 -0
  181. package/dist/guardian-tool.js.map +1 -0
  182. package/dist/hackernews-tool.d.ts +8 -0
  183. package/dist/hackernews-tool.d.ts.map +1 -0
  184. package/dist/hackernews-tool.js +96 -0
  185. package/dist/hackernews-tool.js.map +1 -0
  186. package/dist/haveibeenpwned-tool.d.ts +4 -0
  187. package/dist/haveibeenpwned-tool.d.ts.map +1 -0
  188. package/dist/haveibeenpwned-tool.js +162 -0
  189. package/dist/haveibeenpwned-tool.js.map +1 -0
  190. package/dist/hunter-tool.d.ts +4 -0
  191. package/dist/hunter-tool.d.ts.map +1 -0
  192. package/dist/hunter-tool.js +148 -0
  193. package/dist/hunter-tool.js.map +1 -0
  194. package/dist/instapaper-tool.d.ts +2 -0
  195. package/dist/instapaper-tool.d.ts.map +1 -0
  196. package/dist/instapaper-tool.js +257 -0
  197. package/dist/instapaper-tool.js.map +1 -0
  198. package/dist/ipapi-tool.d.ts +3 -0
  199. package/dist/ipapi-tool.d.ts.map +1 -0
  200. package/dist/ipapi-tool.js +78 -0
  201. package/dist/ipapi-tool.js.map +1 -0
  202. package/dist/ipaustralia-tool.d.ts +4 -0
  203. package/dist/ipaustralia-tool.d.ts.map +1 -0
  204. package/dist/ipaustralia-tool.js +138 -0
  205. package/dist/ipaustralia-tool.js.map +1 -0
  206. package/dist/lastfm-tool.d.ts +8 -0
  207. package/dist/lastfm-tool.d.ts.map +1 -0
  208. package/dist/lastfm-tool.js +169 -0
  209. package/dist/lastfm-tool.js.map +1 -0
  210. package/dist/lego-tool.d.ts +8 -0
  211. package/dist/lego-tool.d.ts.map +1 -0
  212. package/dist/lego-tool.js +235 -0
  213. package/dist/lego-tool.js.map +1 -0
  214. package/dist/lichess-tool.d.ts +6 -0
  215. package/dist/lichess-tool.d.ts.map +1 -0
  216. package/dist/lichess-tool.js +211 -0
  217. package/dist/lichess-tool.js.map +1 -0
  218. package/dist/meal-tool.d.ts +8 -0
  219. package/dist/meal-tool.d.ts.map +1 -0
  220. package/dist/meal-tool.js +143 -0
  221. package/dist/meal-tool.js.map +1 -0
  222. package/dist/monica-tool.d.ts +2 -0
  223. package/dist/monica-tool.d.ts.map +1 -0
  224. package/dist/monica-tool.js +160 -0
  225. package/dist/monica-tool.js.map +1 -0
  226. package/dist/musicbrainz-tool.d.ts +6 -0
  227. package/dist/musicbrainz-tool.d.ts.map +1 -0
  228. package/dist/musicbrainz-tool.js +65 -0
  229. package/dist/musicbrainz-tool.js.map +1 -0
  230. package/dist/nasa-tool.d.ts +6 -0
  231. package/dist/nasa-tool.d.ts.map +1 -0
  232. package/dist/nasa-tool.js +158 -0
  233. package/dist/nasa-tool.js.map +1 -0
  234. package/dist/newsapi-tool.d.ts +4 -0
  235. package/dist/newsapi-tool.d.ts.map +1 -0
  236. package/dist/newsapi-tool.js +108 -0
  237. package/dist/newsapi-tool.js.map +1 -0
  238. package/dist/notion-tool.d.ts +2 -0
  239. package/dist/notion-tool.d.ts.map +1 -0
  240. package/dist/notion-tool.js +167 -0
  241. package/dist/notion-tool.js.map +1 -0
  242. package/dist/numbers-tool.d.ts +3 -0
  243. package/dist/numbers-tool.d.ts.map +1 -0
  244. package/dist/numbers-tool.js +47 -0
  245. package/dist/numbers-tool.js.map +1 -0
  246. package/dist/nvd-tool.d.ts +4 -0
  247. package/dist/nvd-tool.d.ts.map +1 -0
  248. package/dist/nvd-tool.js +150 -0
  249. package/dist/nvd-tool.js.map +1 -0
  250. package/dist/omdb-tool.d.ts +4 -0
  251. package/dist/omdb-tool.d.ts.map +1 -0
  252. package/dist/omdb-tool.js +62 -0
  253. package/dist/omdb-tool.js.map +1 -0
  254. package/dist/openaq-tool.d.ts +5 -0
  255. package/dist/openaq-tool.d.ts.map +1 -0
  256. package/dist/openaq-tool.js +141 -0
  257. package/dist/openaq-tool.js.map +1 -0
  258. package/dist/openexchangerates-tool.d.ts +5 -0
  259. package/dist/openexchangerates-tool.d.ts.map +1 -0
  260. package/dist/openexchangerates-tool.js +101 -0
  261. package/dist/openexchangerates-tool.js.map +1 -0
  262. package/dist/openf1-tool.d.ts +9 -0
  263. package/dist/openf1-tool.d.ts.map +1 -0
  264. package/dist/openf1-tool.js +194 -0
  265. package/dist/openf1-tool.js.map +1 -0
  266. package/dist/openfoodfacts-tool.d.ts +5 -0
  267. package/dist/openfoodfacts-tool.d.ts.map +1 -0
  268. package/dist/openfoodfacts-tool.js +106 -0
  269. package/dist/openfoodfacts-tool.js.map +1 -0
  270. package/dist/openlibrary-tool.d.ts +7 -0
  271. package/dist/openlibrary-tool.d.ts.map +1 -0
  272. package/dist/openlibrary-tool.js +67 -0
  273. package/dist/openlibrary-tool.js.map +1 -0
  274. package/dist/openmeteo-tool.d.ts +4 -0
  275. package/dist/openmeteo-tool.d.ts.map +1 -0
  276. package/dist/openmeteo-tool.js +160 -0
  277. package/dist/openmeteo-tool.js.map +1 -0
  278. package/dist/pandascore-tool.d.ts +6 -0
  279. package/dist/pandascore-tool.d.ts.map +1 -0
  280. package/dist/pandascore-tool.js +239 -0
  281. package/dist/pandascore-tool.js.map +1 -0
  282. package/dist/podcastindex-tool.d.ts +7 -0
  283. package/dist/podcastindex-tool.d.ts.map +1 -0
  284. package/dist/podcastindex-tool.js +98 -0
  285. package/dist/podcastindex-tool.js.map +1 -0
  286. package/dist/ptv-tool.d.ts +6 -0
  287. package/dist/ptv-tool.d.ts.map +1 -0
  288. package/dist/ptv-tool.js +95 -0
  289. package/dist/ptv-tool.js.map +1 -0
  290. package/dist/radiobrowser-tool.d.ts +7 -0
  291. package/dist/radiobrowser-tool.d.ts.map +1 -0
  292. package/dist/radiobrowser-tool.js +125 -0
  293. package/dist/radiobrowser-tool.js.map +1 -0
  294. package/dist/raindrop-tool.d.ts +2 -0
  295. package/dist/raindrop-tool.d.ts.map +1 -0
  296. package/dist/raindrop-tool.js +137 -0
  297. package/dist/raindrop-tool.js.map +1 -0
  298. package/dist/random-tool.d.ts +9 -0
  299. package/dist/random-tool.d.ts.map +1 -0
  300. package/dist/random-tool.js +198 -0
  301. package/dist/random-tool.js.map +1 -0
  302. package/dist/rawg-tool.d.ts +7 -0
  303. package/dist/rawg-tool.d.ts.map +1 -0
  304. package/dist/rawg-tool.js +172 -0
  305. package/dist/rawg-tool.js.map +1 -0
  306. package/dist/readwise-tool.d.ts +2 -0
  307. package/dist/readwise-tool.d.ts.map +1 -0
  308. package/dist/readwise-tool.js +133 -0
  309. package/dist/readwise-tool.js.map +1 -0
  310. package/dist/resend-tool.d.ts +4 -0
  311. package/dist/resend-tool.d.ts.map +1 -0
  312. package/dist/resend-tool.js +133 -0
  313. package/dist/resend-tool.js.map +1 -0
  314. package/dist/restcountries-tool.d.ts +7 -0
  315. package/dist/restcountries-tool.d.ts.map +1 -0
  316. package/dist/restcountries-tool.js +141 -0
  317. package/dist/restcountries-tool.js.map +1 -0
  318. package/dist/riot-tool.d.ts +6 -0
  319. package/dist/riot-tool.d.ts.map +1 -0
  320. package/dist/riot-tool.js +166 -0
  321. package/dist/riot-tool.js.map +1 -0
  322. package/dist/seatgeek-tool.d.ts +7 -0
  323. package/dist/seatgeek-tool.d.ts.map +1 -0
  324. package/dist/seatgeek-tool.js +144 -0
  325. package/dist/seatgeek-tool.js.map +1 -0
  326. package/dist/sendle-tool.d.ts +4 -0
  327. package/dist/sendle-tool.d.ts.map +1 -0
  328. package/dist/sendle-tool.js +146 -0
  329. package/dist/sendle-tool.js.map +1 -0
  330. package/dist/server.d.ts.map +1 -1
  331. package/dist/server.js +114 -1825
  332. package/dist/server.js.map +1 -1
  333. package/dist/setlistfm-tool.d.ts +5 -0
  334. package/dist/setlistfm-tool.d.ts.map +1 -0
  335. package/dist/setlistfm-tool.js +89 -0
  336. package/dist/setlistfm-tool.js.map +1 -0
  337. package/dist/shodan-tool.d.ts +4 -0
  338. package/dist/shodan-tool.d.ts.map +1 -0
  339. package/dist/shodan-tool.js +139 -0
  340. package/dist/shodan-tool.js.map +1 -0
  341. package/dist/sleeper-tool.d.ts +7 -0
  342. package/dist/sleeper-tool.d.ts.map +1 -0
  343. package/dist/sleeper-tool.js +147 -0
  344. package/dist/sleeper-tool.js.map +1 -0
  345. package/dist/splitwise-tool.d.ts +2 -0
  346. package/dist/splitwise-tool.d.ts.map +1 -0
  347. package/dist/splitwise-tool.js +133 -0
  348. package/dist/splitwise-tool.js.map +1 -0
  349. package/dist/supercell-tool.d.ts +8 -0
  350. package/dist/supercell-tool.d.ts.map +1 -0
  351. package/dist/supercell-tool.js +258 -0
  352. package/dist/supercell-tool.js.map +1 -0
  353. package/dist/tab-tool.d.ts +4 -0
  354. package/dist/tab-tool.d.ts.map +1 -0
  355. package/dist/tab-tool.js +128 -0
  356. package/dist/tab-tool.js.map +1 -0
  357. package/dist/text-tool.d.ts +8 -0
  358. package/dist/text-tool.d.ts.map +1 -0
  359. package/dist/text-tool.js +190 -0
  360. package/dist/text-tool.js.map +1 -0
  361. package/dist/thelott-tool.d.ts +3 -0
  362. package/dist/thelott-tool.d.ts.map +1 -0
  363. package/dist/thelott-tool.js +93 -0
  364. package/dist/thelott-tool.js.map +1 -0
  365. package/dist/ticketmaster-tool.d.ts +6 -0
  366. package/dist/ticketmaster-tool.d.ts.map +1 -0
  367. package/dist/ticketmaster-tool.js +140 -0
  368. package/dist/ticketmaster-tool.js.map +1 -0
  369. package/dist/tmdb-tool.d.ts +9 -0
  370. package/dist/tmdb-tool.d.ts.map +1 -0
  371. package/dist/tmdb-tool.js +204 -0
  372. package/dist/tmdb-tool.js.map +1 -0
  373. package/dist/toggl-tool.d.ts +5 -0
  374. package/dist/toggl-tool.d.ts.map +1 -0
  375. package/dist/toggl-tool.js +203 -0
  376. package/dist/toggl-tool.js.map +1 -0
  377. package/dist/toilets-tool.d.ts +3 -0
  378. package/dist/toilets-tool.d.ts.map +1 -0
  379. package/dist/toilets-tool.js +260 -0
  380. package/dist/toilets-tool.js.map +1 -0
  381. package/dist/tomorrowio-tool.d.ts +4 -0
  382. package/dist/tomorrowio-tool.d.ts.map +1 -0
  383. package/dist/tomorrowio-tool.js +114 -0
  384. package/dist/tomorrowio-tool.js.map +1 -0
  385. package/dist/tool-wiring.d.ts +7370 -0
  386. package/dist/tool-wiring.d.ts.map +1 -0
  387. package/dist/tool-wiring.js +6068 -0
  388. package/dist/tool-wiring.js.map +1 -0
  389. package/dist/trivia-tool.d.ts +3 -0
  390. package/dist/trivia-tool.d.ts.map +1 -0
  391. package/dist/trivia-tool.js +91 -0
  392. package/dist/trivia-tool.js.map +1 -0
  393. package/dist/trove-tool.d.ts +4 -0
  394. package/dist/trove-tool.d.ts.map +1 -0
  395. package/dist/trove-tool.js +121 -0
  396. package/dist/trove-tool.js.map +1 -0
  397. package/dist/twitch-tool.d.ts +8 -0
  398. package/dist/twitch-tool.d.ts.map +1 -0
  399. package/dist/twitch-tool.js +188 -0
  400. package/dist/twitch-tool.js.map +1 -0
  401. package/dist/unit-converter-tool.d.ts +8 -0
  402. package/dist/unit-converter-tool.d.ts.map +1 -0
  403. package/dist/unit-converter-tool.js +176 -0
  404. package/dist/unit-converter-tool.js.map +1 -0
  405. package/dist/untappd-tool.d.ts +6 -0
  406. package/dist/untappd-tool.d.ts.map +1 -0
  407. package/dist/untappd-tool.js +193 -0
  408. package/dist/untappd-tool.js.map +1 -0
  409. package/dist/urlscan-tool.d.ts +4 -0
  410. package/dist/urlscan-tool.d.ts.map +1 -0
  411. package/dist/urlscan-tool.js +154 -0
  412. package/dist/urlscan-tool.js.map +1 -0
  413. package/dist/usgs-tool.d.ts +5 -0
  414. package/dist/usgs-tool.d.ts.map +1 -0
  415. package/dist/usgs-tool.js +140 -0
  416. package/dist/usgs-tool.js.map +1 -0
  417. package/dist/vault-bridge.d.ts +16 -0
  418. package/dist/vault-bridge.d.ts.map +1 -0
  419. package/dist/vault-bridge.js +139 -0
  420. package/dist/vault-bridge.js.map +1 -0
  421. package/dist/vercel-tool.d.ts +6 -0
  422. package/dist/vercel-tool.d.ts.map +1 -0
  423. package/dist/vercel-tool.js +202 -0
  424. package/dist/vercel-tool.js.map +1 -0
  425. package/dist/virustotal-tool.d.ts +5 -0
  426. package/dist/virustotal-tool.d.ts.map +1 -0
  427. package/dist/virustotal-tool.js +154 -0
  428. package/dist/virustotal-tool.js.map +1 -0
  429. package/dist/willyweather-tool.d.ts +4 -0
  430. package/dist/willyweather-tool.d.ts.map +1 -0
  431. package/dist/willyweather-tool.js +128 -0
  432. package/dist/willyweather-tool.js.map +1 -0
  433. package/dist/wise-tool.d.ts +5 -0
  434. package/dist/wise-tool.d.ts.map +1 -0
  435. package/dist/wise-tool.js +129 -0
  436. package/dist/wise-tool.js.map +1 -0
  437. package/dist/xero-tool.d.ts.map +1 -1
  438. package/dist/xero-tool.js +40 -35
  439. package/dist/xero-tool.js.map +1 -1
  440. package/dist/yelp-tool.d.ts +6 -0
  441. package/dist/yelp-tool.d.ts.map +1 -0
  442. package/dist/yelp-tool.js +150 -0
  443. package/dist/yelp-tool.js.map +1 -0
  444. package/package.json +5 -1
package/dist/server.js CHANGED
@@ -3,19 +3,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
3
3
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
4
  import { CATALOG, TOOL_MAP, ENDPOINT_MAP } from "./catalog.js";
5
5
  import { createClient } from "./client.js";
6
- import { countText, generateSlug, generateLorem, decodeJwt, lookupHttpStatus, searchEmoji, parseUserAgent, generateReadme, generateChangelog, getFaviconUrls, } from "./local-tools.js";
7
- import { markdownToHtml, htmlToMarkdown, jsonToYaml, yamlToJson, jsonToXml, xmlToJson, jsonToToml, tomlToJson, csvToJson, jsonToCsv, jsonFormat, jsonToJsonl, jsonlToJson, } from "./converter-tools.js";
8
- import { csuitAnalyze } from "./csuite-tool.js";
9
- import { vaultAction } from "./vault-tool.js";
10
- import { telegramSend, telegramRead, telegramSearch, telegramSendMedia, telegramGetUpdates, telegramManageChat, } from "./telegram-tool.js";
11
- import { slackAction } from "./slack-tool.js";
12
- import { discordSend, discordRead, discordThread, discordReact, discordChannels, discordMembers, discordSearch, } from "./discord-tool.js";
13
- import { redditRead, redditPost, redditComment, redditSearch, redditUser, redditVote, redditSubscribe, } from "./reddit-tool.js";
14
- import { blueskyAction } from "./bluesky-tool.js";
15
- import { mastodonAction } from "./mastodon-tool.js";
16
- import { amazonSearch, amazonProduct, amazonBrowse, amazonVariations, } from "./amazon-tool.js";
17
- import { xeroInvoices, xeroContacts, xeroAccounts, xeroPayments, xeroBankTransactions, xeroReports, xeroQuotes, xeroOrganisation, } from "./xero-tool.js";
18
- import { shopifyProducts, shopifyOrders, shopifyCustomers, shopifyInventory, shopifyCollections, shopifyShop, shopifyFulfillments, } from "./shopify-tool.js";
6
+ import { ADDITIONAL_TOOLS, ADDITIONAL_HANDLERS } from "./tool-wiring.js";
19
7
  // ─── Search helper ──────────────────────────────────────────────────────────
20
8
  function searchTools(query, category) {
21
9
  const q = query.toLowerCase();
@@ -53,7 +41,7 @@ const META_TOOLS = [
53
41
  properties: {
54
42
  query: {
55
43
  type: "string",
56
- description: "Search term - describe what you want to do",
44
+ description: "Search term describe what you want to do",
57
45
  },
58
46
  category: {
59
47
  type: "string",
@@ -228,1617 +216,190 @@ const DIRECT_TOOLS = [
228
216
  },
229
217
  },
230
218
  {
231
- name: "unclick_encode",
232
- description: "Encode or decode text. Supports base64, URL, HTML, and hex.",
233
- inputSchema: {
234
- type: "object",
235
- properties: {
236
- text: { type: "string" },
237
- operation: {
238
- type: "string",
239
- enum: [
240
- "encode_base64", "decode_base64",
241
- "encode_url", "decode_url",
242
- "encode_html", "decode_html",
243
- "encode_hex", "decode_hex",
244
- ],
245
- },
246
- },
247
- required: ["text", "operation"],
248
- },
249
- },
250
- {
251
- name: "unclick_generate_uuid",
252
- description: "Generate one or more random UUIDs (v4).",
253
- inputSchema: {
254
- type: "object",
255
- properties: {
256
- count: { type: "number", minimum: 1, maximum: 100, default: 1 },
257
- },
258
- },
259
- },
260
- {
261
- name: "unclick_random_password",
262
- description: "Generate a secure random password.",
263
- inputSchema: {
264
- type: "object",
265
- properties: {
266
- length: { type: "number", minimum: 4, maximum: 512, default: 16 },
267
- uppercase: { type: "boolean", default: true },
268
- lowercase: { type: "boolean", default: true },
269
- numbers: { type: "boolean", default: true },
270
- symbols: { type: "boolean", default: true },
271
- },
272
- },
273
- },
274
- {
275
- name: "unclick_cron_parse",
276
- description: "Convert a cron expression to a human-readable description and get next occurrences.",
277
- inputSchema: {
278
- type: "object",
279
- properties: {
280
- expression: { type: "string", description: "e.g. '0 9 * * 1-5' (weekdays at 9am)" },
281
- next_count: { type: "number", minimum: 1, maximum: 10, default: 5 },
282
- },
283
- required: ["expression"],
284
- },
285
- },
286
- {
287
- name: "unclick_ip_parse",
288
- description: "Parse an IP address - get decimal, binary, hex, and type (private/loopback/multicast).",
289
- inputSchema: {
290
- type: "object",
291
- properties: {
292
- ip: { type: "string" },
293
- },
294
- required: ["ip"],
295
- },
296
- },
297
- {
298
- name: "unclick_color_convert",
299
- description: "Convert a color between hex, RGB, HSL, and HSV formats.",
300
- inputSchema: {
301
- type: "object",
302
- properties: {
303
- color: {
304
- description: "Color as hex string (e.g. '#ff6b6b'), RGB object {r,g,b}, or HSL object {h,s,l}",
305
- },
306
- },
307
- required: ["color"],
308
- },
309
- },
310
- {
311
- name: "unclick_regex_test",
312
- description: "Test a regex pattern against text and get all matches with groups.",
313
- inputSchema: {
314
- type: "object",
315
- properties: {
316
- pattern: { type: "string", description: "Regex pattern (no surrounding slashes)" },
317
- flags: { type: "string", description: "Flags like 'gi'", default: "" },
318
- input: { type: "string" },
319
- },
320
- required: ["pattern", "input"],
321
- },
322
- },
323
- {
324
- name: "unclick_timestamp_convert",
325
- description: "Convert a timestamp (ISO, Unix seconds, or Unix ms) to all common formats.",
326
- inputSchema: {
327
- type: "object",
328
- properties: {
329
- timestamp: {
330
- description: "ISO string, Unix seconds (e.g. 1700000000), or Unix ms (e.g. 1700000000000)",
331
- },
332
- },
333
- required: ["timestamp"],
334
- },
335
- },
336
- {
337
- name: "unclick_diff_text",
338
- description: "Compare two strings and return a unified diff showing what changed.",
339
- inputSchema: {
340
- type: "object",
341
- properties: {
342
- a: { type: "string", description: "Original text" },
343
- b: { type: "string", description: "New text" },
344
- },
345
- required: ["a", "b"],
346
- },
347
- },
348
- {
349
- name: "unclick_kv_set",
350
- description: "Store a value in the UnClick key-value store with optional TTL.",
351
- inputSchema: {
352
- type: "object",
353
- properties: {
354
- key: { type: "string" },
355
- value: { description: "Any JSON-serializable value" },
356
- ttl: { type: "number", description: "Seconds until expiry (optional)" },
357
- },
358
- required: ["key", "value"],
359
- },
360
- },
361
- {
362
- name: "unclick_kv_get",
363
- description: "Retrieve a value from the UnClick key-value store.",
364
- inputSchema: {
365
- type: "object",
366
- properties: {
367
- key: { type: "string" },
368
- },
369
- required: ["key"],
370
- },
371
- },
372
- // ── Local tools (no API call required) ────────────────────────────────────
373
- {
374
- name: "unclick_count_text",
375
- description: "Count words, characters, sentences, lines, and paragraphs in any text.",
376
- inputSchema: {
377
- type: "object",
378
- properties: {
379
- text: { type: "string", description: "Text to analyse" },
380
- },
381
- required: ["text"],
382
- },
383
- },
384
- {
385
- name: "unclick_slug",
386
- description: "Convert any string into a URL-friendly slug: lowercase, ASCII, words joined by a separator.",
387
- inputSchema: {
388
- type: "object",
389
- properties: {
390
- text: { type: "string", description: "Text to slugify" },
391
- separator: { type: "string", default: "-", description: "Word separator (default: '-')" },
392
- },
393
- required: ["text"],
394
- },
395
- },
396
- {
397
- name: "unclick_lorem_ipsum",
398
- description: "Generate Lorem Ipsum placeholder text by words, sentences, or paragraphs.",
399
- inputSchema: {
400
- type: "object",
401
- properties: {
402
- count: { type: "number", minimum: 1, maximum: 100, default: 5 },
403
- unit: {
404
- type: "string",
405
- enum: ["words", "sentences", "paragraphs"],
406
- default: "sentences",
407
- },
408
- start_with_lorem: {
409
- type: "boolean",
410
- default: true,
411
- description: "Start output with 'Lorem ipsum...'",
412
- },
413
- },
414
- },
415
- },
416
- {
417
- name: "unclick_decode_jwt",
418
- description: "Decode a JWT token and inspect its header, payload, and expiry. " +
419
- "Does NOT verify the signature — for inspection only.",
420
- inputSchema: {
421
- type: "object",
422
- properties: {
423
- token: { type: "string", description: "JWT string (three dot-separated parts)" },
424
- },
425
- required: ["token"],
426
- },
427
- },
428
- {
429
- name: "unclick_http_status",
430
- description: "Look up any HTTP status code: get its official phrase, category, and a plain-English description.",
431
- inputSchema: {
432
- type: "object",
433
- properties: {
434
- code: { type: "number", description: "HTTP status code, e.g. 404, 200, 429" },
435
- },
436
- required: ["code"],
437
- },
438
- },
439
- {
440
- name: "unclick_emoji_search",
441
- description: "Find emoji by keyword. Returns matching emoji with names and keywords.",
442
- inputSchema: {
443
- type: "object",
444
- properties: {
445
- keyword: { type: "string", description: "Search term, e.g. 'fire', 'happy', 'rocket'" },
446
- limit: { type: "number", minimum: 1, maximum: 30, default: 10 },
447
- },
448
- required: ["keyword"],
449
- },
450
- },
451
- {
452
- name: "unclick_parse_user_agent",
453
- description: "Parse a browser User-Agent string into browser, OS, device type, and rendering engine.",
454
- inputSchema: {
455
- type: "object",
456
- properties: {
457
- user_agent: {
458
- type: "string",
459
- description: "Full User-Agent header value",
460
- },
461
- },
462
- required: ["user_agent"],
463
- },
464
- },
465
- {
466
- name: "unclick_readme_template",
467
- description: "Scaffold a README.md from project info: name, description, install command, usage snippet, license.",
468
- inputSchema: {
469
- type: "object",
470
- properties: {
471
- name: { type: "string", description: "Project name" },
472
- description: { type: "string", description: "One-line project description" },
473
- install: { type: "string", description: "Install command (optional — auto-detected from language)" },
474
- usage: { type: "string", description: "Usage code snippet (optional)" },
475
- language: {
476
- type: "string",
477
- enum: ["javascript", "typescript", "python", "rust", "go", "other"],
478
- description: "Primary language — used to pick install command if not provided",
479
- },
480
- license: { type: "string", default: "MIT" },
481
- repo: { type: "string", description: "GitHub repo URL (optional, e.g. https://github.com/owner/repo)" },
482
- badges: { type: "boolean", default: true },
483
- },
484
- required: ["name", "description"],
485
- },
486
- },
487
- {
488
- name: "unclick_changelog_entry",
489
- description: "Format a Keep a Changelog-style entry for a release. " +
490
- "Provide the version and lists of added/changed/fixed/removed items.",
491
- inputSchema: {
492
- type: "object",
493
- properties: {
494
- version: { type: "string", description: "Semantic version, e.g. '1.2.0'" },
495
- date: { type: "string", description: "ISO date (default: today)" },
496
- added: { type: "array", items: { type: "string" }, description: "New features" },
497
- changed: { type: "array", items: { type: "string" }, description: "Changes to existing functionality" },
498
- deprecated: { type: "array", items: { type: "string" } },
499
- removed: { type: "array", items: { type: "string" } },
500
- fixed: { type: "array", items: { type: "string" }, description: "Bug fixes" },
501
- security: { type: "array", items: { type: "string" }, description: "Security fixes" },
502
- },
503
- required: ["version"],
504
- },
505
- },
506
- {
507
- name: "unclick_favicon_url",
508
- description: "Get the favicon URLs for any website domain — returns the direct /favicon.ico URL plus " +
509
- "reliable fallback URLs via Google and DuckDuckGo favicon APIs.",
510
- inputSchema: {
511
- type: "object",
512
- properties: {
513
- domain: {
514
- type: "string",
515
- description: "Domain or URL, e.g. 'github.com' or 'https://github.com/owner/repo'",
516
- },
517
- },
518
- required: ["domain"],
519
- },
520
- },
521
- // ── Converter tools (pure-local, no API call) ─────────────────────────────
522
- {
523
- name: "unclick_markdown_to_html",
524
- description: "Convert Markdown text to HTML.",
525
- inputSchema: {
526
- type: "object",
527
- properties: {
528
- markdown: { type: "string", description: "Markdown text to convert" },
529
- },
530
- required: ["markdown"],
531
- },
532
- },
533
- {
534
- name: "unclick_html_to_markdown",
535
- description: "Convert HTML to Markdown.",
536
- inputSchema: {
537
- type: "object",
538
- properties: {
539
- html: { type: "string", description: "HTML string to convert" },
540
- },
541
- required: ["html"],
542
- },
543
- },
544
- {
545
- name: "unclick_json_to_yaml",
546
- description: "Convert a JSON string to YAML.",
547
- inputSchema: {
548
- type: "object",
549
- properties: {
550
- json: { type: "string", description: "Valid JSON string" },
551
- indent: { type: "number", default: 2, description: "YAML indent width (default 2)" },
552
- },
553
- required: ["json"],
554
- },
555
- },
556
- {
557
- name: "unclick_yaml_to_json",
558
- description: "Convert a YAML string to JSON.",
559
- inputSchema: {
560
- type: "object",
561
- properties: {
562
- yaml: { type: "string", description: "Valid YAML string" },
563
- indent: { type: "number", default: 2, description: "JSON indent width (default 2)" },
564
- },
565
- required: ["yaml"],
566
- },
567
- },
568
- {
569
- name: "unclick_json_to_xml",
570
- description: "Convert a JSON string to XML.",
571
- inputSchema: {
572
- type: "object",
573
- properties: {
574
- json: { type: "string", description: "Valid JSON string" },
575
- root_key: { type: "string", default: "root", description: "Root element name when input is an array (default: 'root')" },
576
- },
577
- required: ["json"],
578
- },
579
- },
580
- {
581
- name: "unclick_xml_to_json",
582
- description: "Convert an XML string to JSON.",
583
- inputSchema: {
584
- type: "object",
585
- properties: {
586
- xml: { type: "string", description: "Valid XML string" },
587
- indent: { type: "number", default: 2, description: "JSON indent width (default 2)" },
588
- },
589
- required: ["xml"],
590
- },
591
- },
592
- {
593
- name: "unclick_json_to_toml",
594
- description: "Convert a JSON object to TOML. Input must be a top-level object (not an array).",
595
- inputSchema: {
596
- type: "object",
597
- properties: {
598
- json: { type: "string", description: "Valid JSON object string" },
599
- },
600
- required: ["json"],
601
- },
602
- },
603
- {
604
- name: "unclick_toml_to_json",
605
- description: "Convert a TOML string to JSON.",
606
- inputSchema: {
607
- type: "object",
608
- properties: {
609
- toml: { type: "string", description: "Valid TOML string" },
610
- indent: { type: "number", default: 2, description: "JSON indent width (default 2)" },
611
- },
612
- required: ["toml"],
613
- },
614
- },
615
- {
616
- name: "unclick_csv_to_json",
617
- description: "Convert CSV text to a JSON array.",
618
- inputSchema: {
619
- type: "object",
620
- properties: {
621
- csv: { type: "string", description: "CSV text to convert" },
622
- header: { type: "boolean", default: true, description: "First row is a header (default: true)" },
623
- delimiter: { type: "string", default: ",", description: "Column delimiter (default: ',')" },
624
- },
625
- required: ["csv"],
626
- },
627
- },
628
- {
629
- name: "unclick_json_to_csv",
630
- description: "Convert a JSON array to CSV text.",
631
- inputSchema: {
632
- type: "object",
633
- properties: {
634
- json: { type: "string", description: "JSON array of objects to convert" },
635
- delimiter: { type: "string", default: ",", description: "Column delimiter (default: ',')" },
636
- },
637
- required: ["json"],
638
- },
639
- },
640
- {
641
- name: "unclick_json_format",
642
- description: "Pretty-print or minify a JSON string. Use indent=0 or 'minify' to minify.",
643
- inputSchema: {
644
- type: "object",
645
- properties: {
646
- json: { type: "string", description: "Valid JSON string" },
647
- indent: {
648
- description: "Indent width: 2, 4, 'tab', or 'minify' (default: 2)",
649
- default: 2,
650
- },
651
- },
652
- required: ["json"],
653
- },
654
- },
655
- {
656
- name: "unclick_json_to_jsonl",
657
- description: "Convert a JSON array to newline-delimited JSON (JSONL), one item per line.",
658
- inputSchema: {
659
- type: "object",
660
- properties: {
661
- json: { type: "string", description: "JSON array to convert" },
662
- },
663
- required: ["json"],
664
- },
665
- },
666
- {
667
- name: "unclick_jsonl_to_json",
668
- description: "Convert newline-delimited JSON (JSONL) to a JSON array.",
669
- inputSchema: {
670
- type: "object",
671
- properties: {
672
- jsonl: { type: "string", description: "JSONL text (one JSON value per line)" },
673
- indent: { type: "number", default: 2, description: "JSON indent width (default 2)" },
674
- },
675
- required: ["jsonl"],
676
- },
677
- },
678
- // ── Number base converters ───────────────────────────────────────────────
679
- {
680
- name: "binary_to_decimal",
681
- description: "Convert a binary string (base 2) to a decimal number.",
682
- inputSchema: {
683
- type: "object",
684
- properties: {
685
- binary: { type: "string", description: "Binary string, e.g. '1010'" },
686
- },
687
- required: ["binary"],
688
- },
689
- },
690
- {
691
- name: "decimal_to_binary",
692
- description: "Convert a decimal number to a binary string (base 2).",
693
- inputSchema: {
694
- type: "object",
695
- properties: {
696
- decimal: { type: "number", description: "Decimal integer, e.g. 10" },
697
- },
698
- required: ["decimal"],
699
- },
700
- },
701
- {
702
- name: "hex_to_decimal",
703
- description: "Convert a hexadecimal string to a decimal number.",
704
- inputSchema: {
705
- type: "object",
706
- properties: {
707
- hex: { type: "string", description: "Hex string (with or without 0x prefix), e.g. 'FF' or '0xff'" },
708
- },
709
- required: ["hex"],
710
- },
711
- },
712
- {
713
- name: "decimal_to_hex",
714
- description: "Convert a decimal number to a hexadecimal string.",
715
- inputSchema: {
716
- type: "object",
717
- properties: {
718
- decimal: { type: "number", description: "Decimal integer, e.g. 255" },
719
- },
720
- required: ["decimal"],
721
- },
722
- },
723
- {
724
- name: "octal_to_decimal",
725
- description: "Convert an octal string (base 8) to a decimal number.",
726
- inputSchema: {
727
- type: "object",
728
- properties: {
729
- octal: { type: "string", description: "Octal string, e.g. '17'" },
730
- },
731
- required: ["octal"],
732
- },
733
- },
734
- {
735
- name: "decimal_to_octal",
736
- description: "Convert a decimal number to an octal string (base 8).",
737
- inputSchema: {
738
- type: "object",
739
- properties: {
740
- decimal: { type: "number", description: "Decimal integer, e.g. 15" },
741
- },
742
- required: ["decimal"],
743
- },
744
- },
745
- // ── Temperature converters ───────────────────────────────────────────────
746
- {
747
- name: "celsius_to_fahrenheit",
748
- description: "Convert a temperature from Celsius to Fahrenheit.",
749
- inputSchema: {
750
- type: "object",
751
- properties: {
752
- celsius: { type: "number", description: "Temperature in Celsius, e.g. 100" },
753
- },
754
- required: ["celsius"],
755
- },
756
- },
757
- {
758
- name: "fahrenheit_to_celsius",
759
- description: "Convert a temperature from Fahrenheit to Celsius.",
760
- inputSchema: {
761
- type: "object",
762
- properties: {
763
- fahrenheit: { type: "number", description: "Temperature in Fahrenheit, e.g. 212" },
764
- },
765
- required: ["fahrenheit"],
766
- },
767
- },
768
- // ── Byte size converters ─────────────────────────────────────────────────
769
- {
770
- name: "bytes_to_human",
771
- description: "Convert a byte count to a human-readable size string (e.g. 1048576 → '1 MB').",
772
- inputSchema: {
773
- type: "object",
774
- properties: {
775
- bytes: { type: "number", description: "Number of bytes, e.g. 1048576" },
776
- },
777
- required: ["bytes"],
778
- },
779
- },
780
- {
781
- name: "human_to_bytes",
782
- description: "Convert a human-readable size string to bytes (e.g. '1.5 GB' → 1610612736).",
783
- inputSchema: {
784
- type: "object",
785
- properties: {
786
- size: { type: "string", description: "Size string, e.g. '1.5 GB', '512 MB', '2 TB'" },
787
- },
788
- required: ["size"],
789
- },
790
- },
791
- {
792
- name: "report_bug",
793
- description: "Report a bug or unexpected behavior encountered while using an UnClick tool. " +
794
- "Call this whenever a tool returns an error, behaves unexpectedly, or fails silently. " +
795
- "Severity is auto-classified from the error message: 500/fatal → critical, " +
796
- "timeout/503 → high, 4xx/invalid → low, everything else → medium.",
797
- inputSchema: {
798
- type: "object",
799
- properties: {
800
- tool_name: {
801
- type: "string",
802
- description: "Name or slug of the UnClick tool that failed (e.g. 'image', 'hash', 'uuid')",
803
- },
804
- error_message: {
805
- type: "string",
806
- description: "The error message or unexpected output received",
807
- },
808
- request_payload: {
809
- type: "object",
810
- description: "The request parameters sent to the tool (optional)",
811
- },
812
- expected_behavior: {
813
- type: "string",
814
- description: "What the tool should have done instead (optional)",
815
- },
816
- agent_context: {
817
- type: "string",
818
- description: "Brief description of what the agent was trying to accomplish (optional)",
819
- },
820
- },
821
- required: ["tool_name", "error_message"],
822
- },
823
- },
824
- // ── C-Suite analysis (pure local, no API call) ────────────────────────────
825
- {
826
- name: "csuite_analyze",
827
- description: "Run a business decision, scenario, or question through multiple C-suite executive perspectives simultaneously. " +
828
- "Each 'hat' analyzes the scenario through its unique lens: strategy, operations, finance, technology, people, data, security, product, customer, and AI. " +
829
- "Returns structured analysis per perspective plus a consensus synthesis. " +
830
- "Use this to make richer, more well-rounded business decisions by surfacing angles that would otherwise be missed.",
831
- inputSchema: {
832
- type: "object",
833
- properties: {
834
- scenario: {
835
- type: "string",
836
- description: "The business decision, scenario, or question to analyze. Be specific for better analysis.",
837
- },
838
- context: {
839
- type: "string",
840
- description: "Optional additional context: industry, company stage, size, constraints, current situation.",
841
- },
842
- perspectives: {
843
- type: "array",
844
- items: {
845
- type: "string",
846
- enum: ["CEO", "COO", "CTO", "CFO", "CMO", "CIO", "CHRO", "CDO", "CPO", "CSO", "CCO", "CAIO"],
847
- },
848
- description: "Which C-suite roles to include. Defaults to all 12. " +
849
- "CEO=strategy/vision, COO=operations/scalability, CTO=tech/architecture, CFO=finance/ROI, " +
850
- "CMO=marketing/brand, CIO=information systems/integration, CHRO=people/culture, " +
851
- "CDO=data/governance, CPO=product/UX, CSO=security/compliance, CCO=customer/retention, " +
852
- "CAIO=AI/automation/ethics.",
853
- },
854
- depth: {
855
- type: "string",
856
- enum: ["quick", "standard", "deep"],
857
- default: "standard",
858
- description: "Analysis depth. quick=2-3 points per area, standard=4-5, deep=6-7 with sub-considerations.",
859
- },
860
- focus: {
861
- type: "string",
862
- description: "Optional aspect to emphasize across all perspectives, e.g. 'risk', 'growth', 'cost', 'speed'.",
863
- },
864
- },
865
- required: ["scenario"],
866
- },
867
- },
868
- // ── Encrypted credential vault (pure local, no API call) ─────────────────
869
- {
870
- name: "vault",
871
- description: "Secure encrypted credential vault. Store, retrieve, rotate, and audit API keys, " +
872
- "tokens, passwords, and secrets. All data is AES-256-GCM encrypted at rest using a " +
873
- "master password you control. Secrets are masked by default (****last4) unless reveal=true. " +
874
- "Vault lives at ~/.unclick/vault.enc. " +
875
- "Actions: vault_init, vault_store, vault_retrieve, vault_list, vault_delete, vault_rotate, vault_audit.",
876
- inputSchema: {
877
- type: "object",
878
- properties: {
879
- action: {
880
- type: "string",
881
- enum: [
882
- "vault_init",
883
- "vault_store",
884
- "vault_retrieve",
885
- "vault_list",
886
- "vault_delete",
887
- "vault_rotate",
888
- "vault_audit",
889
- ],
890
- description: "vault_init: create new vault. " +
891
- "vault_store: save a secret. " +
892
- "vault_retrieve: get a secret (masked unless reveal=true). " +
893
- "vault_list: list key names and metadata (never values). " +
894
- "vault_delete: remove a secret. " +
895
- "vault_rotate: replace a secret value with a new IV. " +
896
- "vault_audit: view access event log.",
897
- },
898
- master_password: {
899
- type: "string",
900
- description: "Master password used to encrypt/decrypt the vault.",
901
- },
902
- key: {
903
- type: "string",
904
- description: "Secret name/label (required for store, retrieve, delete, rotate).",
905
- },
906
- value: {
907
- type: "string",
908
- description: "Secret value to store (required for vault_store).",
909
- },
910
- new_value: {
911
- type: "string",
912
- description: "Replacement secret value (required for vault_rotate).",
913
- },
914
- reveal: {
915
- type: "boolean",
916
- default: false,
917
- description: "If true, returns the full decrypted value. Default false returns ****last4.",
918
- },
919
- metadata: {
920
- type: "object",
921
- description: "Optional tags/notes for vault_store: " +
922
- "{ service, tags, expires, notes } - any JSON object.",
923
- },
924
- limit: {
925
- type: "number",
926
- minimum: 1,
927
- maximum: 100,
928
- default: 20,
929
- description: "Max audit events to return (vault_audit only, default 20).",
930
- },
931
- },
932
- required: ["action", "master_password"],
933
- },
934
- },
935
- // ── Telegram Bot API tools ────────────────────────────────────────────────
936
- {
937
- name: "telegram_send",
938
- description: "Send a text message to a Telegram chat, group, or channel via your bot. " +
939
- "Supports plain text and Markdown/HTML formatting. " +
940
- "Get a bot token from @BotFather. The bot must be a member of the target chat.",
941
- inputSchema: {
942
- type: "object",
943
- properties: {
944
- bot_token: { type: "string", description: "Telegram bot token from @BotFather (e.g. 123456:ABC-DEF...)." },
945
- chat_id: { type: ["string", "number"], description: "Target chat ID or @username (e.g. -1001234567890 or @mychannel)." },
946
- text: { type: "string", description: "Message text to send (up to 4096 characters)." },
947
- parse_mode: { type: "string", enum: ["Markdown", "HTML", "MarkdownV2"], description: "Optional formatting mode. Default is plain text." },
948
- reply_to_message_id: { type: "number", description: "Optional message ID to reply to." },
949
- disable_notification: { type: "boolean", description: "Send silently without notification sound. Default false." },
950
- },
951
- required: ["bot_token", "chat_id", "text"],
952
- },
953
- },
954
- {
955
- name: "telegram_read",
956
- description: "Read recent messages received by your Telegram bot. " +
957
- "Returns messages the bot has received since the last getUpdates call (or from a given offset). " +
958
- "Filter by chat_id to see messages from a specific chat.",
959
- inputSchema: {
960
- type: "object",
961
- properties: {
962
- bot_token: { type: "string", description: "Telegram bot token from @BotFather." },
963
- chat_id: { type: ["string", "number"], description: "Optional chat ID to filter messages (e.g. -1001234567890)." },
964
- limit: { type: "number", minimum: 1, maximum: 100, default: 20, description: "Max number of recent messages to return. Default 20." },
965
- offset: { type: "number", description: "Update ID offset for pagination. Use next_offset from a previous response." },
966
- },
967
- required: ["bot_token"],
968
- },
969
- },
970
- {
971
- name: "telegram_search",
972
- description: "Search for messages containing a keyword in your bot's recent message history. " +
973
- "Searches across all updates the bot has received. Filter by chat_id for a specific chat.",
974
- inputSchema: {
975
- type: "object",
976
- properties: {
977
- bot_token: { type: "string", description: "Telegram bot token from @BotFather." },
978
- query: { type: "string", description: "Keyword or phrase to search for (case-insensitive)." },
979
- chat_id: { type: ["string", "number"], description: "Optional chat ID to narrow search to a specific chat." },
980
- limit: { type: "number", minimum: 1, maximum: 50, default: 10, description: "Max number of matching messages to return. Default 10." },
981
- offset: { type: "number", description: "Update ID offset to start from." },
982
- },
983
- required: ["bot_token", "query"],
984
- },
985
- },
986
- {
987
- name: "telegram_send_media",
988
- description: "Send a photo, document, audio, video, or animation to a Telegram chat via your bot. " +
989
- "The media must be accessible via a public URL. Supports optional captions.",
990
- inputSchema: {
991
- type: "object",
992
- properties: {
993
- bot_token: { type: "string", description: "Telegram bot token from @BotFather." },
994
- chat_id: { type: ["string", "number"], description: "Target chat ID or @username." },
995
- media_type: { type: "string", enum: ["photo", "document", "audio", "video", "animation"], description: "Type of media to send." },
996
- media_url: { type: "string", description: "Public URL of the media file to send." },
997
- caption: { type: "string", description: "Optional caption for the media (up to 1024 characters)." },
998
- parse_mode: { type: "string", enum: ["Markdown", "HTML", "MarkdownV2"], description: "Formatting mode for the caption." },
999
- disable_notification: { type: "boolean", description: "Send silently without notification sound. Default false." },
1000
- },
1001
- required: ["bot_token", "chat_id", "media_type", "media_url"],
1002
- },
1003
- },
1004
- {
1005
- name: "telegram_get_updates",
1006
- description: "Fetch pending updates (messages, edited messages, channel posts) from the Telegram Bot API. " +
1007
- "Use offset to mark previous updates as processed and avoid seeing them again.",
1008
- inputSchema: {
1009
- type: "object",
1010
- properties: {
1011
- bot_token: { type: "string", description: "Telegram bot token from @BotFather." },
1012
- limit: { type: "number", minimum: 1, maximum: 100, default: 20, description: "Max number of updates to return." },
1013
- offset: { type: "number", description: "Update ID offset. Pass next_offset from previous response to mark updates as read." },
1014
- timeout: { type: "number", minimum: 0, maximum: 30, default: 0, description: "Seconds to wait for long polling. 0 = return immediately." },
1015
- allowed_updates: { type: "array", items: { type: "string" }, description: "List of update types to receive, e.g. ['message', 'channel_post']." },
1016
- },
1017
- required: ["bot_token"],
1018
- },
1019
- },
1020
- {
1021
- name: "telegram_manage_chat",
1022
- description: "Manage a Telegram chat: get chat info, list admins, pin a message, or unpin a message. " +
1023
- "The bot must be an admin with the appropriate permissions to pin/unpin.",
1024
- inputSchema: {
1025
- type: "object",
1026
- properties: {
1027
- bot_token: { type: "string", description: "Telegram bot token from @BotFather." },
1028
- chat_id: { type: ["string", "number"], description: "Target chat ID or @username." },
1029
- action: {
1030
- type: "string",
1031
- enum: ["info", "members", "pin", "unpin"],
1032
- description: "info: get chat details. members: list admins. pin: pin a message (requires message_id). unpin: unpin a message (message_id optional).",
1033
- },
1034
- message_id: { type: "number", description: "Message ID to pin or unpin (required for pin, optional for unpin)." },
1035
- disable_notification: { type: "boolean", description: "Pin without notification. Applies to pin action only. Default false." },
1036
- },
1037
- required: ["bot_token", "chat_id", "action"],
1038
- },
1039
- },
1040
- // ── Slack Web API ─────────────────────────────────────────────────────────
1041
- {
1042
- name: "slack",
1043
- description: "Send and receive Slack messages, search conversations, manage reactions, " +
1044
- "upload files, and list channels via the official Slack Web API. " +
1045
- "Requires a Bot Token (xoxb-...) with the appropriate OAuth scopes. " +
1046
- "Actions: slack_send, slack_read, slack_search, slack_thread_reply, " +
1047
- "slack_channels, slack_react, slack_upload.",
1048
- inputSchema: {
1049
- type: "object",
1050
- properties: {
1051
- action: {
1052
- type: "string",
1053
- enum: ["slack_send", "slack_read", "slack_search", "slack_thread_reply", "slack_channels", "slack_react", "slack_upload"],
1054
- description: "slack_send: post a message to a channel or DM. " +
1055
- "slack_read: fetch recent messages from a channel (conversation history). " +
1056
- "slack_search: search messages across the workspace. " +
1057
- "slack_thread_reply: reply to an existing message thread. " +
1058
- "slack_channels: list channels the bot can access. " +
1059
- "slack_react: add an emoji reaction to a message. " +
1060
- "slack_upload: upload a text file to a channel.",
1061
- },
1062
- bot_token: { type: "string", description: "Slack Bot Token starting with xoxb-. Create one at api.slack.com/apps under 'OAuth and Permissions'." },
1063
- channel: { type: "string", description: "Channel ID (e.g. C01234ABCDE) or name (e.g. #general). Used by: slack_send, slack_read, slack_thread_reply, slack_react, slack_upload." },
1064
- text: { type: "string", description: "Message text (supports Slack mrkdwn). Required by slack_send and slack_thread_reply unless blocks is provided." },
1065
- blocks: { description: "Slack Block Kit payload (array of block objects). Optional alternative/addition to text for rich messages." },
1066
- thread_ts: { type: "string", description: "Parent message timestamp to reply in a thread. Required for slack_thread_reply. Optional for slack_send." },
1067
- username: { type: "string", description: "Override the bot display name for this message (slack_send only)." },
1068
- limit: { type: "number", minimum: 1, maximum: 200, default: 20, description: "Max messages to return (slack_read: 1-200; slack_channels: 1-1000)." },
1069
- oldest: { type: "string", description: "Return messages after this Unix timestamp (slack_read only)." },
1070
- latest: { type: "string", description: "Return messages before this Unix timestamp (slack_read only)." },
1071
- query: { type: "string", description: "Search query string (slack_search only). Supports Slack search modifiers." },
1072
- count: { type: "number", minimum: 1, maximum: 100, default: 20, description: "Max search results to return (slack_search only)." },
1073
- sort: { type: "string", enum: ["score", "timestamp"], default: "timestamp", description: "Sort search results by relevance or recency (slack_search only)." },
1074
- sort_dir: { type: "string", enum: ["asc", "desc"], default: "desc", description: "Sort direction for search results (slack_search only)." },
1075
- types: { type: "string", default: "public_channel", description: "Comma-separated channel types to include (slack_channels only)." },
1076
- exclude_archived: { type: "boolean", default: true, description: "Exclude archived channels from results (slack_channels only)." },
1077
- timestamp: { type: "string", description: "Message timestamp (ts) to react to (slack_react only)." },
1078
- emoji: { type: "string", description: "Emoji name without colons, e.g. 'thumbsup' or '+1' (slack_react only)." },
1079
- filename: { type: "string", default: "file.txt", description: "Filename for the uploaded file (slack_upload only)." },
1080
- content: { type: "string", description: "Text content of the file to upload (slack_upload only)." },
1081
- channels: { type: "string", description: "Comma-separated channel IDs to share the file with (slack_upload only)." },
1082
- initial_comment: { type: "string", description: "Optional message to post alongside the uploaded file (slack_upload only)." },
1083
- },
1084
- required: ["action", "bot_token"],
1085
- },
1086
- },
1087
- // ── Discord REST API v10 ──────────────────────────────────────────────────
1088
- {
1089
- name: "discord_send",
1090
- description: "Send a message to a Discord channel. Optionally reply to an existing message or enable TTS.",
1091
- inputSchema: {
1092
- type: "object",
1093
- properties: {
1094
- bot_token: { type: "string", description: "Discord bot token (starts with Bot ...)" },
1095
- channel_id: { type: "string", description: "ID of the channel to send the message to" },
1096
- content: { type: "string", description: "Message text (up to 2000 characters)" },
1097
- reply_to: { type: "string", description: "Message ID to reply to (optional)" },
1098
- tts: { type: "boolean", default: false, description: "Send as text-to-speech (optional)" },
1099
- },
1100
- required: ["bot_token", "channel_id", "content"],
1101
- },
1102
- },
1103
- {
1104
- name: "discord_read",
1105
- description: "Read recent messages from a Discord channel.",
1106
- inputSchema: {
1107
- type: "object",
1108
- properties: {
1109
- bot_token: { type: "string", description: "Discord bot token" },
1110
- channel_id: { type: "string", description: "ID of the channel to read" },
1111
- limit: { type: "number", minimum: 1, maximum: 100, default: 50, description: "Number of messages to fetch (default 50, max 100)" },
1112
- before: { type: "string", description: "Fetch messages before this message ID (optional)" },
1113
- after: { type: "string", description: "Fetch messages after this message ID (optional)" },
1114
- },
1115
- required: ["bot_token", "channel_id"],
1116
- },
1117
- },
1118
- {
1119
- name: "discord_thread",
1120
- description: "Create a thread from a message, create a standalone thread in a channel, or reply to an existing thread. " +
1121
- "Provide thread_id to reply. Provide message_id to start a thread from that message. " +
1122
- "Provide neither to create a standalone thread.",
1123
- inputSchema: {
1124
- type: "object",
1125
- properties: {
1126
- bot_token: { type: "string", description: "Discord bot token" },
1127
- channel_id: { type: "string", description: "Channel to create the thread in" },
1128
- name: { type: "string", description: "Thread name (required when creating a thread)" },
1129
- content: { type: "string", description: "Initial or reply message content" },
1130
- thread_id: { type: "string", description: "Existing thread ID to reply to (optional)" },
1131
- message_id: { type: "string", description: "Message ID to start a thread from (optional)" },
1132
- auto_archive_duration: { type: "number", enum: [60, 1440, 4320, 10080], description: "Minutes until the thread auto-archives: 60, 1440, 4320, or 10080 (optional)" },
1133
- },
1134
- required: ["bot_token", "channel_id"],
1135
- },
1136
- },
1137
- {
1138
- name: "discord_react",
1139
- description: "Add an emoji reaction to a Discord message.",
1140
- inputSchema: {
1141
- type: "object",
1142
- properties: {
1143
- bot_token: { type: "string", description: "Discord bot token" },
1144
- channel_id: { type: "string", description: "Channel containing the message" },
1145
- message_id: { type: "string", description: "ID of the message to react to" },
1146
- emoji: { type: "string", description: "Unicode emoji (e.g. '👍') or custom emoji in name:id format (e.g. 'thumbsup:123456789')" },
1147
- },
1148
- required: ["bot_token", "channel_id", "message_id", "emoji"],
1149
- },
1150
- },
1151
- {
1152
- name: "discord_channels",
1153
- description: "List all channels in a Discord guild (server).",
1154
- inputSchema: {
1155
- type: "object",
1156
- properties: {
1157
- bot_token: { type: "string", description: "Discord bot token" },
1158
- guild_id: { type: "string", description: "Guild (server) ID" },
1159
- },
1160
- required: ["bot_token", "guild_id"],
1161
- },
1162
- },
1163
- {
1164
- name: "discord_members",
1165
- description: "List members of a Discord guild. Requires the SERVER MEMBERS INTENT to be enabled on the bot.",
1166
- inputSchema: {
1167
- type: "object",
1168
- properties: {
1169
- bot_token: { type: "string", description: "Discord bot token" },
1170
- guild_id: { type: "string", description: "Guild (server) ID" },
1171
- limit: { type: "number", minimum: 1, maximum: 1000, default: 100, description: "Number of members to return (default 100, max 1000)" },
1172
- after: { type: "string", description: "Return members after this user ID for pagination (optional)" },
1173
- },
1174
- required: ["bot_token", "guild_id"],
1175
- },
1176
- },
1177
- {
1178
- name: "discord_search",
1179
- description: "Search messages in a Discord guild using Discord's search endpoint.",
1180
- inputSchema: {
1181
- type: "object",
1182
- properties: {
1183
- bot_token: { type: "string", description: "Discord bot token" },
1184
- guild_id: { type: "string", description: "Guild (server) ID to search in" },
1185
- query: { type: "string", description: "Text to search for in message content" },
1186
- channel_id: { type: "string", description: "Restrict search to this channel (optional)" },
1187
- author_id: { type: "string", description: "Restrict search to messages from this user ID (optional)" },
1188
- has: { type: "string", enum: ["link", "embed", "file", "video", "image", "sound", "sticker"], description: "Filter by attachment type (optional)" },
1189
- limit: { type: "number", minimum: 1, maximum: 25, default: 25, description: "Max results (default 25)" },
1190
- offset: { type: "number", default: 0, description: "Pagination offset (optional)" },
1191
- },
1192
- required: ["bot_token", "guild_id", "query"],
1193
- },
1194
- },
1195
- // ── Reddit OAuth2 API ─────────────────────────────────────────────────────
1196
- {
1197
- name: "reddit_read",
1198
- description: "Read posts from a subreddit. Supports hot, new, top, and rising feeds. " +
1199
- "Returns post titles, scores, authors, URLs, and comment counts. " +
1200
- "Requires a Reddit OAuth2 bearer token with the 'read' scope.",
1201
- inputSchema: {
1202
- type: "object",
1203
- properties: {
1204
- access_token: { type: "string", description: "Reddit OAuth2 bearer token (scope: read)." },
1205
- subreddit: { type: "string", description: "Subreddit name, e.g. 'programming' or 'r/programming'." },
1206
- sort: { type: "string", enum: ["hot", "new", "top", "rising"], default: "hot", description: "Feed sort order (default: hot)." },
1207
- limit: { type: "number", minimum: 1, maximum: 100, default: 25, description: "Number of posts to return (1-100, default 25)." },
1208
- after: { type: "string", description: "Pagination cursor from a previous response (optional)." },
1209
- t: { type: "string", enum: ["hour", "day", "week", "month", "year", "all"], description: "Time filter for 'top' sort (optional)." },
1210
- },
1211
- required: ["access_token", "subreddit"],
1212
- },
1213
- },
1214
- {
1215
- name: "reddit_post",
1216
- description: "Submit a new post to a subreddit. Supports text (self) posts and link posts. " +
1217
- "Requires a Reddit OAuth2 bearer token with the 'submit' scope.",
1218
- inputSchema: {
1219
- type: "object",
1220
- properties: {
1221
- access_token: { type: "string", description: "Reddit OAuth2 bearer token (scope: submit)." },
1222
- subreddit: { type: "string", description: "Subreddit to post to, e.g. 'test' or 'r/test'." },
1223
- title: { type: "string", description: "Post title (required)." },
1224
- kind: { type: "string", enum: ["self", "link"], description: "'self' for text posts, 'link' for URL posts." },
1225
- text: { type: "string", description: "Post body in Markdown (required when kind is 'self')." },
1226
- url: { type: "string", description: "URL to submit (required when kind is 'link')." },
1227
- nsfw: { type: "boolean", default: false, description: "Mark post as NSFW (default false)." },
1228
- spoiler: { type: "boolean", default: false, description: "Mark post as spoiler (default false)." },
1229
- flair_id: { type: "string", description: "Flair template ID (optional)." },
1230
- flair_text: { type: "string", description: "Flair text (optional)." },
1231
- },
1232
- required: ["access_token", "subreddit", "title", "kind"],
1233
- },
1234
- },
1235
- {
1236
- name: "reddit_comment",
1237
- description: "Post a comment on a Reddit post or reply to an existing comment. " +
1238
- "Use the fullname of the parent (t3_ for posts, t1_ for comments). " +
1239
- "Requires a Reddit OAuth2 bearer token with the 'submit' scope.",
1240
- inputSchema: {
1241
- type: "object",
1242
- properties: {
1243
- access_token: { type: "string", description: "Reddit OAuth2 bearer token (scope: submit)." },
1244
- parent_id: { type: "string", description: "Fullname of the post or comment to reply to, e.g. 't3_abc123' or 't1_def456'." },
1245
- text: { type: "string", description: "Comment body in Markdown." },
1246
- },
1247
- required: ["access_token", "parent_id", "text"],
1248
- },
1249
- },
1250
- {
1251
- name: "reddit_search",
1252
- description: "Search posts across all of Reddit or within a specific subreddit. " +
1253
- "Supports relevance, hot, top, new, and comments sort orders. " +
1254
- "Requires a Reddit OAuth2 bearer token with the 'read' scope.",
1255
- inputSchema: {
1256
- type: "object",
1257
- properties: {
1258
- access_token: { type: "string", description: "Reddit OAuth2 bearer token (scope: read)." },
1259
- query: { type: "string", description: "Search query string." },
1260
- subreddit: { type: "string", description: "Restrict search to this subreddit (optional)." },
1261
- sort: { type: "string", enum: ["relevance", "hot", "top", "new", "comments"], default: "relevance", description: "Result sort order (default: relevance)." },
1262
- t: { type: "string", enum: ["hour", "day", "week", "month", "year", "all"], description: "Time filter for 'top' sort (optional)." },
1263
- limit: { type: "number", minimum: 1, maximum: 100, default: 25, description: "Number of results to return (1-100, default 25)." },
1264
- after: { type: "string", description: "Pagination cursor from a previous response (optional)." },
1265
- },
1266
- required: ["access_token", "query"],
1267
- },
1268
- },
1269
- {
1270
- name: "reddit_user",
1271
- description: "Get a Reddit user's profile and recent activity (posts and comments). " +
1272
- "Requires a Reddit OAuth2 bearer token with the 'read' scope.",
1273
- inputSchema: {
1274
- type: "object",
1275
- properties: {
1276
- access_token: { type: "string", description: "Reddit OAuth2 bearer token (scope: read)." },
1277
- username: { type: "string", description: "Reddit username, e.g. 'spez' or 'u/spez'." },
1278
- include_posts: { type: "boolean", default: true, description: "Include recent posts in the response (default true)." },
1279
- include_comments: { type: "boolean", default: true, description: "Include recent comments in the response (default true)." },
1280
- limit: { type: "number", minimum: 1, maximum: 100, default: 10, description: "Max recent posts/comments to return per type (default 10)." },
1281
- },
1282
- required: ["access_token", "username"],
1283
- },
1284
- },
1285
- {
1286
- name: "reddit_vote",
1287
- description: "Upvote, downvote, or remove your vote on a Reddit post or comment. " +
1288
- "Pass the fullname of the item (t3_ for posts, t1_ for comments). " +
1289
- "Requires a Reddit OAuth2 bearer token with the 'vote' scope.",
1290
- inputSchema: {
1291
- type: "object",
1292
- properties: {
1293
- access_token: { type: "string", description: "Reddit OAuth2 bearer token (scope: vote)." },
1294
- id: { type: "string", description: "Fullname of the post or comment, e.g. 't3_abc123' or 't1_def456'." },
1295
- dir: { type: "number", enum: [1, 0, -1], description: "Vote direction: 1 = upvote, 0 = remove vote, -1 = downvote." },
1296
- },
1297
- required: ["access_token", "id", "dir"],
1298
- },
1299
- },
1300
- {
1301
- name: "reddit_subscribe",
1302
- description: "Subscribe to or unsubscribe from a subreddit. " +
1303
- "Requires a Reddit OAuth2 bearer token with the 'subscribe' scope.",
219
+ name: "unclick_json_format",
220
+ description: "Format / pretty-print a JSON string.",
1304
221
  inputSchema: {
1305
222
  type: "object",
1306
223
  properties: {
1307
- access_token: { type: "string", description: "Reddit OAuth2 bearer token (scope: subscribe)." },
1308
- subreddit: { type: "string", description: "Subreddit name, e.g. 'programming' or 'r/programming'." },
1309
- action: { type: "string", enum: ["sub", "unsub"], description: "'sub' to subscribe, 'unsub' to unsubscribe." },
224
+ json: { type: "string" },
225
+ indent: { description: "2, 4, or 'tab'", default: 2 },
1310
226
  },
1311
- required: ["access_token", "subreddit", "action"],
227
+ required: ["json"],
1312
228
  },
1313
229
  },
1314
- // ── Bluesky / AT Protocol ─────────────────────────────────────────────────
1315
230
  {
1316
- name: "bluesky",
1317
- description: "Post, read, reply, like, repost, search, and follow on Bluesky social network via the AT Protocol. " +
1318
- "Authenticates per-call with your Bluesky handle/email and app password. " +
1319
- "Actions: bluesky_post, bluesky_read_feed, bluesky_reply, bluesky_like, bluesky_repost, " +
1320
- "bluesky_search, bluesky_profile, bluesky_follow.",
231
+ name: "unclick_encode",
232
+ description: "Encode or decode text. Supports base64, URL, HTML, and hex.",
1321
233
  inputSchema: {
1322
234
  type: "object",
1323
235
  properties: {
1324
- action: {
236
+ text: { type: "string" },
237
+ operation: {
1325
238
  type: "string",
1326
- enum: ["bluesky_post", "bluesky_read_feed", "bluesky_reply", "bluesky_like", "bluesky_repost", "bluesky_search", "bluesky_profile", "bluesky_follow"],
1327
- description: "bluesky_post: create a new post (up to 300 chars). " +
1328
- "bluesky_read_feed: read home timeline or a user's posts. " +
1329
- "bluesky_reply: reply to an existing post. " +
1330
- "bluesky_like: like a post by URI. " +
1331
- "bluesky_repost: repost/share a post by URI. " +
1332
- "bluesky_search: search posts or users by keyword. " +
1333
- "bluesky_profile: get a user's profile. " +
1334
- "bluesky_follow: follow or unfollow a user.",
239
+ enum: [
240
+ "encode_base64", "decode_base64",
241
+ "encode_url", "decode_url",
242
+ "encode_html", "decode_html",
243
+ "encode_hex", "decode_hex",
244
+ ],
1335
245
  },
1336
- identifier: { type: "string", description: "Your Bluesky handle (e.g. alice.bsky.social) or email address." },
1337
- password: { type: "string", description: "Your Bluesky app password. Create one at Settings > Privacy and Security > App Passwords." },
1338
- text: { type: "string", description: "Post or reply text (max 300 characters). Required for bluesky_post and bluesky_reply." },
1339
- langs: { type: "array", items: { type: "string" }, description: "BCP-47 language tags for the post, e.g. ['en']. Optional." },
1340
- feed_type: { type: "string", enum: ["home", "user"], default: "home", description: "bluesky_read_feed: 'home' for your timeline, 'user' for a specific actor's posts." },
1341
- actor: { type: "string", description: "Handle or DID of the target user. Required for bluesky_profile and bluesky_follow. Optional for bluesky_read_feed." },
1342
- post_uri: { type: "string", description: "AT URI of the post to like or repost. Required for bluesky_like and bluesky_repost." },
1343
- parent_uri: { type: "string", description: "AT URI of the post to reply to. Required for bluesky_reply." },
1344
- root_uri: { type: "string", description: "AT URI of the root post in the thread. Optional for bluesky_reply (defaults to parent_uri)." },
1345
- query: { type: "string", description: "Search query string. Required for bluesky_search." },
1346
- type: { type: "string", enum: ["posts", "users"], default: "posts", description: "bluesky_search: search 'posts' (default) or 'users'." },
1347
- unfollow: { type: "boolean", default: false, description: "bluesky_follow: set true to unfollow instead of follow." },
1348
- limit: { type: "number", minimum: 1, maximum: 100, default: 20, description: "Max results to return for feed/search operations." },
1349
- cursor: { type: "string", description: "Pagination cursor from a previous response." },
1350
- },
1351
- required: ["action", "identifier", "password"],
1352
- },
1353
- },
1354
- // ── Mastodon (works with any Mastodon-compatible instance) ───────────────
1355
- {
1356
- name: "mastodon_post",
1357
- description: "Create a new toot/status on Mastodon (or any compatible instance: Pleroma, Akkoma, Misskey). Supports visibility settings and content warnings.",
1358
- inputSchema: {
1359
- type: "object",
1360
- properties: {
1361
- instance_url: { type: "string", description: "Your Mastodon instance URL, e.g. 'mastodon.social'" },
1362
- access_token: { type: "string", description: "Your Mastodon access token" },
1363
- status: { type: "string", description: "The text content of the toot" },
1364
- visibility: { type: "string", enum: ["public", "unlisted", "private", "direct"], default: "public", description: "Who can see this post" },
1365
- spoiler_text: { type: "string", description: "Content warning text shown before the post body" },
1366
- sensitive: { type: "boolean", default: false, description: "Mark media as sensitive" },
1367
- media_ids: { type: "array", items: { type: "string" }, description: "IDs of already-uploaded media attachments to attach (up to 4)" },
1368
- },
1369
- required: ["instance_url", "access_token", "status"],
1370
- },
1371
- },
1372
- {
1373
- name: "mastodon_read_timeline",
1374
- description: "Read posts from a Mastodon timeline. home = accounts you follow, local = your instance only, public = federated (whole Fediverse).",
1375
- inputSchema: {
1376
- type: "object",
1377
- properties: {
1378
- instance_url: { type: "string", description: "Your Mastodon instance URL" },
1379
- access_token: { type: "string", description: "Your Mastodon access token" },
1380
- timeline: { type: "string", enum: ["home", "local", "public"], default: "home", description: "Which timeline to read" },
1381
- limit: { type: "number", minimum: 1, maximum: 40, default: 20, description: "Number of posts to return" },
1382
- max_id: { type: "string", description: "Return posts older than this status ID (for pagination)" },
1383
- },
1384
- required: ["instance_url", "access_token"],
1385
- },
1386
- },
1387
- {
1388
- name: "mastodon_reply",
1389
- description: "Reply to an existing Mastodon status.",
1390
- inputSchema: {
1391
- type: "object",
1392
- properties: {
1393
- instance_url: { type: "string", description: "Your Mastodon instance URL" },
1394
- access_token: { type: "string", description: "Your Mastodon access token" },
1395
- in_reply_to_id: { type: "string", description: "ID of the status to reply to" },
1396
- status: { type: "string", description: "Text content of your reply" },
1397
- visibility: { type: "string", enum: ["public", "unlisted", "private", "direct"], description: "Visibility of the reply (defaults to same as the original post)" },
1398
- spoiler_text: { type: "string", description: "Optional content warning text" },
1399
- },
1400
- required: ["instance_url", "access_token", "in_reply_to_id", "status"],
1401
- },
1402
- },
1403
- {
1404
- name: "mastodon_boost",
1405
- description: "Boost (reblog) a Mastodon status, or undo a boost.",
1406
- inputSchema: {
1407
- type: "object",
1408
- properties: {
1409
- instance_url: { type: "string", description: "Your Mastodon instance URL" },
1410
- access_token: { type: "string", description: "Your Mastodon access token" },
1411
- status_id: { type: "string", description: "ID of the status to boost" },
1412
- unboost: { type: "boolean", default: false, description: "If true, removes the boost instead" },
1413
- },
1414
- required: ["instance_url", "access_token", "status_id"],
1415
- },
1416
- },
1417
- {
1418
- name: "mastodon_favorite",
1419
- description: "Favorite (like) a Mastodon status, or remove a favorite.",
1420
- inputSchema: {
1421
- type: "object",
1422
- properties: {
1423
- instance_url: { type: "string", description: "Your Mastodon instance URL" },
1424
- access_token: { type: "string", description: "Your Mastodon access token" },
1425
- status_id: { type: "string", description: "ID of the status to favorite" },
1426
- unfavorite: { type: "boolean", default: false, description: "If true, removes the favorite instead" },
1427
- },
1428
- required: ["instance_url", "access_token", "status_id"],
1429
- },
1430
- },
1431
- {
1432
- name: "mastodon_search",
1433
- description: "Search Mastodon for posts, accounts, or hashtags. Omit 'type' to search all three categories at once.",
1434
- inputSchema: {
1435
- type: "object",
1436
- properties: {
1437
- instance_url: { type: "string", description: "Your Mastodon instance URL" },
1438
- access_token: { type: "string", description: "Your Mastodon access token" },
1439
- query: { type: "string", description: "Search term, hashtag, or account handle" },
1440
- type: { type: "string", enum: ["accounts", "statuses", "hashtags"], description: "Limit results to one category (optional)" },
1441
- limit: { type: "number", minimum: 1, maximum: 40, default: 20 },
1442
- resolve: { type: "boolean", default: true, description: "Resolve remote accounts/posts via WebFinger" },
1443
- },
1444
- required: ["instance_url", "access_token", "query"],
1445
- },
1446
- },
1447
- {
1448
- name: "mastodon_profile",
1449
- description: "Get account information for a Mastodon user. Omit account_id and acct to return your own profile.",
1450
- inputSchema: {
1451
- type: "object",
1452
- properties: {
1453
- instance_url: { type: "string", description: "Your Mastodon instance URL" },
1454
- access_token: { type: "string", description: "Your Mastodon access token" },
1455
- account_id: { type: "string", description: "Numeric account ID (takes priority over acct)" },
1456
- acct: { type: "string", description: "Account handle, e.g. 'user@mastodon.social' or just 'user'" },
1457
- },
1458
- required: ["instance_url", "access_token"],
1459
- },
1460
- },
1461
- {
1462
- name: "mastodon_follow",
1463
- description: "Follow or unfollow a Mastodon account. Returns the updated relationship.",
1464
- inputSchema: {
1465
- type: "object",
1466
- properties: {
1467
- instance_url: { type: "string", description: "Your Mastodon instance URL" },
1468
- access_token: { type: "string", description: "Your Mastodon access token" },
1469
- account_id: { type: "string", description: "Numeric ID of the account to follow/unfollow" },
1470
- unfollow: { type: "boolean", default: false, description: "If true, unfollows instead" },
1471
- },
1472
- required: ["instance_url", "access_token", "account_id"],
1473
- },
1474
- },
1475
- {
1476
- name: "mastodon_notifications",
1477
- description: "Read your Mastodon notifications. Notification types: mention, status, reblog, follow, follow_request, favourite, poll, update.",
1478
- inputSchema: {
1479
- type: "object",
1480
- properties: {
1481
- instance_url: { type: "string", description: "Your Mastodon instance URL" },
1482
- access_token: { type: "string", description: "Your Mastodon access token" },
1483
- limit: { type: "number", minimum: 1, maximum: 30, default: 15, description: "Number of notifications to return" },
1484
- max_id: { type: "string", description: "Return notifications older than this ID (for pagination)" },
1485
- types: { type: "array", items: { type: "string", enum: ["mention", "status", "reblog", "follow", "follow_request", "favourite", "poll", "update"] }, description: "Filter to specific notification types (optional)" },
1486
- },
1487
- required: ["instance_url", "access_token"],
1488
- },
1489
- },
1490
- // ── Amazon Product Advertising API 5.0 ───────────────────────────────────
1491
- {
1492
- name: "amazon_search",
1493
- description: "Search Amazon products by keyword, category (SearchIndex), browse node, or any combination. " +
1494
- "Uses Amazon PA-API 5.0 SearchItems endpoint. Returns titles, prices, images, ratings, and direct product URLs. " +
1495
- "Requires an Amazon Associates account: Access Key, Secret Key, and Partner Tag.",
1496
- inputSchema: {
1497
- type: "object",
1498
- properties: {
1499
- access_key: { type: "string", description: "Amazon PA-API access key ID" },
1500
- secret_key: { type: "string", description: "Amazon PA-API secret access key" },
1501
- partner_tag: { type: "string", description: "Amazon Associates partner/tracking tag (e.g. mytag-20)" },
1502
- keywords: { type: "string", description: "Search keywords (e.g. 'wireless headphones')" },
1503
- search_index: { type: "string", description: "Product category / SearchIndex (e.g. Electronics, Books, Apparel, All). Defaults to All." },
1504
- browse_node_id: { type: "string", description: "Amazon browse node ID to filter results" },
1505
- sort_by: { type: "string", enum: ["AvgCustomerReviews", "Featured", "NewestArrivals", "Price:HighToLow", "Price:LowToHigh", "Relevance"], description: "Sort order for results" },
1506
- min_price: { type: "number", description: "Minimum price in cents (e.g. 1000 = $10.00)" },
1507
- max_price: { type: "number", description: "Maximum price in cents (e.g. 5000 = $50.00)" },
1508
- item_count: { type: "number", description: "Number of results to return (1-10, default 10)", default: 10 },
1509
- item_page: { type: "number", description: "Results page number (1-10)", default: 1 },
1510
- marketplace: { type: "string", enum: ["US", "CA", "MX", "BR", "UK", "DE", "FR", "IT", "ES", "NL", "SE", "PL", "BE", "IN", "JP", "AU", "SG", "AE", "SA", "TR"], default: "US", description: "Amazon marketplace country code (default: US)" },
1511
- },
1512
- required: ["access_key", "secret_key", "partner_tag"],
1513
- },
1514
- },
1515
- {
1516
- name: "amazon_product",
1517
- description: "Get detailed product information for one or more Amazon products by ASIN. " +
1518
- "Uses Amazon PA-API 5.0 GetItems endpoint. Returns full details: title, price, features, images, ratings, brand, availability. " +
1519
- "Requires an Amazon Associates account.",
1520
- inputSchema: {
1521
- type: "object",
1522
- properties: {
1523
- access_key: { type: "string", description: "Amazon PA-API access key ID" },
1524
- secret_key: { type: "string", description: "Amazon PA-API secret access key" },
1525
- partner_tag: { type: "string", description: "Amazon Associates partner/tracking tag" },
1526
- asin: { type: "string", description: "Single product ASIN (e.g. B08N5WRWNW)" },
1527
- asins: { type: "array", items: { type: "string" }, description: "Array of ASINs for batch lookup (up to 10)" },
1528
- marketplace: { type: "string", enum: ["US", "CA", "MX", "BR", "UK", "DE", "FR", "IT", "ES", "NL", "SE", "PL", "BE", "IN", "JP", "AU", "SG", "AE", "SA", "TR"], default: "US", description: "Amazon marketplace country code (default: US)" },
1529
- },
1530
- required: ["access_key", "secret_key", "partner_tag"],
1531
- },
1532
- },
1533
- {
1534
- name: "amazon_browse",
1535
- description: "Browse Amazon product categories by browse node ID. " +
1536
- "Uses Amazon PA-API 5.0 GetBrowseNodes endpoint. Returns node name, parent ancestor, and child subcategories.",
1537
- inputSchema: {
1538
- type: "object",
1539
- properties: {
1540
- access_key: { type: "string", description: "Amazon PA-API access key ID" },
1541
- secret_key: { type: "string", description: "Amazon PA-API secret access key" },
1542
- partner_tag: { type: "string", description: "Amazon Associates partner/tracking tag" },
1543
- browse_node_id: { type: "string", description: "Single browse node ID (e.g. 172282 for Electronics)" },
1544
- browse_node_ids: { type: "array", items: { type: "string" }, description: "Array of browse node IDs for batch lookup" },
1545
- marketplace: { type: "string", enum: ["US", "CA", "MX", "BR", "UK", "DE", "FR", "IT", "ES", "NL", "SE", "PL", "BE", "IN", "JP", "AU", "SG", "AE", "SA", "TR"], default: "US", description: "Amazon marketplace country code (default: US)" },
1546
- },
1547
- required: ["access_key", "secret_key", "partner_tag"],
1548
- },
1549
- },
1550
- {
1551
- name: "amazon_variations",
1552
- description: "Get all product variations for an Amazon parent ASIN (colors, sizes, styles, etc.). " +
1553
- "Uses Amazon PA-API 5.0 GetVariations endpoint. Returns each variation with its own ASIN, price, and images.",
1554
- inputSchema: {
1555
- type: "object",
1556
- properties: {
1557
- access_key: { type: "string", description: "Amazon PA-API access key ID" },
1558
- secret_key: { type: "string", description: "Amazon PA-API secret access key" },
1559
- partner_tag: { type: "string", description: "Amazon Associates partner/tracking tag" },
1560
- asin: { type: "string", description: "Parent product ASIN whose variations to retrieve" },
1561
- variation_count: { type: "number", description: "Number of variations to return (1-10, default 10)", default: 10 },
1562
- variation_page: { type: "number", description: "Variations page number (1-10)", default: 1 },
1563
- marketplace: { type: "string", enum: ["US", "CA", "MX", "BR", "UK", "DE", "FR", "IT", "ES", "NL", "SE", "PL", "BE", "IN", "JP", "AU", "SG", "AE", "SA", "TR"], default: "US", description: "Amazon marketplace country code (default: US)" },
1564
- },
1565
- required: ["access_key", "secret_key", "partner_tag", "asin"],
1566
- },
1567
- },
1568
- // ── Xero accounting (OAuth 2.0, Xero API v2) ─────────────────────────────
1569
- {
1570
- name: "xero_invoices",
1571
- description: "List, get, or create invoices in Xero. Requires a valid OAuth 2.0 access_token and your Xero tenant_id.",
1572
- inputSchema: {
1573
- type: "object",
1574
- properties: {
1575
- access_token: { type: "string", description: "Xero OAuth 2.0 Bearer token" },
1576
- tenant_id: { type: "string", description: "Xero organisation tenant ID" },
1577
- action: { type: "string", enum: ["list", "get", "create"], default: "list", description: "Operation to perform" },
1578
- invoice_id: { type: "string", description: "Invoice ID or number (required for action='get')" },
1579
- body: { type: "object", description: "Invoice object to create (required for action='create'). Must include Type, Contact.ContactID, and LineItems." },
1580
- where: { type: "string", description: "OData-style filter, e.g. \"Status==\"DRAFT\"\"" },
1581
- order: { type: "string", description: "Sort field, e.g. \"DueDate DESC\"" },
1582
- page: { type: "number", description: "Page number (100 records per page)" },
1583
- page_size: { type: "number", description: "Records per page (max 1000)" },
1584
- statuses: { type: "string", description: "Comma-separated statuses, e.g. \"DRAFT,SUBMITTED\"" },
1585
- contact_ids: { type: "string", description: "Comma-separated ContactIDs to filter by" },
1586
- ids: { type: "string", description: "Comma-separated InvoiceIDs to fetch" },
1587
246
  },
1588
- required: ["access_token", "tenant_id"],
1589
- },
1590
- },
1591
- {
1592
- name: "xero_contacts",
1593
- description: "List, get, or create contacts (customers and suppliers) in Xero. Requires access_token and tenant_id.",
1594
- inputSchema: {
1595
- type: "object",
1596
- properties: {
1597
- access_token: { type: "string", description: "Xero OAuth 2.0 Bearer token" },
1598
- tenant_id: { type: "string", description: "Xero organisation tenant ID" },
1599
- action: { type: "string", enum: ["list", "get", "create"], default: "list" },
1600
- contact_id: { type: "string", description: "Contact ID (required for action='get')" },
1601
- body: { type: "object", description: "Contact object to create (required for action='create'). Must include Name." },
1602
- where: { type: "string", description: "OData-style filter" },
1603
- order: { type: "string", description: "Sort field" },
1604
- page: { type: "number", description: "Page number" },
1605
- page_size: { type: "number", description: "Records per page" },
1606
- search_term: { type: "string", description: "Search contacts by name, email, or account number" },
1607
- ids: { type: "string", description: "Comma-separated ContactIDs to fetch" },
1608
- include_archived: { type: "boolean", description: "Include archived contacts (default false)" },
1609
- },
1610
- required: ["access_token", "tenant_id"],
1611
- },
1612
- },
1613
- {
1614
- name: "xero_accounts",
1615
- description: "List the chart of accounts for a Xero organisation. Returns all accounts with their codes, types, and balances.",
1616
- inputSchema: {
1617
- type: "object",
1618
- properties: {
1619
- access_token: { type: "string", description: "Xero OAuth 2.0 Bearer token" },
1620
- tenant_id: { type: "string", description: "Xero organisation tenant ID" },
1621
- where: { type: "string", description: "OData-style filter, e.g. \"Type==\"BANK\"\"" },
1622
- order: { type: "string", description: "Sort field, e.g. \"Code ASC\"" },
1623
- },
1624
- required: ["access_token", "tenant_id"],
1625
- },
1626
- },
1627
- {
1628
- name: "xero_payments",
1629
- description: "List or create payments in Xero. action='list' returns payments; action='create' records a payment against an invoice.",
1630
- inputSchema: {
1631
- type: "object",
1632
- properties: {
1633
- access_token: { type: "string", description: "Xero OAuth 2.0 Bearer token" },
1634
- tenant_id: { type: "string", description: "Xero organisation tenant ID" },
1635
- action: { type: "string", enum: ["list", "create"], default: "list" },
1636
- body: { type: "object", description: "Payment object (required for action='create'). Must include Invoice.InvoiceID, Account.AccountID, Date, and Amount." },
1637
- where: { type: "string", description: "OData-style filter" },
1638
- order: { type: "string", description: "Sort field" },
1639
- page: { type: "number", description: "Page number" },
1640
- },
1641
- required: ["access_token", "tenant_id"],
247
+ required: ["text", "operation"],
1642
248
  },
1643
249
  },
1644
250
  {
1645
- name: "xero_bank_transactions",
1646
- description: "List bank transactions for a Xero organisation. Returns spend and receive money transactions from bank accounts.",
251
+ name: "unclick_generate_uuid",
252
+ description: "Generate one or more random UUIDs (v4).",
1647
253
  inputSchema: {
1648
254
  type: "object",
1649
255
  properties: {
1650
- access_token: { type: "string", description: "Xero OAuth 2.0 Bearer token" },
1651
- tenant_id: { type: "string", description: "Xero organisation tenant ID" },
1652
- where: { type: "string", description: "OData-style filter" },
1653
- order: { type: "string", description: "Sort field" },
1654
- page: { type: "number", description: "Page number (100 per page)" },
256
+ count: { type: "number", minimum: 1, maximum: 100, default: 1 },
1655
257
  },
1656
- required: ["access_token", "tenant_id"],
1657
258
  },
1658
259
  },
1659
260
  {
1660
- name: "xero_reports",
1661
- description: "Retrieve financial reports from Xero. " +
1662
- "Common report IDs: ProfitAndLoss, BalanceSheet, CashSummary, ExecutiveSummary, TrialBalance, BankSummary, AgedReceivablesByContact, AgedPayablesByContact.",
261
+ name: "unclick_random_password",
262
+ description: "Generate a secure random password.",
1663
263
  inputSchema: {
1664
264
  type: "object",
1665
265
  properties: {
1666
- access_token: { type: "string", description: "Xero OAuth 2.0 Bearer token" },
1667
- tenant_id: { type: "string", description: "Xero organisation tenant ID" },
1668
- report_id: { type: "string", description: "Report identifier. Options: ProfitAndLoss, BalanceSheet, CashSummary, ExecutiveSummary, TrialBalance, BankSummary, AgedReceivablesByContact, AgedPayablesByContact." },
1669
- from_date: { type: "string", description: "Report start date, e.g. '2024-01-01'" },
1670
- to_date: { type: "string", description: "Report end date, e.g. '2024-12-31'" },
1671
- date: { type: "string", description: "As-at date for balance sheet reports" },
1672
- periods: { type: "number", description: "Number of periods to compare" },
1673
- timeframe: { type: "string", description: "Comparison period: MONTH, QUARTER, YEAR" },
1674
- contact_id: { type: "string", description: "ContactID for aged receivables/payables reports" },
1675
- account_id: { type: "string", description: "AccountID to filter by" },
266
+ length: { type: "number", minimum: 4, maximum: 512, default: 16 },
267
+ uppercase: { type: "boolean", default: true },
268
+ lowercase: { type: "boolean", default: true },
269
+ numbers: { type: "boolean", default: true },
270
+ symbols: { type: "boolean", default: true },
1676
271
  },
1677
- required: ["access_token", "tenant_id", "report_id"],
1678
272
  },
1679
273
  },
1680
274
  {
1681
- name: "xero_quotes",
1682
- description: "List, get, or create quotes (sales quotes) in Xero. Requires access_token and tenant_id.",
275
+ name: "unclick_cron_parse",
276
+ description: "Convert a cron expression to a human-readable description and get next occurrences.",
1683
277
  inputSchema: {
1684
278
  type: "object",
1685
279
  properties: {
1686
- access_token: { type: "string", description: "Xero OAuth 2.0 Bearer token" },
1687
- tenant_id: { type: "string", description: "Xero organisation tenant ID" },
1688
- action: { type: "string", enum: ["list", "get", "create"], default: "list" },
1689
- quote_id: { type: "string", description: "Quote ID (required for action='get')" },
1690
- body: { type: "object", description: "Quote object to create (required for action='create'). Must include Contact.ContactID and LineItems." },
1691
- status: { type: "string", description: "Filter by status: DRAFT, SENT, DECLINED, ACCEPTED, INVOICED, DELETED" },
1692
- contact_id: { type: "string", description: "Filter by ContactID" },
1693
- date_from: { type: "string", description: "Filter quotes from this date, e.g. '2024-01-01'" },
1694
- date_to: { type: "string", description: "Filter quotes to this date, e.g. '2024-12-31'" },
1695
- page: { type: "number", description: "Page number" },
280
+ expression: { type: "string", description: "e.g. '0 9 * * 1-5' (weekdays at 9am)" },
281
+ next_count: { type: "number", minimum: 1, maximum: 10, default: 5 },
1696
282
  },
1697
- required: ["access_token", "tenant_id"],
283
+ required: ["expression"],
1698
284
  },
1699
285
  },
1700
286
  {
1701
- name: "xero_organisation",
1702
- description: "Get organisation and tenant information from Xero. Returns legal name, organisation type, base currency, country, financial year end, and subscription status.",
287
+ name: "unclick_ip_parse",
288
+ description: "Parse an IP address get decimal, binary, hex, and type (private/loopback/multicast).",
1703
289
  inputSchema: {
1704
290
  type: "object",
1705
291
  properties: {
1706
- access_token: { type: "string", description: "Xero OAuth 2.0 Bearer token" },
1707
- tenant_id: { type: "string", description: "Xero organisation tenant ID" },
292
+ ip: { type: "string" },
1708
293
  },
1709
- required: ["access_token", "tenant_id"],
294
+ required: ["ip"],
1710
295
  },
1711
296
  },
1712
- // ── Shopify Admin API ─────────────────────────────────────────────────────
1713
297
  {
1714
- name: "shopify_products",
1715
- description: "Manage Shopify products via the Admin REST API. List all products, get a single product by ID, create a new product, or update an existing one.",
298
+ name: "unclick_color_convert",
299
+ description: "Convert a color between hex, RGB, HSL, and HSV formats.",
1716
300
  inputSchema: {
1717
301
  type: "object",
1718
302
  properties: {
1719
- store: { type: "string", description: "Shopify store domain, e.g. 'mystore' or 'mystore.myshopify.com'." },
1720
- access_token: { type: "string", description: "Shopify Admin API access token (shpat_...)." },
1721
- action: { type: "string", enum: ["list", "get", "create", "update"], default: "list", description: "list: all products. get: one by ID. create: new product. update: edit existing." },
1722
- id: { type: "string", description: "Product ID (required for get and update)." },
1723
- product: { type: "object", description: "Product data for create or update. Keys: title, body_html, vendor, product_type, tags, variants, images, status." },
1724
- limit: { type: "number", minimum: 1, maximum: 250, default: 50 },
1725
- page_info: { type: "string", description: "Cursor for paginating through results (from _pagination.next)." },
1726
- status: { type: "string", enum: ["active", "archived", "draft"], description: "Filter by product status (list only)." },
1727
- vendor: { type: "string", description: "Filter by vendor (list only)." },
1728
- product_type: { type: "string", description: "Filter by product type (list only)." },
1729
- published_status: { type: "string", enum: ["published", "unpublished", "any"], description: "Filter by published status (list only)." },
1730
- title: { type: "string", description: "Filter by title (list only)." },
1731
- since_id: { type: "string", description: "Return only products after this ID (list only)." },
1732
- fields: { type: "string", description: "Comma-separated list of fields to return." },
303
+ color: {
304
+ description: "Color as hex string (e.g. '#ff6b6b'), RGB object {r,g,b}, or HSL object {h,s,l}",
305
+ },
1733
306
  },
1734
- required: ["store", "access_token"],
307
+ required: ["color"],
1735
308
  },
1736
309
  },
1737
310
  {
1738
- name: "shopify_orders",
1739
- description: "List or retrieve Shopify orders via the Admin REST API. Filter by status, financial status, fulfillment status, and date ranges.",
311
+ name: "unclick_regex_test",
312
+ description: "Test a regex pattern against text and get all matches with groups.",
1740
313
  inputSchema: {
1741
314
  type: "object",
1742
315
  properties: {
1743
- store: { type: "string", description: "Shopify store domain." },
1744
- access_token: { type: "string", description: "Shopify Admin API access token." },
1745
- action: { type: "string", enum: ["list", "get"], default: "list", description: "list: all orders. get: one order by ID." },
1746
- id: { type: "string", description: "Order ID (required for get)." },
1747
- limit: { type: "number", minimum: 1, maximum: 250, default: 50 },
1748
- status: { type: "string", enum: ["open", "closed", "cancelled", "any"], default: "any" },
1749
- financial_status: { type: "string", enum: ["authorized", "pending", "paid", "partially_paid", "refunded", "voided", "partially_refunded", "any"] },
1750
- fulfillment_status: { type: "string", enum: ["shipped", "partial", "unshipped", "unfulfilled", "any"] },
1751
- since_id: { type: "string" },
1752
- created_at_min: { type: "string", description: "ISO 8601 datetime, e.g. '2024-01-01T00:00:00Z'." },
1753
- created_at_max: { type: "string", description: "ISO 8601 datetime." },
1754
- page_info: { type: "string", description: "Cursor for next/previous page." },
1755
- fields: { type: "string", description: "Comma-separated fields to return." },
316
+ pattern: { type: "string", description: "Regex pattern (no surrounding slashes)" },
317
+ flags: { type: "string", description: "Flags like 'gi'", default: "" },
318
+ input: { type: "string" },
1756
319
  },
1757
- required: ["store", "access_token"],
320
+ required: ["pattern", "input"],
1758
321
  },
1759
322
  },
1760
323
  {
1761
- name: "shopify_customers",
1762
- description: "List, retrieve, or search Shopify customers via the Admin REST API.",
324
+ name: "unclick_timestamp_convert",
325
+ description: "Convert a timestamp (ISO, Unix seconds, or Unix ms) to all common formats.",
1763
326
  inputSchema: {
1764
327
  type: "object",
1765
328
  properties: {
1766
- store: { type: "string", description: "Shopify store domain." },
1767
- access_token: { type: "string", description: "Shopify Admin API access token." },
1768
- action: { type: "string", enum: ["list", "get", "search"], default: "list", description: "list: all customers. get: one by ID. search: query by email/name/phone." },
1769
- id: { type: "string", description: "Customer ID (required for get)." },
1770
- query: { type: "string", description: "Search query (required for search), e.g. 'email:foo@bar.com' or 'Bob'." },
1771
- limit: { type: "number", minimum: 1, maximum: 250, default: 50 },
1772
- since_id: { type: "string" },
1773
- created_at_min: { type: "string" },
1774
- created_at_max: { type: "string" },
1775
- updated_at_min: { type: "string" },
1776
- page_info: { type: "string" },
1777
- fields: { type: "string" },
329
+ timestamp: {
330
+ description: "ISO string, Unix seconds (e.g. 1700000000), or Unix ms (e.g. 1700000000000)",
331
+ },
1778
332
  },
1779
- required: ["store", "access_token"],
333
+ required: ["timestamp"],
1780
334
  },
1781
335
  },
1782
336
  {
1783
- name: "shopify_inventory",
1784
- description: "Get inventory levels for specific items or locations from Shopify. At least one of inventory_item_ids or location_ids must be provided.",
337
+ name: "unclick_diff_text",
338
+ description: "Compare two strings and return a unified diff showing what changed.",
1785
339
  inputSchema: {
1786
340
  type: "object",
1787
341
  properties: {
1788
- store: { type: "string", description: "Shopify store domain." },
1789
- access_token: { type: "string", description: "Shopify Admin API access token." },
1790
- inventory_item_ids: { description: "One or more inventory item IDs (string or array of strings)." },
1791
- location_ids: { description: "One or more location IDs (string or array of strings)." },
1792
- limit: { type: "number", minimum: 1, maximum: 250, default: 50 },
342
+ a: { type: "string", description: "Original text" },
343
+ b: { type: "string", description: "New text" },
1793
344
  },
1794
- required: ["store", "access_token"],
345
+ required: ["a", "b"],
1795
346
  },
1796
347
  },
1797
348
  {
1798
- name: "shopify_collections",
1799
- description: "List Shopify collections (custom and/or smart) via the Admin REST API.",
349
+ name: "unclick_kv_set",
350
+ description: "Store a value in the UnClick key-value store with optional TTL.",
1800
351
  inputSchema: {
1801
352
  type: "object",
1802
353
  properties: {
1803
- store: { type: "string", description: "Shopify store domain." },
1804
- access_token: { type: "string", description: "Shopify Admin API access token." },
1805
- type: { type: "string", enum: ["all", "custom", "smart"], default: "all", description: "Which collection type to fetch." },
1806
- limit: { type: "number", minimum: 1, maximum: 250, default: 50 },
1807
- since_id: { type: "string" },
1808
- title: { type: "string", description: "Filter by collection title." },
1809
- fields: { type: "string" },
354
+ key: { type: "string" },
355
+ value: { description: "Any JSON-serializable value" },
356
+ ttl: { type: "number", description: "Seconds until expiry (optional)" },
1810
357
  },
1811
- required: ["store", "access_token"],
358
+ required: ["key", "value"],
1812
359
  },
1813
360
  },
1814
361
  {
1815
- name: "shopify_shop",
1816
- description: "Get store information for a Shopify shop: name, email, domain, currency, timezone, plan, and more.",
362
+ name: "unclick_kv_get",
363
+ description: "Retrieve a value from the UnClick key-value store.",
1817
364
  inputSchema: {
1818
365
  type: "object",
1819
366
  properties: {
1820
- store: { type: "string", description: "Shopify store domain." },
1821
- access_token: { type: "string", description: "Shopify Admin API access token." },
367
+ key: { type: "string" },
1822
368
  },
1823
- required: ["store", "access_token"],
369
+ required: ["key"],
1824
370
  },
1825
371
  },
1826
372
  {
1827
- name: "shopify_fulfillments",
1828
- description: "List or create fulfillments for a Shopify order via the Admin REST API.",
373
+ name: "report_bug",
374
+ description: "Report a bug or unexpected behavior encountered while using an UnClick tool. " +
375
+ "Call this whenever a tool returns an error, behaves unexpectedly, or fails silently. " +
376
+ "Severity is auto-classified from the error message: 500/fatal → critical, " +
377
+ "timeout/503 → high, 4xx/invalid → low, everything else → medium.",
1829
378
  inputSchema: {
1830
379
  type: "object",
1831
380
  properties: {
1832
- store: { type: "string", description: "Shopify store domain." },
1833
- access_token: { type: "string", description: "Shopify Admin API access token." },
1834
- order_id: { type: "string", description: "The order ID to list or create fulfillments for." },
1835
- action: { type: "string", enum: ["list", "create"], default: "list", description: "list: all fulfillments for the order. create: create a new fulfillment." },
1836
- fulfillment: { type: "object", description: "Fulfillment data for action='create'. Keys: location_id (required), tracking_number, tracking_company, tracking_url, notify_customer, line_items_by_fulfillment_order." },
1837
- limit: { type: "number", minimum: 1, maximum: 250, default: 50 },
1838
- since_id: { type: "string" },
1839
- fields: { type: "string" },
381
+ tool_name: {
382
+ type: "string",
383
+ description: "Name or slug of the UnClick tool that failed (e.g. 'image', 'hash', 'uuid')",
384
+ },
385
+ error_message: {
386
+ type: "string",
387
+ description: "The error message or unexpected output received",
388
+ },
389
+ request_payload: {
390
+ type: "object",
391
+ description: "The request parameters sent to the tool (optional)",
392
+ },
393
+ expected_behavior: {
394
+ type: "string",
395
+ description: "What the tool should have done instead (optional)",
396
+ },
397
+ agent_context: {
398
+ type: "string",
399
+ description: "Brief description of what the agent was trying to accomplish (optional)",
400
+ },
1840
401
  },
1841
- required: ["store", "access_token", "order_id"],
402
+ required: ["tool_name", "error_message"],
1842
403
  },
1843
404
  },
1844
405
  ];
@@ -1851,6 +412,7 @@ const DIRECT_HANDLERS = {
1851
412
  unclick_validate_url: (c, a) => c.call("POST", "/v1/validate/url", a),
1852
413
  unclick_resize_image: (c, a) => c.call("POST", "/v1/image/resize", a),
1853
414
  unclick_parse_csv: (c, a) => c.call("POST", "/v1/csv/parse", a),
415
+ unclick_json_format: (c, a) => c.call("POST", "/v1/json/format", a),
1854
416
  unclick_encode: async (c, a) => {
1855
417
  const op = a.operation;
1856
418
  const [action, format] = op.split("_");
@@ -1877,293 +439,6 @@ const DIRECT_HANDLERS = {
1877
439
  unclick_kv_set: (c, a) => c.call("POST", "/v1/kv/set", a),
1878
440
  unclick_kv_get: (c, a) => c.call("POST", "/v1/kv/get", a),
1879
441
  report_bug: (c, a) => c.call("POST", "/v1/report-bug", a),
1880
- csuite_analyze: async (_c, a) => {
1881
- const scenario = String(a.scenario ?? "");
1882
- if (!scenario.trim())
1883
- return { error: "scenario is required and cannot be empty." };
1884
- return csuitAnalyze(scenario, {
1885
- context: a.context ? String(a.context) : undefined,
1886
- perspectives: Array.isArray(a.perspectives) ? a.perspectives.map(String) : undefined,
1887
- depth: a.depth ?? "standard",
1888
- focus: a.focus ? String(a.focus) : undefined,
1889
- });
1890
- },
1891
- // ── Local handlers (pure computation, no API call) ────────────────────────
1892
- unclick_count_text: async (_c, a) => countText(String(a.text ?? "")),
1893
- unclick_slug: async (_c, a) => ({ slug: generateSlug(String(a.text ?? ""), String(a.separator ?? "-")) }),
1894
- unclick_lorem_ipsum: async (_c, a) => {
1895
- const count = Math.min(100, Math.max(1, Number(a.count ?? 5)));
1896
- const unit = a.unit ?? "sentences";
1897
- const startWithLorem = a.start_with_lorem !== false;
1898
- return { text: generateLorem(count, unit, startWithLorem), unit, count };
1899
- },
1900
- unclick_decode_jwt: async (_c, a) => decodeJwt(String(a.token ?? "")),
1901
- unclick_http_status: async (_c, a) => lookupHttpStatus(Number(a.code)),
1902
- unclick_emoji_search: async (_c, a) => {
1903
- const limit = Math.min(30, Math.max(1, Number(a.limit ?? 10)));
1904
- const results = searchEmoji(String(a.keyword ?? ""), limit);
1905
- return {
1906
- keyword: a.keyword,
1907
- count: results.length,
1908
- results: results.map((e) => ({ emoji: e.emoji, name: e.name, keywords: e.keywords })),
1909
- };
1910
- },
1911
- unclick_parse_user_agent: async (_c, a) => parseUserAgent(String(a.user_agent ?? "")),
1912
- unclick_readme_template: async (_c, a) => {
1913
- const md = generateReadme({
1914
- name: String(a.name ?? ""),
1915
- description: String(a.description ?? ""),
1916
- install: a.install ? String(a.install) : undefined,
1917
- usage: a.usage ? String(a.usage) : undefined,
1918
- language: a.language ? String(a.language) : undefined,
1919
- license: a.license ? String(a.license) : "MIT",
1920
- repo: a.repo ? String(a.repo) : undefined,
1921
- badges: a.badges !== false,
1922
- });
1923
- return { markdown: md };
1924
- },
1925
- unclick_changelog_entry: async (_c, a) => {
1926
- const toStrArray = (v) => Array.isArray(v) ? v.map(String) : [];
1927
- const md = generateChangelog({
1928
- version: String(a.version ?? "0.0.0"),
1929
- date: a.date ? String(a.date) : undefined,
1930
- added: toStrArray(a.added),
1931
- changed: toStrArray(a.changed),
1932
- deprecated: toStrArray(a.deprecated),
1933
- removed: toStrArray(a.removed),
1934
- fixed: toStrArray(a.fixed),
1935
- security: toStrArray(a.security),
1936
- });
1937
- return { markdown: md };
1938
- },
1939
- unclick_favicon_url: async (_c, a) => getFaviconUrls(String(a.domain ?? "")),
1940
- // ── Converter handlers ────────────────────────────────────────────────────
1941
- unclick_markdown_to_html: async (_c, a) => markdownToHtml(String(a.markdown ?? "")),
1942
- unclick_html_to_markdown: async (_c, a) => htmlToMarkdown(String(a.html ?? "")),
1943
- unclick_json_to_yaml: async (_c, a) => jsonToYaml(String(a.json ?? ""), Number(a.indent ?? 2)),
1944
- unclick_yaml_to_json: async (_c, a) => yamlToJson(String(a.yaml ?? ""), Number(a.indent ?? 2)),
1945
- unclick_json_to_xml: async (_c, a) => jsonToXml(String(a.json ?? ""), a.root_key ? String(a.root_key) : "root"),
1946
- unclick_xml_to_json: async (_c, a) => xmlToJson(String(a.xml ?? ""), Number(a.indent ?? 2)),
1947
- unclick_json_to_toml: async (_c, a) => jsonToToml(String(a.json ?? "")),
1948
- unclick_toml_to_json: async (_c, a) => tomlToJson(String(a.toml ?? ""), Number(a.indent ?? 2)),
1949
- unclick_csv_to_json: async (_c, a) => csvToJson(String(a.csv ?? ""), {
1950
- header: a.header !== false,
1951
- delimiter: a.delimiter ? String(a.delimiter) : ",",
1952
- }),
1953
- unclick_json_to_csv: async (_c, a) => jsonToCsv(String(a.json ?? ""), {
1954
- delimiter: a.delimiter ? String(a.delimiter) : ",",
1955
- }),
1956
- unclick_json_format: async (_c, a) => {
1957
- const indent = a.indent === "tab" || a.indent === "minify"
1958
- ? a.indent
1959
- : Number(a.indent ?? 2);
1960
- return jsonFormat(String(a.json ?? ""), indent);
1961
- },
1962
- unclick_json_to_jsonl: async (_c, a) => jsonToJsonl(String(a.json ?? "")),
1963
- unclick_jsonl_to_json: async (_c, a) => jsonlToJson(String(a.jsonl ?? ""), Number(a.indent ?? 2)),
1964
- // ── Encoding & utility converter handlers ─────────────────────────────────
1965
- binary_to_decimal: async (_c, a) => {
1966
- const bin = String(a.binary ?? "").trim().replace(/^0b/i, "");
1967
- if (!/^[01]+$/.test(bin))
1968
- return { error: "Invalid binary string. Use only 0 and 1." };
1969
- const decimal = parseInt(bin, 2);
1970
- return { binary: bin, decimal, decimal_string: String(decimal) };
1971
- },
1972
- decimal_to_binary: async (_c, a) => {
1973
- const n = Math.trunc(Number(a.decimal));
1974
- if (!Number.isFinite(n))
1975
- return { error: "Invalid decimal number." };
1976
- const binary = Math.abs(n).toString(2);
1977
- return { decimal: n, binary: n < 0 ? `-${binary}` : binary };
1978
- },
1979
- hex_to_decimal: async (_c, a) => {
1980
- const hex = String(a.hex ?? "").trim().replace(/^0x/i, "");
1981
- if (!/^[0-9a-fA-F]+$/.test(hex))
1982
- return { error: "Invalid hex string." };
1983
- const decimal = parseInt(hex, 16);
1984
- return { hex: hex.toUpperCase(), decimal, decimal_string: String(decimal) };
1985
- },
1986
- decimal_to_hex: async (_c, a) => {
1987
- const n = Math.trunc(Number(a.decimal));
1988
- if (!Number.isFinite(n))
1989
- return { error: "Invalid decimal number." };
1990
- const hex = Math.abs(n).toString(16).toUpperCase();
1991
- return { decimal: n, hex: n < 0 ? `-${hex}` : hex, hex_prefixed: n < 0 ? `-0x${hex}` : `0x${hex}` };
1992
- },
1993
- octal_to_decimal: async (_c, a) => {
1994
- const oct = String(a.octal ?? "").trim().replace(/^0o/i, "");
1995
- if (!/^[0-7]+$/.test(oct))
1996
- return { error: "Invalid octal string. Use only digits 0–7." };
1997
- const decimal = parseInt(oct, 8);
1998
- return { octal: oct, decimal, decimal_string: String(decimal) };
1999
- },
2000
- decimal_to_octal: async (_c, a) => {
2001
- const n = Math.trunc(Number(a.decimal));
2002
- if (!Number.isFinite(n))
2003
- return { error: "Invalid decimal number." };
2004
- const octal = Math.abs(n).toString(8);
2005
- return { decimal: n, octal: n < 0 ? `-${octal}` : octal };
2006
- },
2007
- celsius_to_fahrenheit: async (_c, a) => {
2008
- const c = Number(a.celsius);
2009
- if (!Number.isFinite(c))
2010
- return { error: "Invalid Celsius value." };
2011
- const f = (c * 9) / 5 + 32;
2012
- return { celsius: c, fahrenheit: Math.round(f * 100) / 100 };
2013
- },
2014
- fahrenheit_to_celsius: async (_c, a) => {
2015
- const f = Number(a.fahrenheit);
2016
- if (!Number.isFinite(f))
2017
- return { error: "Invalid Fahrenheit value." };
2018
- const c = ((f - 32) * 5) / 9;
2019
- return { fahrenheit: f, celsius: Math.round(c * 100) / 100 };
2020
- },
2021
- bytes_to_human: async (_c, a) => {
2022
- const bytes = Number(a.bytes);
2023
- if (!Number.isFinite(bytes) || bytes < 0)
2024
- return { error: "Invalid byte count." };
2025
- const units = ["B", "KB", "MB", "GB", "TB", "PB"];
2026
- let value = bytes;
2027
- let unitIndex = 0;
2028
- while (value >= 1024 && unitIndex < units.length - 1) {
2029
- value /= 1024;
2030
- unitIndex++;
2031
- }
2032
- const rounded = Math.round(value * 100) / 100;
2033
- return { bytes, human: `${rounded} ${units[unitIndex]}`, value: rounded, unit: units[unitIndex] };
2034
- },
2035
- vault: async (_c, a) => {
2036
- const action = String(a.action ?? "").trim();
2037
- if (!action)
2038
- return { error: "action is required." };
2039
- return vaultAction(action, a);
2040
- },
2041
- human_to_bytes: async (_c, a) => {
2042
- const raw = String(a.size ?? "").trim();
2043
- const match = raw.match(/^([0-9]*\.?[0-9]+)\s*(B|KB|MB|GB|TB|PB)?$/i);
2044
- if (!match)
2045
- return { error: `Cannot parse size string: "${raw}". Expected format like '1.5 GB' or '512 MB'.` };
2046
- const value = parseFloat(match[1]);
2047
- const unitMap = {
2048
- b: 1, kb: 1024, mb: 1024 ** 2, gb: 1024 ** 3, tb: 1024 ** 4, pb: 1024 ** 5,
2049
- };
2050
- const unit = (match[2] ?? "b").toLowerCase();
2051
- const bytes = Math.round(value * (unitMap[unit] ?? 1));
2052
- return { size: raw, bytes, unit: (match[2] ?? "B").toUpperCase() };
2053
- },
2054
- // ── Telegram handlers ─────────────────────────────────────────────────────
2055
- telegram_send: async (_c, a) => telegramSend(a),
2056
- telegram_read: async (_c, a) => telegramRead(a),
2057
- telegram_search: async (_c, a) => telegramSearch(a),
2058
- telegram_send_media: async (_c, a) => telegramSendMedia(a),
2059
- telegram_get_updates: async (_c, a) => telegramGetUpdates(a),
2060
- telegram_manage_chat: async (_c, a) => telegramManageChat(a),
2061
- // ── Slack handler ─────────────────────────────────────────────────────────
2062
- slack: async (_c, a) => {
2063
- const action = String(a.action ?? "").trim();
2064
- if (!action)
2065
- return { error: "action is required." };
2066
- return slackAction(action, a);
2067
- },
2068
- // ── Discord handlers ──────────────────────────────────────────────────────
2069
- discord_send: async (_c, a) => discordSend(a),
2070
- discord_read: async (_c, a) => discordRead(a),
2071
- discord_thread: async (_c, a) => discordThread(a),
2072
- discord_react: async (_c, a) => discordReact(a),
2073
- discord_channels: async (_c, a) => discordChannels(a),
2074
- discord_members: async (_c, a) => discordMembers(a),
2075
- discord_search: async (_c, a) => discordSearch(a),
2076
- // ── Reddit handlers ───────────────────────────────────────────────────────
2077
- reddit_read: async (_c, a) => redditRead({
2078
- access_token: String(a.access_token ?? ""),
2079
- subreddit: String(a.subreddit ?? ""),
2080
- sort: a.sort ? String(a.sort) : undefined,
2081
- limit: a.limit ? Number(a.limit) : undefined,
2082
- after: a.after ? String(a.after) : undefined,
2083
- t: a.t ? String(a.t) : undefined,
2084
- }),
2085
- reddit_post: async (_c, a) => redditPost({
2086
- access_token: String(a.access_token ?? ""),
2087
- subreddit: String(a.subreddit ?? ""),
2088
- title: String(a.title ?? ""),
2089
- kind: String(a.kind ?? "self"),
2090
- text: a.text ? String(a.text) : undefined,
2091
- url: a.url ? String(a.url) : undefined,
2092
- nsfw: a.nsfw === true,
2093
- spoiler: a.spoiler === true,
2094
- flair_id: a.flair_id ? String(a.flair_id) : undefined,
2095
- flair_text: a.flair_text ? String(a.flair_text) : undefined,
2096
- }),
2097
- reddit_comment: async (_c, a) => redditComment({
2098
- access_token: String(a.access_token ?? ""),
2099
- parent_id: String(a.parent_id ?? ""),
2100
- text: String(a.text ?? ""),
2101
- }),
2102
- reddit_search: async (_c, a) => redditSearch({
2103
- access_token: String(a.access_token ?? ""),
2104
- query: String(a.query ?? ""),
2105
- subreddit: a.subreddit ? String(a.subreddit) : undefined,
2106
- sort: a.sort ? String(a.sort) : undefined,
2107
- t: a.t ? String(a.t) : undefined,
2108
- limit: a.limit ? Number(a.limit) : undefined,
2109
- after: a.after ? String(a.after) : undefined,
2110
- }),
2111
- reddit_user: async (_c, a) => redditUser({
2112
- access_token: String(a.access_token ?? ""),
2113
- username: String(a.username ?? ""),
2114
- include_posts: a.include_posts !== false,
2115
- include_comments: a.include_comments !== false,
2116
- limit: a.limit ? Number(a.limit) : undefined,
2117
- }),
2118
- reddit_vote: async (_c, a) => redditVote({
2119
- access_token: String(a.access_token ?? ""),
2120
- id: String(a.id ?? ""),
2121
- dir: Number(a.dir ?? 0),
2122
- }),
2123
- reddit_subscribe: async (_c, a) => redditSubscribe({
2124
- access_token: String(a.access_token ?? ""),
2125
- subreddit: String(a.subreddit ?? ""),
2126
- action: String(a.action ?? "sub"),
2127
- }),
2128
- // ── Bluesky handler ───────────────────────────────────────────────────────
2129
- bluesky: async (_c, a) => {
2130
- const action = String(a.action ?? "").trim();
2131
- if (!action)
2132
- return { error: "action is required." };
2133
- return blueskyAction(action, a);
2134
- },
2135
- // ── Mastodon handlers ─────────────────────────────────────────────────────
2136
- mastodon_post: async (_c, a) => mastodonAction("mastodon_post", a),
2137
- mastodon_read_timeline: async (_c, a) => mastodonAction("mastodon_read_timeline", a),
2138
- mastodon_reply: async (_c, a) => mastodonAction("mastodon_reply", a),
2139
- mastodon_boost: async (_c, a) => mastodonAction("mastodon_boost", a),
2140
- mastodon_favorite: async (_c, a) => mastodonAction("mastodon_favorite", a),
2141
- mastodon_search: async (_c, a) => mastodonAction("mastodon_search", a),
2142
- mastodon_profile: async (_c, a) => mastodonAction("mastodon_profile", a),
2143
- mastodon_follow: async (_c, a) => mastodonAction("mastodon_follow", a),
2144
- mastodon_notifications: async (_c, a) => mastodonAction("mastodon_notifications", a),
2145
- // ── Amazon handlers ───────────────────────────────────────────────────────
2146
- amazon_search: async (_c, a) => amazonSearch(a),
2147
- amazon_product: async (_c, a) => amazonProduct(a),
2148
- amazon_browse: async (_c, a) => amazonBrowse(a),
2149
- amazon_variations: async (_c, a) => amazonVariations(a),
2150
- // ── Xero handlers ─────────────────────────────────────────────────────────
2151
- xero_invoices: async (_c, a) => xeroInvoices(a),
2152
- xero_contacts: async (_c, a) => xeroContacts(a),
2153
- xero_accounts: async (_c, a) => xeroAccounts(a),
2154
- xero_payments: async (_c, a) => xeroPayments(a),
2155
- xero_bank_transactions: async (_c, a) => xeroBankTransactions(a),
2156
- xero_reports: async (_c, a) => xeroReports(a),
2157
- xero_quotes: async (_c, a) => xeroQuotes(a),
2158
- xero_organisation: async (_c, a) => xeroOrganisation(a),
2159
- // ── Shopify handlers ──────────────────────────────────────────────────────
2160
- shopify_products: async (_c, a) => shopifyProducts(a),
2161
- shopify_orders: async (_c, a) => shopifyOrders(a),
2162
- shopify_customers: async (_c, a) => shopifyCustomers(a),
2163
- shopify_inventory: async (_c, a) => shopifyInventory(a),
2164
- shopify_collections: async (_c, a) => shopifyCollections(a),
2165
- shopify_shop: async (_c, a) => shopifyShop(a),
2166
- shopify_fulfillments: async (_c, a) => shopifyFulfillments(a),
2167
442
  };
2168
443
  // ─── Server factory ─────────────────────────────────────────────────────────
2169
444
  export function createServer() {
@@ -2178,6 +453,7 @@ export function createServer() {
2178
453
  const tools = [
2179
454
  ...META_TOOLS,
2180
455
  ...DIRECT_TOOLS,
456
+ ...ADDITIONAL_TOOLS,
2181
457
  ];
2182
458
  return { tools };
2183
459
  });
@@ -2221,7 +497,7 @@ export function createServer() {
2221
497
  for (const [cat, tools] of Object.entries(byCategory)) {
2222
498
  lines.push(`## ${cat.toUpperCase()}`);
2223
499
  for (const tool of tools) {
2224
- lines.push(`- **${tool.name}** (\`${tool.slug}\`) - ${tool.description}`);
500
+ lines.push(`- **${tool.name}** (\`${tool.slug}\`) ${tool.description}`);
2225
501
  }
2226
502
  lines.push("");
2227
503
  }
@@ -2258,7 +534,7 @@ export function createServer() {
2258
534
  "## Endpoints",
2259
535
  ];
2260
536
  for (const ep of tool.endpoints) {
2261
- lines.push(`### \`${ep.id}\` - ${ep.name}`);
537
+ lines.push(`### \`${ep.id}\` ${ep.name}`);
2262
538
  lines.push(ep.description);
2263
539
  lines.push(`**Method:** ${ep.method} | **Path:** ${ep.path}`);
2264
540
  lines.push(`**Input Schema:**`);
@@ -2312,6 +588,19 @@ export function createServer() {
2312
588
  ],
2313
589
  };
2314
590
  }
591
+ // ── Additional tools (third-party integrations) ───────────────
592
+ const additionalHandler = ADDITIONAL_HANDLERS[name];
593
+ if (additionalHandler) {
594
+ const result = await additionalHandler(args);
595
+ return {
596
+ content: [
597
+ {
598
+ type: "text",
599
+ text: JSON.stringify(result, null, 2),
600
+ },
601
+ ],
602
+ };
603
+ }
2315
604
  return {
2316
605
  content: [{ type: "text", text: `Unknown tool: ${name}` }],
2317
606
  isError: true,
@@ -2331,7 +620,7 @@ export async function startServer() {
2331
620
  const server = createServer();
2332
621
  const transport = new StdioServerTransport();
2333
622
  await server.connect(transport);
2334
- // Server is running - errors go to stderr so they don't corrupt the MCP stream
623
+ // Server is running errors go to stderr so they don't corrupt the MCP stream
2335
624
  process.stderr.write("UnClick MCP server running on stdio\n");
2336
625
  }
2337
626
  //# sourceMappingURL=server.js.map