@scavio/mcp-server 0.12.0 → 0.13.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 (101) hide show
  1. package/README.md +365 -4
  2. package/dist/index.js +26 -7
  3. package/dist/index.js.map +1 -1
  4. package/dist/lib/env.d.ts +1 -0
  5. package/dist/lib/env.js +4 -0
  6. package/dist/lib/env.js.map +1 -1
  7. package/dist/lib/tool-error.d.ts +22 -0
  8. package/dist/lib/tool-error.js +28 -0
  9. package/dist/lib/tool-error.js.map +1 -0
  10. package/dist/tools/airbnb.d.ts +3 -0
  11. package/dist/tools/airbnb.js +121 -0
  12. package/dist/tools/airbnb.js.map +1 -0
  13. package/dist/tools/amazon.js +1 -12
  14. package/dist/tools/amazon.js.map +1 -1
  15. package/dist/tools/appstore.d.ts +3 -0
  16. package/dist/tools/appstore.js +59 -0
  17. package/dist/tools/appstore.js.map +1 -0
  18. package/dist/tools/booking.d.ts +3 -0
  19. package/dist/tools/booking.js +116 -0
  20. package/dist/tools/booking.js.map +1 -0
  21. package/dist/tools/capterra.d.ts +3 -0
  22. package/dist/tools/capterra.js +53 -0
  23. package/dist/tools/capterra.js.map +1 -0
  24. package/dist/tools/companieshouse.d.ts +3 -0
  25. package/dist/tools/companieshouse.js +56 -0
  26. package/dist/tools/companieshouse.js.map +1 -0
  27. package/dist/tools/ebay.d.ts +3 -0
  28. package/dist/tools/ebay.js +79 -0
  29. package/dist/tools/ebay.js.map +1 -0
  30. package/dist/tools/extract.d.ts +3 -0
  31. package/dist/tools/extract.js +21 -0
  32. package/dist/tools/extract.js.map +1 -0
  33. package/dist/tools/g2.d.ts +3 -0
  34. package/dist/tools/g2.js +69 -0
  35. package/dist/tools/g2.js.map +1 -0
  36. package/dist/tools/glassdoor.d.ts +3 -0
  37. package/dist/tools/glassdoor.js +72 -0
  38. package/dist/tools/glassdoor.js.map +1 -0
  39. package/dist/tools/google.js +1 -12
  40. package/dist/tools/google.js.map +1 -1
  41. package/dist/tools/googleads.d.ts +3 -0
  42. package/dist/tools/googleads.js +61 -0
  43. package/dist/tools/googleads.js.map +1 -0
  44. package/dist/tools/googleplay.d.ts +3 -0
  45. package/dist/tools/googleplay.js +57 -0
  46. package/dist/tools/googleplay.js.map +1 -0
  47. package/dist/tools/homedepot.d.ts +3 -0
  48. package/dist/tools/homedepot.js +71 -0
  49. package/dist/tools/homedepot.js.map +1 -0
  50. package/dist/tools/indeed.d.ts +3 -0
  51. package/dist/tools/indeed.js +98 -0
  52. package/dist/tools/indeed.js.map +1 -0
  53. package/dist/tools/index.d.ts +42 -1
  54. package/dist/tools/index.js +204 -15
  55. package/dist/tools/index.js.map +1 -1
  56. package/dist/tools/instagram.js +1 -12
  57. package/dist/tools/instagram.js.map +1 -1
  58. package/dist/tools/kuaishou.d.ts +3 -0
  59. package/dist/tools/kuaishou.js +207 -0
  60. package/dist/tools/kuaishou.js.map +1 -0
  61. package/dist/tools/linkedin.js +1 -12
  62. package/dist/tools/linkedin.js.map +1 -1
  63. package/dist/tools/metaads.d.ts +3 -0
  64. package/dist/tools/metaads.js +63 -0
  65. package/dist/tools/metaads.js.map +1 -0
  66. package/dist/tools/reddit.js +1 -12
  67. package/dist/tools/reddit.js.map +1 -1
  68. package/dist/tools/redfin.d.ts +3 -0
  69. package/dist/tools/redfin.js +100 -0
  70. package/dist/tools/redfin.js.map +1 -0
  71. package/dist/tools/sec.d.ts +3 -0
  72. package/dist/tools/sec.js +104 -0
  73. package/dist/tools/sec.js.map +1 -0
  74. package/dist/tools/target.d.ts +3 -0
  75. package/dist/tools/target.js +105 -0
  76. package/dist/tools/target.js.map +1 -0
  77. package/dist/tools/threads.d.ts +3 -0
  78. package/dist/tools/threads.js +93 -0
  79. package/dist/tools/threads.js.map +1 -0
  80. package/dist/tools/tiktok-shop.js +3 -11
  81. package/dist/tools/tiktok-shop.js.map +1 -1
  82. package/dist/tools/tiktok.js +1 -12
  83. package/dist/tools/tiktok.js.map +1 -1
  84. package/dist/tools/tripadvisor.d.ts +3 -0
  85. package/dist/tools/tripadvisor.js +103 -0
  86. package/dist/tools/tripadvisor.js.map +1 -0
  87. package/dist/tools/usage.js +2 -10
  88. package/dist/tools/usage.js.map +1 -1
  89. package/dist/tools/walmart.js +108 -41
  90. package/dist/tools/walmart.js.map +1 -1
  91. package/dist/tools/x.js +1 -12
  92. package/dist/tools/x.js.map +1 -1
  93. package/dist/tools/yelp.d.ts +3 -0
  94. package/dist/tools/yelp.js +65 -0
  95. package/dist/tools/yelp.js.map +1 -0
  96. package/dist/tools/youtube.js +1 -12
  97. package/dist/tools/youtube.js.map +1 -1
  98. package/dist/tools/zillow.d.ts +3 -0
  99. package/dist/tools/zillow.js +123 -0
  100. package/dist/tools/zillow.js.map +1 -0
  101. package/package.json +12 -2
@@ -0,0 +1,207 @@
1
+ import { z } from "zod";
2
+ import { handleApiError } from "../lib/tool-error.js";
3
+ // Kuaishou is priced PER ENDPOINT off four upstream price points, so every tool
4
+ // carries its own cost line. A single platform-wide "costs N credits" claim is
5
+ // wrong by up to 40x, which is why this sentence is appended everywhere rather
6
+ // than stated once.
7
+ const PRICING = "Kuaishou is priced PER ENDPOINT (1, 2, 10 or 40 credits), never per platform.";
8
+ // This is CHINA Kuaishou (kuaishou.com). TikHub does not serve Kwai
9
+ // international (kwai.com): a real kwai.com id returns an empty envelope and
10
+ // still bills, so the distinction goes in the description, not a comment.
11
+ const NOT_KWAI = "Kuaishou China (kuaishou.com) only; Kwai international (kwai.com) is not served upstream.";
12
+ const CURSOR_DESC = "Opaque pagination cursor: the data.pcursor value from the previous response (the field is pcursor, NOT next_cursor). Omit for the first page; a pcursor of 'no_more' means there are no further pages.";
13
+ const SEARCH_CURSOR_DESC = "Opaque pagination cursor: the data.pcursor value from the previous response (the field is pcursor, NOT next_cursor, and NOT data.recoPcursor, which belongs to a separate recommendation stream and will not page the search). Omit for the first page; 'no_more' means the end.";
14
+ const KEYWORD_DESC = "Search keyword, 1-200 characters. Kuaishou is a Chinese-language platform: Chinese keywords reach the real catalogue, Latin-script queries return whatever Kuaishou matches, which is usually much thinner.";
15
+ export function registerKuaishouTools(server, getClient) {
16
+ server.tool("get_kuaishou_profile", `Get the full profile of a Kuaishou (China) creator by user id as JSON: display name, bio, avatar, gender, IP-location province, and the follower / public-video / lifetime-like counters. Read followers from data.userProfile.ownerCount.fan, public videos from ownerCount.photo, and lifetime likes from ownerCount.total_photo_like - ownerCount.like is a DIFFERENT counter and is not the video like total. Both id forms work here, numeric and alphanumeric. Not paginated. Costs 10 credits, the dearest single-object call on the platform: resolve_kuaishou_user turns a share link into an id for 1 credit, and get_kuaishou_video already carries the author's follower count for 2, so only pay this when you need the profile itself. ${PRICING} ${NOT_KWAI}`, {
17
+ user_id: z.string().min(1)
18
+ .describe("Kuaishou user id, non-empty. Both forms work on this endpoint: numeric ('5518803932') and alphanumeric ('3xcuu5habgc8z29'). Get one from resolve_kuaishou_user or search_kuaishou_users and pass it through unchanged."),
19
+ }, async (params) => {
20
+ try {
21
+ const data = await getClient().post("/api/v1/kuaishou/profile", params);
22
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
23
+ }
24
+ catch (err) {
25
+ return handleApiError(err);
26
+ }
27
+ });
28
+ server.tool("get_kuaishou_user_posts", `List a Kuaishou (China) creator's top posts as JSON, under data.feeds[]: caption, play / like / comment / share / collect counts, duration in milliseconds, publish timestamp in epoch milliseconds, cover image and video URL. Cursor-paginated. feeds[].photo_id is a JSON number above 2^53 and therefore arrives ROUNDED - take the exact ids from feeds[].share_info ("userId=<eid>&photoId=<eid>"), which is the form get_kuaishou_video accepts. Costs 1 credit per page, so this is the cheap way to pull a creator's catalogue when get_kuaishou_profile costs 10. ${PRICING} ${NOT_KWAI}`, {
29
+ user_id: z.string().min(1)
30
+ .describe("Kuaishou user id, non-empty. Get one from resolve_kuaishou_user (alphanumeric form) or search_kuaishou_users (numeric form) and pass it through unchanged rather than converting between forms."),
31
+ cursor: z.string().optional()
32
+ .describe(CURSOR_DESC),
33
+ }, async (params) => {
34
+ try {
35
+ const data = await getClient().post("/api/v1/kuaishou/user/posts", params);
36
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
37
+ }
38
+ catch (err) {
39
+ return handleApiError(err);
40
+ }
41
+ });
42
+ server.tool("get_kuaishou_user_live", `Check whether one Kuaishou (China) creator is broadcasting right now, as JSON. Read data.dynamicIconV2.isLive for the on-air flag and data.dynamicIconV2.liveStream for the stream itself (stream id, title, cover, and the broadcaster's verified details). When the creator is offline the liveStream is simply absent: that is a normal "not broadcasting" answer, not an error, and it still bills. Not paginated - one account, one answer. Costs 1 credit, cheap enough to poll a watchlist; finding live streams by keyword instead is search_kuaishou_live at 10 credits. ${PRICING} ${NOT_KWAI}`, {
43
+ user_id: z.string().min(1)
44
+ .describe("Kuaishou user id, non-empty. Get one from resolve_kuaishou_user or search_kuaishou_users and pass it through unchanged."),
45
+ }, async (params) => {
46
+ try {
47
+ const data = await getClient().post("/api/v1/kuaishou/user/live", params);
48
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
49
+ }
50
+ catch (err) {
51
+ return handleApiError(err);
52
+ }
53
+ });
54
+ server.tool("resolve_kuaishou_user", `Turn a Kuaishou (China) share link into the user id that get_kuaishou_profile, get_kuaishou_user_posts and get_kuaishou_user_live all require. Returns a bare { user_id } in the ALPHANUMERIC form (e.g. "3xcuu5habgc8z29"); this is the only Kuaishou endpoint whose response carries no data.result field. Accepts kuaishou.com and v.kuaishou.com links only - Kwai international (kwai.com) is not served upstream, so kwai.com links do not resolve. Not paginated. Costs 1 credit, a tenth of get_kuaishou_profile, so resolve first rather than guessing ids. ${PRICING}`, {
55
+ share_link: z.string().url()
56
+ .describe("A kuaishou.com or v.kuaishou.com link, e.g. 'https://v.kuaishou.com/KcdKDwFp'. Must be a syntactically valid URL. kwai.com links are not supported."),
57
+ }, async (params) => {
58
+ try {
59
+ const data = await getClient().post("/api/v1/kuaishou/user/resolve", params);
60
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
61
+ }
62
+ catch (err) {
63
+ return handleApiError(err);
64
+ }
65
+ });
66
+ server.tool("get_kuaishou_video", `Get one Kuaishou (China) video by photo id or URL as JSON: caption, play / like / comment / share counts, duration in milliseconds, source resolution, publish timestamp, cover image and the MP4 URL. data.counts carries the AUTHOR's account totals (fanCount, followCount, collectionCount, photoCount), which saves a 10-credit get_kuaishou_profile call when the follower number is all you need. FIELD NAMES ARE camelCase HERE (photoId, viewCount, likeCount, commentCount, userId) while every feed endpoint on this platform is snake_case, so do not share one parser between them. data.photo.photoId is a STRING and exact, and both author id forms come back (photo.userId numeric, photo.userEid alphanumeric), which makes this the reliable place to get them. coverUrls[] and mainMvUrls[] are CDN mirrors of the same asset, signed and expiring - take the first and fall back to the next. Pass photo_id or url; sending neither is a 400 and is not billed. Not paginated. Costs 2 credits. ${PRICING} ${NOT_KWAI}`, {
67
+ photo_id: z.string().min(1).optional()
68
+ .describe("Kuaishou photo (video) id. Both the alphanumeric form ('3xtdqvdnqd3psuc') and the numeric form ('5211790816292981090') work. Either this or url is required. When piping from a feed endpoint, take the id from that feed's share_info rather than its rounded photo_id number."),
69
+ url: z.string().url().optional()
70
+ .describe("A kuaishou.com or v.kuaishou.com video URL, e.g. 'https://v.kuaishou.com/GKTpYm', as an alternative to photo_id. Either this or photo_id is required."),
71
+ }, async (params) => {
72
+ try {
73
+ const data = await getClient().post("/api/v1/kuaishou/video", params);
74
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
75
+ }
76
+ catch (err) {
77
+ return handleApiError(err);
78
+ }
79
+ });
80
+ server.tool("get_kuaishou_video_comments", `Get the comment thread under a Kuaishou (China) video as JSON, 30 root comments per page: comment text, author name and id, authorArea (the commenter's IP-location province, the only geography Kuaishou publishes per comment), like count, subCommentCount and timestamp. data.subCommentsMap is a free bonus rather than a duplicate - it is keyed by root comment_id and pre-loads the first replies for the comments Kuaishou considers hot, so read it BEFORE spending a credit on get_kuaishou_comment_replies. data.commentCount is the video's TOTAL including replies and is far larger than the rows you can page through, so never use it as a loop bound; rootComments[].subCommentCount of 0 means there is nothing for get_kuaishou_comment_replies to fetch. Cursor-paginated. Costs 1 credit per page, so a full thread is cheap to mine. ${PRICING} ${NOT_KWAI}`, {
81
+ photo_id: z.string().min(1)
82
+ .describe("Kuaishou photo (video) id. Id only - this endpoint has no URL form. Use the exact id from get_kuaishou_video (photo.photoId) or a feed's share_info, not a rounded photo_id number."),
83
+ cursor: z.string().optional()
84
+ .describe(CURSOR_DESC),
85
+ }, async (params) => {
86
+ try {
87
+ const data = await getClient().post("/api/v1/kuaishou/video/comments", params);
88
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
89
+ }
90
+ catch (err) {
91
+ return handleApiError(err);
92
+ }
93
+ });
94
+ server.tool("get_kuaishou_comment_replies", `Expand one comment thread on a Kuaishou (China) video: every reply under a root comment, as JSON, with reply text, author, authorArea (IP-location province), the user being answered (reply_to plus replyToUserName, so a thread can be rebuilt in order) and like count. THE EMPTY-RESULT TRAP: an unknown, mistyped, or wrong-video root_comment_id is NOT an error - Kuaishou answers HTTP 200 with subComments: [] and pcursor "no_more", and the call is still billed. Take photo_id and root_comment_id from the SAME get_kuaishou_video_comments response and only call this for comments whose subCommentCount is above 0. Check that response's data.subCommentsMap first: for the hottest comments the replies are already in hand for free. Cursor-paginated, and count sizes the page (1-50). Costs 1 credit per page. ${PRICING} ${NOT_KWAI}`, {
95
+ photo_id: z.string().min(1)
96
+ .describe("Kuaishou photo (video) id the root comment sits on, non-empty. Use your own exact request value, not the rounded photo_id echoed inside comment objects."),
97
+ root_comment_id: z.string().min(1)
98
+ .describe("Id of the top-level comment whose replies you want: rootComments[].comment_id from get_kuaishou_video_comments, taken from the same response as photo_id. An id belonging to a different video returns an empty page and still bills."),
99
+ cursor: z.string().optional()
100
+ .describe(CURSOR_DESC),
101
+ count: z.number().int().min(1).max(50).optional()
102
+ .describe("Replies per page, 1-50. Omit to use Kuaishou's default. A value outside 1-50 is a 400 and is not billed."),
103
+ }, async (params) => {
104
+ try {
105
+ const data = await getClient().post("/api/v1/kuaishou/video/sub-comments", params);
106
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
107
+ }
108
+ catch (err) {
109
+ return handleApiError(err);
110
+ }
111
+ });
112
+ server.tool("get_kuaishou_videos_batch", `Look up as many as 20 Kuaishou (China) videos in ONE request as JSON, under data.photos[]: caption, play / like / comment / share / collect counts, duration, publish time, cover and MP4 URL for each. COSTS 40 CREDITS FLAT, whatever the list length - by far the dearest call on the platform. get_kuaishou_video costs 2, so a batch only pays off from roughly 20 ids down; below that, loop the cheap call. The list is hard-capped at 20 and a longer one is rejected by validation before you are billed. MISSING IDS ARE SILENT: Kuaishou returns only the photos it resolved, so data.photos can be shorter than the ids you sent (deleted, private and region-blocked videos simply do not appear) and the 40 credits are still spent - diff the two lists yourself. Order is not guaranteed to match the request: match on photos[].originalPhotoId, which is a STRING and exact, because photos[].photo_id is a JSON number above 2^53 and arrives rounded. Field names are snake_case here, unlike the camelCase get_kuaishou_video. Not paginated. ${PRICING} Kuaishou China (kuaishou.com) only; a Kwai international (kwai.com) id returns an empty envelope and still costs 40.`, {
113
+ photo_ids: z.array(z.string().min(1)).min(1).max(20)
114
+ .describe("1 to 20 non-empty Kuaishou photo (video) ids; use the numeric id form. More than 20 is rejected before billing - chunk longer lists yourself, at 40 credits per chunk."),
115
+ }, async (params) => {
116
+ try {
117
+ const data = await getClient().post("/api/v1/kuaishou/videos/batch", params);
118
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
119
+ }
120
+ catch (err) {
121
+ return handleApiError(err);
122
+ }
123
+ });
124
+ server.tool("search_kuaishou", `Run Kuaishou (China)'s own MIXED search for a keyword as JSON: ranked videos with full engagement counts, plus the related-search suggestions the app surfaces alongside them. Rows arrive under data.mixFeeds[] and are HETEROGENEOUS - switch on itemType before reading anything: 5 is a video at item.feed, 9 is related searches at item.relatedSearches[], 4 is a user at item.user, 6 is a live stream at item.live, and 25 is a commerce promo card at item.mixKbox[] which is an ad slot, not an organic result. Never index mixFeeds positionally, and treat an unknown itemType as skippable rather than as an error. THIS IS THE SLOWEST CALL ON THE PLATFORM, roughly 20 seconds against 1.5-3 seconds for the dedicated searches, so set a client timeout above 30 seconds - or prefer search_kuaishou_videos, search_kuaishou_users or search_kuaishou_live, which cost the same 10 credits, answer far faster and come back already filtered. data.isRecommendResult true means Kuaishou filled the page with recommendations rather than keyword matches; do not read those rows as matches. Cursor-paginated. Costs 10 credits PER PAGE - all four search endpoints are the 10, so cap your page count. ${PRICING} ${NOT_KWAI}`, {
125
+ keyword: z.string().min(1).max(200)
126
+ .describe(KEYWORD_DESC),
127
+ cursor: z.string().optional()
128
+ .describe(SEARCH_CURSOR_DESC),
129
+ }, async (params) => {
130
+ try {
131
+ const data = await getClient().post("/api/v1/kuaishou/search", params);
132
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
133
+ }
134
+ catch (err) {
135
+ return handleApiError(err);
136
+ }
137
+ });
138
+ server.tool("search_kuaishou_videos", `Search Kuaishou (China) videos by keyword as JSON, 20 ranked results a page: caption, author, play / like / comment / share / collect counts, duration, publish time and cover image, with no user rows mixed in. Rows arrive under data.mixFeeds[] with itemType 5 and the payload at item.feed - Kuaishou can still inject a card row, so skip anything that is not itemType 5 rather than assuming index positions. feed.photo_id is a JSON number above 2^53 and arrives ROUNDED; use feed.share_info ("userId=<eid>&photoId=<eid>") for the exact ids, which is the form get_kuaishou_video accepts. Field names are snake_case here, unlike the camelCase get_kuaishou_video. Prefer this over search_kuaishou when you only want videos: same 10 credits, roughly eight times faster. Cursor-paginated. Costs 10 credits PER PAGE - all four search endpoints are the 10, so cap your page count. ${PRICING} ${NOT_KWAI}`, {
139
+ keyword: z.string().min(1).max(200)
140
+ .describe(KEYWORD_DESC),
141
+ cursor: z.string().optional()
142
+ .describe(SEARCH_CURSOR_DESC),
143
+ }, async (params) => {
144
+ try {
145
+ const data = await getClient().post("/api/v1/kuaishou/search/videos", params);
146
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
147
+ }
148
+ catch (err) {
149
+ return handleApiError(err);
150
+ }
151
+ });
152
+ server.tool("search_kuaishou_users", `Find Kuaishou (China) creators by name, handle or topic as JSON, 20 accounts a page: display name, public handle (kwaiId), bio, fansCount, photoCount, verified and isBanned flags, and the numeric user_id. This is the creator-discovery entry point - the ids it returns are what get_kuaishou_profile, get_kuaishou_user_posts and get_kuaishou_user_live all take. Rows arrive under data.mixFeeds[] with itemType 4 and the payload at item.user; skip anything else rather than indexing positionally. user_id arrives as a JSON number, so stringify it and pass it through unchanged, do not reformat it. Field traps: fansCount is an integer but photoCount is a STRING ("20"), photoInfo is a pre-rendered Chinese summary line and not a parseable metric, the row carries NO total like count (that is ownerCount.total_photo_like on get_kuaishou_profile, 10 credits), and isBanned accounts still appear in results. There is NO follower-count or verified filter upstream - filter client-side on fansCount and verified. Cursor-paginated. Costs 10 credits per page; if you already have a share link, resolve_kuaishou_user gets you the id for 1. ${PRICING} ${NOT_KWAI}`, {
153
+ keyword: z.string().min(1).max(200)
154
+ .describe(KEYWORD_DESC),
155
+ cursor: z.string().optional()
156
+ .describe(SEARCH_CURSOR_DESC),
157
+ }, async (params) => {
158
+ try {
159
+ const data = await getClient().post("/api/v1/kuaishou/search/users", params);
160
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
161
+ }
162
+ catch (err) {
163
+ return handleApiError(err);
164
+ }
165
+ });
166
+ server.tool("search_kuaishou_live", `Search Kuaishou (China) live streams that are ON AIR RIGHT NOW for a keyword, as JSON: stream id, broadcaster, like count, cover, the commerce badge Kuaishou shows on the card, and the FLV playback URLs. This is how to find live-commerce broadcasts while they are still selling. Rows arrive under data.mixFeeds[]: itemType 6 is a stream at item.live, and itemType 25 is a commerce promo card at item.mixKbox[] - an ad slot carrying no stream, which was the FIRST row of the capture - so filter on itemType 6 and never index positionally. LIVE DATA IS A SNAPSHOT: streams end without notice, a liveStreamId is only good while the broadcast lasts, and live.playInfo.playUrls[] are signed FLV pull URLs that expire and stop working the moment the broadcast ends, so re-run the search instead of caching it. live.likeCount and live.audienceCount are ABBREVIATED STRINGS as the app renders them ("629.1k"), not integers - parse them or you will silently compare strings; live.acu is a number. live.simpleLiveCoverReasonTag.text.content is the card badge and carries the sales line on live-commerce streams. live.user is a reduced user object with no counters; call get_kuaishou_profile for those. Cursor-paginated. Costs 10 credits per page; checking ONE known creator is get_kuaishou_user_live at 1 credit. ${PRICING} ${NOT_KWAI}`, {
167
+ keyword: z.string().min(1).max(200)
168
+ .describe(KEYWORD_DESC),
169
+ cursor: z.string().optional()
170
+ .describe(SEARCH_CURSOR_DESC),
171
+ }, async (params) => {
172
+ try {
173
+ const data = await getClient().post("/api/v1/kuaishou/search/live", params);
174
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
175
+ }
176
+ catch (err) {
177
+ return handleApiError(err);
178
+ }
179
+ });
180
+ server.tool("get_kuaishou_tag_feed", `Read the feed behind a Kuaishou (China) hashtag as JSON, 20 posts a page: caption, author, play / like / comment / share / collect counts and cover image under data.mixFeeds[] (videos are itemType 5 with the payload at item.feed - skip other card types), plus the tag's own lifetime view total at data.tagInfo.viewCount. Send the tag TEXT without the leading '#'; Kuaishou resolves it to its own tag id and echoes both back as tagInfo.name and tagInfo.tagId, so CHECK tagInfo.name against what you asked for before trusting a run - a near-miss resolves to a different tag rather than erroring. THERE IS NO TAB OR SORT PARAMETER: you always get Kuaishou's default ordering for the tag, so do not read the feed as chronological. feed.photo_id is a JSON number above 2^53 and arrives rounded - use feed.share_info for the exact ids. Cursor-paginated. Costs 1 credit per page, a tenth of what the search endpoints cost, so this is the cheap way to mine a trend or track a campaign tag over time. ${PRICING} ${NOT_KWAI}`, {
181
+ tag: z.string().min(1).max(200)
182
+ .describe("Hashtag text, 1-200 characters, WITHOUT the leading # - send '挑战', not '#挑战'. Kuaishou is a Chinese-language platform, so Chinese tags are where the volume is."),
183
+ cursor: z.string().optional()
184
+ .describe(CURSOR_DESC),
185
+ }, async (params) => {
186
+ try {
187
+ const data = await getClient().post("/api/v1/kuaishou/tag/feed", params);
188
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
189
+ }
190
+ catch (err) {
191
+ return handleApiError(err);
192
+ }
193
+ });
194
+ server.tool("get_kuaishou_trending", `Read one Kuaishou (China) leaderboard as JSON - one board per call, and each call bills. board 'hot' (the default when omitted) returns the hot-search keyword list: 50 ranked entries under data.hots already sorted by hotValue descending, plus the pinned data.topHots, each entry carrying id, keyword, hotValue, hotWordType, ksOrderId, pvSoarSignal and viewCount. The live, shopping, brand and music boards are SEPARATE upstream rankings with their OWN response shapes - do not assume they carry hots[]; read the one you need once and map it yourself. Fields that look useful and are not: hotValue is Kuaishou's heat score, not views or searches, and is only comparable within one snapshot of one board; viewCount and pvSoarSignal were 0 on every row of the capture, so treat them as unpopulated rather than as zero traffic; a non-empty ksOrderId marks a promoted slot, so check it before treating an entry as organic. Not paginated, with no limit or region parameter and no historical view - poll on a schedule and store the results if you want a time series. The keywords are the natural input to get_kuaishou_tag_feed (1 credit) or search_kuaishou_videos (10). Costs 1 credit whichever board you ask for, the cheapest trend signal on the platform. ${PRICING} ${NOT_KWAI}`, {
195
+ board: z.enum(["hot", "live", "shopping", "brand", "music"]).optional()
196
+ .describe("Which leaderboard to read: 'hot' (used when omitted) is the hot-search keyword list; 'live', 'shopping', 'brand' and 'music' are the live-stream, e-commerce, brand and music rankings. One board per call, and each board is a different upstream ranking with its own response shape."),
197
+ }, async (params) => {
198
+ try {
199
+ const data = await getClient().post("/api/v1/kuaishou/trending", params);
200
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
201
+ }
202
+ catch (err) {
203
+ return handleApiError(err);
204
+ }
205
+ });
206
+ }
207
+ //# sourceMappingURL=kuaishou.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kuaishou.js","sourceRoot":"","sources":["../../src/tools/kuaishou.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,gFAAgF;AAChF,+EAA+E;AAC/E,+EAA+E;AAC/E,oBAAoB;AACpB,MAAM,OAAO,GAAG,+EAA+E,CAAC;AAEhG,oEAAoE;AACpE,6EAA6E;AAC7E,0EAA0E;AAC1E,MAAM,QAAQ,GAAG,2FAA2F,CAAC;AAE7G,MAAM,WAAW,GACf,wMAAwM,CAAC;AAE3M,MAAM,kBAAkB,GACtB,kRAAkR,CAAC;AAErR,MAAM,YAAY,GAChB,6MAA6M,CAAC;AAEhN,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,SAA6B;IACpF,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,wtBAAwtB,OAAO,IAAI,QAAQ,EAAE,EAC7uB;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aACvB,QAAQ,CAAC,wNAAwN,CAAC;KACtO,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC;YACxE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,yBAAyB,EACzB,+iBAA+iB,OAAO,IAAI,QAAQ,EAAE,EACpkB;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aACvB,QAAQ,CAAC,iMAAiM,CAAC;QAC9M,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,WAAW,CAAC;KACzB,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YAC3E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,qjBAAqjB,OAAO,IAAI,QAAQ,EAAE,EAC1kB;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aACvB,QAAQ,CAAC,yHAAyH,CAAC;KACvI,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC;YAC1E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,wiBAAwiB,OAAO,EAAE,EACjjB;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;aACzB,QAAQ,CAAC,qJAAqJ,CAAC;KACnK,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;YAC7E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,w9BAAw9B,OAAO,IAAI,QAAQ,EAAE,EAC7+B;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACnC,QAAQ,CAAC,iRAAiR,CAAC;QAC9R,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;aAC7B,QAAQ,CAAC,uJAAuJ,CAAC;KACrK,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,6BAA6B,EAC7B,+zBAA+zB,OAAO,IAAI,QAAQ,EAAE,EACp1B;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aACxB,QAAQ,CAAC,qLAAqL,CAAC;QAClM,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,WAAW,CAAC;KACzB,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,iCAAiC,EAAE,MAAM,CAAC,CAAC;YAC/E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,8BAA8B,EAC9B,uyBAAuyB,OAAO,IAAI,QAAQ,EAAE,EAC5zB;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aACxB,QAAQ,CAAC,0JAA0J,CAAC;QACvK,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aAC/B,QAAQ,CAAC,uOAAuO,CAAC;QACpP,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,WAAW,CAAC;QACxB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;aAC9C,QAAQ,CAAC,0GAA0G,CAAC;KACxH,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,qCAAqC,EAAE,MAAM,CAAC,CAAC;YACnF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,sgCAAsgC,OAAO,uHAAuH,EACpoC;QACE,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;aACjD,QAAQ,CAAC,wKAAwK,CAAC;KACtL,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;YAC7E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,6pCAA6pC,OAAO,IAAI,QAAQ,EAAE,EAClrC;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAChC,QAAQ,CAAC,YAAY,CAAC;QACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,kBAAkB,CAAC;KAChC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;YACvE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,42BAA42B,OAAO,IAAI,QAAQ,EAAE,EACj4B;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAChC,QAAQ,CAAC,YAAY,CAAC;QACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,kBAAkB,CAAC;KAChC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,gCAAgC,EAAE,MAAM,CAAC,CAAC;YAC9E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,4mCAA4mC,OAAO,IAAI,QAAQ,EAAE,EACjoC;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAChC,QAAQ,CAAC,YAAY,CAAC;QACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,kBAAkB,CAAC;KAChC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;YAC7E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,0xCAA0xC,OAAO,IAAI,QAAQ,EAAE,EAC/yC;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAChC,QAAQ,CAAC,YAAY,CAAC;QACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,kBAAkB,CAAC;KAChC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,8BAA8B,EAAE,MAAM,CAAC,CAAC;YAC5E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,m+BAAm+B,OAAO,IAAI,QAAQ,EAAE,EACx/B;QACE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aAC5B,QAAQ,CAAC,iKAAiK,CAAC;QAC9K,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;aAC1B,QAAQ,CAAC,WAAW,CAAC;KACzB,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;YACzE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,quCAAquC,OAAO,IAAI,QAAQ,EAAE,EAC1vC;QACE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;aACpE,QAAQ,CAAC,yRAAyR,CAAC;KACvS,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;YACzE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1,6 +1,5 @@
1
1
  import { z } from "zod";
2
- import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
3
- import { ApiError } from "../lib/errors.js";
2
+ import { handleApiError } from "../lib/tool-error.js";
4
3
  // The provider retired the `linkedin/web/*` namespace these tools were built on.
5
4
  // The nine below run on `web_v2`: every reference is a vanity handle, slug or id
6
5
  // (a full LinkedIn URL also works anywhere).
@@ -15,16 +14,6 @@ import { ApiError } from "../lib/errors.js";
15
14
  // and can only return 410. Unlike an SDK method, an MCP tool is a menu item for
16
15
  // a model: one that always fails burns turns and invites retries, so it is
17
16
  // better absent. The REST API still answers those paths with an explicit 410.
18
- function handleApiError(err) {
19
- if (err instanceof ApiError) {
20
- if (err.status === 429)
21
- return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
22
- if (err.status === 401)
23
- throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
24
- return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
25
- }
26
- throw new McpError(ErrorCode.InternalError, String(err));
27
- }
28
17
  const personRef = {
29
18
  username: z.string().min(1).optional()
30
19
  .describe("Public identifier (vanity handle), e.g. 'williamhgates'."),
@@ -1 +1 @@
1
- {"version":3,"file":"linkedin.js","sourceRoot":"","sources":["../../src/tools/linkedin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"linkedin.js","sourceRoot":"","sources":["../../src/tools/linkedin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ScavioClient } from "../lib/client.js";
3
+ export declare function registerMetaAdsTools(server: McpServer, getClient: () => ScavioClient): void;
@@ -0,0 +1,63 @@
1
+ import { z } from "zod";
2
+ import { handleApiError } from "../lib/tool-error.js";
3
+ export function registerMetaAdsTools(server, getClient) {
4
+ server.tool("search_meta_ads", `Meta Ad Library - every ad running on Facebook and Instagram, public and logged-out. Search it by keyword and get 30 ads on page one as JSON, each with the full creative: advertising page name, ad copy, headline, call to action, image and video URLs, which platforms it ran on, and its run dates. Also returns total_results, total_is_capped, has_next_page and next_cursor. FULL CURSOR PAGINATION, which is the differentiator here: page one is 30 ads, every page after it is 10, and walking has_next_page with next_cursor lets you scrape an entire query rather than a sample. THE CURSOR IS SELF-CONTAINED, SO ALL OTHER FILTERS ARE IGNORED WHEN YOU SEND ONE - it already carries the query, country and filters from page one; changing them mid-walk does nothing. total_results CAPS AT 50000 with total_is_capped set true, because Meta only reports ">50,000" - never present it as an exact count. spend, reach, impressions and the paid-for-by disclosure are NULL ON COMMERCIAL ADS: only political and issue ads carry them, so set ad_type='political_and_issue_ads' if you need spend data. Costs 1 CREDIT PER PAGE, so a full crawl costs roughly 1 credit per 10 ads past the first 30 - budget the walk before starting it.`, {
5
+ query: z.string().min(1).max(200)
6
+ .describe("Keyword or brand to search the ad library for, e.g. 'protein powder' or 'Ridge Wallet'. Ignored if cursor is set."),
7
+ country: z.string().length(2).optional()
8
+ .describe("Two-letter country code the ads ran in, e.g. 'US', 'GB', 'DE' (default 'US')."),
9
+ active_status: z.enum(["all", "active", "inactive"]).optional()
10
+ .describe("Whether the ad is still running (default 'all')."),
11
+ ad_type: z.enum(["all", "political_and_issue_ads"]).optional()
12
+ .describe("Ad category (default 'all'). Set 'political_and_issue_ads' to expose spend, reach, impressions and the paid-for-by disclosure - those fields are null on commercial ads."),
13
+ media_type: z.enum(["all", "image", "video", "meme", "image_and_meme", "none"]).optional()
14
+ .describe("Creative media type. Default: no media filter."),
15
+ search_type: z.enum(["keyword_unordered", "keyword_exact_phrase"]).optional()
16
+ .describe("How the query is matched (default 'keyword_unordered'). 'keyword_exact_phrase' requires the words in order."),
17
+ cursor: z.string().min(1).optional()
18
+ .describe("next_cursor from the previous response. Page one is 30 ads, each page after it is 10. THE OTHER FILTERS ARE IGNORED when this is set - the cursor already carries them."),
19
+ }, async (params) => {
20
+ try {
21
+ const data = await getClient().post("/api/v1/meta-ads/search", params);
22
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
23
+ }
24
+ catch (err) {
25
+ return handleApiError(err);
26
+ }
27
+ });
28
+ server.tool("get_meta_ads_advertiser", `Meta Ad Library - every ad running on Facebook and Instagram, public and logged-out. Get every ad ONE advertiser is running, addressed by its numeric Facebook Page id. Returns 30 ads on page one as JSON with the same creative detail as search_meta_ads: page name, ad copy, headline, call to action, image and video URLs, platforms and run dates, plus has_next_page and next_cursor. CURSOR PAGINATION: page one is 30 ads, every page after it is 10 - walk has_next_page with next_cursor to pull an advertiser's whole active set. THE CURSOR IS SELF-CONTAINED, SO THE OTHER FILTERS ARE IGNORED WHEN YOU SEND ONE. Requires the NUMERIC page id, not a page name or vanity handle. spend, reach, impressions and the paid-for-by disclosure are NULL ON COMMERCIAL ADS - only political and issue ads carry them, so set ad_type='political_and_issue_ads' if you need spend data. Costs 1 CREDIT PER PAGE, roughly 1 credit per 10 ads past the first 30.`, {
29
+ page_id: z.string().regex(/^\d{3,25}$/)
30
+ .describe("The advertiser's NUMERIC Facebook Page id, digits only, e.g. '20531316728'. A page name or vanity handle will not work."),
31
+ country: z.string().length(2).optional()
32
+ .describe("Two-letter country code the ads ran in, e.g. 'US', 'GB', 'DE' (default 'US')."),
33
+ active_status: z.enum(["all", "active", "inactive"]).optional()
34
+ .describe("Whether the ad is still running (default 'all')."),
35
+ ad_type: z.enum(["all", "political_and_issue_ads"]).optional()
36
+ .describe("Ad category (default 'all'). Set 'political_and_issue_ads' to expose spend, reach, impressions and the paid-for-by disclosure - those fields are null on commercial ads."),
37
+ media_type: z.enum(["all", "image", "video", "meme", "image_and_meme", "none"]).optional()
38
+ .describe("Creative media type. Default: no media filter."),
39
+ cursor: z.string().min(1).optional()
40
+ .describe("next_cursor from the previous response. Page one is 30 ads, each page after it is 10. The other filters are ignored when this is set."),
41
+ }, async (params) => {
42
+ try {
43
+ const data = await getClient().post("/api/v1/meta-ads/advertiser", params);
44
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
45
+ }
46
+ catch (err) {
47
+ return handleApiError(err);
48
+ }
49
+ });
50
+ server.tool("get_meta_ad", `Meta Ad Library - every ad running on Facebook and Instagram, public and logged-out. Get ONE ad in full as JSON by its ad archive id: the creative, the advertiser, run dates, the platforms it ran on, and any political disclosure. Use it to expand a single ad you already found via search_meta_ads or get_meta_ads_advertiser. Requires the numeric ad_archive_id. No pagination - one ad, one call. spend, reach, impressions and the paid-for-by disclosure are NULL unless this is a political or issue ad; commercial ads never carry them. Costs 1 credit.`, {
51
+ ad_archive_id: z.string().regex(/^\d{3,25}$/)
52
+ .describe("The ad's numeric archive id, digits only, e.g. '1234567890123456'. Take it from a search_meta_ads or get_meta_ads_advertiser row."),
53
+ }, async (params) => {
54
+ try {
55
+ const data = await getClient().post("/api/v1/meta-ads/ad", params);
56
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
57
+ }
58
+ catch (err) {
59
+ return handleApiError(err);
60
+ }
61
+ });
62
+ }
63
+ //# sourceMappingURL=metaads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metaads.js","sourceRoot":"","sources":["../../src/tools/metaads.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,5 @@
1
1
  import { z } from "zod";
2
- import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
3
- import { ApiError } from "../lib/errors.js";
4
- function handleApiError(err) {
5
- if (err instanceof ApiError) {
6
- if (err.status === 429)
7
- return { isError: true, content: [{ type: "text", text: "Rate limited. Wait and retry." }] };
8
- if (err.status === 401)
9
- throw new McpError(ErrorCode.InternalError, "Invalid SCAVIO_API_KEY. Check your configuration.");
10
- return { isError: true, content: [{ type: "text", text: `Scavio API error (${err.status}): ${err.message}` }] };
11
- }
12
- throw new McpError(ErrorCode.InternalError, String(err));
13
- }
2
+ import { handleApiError } from "../lib/tool-error.js";
14
3
  export function registerRedditTools(server, getClient) {
15
4
  server.tool("search_reddit", `Search Reddit posts across all of Reddit as JSON. Returns data.results, each with post_id, title, text, url, subreddit, author, score, upvote_ratio, num_comments, created_at, is_nsfw, is_video, thumbnail, and media. Use data.next_cursor as the cursor parameter for the next page while data.has_more is true. Results cannot be sorted or filtered by type - the API returns relevance order only. Slower than other platforms (5-15 seconds). Costs 1 credit.`, {
16
5
  query: z.string().min(1).max(500)
@@ -1 +1 @@
1
- {"version":3,"file":"reddit.js","sourceRoot":"","sources":["../../src/tools/reddit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reddit.js","sourceRoot":"","sources":["../../src/tools/reddit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ScavioClient } from "../lib/client.js";
3
+ export declare function registerRedfinTools(server: McpServer, getClient: () => ScavioClient): void;
@@ -0,0 +1,100 @@
1
+ import { z } from "zod";
2
+ import { handleApiError } from "../lib/tool-error.js";
3
+ // Redfin - US residential real estate. Three tools, 1 credit each, flat:
4
+ // property and market read the listing/region PAGE, whose inlined request cache
5
+ // replaces the ~40 internal calls the page made, which is why a full fact sheet
6
+ // costs the same as a search page.
7
+ //
8
+ // Two things a model must be told or it will burn a billed call:
9
+ // 1. CITY NAMES ARE NOT ACCEPTED on `location`. Redfin's own name lookup is
10
+ // the single path its edge blocks our proxy pool from. A redfin.com region
11
+ // URL, a bare 5-digit ZIP, or region_id + region_type together.
12
+ // 2. days_on_market IS ALWAYS NULL on search - Redfin's mainHouseInfo has no
13
+ // `dom` key. It is described as null here rather than omitted, because a
14
+ // model that sees "days on market" in a field list will otherwise plan
15
+ // around a value that never arrives.
16
+ //
17
+ // No zod `.default()` anywhere in this file, deliberately: the MCP SDK applies
18
+ // a zod default BEFORE the handler runs, so a declared default is posted on
19
+ // every call. `sold_within_days` is the sharp edge - the backend REJECTS it
20
+ // unless listing_status=sold, so a default of 90 here would 400 every for-sale
21
+ // search. Defaults belong to the backend and are documented in .describe() text.
22
+ /** location OR (region_id AND region_type) - the region halves must travel together. */
23
+ const regionRef = {
24
+ location: z.string().min(1).max(500).optional()
25
+ .describe("Region to look up: a redfin.com region URL ('https://www.redfin.com/city/30818/TX/Austin', /neighborhood/, /county/, /zipcode/) or a bare 5-digit ZIP ('78701'). CITY NAMES ARE NOT ACCEPTED - 'Austin, TX' will fail. Required unless you pass region_id AND region_type."),
26
+ region_id: z.number().int().min(1).optional()
27
+ .describe("Redfin's internal region id, as returned in region.id by a previous response. NOT a ZIP code - the two are different number spaces, and a ZIP here resolves to another city rather than failing. Must be sent together with region_type."),
28
+ region_type: z.union([z.literal(1), z.literal(2), z.literal(5), z.literal(6)]).optional()
29
+ .describe("Redfin region type: 1 neighborhood, 2 ZIP, 5 county, 6 city. Must be sent together with region_id."),
30
+ };
31
+ export function registerRedfinTools(server, getClient) {
32
+ const call = (path) => async (params) => {
33
+ try {
34
+ const data = await getClient().post(path, params);
35
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
36
+ }
37
+ catch (err) {
38
+ return handleApiError(err);
39
+ }
40
+ };
41
+ server.tool("search_redfin", `Search Redfin, the US residential real-estate marketplace, and return listings as JSON: price, price per sqft, beds, baths, living area, lot size, year built, coordinates, listing remarks and full photo galleries. Covers for-sale, sold and for-rent inventory. IMPORTANT: days_on_market is ALWAYS NULL in the response - Redfin does not expose it on this feed, so filter with max_days_on_market / min_days_on_market instead of reading it back. CITY NAMES ARE NOT ACCEPTED: pass \`location\` as a redfin.com region URL (/city/, /neighborhood/, /county/, /zipcode/) or a bare 5-digit ZIP, or pass region_id AND region_type together. Paginated with page + limit, up to 350 listings per page (backend default 100). Every numeric filter is truncated into Redfin's query, so fractional bounds are rejected - 1.5 baths is not expressible. max_days_on_market and min_days_on_market cannot be combined, and sold_within_days is rejected unless listing_status=sold. Costs 1 credit.`, {
42
+ ...regionRef,
43
+ listing_status: z.enum(["for_sale", "sold", "for_rent"]).optional()
44
+ .describe("Market to search. Backend default is 'for_sale'."),
45
+ sold_within_days: z.number().int().min(1).optional()
46
+ .describe("Sold within the last N days. ONLY valid with listing_status='sold', where the backend defaults it to 90 - sending it on any other listing_status is a 400."),
47
+ page: z.number().int().min(1).optional()
48
+ .describe("Results page, 1-based."),
49
+ limit: z.number().int().min(1).max(350).optional()
50
+ .describe("Listings per page, 1-350. Backend default is 100."),
51
+ sort: z.enum([
52
+ "recommended",
53
+ "price_low",
54
+ "price_high",
55
+ "newest",
56
+ "oldest",
57
+ "sqft_low",
58
+ "sqft_high",
59
+ "price_per_sqft_low",
60
+ "price_per_sqft_high",
61
+ ]).optional()
62
+ .describe("Result sort order. Backend default is Redfin's own 'recommended' ranking."),
63
+ min_price: z.number().min(0).optional()
64
+ .describe("Minimum price, inclusive. This is monthly rent when listing_status='for_rent'."),
65
+ max_price: z.number().min(0).optional()
66
+ .describe("Maximum price, inclusive. This is monthly rent when listing_status='for_rent'."),
67
+ beds_min: z.number().int().min(0).optional()
68
+ .describe("Minimum bedrooms. Whole numbers only."),
69
+ beds_max: z.number().int().min(0).optional()
70
+ .describe("Maximum bedrooms. Whole numbers only."),
71
+ baths_min: z.number().int().min(0).optional()
72
+ .describe("Minimum bathrooms, WHOLE baths only - 1.5 is rejected, not rounded."),
73
+ sqft_min: z.number().int().min(0).optional()
74
+ .describe("Minimum living area in square feet."),
75
+ sqft_max: z.number().int().min(0).optional()
76
+ .describe("Maximum living area in square feet."),
77
+ lot_size_min: z.number().int().min(0).optional()
78
+ .describe("Minimum lot size in square feet."),
79
+ year_built_min: z.number().int().min(0).optional()
80
+ .describe("Earliest year built."),
81
+ year_built_max: z.number().int().min(0).optional()
82
+ .describe("Latest year built."),
83
+ max_hoa: z.number().min(0).optional()
84
+ .describe("Maximum monthly HOA fee in dollars."),
85
+ property_type: z.enum(["house", "condo", "townhouse", "multi_family", "land", "other", "co_op"]).optional()
86
+ .describe("Restrict to one property type."),
87
+ has_pool: z.boolean().optional()
88
+ .describe("Only listings with a pool."),
89
+ max_days_on_market: z.number().int().min(0).optional()
90
+ .describe("Listed at most N days ago. Cannot be combined with min_days_on_market - Redfin expresses both through one param, so sending both is a 400."),
91
+ min_days_on_market: z.number().int().min(0).optional()
92
+ .describe("Listed at least N days ago. Cannot be combined with max_days_on_market."),
93
+ }, call("/api/v1/redfin/search"));
94
+ server.tool("get_redfin_property", `Get one Redfin listing (US residential real estate) in full as JSON: price, the Redfin Estimate and rental estimate, the complete MLS fact sheet, price and tax history, listing agents, open houses, schools, climate risk, walkability and location scores, sun exposure, monthly weather, permits, zoning, comparable sales and photos. Takes a Redfin property id or any redfin.com listing URL carrying one - get either from search_redfin. Not paginated. Costs 1 credit, the same as a search page, because it reads the property page's inlined request cache in one fetch.`, {
95
+ property_id: z.string().min(1).max(500)
96
+ .describe("Redfin property id ('31295086'), or any redfin.com listing URL carrying one ('https://www.redfin.com/TX/Austin/7644-Parkview-Cir-78731/home/31295086'). Only the id in such a URL is used - Redfin resolves the address itself."),
97
+ }, call("/api/v1/redfin/property"));
98
+ server.tool("get_redfin_market", `Get Redfin housing-market statistics for a US region as JSON: median list and sale price, median price per sqft, sale-to-list ratio, average number of offers, average days on market, year-over-year movement, Redfin's 0-100 compete score, live inventory broken down by property type, median price and active listings per bedroom count, and Redfin agent presence with aggregate rating. Region-level aggregates only - use search_redfin for individual listings. Addressed exactly like search_redfin: a redfin.com region URL or a bare 5-digit ZIP in \`location\`, or region_id AND region_type together. CITY NAMES ARE NOT ACCEPTED. Not paginated. Costs 1 credit.`, { ...regionRef }, call("/api/v1/redfin/market"));
99
+ }
100
+ //# sourceMappingURL=redfin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redfin.js","sourceRoot":"","sources":["../../src/tools/redfin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,mCAAmC;AACnC,EAAE;AACF,iEAAiE;AACjE,8EAA8E;AAC9E,gFAAgF;AAChF,qEAAqE;AACrE,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,0CAA0C;AAC1C,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,4EAA4E;AAC5E,+EAA+E;AAC/E,iFAAiF;AAEjF,wFAAwF;AACxF,MAAM,SAAS,GAAG;IAChB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;SAC5C,QAAQ,CAAC,4QAA4Q,CAAC;IACzR,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;SAC1C,QAAQ,CAAC,0OAA0O,CAAC;IACvP,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;SACtF,QAAQ,CAAC,oGAAoG,CAAC;CAClH,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,SAA6B;IAClF,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,EAAE,MAA+B,EAAE,EAAE;QACvE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAClD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACvF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,08BAA08B,EAC18B;QACE,GAAG,SAAS;QACZ,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE;aAChE,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACjD,QAAQ,CAAC,4JAA4J,CAAC;QACzK,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACrC,QAAQ,CAAC,wBAAwB,CAAC;QACrC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;aAC/C,QAAQ,CAAC,mDAAmD,CAAC;QAChE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;YACX,aAAa;YACb,WAAW;YACX,YAAY;YACZ,QAAQ;YACR,QAAQ;YACR,UAAU;YACV,WAAW;YACX,oBAAoB;YACpB,qBAAqB;SACtB,CAAC,CAAC,QAAQ,EAAE;aACV,QAAQ,CAAC,2EAA2E,CAAC;QACxF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACpC,QAAQ,CAAC,gFAAgF,CAAC;QAC7F,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACpC,QAAQ,CAAC,gFAAgF,CAAC;QAC7F,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACzC,QAAQ,CAAC,uCAAuC,CAAC;QACpD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACzC,QAAQ,CAAC,uCAAuC,CAAC;QACpD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aAC1C,QAAQ,CAAC,qEAAqE,CAAC;QAClF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACzC,QAAQ,CAAC,qCAAqC,CAAC;QAClD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACzC,QAAQ,CAAC,qCAAqC,CAAC;QAClD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aAC7C,QAAQ,CAAC,kCAAkC,CAAC;QAC/C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aAC/C,QAAQ,CAAC,sBAAsB,CAAC;QACnC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aAC/C,QAAQ,CAAC,oBAAoB,CAAC;QACjC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aAClC,QAAQ,CAAC,qCAAqC,CAAC;QAClD,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;aACxG,QAAQ,CAAC,gCAAgC,CAAC;QAC7C,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;aAC7B,QAAQ,CAAC,4BAA4B,CAAC;QACzC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACnD,QAAQ,CAAC,4IAA4I,CAAC;QACzJ,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;aACnD,QAAQ,CAAC,yEAAyE,CAAC;KACvF,EACD,IAAI,CAAC,uBAAuB,CAAC,CAC9B,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,sjBAAsjB,EACtjB;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;aACpC,QAAQ,CAAC,iOAAiO,CAAC;KAC/O,EACD,IAAI,CAAC,yBAAyB,CAAC,CAChC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,mpBAAmpB,EACnpB,EAAE,GAAG,SAAS,EAAE,EAChB,IAAI,CAAC,uBAAuB,CAAC,CAC9B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ScavioClient } from "../lib/client.js";
3
+ export declare function registerSecTools(server: McpServer, getClient: () => ScavioClient): void;