@simpligen/mcp 0.1.2 → 0.1.3
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/package.json +1 -1
- package/src/bin.js +1 -1
- package/src/client.js +7 -0
- package/src/tools.js +53 -0
package/package.json
CHANGED
package/src/bin.js
CHANGED
package/src/client.js
CHANGED
|
@@ -68,6 +68,13 @@ export class ControlApiClient {
|
|
|
68
68
|
regenerateCharacterBase(id, args) { return this.#req('POST', `/characters/${encodeURIComponent(id)}/regenerate-base`, args); }
|
|
69
69
|
removeCharacter(id) { return this.#req('DELETE', `/characters/${encodeURIComponent(id)}`); }
|
|
70
70
|
|
|
71
|
+
listRecipeBlocks() { return this.#req('GET', '/recipe-blocks'); }
|
|
72
|
+
composeRecipe(args) { return this.#req('POST', '/recipes', args); }
|
|
73
|
+
validateRecipe(args) { return this.#req('POST', '/recipes/validate', args); }
|
|
74
|
+
listRecipes() { return this.#req('GET', '/recipes'); }
|
|
75
|
+
getRecipe(id) { return this.#req('GET', `/recipes/${encodeURIComponent(id)}`); }
|
|
76
|
+
publishRecipe(id, args) { return this.#req('POST', `/recipes/${encodeURIComponent(id)}/publish`, args); }
|
|
77
|
+
|
|
71
78
|
async uploadFile(filePath) {
|
|
72
79
|
let buf;
|
|
73
80
|
try {
|
package/src/tools.js
CHANGED
|
@@ -13,6 +13,7 @@ export const TOOL_NAMES = [
|
|
|
13
13
|
'remove_character', 'create_character', 'generate_character_image', 'generate_character_video',
|
|
14
14
|
'generate_character_frame', 'animate_character', 'set_character_preset',
|
|
15
15
|
'enhance_character_media', 'regenerate_character_base',
|
|
16
|
+
'list_recipe_blocks', 'compose_recipe', 'validate_recipe', 'list_recipes', 'get_recipe', 'publish_recipe',
|
|
16
17
|
];
|
|
17
18
|
|
|
18
19
|
const ok = (data) => ({ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] });
|
|
@@ -307,4 +308,56 @@ export function registerTools(server, client) {
|
|
|
307
308
|
}
|
|
308
309
|
} catch (e) { return fail(e); }
|
|
309
310
|
});
|
|
311
|
+
|
|
312
|
+
// --- Recipe authoring: compose multi-step recipes out of packs/presets ---
|
|
313
|
+
|
|
314
|
+
const recipeStep = z.object({
|
|
315
|
+
preset: z.string().describe('The preset this step runs, as "packId:presetId" (from list_recipe_blocks).'),
|
|
316
|
+
entry: z.string().optional().describe('Entry point: create-image | create-video | edit-image | upscale. Inferred from the preset when omitted.'),
|
|
317
|
+
promptInput: z.object({ key: z.string().optional(), label: z.string().optional() }).optional()
|
|
318
|
+
.describe('Name this step\'s prompt input, or set key to an existing input to SHARE a prompt. Default: a dedicated prompt input per step.'),
|
|
319
|
+
negativePrompt: z.string().optional(),
|
|
320
|
+
params: z.record(z.any()).optional().describe('Param bindings, literal or { from: "input:<key>" } (e.g. aspectRatio, seed, duration).'),
|
|
321
|
+
}).passthrough();
|
|
322
|
+
|
|
323
|
+
const recipeInput = z.object({
|
|
324
|
+
key: z.string().describe('Unique slug referenced as input:<key>.'),
|
|
325
|
+
kind: z.string().describe('subject | text | image | video | reference | audio | select | color | number | toggle'),
|
|
326
|
+
label: z.string().optional(),
|
|
327
|
+
required: z.boolean().optional(),
|
|
328
|
+
}).passthrough();
|
|
329
|
+
|
|
330
|
+
const recipeSpec = z.object({
|
|
331
|
+
name: z.string().describe('Recipe name shown to end users.'),
|
|
332
|
+
description: z.string().optional(),
|
|
333
|
+
category: z.string().optional().describe('e.g. product | ugc'),
|
|
334
|
+
nsfw: z.boolean().optional(),
|
|
335
|
+
version: z.string().optional().describe('Creator-facing semver, default 1.0.0.'),
|
|
336
|
+
inputs: z.array(recipeInput).optional().describe('Extra user-facing inputs (subjects, choices, media holes). A prompt input is auto-created per step, so you rarely list prompts here.'),
|
|
337
|
+
steps: z.array(recipeStep).min(1).describe('The pipeline in order. Each step pins a preset; media output flows into the next step automatically, and a subject input seeds a reference port.'),
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
server.registerTool('list_recipe_blocks',
|
|
341
|
+
{ title: 'List recipe blocks', description: 'The building blocks for authoring a recipe: entry points (create-image/video, edit-image, upscale) and every preset usable as a step, each with its port contract (inputs it needs, what it produces, which entry points it fits). Call this before compose_recipe to choose presets.', inputSchema: {} },
|
|
342
|
+
wrap(() => client.listRecipeBlocks()));
|
|
343
|
+
|
|
344
|
+
server.registerTool('compose_recipe',
|
|
345
|
+
{ title: 'Compose a recipe', description: 'Author a new recipe from a high-level spec and save it as a draft. You give an ordered list of steps (each pinned to a preset from list_recipe_blocks) plus any extra inputs; SimpliGen auto-wires the ports, media chain, and per-step prompt inputs and validates it. Returns { recipeId, valid, errors }. Anyone can compose; publishing later needs a connected account.', inputSchema: { spec: recipeSpec } },
|
|
346
|
+
wrap(({ spec }) => client.composeRecipe({ spec })));
|
|
347
|
+
|
|
348
|
+
server.registerTool('validate_recipe',
|
|
349
|
+
{ title: 'Validate a recipe', description: 'Dry-run without saving: pass a `spec` to compose+validate it, or a `config` to validate an existing recipe config. Returns precise errors (unbound ports, missing presets, type mismatches, cycles) to fix before compose_recipe.', inputSchema: { spec: recipeSpec.optional(), config: z.record(z.any()).optional() } },
|
|
350
|
+
wrap((args) => client.validateRecipe(args)));
|
|
351
|
+
|
|
352
|
+
server.registerTool('list_recipes',
|
|
353
|
+
{ title: 'List recipes', description: 'List the recipe drafts saved on this device (id, name, version, category).', inputSchema: {} },
|
|
354
|
+
wrap(() => client.listRecipes()));
|
|
355
|
+
|
|
356
|
+
server.registerTool('get_recipe',
|
|
357
|
+
{ title: 'Get a recipe', description: 'Get a saved recipe and its full config by id.', inputSchema: { id: z.string().describe('Recipe id from compose_recipe or list_recipes') } },
|
|
358
|
+
wrap(({ id }) => client.getRecipe(id)));
|
|
359
|
+
|
|
360
|
+
server.registerTool('publish_recipe',
|
|
361
|
+
{ title: 'Publish a recipe', description: 'Submit a saved recipe to the SimpliGen Creator Marketplace (queued for human review). Requires a connected account: if none, returns not_connected and the user connects once in Settings, then this succeeds on the same recipe. priceTokens sets an optional one-time price (0 or omitted = free). Every preset the recipe uses must be a distributable first-party pack.', inputSchema: { id: z.string().describe('Recipe id to publish'), changelog: z.string().optional(), priceTokens: z.number().optional().describe('One-time price in tokens (0/omitted = free).') } },
|
|
362
|
+
wrap(({ id, changelog, priceTokens }) => client.publishRecipe(id, { changelog, priceTokens })));
|
|
310
363
|
}
|