@mambalabsdev/mcp-talent-agency-lookup 1.0.1 → 1.1.1
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 +13 -7
- package/build/index.js +56 -20
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Influencer Talent Agency Lookup MCP Server
|
|
2
2
|
|
|
3
|
-
[](https://glama.ai/mcp/servers/mambalabsdev/mcp-talent-agency-lookup) [](https://registry.modelcontextprotocol.io/v0/servers?search=com.mambabuilt/mcp-talent-agency-lookup&limit=1) [](https://www.npmjs.com/package/@mambalabsdev/mcp-talent-agency-lookup) [](https://www.npmjs.com/package/@mambalabsdev/mcp-talent-agency-lookup) [](https://github.com/mambalabsdev/mcp-talent-agency-lookup/blob/main/LICENSE) [](https://mcpservers.org/servers/mambalabsdev/mcp-talent-agency-lookup)
|
|
4
4
|
|
|
5
5
|
MCP server for the Mamba Labs [Influencer Talent Agency Lookup](https://apify.com/mambalabs/talent-agency-lookup) actor on Apify.
|
|
6
6
|
|
|
@@ -28,13 +28,17 @@ npx -y @mambalabsdev/mcp-talent-agency-lookup
|
|
|
28
28
|
|
|
29
29
|
Get an Apify token at [console.apify.com/account/integrations](https://console.apify.com/account/integrations).
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Tools
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
| Tool | Direction | Inputs |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `lookup_agency_for_creator` | Creator to agency: one row per creator with the agency that represents them | `handles`, `platforms`, `escalate_on_block`, `batch_size`, `contribute_to_shared_pool` |
|
|
36
|
+
| `list_agency_roster` | Agency to roster: one row per creator on the agency's public roster | `agency_domains`, `agency_names`, `render_unreadable_pages`, `contribute_to_shared_pool` |
|
|
37
|
+
| `lookup_influencer_talent_agency` | Both directions in one call, every actor input | all of the inputs below |
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
All three call the same actor, so the pricing below applies to each. The two directional tools are the simpler choice when only one direction is needed; the combined tool is kept so existing callers keep working.
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
### Inputs
|
|
38
42
|
|
|
39
43
|
| Input | Type | Required | Notes |
|
|
40
44
|
| --- | --- | --- | --- |
|
|
@@ -44,7 +48,7 @@ Pass `handles` for creator to agency, or `agency_domains` or `agency_names` for
|
|
|
44
48
|
| `agency_names` | array | no | Agency to roster by name when you do not have the domain. Exact or partial name match against the list. |
|
|
45
49
|
| `render_unreadable_pages` | boolean | no | Off by default. Some agency roster pages build their talent grid in the browser and return an empty shell to a plain fetch, so the roster reads as empty. Turn this on to render those pages in a headless browser and read the roster from the rendered page. Charged per page rendered (event browser-render) to cover the browser compute, and only when the rendered page comes back readable. A page that answers with a bot challenge is recorded as blocked and is never rendered. Default `false`. |
|
|
46
50
|
| `escalate_on_block` | boolean | no | On by default. A profile fetch that comes back as a bot detection page is retried once over the residential proxy. On Instagram the bio, bio link, and following are read from the profile page over residential when the embed and the datacenter API did not carry them, and a page that comes back readable charges instagram-bio-fetch ($0.010). Uncheck it to never pay that event: a blocked profile then returns a labeled error row, and Instagram rows keep an empty bio and bio link on about half of the reads. Default `true`. |
|
|
47
|
-
| `batch_size` | integer | no | Rows fetched at once. Leave empty for the measured per platform default; the measurement is in the README. Higher is faster and, above the measured point, loses rows. |
|
|
51
|
+
| `batch_size` | integer | no | Rows fetched at once. Leave empty for the measured per platform default; the measurement is in the [actor README](https://apify.com/mambalabs/talent-agency-lookup#-batch-or-single). Higher is faster and, above the measured point, loses rows. |
|
|
48
52
|
| `contribute_to_shared_pool` | boolean | no | On by default. The run contributes the public records it finds to a shared creator and agency pool that all users of this actor read from, so a later run reads what this one found. Only public data that is already in your own output rows is sent: nothing from your Apify account, your input list, your API keys, or your own notes. Nothing is charged for a contribution. Turn this off and the run still reads the pool and writes nothing to it. Default: true. |
|
|
49
53
|
|
|
50
54
|
Nothing is required, but a call with no `handles`, no `agency_domains`, and no `agency_names` has nothing to look up and the run fails with a message saying so.
|
|
@@ -60,11 +64,13 @@ Influencer Talent Agency Lookup is pay per event on Apify. Every price below is
|
|
|
60
64
|
| `browser-render` | Browser render | $0.004 | Once per agency roster page rendered in the headless browser because the plain fetch returned an empty shell, and only when the rendered page came back readable. Only when `render_unreadable_pages` is on. |
|
|
61
65
|
| `instagram-bio-fetch` | Instagram bio fetch | $0.01 | Once per Instagram profile row when the bio, bio link, and following were read from the profile page over the residential proxy and came back readable. Only when `escalate_on_block` is on. |
|
|
62
66
|
|
|
67
|
+
`apify-actor-start`, the start event Apify adds to pay per event actors by default, is not on this actor's pricing record. The run overhead is billed once per run through the actor's own `actor-start` event above, at $0.001, so a run is never charged for its start twice.
|
|
68
|
+
|
|
63
69
|
## Reading the output
|
|
64
70
|
|
|
65
71
|
Every row carries `agency_match_method`: `email_domain_exact`, `email_domain_parent`, `public_roster`, `bio_wording`, or `no_match`. A `no_match` row names the email domains it tried in `error_reason`. Every row also carries `row_status` and `error_reason`, so a creator or an agency the actor could not read comes back as a row saying why, not as a gap in the list. Filter on `row_status` before loading a table.
|
|
66
72
|
|
|
67
|
-
Coverage is partial by construction. The bundled list
|
|
73
|
+
Coverage is partial by construction. The bundled list held 143 agencies and 557 roster creators when the actor was published, seeded from 13 public directories, and it grows through the shared pool.
|
|
68
74
|
|
|
69
75
|
## What this actor shares
|
|
70
76
|
|
package/build/index.js
CHANGED
|
@@ -171,28 +171,64 @@ const server = new McpServer({
|
|
|
171
171
|
version: pkg.version,
|
|
172
172
|
});
|
|
173
173
|
// Influencer Talent Agency Lookup (immutable actor ID zCuX4Mgyg6JvXgGzd)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
174
|
+
const ACTOR_ID = "zCuX4Mgyg6JvXgGzd";
|
|
175
|
+
const ACTOR_LABEL = "Influencer Talent Agency Lookup";
|
|
176
|
+
// Input fields, defined once and shared by the three tools. Descriptions mirror
|
|
177
|
+
// the live actor input schema (test/fixtures/live-input-schema.json).
|
|
178
|
+
const fields = {
|
|
179
|
+
handles: z.array(z.string()).optional().describe("One per line. A profile URL on any supported platform (https://www.tiktok.com/@name, https://www.instagram.com/name/, https://www.youtube.com/@name, a Pinterest, Twitch, or Threads profile, an Apple Podcasts show page, or a Spotify show), or platform:@handle (tiktok:@name). A bare @handle needs `platforms` and is looked up on each listed platform. One entry is a single run; a list is a batch. Duplicates are removed before any fetch."),
|
|
180
|
+
platforms: z.array(z.enum(["tiktok", "instagram", "youtube", "pinterest", "twitch", "threads", "podcast"])).optional().describe("Which platforms a bare @handle is looked up on. A full profile URL carries its own platform and ignores this. This actor does not search; pass the creators you want read. Supported: TikTok, Instagram, YouTube, Pinterest, Twitch, Threads, and podcasts. Not X, not Facebook pages, not LinkedIn."),
|
|
181
|
+
agency_domains: z.array(z.string()).optional().describe("Agency to roster: one domain per line (for example viralnation.com). Returns one row per creator on the agency's public roster."),
|
|
182
|
+
agency_names: z.array(z.string()).optional().describe("Agency to roster by name when you do not have the domain. Exact or partial name match against the list."),
|
|
183
|
+
render_unreadable_pages: z.boolean().optional().describe("Off by default. Some agency roster pages build their talent grid in the browser and return an empty shell to a plain fetch, so the roster reads as empty. Turn this on to render those pages in a headless browser and read the roster from the rendered page. Charged per page rendered (event browser-render) to cover the browser compute, and only when the rendered page comes back readable. A page that answers with a bot challenge is recorded as blocked and is never rendered."),
|
|
184
|
+
escalate_on_block: z.boolean().optional().describe("On by default. A profile fetch that comes back as a bot detection page is retried once over the residential proxy. On Instagram the bio, bio link, and following are read from the profile page over residential when the embed and the datacenter API did not carry them, and a page that comes back readable charges instagram-bio-fetch ($0.010). Uncheck it to never pay that event: a blocked profile then returns a labeled error row, and Instagram rows keep an empty bio and bio link on about half of the reads."),
|
|
185
|
+
batch_size: z.number().int().min(1).max(10).optional().describe("Rows fetched at once. Leave empty for the measured per platform default; the measurement is in the actor README, https://apify.com/mambalabs/talent-agency-lookup#-batch-or-single. Higher is faster and, above the measured point, loses rows."),
|
|
186
|
+
// Shared pool toggle. The actor input field shipped in build 0.1.11; this mirror exists so an
|
|
187
|
+
// MCP caller can turn the contribution off.
|
|
188
|
+
contribute_to_shared_pool: z.boolean().optional().describe("On by default. The run contributes the public records it finds to a shared creator and agency pool that all users of this actor read from, so a later run reads what this one found. Only public data that is already in your own output rows is sent: nothing from your Apify account, your input list, your API keys, or your own notes. Nothing is charged for a contribution. Turn this off and the run still reads the pool and writes nothing to it. Default: true."),
|
|
189
|
+
};
|
|
190
|
+
const PRICING = "Charges $0.001 per run (actor-start) plus $0.008 per row returned (agency-lookup), $0.004 per agency roster page rendered in the headless browser when render_unreadable_pages is on and the page comes back readable (browser-render), and $0.01 per Instagram bio fetch over the residential proxy when escalate_on_block is on and one is needed (instagram-bio-fetch).";
|
|
191
|
+
const POOL = "Contributes the public records it finds to a shared creator and agency pool that all users of this actor read from; set contribute_to_shared_pool to false to read the pool and write nothing. A contribution is not charged.";
|
|
192
|
+
const COVERAGE = "The agency list is seeded from 13 public directories (143 agencies and 557 roster creators when the actor was published) and grows through the shared pool; coverage is partial and every row says how it matched.";
|
|
193
|
+
const LIMITS = "It does not search for creators and does not read X, Facebook pages, or LinkedIn. Requires an APIFY_TOKEN and consumes Apify credits. Read only.";
|
|
194
|
+
const annotations = (title) => ({
|
|
195
|
+
title,
|
|
196
|
+
readOnlyHint: true,
|
|
197
|
+
destructiveHint: false,
|
|
198
|
+
idempotentHint: true,
|
|
199
|
+
openWorldHint: true,
|
|
200
|
+
});
|
|
201
|
+
const callActor = (args) => runActor(ACTOR_ID, ACTOR_LABEL, compact(args));
|
|
202
|
+
server.registerTool("lookup_agency_for_creator", {
|
|
203
|
+
title: "Find the Talent Agency Behind an Influencer",
|
|
204
|
+
description: `Creator to agency. Pass creator handles or profile URLs (TikTok, Instagram, YouTube, Pinterest, Twitch, Threads, or a podcast) and get one row per creator with the talent agency that represents them, its domain, its public contact, and agency_match_method (email_domain_exact, email_domain_parent, public_roster, bio_wording, or no_match with the email domains tried in error_reason). Use list_agency_roster for the other direction. ${COVERAGE} ${PRICING} ${POOL} ${LIMITS}`,
|
|
205
|
+
annotations: annotations("Find the Talent Agency Behind an Influencer"),
|
|
206
|
+
inputSchema: {
|
|
207
|
+
handles: fields.handles,
|
|
208
|
+
platforms: fields.platforms,
|
|
209
|
+
escalate_on_block: fields.escalate_on_block,
|
|
210
|
+
batch_size: fields.batch_size,
|
|
211
|
+
contribute_to_shared_pool: fields.contribute_to_shared_pool,
|
|
183
212
|
},
|
|
213
|
+
}, async (args) => callActor(args));
|
|
214
|
+
server.registerTool("list_agency_roster", {
|
|
215
|
+
title: "List an Influencer Talent Agency's Roster",
|
|
216
|
+
description: `Agency to roster. Pass agency domains or agency names and get one row per creator on the agency's public roster, with platform, handle, and profile URL. Use lookup_agency_for_creator for the other direction. ${COVERAGE} ${PRICING} ${POOL} ${LIMITS}`,
|
|
217
|
+
annotations: annotations("List an Influencer Talent Agency's Roster"),
|
|
184
218
|
inputSchema: {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
render_unreadable_pages: z.boolean().optional().describe("Off by default. Some agency roster pages build their talent grid in the browser and return an empty shell to a plain fetch, so the roster reads as empty. Turn this on to render those pages in a headless browser and read the roster from the rendered page. Charged per page rendered (event browser-render) to cover the browser compute, and only when the rendered page comes back readable. A page that answers with a bot challenge is recorded as blocked and is never rendered."),
|
|
190
|
-
escalate_on_block: z.boolean().optional().describe("On by default. A profile fetch that comes back as a bot detection page is retried once over the residential proxy. On Instagram the bio, bio link, and following are read from the profile page over residential when the embed and the datacenter API did not carry them, and a page that comes back readable charges instagram-bio-fetch ($0.010). Uncheck it to never pay that event: a blocked profile then returns a labeled error row, and Instagram rows keep an empty bio and bio link on about half of the reads."),
|
|
191
|
-
batch_size: z.number().int().min(1).max(10).optional().describe("Rows fetched at once. Leave empty for the measured per platform default; the measurement is in the README. Higher is faster and, above the measured point, loses rows."),
|
|
192
|
-
// Shared pool toggle. The actor input field shipped in build 0.1.11; this mirror exists so an
|
|
193
|
-
// MCP caller can turn the contribution off.
|
|
194
|
-
contribute_to_shared_pool: z.boolean().optional().describe("On by default. The run contributes the public records it finds to a shared creator and agency pool that all users of this actor read from, so a later run reads what this one found. Only public data that is already in your own output rows is sent: nothing from your Apify account, your input list, your API keys, or your own notes. Nothing is charged for a contribution. Turn this off and the run still reads the pool and writes nothing to it. Default: true."),
|
|
219
|
+
agency_domains: fields.agency_domains,
|
|
220
|
+
agency_names: fields.agency_names,
|
|
221
|
+
render_unreadable_pages: fields.render_unreadable_pages,
|
|
222
|
+
contribute_to_shared_pool: fields.contribute_to_shared_pool,
|
|
195
223
|
},
|
|
196
|
-
}, async (args) =>
|
|
224
|
+
}, async (args) => callActor(args));
|
|
225
|
+
// The original combined tool, kept so existing callers keep working. It runs
|
|
226
|
+
// both directions in one call and exposes every buyer input of the live actor.
|
|
227
|
+
server.registerTool("lookup_influencer_talent_agency", {
|
|
228
|
+
title: "Look Up an Influencer's Talent Agency or an Agency's Roster",
|
|
229
|
+
description: `Both directions in one call: handles for creator to agency, agency_domains or agency_names for agency to roster. Prefer lookup_agency_for_creator or list_agency_roster when only one direction is needed. ${COVERAGE} ${PRICING} ${POOL} ${LIMITS}`,
|
|
230
|
+
annotations: annotations("Look Up an Influencer's Talent Agency or an Agency's Roster"),
|
|
231
|
+
inputSchema: fields,
|
|
232
|
+
}, async (args) => callActor(args));
|
|
197
233
|
const transport = new StdioServerTransport();
|
|
198
234
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mambalabsdev/mcp-talent-agency-lookup",
|
|
3
3
|
"displayName": "Influencer Talent Agency Lookup",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"description": "MCP server for the Mamba Labs Influencer Talent Agency Lookup actor on Apify. Creator handles in, the talent agency behind each one out, or an agency in, its public roster out.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc && chmod +x build/index.js",
|
|
12
12
|
"test": "npm run build && node --test test/*.test.js",
|
|
13
|
-
"prepublishOnly": "npm run build"
|
|
13
|
+
"prepublishOnly": "npm run build",
|
|
14
|
+
"sync-fixture": "node scripts/sync-input-schema-fixture.mjs"
|
|
14
15
|
},
|
|
15
16
|
"keywords": [
|
|
16
17
|
"mcp",
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"node": ">=18"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
49
|
+
"@modelcontextprotocol/sdk": "^1.32.0",
|
|
49
50
|
"zod": "^4.5.4"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|