@mambalabsdev/mcp-youtube-channel-transcript-extractor 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -53,6 +53,7 @@ Tool: `get_youtube_channel_stats`
53
53
  | `skipCache` | boolean | When "false" (default) a successful lookup is cached for seven days and reused. Set "true" to force a fresh fetch. Sent as a string for Clay compatibi |
54
54
  | `includeTranscripts` | boolean | When "true", full timestamped transcripts are pulled for the most recent videos on the channel and returned as one row per video. Default is "false" b |
55
55
  | `transcriptVideoCount` | string | How many of the channel's most recent videos to pull transcripts for, when transcripts are on. Default 5. Each video is one extra fetch and one extra |
56
+ | `max_charge_usd` | number | Optional spending cap for this call, in USD. The actor stops before any charge that would take the run past this amount and keeps every row already charged. |
56
57
 
57
58
  ## Reading the output
58
59
 
@@ -72,6 +73,20 @@ first. The vocabulary is the same across the whole Mamba Labs social family:
72
73
  answer is no. `null` means we could not look. If you filter for companies with no
73
74
  presence, filter on `false`, because `null` rows are unknown rather than absent.
74
75
 
76
+ ## Pricing
77
+
78
+ You pay per event on Apify, billed to your own Apify account. Prices from the live pricing record, read 2026-10-16:
79
+
80
+ | Event | Price per event (USD) | Fires when |
81
+ | --- | --- | --- |
82
+ | `apify-actor-start` | $0.00005 | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). |
83
+ | `company-checked` | $0.0035 on the Free plan, down to $0.00245 on higher Apify plans | Once per company for which the discovery cascade completed and a non degraded channel row was produced, whether or not a channel was found. Does not fire on a degraded row. |
84
+ | `profile-resolved` | $0.0025 on the Free plan, down to $0.00175 on higher Apify plans | Once per company whose candidate channel URL passed the identity gate. Fires on the validation work, not on a populated subscriber cell. |
85
+ | `follower-count-extracted` | $0.0025 on the Free plan, down to $0.00175 on higher Apify plans | Once per channel where a numeric subscriber count was read off the public page. Does not fire when the owner has hidden the count, which reports not_extractable. |
86
+ | `transcript-extracted` | $0.015 on the Free plan, down to $0.0105 on higher Apify plans | Once per video for which transcript TEXT was actually returned. A video with no caption track does not charge, and neither does a video whose caption track exists but whose content YouTube refused to serve. Never fires when transcripts are turned off. This is deliberately strict: the fetch costs us roughly a cent whether or not it yields text, and the buyer should not carry that. |
87
+
88
+ The [actor's Apify page](https://apify.com/mambalabs/youtube-channel-transcript-extractor) carries the current prices. Running this server consumes Apify credits.
89
+
75
90
  ## Full actor documentation
76
91
 
77
92
  [apify.com/mambalabs/youtube-channel-transcript-extractor](https://apify.com/mambalabs/youtube-channel-transcript-extractor)
package/build/index.js CHANGED
@@ -5,6 +5,13 @@ import { dirname, join } from "node:path";
5
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
  import { z } from "zod";
8
+ // Optional per call spending cap, passed through to the actor's own max_charge_usd
9
+ // input. The actor enforces it; this wrapper only forwards it when set.
10
+ const MAX_CHARGE_USD = z
11
+ .number()
12
+ .min(0)
13
+ .optional()
14
+ .describe("Optional spending cap for this call, in USD, passed to the actor as max_charge_usd. The run stops before any charge that would take it past this amount and keeps every row already charged. Leave empty to rely only on the maximum charge per run set on your Apify account.");
8
15
  const here = dirname(fileURLToPath(import.meta.url));
9
16
  const pkg = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8"));
10
17
  // Distinctive UA so Apify run meta.userAgent marks MCP-originated runs.
@@ -57,7 +64,9 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
57
64
  //
58
65
  // The wrapper never reinterprets a row's status field: not_extractable,
59
66
  // blocked and not_found are different answers and are passed through unchanged.
60
- async function runActor(actorPath, actorLabel, input) {
67
+ async function runActor(actorPath, actorLabel, input, maxChargeUsd) {
68
+ if (maxChargeUsd !== undefined)
69
+ input = { ...input, max_charge_usd: maxChargeUsd };
61
70
  const APIFY_TOKEN = process.env.APIFY_TOKEN;
62
71
  if (!APIFY_TOKEN) {
63
72
  return { isError: true, content: [{ type: "text", text: "APIFY_TOKEN is not set. Create a token at https://console.apify.com/account/integrations and set it as the APIFY_TOKEN environment variable." }] };
@@ -187,7 +196,7 @@ server.registerTool("get_youtube_channel_stats", {
187
196
  description: "Resolve a company domain, or a YouTube handle, to that company's YouTube channel. Returns the subscriber count, the stable UC channel id, channel name, creation date and description, as one flat Clay ready row. Subscriber counts are rounded by YouTube above roughly a thousand subscribers, on the page and in its official API alike, and the row flags that. Optional transcript pulling is available and is CURRENTLY GATED by YouTube: the caption track list is readable and the caption content endpoint returns an empty body without a proof of origin token, which the row reports as not_extractable rather than as a video having no captions. A company with no channel reports youtube_status not_found. Read youtube_status before any count. Use it to look up one known company channel per call; it does not search YouTube, list a channel's videos, or return video detail, and the package name mentions transcripts only because transcript pulling is an option. No API key needed. Read only; requires an APIFY_TOKEN and consumes Apify credits per call.",
188
197
  annotations: {
189
198
  title: "Get YouTube Channel Stats",
190
- readOnlyHint: true,
199
+ readOnlyHint: false,
191
200
  destructiveHint: false,
192
201
  idempotentHint: true,
193
202
  openWorldHint: true,
@@ -214,8 +223,9 @@ server.registerTool("get_youtube_channel_stats", {
214
223
  transcriptVideoCount: z.string()
215
224
  .optional()
216
225
  .describe("How many of the channel's most recent videos to pull transcripts for, when transcripts are on. Default 5. Each video is one extra fetch and one extra billable transcript event, so this is the dial that sets the cost of a transcript run."),
226
+ max_charge_usd: MAX_CHARGE_USD,
217
227
  },
218
- }, async ({ company_domain, company_name, handle, includeFollowerCounts, skipCache, includeTranscripts, transcriptVideoCount }) => {
228
+ }, async ({ company_domain, company_name, handle, includeFollowerCounts, skipCache, includeTranscripts, transcriptVideoCount, max_charge_usd }) => {
219
229
  return runActor("6hSpD3kd2s2IQ4VSs", "YouTube Channel Stats Extractor", compact({
220
230
  company_domain,
221
231
  company_name,
@@ -224,7 +234,7 @@ server.registerTool("get_youtube_channel_stats", {
224
234
  skipCache: boolToString(skipCache),
225
235
  includeTranscripts: boolToString(includeTranscripts),
226
236
  transcriptVideoCount,
227
- }));
237
+ }), max_charge_usd);
228
238
  });
229
239
  const transport = new StdioServerTransport();
230
240
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mambalabsdev/mcp-youtube-channel-transcript-extractor",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for the Mamba Labs YouTube Channel Stats Extractor actor on Apify. Resolve a company domain or YouTube handle to the channel with subscriber count and channel metadata.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,7 +39,7 @@
39
39
  "node": ">=18"
40
40
  },
41
41
  "dependencies": {
42
- "@modelcontextprotocol/sdk": "^1.12.0",
42
+ "@modelcontextprotocol/sdk": "^1.32.0",
43
43
  "zod": "^4.5.4"
44
44
  },
45
45
  "devDependencies": {