@scavio/mcp-server 0.6.0 → 0.8.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.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  ![GitHub Repo stars](https://img.shields.io/github/stars/scavio-ai/scavio-mcp?style=social)
4
4
  ![License](https://img.shields.io/github/license/scavio-ai/scavio-mcp)
5
5
 
6
- [Scavio](https://scavio.dev) is a unified [Web Search API](https://scavio.dev/docs/search-api) and MCP server that connects AI agents to Google, YouTube, Amazon, Walmart, TikTok, Instagram, Reddit, X, and LinkedIn. 95 tools for web search, product lookup, video discovery, and social media data through a single [Search API](https://scavio.dev/docs/search-api) endpoint.
6
+ [Scavio](https://scavio.dev) is a unified [Web Search API](https://scavio.dev/docs/search-api) and MCP server that connects AI agents to Google, YouTube, Amazon, Walmart, TikTok, Instagram, Reddit, X, LinkedIn, and TikTok Shop. 98 tools for web search, product lookup, video discovery, and social media data through a single [Search API](https://scavio.dev/docs/search-api) endpoint.
7
7
 
8
8
  ## Remote MCP Server
9
9
 
@@ -296,7 +296,7 @@ Add to settings (`Cmd+,`):
296
296
  | `get_reddit_popular` | Get the site-wide popular feed |
297
297
  | `get_reddit_trending` | Get current trending search queries |
298
298
 
299
- ### [X API](https://scavio.dev/docs/x-api)
299
+ ### [X API](https://scavio.dev/docs/x-search)
300
300
 
301
301
  | Tool | Description |
302
302
  |------|-------------|
@@ -312,24 +312,52 @@ Add to settings (`Cmd+,`):
312
312
  | `get_x_user_followings` | List accounts a user follows |
313
313
  | `get_x_trending` | Get trending topics for a country |
314
314
 
315
- ### [LinkedIn API](https://scavio.dev/docs/linkedin-api)
315
+ ### [LinkedIn API](https://scavio.dev/docs/linkedin-person)
316
316
 
317
317
  | Tool | Description |
318
318
  |------|-------------|
319
- | `get_linkedin_person` | Get a member's full profile |
320
- | `get_linkedin_person_about` | Get a member's about/overview metadata |
321
- | `get_linkedin_person_posts` | List a member's recent posts |
322
- | `get_linkedin_person_contact` | Get a member's public contact info |
323
- | `get_linkedin_company` | Get a company's profile |
324
- | `get_linkedin_company_posts` | List a company's recent posts |
325
- | `get_linkedin_company_people` | List people who work at a company |
326
- | `get_linkedin_company_jobs` | List a company's open job listings |
327
- | `search_linkedin_people` | Search for people by name, title, company, or school |
328
- | `search_linkedin_jobs` | Search for jobs by keyword |
329
- | `search_linkedin_posts` | Search for posts by keyword |
319
+ | `get_linkedin_person` | Get a member's full profile, experience and education |
320
+ | `get_linkedin_person_about` | Get a member's about/overview sections |
321
+ | `get_linkedin_person_posts` | List a member's recent posts (up to 50) |
322
+ | `get_linkedin_company` | Get a company's profile, locations and related companies |
323
+ | `get_linkedin_company_posts` | List a company's recent posts (up to 50) |
324
+ | `search_linkedin_jobs` | Search for jobs by keyword and location |
330
325
  | `get_linkedin_job` | Get full details for a job listing |
331
326
  | `get_linkedin_post` | Get full details for a single post |
332
- | `get_linkedin_post_comments` | Get comments on a post |
327
+ | `get_linkedin_post_comments` | Get comments on a post, 10 per page |
328
+
329
+ Every LinkedIn tool costs 1 credit. Take a vanity handle, slug or id, or a full
330
+ LinkedIn URL.
331
+
332
+ The upstream provider retired the datasets behind member contact info, the
333
+ company employee directory, per-company job listings, people search and post
334
+ search, so those five tools were removed. `get_linkedin_company` still returns a
335
+ small sample of featured employees, and `search_linkedin_jobs` with a company
336
+ name substitutes for per-company listings.
337
+
338
+ ### [TikTok Shop API](https://scavio.dev/docs/tiktok-shop-search)
339
+
340
+ | Tool | Description |
341
+ |------|-------------|
342
+ | `search_tiktok_shop` | Search TikTok Shop products by keyword (US catalog, exact prices) |
343
+ | `get_tiktok_shop_search_suggestions` | Keyword autocomplete for a partial query, 8 regions |
344
+ | `get_tiktok_shop_product` | Full product detail (no price; ~44% of search IDs resolve) |
345
+ | `get_tiktok_shop_product_reviews` | Paginated product reviews, up to 200 per call |
346
+ | `get_tiktok_shop_categories` | The global category tree (28 top-level, 240 nodes) |
347
+ | `get_tiktok_shop_category_products` | List products under a category ID, with exact prices |
348
+ | `get_tiktok_shop_shop_products` | List a seller's catalog, 30 per page, with exact prices |
349
+ | `resolve_tiktok_shop_url` | Resolve a TikTok Shop URL or share link to a product/shop ID |
350
+
351
+ Two things to know: `get_tiktok_shop_product` does not return a price (TikTok masks it on the
352
+ product page upstream) - exact prices come from `search_tiktok_shop`,
353
+ `get_tiktok_shop_shop_products` and `get_tiktok_shop_category_products`. And only about 44% of the
354
+ product IDs returned by search resolve on `get_tiktok_shop_product` (11 of 25 measured), because
355
+ upstream has no detail data for the rest. That miss is signalled by the HTTP 404 status, not by any
356
+ field in the response body, and it is a normal outcome rather than an error to retry - the tool
357
+ returns it as a plain result with `status: "no_detail_data"` so agents skip the product instead of
358
+ looping. For an id that will not resolve, `get_tiktok_shop_product_reviews` is often still usable:
359
+ across 8 measured ids that failed on detail, 8 of 8 returned HTTP 200 on reviews and 7 of 8 returned
360
+ at least one review.
333
361
 
334
362
  ### Account
335
363
 
@@ -4,6 +4,7 @@ import { registerAmazonTools } from "./amazon.js";
4
4
  import { registerWalmartTools } from "./walmart.js";
5
5
  import { registerUsageTool } from "./usage.js";
6
6
  import { registerTiktokTools } from "./tiktok.js";
7
+ import { registerTiktokShopTools } from "./tiktok-shop.js";
7
8
  import { registerInstagramTools } from "./instagram.js";
8
9
  import { registerRedditTools } from "./reddit.js";
9
10
  import { registerXTools } from "./x.js";
@@ -14,6 +15,7 @@ export function registerAllTools(server, getClient) {
14
15
  registerAmazonTools(server, getClient);
15
16
  registerWalmartTools(server, getClient);
16
17
  registerTiktokTools(server, getClient);
18
+ registerTiktokShopTools(server, getClient);
17
19
  registerInstagramTools(server, getClient);
18
20
  registerRedditTools(server, getClient);
19
21
  registerXTools(server, getClient);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,SAA6B;IAC/E,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,sBAAsB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,qBAAqB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzC,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,SAA6B;IAC/E,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,uBAAuB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC3C,sBAAsB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvC,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,qBAAqB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzC,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACvC,CAAC"}
@@ -1,6 +1,15 @@
1
1
  import { z } from "zod";
2
2
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
3
3
  import { ApiError } from "../lib/errors.js";
4
+ // The provider retired the `linkedin/web/*` namespace these tools were built on.
5
+ // The nine below run on `web_v2`: every reference is a vanity handle, slug or id
6
+ // (a full LinkedIn URL also works anywhere), and all cost 1 credit.
7
+ //
8
+ // Five tools were removed rather than left registered - person_contact,
9
+ // company_people, company_jobs, search_people and search_posts have no upstream
10
+ // and can only return 410. Unlike an SDK method, an MCP tool is a menu item for
11
+ // a model: one that always fails burns turns and invites retries, so it is
12
+ // better absent. The REST API still answers those paths with an explicit 410.
4
13
  function handleApiError(err) {
5
14
  if (err instanceof ApiError) {
6
15
  if (err.status === 429)
@@ -11,240 +20,53 @@ function handleApiError(err) {
11
20
  }
12
21
  throw new McpError(ErrorCode.InternalError, String(err));
13
22
  }
23
+ const personRef = {
24
+ username: z.string().min(1).optional()
25
+ .describe("Public identifier (vanity handle), e.g. 'williamhgates'."),
26
+ url: z.string().url().optional()
27
+ .describe("Full LinkedIn profile URL, as an alternative to username."),
28
+ };
29
+ const companyRef = {
30
+ company: z.string().min(1).optional()
31
+ .describe("Company universal name (slug), e.g. 'microsoft'."),
32
+ url: z.string().url().optional()
33
+ .describe("Full LinkedIn company URL, as an alternative to company."),
34
+ };
35
+ const postRef = {
36
+ post_id: z.string().min(1).optional()
37
+ .describe("Post id or activity urn, e.g. '7488618410256523265'."),
38
+ url: z.string().url().optional()
39
+ .describe("Full LinkedIn post URL, as an alternative to post_id."),
40
+ };
14
41
  export function registerLinkedinTools(server, getClient) {
15
- server.tool("get_linkedin_person", `Get a LinkedIn member's full profile as JSON. Returns the member urn, public identifier, name, headline, location, premium/open-to-work/hiring flags, avatar, about, experiences, educations, skills, and follower/connection counts. Accepts the public identifier (vanity handle). Costs 4 credits.`, {
16
- username: z.string().min(1)
17
- .describe("Public identifier (vanity handle), e.g. 'williamhgates'."),
18
- include_experiences: z.boolean().optional()
19
- .describe("Include the work experience section (default true)."),
20
- include_educations: z.boolean().optional()
21
- .describe("Include the education section (default true)."),
22
- include_skills: z.boolean().optional()
23
- .describe("Include the skills section (default true)."),
24
- include_certifications: z.boolean().optional()
25
- .describe("Include the certifications section (default true)."),
26
- include_follower_and_connection: z.boolean().optional()
27
- .describe("Include follower and connection counts (default true)."),
28
- }, async (params) => {
42
+ const call = (path) => async (params) => {
29
43
  try {
30
- const data = await getClient().post("/api/v1/linkedin/person", params);
44
+ const data = await getClient().post(path, params);
31
45
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
32
46
  }
33
47
  catch (err) {
34
48
  return handleApiError(err);
35
49
  }
36
- });
37
- server.tool("get_linkedin_person_about", `Get about/overview metadata for a LinkedIn member as JSON, including join date, contact information, and profile photo. Provide the member urn, or a username that will be resolved to a urn. Costs 4 credits.`, {
38
- urn: z.string().min(1).optional()
39
- .describe("Member urn, e.g. 'ACoAAA8BYqEBCGLg_vT_ca6mMEqkpp9nVffJ3hc'."),
40
- username: z.string().min(1).optional()
41
- .describe("Public identifier; resolved to a urn if urn is omitted, e.g. 'williamhgates'."),
42
- }, async (params) => {
43
- try {
44
- const data = await getClient().post("/api/v1/linkedin/person/about", params);
45
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
46
- }
47
- catch (err) {
48
- return handleApiError(err);
49
- }
50
- });
51
- server.tool("get_linkedin_person_posts", `List a LinkedIn member's recent posts as JSON. Each post includes its ID, type, text, content (images, video, article, poll), and activity counts (likes, comments, shares). Provide the member urn or a username. Use data.next_cursor as the next cursor while has_more is true. Costs 4 credits.`, {
52
- urn: z.string().min(1).optional()
53
- .describe("Member urn, e.g. 'ACoAAA8BYqEBCGLg_vT_ca6mMEqkpp9nVffJ3hc'."),
54
- username: z.string().min(1).optional()
55
- .describe("Public identifier; resolved if urn is omitted, e.g. 'williamhgates'."),
56
- cursor: z.string().optional()
57
- .describe("Pagination cursor (next_cursor) from a previous response."),
58
- }, async (params) => {
59
- try {
60
- const data = await getClient().post("/api/v1/linkedin/person/posts", params);
61
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
62
- }
63
- catch (err) {
64
- return handleApiError(err);
65
- }
66
- });
67
- server.tool("get_linkedin_person_contact", `Get a LinkedIn member's public contact information as JSON. Accepts the public identifier (vanity handle). Costs 4 credits.`, {
68
- username: z.string().min(1)
69
- .describe("Public identifier (vanity handle), e.g. 'williamhgates'."),
70
- }, async (params) => {
71
- try {
72
- const data = await getClient().post("/api/v1/linkedin/person/contact", params);
73
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
74
- }
75
- catch (err) {
76
- return handleApiError(err);
77
- }
78
- });
79
- server.tool("get_linkedin_company", `Get a LinkedIn company's profile as JSON. Accepts the company universal name (slug) or a LinkedIn company URL. Costs 1 credit.`, {
80
- company: z.string().min(1)
81
- .describe("Company universal name (slug) or LinkedIn company URL, e.g. 'microsoft'."),
82
- }, async (params) => {
83
- try {
84
- const data = await getClient().post("/api/v1/linkedin/company", params);
85
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
86
- }
87
- catch (err) {
88
- return handleApiError(err);
89
- }
90
- });
91
- server.tool("get_linkedin_company_posts", `List a LinkedIn company's recent posts as JSON. Accepts the company slug or URL. Use data.next_cursor as the next cursor while has_more is true. Costs 1 credit.`, {
92
- company: z.string().min(1)
93
- .describe("Company universal name (slug) or LinkedIn company URL, e.g. 'microsoft'."),
94
- cursor: z.string().optional()
95
- .describe("Pagination cursor (next_cursor) from a previous response."),
96
- count: z.number().int().positive().max(100).optional()
97
- .describe("Number of posts to return per page (max 100)."),
98
- }, async (params) => {
99
- try {
100
- const data = await getClient().post("/api/v1/linkedin/company/posts", params);
101
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
102
- }
103
- catch (err) {
104
- return handleApiError(err);
105
- }
106
- });
107
- server.tool("get_linkedin_company_people", `List people who work at a LinkedIn company as JSON. Provide the numeric company_id, or a company slug/url that will be resolved to a company_id. Use data.next_cursor as the next cursor while has_more is true. Costs 4 credits.`, {
108
- company_id: z.string().min(1).optional()
109
- .describe("Numeric company id, e.g. '1035'."),
110
- company: z.string().min(1).optional()
111
- .describe("Company slug/url; resolved to a company_id if company_id is omitted, e.g. 'microsoft'."),
112
- cursor: z.string().optional()
113
- .describe("Pagination cursor (next_cursor) from a previous response."),
114
- }, async (params) => {
115
- try {
116
- const data = await getClient().post("/api/v1/linkedin/company/people", params);
117
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
118
- }
119
- catch (err) {
120
- return handleApiError(err);
121
- }
122
- });
123
- server.tool("get_linkedin_company_jobs", `List a LinkedIn company's open job listings as JSON. Provide the numeric company_id, or a company slug/url that will be resolved to a company_id. Use data.next_cursor as the next cursor while has_more is true. Costs 4 credits.`, {
124
- company_id: z.string().min(1).optional()
125
- .describe("Numeric company id, e.g. '1035'."),
126
- company: z.string().min(1).optional()
127
- .describe("Company slug/url; resolved to a company_id if company_id is omitted, e.g. 'microsoft'."),
128
- cursor: z.string().optional()
129
- .describe("Pagination cursor (next_cursor) from a previous response."),
130
- }, async (params) => {
131
- try {
132
- const data = await getClient().post("/api/v1/linkedin/company/jobs", params);
133
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
134
- }
135
- catch (err) {
136
- return handleApiError(err);
137
- }
138
- });
139
- server.tool("search_linkedin_people", `Search LinkedIn for people as JSON. Filter by name, title, company, or school, and optionally location. Each result includes the member urn, profile URL, public identifier, name, title, location, and verified/premium/open-to-work/hiring flags. Provide at least one of search, title, company, or school. Use data.next_cursor as the next cursor while has_more is true. Costs 4 credits.`, {
140
- search: z.string().min(1).optional()
141
- .describe("Name to search for, e.g. 'john'."),
142
- title: z.string().optional()
143
- .describe("Job title filter, e.g. 'engineer'."),
144
- company: z.string().optional()
145
- .describe("Company filter."),
146
- school: z.string().optional()
147
- .describe("School filter."),
50
+ };
51
+ server.tool("get_linkedin_person", `Get a LinkedIn member's full profile as JSON: name, headline, about text, location, avatar, banner, follower and connection counts, current company, full work experience (including grouped multi-role entries), education, honours, bio links and similar profiles. Provide a vanity handle or a full profile URL. Costs 1 credit.`, personRef, call("/api/v1/linkedin/person"));
52
+ server.tool("get_linkedin_person_about", `Get the about/overview slice of a LinkedIn member's profile as JSON: about text, headline, work experience, education, honours and bio links. Use this instead of get_linkedin_person when you only need the narrative sections. Provide a vanity handle or a full profile URL. Costs 1 credit.`, personRef, call("/api/v1/linkedin/person/about"));
53
+ server.tool("get_linkedin_person_posts", `Get a LinkedIn member's recent posts as JSON, each with text, url, timestamps, a full reaction breakdown (likes, appreciations, empathy, interest, praise), comment and repost counts, attached images, article metadata and the author. Returns up to 50 posts; the provider exposes no further pages, so there is no cursor. Provide a vanity handle or a full profile URL. Costs 1 credit.`, personRef, call("/api/v1/linkedin/person/posts"));
54
+ server.tool("get_linkedin_company", `Get a LinkedIn company profile as JSON: name, about, description, website, industries, specialties, company size, employee and follower counts, headquarters, all office locations, logo, a small sample of featured employees, similar and affiliated companies, and recent updates. Provide a company slug or a full company URL. Costs 1 credit.`, companyRef, call("/api/v1/linkedin/company"));
55
+ server.tool("get_linkedin_company_posts", `Get a LinkedIn company's recent posts as JSON, in the same shape as member posts (text, url, reaction breakdown, comment and repost counts, images, author). Returns up to 50 posts; the provider exposes no further pages, so there is no cursor. Provide a company slug or a full company URL. Costs 1 credit.`, companyRef, call("/api/v1/linkedin/company/posts"));
56
+ server.tool("search_linkedin_jobs", `Search LinkedIn job listings by keyword as JSON, returning title, company, company URL and logo, location, posted time, workplace type and salary for each hit. Note the provider rotates its result set, so repeating the same search returns different listings and there is no stable pagination. Pass a company name as the search term to approximate a per-company job listing. Costs 1 credit.`, {
57
+ search: z.string().min(1).describe("Search keyword, e.g. 'software engineer'."),
148
58
  location: z.string().optional()
149
- .describe("A geo name or id to filter by."),
150
- cursor: z.string().optional()
151
- .describe("Pagination cursor (next_cursor) from a previous response."),
152
- }, async (params) => {
153
- try {
154
- const data = await getClient().post("/api/v1/linkedin/search/people", params);
155
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
156
- }
157
- catch (err) {
158
- return handleApiError(err);
159
- }
160
- });
161
- server.tool("search_linkedin_jobs", `Search LinkedIn for jobs by keyword as JSON, with optional filters for date posted, location, experience level, remote, and job type. Use data.next_cursor as the next cursor while has_more is true. Costs 4 credits.`, {
162
- search: z.string().min(1)
163
- .describe("Job search keyword, e.g. 'software engineer'."),
164
- cursor: z.string().optional()
165
- .describe("Pagination cursor (next_cursor) from a previous response."),
166
- date_posted: z.string().optional()
167
- .describe("Date-posted filter."),
168
- geocode: z.string().optional()
169
- .describe("Location geocode filter."),
170
- experience_level: z.string().optional()
171
- .describe("Experience-level filter."),
172
- remote: z.string().optional()
173
- .describe("Remote filter."),
174
- job_type: z.string().optional()
175
- .describe("Job-type filter."),
176
- }, async (params) => {
177
- try {
178
- const data = await getClient().post("/api/v1/linkedin/search/jobs", params);
179
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
180
- }
181
- catch (err) {
182
- return handleApiError(err);
183
- }
184
- });
185
- server.tool("search_linkedin_posts", `Search LinkedIn for posts by keyword as JSON. Each result includes the post ID, URL, title, activity counts (likes, comments, shares), timestamp, and author details. Use data.next_cursor as the next cursor while has_more is true. Costs 4 credits.`, {
186
- search: z.string().min(1)
187
- .describe("Post search keyword, e.g. 'AI agents'."),
188
- cursor: z.string().optional()
189
- .describe("Pagination cursor (next_cursor) from a previous response."),
190
- date_posted: z.string().optional()
191
- .describe("Date-posted filter."),
192
- sort_by: z.string().optional()
193
- .describe("Sort order filter."),
194
- content_type: z.string().optional()
195
- .describe("Content-type filter."),
196
- }, async (params) => {
197
- try {
198
- const data = await getClient().post("/api/v1/linkedin/search/posts", params);
199
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
200
- }
201
- catch (err) {
202
- return handleApiError(err);
203
- }
204
- });
205
- server.tool("get_linkedin_job", `Get full details for a single LinkedIn job listing as JSON. Accepts a job ID. Costs 4 credits.`, {
206
- job_id: z.string().min(1)
207
- .describe("Job ID, e.g. '3900000000'."),
208
- include_skills: z.boolean().optional()
209
- .describe("Include the required-skills section."),
210
- }, async (params) => {
211
- try {
212
- const data = await getClient().post("/api/v1/linkedin/job", params);
213
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
214
- }
215
- catch (err) {
216
- return handleApiError(err);
217
- }
218
- });
219
- server.tool("get_linkedin_post", `Get full details for a single LinkedIn post as JSON. Accepts a post ID or activity urn. Costs 4 credits.`, {
220
- post_id: z.string().min(1)
221
- .describe("Post id or activity urn, e.g. '7486820977411145728'."),
222
- }, async (params) => {
223
- try {
224
- const data = await getClient().post("/api/v1/linkedin/post", params);
225
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
226
- }
227
- catch (err) {
228
- return handleApiError(err);
229
- }
230
- });
231
- server.tool("get_linkedin_post_comments", `Get comments on a LinkedIn post as JSON. Accepts a post ID or activity urn. Use data.next_cursor as the next cursor while has_more is true. Costs 4 credits.`, {
232
- post_id: z.string().min(1)
233
- .describe("Post id or activity urn, e.g. '7486820977411145728'."),
234
- cursor: z.string().optional()
235
- .describe("Pagination cursor (next_cursor) from a previous response."),
236
- sort_order: z.enum(["relevance", "recent"]).optional()
237
- .describe("'relevance' or 'recent'."),
238
- post_type: z.enum(["activity", "ugc"]).optional()
239
- .describe("Post type: 'activity' or 'ugc'."),
240
- }, async (params) => {
241
- try {
242
- const data = await getClient().post("/api/v1/linkedin/post/comments", params);
243
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
244
- }
245
- catch (err) {
246
- return handleApiError(err);
247
- }
248
- });
59
+ .describe("Geographic filter, e.g. 'United States'. Omit to search everywhere."),
60
+ }, call("/api/v1/linkedin/search/jobs"));
61
+ server.tool("get_linkedin_job", `Get full details for one LinkedIn job listing as JSON: title, full description, location, employment type, experience level, job functions, industries, benefits, skills, remote flag, closed/expiry state, applicant and view counts, salary, plus the hiring company (name, size, follower count and headquarters). Provide a job id or a full job URL. Costs 1 credit.`, {
62
+ job_id: z.string().min(1).optional().describe("Job listing id, e.g. '4415427228'."),
63
+ url: z.string().url().optional().describe("Full LinkedIn job URL, as an alternative to job_id."),
64
+ }, call("/api/v1/linkedin/job"));
65
+ server.tool("get_linkedin_post", `Get full details for one LinkedIn post as JSON: title, headline, body text, url, timestamp, hashtags, embedded links, images, video and document metadata, like and comment counts, tagged companies and people, the top visible comments, and the author with their follower and post counts. Provide a post id, activity urn, or a full post URL. Costs 1 credit.`, postRef, call("/api/v1/linkedin/post"));
66
+ server.tool("get_linkedin_post_comments", `Get the comments on a LinkedIn post as JSON, each with text, permalink, timestamp, pinned flag, the commenter (name, headline, avatar, profile URL) and any nested replies. Paginated 10 per page via a 1-based page number; the response carries the total and a has_more flag. Provide a post id, activity urn, or a full post URL. Costs 1 credit.`, {
67
+ ...postRef,
68
+ page: z.number().int().positive().optional()
69
+ .describe("1-based page number, 10 comments per page. Defaults to 1."),
70
+ }, call("/api/v1/linkedin/post/comments"));
249
71
  }
250
72
  //# sourceMappingURL=linkedin.js.map
@@ -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 registerTiktokShopTools(server: McpServer, getClient: () => ScavioClient): void;
@@ -0,0 +1,159 @@
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
+ }
14
+ const REGIONS_FULL = ["US", "GB", "SG", "MY", "PH", "TH", "VN", "ID"];
15
+ const REGIONS_LISTING = ["US", "GB"];
16
+ export function registerTiktokShopTools(server, getClient) {
17
+ server.tool("search_tiktok_shop", `Search TikTok Shop products by keyword as JSON (US catalog only). Returns up to 30 products per page, each with the product ID, title, product URL, image, exact price (current, original, discount, savings, min/max across variants), rating, sold count, variant count, brand and shop. This is one of the endpoints that carries exact prices; get_tiktok_shop_product does not. Use data.next_cursor as the next cursor while has_more is true, and dedupe by product_id across pages. Product IDs returned here are not guaranteed to resolve on get_tiktok_shop_product: only about 44% do, because upstream has no detail data for the rest. Treat search as a standalone source of product and price data, not as the first step of a reliable search-to-detail pipeline. Costs 1 credit.`, {
18
+ search: z.string().min(1).max(200)
19
+ .describe("Keyword to search the TikTok Shop catalog, e.g. 'phone case'."),
20
+ cursor: z.string().optional()
21
+ .describe("Pagination cursor (next_cursor) from a previous response."),
22
+ }, async (params) => {
23
+ try {
24
+ const data = await getClient().post("/api/v1/tiktok-shop/search", params);
25
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
26
+ }
27
+ catch (err) {
28
+ return handleApiError(err);
29
+ }
30
+ });
31
+ server.tool("get_tiktok_shop_search_suggestions", `Get TikTok Shop keyword autocomplete and expansion for a partial query as JSON, in any of 8 marketplace regions. Returns a plain list of suggestion strings (20 to 50). Suggestions are not guaranteed prefix matches: a misspelling returns typo corrections, and results can include brand and shop names. Costs 1 credit.`, {
32
+ search: z.string().min(1).max(100)
33
+ .describe("Partial keyword to expand, e.g. 'wireless'."),
34
+ region: z.enum(REGIONS_FULL).optional()
35
+ .describe("Marketplace region: US (default), GB, SG, MY, PH, TH, VN, or ID."),
36
+ }, async (params) => {
37
+ try {
38
+ const data = await getClient().post("/api/v1/tiktok-shop/search/suggestions", params);
39
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
40
+ }
41
+ catch (err) {
42
+ return handleApiError(err);
43
+ }
44
+ });
45
+ server.tool("get_tiktok_shop_product", `Get full TikTok Shop product detail as JSON: title, plain-text description, images, variants with stock and dimensions, shipping, full shop profile (followers, shop rating, sold count), category path, breadcrumbs and top reviews. Two hard limits you must plan for. First, this endpoint does NOT return a price: TikTok masks prices on the product page upstream, so read exact prices from search_tiktok_shop, get_tiktok_shop_shop_products or get_tiktok_shop_category_products instead. Second, only about 44% of the product IDs returned by search_tiktok_shop resolve here (11 of 25 measured), because upstream has no detail data for the rest. That miss is identified by the HTTP 404 status, never by a field in the body. A 404 is a NORMAL outcome, not an error and not a transient failure: this tool returns it as a plain (non-error) result with status "no_detail_data", so do not retry it, do not treat it as a broken tool, and do not switch region hoping to recover it; skip that product and move on. Search to product is not a reliable pipeline. When you still need data about an unresolvable product, try get_tiktok_shop_product_reviews: in a measured sample of 8 IDs that this endpoint could not resolve, all 8 returned HTTP 200 on reviews and 7 of 8 returned at least one review. Costs 1 credit (a 404 is billed, since the lookup still ran).`, {
46
+ product_id: z.string().regex(/^\d{6,25}$/)
47
+ .describe("TikTok Shop product ID, e.g. '1732293553906094315'."),
48
+ region: z.enum(REGIONS_FULL).optional()
49
+ .describe("Marketplace region: US (default), GB, SG, MY, PH, TH, VN, or ID."),
50
+ }, async (params) => {
51
+ try {
52
+ const data = await getClient().post("/api/v1/tiktok-shop/product", params);
53
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
54
+ }
55
+ catch (err) {
56
+ // A 404 means upstream carries no detail data for this product id. It is the
57
+ // expected outcome for roughly 56% of ids that search returns, so it must NOT be
58
+ // surfaced as isError: clients read isError as a tool failure and retry, which is
59
+ // exactly what this endpoint must not do. Genuine failures still go to handleApiError.
60
+ if (err instanceof ApiError && err.status === 404) {
61
+ return {
62
+ content: [{
63
+ type: "text",
64
+ text: JSON.stringify({
65
+ status: "no_detail_data",
66
+ http_status: 404,
67
+ product_id: params.product_id,
68
+ region: params.region ?? "US",
69
+ message: "No detail data exists upstream for this product id. This is a normal outcome for about 56% of ids returned by search_tiktok_shop, not a failure.",
70
+ retryable: false,
71
+ next_step: "Skip this product. Do not retry and do not change region. For an unresolvable id, get_tiktok_shop_product_reviews often still returns data; exact prices come from search_tiktok_shop, get_tiktok_shop_shop_products or get_tiktok_shop_category_products.",
72
+ }, null, 2),
73
+ }],
74
+ };
75
+ }
76
+ return handleApiError(err);
77
+ }
78
+ });
79
+ server.tool("get_tiktok_shop_product_reviews", `Get paginated TikTok Shop product reviews as JSON, up to 200 per call. Each review includes the review ID, star rating, text, ISO timestamp, masked reviewer name, images, verified-purchase and incentivized flags, variant and country. Also returns the star distribution and total_reviews. total_reviews drifts between calls and must not be used to compute a page count: page with has_more instead. Reviews often work for products that get_tiktok_shop_product cannot resolve, which makes this a useful fallback detail source: in a measured sample of 8 product IDs that failed on get_tiktok_shop_product, 8 of 8 returned HTTP 200 here and 7 of 8 returned at least one review (counts 15, 0, 2, 20, 4, 6, 20, 11). That is a small sample, not a guarantee. Costs 1 credit.`, {
80
+ product_id: z.string().regex(/^\d{6,25}$/)
81
+ .describe("TikTok Shop product ID, e.g. '1732293553906094315'."),
82
+ page: z.number().int().min(1).max(500).optional()
83
+ .describe("1-based page number (default 1)."),
84
+ page_size: z.number().int().min(1).max(200).optional()
85
+ .describe("Reviews per page, 1-200 (default 20)."),
86
+ sort: z.enum(["relevant", "recent"]).optional()
87
+ .describe("'relevant' (default) returns text-complete, image-heavy reviews; 'recent' is fresher but far more text-sparse."),
88
+ rating: z.number().int().min(1).max(5).optional()
89
+ .describe("Only reviews with this star rating (1-5)."),
90
+ has_media: z.boolean().optional()
91
+ .describe("Only reviews with a photo or video (default false). Wins over verified_only if both are set."),
92
+ verified_only: z.boolean().optional()
93
+ .describe("Only verified purchases (default false)."),
94
+ region: z.enum(REGIONS_FULL).optional()
95
+ .describe("Marketplace region: US (default), GB, SG, MY, PH, TH, VN, or ID."),
96
+ }, async (params) => {
97
+ try {
98
+ const data = await getClient().post("/api/v1/tiktok-shop/product/reviews", params);
99
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
100
+ }
101
+ catch (err) {
102
+ return handleApiError(err);
103
+ }
104
+ });
105
+ server.tool("get_tiktok_shop_categories", `Get the global TikTok Shop category tree as JSON: 28 top-level categories, 240 nodes, exactly two levels deep. Each node has a category ID, English name, slug, level, parent ID and image. Category IDs are identical in every region and names are always English. Takes no parameters. Use the returned IDs with get_tiktok_shop_category_products. Costs 1 credit.`, {}, async () => {
106
+ try {
107
+ const data = await getClient().post("/api/v1/tiktok-shop/categories", {});
108
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
109
+ }
110
+ catch (err) {
111
+ return handleApiError(err);
112
+ }
113
+ });
114
+ server.tool("get_tiktok_shop_category_products", `List TikTok Shop products under a category ID from get_tiktok_shop_categories as JSON, with exact prices (this is one of the endpoints that carries real prices, unlike get_tiktok_shop_product). Level 1 and level 2 category IDs both work. Page size is inconsistent upstream (15 to 20 per page), so always paginate with data.next_cursor rather than assuming a fixed page size. Category listings are shallow: after a few pages the source stops returning new products and has_more turns false, which is the end of the listing rather than an error. Costs 1 credit.`, {
115
+ category_id: z.string().regex(/^\d{4,20}$/)
116
+ .describe("Category ID from get_tiktok_shop_categories, e.g. '601450'. Level 1 or 2 both work."),
117
+ cursor: z.string().optional()
118
+ .describe("Pagination cursor (next_cursor) from a previous response."),
119
+ region: z.enum(REGIONS_LISTING).optional()
120
+ .describe("Marketplace region: US (default) or GB only. GB coverage is intermittent upstream and answers 502 when unavailable."),
121
+ }, async (params) => {
122
+ try {
123
+ const data = await getClient().post("/api/v1/tiktok-shop/category/products", params);
124
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
125
+ }
126
+ catch (err) {
127
+ return handleApiError(err);
128
+ }
129
+ });
130
+ server.tool("get_tiktok_shop_shop_products", `List a TikTok Shop seller's product catalog as JSON, 30 per page, with exact prices (this is one of the endpoints that carries real prices, unlike get_tiktok_shop_product). Accepts a shop ID (also called seller ID elsewhere on TikTok). Use data.next_cursor as the next cursor while has_more is true. Shop follower count, location and shop-level rating are not available here; call get_tiktok_shop_product for the full shop profile. Costs 1 credit.`, {
131
+ shop_id: z.string().regex(/^\d{6,25}$/)
132
+ .describe("TikTok Shop seller ID, e.g. '7495514739648989419'."),
133
+ cursor: z.string().optional()
134
+ .describe("Pagination cursor (next_cursor) from a previous response."),
135
+ region: z.enum(REGIONS_FULL).optional()
136
+ .describe("Marketplace region: US (default), GB, SG, MY, PH, TH, VN, or ID."),
137
+ }, async (params) => {
138
+ try {
139
+ const data = await getClient().post("/api/v1/tiktok-shop/shop/products", params);
140
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
141
+ }
142
+ catch (err) {
143
+ return handleApiError(err);
144
+ }
145
+ });
146
+ server.tool("resolve_tiktok_shop_url", `Resolve any TikTok Shop URL or share link to a product_id or shop_id as JSON, ready to pass to the other TikTok Shop tools. Accepts shop.tiktok.com product and store pages, tiktok.com/view/product and /view/shop links, affiliate-*.tiktok.com share links, and vt.tiktok.com or tiktok.com/t short links. Returns the type ('product' or 'shop'), the ID, a canonical shop.tiktok.com URL, and how it was resolved. Note that a product_id resolved from a link is not guaranteed to resolve on get_tiktok_shop_product either; prices always come from the listing tools. Costs 1 credit.`, {
147
+ url: z.string().url().max(2000)
148
+ .describe("A TikTok Shop URL or share link, e.g. 'https://vt.tiktok.com/ZT2AHoGsE/'."),
149
+ }, async (params) => {
150
+ try {
151
+ const data = await getClient().post("/api/v1/tiktok-shop/resolve", params);
152
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
153
+ }
154
+ catch (err) {
155
+ return handleApiError(err);
156
+ }
157
+ });
158
+ }
159
+ //# sourceMappingURL=tiktok-shop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiktok-shop.js","sourceRoot":"","sources":["../../src/tools/tiktok-shop.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@scavio/mcp-server",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "mcpName": "io.github.scavio-ai/scavio-mcp",
5
- "description": "MCP server connecting AI agents to Google, YouTube, Amazon, Walmart, TikTok, Instagram, Reddit, X, and LinkedIn. 95 tools for web search, product lookup, video discovery, and social media analysis.",
5
+ "description": "MCP server connecting AI agents to Google, YouTube, Amazon, Walmart, TikTok, Instagram, Reddit, X, LinkedIn, and TikTok Shop. 98 tools for web search, product lookup, video discovery, and social media analysis.",
6
6
  "type": "module",
7
7
  "license": "MIT",
8
8
  "author": "Scavio",