@contenthero/mcp 0.4.2 → 0.4.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/dist/format.d.ts +35 -2
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +69 -5
- package/dist/format.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +168 -38
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -37,7 +37,7 @@ import { z } from 'zod';
|
|
|
37
37
|
import { GenerationTimeoutError, pendingOutputId, } from '@contenthero/sdk';
|
|
38
38
|
import { getClient as defaultGetClient } from './client.js';
|
|
39
39
|
import { resolveModelEnums, BOARD_TYPES, BOARD_TYPE_GUIDANCE, IMAGE_MODEL_GUIDANCE, VIDEO_MODEL_GUIDANCE, AUDIO_MODEL_GUIDANCE, EDIT_AUDIO_MODEL_GUIDANCE, UPSCALE_MODEL_GUIDANCE, LIP_SYNC_MODEL_GUIDANCE, } from './models.js';
|
|
40
|
-
import { audioResult, avatarListResult, avatarResult, balanceResult, brandKitListResult, brandKitResult, brandKnowledgeListResult, brandKnowledgeDetailResult, brandKnowledgeSearchResult, brandKnowledgeItemResult, completedResult, connectedAccountListResult, connectedAccountResult, costResult, accountDetailResult, inspirationContentResult, mediaListResult, mediaSearchResult, folderListResult, folderContentsResult, mediaBatchResult, mediaUploadResult, importedMediaResult, uploadedMediaResult, tagListResult, tagResult, tagDeletedResult, modelListResult, modelResult, platformListResult, platformResult, elementListResult, elementResult, elementDeletedResult, errorResult, generationBatchResult, outlierListResult, enhanceClipsResult, pendingResult, stageListResult, spaceDeletedResult, spaceListResult, spaceResult, cardListResult, cardResult, postSummaryResult, publishResult, statusActionResult, editorOpsResult, text, projectDetailResult, liveContextResult, projectListResult, projectCreatedResult, projectDeletedResult, layerTypesResult, timelineTypesResult, editorTranscriptResult, exportJobResult, exportFormatsResult, trackedAccountListResult, transcriptResult, voiceListResult, voiceResult, } from './format.js';
|
|
40
|
+
import { audioResult, avatarListResult, avatarResult, avatarPendingResult, balanceResult, brandKitListResult, brandKitResult, brandKnowledgeListResult, brandKnowledgeDetailResult, brandKnowledgeSearchResult, brandKnowledgeItemResult, completedResult, connectedAccountListResult, connectedAccountResult, costResult, accountDetailResult, inspirationContentResult, mediaListResult, mediaSearchResult, folderListResult, folderContentsResult, mediaBatchResult, mediaUploadResult, importedMediaResult, uploadedMediaResult, tagListResult, tagResult, tagDeletedResult, modelListResult, modelResult, platformListResult, platformResult, elementListResult, elementResult, elementDeletedResult, errorResult, generationBatchResult, outlierListResult, enhanceClipsResult, pendingResult, stageListResult, spaceDeletedResult, spaceListResult, spaceResult, cardListResult, cardResult, postSummaryResult, publishResult, statusActionResult, editorOpsResult, text, projectDetailResult, liveContextResult, projectListResult, projectCreatedResult, projectDeletedResult, layerTypesResult, timelineTypesResult, editorTranscriptResult, exportJobResult, exportFormatsResult, trackedAccountListResult, transcriptResult, voiceListResult, voiceResult, } from './format.js';
|
|
41
41
|
/** Platforms a card or one of its posts may target. */
|
|
42
42
|
const POST_PLATFORMS = [
|
|
43
43
|
'youtube',
|
|
@@ -286,6 +286,10 @@ export function registerTools(server, opts) {
|
|
|
286
286
|
.array(z.string())
|
|
287
287
|
.optional()
|
|
288
288
|
.describe('References for image-to-image / editing. Each may be a URL or a previous output id (e.g. "<id>" or "<id>-2") to chain from an earlier generation.'),
|
|
289
|
+
avatarId: z
|
|
290
|
+
.string()
|
|
291
|
+
.optional()
|
|
292
|
+
.describe('Optional avatar id from list_avatars. File the result onto that avatar as a new LOOK (one appearance of a reusable character: same person, different outfit, setting or framing) instead of saving a standalone library output. Combine with a referenceImage of the avatar to keep the subject on-model.'),
|
|
289
293
|
...PLACEMENT_INPUT_FIELDS,
|
|
290
294
|
getCost: z.boolean().optional().describe('Return the credit cost estimate instead of generating (nothing runs, nothing is charged).'),
|
|
291
295
|
},
|
|
@@ -302,6 +306,7 @@ export function registerTools(server, opts) {
|
|
|
302
306
|
seed: args.seed,
|
|
303
307
|
references: buildReferences({ images: args.referenceImages }),
|
|
304
308
|
parameters: args.mode ? { mode: args.mode } : undefined,
|
|
309
|
+
avatarId: args.avatarId,
|
|
305
310
|
projectId: args.projectId,
|
|
306
311
|
placement: args.placement,
|
|
307
312
|
playheadFrame: args.playheadFrame,
|
|
@@ -344,6 +349,10 @@ export function registerTools(server, opts) {
|
|
|
344
349
|
.optional()
|
|
345
350
|
.describe('Number of board variations (1-4). Defaults to 1.'),
|
|
346
351
|
boardName: z.string().optional().describe('Optional name for the board.'),
|
|
352
|
+
avatarId: z
|
|
353
|
+
.string()
|
|
354
|
+
.optional()
|
|
355
|
+
.describe('Optional avatar id from list_avatars. Associate the board with that avatar, so a character sheet built for an avatar stays filed against it.'),
|
|
347
356
|
getCost: z.boolean().optional().describe('Return the credit cost estimate instead of generating (nothing runs, nothing is charged).'),
|
|
348
357
|
},
|
|
349
358
|
}, async (args, extra) => {
|
|
@@ -355,6 +364,7 @@ export function registerTools(server, opts) {
|
|
|
355
364
|
referenceImages: args.referenceImages,
|
|
356
365
|
numImages: args.numImages,
|
|
357
366
|
boardName: args.boardName,
|
|
367
|
+
avatarId: args.avatarId,
|
|
358
368
|
});
|
|
359
369
|
if (args.getCost)
|
|
360
370
|
return costResult(await client.estimateBoardCost(request));
|
|
@@ -735,6 +745,115 @@ export function registerTools(server, opts) {
|
|
|
735
745
|
return errorResult(err);
|
|
736
746
|
}
|
|
737
747
|
});
|
|
748
|
+
// -- create_avatar --------------------------------------------------------
|
|
749
|
+
server.registerTool('create_avatar', {
|
|
750
|
+
title: 'Create Avatar',
|
|
751
|
+
annotations: WRITE,
|
|
752
|
+
description: "Create a reusable character and start generating its first look. SPENDS CREDITS (pass getCost to preview the price without creating anything). Returns as soon as the record exists: the avatar is NOT usable yet, it sits at status 'processing' with no image until its first look finishes, so poll get_avatar until status is 'completed'. Supply referenceImageUrls to make the avatar a likeness of a real person from their photos; omit them to invent a character from the description and traits.",
|
|
753
|
+
inputSchema: {
|
|
754
|
+
name: z.string().describe('Avatar name, at least 3 characters.'),
|
|
755
|
+
age: z.string().describe("Apparent age, e.g. '20s', '35', 'middle-aged'. Required: the prompt writer describes the character from these traits."),
|
|
756
|
+
gender: z.string().describe('Gender presentation. Required, same reason as age.'),
|
|
757
|
+
ethnicity: z.string().optional().describe('Optional ethnicity, for a more specific likeness.'),
|
|
758
|
+
niche: z.array(z.string()).optional().describe('Content niches this character is for, e.g. ["fitness","nutrition"].'),
|
|
759
|
+
style: z.string().optional().describe('Visual style hint for the portrait, e.g. "editorial", "cinematic". Not stored on the avatar.'),
|
|
760
|
+
description: z
|
|
761
|
+
.string()
|
|
762
|
+
.optional()
|
|
763
|
+
.describe('Free-text description of the character. The strongest single input when no reference photos are given.'),
|
|
764
|
+
defaultVoiceId: z.string().optional().describe('A voiceId from list_voices, used as this avatar the default voice.'),
|
|
765
|
+
referenceImageUrls: z
|
|
766
|
+
.array(z.string())
|
|
767
|
+
.optional()
|
|
768
|
+
.describe('Photos of a REAL PERSON to anchor identity to: each a URL or a previous output id. Only use photos of someone who has agreed to being cloned.'),
|
|
769
|
+
getCost: z.boolean().optional().describe('Return the credit cost estimate instead of creating (nothing runs, nothing is charged).'),
|
|
770
|
+
},
|
|
771
|
+
}, async (args, extra) => {
|
|
772
|
+
try {
|
|
773
|
+
const client = await getClient(extra);
|
|
774
|
+
if (args.getCost) {
|
|
775
|
+
const creditsEstimate = await client.estimateAvatarCost();
|
|
776
|
+
// `modelId` is the first thing `costResult` names in its sentence, and `contentType` only
|
|
777
|
+
// admits image/video/audio. An avatar is none of those: the price is the fixed
|
|
778
|
+
// avatar-creation fee, not the cost of the portrait model, so say that rather than pick a
|
|
779
|
+
// media kind that would misdescribe it.
|
|
780
|
+
return costResult({ getCost: true, creditsEstimate, modelId: 'avatar creation' });
|
|
781
|
+
}
|
|
782
|
+
const created = await client.createAvatar({
|
|
783
|
+
name: args.name,
|
|
784
|
+
age: args.age,
|
|
785
|
+
gender: args.gender,
|
|
786
|
+
ethnicity: args.ethnicity,
|
|
787
|
+
niche: args.niche,
|
|
788
|
+
style: args.style,
|
|
789
|
+
description: args.description,
|
|
790
|
+
defaultVoiceId: args.defaultVoiceId,
|
|
791
|
+
referenceImageUrls: args.referenceImageUrls,
|
|
792
|
+
});
|
|
793
|
+
return avatarPendingResult(created);
|
|
794
|
+
}
|
|
795
|
+
catch (err) {
|
|
796
|
+
return errorResult(err);
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
// -- update_avatar --------------------------------------------------------
|
|
800
|
+
server.registerTool('update_avatar', {
|
|
801
|
+
title: 'Update Avatar',
|
|
802
|
+
annotations: WRITE,
|
|
803
|
+
description: "Update an avatar and/or change its looks. Fields: name, defaultLookId (also becomes the avatar's profile photo), defaultVoiceId. Looks are changed through ops, the same shape update_timeline and update_canvas use: add_look files images the account ALREADY OWNS onto the avatar, remove_look trashes one (recoverable for 30 days). Ops run before the fields, so one call can add a look and make it the default. To GENERATE a new look instead of filing an existing image, call generate_image with avatarId.",
|
|
804
|
+
inputSchema: {
|
|
805
|
+
avatarId: z.string().describe('The avatar id from list_avatars.'),
|
|
806
|
+
name: z.string().optional().describe('New name, at least 3 characters.'),
|
|
807
|
+
defaultLookId: z
|
|
808
|
+
.string()
|
|
809
|
+
.optional()
|
|
810
|
+
.describe("A look id from get_avatar. Becomes the avatar's default look AND its profile photo."),
|
|
811
|
+
defaultVoiceId: z.string().nullable().optional().describe('A voiceId from list_voices, or null to clear it.'),
|
|
812
|
+
ops: z
|
|
813
|
+
.array(z.union([
|
|
814
|
+
z.object({
|
|
815
|
+
op: z.literal('add_look'),
|
|
816
|
+
imageUrls: z
|
|
817
|
+
.array(z.string())
|
|
818
|
+
.describe('Images the account already owns, as URLs: an upload, a creation, an editor export, or another avatar look. Anything not owned by this account is skipped rather than failing the call.'),
|
|
819
|
+
}),
|
|
820
|
+
z.object({
|
|
821
|
+
op: z.literal('remove_look'),
|
|
822
|
+
lookId: z.string().describe('A look id from get_avatar.'),
|
|
823
|
+
}),
|
|
824
|
+
]))
|
|
825
|
+
.optional()
|
|
826
|
+
.describe('Look changes, applied in order before the field updates. NOT a transaction: a failure part-way leaves earlier ops applied.'),
|
|
827
|
+
},
|
|
828
|
+
}, async (args, extra) => {
|
|
829
|
+
try {
|
|
830
|
+
const client = await getClient(extra);
|
|
831
|
+
const { avatarId, ...request } = args;
|
|
832
|
+
const updated = await client.updateAvatar(avatarId, request);
|
|
833
|
+
return avatarResult(updated.avatar);
|
|
834
|
+
}
|
|
835
|
+
catch (err) {
|
|
836
|
+
return errorResult(err);
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
// -- delete_avatar --------------------------------------------------------
|
|
840
|
+
server.registerTool('delete_avatar', {
|
|
841
|
+
title: 'Delete Avatar',
|
|
842
|
+
annotations: WRITE,
|
|
843
|
+
description: "Delete an avatar. Soft: the avatar stops appearing, but ITS LOOKS SURVIVE as library images and can be filed onto another avatar with update_avatar's add_look. Use this to retire a duplicate or an abandoned character, after moving any looks worth keeping.",
|
|
844
|
+
inputSchema: {
|
|
845
|
+
avatarId: z.string().describe('The avatar id from list_avatars.'),
|
|
846
|
+
},
|
|
847
|
+
}, async (args, extra) => {
|
|
848
|
+
try {
|
|
849
|
+
const client = await getClient(extra);
|
|
850
|
+
await client.deleteAvatar(args.avatarId);
|
|
851
|
+
return text(`Avatar ${args.avatarId} deleted. Its looks are retained and can be filed onto another avatar with update_avatar add_look.`);
|
|
852
|
+
}
|
|
853
|
+
catch (err) {
|
|
854
|
+
return errorResult(err);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
738
857
|
// -- list_voices ----------------------------------------------------------
|
|
739
858
|
server.registerTool('list_voices', {
|
|
740
859
|
title: 'List Voices',
|
|
@@ -1157,11 +1276,11 @@ export function registerTools(server, opts) {
|
|
|
1157
1276
|
annotations: READ,
|
|
1158
1277
|
description: "Return the contents of one folder. The folder id is either one of the account's own folder ids or a built-in derived-folder key. A manual folder returns exactly the items filed in it; a smart folder computes its members live from its saved query; a derived folder returns its built-in set. Items are media (with kind and a description) and, in manual folders, entities such as projects or posts.",
|
|
1159
1278
|
inputSchema: {
|
|
1160
|
-
|
|
1279
|
+
folderId: z.string().describe('A folder id, or a derived-folder key (recents, favorites, edits, canvas, cards).'),
|
|
1161
1280
|
},
|
|
1162
1281
|
}, async (args, extra) => {
|
|
1163
1282
|
try {
|
|
1164
|
-
const r = await (await getClient(extra)).getFolder(args.
|
|
1283
|
+
const r = await (await getClient(extra)).getFolder(args.folderId);
|
|
1165
1284
|
return folderContentsResult(r.folder, r.items);
|
|
1166
1285
|
}
|
|
1167
1286
|
catch (err) {
|
|
@@ -1176,11 +1295,11 @@ export function registerTools(server, opts) {
|
|
|
1176
1295
|
name: z.string().describe('The folder name.'),
|
|
1177
1296
|
type: z.enum(['manual', 'smart']).optional().describe("'manual' (a collection you file items into) or 'smart' (a saved live query). Defaults to manual."),
|
|
1178
1297
|
query: smartQuerySchema,
|
|
1179
|
-
|
|
1298
|
+
parentId: z.string().optional().describe('Nest the new folder under this parent folder id.'),
|
|
1180
1299
|
},
|
|
1181
1300
|
}, async (args, extra) => {
|
|
1182
1301
|
try {
|
|
1183
|
-
const f = await (await getClient(extra)).createFolder({ name: args.name, type: args.type, query: args.query, parentId: args.
|
|
1302
|
+
const f = await (await getClient(extra)).createFolder({ name: args.name, type: args.type, query: args.query, parentId: args.parentId });
|
|
1184
1303
|
return text(`Created ${f.type} folder "${f.name}" (id ${f.id}).`);
|
|
1185
1304
|
}
|
|
1186
1305
|
catch (err) {
|
|
@@ -1188,32 +1307,32 @@ export function registerTools(server, opts) {
|
|
|
1188
1307
|
}
|
|
1189
1308
|
});
|
|
1190
1309
|
/**
|
|
1191
|
-
* One item's universal identity. NO
|
|
1192
|
-
*
|
|
1310
|
+
* One item's universal identity. NO folderId: the folder is named by the tool's own folderId /
|
|
1311
|
+
* folderIds now, which is what lets one call file many items into many folders.
|
|
1193
1312
|
*/
|
|
1194
1313
|
const itemRefBodySchema = z.object({
|
|
1195
|
-
|
|
1196
|
-
|
|
1314
|
+
sourceTable: z.string().describe("The item's source table (e.g. as returned by list_media / get_media)."),
|
|
1315
|
+
sourceRecordId: z.string().describe("The item's source record id."),
|
|
1197
1316
|
variant: z.number().int().optional().describe('The variation index (default 0 for single-asset items).'),
|
|
1198
1317
|
});
|
|
1199
1318
|
server.registerTool('update_folder', {
|
|
1200
1319
|
title: 'Update Folder',
|
|
1201
1320
|
annotations: WRITE,
|
|
1202
|
-
description: "Update the account's own folders: rename one, MOVE folders under a different parent (or to the top level with a null parent), change a smart folder's saved query, and FILE or UNFILE items. addItems/removeItems are DELTAS of {
|
|
1321
|
+
description: "Update the account's own folders: rename one, MOVE folders under a different parent (or to the top level with a null parent), change a smart folder's saved query, and FILE or UNFILE items. addItems/removeItems are DELTAS of { sourceTable, sourceRecordId, variant? }, not a list to replace, because an item can sit in several folders at once and a replace would silently unfile it from the others. Filing never moves or copies anything: it adds a pointer, and only manual folders accept items (a smart folder computes its own membership). Pass folderIds to patch several folders at once, which crossed with addItems files the same items into all of them; renaming and re-querying still need exactly one folder. NOTE the asymmetry: nesting a FOLDER via parentId is a MOVE (a folder has one parent), while filing an ITEM is a pointer that leaves its other folders alone.",
|
|
1203
1322
|
inputSchema: {
|
|
1204
|
-
|
|
1205
|
-
|
|
1323
|
+
folderId: z.string().describe('The folder id to update.'),
|
|
1324
|
+
folderIds: z
|
|
1206
1325
|
.array(z.string())
|
|
1207
1326
|
.optional()
|
|
1208
1327
|
.describe('Patch several folders at once. Attribute fields (name, query) still need exactly one.'),
|
|
1209
1328
|
name: z.string().optional().describe('A new name.'),
|
|
1210
|
-
|
|
1329
|
+
parentId: z.string().nullable().optional().describe('A new parent folder id, or null to move to the top level. MOVES the folder.'),
|
|
1211
1330
|
query: smartQuerySchema,
|
|
1212
|
-
|
|
1331
|
+
addItems: z
|
|
1213
1332
|
.array(itemRefBodySchema)
|
|
1214
1333
|
.optional()
|
|
1215
1334
|
.describe('File these items into the folder(s). A delta: their other folders are untouched.'),
|
|
1216
|
-
|
|
1335
|
+
removeItems: z
|
|
1217
1336
|
.array(itemRefBodySchema)
|
|
1218
1337
|
.optional()
|
|
1219
1338
|
.describe('Unfile these items. Only the pointer goes; the asset is never deleted.'),
|
|
@@ -1223,17 +1342,17 @@ export function registerTools(server, opts) {
|
|
|
1223
1342
|
const client = await getClient(extra);
|
|
1224
1343
|
const patch = {
|
|
1225
1344
|
name: args.name,
|
|
1226
|
-
parentId: args.
|
|
1345
|
+
parentId: args.parentId,
|
|
1227
1346
|
query: args.query,
|
|
1228
|
-
addItems: args.
|
|
1229
|
-
removeItems: args.
|
|
1347
|
+
addItems: args.addItems,
|
|
1348
|
+
removeItems: args.removeItems,
|
|
1230
1349
|
};
|
|
1231
|
-
const targets = args.
|
|
1350
|
+
const targets = args.folderIds?.length ? args.folderIds : [args.folderId];
|
|
1232
1351
|
const folders = targets.length > 1
|
|
1233
1352
|
? await client.updateFolders(targets, patch)
|
|
1234
1353
|
: [await client.updateFolder(targets[0], patch)];
|
|
1235
|
-
const filed = args.
|
|
1236
|
-
const unfiled = args.
|
|
1354
|
+
const filed = args.addItems?.length ?? 0;
|
|
1355
|
+
const unfiled = args.removeItems?.length ?? 0;
|
|
1237
1356
|
const what = [
|
|
1238
1357
|
filed ? `filed ${filed} item(s)` : null,
|
|
1239
1358
|
unfiled ? `unfiled ${unfiled} item(s)` : null,
|
|
@@ -1249,11 +1368,11 @@ export function registerTools(server, opts) {
|
|
|
1249
1368
|
title: 'Delete Folder',
|
|
1250
1369
|
annotations: WRITE,
|
|
1251
1370
|
description: "Delete one of the account's own folders and everything nested under it. This removes the folder structure only; the media and entities inside are pointers, so the underlying assets are never deleted. Confirm intent before deleting a folder that contains items.",
|
|
1252
|
-
inputSchema: {
|
|
1371
|
+
inputSchema: { folderId: z.string().describe('The folder id to delete.') },
|
|
1253
1372
|
}, async (args, extra) => {
|
|
1254
1373
|
try {
|
|
1255
|
-
await (await getClient(extra)).deleteFolder(args.
|
|
1256
|
-
return text(`Deleted folder ${args.
|
|
1374
|
+
await (await getClient(extra)).deleteFolder(args.folderId);
|
|
1375
|
+
return text(`Deleted folder ${args.folderId}.`);
|
|
1257
1376
|
}
|
|
1258
1377
|
catch (err) {
|
|
1259
1378
|
return errorResult(err);
|
|
@@ -1462,11 +1581,11 @@ export function registerTools(server, opts) {
|
|
|
1462
1581
|
title: 'Get Element',
|
|
1463
1582
|
annotations: READ,
|
|
1464
1583
|
description: "Get one saved reference element by id: its name, category, description, and images.",
|
|
1465
|
-
inputSchema: {
|
|
1584
|
+
inputSchema: { elementId: z.string().describe('The element id.') },
|
|
1466
1585
|
}, async (args, extra) => {
|
|
1467
1586
|
try {
|
|
1468
1587
|
const client = await getClient(extra);
|
|
1469
|
-
return elementResult(await client.getElement(args.
|
|
1588
|
+
return elementResult(await client.getElement(args.elementId));
|
|
1470
1589
|
}
|
|
1471
1590
|
catch (err) {
|
|
1472
1591
|
return errorResult(err);
|
|
@@ -1505,7 +1624,7 @@ export function registerTools(server, opts) {
|
|
|
1505
1624
|
annotations: WRITE,
|
|
1506
1625
|
description: "Update a saved element's name, description, or category.",
|
|
1507
1626
|
inputSchema: {
|
|
1508
|
-
|
|
1627
|
+
elementId: z.string().describe('The element id.'),
|
|
1509
1628
|
name: z.string().optional(),
|
|
1510
1629
|
description: z.string().optional(),
|
|
1511
1630
|
category: z.enum(['auto', 'character', 'location', 'prop']).optional(),
|
|
@@ -1513,7 +1632,7 @@ export function registerTools(server, opts) {
|
|
|
1513
1632
|
}, async (args, extra) => {
|
|
1514
1633
|
try {
|
|
1515
1634
|
const client = await getClient(extra);
|
|
1516
|
-
return elementResult(await client.updateElement(args.
|
|
1635
|
+
return elementResult(await client.updateElement(args.elementId, { name: args.name, description: args.description, category: args.category }), 'Updated');
|
|
1517
1636
|
}
|
|
1518
1637
|
catch (err) {
|
|
1519
1638
|
return errorResult(err);
|
|
@@ -1524,12 +1643,12 @@ export function registerTools(server, opts) {
|
|
|
1524
1643
|
title: 'Delete Element',
|
|
1525
1644
|
annotations: WRITE,
|
|
1526
1645
|
description: 'Delete a saved reference element.',
|
|
1527
|
-
inputSchema: {
|
|
1646
|
+
inputSchema: { elementId: z.string().describe('The element id.') },
|
|
1528
1647
|
}, async (args, extra) => {
|
|
1529
1648
|
try {
|
|
1530
1649
|
const client = await getClient(extra);
|
|
1531
|
-
await client.deleteElement(args.
|
|
1532
|
-
return elementDeletedResult(args.
|
|
1650
|
+
await client.deleteElement(args.elementId);
|
|
1651
|
+
return elementDeletedResult(args.elementId);
|
|
1533
1652
|
}
|
|
1534
1653
|
catch (err) {
|
|
1535
1654
|
return errorResult(err);
|
|
@@ -1585,12 +1704,16 @@ export function registerTools(server, opts) {
|
|
|
1585
1704
|
server.registerTool('list_cards', {
|
|
1586
1705
|
title: 'List Cards',
|
|
1587
1706
|
annotations: READ,
|
|
1588
|
-
description: "List
|
|
1707
|
+
description: "List one SPACE's cards (newest-updated first). ⚠️ SCOPED, NOT COMPLETE: without spaceId this lists the account's DEFAULT space only, and cards on any other board are absent with nothing in the response saying so (search misses them too). Call list_spaces FIRST and pass spaceId unless you specifically mean the default board. Filter by status, platform, stage (id/slug/name), favorite, or a title search. Call get_card for one card's full detail (posts + assets).",
|
|
1589
1708
|
inputSchema: {
|
|
1709
|
+
spaceId: z
|
|
1710
|
+
.string()
|
|
1711
|
+
.optional()
|
|
1712
|
+
.describe("Which space's board to list, from list_spaces. Omit ONLY when you mean the account's default space; omitting it does not search every board."),
|
|
1590
1713
|
status: z.enum(['draft', 'active', 'completed', 'archived']).optional().describe('Filter by lifecycle status.'),
|
|
1591
1714
|
platform: z.enum(POST_PLATFORMS).optional().describe('Filter by the post platform.'),
|
|
1592
|
-
stage: z.string().optional().describe('Filter by a stage id, slug, or name.'),
|
|
1593
|
-
search: z.string().optional().describe('Case-insensitive title search.'),
|
|
1715
|
+
stage: z.string().optional().describe('Filter by a stage id, slug, or name. Resolved within the chosen space.'),
|
|
1716
|
+
search: z.string().optional().describe('Case-insensitive title search, scoped to the chosen space.'),
|
|
1594
1717
|
limit: z.number().int().min(1).max(100).optional().describe('How many to return (default 50).'),
|
|
1595
1718
|
offset: z.number().int().min(0).optional().describe('Pagination offset.'),
|
|
1596
1719
|
},
|
|
@@ -1598,6 +1721,7 @@ export function registerTools(server, opts) {
|
|
|
1598
1721
|
try {
|
|
1599
1722
|
const client = await getClient(extra);
|
|
1600
1723
|
return cardListResult(await client.listCards({
|
|
1724
|
+
spaceId: args.spaceId,
|
|
1601
1725
|
status: args.status,
|
|
1602
1726
|
platform: args.platform,
|
|
1603
1727
|
stage: args.stage,
|
|
@@ -1733,11 +1857,17 @@ export function registerTools(server, opts) {
|
|
|
1733
1857
|
server.registerTool('list_stages', {
|
|
1734
1858
|
title: 'List Pipeline Stages',
|
|
1735
1859
|
annotations: READ,
|
|
1736
|
-
description: "List
|
|
1737
|
-
|
|
1860
|
+
description: "List one SPACE's stages, in order. ⚠️ STAGES ARE PER-SPACE: without spaceId this is the account's DEFAULT space, and two spaces can each hold a stage named 'Published' with different ids, so a stage name resolved against the wrong space is a different column. Stages are user-customizable (renamed, reordered, added, removed), so call this to discover the real stages before placing a card; pass a stage's id (most stable), slug, or name to create_card / update_card.",
|
|
1861
|
+
inputSchema: {
|
|
1862
|
+
spaceId: z
|
|
1863
|
+
.string()
|
|
1864
|
+
.optional()
|
|
1865
|
+
.describe("Which space's stages, from list_spaces. Omit only when you mean the account's default space."),
|
|
1866
|
+
},
|
|
1867
|
+
}, async (args, extra) => {
|
|
1738
1868
|
try {
|
|
1739
1869
|
const client = await getClient(extra);
|
|
1740
|
-
return stageListResult(await client.listStages());
|
|
1870
|
+
return stageListResult(await client.listStages({ spaceId: args.spaceId }));
|
|
1741
1871
|
}
|
|
1742
1872
|
catch (err) {
|
|
1743
1873
|
return errorResult(err);
|
|
@@ -1833,7 +1963,7 @@ export function registerTools(server, opts) {
|
|
|
1833
1963
|
...(posts !== undefined ? { posts: posts } : {}),
|
|
1834
1964
|
...(assets !== undefined ? { assets: assets } : {}),
|
|
1835
1965
|
};
|
|
1836
|
-
// `cardIds` widens the path id, matching update_folder's
|
|
1966
|
+
// `cardIds` widens the path id, matching update_folder's folderId / folderIds. One card still
|
|
1837
1967
|
// goes through updateCard so the single-card response shape is unchanged for every caller.
|
|
1838
1968
|
const targets = cardIds?.length ? cardIds : [cardId];
|
|
1839
1969
|
if (targets.length > 1) {
|