kineto-mcp 0.1.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 ADDED
@@ -0,0 +1,53 @@
1
+ # kineto-mcp
2
+
3
+ **Give your coding agent a camera.**
4
+
5
+ [Kineto](https://github.com/DanielFidalgo/kineto) is a video *compiler*, not a
6
+ screen recorder. You describe a scene as a JSON document; it compiles to an
7
+ MP4. Deterministic, no browser, no display, no render farm.
8
+
9
+ This package ships Kineto's **MCP server**, so an agent can render, inspect and
10
+ correct video on its own.
11
+
12
+ ## Use it
13
+
14
+ ```sh
15
+ claude mcp add --scope user kineto npx kineto-mcp
16
+ ```
17
+
18
+ That is the whole install — `npx` fetches the binary for your platform on
19
+ first use. Then, in any session:
20
+
21
+ > Turn these screenshots into a 20-second clip with captions.
22
+
23
+ > Render a release video from the last ten commits.
24
+
25
+ > Explain this architecture as a diagram, then make it move.
26
+
27
+ Prefer a binary on your PATH? `cargo install kineto`, or take an archive from
28
+ [Releases](https://github.com/DanielFidalgo/kineto/releases).
29
+
30
+ > Use `--scope user`, not the default. Project scope registers the server for
31
+ > one directory only, which is a confusing way to discover that your other
32
+ > sessions cannot see it.
33
+
34
+ ## What the agent gets
35
+
36
+ Tools to render a document, an asciinema recording, or a storyboard; to
37
+ preview single frames as images so it can *see* what it made; and to check a
38
+ document for the mistakes that are invisible in JSON and obvious on screen —
39
+ text too small to read, colours with no contrast, elements off-canvas.
40
+
41
+ Reading a frame back is what closes the loop. An agent that can look at its
42
+ own output stops producing slide decks.
43
+
44
+ ## Requirements
45
+
46
+ Node 18+. **ffmpeg** on `PATH` for encoding — frames render without it.
47
+
48
+ Prebuilt binaries cover macOS and Linux on arm64 and x64. On anything else,
49
+ `cargo install kineto` builds from source.
50
+
51
+ ## License
52
+
53
+ MIT OR Apache-2.0
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ // Locates the platform binary npm installed and hands control to it.
3
+ //
4
+ // `stdio: "inherit"` is not a detail here. Kineto's MCP server speaks JSON-RPC
5
+ // over stdin/stdout, so the child must receive the real file descriptors --
6
+ // piping through Node would put a buffering layer inside the protocol, and any
7
+ // stray write from this script would corrupt the stream. Nothing here may
8
+ // print to stdout, ever.
9
+ //
10
+ // spawnSync rather than spawn: it blocks until the child exits and forwards
11
+ // the descriptors directly, so there is no parent-side event loop to keep
12
+ // alive and no chance of the wrapper outliving the server.
13
+
14
+ import { spawnSync } from "node:child_process";
15
+ import { createRequire } from "node:module";
16
+ import { dirname } from "node:path";
17
+
18
+ // npm installs exactly one of these, chosen by the `os`/`cpu` fields the
19
+ // build script writes into each platform package.
20
+ import { PACKAGES } from "../targets.mjs";
21
+
22
+ const require = createRequire(import.meta.url);
23
+
24
+ const key = `${process.platform} ${process.arch}`;
25
+ const pkg = PACKAGES[key];
26
+
27
+ if (!pkg) {
28
+ process.stderr.write(
29
+ `kineto: no prebuilt binary for ${key}.\n` +
30
+ `Supported: ${Object.keys(PACKAGES).join(", ")}.\n` +
31
+ `Build from source instead: cargo install kineto\n`,
32
+ );
33
+ process.exit(1);
34
+ }
35
+
36
+ // Node resolves a module's realpath, so under any symlinked layout --
37
+ // `npm link`, npm workspaces, pnpm's default store -- `import.meta.url` points
38
+ // at the package's true location rather than the tree it was installed into,
39
+ // and resolution from there misses its own siblings. A registry install is not
40
+ // symlinked and hits the first branch; the fallbacks are what keep the linked
41
+ // cases working. argv[1] before cwd: under `npx` the cache directory holds the
42
+ // dependency, and the user's cwd is unrelated.
43
+ function resolveBinary(spec) {
44
+ const bases = [null, dirname(process.argv[1] ?? "."), process.cwd()];
45
+ for (const base of bases) {
46
+ try {
47
+ return base === null ? require.resolve(spec) : require.resolve(spec, { paths: [base] });
48
+ } catch {
49
+ // Try the next base; the caller reports failure once all are exhausted.
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+
55
+ const binary = resolveBinary(`${pkg}/bin/kineto-mcp`);
56
+ if (!binary) {
57
+ // Optional dependencies fail silently by design, so this is a normal
58
+ // outcome of --no-optional, a partially populated cache, or an install that
59
+ // raced. Naming the package is what makes it fixable.
60
+ process.stderr.write(
61
+ `kineto: ${pkg} is not installed.\n` +
62
+ `It is an optional dependency selected by platform; installing with\n` +
63
+ `--no-optional or --omit=optional skips it. Try: npm install ${pkg}\n`,
64
+ );
65
+ process.exit(1);
66
+ }
67
+
68
+ const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
69
+
70
+ if (result.error) {
71
+ process.stderr.write(`kineto: failed to run ${binary}: ${result.error.message}\n`);
72
+ process.exit(1);
73
+ }
74
+
75
+ // A signalled child has a null status. Reporting 0 there would tell the caller
76
+ // the server exited cleanly when it was killed.
77
+ process.exit(result.status === null ? 1 : result.status);
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "kineto-mcp",
3
+ "version": "0.1.2",
4
+ "description": "Kineto MCP server: give your coding agent a camera. Compiles declarative scene documents to MP4, animated WebP or PNG. No browser, no display.",
5
+ "keywords": [
6
+ "mcp",
7
+ "video",
8
+ "mp4",
9
+ "render",
10
+ "deterministic",
11
+ "agent"
12
+ ],
13
+ "license": "MIT OR Apache-2.0",
14
+ "type": "module",
15
+ "bin": {
16
+ "kineto-mcp": "bin/kineto-mcp.mjs"
17
+ },
18
+ "files": [
19
+ "bin/kineto-mcp.mjs",
20
+ "targets.mjs",
21
+ "README.md"
22
+ ],
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "scripts": {
27
+ "prepublishOnly": "node ../../scripts/guard-publish.mjs",
28
+ "test": "node --test test/*.test.mjs"
29
+ },
30
+ "optionalDependencies": {
31
+ "kineto-mcp-darwin-arm64": "0.1.2",
32
+ "kineto-mcp-darwin-x64": "0.1.2",
33
+ "kineto-mcp-linux-arm64": "0.1.2",
34
+ "kineto-mcp-linux-x64": "0.1.2"
35
+ },
36
+ "publishConfig": {
37
+ "registry": "https://registry.npmjs.org/"
38
+ }
39
+ }
package/targets.mjs ADDED
@@ -0,0 +1,24 @@
1
+ // The supported platforms, in one place.
2
+ //
3
+ // Unscoped: the npm organisation `kineto` was not available, and every name
4
+ // here is. It also lines the package up with the binary and the MCP
5
+ // serverInfo identity, which are both already `kineto-mcp`.
6
+ //
7
+ // The shim maps a running process to a package name; the build script maps a
8
+ // rust target to that same package. Those two lists silently disagreeing is a
9
+ // real failure mode -- add a platform to the builder alone and npm publishes a
10
+ // package nothing resolves; add it to the shim alone and the shim points at a
11
+ // package that was never built. Both import this, and a test asserts the shim
12
+ // covers exactly these.
13
+
14
+ export const TARGETS = [
15
+ { rust: "aarch64-apple-darwin", npm: "darwin-arm64", os: "darwin", cpu: "arm64" },
16
+ { rust: "x86_64-apple-darwin", npm: "darwin-x64", os: "darwin", cpu: "x64" },
17
+ { rust: "aarch64-unknown-linux-gnu", npm: "linux-arm64", os: "linux", cpu: "arm64" },
18
+ { rust: "x86_64-unknown-linux-gnu", npm: "linux-x64", os: "linux", cpu: "x64" },
19
+ ];
20
+
21
+ /// `process.platform process.arch` -> package name, as the shim needs it.
22
+ export const PACKAGES = Object.fromEntries(
23
+ TARGETS.map((t) => [`${t.os} ${t.cpu}`, `kineto-mcp-${t.npm}`]),
24
+ );