realtime-avatar-mcp 0.4.0 → 0.5.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 +6 -7
- package/dist/server.d.ts +1 -1
- package/dist/server.js +50 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
# realtime-avatar-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Published on npm as [`realtime-avatar-mcp`](https://www.npmjs.com/package/realtime-avatar-mcp) — run it with `npx`, never installed into an app.
|
|
4
4
|
|
|
5
5
|
An MCP server for Realtime Avatar. [`AGENTS.md`](../../AGENTS.md) tells a coding agent what
|
|
6
6
|
the API is; this lets it *look* — at your avatars, your balance, your bill — instead of
|
|
7
7
|
guessing ids and inventing shapes.
|
|
8
8
|
|
|
9
|
-
```bash
|
|
10
|
-
npm run build
|
|
11
|
-
```
|
|
12
|
-
|
|
13
9
|
```jsonc
|
|
14
10
|
{
|
|
15
11
|
"mcpServers": {
|
|
16
12
|
"realtime-avatar": {
|
|
17
|
-
"command": "
|
|
18
|
-
"args": ["
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "realtime-avatar-mcp"],
|
|
19
15
|
"env": { "REALTIME_AVATAR_API_KEY": "tic_test_…" }
|
|
20
16
|
}
|
|
21
17
|
}
|
|
22
18
|
}
|
|
23
19
|
```
|
|
24
20
|
|
|
21
|
+
Working on it in this repo? `npm run build`, then point `command` at `node` with
|
|
22
|
+
`args: ["/abs/path/to/realtime-avatar-sdk/libs/mcp/dist/bin.js"]`.
|
|
23
|
+
|
|
25
24
|
## Tools
|
|
26
25
|
|
|
27
26
|
| Tool | |
|
package/dist/server.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
5
5
|
* `test/server.test.ts` asserts the two stay equal; the equivalent constant in
|
|
6
6
|
* `realtime-avatar` had that guard and this one did not, which is how it drifted.
|
|
7
7
|
*/
|
|
8
|
-
export declare const MCP_VERSION = "0.
|
|
8
|
+
export declare const MCP_VERSION = "0.5.0";
|
|
9
9
|
/**
|
|
10
10
|
* The Realtime Avatar MCP server.
|
|
11
11
|
*
|
package/dist/server.js
CHANGED
|
@@ -10,7 +10,7 @@ import { RealtimeAvatar, isQueued } from "realtime-avatar";
|
|
|
10
10
|
* `test/server.test.ts` asserts the two stay equal; the equivalent constant in
|
|
11
11
|
* `realtime-avatar` had that guard and this one did not, which is how it drifted.
|
|
12
12
|
*/
|
|
13
|
-
export const MCP_VERSION = "0.
|
|
13
|
+
export const MCP_VERSION = "0.5.0";
|
|
14
14
|
const MICROS_PER_CREDIT = 1_000_000;
|
|
15
15
|
/** Extension -> asset kind, so a caller does not have to restate what the filename says. */
|
|
16
16
|
const KIND_BY_EXT = {
|
|
@@ -109,6 +109,15 @@ export function createServer(options) {
|
|
|
109
109
|
`total ${credits(total)}` +
|
|
110
110
|
(page.nextCursor ? "\n(more pages available)" : ""));
|
|
111
111
|
});
|
|
112
|
+
server.registerTool("list_clips", {
|
|
113
|
+
title: "List an avatar's clip library",
|
|
114
|
+
description: "The declared clip library: every non-retired clip with its render status, plus " +
|
|
115
|
+
"the library revision (pass it to set_clip_library as expectedRevision), the pose " +
|
|
116
|
+
"anchor and eligibility. status is the render JOB, not serveability — a clip " +
|
|
117
|
+
"re-rendering keeps serving its previous take.",
|
|
118
|
+
inputSchema: { avatarId: z.string() },
|
|
119
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
120
|
+
}, async ({ avatarId }) => text(JSON.stringify(await rta.listClips(avatarId), null, 2)));
|
|
112
121
|
if (!options.allowWrites)
|
|
113
122
|
return server;
|
|
114
123
|
// ── writes, opt-in only ────────────────────────────────────────────────────
|
|
@@ -153,9 +162,48 @@ export function createServer(options) {
|
|
|
153
162
|
"Relay this payload to the browser byte-for-byte — the client SDK validates it " +
|
|
154
163
|
"strictly and rejects a reshaped object.");
|
|
155
164
|
});
|
|
165
|
+
server.registerTool("set_clip_library", {
|
|
166
|
+
title: "Declare an avatar's clip library",
|
|
167
|
+
description: "Declare the avatar's FULL desired clip library — a declaration, not a delta: " +
|
|
168
|
+
"unchanged clips are kept, new or changed ones are queued to render, omitted ones " +
|
|
169
|
+
"are retired. The 202 is acceptance, not readiness — poll list_clips until no row " +
|
|
170
|
+
"is queued or generating. Pass expectedRevision from list_clips so a concurrent " +
|
|
171
|
+
"writer surfaces as a 409 instead of a lost update. Does not spend credits.",
|
|
172
|
+
inputSchema: {
|
|
173
|
+
avatarId: z.string(),
|
|
174
|
+
clips: z.array(z.object({
|
|
175
|
+
clipId: z.string().describe("Stable id you choose; same id + same source = kept"),
|
|
176
|
+
role: z.enum(["idle", "listen", "gesture"]),
|
|
177
|
+
whenHint: z.string().optional().describe("Briefed to the character, like an actor"),
|
|
178
|
+
source: z.union([
|
|
179
|
+
z.object({ motionPrompt: z.string() }),
|
|
180
|
+
z.object({ assetId: z.string() }),
|
|
181
|
+
]).describe("motionPrompt renders motion; assetId uploads a clip that must start AND end on the rest pose"),
|
|
182
|
+
durationSeconds: z.number().optional(),
|
|
183
|
+
reroll: z.boolean().optional().describe("Set true to force a re-render of the same prompt"),
|
|
184
|
+
})).max(12).describe("The COMPLETE library. Omitted clips are retired."),
|
|
185
|
+
expectedRevision: z.number().int().optional()
|
|
186
|
+
.describe("CAS: the revision you last read. Omit to declare unconditionally."),
|
|
187
|
+
},
|
|
188
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
189
|
+
}, async ({ avatarId, clips, expectedRevision }) => {
|
|
190
|
+
const update = await rta.setClipLibrary(avatarId, { clips, expectedRevision });
|
|
191
|
+
const bucket = (label, ids) => `${label} (${ids.length})${ids.length ? ` ${ids.join(", ")}` : ""}`;
|
|
192
|
+
return text(`revision ${update.revision}\n` +
|
|
193
|
+
[
|
|
194
|
+
bucket("kept — still serving", update.plan.kept),
|
|
195
|
+
bucket("queued — rendering now", update.plan.queued),
|
|
196
|
+
bucket("retired — no longer live", update.plan.retired),
|
|
197
|
+
].join("\n") +
|
|
198
|
+
(update.plan.queued.length
|
|
199
|
+
? "\n\nQueued clips render in the background — poll list_clips until no row is queued or generating."
|
|
200
|
+
: ""));
|
|
201
|
+
});
|
|
156
202
|
server.registerTool("sync_clips", {
|
|
157
203
|
title: "Sync an avatar's clips",
|
|
158
|
-
description: "
|
|
204
|
+
description: "DEPRECATED — this serves the sunsetting external-URL clip tier; declare the " +
|
|
205
|
+
"library with set_clip_library instead. Clips are prepared once and cached by URL " +
|
|
206
|
+
"hash, and " +
|
|
159
207
|
"the serve path only LOADS that cache — so a clip you added but never synced does " +
|
|
160
208
|
"nothing at all on the next call, silently. Idempotent: call it after every clip " +
|
|
161
209
|
"change. Pass the complete set you want live; anything omitted is retired. This does " +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "realtime-avatar-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MCP server for Realtime Avatar — let a coding agent read your avatars, balance and bill directly.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "The Influence Company",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
58
|
-
"realtime-avatar": "0.
|
|
58
|
+
"realtime-avatar": "0.5.0",
|
|
59
59
|
"zod": "^4.4.3"
|
|
60
60
|
}
|
|
61
61
|
}
|