@captionbolt/mcp 0.3.1 → 0.3.2
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 +6 -5
- package/dist/index.mjs +44 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Pin the reviewed version in your client's STDIO configuration:
|
|
|
13
13
|
"mcpServers": {
|
|
14
14
|
"captionbolt": {
|
|
15
15
|
"command": "npx",
|
|
16
|
-
"args": ["--yes", "@captionbolt/mcp@0.3.
|
|
16
|
+
"args": ["--yes", "@captionbolt/mcp@0.3.2"]
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -23,12 +23,13 @@ Run this once in a desktop terminal using the same pinned package version as
|
|
|
23
23
|
your MCP configuration:
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
|
-
npx --yes @captionbolt/mcp@0.3.
|
|
26
|
+
npx --yes @captionbolt/mcp@0.3.2 login
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
If installed globally, `captionbolt-mcp login` is equivalent.
|
|
30
|
-
The command opens CaptionBolt in your browser (on
|
|
31
|
-
|
|
30
|
+
The command opens CaptionBolt in your default browser (on Windows and WSL through
|
|
31
|
+
PowerShell) and prints the link in case no browser opens. Open that link on the
|
|
32
|
+
same computer: authorization returns to a local address. An existing website
|
|
32
33
|
session can skip password entry, but you still approve MCP access. OAuth tokens
|
|
33
34
|
and the registered client are saved in the macOS Keychain, Windows Credential
|
|
34
35
|
Manager or a Linux Secret Service keyring. On Linux without Secret Service (common
|
|
@@ -41,7 +42,7 @@ If a grant or registered client becomes invalid, run `login` again. The client
|
|
|
41
42
|
discards the invalid local credentials and starts a new browser authorization;
|
|
42
43
|
the callback page confirms success only after the token exchange and account
|
|
43
44
|
check succeed.
|
|
44
|
-
`npx --yes @captionbolt/mcp@0.3.
|
|
45
|
+
`npx --yes @captionbolt/mcp@0.3.2 logout` (or `captionbolt-mcp logout`)
|
|
45
46
|
deletes local authorization. Revoke server access in
|
|
46
47
|
CaptionBolt settings when you want to invalidate the grant.
|
|
47
48
|
`CAPTIONBOLT_API_URL` optionally selects an explicitly trusted HTTPS API origin;
|
package/dist/index.mjs
CHANGED
|
@@ -504,6 +504,17 @@ function fileStore(origin2, path = join(
|
|
|
504
504
|
}
|
|
505
505
|
};
|
|
506
506
|
}
|
|
507
|
+
function keyringStore(entry2, location) {
|
|
508
|
+
return {
|
|
509
|
+
location,
|
|
510
|
+
getPassword() {
|
|
511
|
+
const secret = entry2.getSecret();
|
|
512
|
+
return secret && Buffer.from(secret).toString("utf8");
|
|
513
|
+
},
|
|
514
|
+
setPassword: (value) => entry2.setSecret(Buffer.from(value, "utf8")),
|
|
515
|
+
deletePassword: () => entry2.deletePassword()
|
|
516
|
+
};
|
|
517
|
+
}
|
|
507
518
|
async function entry(origin2) {
|
|
508
519
|
let Entry;
|
|
509
520
|
try {
|
|
@@ -513,11 +524,11 @@ async function entry(origin2) {
|
|
|
513
524
|
if (process.platform === "linux") {
|
|
514
525
|
try {
|
|
515
526
|
if (Entry) {
|
|
516
|
-
return
|
|
527
|
+
return keyringStore(
|
|
517
528
|
new Entry("captionbolt-mcp-oauth", origin2.origin, {
|
|
518
529
|
linux: { store: "secret-service" }
|
|
519
530
|
}),
|
|
520
|
-
|
|
531
|
+
"the Secret Service keyring"
|
|
521
532
|
);
|
|
522
533
|
}
|
|
523
534
|
} catch {
|
|
@@ -530,9 +541,10 @@ async function entry(origin2) {
|
|
|
530
541
|
{ kind: "invalid-response", code: "CREDENTIAL_STORE_UNAVAILABLE" }
|
|
531
542
|
);
|
|
532
543
|
}
|
|
533
|
-
return
|
|
534
|
-
|
|
535
|
-
|
|
544
|
+
return keyringStore(
|
|
545
|
+
new Entry("captionbolt-mcp-oauth", origin2.origin),
|
|
546
|
+
"the system credential store"
|
|
547
|
+
);
|
|
536
548
|
}
|
|
537
549
|
async function credentialLocation(origin2) {
|
|
538
550
|
return (await entry(origin2)).location;
|
|
@@ -753,6 +765,7 @@ async function createLoginCallback() {
|
|
|
753
765
|
},
|
|
754
766
|
close() {
|
|
755
767
|
server.close();
|
|
768
|
+
server.closeAllConnections();
|
|
756
769
|
}
|
|
757
770
|
};
|
|
758
771
|
}
|
|
@@ -797,15 +810,33 @@ function isWsl() {
|
|
|
797
810
|
return false;
|
|
798
811
|
}
|
|
799
812
|
}
|
|
813
|
+
var WSL_POWERSHELL = "/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe";
|
|
814
|
+
function browserCommand(url, platform = process.platform, wsl = platform === "linux" && isWsl()) {
|
|
815
|
+
if (platform === "darwin") {
|
|
816
|
+
return ["open", [url.href]];
|
|
817
|
+
}
|
|
818
|
+
if (platform !== "win32" && !wsl) {
|
|
819
|
+
return ["xdg-open", [url.href]];
|
|
820
|
+
}
|
|
821
|
+
const script = `Start-Process '${url.href.replaceAll("'", "''")}'`;
|
|
822
|
+
return [
|
|
823
|
+
// appendWindowsPath=false removes Windows tools from the WSL PATH.
|
|
824
|
+
wsl && existsSync(WSL_POWERSHELL) ? WSL_POWERSHELL : "powershell.exe",
|
|
825
|
+
[
|
|
826
|
+
"-NoProfile",
|
|
827
|
+
"-NonInteractive",
|
|
828
|
+
"-EncodedCommand",
|
|
829
|
+
Buffer.from(script, "utf16le").toString("base64")
|
|
830
|
+
]
|
|
831
|
+
];
|
|
832
|
+
}
|
|
800
833
|
function openBrowser(url) {
|
|
801
|
-
const command2
|
|
802
|
-
|
|
803
|
-
existsSync("/mnt/c/Windows/explorer.exe") ? "/mnt/c/Windows/explorer.exe" : "explorer.exe",
|
|
804
|
-
url.href
|
|
805
|
-
] : ["xdg-open", url.href];
|
|
806
|
-
const child = spawn(command2[0] ?? "xdg-open", command2.slice(1), {
|
|
834
|
+
const [command2, args] = browserCommand(url);
|
|
835
|
+
const child = spawn(command2, args, {
|
|
807
836
|
stdio: "ignore",
|
|
808
|
-
detached
|
|
837
|
+
// A detached PowerShell on native Windows exits without opening the browser.
|
|
838
|
+
detached: process.platform !== "win32",
|
|
839
|
+
windowsHide: true
|
|
809
840
|
});
|
|
810
841
|
child.on("error", () => {
|
|
811
842
|
});
|
|
@@ -1308,7 +1339,7 @@ var LocalDownloads = class {
|
|
|
1308
1339
|
|
|
1309
1340
|
// src/instructions.ts
|
|
1310
1341
|
var localMcpInstructions = `CaptionBolt adds styled captions to the user's existing videos and keeps the original framing. A typical request is "add captions to <file>".
|
|
1311
|
-
1. Use the exact absolute path of the video the user named. Resolve a relative path or bare file name against your working directory; if that file does not exist, ask for the full path. Never search other folders. Call upload_file right away; it keeps uploading in the background.
|
|
1342
|
+
1. Use the exact absolute path of the video the user named. Resolve a relative path or bare file name against your working directory; if that file does not exist, ask for the full path. On WSL, a Windows path such as C:\\Users\\... is /mnt/c/Users/... Never search other folders. Call upload_file right away; it keeps uploading in the background.
|
|
1312
1343
|
2. While it uploads, ask one question unless the user already chose a style or preset or asked you to decide. Offer the list_styles items marked recommended (numbered, name plus one-line description) and at most the first three list_presets entries (most recently updated). The user can reply with a number, describe a look (search list_styles) or say "you decide" (use the first recommended style). Never list the whole catalog. You may mention the remaining minutes (get_account credits.availableCreditsSec / 60).
|
|
1313
1344
|
3. Poll get_upload_progress. Once uploaded, call create_project with uploadSessionId set to its uploadId, the chosen styleId or presetId, and mode auto-export. The export includes the MP4 and the subtitle files the plan allows. Use review only when the user wants to check captions in the Editor first.
|
|
1314
1345
|
4. create_project, export_project, retry_project and cancel_project return an operation: poll get_operation until it completes; its resourceId is the projectId. If it fails, report the error and stop. Then call wait_for_project until the project is completed (inspect autoExport if it stays ready). Keep progress updates short.
|