mcp-server-autoshorts 2.1.0 → 2.3.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 +87 -16
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +1 -0
- package/dist/catalog.js.map +1 -1
- package/dist/client.d.ts +2 -97
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -150
- package/dist/client.js.map +1 -1
- package/dist/constants.d.ts +8 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +8 -3
- package/dist/constants.js.map +1 -1
- package/dist/index.js +15 -16
- package/dist/index.js.map +1 -1
- package/dist/prompts/generate-video.d.ts.map +1 -1
- package/dist/prompts/generate-video.js +8 -2
- package/dist/prompts/generate-video.js.map +1 -1
- package/dist/proxy.d.ts +75 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +162 -0
- package/dist/proxy.js.map +1 -0
- package/package.json +4 -2
- package/dist/prompts/clone-viral.d.ts +0 -6
- package/dist/prompts/clone-viral.d.ts.map +0 -1
- package/dist/prompts/clone-viral.js +0 -33
- package/dist/prompts/clone-viral.js.map +0 -1
- package/dist/tool-helpers.d.ts +0 -21
- package/dist/tool-helpers.d.ts.map +0 -1
- package/dist/tool-helpers.js +0 -27
- package/dist/tool-helpers.js.map +0 -1
- package/dist/tools/billing.d.ts +0 -7
- package/dist/tools/billing.d.ts.map +0 -1
- package/dist/tools/billing.js +0 -8
- package/dist/tools/billing.js.map +0 -1
- package/dist/tools/credits.d.ts +0 -7
- package/dist/tools/credits.d.ts.map +0 -1
- package/dist/tools/credits.js +0 -8
- package/dist/tools/credits.js.map +0 -1
- package/dist/tools/keys.d.ts +0 -8
- package/dist/tools/keys.d.ts.map +0 -1
- package/dist/tools/keys.js +0 -9
- package/dist/tools/keys.js.map +0 -1
- package/dist/tools/niches.d.ts +0 -7
- package/dist/tools/niches.d.ts.map +0 -1
- package/dist/tools/niches.js +0 -8
- package/dist/tools/niches.js.map +0 -1
- package/dist/tools/usage.d.ts +0 -7
- package/dist/tools/usage.d.ts.map +0 -1
- package/dist/tools/usage.js +0 -8
- package/dist/tools/usage.js.map +0 -1
- package/dist/tools/videos.d.ts +0 -7
- package/dist/tools/videos.d.ts.map +0 -1
- package/dist/tools/videos.js +0 -75
- package/dist/tools/videos.js.map +0 -1
package/README.md
CHANGED
|
@@ -49,22 +49,94 @@ export AUTOSHORT_API_KEY=sk_live_your_key_here
|
|
|
49
49
|
npx mcp-server-autoshorts
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
## Recommended flow: Director mode
|
|
53
|
+
|
|
54
|
+
When the user cares about the script or the shots, agree the video with them in the chat first,
|
|
55
|
+
then let AutoShort render exactly that:
|
|
56
|
+
|
|
57
|
+
1. Write the script with the user — narration per scene, and what each scene should show.
|
|
58
|
+
2. `autoshort_draft_video` with `scenes: [{ narration, visual?, seconds? }]` — **free**, nothing is
|
|
59
|
+
rendered or charged. Narration is stored and read **verbatim**; `visual` becomes that scene's
|
|
60
|
+
image prompt as written (plus the art style).
|
|
61
|
+
3. Show the user the draft: scenes, `estimatedDurationSeconds`, `estimatedCredits`, `warnings[]`
|
|
62
|
+
(for example: the words take ~22s to read but 30s was requested — the duration is never
|
|
63
|
+
silently changed). Apply their changes with `autoshort_update_draft`.
|
|
64
|
+
4. Only after the user approves: `autoshort_render_draft`. Credits are charged at this moment,
|
|
65
|
+
before any rendering work, and refunded automatically if the render fails for good. A
|
|
66
|
+
repeated call charges nothing.
|
|
67
|
+
5. Poll `autoshort_get_video` every 20-30 seconds until `COMPLETED`.
|
|
68
|
+
6. To change a scene of the finished video: `autoshort_revise_scene` creates a NEW draft with the
|
|
69
|
+
change (the original is untouched); render it as a new video.
|
|
70
|
+
|
|
71
|
+
No script yet? `autoshort_draft_video` with a `brief` writes a draft for review (needs a positive
|
|
72
|
+
credit balance; at most 20 per hour).
|
|
73
|
+
|
|
74
|
+
## The whole workflow, no website
|
|
75
|
+
|
|
76
|
+
An agent can run everything through MCP. A person does only three one-time steps:
|
|
77
|
+
|
|
78
|
+
1. **Authorize the connector** (OAuth "Allow" in Claude/ChatGPT) or create an API key.
|
|
79
|
+
2. **Platform consent once per platform**: `autoshort_get_connection_status` returns a short,
|
|
80
|
+
single-use `connectUrl` that opens YouTube/TikTok consent directly; the agent polls the same
|
|
81
|
+
tool until `connected: true` and carries on.
|
|
82
|
+
3. **A payment method once**: pay one checkout link from `autoshort_get_buy_credits_url`, or
|
|
83
|
+
approve auto-recharge (`autoshort_setup_auto_recharge`: a pack and a monthly cap, then a card
|
|
84
|
+
saved on Whop) so later top-ups run through `autoshort_buy_credits` with no link.
|
|
85
|
+
|
|
86
|
+
Every error carries a machine-readable `code` and a `nextAction` (the tool to call next, or the
|
|
87
|
+
`connectUrl` / `checkoutUrl` for the human). Anything still running returns `pollAfterSeconds`;
|
|
88
|
+
webhooks are available instead of polling. Every paid tool takes `idempotencyKey`. Each API key /
|
|
89
|
+
connector has a daily credit cap (default 500) on everything it commits through MCP (and through
|
|
90
|
+
`POST /api/v1/videos/generate`), which an unattended agent cannot pass
|
|
91
|
+
(`autoshort_get_limits`; raising it needs the signed-in owner).
|
|
92
|
+
|
|
52
93
|
## Available Tools
|
|
53
94
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
|
58
|
-
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`
|
|
67
|
-
`
|
|
95
|
+
The tool list comes from the AutoShort server itself (`https://autoshort.org/api/mcp`), so this
|
|
96
|
+
package and the remote connector (claude.ai custom connector) always expose the same tools.
|
|
97
|
+
|
|
98
|
+
| Tool | Description | Cost |
|
|
99
|
+
|------|-------------|------|
|
|
100
|
+
| `autoshort_get_capabilities` | The end-to-end workflow, the human steps, limits | free |
|
|
101
|
+
| `autoshort_list_options` | Voices (premium + price), art styles, caption themes, ratios, durations per tool, motion prices | free |
|
|
102
|
+
| `autoshort_estimate_cost` | Price any paid call before making it | free |
|
|
103
|
+
| `autoshort_draft_video` | Create a draft from agreed `scenes[]` (or a `brief`) | free (brief: needs credits) |
|
|
104
|
+
| `autoshort_get_draft` | Read a draft with estimates and warnings | free |
|
|
105
|
+
| `autoshort_update_draft` | Edit / insert / remove / reorder scenes | free |
|
|
106
|
+
| `autoshort_render_draft` | Render an approved draft | charged here |
|
|
107
|
+
| `autoshort_revise_scene` | Change a scene of a finished video → new draft | free (render is charged) |
|
|
108
|
+
| `autoshort_generate_video` | One-shot video from a topic (AutoShort writes the script) | charged at render |
|
|
109
|
+
| `autoshort_generate_chat_video` | One-shot video from a creative brief | charged at render |
|
|
110
|
+
| `autoshort_generate_product_ad` | Product ad from a public product URL | charged at render |
|
|
111
|
+
| `autoshort_generate_image_to_video` | Animate one image (`imagePath` is read locally) | charged at submit |
|
|
112
|
+
| `autoshort_ugc_upload_recording` | App screen recording by `recordingUrl` / `recordingBase64` (`recordingPath` read locally) → `recordingAssetId` | free |
|
|
113
|
+
| `autoshort_ugc_create_campaign` … `autoshort_ugc_get_campaign` | Silent UGC: campaign, hooks, preview, batch render | see tool |
|
|
114
|
+
| `autoshort_get_video` | Video status and details | free |
|
|
115
|
+
| `autoshort_list_videos` | Your videos with pagination | free |
|
|
116
|
+
| `autoshort_cancel_video` | Cancel before rendering starts; refunded through the ledger | free |
|
|
117
|
+
| `autoshort_list_niches` | Niches, art styles, qualities | free |
|
|
118
|
+
| `autoshort_list_social_accounts` | Connected YouTube/TikTok accounts and today's limits (no tokens) | free |
|
|
119
|
+
| `autoshort_get_connection_status` | Connected? If not, a one-click `connectUrl`; poll until connected | free |
|
|
120
|
+
| `autoshort_publish_video` | YouTube upload or TikTok Drafts; idempotent per video + platform; AI disclosure set | free |
|
|
121
|
+
| `autoshort_list_series` / `autoshort_create_series` / `autoshort_update_series` | Autopilot series | free (each video is charged by the scheduler) |
|
|
122
|
+
| `autoshort_pause_series` / `autoshort_resume_series` | Stop / restart a series | free |
|
|
123
|
+
| `autoshort_create_webhook` / `autoshort_list_webhooks` / `autoshort_delete_webhook` | Signed `video.completed` / `video.failed` POSTs | free |
|
|
124
|
+
| `autoshort_get_credit_balance` | Credit balance and plan | free |
|
|
125
|
+
| `autoshort_get_usage_stats` | API usage statistics | free |
|
|
126
|
+
| `autoshort_get_subscription` | Subscription plan status | free |
|
|
127
|
+
| `autoshort_get_limits` / `autoshort_set_limits` | Daily agent spending cap, auto-recharge, platform caps | free |
|
|
128
|
+
| `autoshort_get_buy_credits_url` | Checkout link for a pack or plan (no email in the URL) | free |
|
|
129
|
+
| `autoshort_setup_auto_recharge` / `autoshort_buy_credits` / `autoshort_disable_auto_recharge` | Opt-in top-ups within an owner-approved monthly cap | the pack price |
|
|
130
|
+
|
|
131
|
+
Every call is authenticated with your API key, and a paid call is refused with 402 before any
|
|
132
|
+
work starts when the balance is short.
|
|
133
|
+
|
|
134
|
+
Webhooks: register once with `autoshort_create_webhook` (public https only); each POST is signed
|
|
135
|
+
with `X-Webhook-Signature` = hex HMAC-SHA256 of the raw body with the secret returned at creation.
|
|
136
|
+
Or poll `autoshort_get_video`; a PENDING video that cannot render returns `blockedReason` (for
|
|
137
|
+
example `INSUFFICIENT_CREDITS`) instead of a countdown.
|
|
138
|
+
|
|
139
|
+
API keys are managed in the dashboard (Developers → API keys); there is no tool for listing them.
|
|
68
140
|
|
|
69
141
|
New API keys include `credits:read` and `usage:read`. A key created earlier without them gets a
|
|
70
142
|
403 from `autoshort_get_credit_balance` whose message links to the page where you create a key
|
|
@@ -81,8 +153,7 @@ with that scope.
|
|
|
81
153
|
|
|
82
154
|
| Name | Description |
|
|
83
155
|
|------|-------------|
|
|
84
|
-
| `generate_video` | Step-by-step
|
|
85
|
-
| `clone_viral_video` | Clone a viral video concept |
|
|
156
|
+
| `generate_video` | Step-by-step guide: make, approve, publish |
|
|
86
157
|
|
|
87
158
|
## Get Your API Key
|
|
88
159
|
|
package/dist/catalog.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* en/vi only (the API speaks nine) and "40-150 credits" (an API video costs 65).
|
|
10
10
|
*/
|
|
11
11
|
/** Prisma VideoStatus, in schema order. */
|
|
12
|
-
export declare const VIDEO_STATUSES: readonly ["PENDING", "GENERATING_SCRIPT", "GENERATING_VOICE", "FETCHING_MEDIA", "RENDERING", "COMPLETED", "FAILED"];
|
|
12
|
+
export declare const VIDEO_STATUSES: readonly ["PENDING", "GENERATING_SCRIPT", "GENERATING_VOICE", "FETCHING_MEDIA", "RENDERING", "COMPLETED", "FAILED", "DRAFT"];
|
|
13
13
|
/** MOTION_LANGUAGE_CODES: what POST /api/videos/chat honours as an explicit language. */
|
|
14
14
|
export declare const CHAT_VIDEO_LANGUAGES: readonly ["en", "es", "pt", "fr", "de", "it", "id", "tr", "vi"];
|
|
15
15
|
/** CHAT_MESSAGE_MAX_CHARS. */
|
package/dist/catalog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,2CAA2C;AAC3C,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,2CAA2C;AAC3C,eAAO,MAAM,cAAc,8HASjB,CAAC;AAEX,yFAAyF;AACzF,eAAO,MAAM,oBAAoB,iEAAkE,CAAC;AAEpG,8BAA8B;AAC9B,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C,2BAA2B;AAC3B,eAAO,MAAM,eAAe,qCAAsC,CAAC;AAEnE,yEAAyE;AACzE,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,QAA4D,CAAC;AAE3F,eAAO,MAAM,mBAAmB,QAE2D,CAAC;AAE5F,eAAO,MAAM,SAAS,QAEmE,CAAC;AAE1F;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,QAI8D,CAAC;AAEpG;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,QAIe,CAAC;AAElD;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,QAMsB,CAAC"}
|
package/dist/catalog.js
CHANGED
|
@@ -17,6 +17,7 @@ export const VIDEO_STATUSES = [
|
|
|
17
17
|
'RENDERING',
|
|
18
18
|
'COMPLETED',
|
|
19
19
|
'FAILED',
|
|
20
|
+
'DRAFT',
|
|
20
21
|
];
|
|
21
22
|
/** MOTION_LANGUAGE_CODES: what POST /api/videos/chat honours as an explicit language. */
|
|
22
23
|
export const CHAT_VIDEO_LANGUAGES = ['en', 'es', 'pt', 'fr', 'de', 'it', 'id', 'tr', 'vi'];
|
package/dist/catalog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,2CAA2C;AAC3C,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,SAAS;IACT,mBAAmB;IACnB,kBAAkB;IAClB,gBAAgB;IAChB,WAAW;IACX,WAAW;IACX,QAAQ;
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,2CAA2C;AAC3C,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,SAAS;IACT,mBAAmB;IACnB,kBAAkB;IAClB,gBAAgB;IAChB,WAAW;IACX,WAAW;IACX,QAAQ;IACR,OAAO;CACC,CAAC;AAEX,yFAAyF;AACzF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;AAEpG,8BAA8B;AAC9B,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAE3C,2BAA2B;AAC3B,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,cAAc,CAAU,CAAC;AAEnE,yEAAyE;AACzE,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,aAAa,EAAE,EAAE;IACjB,eAAe,EAAE,EAAE;CACX,CAAC;AAEX,uFAAuF;AACvF,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC,aAAa,GAAG,YAAY,CAAC,eAAe,CAAC;AAE3F,MAAM,CAAC,MAAM,mBAAmB,GAC9B,SAAS,iBAAiB,aAAa,YAAY,CAAC,aAAa,YAAY;IAC7E,GAAG,YAAY,CAAC,eAAe,0DAA0D,CAAC;AAE5F,MAAM,CAAC,MAAM,SAAS,GACpB,+GAA+G;IAC/G,uFAAuF,CAAC;AAE1F;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,wBAAwB,GACnC,SAAS,sBAAsB,2DAA2D;IAC1F,4FAA4F;IAC5F,8FAA8F;IAC9F,iGAAiG,CAAC;AAEpG;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAChC,4FAA4F;IAC5F,2FAA2F;IAC3F,0FAA0F;IAC1F,+CAA+C,CAAC;AAElD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAC1C,oFAAoF;IACpF,4FAA4F;IAC5F,wFAAwF;IACxF,6FAA6F;IAC7F,uFAAuF;IACvF,gEAAgE,CAAC"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AutoShort API HTTP
|
|
3
|
-
*
|
|
4
|
-
* Wraps all v1 API endpoints with typed methods.
|
|
5
|
-
* Captures rate limit headers for MCP resource exposure.
|
|
2
|
+
* AutoShort API HTTP client, for the package's own resources (credit balance, rate limit).
|
|
3
|
+
* Tools do not use it: they are proxied to the remote /api/mcp registry (see proxy.ts).
|
|
6
4
|
*/
|
|
7
5
|
import type { RateLimitInfo } from './types.js';
|
|
8
6
|
export declare class AutoShortClient {
|
|
@@ -13,65 +11,12 @@ export declare class AutoShortClient {
|
|
|
13
11
|
constructor(apiKey: string, baseUrl: string);
|
|
14
12
|
/** Generic API request with auth, error handling, rate limit capture */
|
|
15
13
|
request<T>(method: string, path: string, body?: unknown): Promise<T>;
|
|
16
|
-
generateVideo(params: {
|
|
17
|
-
topic: string;
|
|
18
|
-
niche?: string;
|
|
19
|
-
duration?: number;
|
|
20
|
-
artStyle?: string;
|
|
21
|
-
quality?: string;
|
|
22
|
-
}): Promise<{
|
|
23
|
-
id: string;
|
|
24
|
-
status: string;
|
|
25
|
-
}>;
|
|
26
|
-
generateChatVideo(params: {
|
|
27
|
-
message: string;
|
|
28
|
-
videoProvider?: 'FFMPEG' | 'VEO_3_1_OPERATOR';
|
|
29
|
-
artStyle?: string;
|
|
30
|
-
aspectRatio?: '9:16' | '1:1' | '16:9';
|
|
31
|
-
language?: string;
|
|
32
|
-
targetDuration?: number;
|
|
33
|
-
}): Promise<{
|
|
34
|
-
videoId: string;
|
|
35
|
-
reply: string;
|
|
36
|
-
params: Record<string, unknown>;
|
|
37
|
-
}>;
|
|
38
|
-
generateProductAd(params: {
|
|
39
|
-
url: string;
|
|
40
|
-
language?: string;
|
|
41
|
-
artStyle?: string;
|
|
42
|
-
duration?: number;
|
|
43
|
-
}): Promise<Record<string, unknown>>;
|
|
44
|
-
generateImageToVideo(params: {
|
|
45
|
-
imagePath: string;
|
|
46
|
-
motionPrompt: string;
|
|
47
|
-
idempotencyKey?: string;
|
|
48
|
-
}): Promise<Record<string, unknown>>;
|
|
49
|
-
getVideo(id: string): Promise<Record<string, unknown>>;
|
|
50
|
-
listVideos(params?: {
|
|
51
|
-
limit?: number;
|
|
52
|
-
offset?: number;
|
|
53
|
-
status?: string;
|
|
54
|
-
}): Promise<{
|
|
55
|
-
videos: unknown[];
|
|
56
|
-
pagination: unknown;
|
|
57
|
-
}>;
|
|
58
|
-
listNiches(): Promise<{
|
|
59
|
-
niches: unknown[];
|
|
60
|
-
artStyles: unknown[];
|
|
61
|
-
videoQualities: unknown[];
|
|
62
|
-
durations: number[];
|
|
63
|
-
}>;
|
|
64
14
|
getCreditBalance(): Promise<{
|
|
65
15
|
balance: number;
|
|
66
16
|
monthlyAllocation: number;
|
|
67
17
|
bonusCredits: number;
|
|
68
18
|
plan: string;
|
|
69
19
|
}>;
|
|
70
|
-
getUsageStats(): Promise<Record<string, unknown>>;
|
|
71
|
-
getSubscription(): Promise<Record<string, unknown>>;
|
|
72
|
-
listApiKeys(): Promise<{
|
|
73
|
-
apiKeys: unknown[];
|
|
74
|
-
}>;
|
|
75
20
|
}
|
|
76
21
|
/** Typed API error with HTTP status and error code */
|
|
77
22
|
export declare class AutoShortApiError extends Error {
|
|
@@ -79,44 +24,4 @@ export declare class AutoShortApiError extends Error {
|
|
|
79
24
|
readonly code: string;
|
|
80
25
|
constructor(message: string, status: number, code: string);
|
|
81
26
|
}
|
|
82
|
-
/**
|
|
83
|
-
* MIME from the file's own first bytes, with the extension only as a tiebreaker.
|
|
84
|
-
*
|
|
85
|
-
* It used to be derived from the extension alone, so an extensionless file, a `.jfif` or a
|
|
86
|
-
* `.gif` was declared `image/jpeg` and failed the server's magic-byte check with the unhelpful
|
|
87
|
-
* "Image contents do not match the uploaded file type" / "Invalid image data". Sniffing means a
|
|
88
|
-
* correct file is labelled correctly whatever it is called, and a genuinely unsupported format
|
|
89
|
-
* keeps its real type so the server's 400 names the actual problem.
|
|
90
|
-
*/
|
|
91
|
-
export declare function sniffImageMime(bytes: Uint8Array, imagePath: string): string;
|
|
92
|
-
/**
|
|
93
|
-
* Shape a deterministic hash into something the route's STRICT v4 regex accepts.
|
|
94
|
-
*
|
|
95
|
-
* `requestId` is validated against
|
|
96
|
-
* /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, so a bare sha256
|
|
97
|
-
* is refused with 400 "A valid request ID is required". Version nibble pinned to 4 and the
|
|
98
|
-
* variant nibble forced into 8..b; every other nibble comes from the hash.
|
|
99
|
-
*/
|
|
100
|
-
export declare function uuidFromSeed(seed: string): string;
|
|
101
|
-
/**
|
|
102
|
-
* The request id for one image-to-video submission: deterministic, and ALWAYS content-bound.
|
|
103
|
-
*
|
|
104
|
-
* Two rules, each closing a way of being charged 35 credits twice.
|
|
105
|
-
*
|
|
106
|
-
* 1. NO CLOCK IN THE SEED. It used to be `randomUUID()` per call, which defeats all three of
|
|
107
|
-
* the endpoint's dedupe layers (pre-check, pg_advisory_xact_lock, in-transaction re-check)
|
|
108
|
-
* and buys a second clip on every retry. A later attempt salted the seed with a UTC day
|
|
109
|
-
* bucket, which is worse than it looks: a bucket has an edge, so a retry at 23:59:59 and
|
|
110
|
-
* its follow-up at 00:00:01 derive DIFFERENT ids and miss every layer. The time bound
|
|
111
|
-
* belongs on the READER, as a continuous window — see imageToVideoDedupeSince() in
|
|
112
|
-
* src/lib/image-to-video-policy.ts.
|
|
113
|
-
*
|
|
114
|
-
* 2. THE CONTENT IS ALWAYS IN THE SEED, even when the caller supplies a key. A caller key used
|
|
115
|
-
* to replace the content seed outright, so an agent passing one run-scoped key for two
|
|
116
|
-
* different clips got the FIRST video back for the second ask — `duplicate: true`, no
|
|
117
|
-
* fingerprint compared, so not even a 422 to tell it apart. Folding both in keeps each
|
|
118
|
-
* direction working: a distinct key separates two deliberate clips from identical inputs,
|
|
119
|
-
* and distinct inputs separate two clips that happen to share a key.
|
|
120
|
-
*/
|
|
121
|
-
export declare function imageToVideoRequestId(imageBytes: Uint8Array, motionPrompt: string, idempotencyKey?: string): string;
|
|
122
27
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qBAAa,eAAe;IAKxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL1B,qDAAqD;IAC9C,aAAa,EAAE,aAAa,GAAG,IAAI,CAAQ;gBAG/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;IAGlC,wEAAwE;IAClE,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAqCpE,gBAAgB;iBACW,MAAM;2BAAqB,MAAM;sBAAgB,MAAM;cAAQ,MAAM;;CAKvG;AAED,sDAAsD;AACtD,qBAAa,iBAAkB,SAAQ,KAAK;aAGxB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;gBAF5B,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM;CAK/B"}
|
package/dist/client.js
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AutoShort API HTTP
|
|
3
|
-
*
|
|
4
|
-
* Wraps all v1 API endpoints with typed methods.
|
|
5
|
-
* Captures rate limit headers for MCP resource exposure.
|
|
2
|
+
* AutoShort API HTTP client, for the package's own resources (credit balance, rate limit).
|
|
3
|
+
* Tools do not use it: they are proxied to the remote /api/mcp registry (see proxy.ts).
|
|
6
4
|
*/
|
|
7
5
|
import { USER_AGENT } from './constants.js';
|
|
8
|
-
import { readFile } from 'node:fs/promises';
|
|
9
|
-
import { basename, extname } from 'node:path';
|
|
10
|
-
import { createHash } from 'node:crypto';
|
|
11
6
|
export class AutoShortClient {
|
|
12
7
|
apiKey;
|
|
13
8
|
baseUrl;
|
|
@@ -52,69 +47,10 @@ export class AutoShortClient {
|
|
|
52
47
|
}
|
|
53
48
|
return res.json();
|
|
54
49
|
}
|
|
55
|
-
// ── Video endpoints ──
|
|
56
|
-
async generateVideo(params) {
|
|
57
|
-
return this.request('POST', '/api/v1/videos/generate', params);
|
|
58
|
-
}
|
|
59
|
-
async generateChatVideo(params) {
|
|
60
|
-
return this.request('POST', '/api/videos/chat', params);
|
|
61
|
-
}
|
|
62
|
-
async generateProductAd(params) {
|
|
63
|
-
return this.request('POST', '/api/videos/product-ad', params);
|
|
64
|
-
}
|
|
65
|
-
async generateImageToVideo(params) {
|
|
66
|
-
const bytes = await readFile(params.imagePath);
|
|
67
|
-
const form = new FormData();
|
|
68
|
-
form.set('image', new Blob([bytes], { type: sniffImageMime(bytes, params.imagePath) }), basename(params.imagePath));
|
|
69
|
-
form.set('motionPrompt', params.motionPrompt);
|
|
70
|
-
// NO `provider` field, deliberately.
|
|
71
|
-
//
|
|
72
|
-
// The route reads `String(form.get("provider") || IMAGE_TO_VIDEO_POLICY.provider)`, so an
|
|
73
|
-
// absent field already resolves to the one token it accepts. We used to send
|
|
74
|
-
// 'VEO_3_1_OPERATOR' — the endpoint's internal RENDER provider, not its submission token —
|
|
75
|
-
// and so EVERY call came back 400 "Image to Video uses its own flow only; direct Veo API is
|
|
76
|
-
// disabled" (reproduced against production 2026-10-16). Hardcoding the correct literal here
|
|
77
|
-
// would fix today's call and re-couple this standalone package to a server constant it
|
|
78
|
-
// cannot import; omitting the field lets the server own its own default.
|
|
79
|
-
form.set('requestId', imageToVideoRequestId(bytes, params.motionPrompt, params.idempotencyKey));
|
|
80
|
-
const res = await fetch(`${this.baseUrl}/api/videos/image-to-video`, {
|
|
81
|
-
method: 'POST',
|
|
82
|
-
headers: { 'Authorization': `Bearer ${this.apiKey}`, 'User-Agent': USER_AGENT },
|
|
83
|
-
body: form,
|
|
84
|
-
});
|
|
85
|
-
if (!res.ok) {
|
|
86
|
-
const body = await res.json().catch(() => ({}));
|
|
87
|
-
throw new AutoShortApiError(body.error || `API error: ${res.status}`, res.status, `HTTP_${res.status}`);
|
|
88
|
-
}
|
|
89
|
-
return res.json();
|
|
90
|
-
}
|
|
91
|
-
async getVideo(id) {
|
|
92
|
-
return this.request('GET', `/api/v1/videos/${encodeURIComponent(id)}`);
|
|
93
|
-
}
|
|
94
|
-
async listVideos(params) {
|
|
95
|
-
const qs = params ? '?' + new URLSearchParams(Object.entries(params).filter(([, v]) => v != null).map(([k, v]) => [k, String(v)])).toString() : '';
|
|
96
|
-
return this.request('GET', `/api/v1/videos${qs}`);
|
|
97
|
-
}
|
|
98
|
-
// ── Niches ──
|
|
99
|
-
async listNiches() {
|
|
100
|
-
return this.request('GET', '/api/v1/scripts/niches');
|
|
101
|
-
}
|
|
102
50
|
// ── Credits ──
|
|
103
51
|
async getCreditBalance() {
|
|
104
52
|
return this.request('GET', '/api/v1/credits/balance');
|
|
105
53
|
}
|
|
106
|
-
// ── Usage ──
|
|
107
|
-
async getUsageStats() {
|
|
108
|
-
return this.request('GET', '/api/v1/usage/stats');
|
|
109
|
-
}
|
|
110
|
-
// ── Billing ──
|
|
111
|
-
async getSubscription() {
|
|
112
|
-
return this.request('GET', '/api/v1/billing/subscription');
|
|
113
|
-
}
|
|
114
|
-
// ── API Keys ──
|
|
115
|
-
async listApiKeys() {
|
|
116
|
-
return this.request('GET', '/api/v1/keys');
|
|
117
|
-
}
|
|
118
54
|
}
|
|
119
55
|
/** Typed API error with HTTP status and error code */
|
|
120
56
|
export class AutoShortApiError extends Error {
|
|
@@ -127,88 +63,4 @@ export class AutoShortApiError extends Error {
|
|
|
127
63
|
this.name = 'AutoShortApiError';
|
|
128
64
|
}
|
|
129
65
|
}
|
|
130
|
-
/**
|
|
131
|
-
* MIME from the file's own first bytes, with the extension only as a tiebreaker.
|
|
132
|
-
*
|
|
133
|
-
* It used to be derived from the extension alone, so an extensionless file, a `.jfif` or a
|
|
134
|
-
* `.gif` was declared `image/jpeg` and failed the server's magic-byte check with the unhelpful
|
|
135
|
-
* "Image contents do not match the uploaded file type" / "Invalid image data". Sniffing means a
|
|
136
|
-
* correct file is labelled correctly whatever it is called, and a genuinely unsupported format
|
|
137
|
-
* keeps its real type so the server's 400 names the actual problem.
|
|
138
|
-
*/
|
|
139
|
-
export function sniffImageMime(bytes, imagePath) {
|
|
140
|
-
const b = bytes;
|
|
141
|
-
if (b.length >= 3 && b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff)
|
|
142
|
-
return 'image/jpeg';
|
|
143
|
-
if (b.length >= 8 &&
|
|
144
|
-
b[0] === 0x89 && b[1] === 0x50 && b[2] === 0x4e && b[3] === 0x47 &&
|
|
145
|
-
b[4] === 0x0d && b[5] === 0x0a && b[6] === 0x1a && b[7] === 0x0a)
|
|
146
|
-
return 'image/png';
|
|
147
|
-
if (b.length >= 12 &&
|
|
148
|
-
String.fromCharCode(b[0], b[1], b[2], b[3]) === 'RIFF' &&
|
|
149
|
-
String.fromCharCode(b[8], b[9], b[10], b[11]) === 'WEBP')
|
|
150
|
-
return 'image/webp';
|
|
151
|
-
if (b.length >= 6 && String.fromCharCode(b[0], b[1], b[2]) === 'GIF')
|
|
152
|
-
return 'image/gif';
|
|
153
|
-
// Unrecognised: fall back to the extension so the server's refusal names a real type rather
|
|
154
|
-
// than one we invented.
|
|
155
|
-
const extension = extname(imagePath).toLowerCase();
|
|
156
|
-
if (extension === '.png')
|
|
157
|
-
return 'image/png';
|
|
158
|
-
if (extension === '.webp')
|
|
159
|
-
return 'image/webp';
|
|
160
|
-
if (extension === '.gif')
|
|
161
|
-
return 'image/gif';
|
|
162
|
-
return 'application/octet-stream';
|
|
163
|
-
}
|
|
164
|
-
const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
165
|
-
/**
|
|
166
|
-
* Shape a deterministic hash into something the route's STRICT v4 regex accepts.
|
|
167
|
-
*
|
|
168
|
-
* `requestId` is validated against
|
|
169
|
-
* /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, so a bare sha256
|
|
170
|
-
* is refused with 400 "A valid request ID is required". Version nibble pinned to 4 and the
|
|
171
|
-
* variant nibble forced into 8..b; every other nibble comes from the hash.
|
|
172
|
-
*/
|
|
173
|
-
export function uuidFromSeed(seed) {
|
|
174
|
-
const h = createHash('sha256').update(seed).digest('hex');
|
|
175
|
-
const variant = ((parseInt(h[16], 16) & 0x3) | 0x8).toString(16);
|
|
176
|
-
const id = `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-${variant}${h.slice(17, 20)}-${h.slice(20, 32)}`;
|
|
177
|
-
/* c8 ignore next */
|
|
178
|
-
if (!UUID_V4.test(id))
|
|
179
|
-
throw new Error(`derived request id is not a v4 UUID: ${id}`);
|
|
180
|
-
return id;
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* The request id for one image-to-video submission: deterministic, and ALWAYS content-bound.
|
|
184
|
-
*
|
|
185
|
-
* Two rules, each closing a way of being charged 35 credits twice.
|
|
186
|
-
*
|
|
187
|
-
* 1. NO CLOCK IN THE SEED. It used to be `randomUUID()` per call, which defeats all three of
|
|
188
|
-
* the endpoint's dedupe layers (pre-check, pg_advisory_xact_lock, in-transaction re-check)
|
|
189
|
-
* and buys a second clip on every retry. A later attempt salted the seed with a UTC day
|
|
190
|
-
* bucket, which is worse than it looks: a bucket has an edge, so a retry at 23:59:59 and
|
|
191
|
-
* its follow-up at 00:00:01 derive DIFFERENT ids and miss every layer. The time bound
|
|
192
|
-
* belongs on the READER, as a continuous window — see imageToVideoDedupeSince() in
|
|
193
|
-
* src/lib/image-to-video-policy.ts.
|
|
194
|
-
*
|
|
195
|
-
* 2. THE CONTENT IS ALWAYS IN THE SEED, even when the caller supplies a key. A caller key used
|
|
196
|
-
* to replace the content seed outright, so an agent passing one run-scoped key for two
|
|
197
|
-
* different clips got the FIRST video back for the second ask — `duplicate: true`, no
|
|
198
|
-
* fingerprint compared, so not even a 422 to tell it apart. Folding both in keeps each
|
|
199
|
-
* direction working: a distinct key separates two deliberate clips from identical inputs,
|
|
200
|
-
* and distinct inputs separate two clips that happen to share a key.
|
|
201
|
-
*/
|
|
202
|
-
export function imageToVideoRequestId(imageBytes, motionPrompt, idempotencyKey) {
|
|
203
|
-
// TRIMMED, to match what the server stores and dedupes on.
|
|
204
|
-
//
|
|
205
|
-
// The route does `String(form.get("motionPrompt") || "").trim()`, so it treats "push in" and
|
|
206
|
-
// "push in " as the same prompt. Hashing the raw string here did not: the two derived
|
|
207
|
-
// DIFFERENT requestIds, missed all three server dedupe layers, and bought two 35-credit
|
|
208
|
-
// charges for two identical clips. An agent replaying a retry with whitespace drift is the
|
|
209
|
-
// realistic caller. Any normalization the server applies has to be applied here too, or the
|
|
210
|
-
// derived id stops being a function of what the server actually keys on.
|
|
211
|
-
const content = `${createHash('sha256').update(imageBytes).digest('hex')}:${motionPrompt.trim()}`;
|
|
212
|
-
return uuidFromSeed(idempotencyKey ? `${idempotencyKey}\u0000${content}` : content);
|
|
213
|
-
}
|
|
214
66
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAG5C,MAAM,OAAO,eAAe;IAKP;IACA;IALnB,qDAAqD;IAC9C,aAAa,GAAyB,IAAI,CAAC;IAElD,YACmB,MAAc,EACd,OAAe;QADf,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAQ;IAC/B,CAAC;IAEJ,wEAAwE;IACxE,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,IAAc;QAC3D,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM;YACN,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;gBACxC,cAAc,EAAE,kBAAkB;gBAClC,YAAY,EAAE,UAAU;aACzB;YACD,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAC9C,CAAC,CAAC;QAEH,6BAA6B;QAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACrD,IAAI,KAAK,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;YAClC,IAAI,CAAC,aAAa,GAAG;gBACnB,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC;gBACtB,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC;gBAC9B,OAAO;aACR,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,SAAS,GAAsC,EAAE,CAAC;YACtD,IAAI,CAAC;gBAAC,SAAS,GAAG,MAAM,GAAG,CAAC,IAAI,EAAsB,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC;YAC/E,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,IAAI,cAAc,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;YAC5E,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;YACpD,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACrD,CAAC;QAED,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAC;IAClC,CAAC;IAED,gBAAgB;IAEhB,KAAK,CAAC,gBAAgB;QACpB,OAAO,IAAI,CAAC,OAAO,CACjB,KAAK,EAAE,yBAAyB,CACjC,CAAC;IACJ,CAAC;CAEF;AAED,sDAAsD;AACtD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAGxB;IACA;IAHlB,YACE,OAAe,EACC,MAAc,EACd,IAAY;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QAG5B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/** Default AutoShort API base URL */
|
|
2
2
|
export declare const DEFAULT_BASE_URL = "https://autoshort.org";
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Read from package.json so the version a client sees is the version that was published
|
|
5
|
+
* (it was hardcoded "2.0.0" while package.json said 2.1.0). `../package.json` resolves from
|
|
6
|
+
* both src/ (tests) and dist/ (the published build).
|
|
7
|
+
*/
|
|
8
|
+
export declare const VERSION: string;
|
|
9
|
+
/** User-Agent header for API requests (the server tags videos made through it as MCP). */
|
|
10
|
+
export declare const USER_AGENT: string;
|
|
7
11
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,qCAAqC;AACrC,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,OAAO,EAAE,MAA2F,CAAC;AAElH,0FAA0F;AAC1F,eAAO,MAAM,UAAU,QAAoC,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
1
2
|
/** Default AutoShort API base URL */
|
|
2
3
|
export const DEFAULT_BASE_URL = 'https://autoshort.org';
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Read from package.json so the version a client sees is the version that was published
|
|
6
|
+
* (it was hardcoded "2.0.0" while package.json said 2.1.0). `../package.json` resolves from
|
|
7
|
+
* both src/ (tests) and dist/ (the published build).
|
|
8
|
+
*/
|
|
9
|
+
export const VERSION = createRequire(import.meta.url)('../package.json').version;
|
|
10
|
+
/** User-Agent header for API requests (the server tags videos made through it as MCP). */
|
|
6
11
|
export const USER_AGENT = `autoshort-mcp-server/${VERSION}`;
|
|
7
12
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAExD
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,qCAAqC;AACrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAY,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAC;AAElH,0FAA0F;AAC1F,MAAM,CAAC,MAAM,UAAU,GAAG,wBAAwB,OAAO,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,19 +9,14 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
9
9
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
10
|
import { AutoShortClient } from './client.js';
|
|
11
11
|
import { DEFAULT_BASE_URL, VERSION } from './constants.js';
|
|
12
|
-
// ──
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { registerCreditTools } from './tools/credits.js';
|
|
16
|
-
import { registerUsageTools } from './tools/usage.js';
|
|
17
|
-
import { registerBillingTools } from './tools/billing.js';
|
|
18
|
-
import { registerKeyTools } from './tools/keys.js';
|
|
12
|
+
// ── Tools: proxied to the remote registry (src/app/api/mcp/tools.ts in the app) ──
|
|
13
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
|
14
|
+
import { RemoteToolProxy } from './proxy.js';
|
|
19
15
|
// ── Resources ──
|
|
20
16
|
import { registerCreditResource } from './resources/credits.js';
|
|
21
17
|
import { registerRateLimitResource } from './resources/rate-limit.js';
|
|
22
18
|
// ── Prompts ──
|
|
23
19
|
import { registerGenerateVideoPrompt } from './prompts/generate-video.js';
|
|
24
|
-
import { registerCloneViralPrompt } from './prompts/clone-viral.js';
|
|
25
20
|
// ── CLI arg parsing ──
|
|
26
21
|
function parseArgs(argv) {
|
|
27
22
|
let apiKey = process.env.AUTOSHORT_API_KEY || '';
|
|
@@ -62,19 +57,23 @@ async function main() {
|
|
|
62
57
|
name: 'autoshort-mcp-server',
|
|
63
58
|
version: VERSION,
|
|
64
59
|
});
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
// Tools: the remote server's registry, so stdio and the remote connector list the same set.
|
|
61
|
+
const proxy = new RemoteToolProxy(apiKey, baseUrl);
|
|
62
|
+
server.server.registerCapabilities({ tools: { listChanged: false } });
|
|
63
|
+
server.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
64
|
+
try {
|
|
65
|
+
return { tools: await proxy.listTools() };
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
throw new McpError(ErrorCode.InternalError, `Could not load AutoShort tools: ${e instanceof Error ? e.message : String(e)}`);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
server.server.setRequestHandler(CallToolRequestSchema, async (request) => proxy.callTool(request.params.name, (request.params.arguments ?? {})));
|
|
72
72
|
// Register resources
|
|
73
73
|
registerCreditResource(server, client);
|
|
74
74
|
registerRateLimitResource(server, client);
|
|
75
75
|
// Register prompts
|
|
76
76
|
registerGenerateVideoPrompt(server);
|
|
77
|
-
registerCloneViralPrompt(server);
|
|
78
77
|
// Connect via stdio transport
|
|
79
78
|
const transport = new StdioServerTransport();
|
|
80
79
|
await server.connect(transport);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE3D,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-video.d.ts","sourceRoot":"","sources":["../../src/prompts/generate-video.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"generate-video.d.ts","sourceRoot":"","sources":["../../src/prompts/generate-video.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,QAoC5D"}
|