@contenthero/mcp 0.3.9 → 0.4.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/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, uploadedMediaResult, tagListResult, tagResult, tagDeletedResult, modelListResult, modelResult, platformListResult, platformResult, elementListResult, elementResult, elementDeletedResult, errorResult, generationBatchResult, outlierListResult, enhanceClipsResult, pendingResult, pipelineStageListResult, postListResult, postResult, 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, balanceResult, brandKitListResult, brandKitResult, brandKnowledgeListResult, brandKnowledgeDetailResult, brandKnowledgeSearchResult, brandKnowledgeItemResult, completedResult, connectedAccountListResult, connectedAccountResult, costResult, accountDetailResult, inspirationContentResult, mediaListResult, mediaSearchResult, folderListResult, folderContentsResult, mediaBatchResult, mediaUploadResult, 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 post or destination may target. */
42
42
  const POST_PLATFORMS = [
43
43
  'youtube',
@@ -1142,7 +1142,7 @@ export function registerTools(server, opts) {
1142
1142
  server.registerTool('list_folders', {
1143
1143
  title: 'List Folders',
1144
1144
  annotations: READ,
1145
- description: "List the account's library folders (their own manual and smart folders, as a flat list with parent links for nesting) together with the built-in derived folders (recents, favorites, edits, canvas, posts). Use this to see how the library is organized before browsing or filing items.",
1145
+ description: "List the account's library folders (their own manual and smart folders, as a flat list with parent links for nesting) together with the built-in derived folders (recents, favorites, edits, canvas, cards). Use this to see how the library is organized before browsing or filing items.",
1146
1146
  inputSchema: {},
1147
1147
  }, async (_args, extra) => {
1148
1148
  try {
@@ -1157,7 +1157,7 @@ export function registerTools(server, opts) {
1157
1157
  annotations: READ,
1158
1158
  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
1159
  inputSchema: {
1160
- folder_id: z.string().describe('A folder id, or a derived-folder key (recents, favorites, edits, canvas, posts).'),
1160
+ folder_id: z.string().describe('A folder id, or a derived-folder key (recents, favorites, edits, canvas, cards).'),
1161
1161
  },
1162
1162
  }, async (args, extra) => {
1163
1163
  try {
@@ -1263,12 +1263,12 @@ export function registerTools(server, opts) {
1263
1263
  server.registerTool('get_media', {
1264
1264
  title: 'Get Media',
1265
1265
  annotations: READ,
1266
- description: 'SEE specific media. Pass a batch of items (up to 10) to view them at once: each item is either a { url } (e.g. a URL threaded from get_context, a layer/asset URL from get_project / get_post, or an upload URL from list_media source=uploads) or an { mediaId, variation? } (a studio output id, full or first-8; omit variation to get the primary one). Returns light metadata per item plus an IMAGE block for each image so you can actually see it. For a VIDEO, set frames (and optionally fromSec/toSec) on the item to get low-res KEYFRAMES across that source-time window, so you can watch the raw footage (judge B-roll relevance, take quality) without editing it; audio still returns metadata + the url. An mediaId without a variation returns ONLY the primary variation and lists the others; request a specific variation to see it. Use this to inspect the actual pixels, not just URLs.',
1266
+ description: 'SEE specific media. Pass a batch of items (up to 10) to view them at once: each item is either a { url } (e.g. a URL threaded from get_context, a layer/asset URL from get_project / get_card, or an upload URL from list_media source=uploads) or an { mediaId, variation? } (a studio output id, full or first-8; omit variation to get the primary one). Returns light metadata per item plus an IMAGE block for each image so you can actually see it. For a VIDEO, set frames (and optionally fromSec/toSec) on the item to get low-res KEYFRAMES across that source-time window, so you can watch the raw footage (judge B-roll relevance, take quality) without editing it; audio still returns metadata + the url. An mediaId without a variation returns ONLY the primary variation and lists the others; request a specific variation to see it. Use this to inspect the actual pixels, not just URLs.',
1267
1267
  inputSchema: {
1268
1268
  items: z
1269
1269
  .array(z.union([
1270
1270
  z.object({
1271
- url: z.string().describe('A media URL on our storage (from get_context / get_project / get_post).'),
1271
+ url: z.string().describe('A media URL on our storage (from get_context / get_project / get_card).'),
1272
1272
  fromSec: z.number().min(0).optional().describe('Video keyframes: start of the source-time window (seconds). Omit for the whole clip.'),
1273
1273
  toSec: z.number().min(0).optional().describe('Video keyframes: end of the source-time window (seconds).'),
1274
1274
  frames: z.number().int().min(1).optional().describe('Video keyframes: how many to return across the window. Set this (or fromSec/toSec) to watch the raw footage.'),
@@ -1581,11 +1581,11 @@ export function registerTools(server, opts) {
1581
1581
  return errorResult(err);
1582
1582
  }
1583
1583
  });
1584
- // -- list_posts -----------------------------------------------------------
1585
- server.registerTool('list_posts', {
1584
+ // -- list_cards -----------------------------------------------------------
1585
+ server.registerTool('list_cards', {
1586
1586
  title: 'List Posts',
1587
1587
  annotations: READ,
1588
- description: "List the account's content-pipeline posts (newest-updated first). Filter by status, platform, pipeline_stage (id/slug/name), folder, favorite, or a title search. Call get_post for one post's full detail (destinations + assets).",
1588
+ description: "List the account's content-pipeline posts (newest-updated first). Filter by status, platform, pipeline_stage (id/slug/name), folder, favorite, or a title search. Call get_card for one post's full detail (destinations + assets).",
1589
1589
  inputSchema: {
1590
1590
  status: z.enum(['draft', 'active', 'completed', 'archived']).optional().describe('Filter by lifecycle status.'),
1591
1591
  platform: z.enum(POST_PLATFORMS).optional().describe('Filter by the post platform.'),
@@ -1597,7 +1597,7 @@ export function registerTools(server, opts) {
1597
1597
  }, async (args, extra) => {
1598
1598
  try {
1599
1599
  const client = await getClient(extra);
1600
- return postListResult(await client.listPosts({
1600
+ return cardListResult(await client.listCards({
1601
1601
  status: args.status,
1602
1602
  platform: args.platform,
1603
1603
  pipelineStage: args.pipelineStage,
@@ -1610,46 +1610,147 @@ export function registerTools(server, opts) {
1610
1610
  return errorResult(err);
1611
1611
  }
1612
1612
  });
1613
- // -- get_post -------------------------------------------------------------
1614
- server.registerTool('get_post', {
1613
+ // -- get_card -------------------------------------------------------------
1614
+ server.registerTool('get_card', {
1615
1615
  title: 'Get Post',
1616
1616
  annotations: READ,
1617
1617
  description: "Get one post in full: its fields (title, description, script, notes, status, stage, schedule), plus its publish destinations and attached assets.",
1618
1618
  inputSchema: {
1619
- postId: z.string().describe('The post id from list_posts.'),
1619
+ postId: z.string().describe('The post id from list_cards.'),
1620
1620
  },
1621
1621
  }, async (args, extra) => {
1622
1622
  try {
1623
1623
  const client = await getClient(extra);
1624
- return postResult(await client.getPost(args.postId));
1624
+ return cardResult(await client.getCard(args.postId));
1625
1625
  }
1626
1626
  catch (err) {
1627
1627
  return errorResult(err);
1628
1628
  }
1629
1629
  });
1630
- // -- list_pipeline_stages -------------------------------------------------
1631
- server.registerTool('list_pipeline_stages', {
1630
+ // -- list_spaces ----------------------------------------------------------
1631
+ server.registerTool('list_spaces', {
1632
+ title: 'List Spaces',
1633
+ annotations: READ,
1634
+ description: "List the account's SPACES. A space is the planner's top-level container: Space > Stage > Card > Post. Each space has its own stages, so two spaces can both hold a stage called 'Published'. Call this FIRST to discover which board to work in, then pass a space id to list_stages, list_cards or create_card. Archived spaces are excluded unless includeArchived is set.",
1635
+ inputSchema: {
1636
+ includeArchived: z
1637
+ .boolean()
1638
+ .optional()
1639
+ .describe('Include archived spaces. Default false, matching the grid in the app.'),
1640
+ },
1641
+ }, async (args, extra) => {
1642
+ try {
1643
+ const client = await getClient(extra);
1644
+ return spaceListResult(await client.listSpaces({ includeArchived: args.includeArchived }));
1645
+ }
1646
+ catch (err) {
1647
+ return errorResult(err);
1648
+ }
1649
+ });
1650
+ // -- get_space ------------------------------------------------------------
1651
+ server.registerTool('get_space', {
1652
+ title: 'Get Space',
1653
+ annotations: READ,
1654
+ description: 'Return one space with its live card count. Use list_spaces to discover ids. The count excludes archived cards, and is the same number list_spaces reports for that space.',
1655
+ inputSchema: { spaceId: z.string().describe('The space id.') },
1656
+ }, async (args, extra) => {
1657
+ try {
1658
+ const client = await getClient(extra);
1659
+ return spaceResult(await client.getSpace(args.spaceId));
1660
+ }
1661
+ catch (err) {
1662
+ return errorResult(err);
1663
+ }
1664
+ });
1665
+ // -- create_space ---------------------------------------------------------
1666
+ server.registerTool('create_space', {
1667
+ title: 'Create Space',
1668
+ annotations: WRITE,
1669
+ description: "Create a space: a new planner board with its own stages. duplicateFrom copies another space's STAGES, never its cards, so the new board arrives with the columns and none of the work. Requires the pipeline:write scope.",
1670
+ inputSchema: {
1671
+ name: z.string().describe('The space name.'),
1672
+ coverUrl: z.string().optional().describe('A cover image URL for the space tile.'),
1673
+ duplicateFrom: z
1674
+ .string()
1675
+ .optional()
1676
+ .describe("Copy this space's stages into the new one. Cards are never copied."),
1677
+ },
1678
+ }, async (args, extra) => {
1679
+ try {
1680
+ const client = await getClient(extra);
1681
+ return spaceResult(await client.createSpace({
1682
+ name: args.name,
1683
+ coverUrl: args.coverUrl,
1684
+ duplicateFrom: args.duplicateFrom,
1685
+ }));
1686
+ }
1687
+ catch (err) {
1688
+ return errorResult(err);
1689
+ }
1690
+ });
1691
+ // -- update_space ---------------------------------------------------------
1692
+ server.registerTool('update_space', {
1693
+ title: 'Update Space',
1694
+ annotations: WRITE,
1695
+ description: "Rename a space or change its cover. This is a PATCH: a field you omit is left alone, so renaming does not disturb the cover. Pass coverUrl as an empty string to REMOVE the cover. To favorite or archive a space, use the `favorite` and `archive` tools with assetType 'space' instead. Requires the pipeline:write scope.",
1696
+ inputSchema: {
1697
+ spaceId: z.string().describe('The space id to update.'),
1698
+ name: z.string().optional().describe('A new name.'),
1699
+ coverUrl: z
1700
+ .string()
1701
+ .optional()
1702
+ .describe('A new cover image URL. Pass an empty string to remove the cover entirely.'),
1703
+ },
1704
+ }, async (args, extra) => {
1705
+ try {
1706
+ const client = await getClient(extra);
1707
+ // An empty string is how a tool caller says "remove it": JSON Schema has no way to
1708
+ // distinguish an omitted string from an explicit null in a plain string field.
1709
+ const coverUrl = args.coverUrl === undefined ? undefined : args.coverUrl === '' ? null : args.coverUrl;
1710
+ return spaceResult(await client.updateSpace(args.spaceId, { name: args.name, coverUrl }));
1711
+ }
1712
+ catch (err) {
1713
+ return errorResult(err);
1714
+ }
1715
+ });
1716
+ // -- delete_space ---------------------------------------------------------
1717
+ server.registerTool('delete_space', {
1718
+ title: 'Delete Space',
1719
+ annotations: WRITE,
1720
+ description: 'Delete a space. The server REFUSES a space that still holds cards and names the count, because the delete cascades to every card in it along with their covers, captions, destinations and schedules. Archive the space instead if you want it out of the way. Requires the pipeline:write scope.',
1721
+ inputSchema: { spaceId: z.string().describe('The space id to delete.') },
1722
+ }, async (args, extra) => {
1723
+ try {
1724
+ const client = await getClient(extra);
1725
+ await client.deleteSpace(args.spaceId);
1726
+ return spaceDeletedResult(args.spaceId);
1727
+ }
1728
+ catch (err) {
1729
+ return errorResult(err);
1730
+ }
1731
+ });
1732
+ // -- list_stages -------------------------------------------------
1733
+ server.registerTool('list_stages', {
1632
1734
  title: 'List Pipeline Stages',
1633
1735
  annotations: READ,
1634
- description: "List the account's pipeline stages, in order. Stages are user-customizable (renamed, reordered, added, removed), so call this to discover the real stages before placing a post; pass a stage's id (most stable), slug, or name to create_post / update_post.",
1736
+ description: "List the account's pipeline stages, in order. Stages are user-customizable (renamed, reordered, added, removed), so call this to discover the real stages before placing a post; pass a stage's id (most stable), slug, or name to create_card / update_card.",
1635
1737
  }, async (extra) => {
1636
1738
  try {
1637
1739
  const client = await getClient(extra);
1638
- return pipelineStageListResult(await client.listPipelineStages());
1740
+ return stageListResult(await client.listStages());
1639
1741
  }
1640
1742
  catch (err) {
1641
1743
  return errorResult(err);
1642
1744
  }
1643
1745
  });
1644
- // -- create_post ----------------------------------------------------------
1645
- server.registerTool('create_post', {
1746
+ // -- create_card ----------------------------------------------------------
1747
+ server.registerTool('create_card', {
1646
1748
  title: 'Create Post',
1647
1749
  annotations: WRITE,
1648
- description: "Create a content-pipeline post. The post is the container; attach platforms with add_post_destination and media with add_post_asset, then schedule_post or publish_post. `stage` accepts a stage id/slug/name (defaults to the first stage). Requires a key with the pipeline:write scope.",
1750
+ description: "Create a content-pipeline post. The post is the container; attach platforms with add_post_destination and media with add_post_asset, then schedule_post or publish_card. `stage` accepts a stage id/slug/name (defaults to the first stage). Requires a key with the pipeline:write scope.",
1649
1751
  inputSchema: {
1650
1752
  title: z.string().describe('Post title (required).'),
1651
1753
  platform: z.enum(POST_PLATFORMS).describe('Primary platform for the post.'),
1652
- description: z.string().optional().describe('Optional description / caption draft.'),
1653
1754
  stage: z.string().optional().describe('Pipeline stage id, slug, or name. Defaults to the first stage.'),
1654
1755
  coverUrl: z.string().optional().describe('Public URL for the post cover (the card thumbnail).'),
1655
1756
  coverOutputId: z
@@ -1664,10 +1765,9 @@ export function registerTools(server, opts) {
1664
1765
  }, async (args, extra) => {
1665
1766
  try {
1666
1767
  const client = await getClient(extra);
1667
- return postSummaryResult(await client.createPost({
1768
+ return postSummaryResult(await client.createCard({
1668
1769
  title: args.title,
1669
1770
  platform: args.platform,
1670
- description: args.description,
1671
1771
  stage: args.stage,
1672
1772
  coverUrl: args.coverUrl,
1673
1773
  coverOutputId: args.coverOutputId,
@@ -1678,15 +1778,14 @@ export function registerTools(server, opts) {
1678
1778
  return errorResult(err);
1679
1779
  }
1680
1780
  });
1681
- // -- update_post ----------------------------------------------------------
1682
- server.registerTool('update_post', {
1781
+ // -- update_card ----------------------------------------------------------
1782
+ server.registerTool('update_card', {
1683
1783
  title: 'Update Post',
1684
1784
  annotations: WRITE,
1685
- description: "Update a post: its fields (title, description, script, notes, status, platform, cover, pipeline stage), its DESTINATIONS (which platforms it publishes to), its ASSETS (the media on it, in order), and its SCHEDULE. destinations and assets are DECLARATIVE: pass the WHOLE set, because anything you leave out is removed. Destinations key on platform. Assets key on id, and THE ARRAY ORDER IS THE carousel ORDER, so reordering is just sending the same ids in a different order; keep an existing asset by id, add a new one by assetUrl or outputId. scheduledAt sets the time on the post AND every destination (pass null to clear); give a destination its own scheduledAt to override it for that platform. To publish NOW, use publish_post. Requires the pipeline:write scope.",
1785
+ description: "Update a post: its fields (title, description, script, notes, status, platform, cover, pipeline stage), its DESTINATIONS (which platforms it publishes to), its ASSETS (the media on it, in order), and its SCHEDULE. destinations and assets are DECLARATIVE: pass the WHOLE set, because anything you leave out is removed. Destinations key on platform. Assets key on id, and THE ARRAY ORDER IS THE carousel ORDER, so reordering is just sending the same ids in a different order; keep an existing asset by id, add a new one by assetUrl or outputId. scheduledAt sets the time on the post AND every destination (pass null to clear); give a destination its own scheduledAt to override it for that platform. To publish NOW, use publish_card. Requires the pipeline:write scope.",
1686
1786
  inputSchema: {
1687
1787
  postId: z.string().describe('The post id.'),
1688
1788
  title: z.string().optional(),
1689
- description: z.string().optional(),
1690
1789
  platform: z.enum(POST_PLATFORMS).optional(),
1691
1790
  status: z.enum(['draft', 'active', 'completed', 'archived']).optional(),
1692
1791
  stage: z.string().optional().describe('Move the post to this stage (id, slug, or name).'),
@@ -1721,7 +1820,7 @@ export function registerTools(server, opts) {
1721
1820
  const { postId, destinations, assets, ...input } = args;
1722
1821
  // The two declarative arrays are `unknown[]` in the schema (their entries are free-form objects the
1723
1822
  // server validates), so they are cast at this one boundary rather than duplicating the shape in zod.
1724
- return postSummaryResult(await client.updatePost(postId, {
1823
+ return postSummaryResult(await client.updateCard(postId, {
1725
1824
  ...input,
1726
1825
  ...(destinations !== undefined ? { destinations: destinations } : {}),
1727
1826
  ...(assets !== undefined ? { assets: assets } : {}),
@@ -1735,7 +1834,7 @@ export function registerTools(server, opts) {
1735
1834
  server.registerTool('list_tags', {
1736
1835
  title: 'List Tags',
1737
1836
  annotations: READ,
1738
- description: "List the account's tags (the organizational tag library). Set a post's tags with the `tags` field on create_post / update_post. A tag is just a lowercase name.",
1837
+ description: "List the account's tags (the organizational tag library). Set a post's tags with the `tags` field on create_card / update_card. A tag is just a lowercase name.",
1739
1838
  inputSchema: {},
1740
1839
  }, async (extra) => {
1741
1840
  try {
@@ -1750,7 +1849,7 @@ export function registerTools(server, opts) {
1750
1849
  server.registerTool('create_tag', {
1751
1850
  title: 'Create Tag',
1752
1851
  annotations: WRITE,
1753
- description: "Create a tag in the account's tag library (the name is lowercased). Tags organize posts; apply them with the `tags` field on create_post / update_post. Requires the pipeline:write scope.",
1852
+ description: "Create a tag in the account's tag library (the name is lowercased). Tags organize posts; apply them with the `tags` field on create_card / update_card. Requires the pipeline:write scope.",
1754
1853
  inputSchema: {
1755
1854
  name: z.string().describe('The tag name (lowercased on save).'),
1756
1855
  },
@@ -1767,7 +1866,7 @@ export function registerTools(server, opts) {
1767
1866
  server.registerTool('update_tag', {
1768
1867
  title: 'Update Tag',
1769
1868
  annotations: WRITE,
1770
- description: 'Rename a tag (preserves its assignments on all posts). To detach a tag from one post, set that post\'s `tags` without it via update_post. Requires the pipeline:write scope.',
1869
+ description: 'Rename a tag (preserves its assignments on all posts). To detach a tag from one post, set that post\'s `tags` without it via update_card. Requires the pipeline:write scope.',
1771
1870
  inputSchema: {
1772
1871
  tagId: z.string().describe('The tag id (from list_tags).'),
1773
1872
  name: z.string().describe('The new tag name (lowercased on save).'),
@@ -1785,7 +1884,7 @@ export function registerTools(server, opts) {
1785
1884
  server.registerTool('delete_tag', {
1786
1885
  title: 'Delete Tag',
1787
1886
  annotations: WRITE,
1788
- description: "Delete a tag from the account's library. This DESTROYS the tag and removes it from every post it was on. To just detach a tag from one post, set that post's `tags` without it via update_post instead. Requires the pipeline:write scope.",
1887
+ description: "Delete a tag from the account's library. This DESTROYS the tag and removes it from every post it was on. To just detach a tag from one post, set that post's `tags` without it via update_card instead. Requires the pipeline:write scope.",
1789
1888
  inputSchema: {
1790
1889
  tagId: z.string().describe('The tag id (from list_tags).'),
1791
1890
  },
@@ -1798,8 +1897,8 @@ export function registerTools(server, opts) {
1798
1897
  return errorResult(err);
1799
1898
  }
1800
1899
  });
1801
- // -- publish_post ---------------------------------------------------------
1802
- server.registerTool('publish_post', {
1900
+ // -- publish_card ---------------------------------------------------------
1901
+ server.registerTool('publish_card', {
1803
1902
  title: 'Publish Post',
1804
1903
  annotations: PUBLISH,
1805
1904
  description: "Publish a post NOW to its destinations (a single platform when `platform` is given, otherwise all). Each destination must have a connected account. Requires a key with the publish:write scope; holding that scope is the account owner's consent to autonomous publishing. Returns per-destination results.",
@@ -1810,7 +1909,7 @@ export function registerTools(server, opts) {
1810
1909
  }, async (args, extra) => {
1811
1910
  try {
1812
1911
  const client = await getClient(extra);
1813
- return publishResult(await client.publishPost(args.postId, { platform: args.platform }));
1912
+ return publishResult(await client.publishCard(args.postId, { platform: args.platform }));
1814
1913
  }
1815
1914
  catch (err) {
1816
1915
  return errorResult(err);
@@ -1932,7 +2031,7 @@ export function registerTools(server, opts) {
1932
2031
  server.registerTool('list_connected_accounts', {
1933
2032
  title: 'List Connected Accounts',
1934
2033
  annotations: READ,
1935
- description: "List the social accounts the owner has connected (the publish targets), default first. Use an account's id as connectedAccountId on add_post_destination, then publish_post. Read-only: connecting an account is done in the ContentHero app.",
2034
+ description: "List the social accounts the owner has connected (the publish targets), default first. Use an account's id as connectedAccountId on add_post_destination, then publish_card. Read-only: connecting an account is done in the ContentHero app.",
1936
2035
  }, async (extra) => {
1937
2036
  try {
1938
2037
  const client = await getClient(extra);
@@ -1980,10 +2079,10 @@ export function registerTools(server, opts) {
1980
2079
  server.registerTool('favorite', {
1981
2080
  title: 'Favorite',
1982
2081
  annotations: WRITE,
1983
- description: "Favorite or UNfavorite an asset: pass favorited:false to clear it (default true). For a top-level asset, pass assetType + id (post, voice, brand_kit, project, inspiration_content, gallery, transition). To favorite a single studio media variation (one image/video/audio slot from list_media / get_media), pass the output id + variationIndex (1-based) and omit assetType. Requires the favorites:write scope. Idempotent in both directions.",
2082
+ description: "Favorite or UNfavorite an asset: pass favorited:false to clear it (default true). For a top-level asset, pass assetType + id (card, voice, brand_kit, project, inspiration_content, gallery, transition, space). To favorite a single studio media variation (one image/video/audio slot from list_media / get_media), pass the output id + variationIndex (1-based) and omit assetType. Requires the favorites:write scope. Idempotent in both directions.",
1984
2083
  inputSchema: {
1985
2084
  assetType: z
1986
- .enum(['post', 'voice', 'brand_kit', 'project', 'inspiration_content', 'gallery', 'transition'])
2085
+ .enum(['card', 'voice', 'brand_kit', 'project', 'inspiration_content', 'gallery', 'transition', 'space'])
1987
2086
  .optional()
1988
2087
  .describe('The kind of asset. Required unless targeting a media variation via variationIndex.'),
1989
2088
  id: z.string().describe('The asset id (or studio output id when using variationIndex).'),
@@ -2011,10 +2110,10 @@ export function registerTools(server, opts) {
2011
2110
  server.registerTool('archive', {
2012
2111
  title: 'Archive',
2013
2112
  annotations: WRITE,
2014
- description: "Archive or UNarchive an asset: pass archived:false to restore it (default true). ContentHero never hard-deletes, so this is always reversible. For a top-level asset, pass assetType + id (post, brand_kit, brand_kit_section, project). To archive a single studio media variation, pass the output id + variationIndex (1-based) and omit assetType. Archiving a post sets its status to 'archived'; restoring returns it to 'draft'. Requires the favorites:write scope. Idempotent in both directions.",
2113
+ description: "Archive or UNarchive an asset: pass archived:false to restore it (default true). ContentHero never hard-deletes, so this is always reversible. For a top-level asset, pass assetType + id (card, brand_kit, brand_kit_section, project, space). To archive a single studio media variation, pass the output id + variationIndex (1-based) and omit assetType. Archiving a card sets its status to 'archived'; restoring returns it to 'draft'. Requires the favorites:write scope. Idempotent in both directions.",
2015
2114
  inputSchema: {
2016
2115
  assetType: z
2017
- .enum(['post', 'brand_kit', 'brand_kit_section', 'project'])
2116
+ .enum(['card', 'brand_kit', 'brand_kit_section', 'project', 'space'])
2018
2117
  .optional()
2019
2118
  .describe('The kind of asset. Required unless targeting a media variation via variationIndex.'),
2020
2119
  id: z.string().describe('The asset id (or studio output id when using variationIndex).'),