@socialneuron/mcp-server 1.5.0 → 1.5.1
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/CHANGELOG.md +9 -0
- package/dist/http.js +448 -76
- package/dist/index.js +448 -76
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -886,6 +886,13 @@ function registerIdeationTools(server) {
|
|
|
886
886
|
"Project ID to auto-load brand profile and performance context for prompt enrichment."
|
|
887
887
|
)
|
|
888
888
|
},
|
|
889
|
+
{
|
|
890
|
+
title: "Generate Content",
|
|
891
|
+
readOnlyHint: false,
|
|
892
|
+
destructiveHint: false,
|
|
893
|
+
idempotentHint: false,
|
|
894
|
+
openWorldHint: true
|
|
895
|
+
},
|
|
889
896
|
async ({
|
|
890
897
|
prompt,
|
|
891
898
|
content_type,
|
|
@@ -1049,6 +1056,13 @@ Content Type: ${content_type}`;
|
|
|
1049
1056
|
),
|
|
1050
1057
|
force_refresh: z.boolean().optional().describe("Skip the server-side cache and fetch fresh data.")
|
|
1051
1058
|
},
|
|
1059
|
+
{
|
|
1060
|
+
title: "Fetch Trends",
|
|
1061
|
+
readOnlyHint: true,
|
|
1062
|
+
destructiveHint: false,
|
|
1063
|
+
idempotentHint: false,
|
|
1064
|
+
openWorldHint: true
|
|
1065
|
+
},
|
|
1052
1066
|
async ({ source, category, niche, url, force_refresh }) => {
|
|
1053
1067
|
if ((source === "rss" || source === "url") && !url) {
|
|
1054
1068
|
return {
|
|
@@ -1153,6 +1167,13 @@ Content Type: ${content_type}`;
|
|
|
1153
1167
|
"Optional project ID to load platform voice overrides from brand profile."
|
|
1154
1168
|
)
|
|
1155
1169
|
},
|
|
1170
|
+
{
|
|
1171
|
+
title: "Adapt Content",
|
|
1172
|
+
readOnlyHint: false,
|
|
1173
|
+
destructiveHint: false,
|
|
1174
|
+
idempotentHint: false,
|
|
1175
|
+
openWorldHint: true
|
|
1176
|
+
},
|
|
1156
1177
|
async ({
|
|
1157
1178
|
content,
|
|
1158
1179
|
source_platform,
|
|
@@ -1312,7 +1333,7 @@ function sanitizeDbError(error) {
|
|
|
1312
1333
|
init_request_context();
|
|
1313
1334
|
|
|
1314
1335
|
// src/lib/version.ts
|
|
1315
|
-
var MCP_VERSION = "1.5.
|
|
1336
|
+
var MCP_VERSION = "1.5.1";
|
|
1316
1337
|
|
|
1317
1338
|
// src/tools/content.ts
|
|
1318
1339
|
var MAX_CREDITS_PER_RUN = Math.max(
|
|
@@ -1454,6 +1475,13 @@ function registerContentTools(server) {
|
|
|
1454
1475
|
),
|
|
1455
1476
|
response_format: z2.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
1456
1477
|
},
|
|
1478
|
+
{
|
|
1479
|
+
title: "Generate Video",
|
|
1480
|
+
readOnlyHint: false,
|
|
1481
|
+
destructiveHint: false,
|
|
1482
|
+
idempotentHint: false,
|
|
1483
|
+
openWorldHint: true
|
|
1484
|
+
},
|
|
1457
1485
|
async ({
|
|
1458
1486
|
prompt,
|
|
1459
1487
|
model,
|
|
@@ -1652,6 +1680,13 @@ function registerContentTools(server) {
|
|
|
1652
1680
|
),
|
|
1653
1681
|
response_format: z2.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
1654
1682
|
},
|
|
1683
|
+
{
|
|
1684
|
+
title: "Generate Image",
|
|
1685
|
+
readOnlyHint: false,
|
|
1686
|
+
destructiveHint: false,
|
|
1687
|
+
idempotentHint: false,
|
|
1688
|
+
openWorldHint: true
|
|
1689
|
+
},
|
|
1655
1690
|
async ({ prompt, model, aspect_ratio, image_url, response_format }) => {
|
|
1656
1691
|
const format = response_format ?? "text";
|
|
1657
1692
|
const startedAt = Date.now();
|
|
@@ -1815,6 +1850,13 @@ function registerContentTools(server) {
|
|
|
1815
1850
|
),
|
|
1816
1851
|
response_format: z2.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
1817
1852
|
},
|
|
1853
|
+
{
|
|
1854
|
+
title: "Check Job Status",
|
|
1855
|
+
readOnlyHint: true,
|
|
1856
|
+
destructiveHint: false,
|
|
1857
|
+
idempotentHint: true,
|
|
1858
|
+
openWorldHint: true
|
|
1859
|
+
},
|
|
1818
1860
|
async ({ job_id, response_format }) => {
|
|
1819
1861
|
const format = response_format ?? "text";
|
|
1820
1862
|
const startedAt = Date.now();
|
|
@@ -2012,6 +2054,13 @@ function registerContentTools(server) {
|
|
|
2012
2054
|
"Response format. Defaults to json for structured storyboard data."
|
|
2013
2055
|
)
|
|
2014
2056
|
},
|
|
2057
|
+
{
|
|
2058
|
+
title: "Create Storyboard",
|
|
2059
|
+
readOnlyHint: false,
|
|
2060
|
+
destructiveHint: false,
|
|
2061
|
+
idempotentHint: false,
|
|
2062
|
+
openWorldHint: true
|
|
2063
|
+
},
|
|
2015
2064
|
async ({
|
|
2016
2065
|
concept,
|
|
2017
2066
|
brand_context,
|
|
@@ -2192,6 +2241,13 @@ Return ONLY valid JSON in this exact format:
|
|
|
2192
2241
|
speed: z2.number().min(0.5).max(2).optional().describe("Speech speed multiplier. 1.0 is normal. Defaults to 1.0."),
|
|
2193
2242
|
response_format: z2.enum(["text", "json"]).optional().describe("Response format. Defaults to text.")
|
|
2194
2243
|
},
|
|
2244
|
+
{
|
|
2245
|
+
title: "Generate Voiceover",
|
|
2246
|
+
readOnlyHint: false,
|
|
2247
|
+
destructiveHint: false,
|
|
2248
|
+
idempotentHint: false,
|
|
2249
|
+
openWorldHint: true
|
|
2250
|
+
},
|
|
2195
2251
|
async ({ text, voice, speed, response_format }) => {
|
|
2196
2252
|
const format = response_format ?? "text";
|
|
2197
2253
|
const startedAt = Date.now();
|
|
@@ -2350,6 +2406,13 @@ Return ONLY valid JSON in this exact format:
|
|
|
2350
2406
|
project_id: z2.string().optional().describe("Project ID to associate the carousel with."),
|
|
2351
2407
|
response_format: z2.enum(["text", "json"]).optional().describe("Response format. Defaults to json.")
|
|
2352
2408
|
},
|
|
2409
|
+
{
|
|
2410
|
+
title: "Generate Carousel",
|
|
2411
|
+
readOnlyHint: false,
|
|
2412
|
+
destructiveHint: false,
|
|
2413
|
+
idempotentHint: false,
|
|
2414
|
+
openWorldHint: true
|
|
2415
|
+
},
|
|
2353
2416
|
async ({
|
|
2354
2417
|
topic,
|
|
2355
2418
|
template_id,
|
|
@@ -2684,6 +2747,13 @@ function registerDistributionTools(server) {
|
|
|
2684
2747
|
'If true, appends "Created with Social Neuron" to the caption. Default: false.'
|
|
2685
2748
|
)
|
|
2686
2749
|
},
|
|
2750
|
+
{
|
|
2751
|
+
title: "Schedule Post",
|
|
2752
|
+
readOnlyHint: false,
|
|
2753
|
+
destructiveHint: false,
|
|
2754
|
+
idempotentHint: false,
|
|
2755
|
+
openWorldHint: true
|
|
2756
|
+
},
|
|
2687
2757
|
async ({
|
|
2688
2758
|
media_url,
|
|
2689
2759
|
media_urls,
|
|
@@ -2835,6 +2905,13 @@ Created with Social Neuron`;
|
|
|
2835
2905
|
{
|
|
2836
2906
|
response_format: z3.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
2837
2907
|
},
|
|
2908
|
+
{
|
|
2909
|
+
title: "List Connected Accounts",
|
|
2910
|
+
readOnlyHint: true,
|
|
2911
|
+
destructiveHint: false,
|
|
2912
|
+
idempotentHint: true,
|
|
2913
|
+
openWorldHint: false
|
|
2914
|
+
},
|
|
2838
2915
|
async ({ response_format }) => {
|
|
2839
2916
|
const format = response_format ?? "text";
|
|
2840
2917
|
const supabase = getSupabaseClient();
|
|
@@ -2913,6 +2990,13 @@ Created with Social Neuron`;
|
|
|
2913
2990
|
limit: z3.number().min(1).max(50).optional().describe("Maximum number of posts to return. Defaults to 20."),
|
|
2914
2991
|
response_format: z3.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
2915
2992
|
},
|
|
2993
|
+
{
|
|
2994
|
+
title: "List Recent Posts",
|
|
2995
|
+
readOnlyHint: true,
|
|
2996
|
+
destructiveHint: false,
|
|
2997
|
+
idempotentHint: true,
|
|
2998
|
+
openWorldHint: false
|
|
2999
|
+
},
|
|
2916
3000
|
async ({ platform: platform2, status, days, limit, response_format }) => {
|
|
2917
3001
|
const format = response_format ?? "text";
|
|
2918
3002
|
const supabase = getSupabaseClient();
|
|
@@ -3012,7 +3096,7 @@ Created with Social Neuron`;
|
|
|
3012
3096
|
};
|
|
3013
3097
|
server.tool(
|
|
3014
3098
|
"find_next_slots",
|
|
3015
|
-
"Find
|
|
3099
|
+
"Find the next available posting time slots that avoid conflicts with already-scheduled posts. Uses engagement data from get_best_posting_times to rank slots. Call this before schedule_content_plan to pick optimal, non-overlapping times for each post.",
|
|
3016
3100
|
{
|
|
3017
3101
|
platforms: z3.array(
|
|
3018
3102
|
z3.enum([
|
|
@@ -3025,11 +3109,18 @@ Created with Social Neuron`;
|
|
|
3025
3109
|
"threads",
|
|
3026
3110
|
"bluesky"
|
|
3027
3111
|
])
|
|
3028
|
-
).min(1),
|
|
3112
|
+
).min(1).describe("Platforms to find posting slots for."),
|
|
3029
3113
|
count: z3.number().min(1).max(20).default(7).describe("Number of slots to find"),
|
|
3030
3114
|
start_after: z3.string().optional().describe("ISO datetime, defaults to now"),
|
|
3031
3115
|
min_gap_hours: z3.number().min(1).max(24).default(4).describe("Minimum gap between posts on same platform"),
|
|
3032
|
-
response_format: z3.enum(["text", "json"]).default("text")
|
|
3116
|
+
response_format: z3.enum(["text", "json"]).default("text").describe("Response format. Defaults to text.")
|
|
3117
|
+
},
|
|
3118
|
+
{
|
|
3119
|
+
title: "Find Next Posting Slots",
|
|
3120
|
+
readOnlyHint: true,
|
|
3121
|
+
destructiveHint: false,
|
|
3122
|
+
idempotentHint: true,
|
|
3123
|
+
openWorldHint: false
|
|
3033
3124
|
},
|
|
3034
3125
|
async ({
|
|
3035
3126
|
platforms,
|
|
@@ -3149,20 +3240,20 @@ Created with Social Neuron`;
|
|
|
3149
3240
|
plan: z3.object({
|
|
3150
3241
|
posts: z3.array(
|
|
3151
3242
|
z3.object({
|
|
3152
|
-
id: z3.string(),
|
|
3153
|
-
caption: z3.string(),
|
|
3154
|
-
platform: z3.string(),
|
|
3155
|
-
title: z3.string().optional(),
|
|
3156
|
-
media_url: z3.string().optional(),
|
|
3157
|
-
schedule_at: z3.string().optional(),
|
|
3158
|
-
hashtags: z3.array(z3.string()).optional()
|
|
3243
|
+
id: z3.string().describe("Unique post identifier from the content plan."),
|
|
3244
|
+
caption: z3.string().describe("Post caption/body text."),
|
|
3245
|
+
platform: z3.string().describe("Target platform name (e.g. instagram, youtube)."),
|
|
3246
|
+
title: z3.string().optional().describe("Post title, required for YouTube."),
|
|
3247
|
+
media_url: z3.string().optional().describe("Public or R2 signed URL for the post media."),
|
|
3248
|
+
schedule_at: z3.string().optional().describe("ISO 8601 UTC datetime to publish (e.g. 2026-03-20T14:00:00Z)."),
|
|
3249
|
+
hashtags: z3.array(z3.string()).optional().describe("Hashtags to append to the caption.")
|
|
3159
3250
|
})
|
|
3160
3251
|
)
|
|
3161
|
-
}).passthrough().optional(),
|
|
3252
|
+
}).passthrough().optional().describe("Inline content plan object with a posts array. Provide this or plan_id."),
|
|
3162
3253
|
plan_id: z3.string().uuid().optional().describe("Persisted content plan ID from content_plans table"),
|
|
3163
3254
|
auto_slot: z3.boolean().default(true).describe("Auto-assign time slots for posts without schedule_at"),
|
|
3164
3255
|
dry_run: z3.boolean().default(false).describe("Preview without actually scheduling"),
|
|
3165
|
-
response_format: z3.enum(["text", "json"]).default("text"),
|
|
3256
|
+
response_format: z3.enum(["text", "json"]).default("text").describe("Response format. Defaults to text."),
|
|
3166
3257
|
enforce_quality: z3.boolean().default(true).describe(
|
|
3167
3258
|
"When true, block scheduling for posts that fail quality checks."
|
|
3168
3259
|
),
|
|
@@ -3172,6 +3263,13 @@ Created with Social Neuron`;
|
|
|
3172
3263
|
batch_size: z3.number().int().min(1).max(10).default(4).describe("Concurrent schedule calls per platform batch."),
|
|
3173
3264
|
idempotency_seed: z3.string().max(128).optional().describe("Optional stable seed used when building idempotency keys.")
|
|
3174
3265
|
},
|
|
3266
|
+
{
|
|
3267
|
+
title: "Schedule Content Plan",
|
|
3268
|
+
readOnlyHint: false,
|
|
3269
|
+
destructiveHint: false,
|
|
3270
|
+
idempotentHint: false,
|
|
3271
|
+
openWorldHint: true
|
|
3272
|
+
},
|
|
3175
3273
|
async ({
|
|
3176
3274
|
plan,
|
|
3177
3275
|
plan_id,
|
|
@@ -3742,6 +3840,7 @@ function registerAnalyticsTools(server) {
|
|
|
3742
3840
|
limit: z4.number().min(1).max(100).optional().describe("Maximum number of posts to return. Defaults to 20."),
|
|
3743
3841
|
response_format: z4.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
3744
3842
|
},
|
|
3843
|
+
{ title: "Fetch Analytics", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
3745
3844
|
async ({ platform: platform2, days, content_id, limit, response_format }) => {
|
|
3746
3845
|
const format = response_format ?? "text";
|
|
3747
3846
|
const supabase = getSupabaseClient();
|
|
@@ -3919,6 +4018,13 @@ function registerAnalyticsTools(server) {
|
|
|
3919
4018
|
{
|
|
3920
4019
|
response_format: z4.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
3921
4020
|
},
|
|
4021
|
+
{
|
|
4022
|
+
title: "Refresh Platform Analytics",
|
|
4023
|
+
readOnlyHint: false,
|
|
4024
|
+
destructiveHint: false,
|
|
4025
|
+
idempotentHint: false,
|
|
4026
|
+
openWorldHint: true
|
|
4027
|
+
},
|
|
3922
4028
|
async ({ response_format }) => {
|
|
3923
4029
|
const format = response_format ?? "text";
|
|
3924
4030
|
const startedAt = Date.now();
|
|
@@ -4318,6 +4424,13 @@ function registerBrandTools(server) {
|
|
|
4318
4424
|
),
|
|
4319
4425
|
response_format: z5.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
4320
4426
|
},
|
|
4427
|
+
{
|
|
4428
|
+
title: "Extract Brand",
|
|
4429
|
+
readOnlyHint: true,
|
|
4430
|
+
destructiveHint: false,
|
|
4431
|
+
idempotentHint: true,
|
|
4432
|
+
openWorldHint: true
|
|
4433
|
+
},
|
|
4321
4434
|
async ({ url, response_format }) => {
|
|
4322
4435
|
const ssrfCheck = await validateUrlForSSRF(url);
|
|
4323
4436
|
if (!ssrfCheck.isValid) {
|
|
@@ -4401,6 +4514,13 @@ function registerBrandTools(server) {
|
|
|
4401
4514
|
project_id: z5.string().uuid().optional().describe("Project ID. Defaults to active project context."),
|
|
4402
4515
|
response_format: z5.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
4403
4516
|
},
|
|
4517
|
+
{
|
|
4518
|
+
title: "Get Brand Profile",
|
|
4519
|
+
readOnlyHint: true,
|
|
4520
|
+
destructiveHint: false,
|
|
4521
|
+
idempotentHint: true,
|
|
4522
|
+
openWorldHint: false
|
|
4523
|
+
},
|
|
4404
4524
|
async ({ project_id, response_format }) => {
|
|
4405
4525
|
const supabase = getSupabaseClient();
|
|
4406
4526
|
const userId = await getDefaultUserId();
|
|
@@ -4498,8 +4618,17 @@ function registerBrandTools(server) {
|
|
|
4498
4618
|
"product_showcase"
|
|
4499
4619
|
]).optional().describe("Extraction method metadata."),
|
|
4500
4620
|
overall_confidence: z5.number().min(0).max(1).optional().describe("Optional overall confidence score in range 0..1."),
|
|
4501
|
-
extraction_metadata: z5.record(z5.string(), z5.unknown()).optional()
|
|
4502
|
-
|
|
4621
|
+
extraction_metadata: z5.record(z5.string(), z5.unknown()).optional().describe(
|
|
4622
|
+
"Arbitrary key-value metadata about the extraction process."
|
|
4623
|
+
),
|
|
4624
|
+
response_format: z5.enum(["text", "json"]).optional().describe("Response format. Defaults to text.")
|
|
4625
|
+
},
|
|
4626
|
+
{
|
|
4627
|
+
title: "Save Brand Profile",
|
|
4628
|
+
readOnlyHint: false,
|
|
4629
|
+
destructiveHint: false,
|
|
4630
|
+
idempotentHint: false,
|
|
4631
|
+
openWorldHint: false
|
|
4503
4632
|
},
|
|
4504
4633
|
async ({
|
|
4505
4634
|
project_id,
|
|
@@ -4612,15 +4741,32 @@ Version: ${payload.version ?? "N/A"}`
|
|
|
4612
4741
|
"facebook",
|
|
4613
4742
|
"threads",
|
|
4614
4743
|
"bluesky"
|
|
4615
|
-
]),
|
|
4744
|
+
]).describe("Social platform to set voice overrides for."),
|
|
4616
4745
|
project_id: z5.string().uuid().optional().describe("Project ID. Defaults to active project context."),
|
|
4617
4746
|
samples: z5.string().max(3e3).optional().describe("3-5 real platform post examples for style anchoring."),
|
|
4618
|
-
tone: z5.array(z5.string()).optional()
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4747
|
+
tone: z5.array(z5.string()).optional().describe(
|
|
4748
|
+
'Tone descriptors for this platform (e.g. ["casual", "witty", "informative"]).'
|
|
4749
|
+
),
|
|
4750
|
+
style: z5.array(z5.string()).optional().describe(
|
|
4751
|
+
'Writing style tags (e.g. ["short-form", "emoji-heavy", "storytelling"]).'
|
|
4752
|
+
),
|
|
4753
|
+
avoid_patterns: z5.array(z5.string()).optional().describe(
|
|
4754
|
+
'Phrases or patterns the brand should never use on this platform (e.g. ["click here", "buy now"]).'
|
|
4755
|
+
),
|
|
4756
|
+
hashtag_strategy: z5.string().max(300).optional().describe(
|
|
4757
|
+
'Hashtag usage guidelines for this platform (e.g. "3-5 niche hashtags, no generic tags").'
|
|
4758
|
+
),
|
|
4759
|
+
cta_style: z5.string().max(300).optional().describe(
|
|
4760
|
+
'Preferred call-to-action style (e.g. "soft CTA with question" or "direct link in bio").'
|
|
4761
|
+
),
|
|
4762
|
+
response_format: z5.enum(["text", "json"]).optional().describe("Response format. Defaults to text.")
|
|
4763
|
+
},
|
|
4764
|
+
{
|
|
4765
|
+
title: "Update Platform Voice",
|
|
4766
|
+
readOnlyHint: false,
|
|
4767
|
+
destructiveHint: false,
|
|
4768
|
+
idempotentHint: false,
|
|
4769
|
+
openWorldHint: false
|
|
4624
4770
|
},
|
|
4625
4771
|
async ({
|
|
4626
4772
|
platform: platform2,
|
|
@@ -4869,6 +5015,13 @@ function registerScreenshotTools(server) {
|
|
|
4869
5015
|
"Extra milliseconds to wait after page load before capturing. Useful for animations. Defaults to 2000."
|
|
4870
5016
|
)
|
|
4871
5017
|
},
|
|
5018
|
+
{
|
|
5019
|
+
title: "Capture App Page",
|
|
5020
|
+
readOnlyHint: true,
|
|
5021
|
+
destructiveHint: false,
|
|
5022
|
+
idempotentHint: false,
|
|
5023
|
+
openWorldHint: false
|
|
5024
|
+
},
|
|
4872
5025
|
async ({ page: pageName, viewport, theme, selector, wait_ms }) => {
|
|
4873
5026
|
const startedAt = Date.now();
|
|
4874
5027
|
let rateLimitKey = "anonymous";
|
|
@@ -4989,6 +5142,13 @@ function registerScreenshotTools(server) {
|
|
|
4989
5142
|
),
|
|
4990
5143
|
wait_ms: z6.number().min(0).max(3e4).optional().describe("Extra milliseconds to wait after page load before capturing. Defaults to 1000.")
|
|
4991
5144
|
},
|
|
5145
|
+
{
|
|
5146
|
+
title: "Capture Screenshot",
|
|
5147
|
+
readOnlyHint: true,
|
|
5148
|
+
destructiveHint: false,
|
|
5149
|
+
idempotentHint: false,
|
|
5150
|
+
openWorldHint: true
|
|
5151
|
+
},
|
|
4992
5152
|
async ({ url, viewport, selector, output_path, wait_ms }) => {
|
|
4993
5153
|
const startedAt = Date.now();
|
|
4994
5154
|
let rateLimitKey = "anonymous";
|
|
@@ -5251,6 +5411,13 @@ function registerRemotionTools(server) {
|
|
|
5251
5411
|
"list_compositions",
|
|
5252
5412
|
"List all available Remotion video compositions defined in Social Neuron. Returns composition IDs, dimensions, duration, and descriptions. Use this to discover what videos can be rendered with render_demo_video.",
|
|
5253
5413
|
{},
|
|
5414
|
+
{
|
|
5415
|
+
title: "List Compositions",
|
|
5416
|
+
readOnlyHint: true,
|
|
5417
|
+
destructiveHint: false,
|
|
5418
|
+
idempotentHint: true,
|
|
5419
|
+
openWorldHint: false
|
|
5420
|
+
},
|
|
5254
5421
|
async () => {
|
|
5255
5422
|
const lines = [`${COMPOSITIONS.length} Remotion compositions available:`, ""];
|
|
5256
5423
|
for (const comp of COMPOSITIONS) {
|
|
@@ -5279,6 +5446,13 @@ function registerRemotionTools(server) {
|
|
|
5279
5446
|
"JSON string of input props to pass to the composition. Each composition accepts different props. Omit for defaults."
|
|
5280
5447
|
)
|
|
5281
5448
|
},
|
|
5449
|
+
{
|
|
5450
|
+
title: "Render Demo Video",
|
|
5451
|
+
readOnlyHint: false,
|
|
5452
|
+
destructiveHint: false,
|
|
5453
|
+
idempotentHint: false,
|
|
5454
|
+
openWorldHint: false
|
|
5455
|
+
},
|
|
5282
5456
|
async ({ composition_id, output_format, props }) => {
|
|
5283
5457
|
const startedAt = Date.now();
|
|
5284
5458
|
const userId = await getDefaultUserId();
|
|
@@ -5459,6 +5633,13 @@ function registerInsightsTools(server) {
|
|
|
5459
5633
|
limit: z8.number().min(1).max(50).optional().describe("Maximum number of insights to return. Defaults to 10."),
|
|
5460
5634
|
response_format: z8.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
5461
5635
|
},
|
|
5636
|
+
{
|
|
5637
|
+
title: "Get Performance Insights",
|
|
5638
|
+
readOnlyHint: true,
|
|
5639
|
+
destructiveHint: false,
|
|
5640
|
+
idempotentHint: true,
|
|
5641
|
+
openWorldHint: false
|
|
5642
|
+
},
|
|
5462
5643
|
async ({ insight_type, days, limit, response_format }) => {
|
|
5463
5644
|
const format = response_format ?? "text";
|
|
5464
5645
|
const supabase = getSupabaseClient();
|
|
@@ -5586,6 +5767,13 @@ function registerInsightsTools(server) {
|
|
|
5586
5767
|
days: z8.number().min(1).max(90).optional().describe("Number of days to analyze. Defaults to 30. Max 90."),
|
|
5587
5768
|
response_format: z8.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
5588
5769
|
},
|
|
5770
|
+
{
|
|
5771
|
+
title: "Get Best Posting Times",
|
|
5772
|
+
readOnlyHint: true,
|
|
5773
|
+
destructiveHint: false,
|
|
5774
|
+
idempotentHint: true,
|
|
5775
|
+
openWorldHint: false
|
|
5776
|
+
},
|
|
5589
5777
|
async ({ platform: platform2, days, response_format }) => {
|
|
5590
5778
|
const format = response_format ?? "text";
|
|
5591
5779
|
const supabase = getSupabaseClient();
|
|
@@ -5734,6 +5922,13 @@ function registerYouTubeAnalyticsTools(server) {
|
|
|
5734
5922
|
video_id: z9.string().optional().describe('YouTube video ID. Required when action is "video".'),
|
|
5735
5923
|
max_results: z9.number().min(1).max(50).optional().describe('Max videos to return for "topVideos" action. Defaults to 10.')
|
|
5736
5924
|
},
|
|
5925
|
+
{
|
|
5926
|
+
title: "Fetch YouTube Analytics",
|
|
5927
|
+
readOnlyHint: true,
|
|
5928
|
+
destructiveHint: false,
|
|
5929
|
+
idempotentHint: true,
|
|
5930
|
+
openWorldHint: true
|
|
5931
|
+
},
|
|
5737
5932
|
async ({ action, start_date, end_date, video_id, max_results }) => {
|
|
5738
5933
|
if (action === "video" && !video_id) {
|
|
5739
5934
|
return {
|
|
@@ -5852,6 +6047,13 @@ function registerCommentsTools(server) {
|
|
|
5852
6047
|
page_token: z10.string().optional().describe("Pagination cursor from previous list_comments response nextPageToken field. Omit for first page of results."),
|
|
5853
6048
|
response_format: z10.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
5854
6049
|
},
|
|
6050
|
+
{
|
|
6051
|
+
title: "List Comments",
|
|
6052
|
+
readOnlyHint: true,
|
|
6053
|
+
destructiveHint: false,
|
|
6054
|
+
idempotentHint: true,
|
|
6055
|
+
openWorldHint: true
|
|
6056
|
+
},
|
|
5855
6057
|
async ({ video_id, max_results, page_token, response_format }) => {
|
|
5856
6058
|
const format = response_format ?? "text";
|
|
5857
6059
|
const { data, error } = await callEdgeFunction("youtube-comments", {
|
|
@@ -5922,6 +6124,13 @@ function registerCommentsTools(server) {
|
|
|
5922
6124
|
text: z10.string().min(1).describe("The reply text."),
|
|
5923
6125
|
response_format: z10.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
5924
6126
|
},
|
|
6127
|
+
{
|
|
6128
|
+
title: "Reply to Comment",
|
|
6129
|
+
readOnlyHint: false,
|
|
6130
|
+
destructiveHint: false,
|
|
6131
|
+
idempotentHint: false,
|
|
6132
|
+
openWorldHint: true
|
|
6133
|
+
},
|
|
5925
6134
|
async ({ parent_id, text, response_format }) => {
|
|
5926
6135
|
const format = response_format ?? "text";
|
|
5927
6136
|
const startedAt = Date.now();
|
|
@@ -6003,6 +6212,13 @@ function registerCommentsTools(server) {
|
|
|
6003
6212
|
text: z10.string().min(1).describe("The comment text."),
|
|
6004
6213
|
response_format: z10.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6005
6214
|
},
|
|
6215
|
+
{
|
|
6216
|
+
title: "Post Comment",
|
|
6217
|
+
readOnlyHint: false,
|
|
6218
|
+
destructiveHint: false,
|
|
6219
|
+
idempotentHint: false,
|
|
6220
|
+
openWorldHint: true
|
|
6221
|
+
},
|
|
6006
6222
|
async ({ video_id, text, response_format }) => {
|
|
6007
6223
|
const format = response_format ?? "text";
|
|
6008
6224
|
const startedAt = Date.now();
|
|
@@ -6081,6 +6297,13 @@ function registerCommentsTools(server) {
|
|
|
6081
6297
|
moderation_status: z10.enum(["published", "rejected"]).describe('"published" to approve, "rejected" to hide.'),
|
|
6082
6298
|
response_format: z10.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6083
6299
|
},
|
|
6300
|
+
{
|
|
6301
|
+
title: "Moderate Comment",
|
|
6302
|
+
readOnlyHint: false,
|
|
6303
|
+
destructiveHint: false,
|
|
6304
|
+
idempotentHint: true,
|
|
6305
|
+
openWorldHint: true
|
|
6306
|
+
},
|
|
6084
6307
|
async ({ comment_id, moderation_status, response_format }) => {
|
|
6085
6308
|
const format = response_format ?? "text";
|
|
6086
6309
|
const startedAt = Date.now();
|
|
@@ -6166,6 +6389,13 @@ function registerCommentsTools(server) {
|
|
|
6166
6389
|
comment_id: z10.string().describe("The comment ID to delete."),
|
|
6167
6390
|
response_format: z10.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6168
6391
|
},
|
|
6392
|
+
{
|
|
6393
|
+
title: "Delete Comment",
|
|
6394
|
+
readOnlyHint: false,
|
|
6395
|
+
destructiveHint: true,
|
|
6396
|
+
idempotentHint: true,
|
|
6397
|
+
openWorldHint: true
|
|
6398
|
+
},
|
|
6169
6399
|
async ({ comment_id, response_format }) => {
|
|
6170
6400
|
const format = response_format ?? "text";
|
|
6171
6401
|
const startedAt = Date.now();
|
|
@@ -6314,12 +6544,19 @@ function asEnvelope7(data) {
|
|
|
6314
6544
|
function registerIdeationContextTools(server) {
|
|
6315
6545
|
server.tool(
|
|
6316
6546
|
"get_ideation_context",
|
|
6317
|
-
"
|
|
6547
|
+
"Load performance-derived context (top hooks, optimal timing, winning patterns) that should inform your next content generation. Call this before generate_content or plan_content_week to ground new content in what has actually performed well. Returns a promptInjection string ready to pass into generation tools.",
|
|
6318
6548
|
{
|
|
6319
6549
|
project_id: z11.string().uuid().optional().describe("Project ID to scope insights."),
|
|
6320
6550
|
days: z11.number().min(1).max(90).optional().describe("Lookback window for insights. Defaults to 30 days."),
|
|
6321
6551
|
response_format: z11.enum(["text", "json"]).optional().describe("Optional output format. Defaults to text.")
|
|
6322
6552
|
},
|
|
6553
|
+
{
|
|
6554
|
+
title: "Get Ideation Context",
|
|
6555
|
+
readOnlyHint: true,
|
|
6556
|
+
destructiveHint: false,
|
|
6557
|
+
idempotentHint: true,
|
|
6558
|
+
openWorldHint: false
|
|
6559
|
+
},
|
|
6323
6560
|
async ({ project_id, days, response_format }) => {
|
|
6324
6561
|
const supabase = getSupabaseClient();
|
|
6325
6562
|
const userId = await getDefaultUserId();
|
|
@@ -6449,6 +6686,13 @@ function registerCreditsTools(server) {
|
|
|
6449
6686
|
{
|
|
6450
6687
|
response_format: z12.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6451
6688
|
},
|
|
6689
|
+
{
|
|
6690
|
+
title: "Get Credit Balance",
|
|
6691
|
+
readOnlyHint: true,
|
|
6692
|
+
destructiveHint: false,
|
|
6693
|
+
idempotentHint: true,
|
|
6694
|
+
openWorldHint: false
|
|
6695
|
+
},
|
|
6452
6696
|
async ({ response_format }) => {
|
|
6453
6697
|
const supabase = getSupabaseClient();
|
|
6454
6698
|
const userId = await getDefaultUserId();
|
|
@@ -6502,6 +6746,13 @@ Monthly used: ${payload.monthlyUsed}` + (payload.monthlyLimit ? ` / ${payload.mo
|
|
|
6502
6746
|
{
|
|
6503
6747
|
response_format: z12.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6504
6748
|
},
|
|
6749
|
+
{
|
|
6750
|
+
title: "Get Budget Status",
|
|
6751
|
+
readOnlyHint: true,
|
|
6752
|
+
destructiveHint: false,
|
|
6753
|
+
idempotentHint: true,
|
|
6754
|
+
openWorldHint: false
|
|
6755
|
+
},
|
|
6505
6756
|
async ({ response_format }) => {
|
|
6506
6757
|
const budget = getCurrentBudgetStatus();
|
|
6507
6758
|
const payload = {
|
|
@@ -6555,11 +6806,18 @@ function asEnvelope9(data) {
|
|
|
6555
6806
|
function registerLoopSummaryTools(server) {
|
|
6556
6807
|
server.tool(
|
|
6557
6808
|
"get_loop_summary",
|
|
6558
|
-
"Get a
|
|
6809
|
+
"Get a single-call health check of the content feedback loop: brand profile status, recent content, and active insights. Call at the start of a session to decide what to do next. The response includes a recommendedNextAction field that tells you which tool to call.",
|
|
6559
6810
|
{
|
|
6560
6811
|
project_id: z13.string().uuid().optional().describe("Project ID. Defaults to active project context."),
|
|
6561
6812
|
response_format: z13.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6562
6813
|
},
|
|
6814
|
+
{
|
|
6815
|
+
title: "Get Loop Summary",
|
|
6816
|
+
readOnlyHint: true,
|
|
6817
|
+
destructiveHint: false,
|
|
6818
|
+
idempotentHint: true,
|
|
6819
|
+
openWorldHint: false
|
|
6820
|
+
},
|
|
6563
6821
|
async ({ project_id, response_format }) => {
|
|
6564
6822
|
const supabase = getSupabaseClient();
|
|
6565
6823
|
const userId = await getDefaultUserId();
|
|
@@ -6657,6 +6915,13 @@ function registerUsageTools(server) {
|
|
|
6657
6915
|
{
|
|
6658
6916
|
response_format: z14.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6659
6917
|
},
|
|
6918
|
+
{
|
|
6919
|
+
title: "Get MCP Usage",
|
|
6920
|
+
readOnlyHint: true,
|
|
6921
|
+
destructiveHint: false,
|
|
6922
|
+
idempotentHint: true,
|
|
6923
|
+
openWorldHint: false
|
|
6924
|
+
},
|
|
6660
6925
|
async ({ response_format }) => {
|
|
6661
6926
|
const format = response_format ?? "text";
|
|
6662
6927
|
const supabase = getSupabaseClient();
|
|
@@ -6746,6 +7011,13 @@ function registerAutopilotTools(server) {
|
|
|
6746
7011
|
active_only: z15.boolean().optional().describe("If true, only return active configs. Defaults to false (show all)."),
|
|
6747
7012
|
response_format: z15.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6748
7013
|
},
|
|
7014
|
+
{
|
|
7015
|
+
title: "List Autopilot Configs",
|
|
7016
|
+
readOnlyHint: true,
|
|
7017
|
+
destructiveHint: false,
|
|
7018
|
+
idempotentHint: true,
|
|
7019
|
+
openWorldHint: false
|
|
7020
|
+
},
|
|
6749
7021
|
async ({ active_only, response_format }) => {
|
|
6750
7022
|
const format = response_format ?? "text";
|
|
6751
7023
|
const supabase = getSupabaseClient();
|
|
@@ -6823,11 +7095,18 @@ ${"=".repeat(40)}
|
|
|
6823
7095
|
{
|
|
6824
7096
|
config_id: z15.string().uuid().describe("The autopilot config ID to update."),
|
|
6825
7097
|
is_active: z15.boolean().optional().describe("Enable or disable this autopilot config."),
|
|
6826
|
-
schedule_days: z15.array(z15.enum(["mon", "tue", "wed", "thu", "fri", "sat", "sun"])).optional().describe('Days of the week to run (e.g
|
|
7098
|
+
schedule_days: z15.array(z15.enum(["mon", "tue", "wed", "thu", "fri", "sat", "sun"]).describe("Three-letter lowercase day abbreviation.")).optional().describe('Days of the week to run (e.g. ["mon", "wed", "fri"]).'),
|
|
6827
7099
|
schedule_time: z15.string().optional().describe('Time to run in HH:MM format (24h, user timezone). E.g., "09:00".'),
|
|
6828
7100
|
max_credits_per_run: z15.number().optional().describe("Maximum credits per execution."),
|
|
6829
7101
|
max_credits_per_week: z15.number().optional().describe("Maximum credits per week.")
|
|
6830
7102
|
},
|
|
7103
|
+
{
|
|
7104
|
+
title: "Update Autopilot Config",
|
|
7105
|
+
readOnlyHint: false,
|
|
7106
|
+
destructiveHint: false,
|
|
7107
|
+
idempotentHint: true,
|
|
7108
|
+
openWorldHint: false
|
|
7109
|
+
},
|
|
6831
7110
|
async ({
|
|
6832
7111
|
config_id,
|
|
6833
7112
|
is_active,
|
|
@@ -6891,6 +7170,13 @@ Schedule: ${JSON.stringify(updated.schedule_config)}`
|
|
|
6891
7170
|
{
|
|
6892
7171
|
response_format: z15.enum(["text", "json"]).optional().describe("Optional response format. Defaults to text.")
|
|
6893
7172
|
},
|
|
7173
|
+
{
|
|
7174
|
+
title: "Get Autopilot Status",
|
|
7175
|
+
readOnlyHint: true,
|
|
7176
|
+
destructiveHint: false,
|
|
7177
|
+
idempotentHint: true,
|
|
7178
|
+
openWorldHint: false
|
|
7179
|
+
},
|
|
6894
7180
|
async ({ response_format }) => {
|
|
6895
7181
|
const format = response_format ?? "text";
|
|
6896
7182
|
const supabase = getSupabaseClient();
|
|
@@ -7010,7 +7296,14 @@ function registerExtractionTools(server) {
|
|
|
7010
7296
|
extract_type: z16.enum(["auto", "transcript", "article", "product"]).default("auto").describe("Type of extraction"),
|
|
7011
7297
|
include_comments: z16.boolean().default(false).describe("Include top comments (YouTube only)"),
|
|
7012
7298
|
max_results: z16.number().min(1).max(100).default(10).describe("Max comments to include"),
|
|
7013
|
-
response_format: z16.enum(["text", "json"]).default("text")
|
|
7299
|
+
response_format: z16.enum(["text", "json"]).default("text").describe("Response format. Defaults to text.")
|
|
7300
|
+
},
|
|
7301
|
+
{
|
|
7302
|
+
title: "Extract URL Content",
|
|
7303
|
+
readOnlyHint: true,
|
|
7304
|
+
destructiveHint: false,
|
|
7305
|
+
idempotentHint: true,
|
|
7306
|
+
openWorldHint: true
|
|
7014
7307
|
},
|
|
7015
7308
|
async ({
|
|
7016
7309
|
url,
|
|
@@ -7220,9 +7513,16 @@ function registerQualityTools(server) {
|
|
|
7220
7513
|
).min(1).describe("Target platforms"),
|
|
7221
7514
|
threshold: z17.number().min(0).max(35).default(26).describe("Minimum total score to pass (max 35, scored across 7 categories at 0-5 each). Default 26 (~75%). Use 20 for rough drafts, 28+ for final posts going to large audiences."),
|
|
7222
7515
|
brand_keyword: z17.string().optional().describe("Brand keyword for alignment check"),
|
|
7223
|
-
brand_avoid_patterns: z17.array(z17.string()).optional(),
|
|
7224
|
-
custom_banned_terms: z17.array(z17.string()).optional(),
|
|
7225
|
-
response_format: z17.enum(["text", "json"]).default("text")
|
|
7516
|
+
brand_avoid_patterns: z17.array(z17.string()).optional().describe("Phrases the brand should never use (e.g. competitor names, off-brand slang). Matched case-insensitively."),
|
|
7517
|
+
custom_banned_terms: z17.array(z17.string()).optional().describe("Additional banned words beyond the built-in safety list. Useful for industry-specific compliance terms."),
|
|
7518
|
+
response_format: z17.enum(["text", "json"]).default("text").describe("'text' for human-readable report, 'json' for structured scores suitable for pipeline automation.")
|
|
7519
|
+
},
|
|
7520
|
+
{
|
|
7521
|
+
title: "Quality Check",
|
|
7522
|
+
readOnlyHint: true,
|
|
7523
|
+
destructiveHint: false,
|
|
7524
|
+
idempotentHint: true,
|
|
7525
|
+
openWorldHint: false
|
|
7226
7526
|
},
|
|
7227
7527
|
async ({
|
|
7228
7528
|
caption,
|
|
@@ -7294,15 +7594,22 @@ function registerQualityTools(server) {
|
|
|
7294
7594
|
plan: z17.object({
|
|
7295
7595
|
posts: z17.array(
|
|
7296
7596
|
z17.object({
|
|
7297
|
-
id: z17.string(),
|
|
7298
|
-
caption: z17.string(),
|
|
7299
|
-
title: z17.string().optional(),
|
|
7300
|
-
platform: z17.string()
|
|
7597
|
+
id: z17.string().describe("Unique post identifier."),
|
|
7598
|
+
caption: z17.string().describe("Post caption/body text to quality-check."),
|
|
7599
|
+
title: z17.string().optional().describe("Post title (important for YouTube)."),
|
|
7600
|
+
platform: z17.string().describe("Target platform (e.g. instagram, youtube).")
|
|
7301
7601
|
})
|
|
7302
7602
|
)
|
|
7303
|
-
}).passthrough().describe("Content plan with posts array"),
|
|
7603
|
+
}).passthrough().describe("Content plan with posts array."),
|
|
7304
7604
|
threshold: z17.number().min(0).max(35).default(26).describe("Minimum total score to pass (max 35, scored across 7 categories at 0-5 each). Default 26 (~75%). Use 20 for rough drafts, 28+ for final posts going to large audiences."),
|
|
7305
|
-
response_format: z17.enum(["text", "json"]).default("text")
|
|
7605
|
+
response_format: z17.enum(["text", "json"]).default("text").describe("Response format. Defaults to text.")
|
|
7606
|
+
},
|
|
7607
|
+
{
|
|
7608
|
+
title: "Quality Check Plan",
|
|
7609
|
+
readOnlyHint: true,
|
|
7610
|
+
destructiveHint: false,
|
|
7611
|
+
idempotentHint: true,
|
|
7612
|
+
openWorldHint: false
|
|
7306
7613
|
},
|
|
7307
7614
|
async ({ plan, threshold, response_format }) => {
|
|
7308
7615
|
const startedAt = Date.now();
|
|
@@ -7503,7 +7810,14 @@ function registerPlanningTools(server) {
|
|
|
7503
7810
|
start_date: z18.string().optional().describe("ISO date, defaults to tomorrow"),
|
|
7504
7811
|
brand_voice: z18.string().optional().describe("Override brand voice description"),
|
|
7505
7812
|
project_id: z18.string().optional().describe("Project ID for brand/insights context"),
|
|
7506
|
-
response_format: z18.enum(["text", "json"]).default("json")
|
|
7813
|
+
response_format: z18.enum(["text", "json"]).default("json").describe("Response format. Defaults to json.")
|
|
7814
|
+
},
|
|
7815
|
+
{
|
|
7816
|
+
title: "Plan Content Week",
|
|
7817
|
+
readOnlyHint: false,
|
|
7818
|
+
destructiveHint: false,
|
|
7819
|
+
idempotentHint: false,
|
|
7820
|
+
openWorldHint: true
|
|
7507
7821
|
},
|
|
7508
7822
|
async ({
|
|
7509
7823
|
topic,
|
|
@@ -7821,12 +8135,19 @@ ${rawText.slice(0, 1e3)}`
|
|
|
7821
8135
|
"Save a content plan to the database for team review, approval workflows, and scheduled publishing. Creates a plan_id you can reference in get_content_plan, update_content_plan, and schedule_content_plan.",
|
|
7822
8136
|
{
|
|
7823
8137
|
plan: z18.object({
|
|
7824
|
-
topic: z18.string(),
|
|
7825
|
-
posts: z18.array(z18.record(z18.string(), z18.unknown()))
|
|
7826
|
-
}).passthrough(),
|
|
7827
|
-
project_id: z18.string().uuid().optional(),
|
|
7828
|
-
status: z18.enum(["draft", "in_review", "approved", "scheduled", "completed"]).default("draft"),
|
|
7829
|
-
response_format: z18.enum(["text", "json"]).default("json")
|
|
8138
|
+
topic: z18.string().describe("Content plan topic or theme."),
|
|
8139
|
+
posts: z18.array(z18.record(z18.string(), z18.unknown())).describe("Array of post objects to save.")
|
|
8140
|
+
}).passthrough().describe("Content plan object with topic and posts array."),
|
|
8141
|
+
project_id: z18.string().uuid().optional().describe("Project ID. Defaults to active project context."),
|
|
8142
|
+
status: z18.enum(["draft", "in_review", "approved", "scheduled", "completed"]).default("draft").describe("Initial plan status. Defaults to draft."),
|
|
8143
|
+
response_format: z18.enum(["text", "json"]).default("json").describe("Response format. Defaults to json.")
|
|
8144
|
+
},
|
|
8145
|
+
{
|
|
8146
|
+
title: "Save Content Plan",
|
|
8147
|
+
readOnlyHint: false,
|
|
8148
|
+
destructiveHint: false,
|
|
8149
|
+
idempotentHint: false,
|
|
8150
|
+
openWorldHint: false
|
|
7830
8151
|
},
|
|
7831
8152
|
async ({ plan, project_id, status, response_format }) => {
|
|
7832
8153
|
const startedAt = Date.now();
|
|
@@ -7924,10 +8245,17 @@ ${rawText.slice(0, 1e3)}`
|
|
|
7924
8245
|
);
|
|
7925
8246
|
server.tool(
|
|
7926
8247
|
"get_content_plan",
|
|
7927
|
-
"Retrieve a
|
|
8248
|
+
"Retrieve a saved content plan to review its posts, status, and applied insights. Use after plan_content_week or save_content_plan to inspect what was generated. Feed the result into update_content_plan to revise posts or submit_content_plan_for_approval to start the review workflow.",
|
|
7928
8249
|
{
|
|
7929
8250
|
plan_id: z18.string().uuid().describe("Persisted content plan ID"),
|
|
7930
|
-
response_format: z18.enum(["text", "json"]).default("json")
|
|
8251
|
+
response_format: z18.enum(["text", "json"]).default("json").describe("Response format. Defaults to json.")
|
|
8252
|
+
},
|
|
8253
|
+
{
|
|
8254
|
+
title: "Get Content Plan",
|
|
8255
|
+
readOnlyHint: true,
|
|
8256
|
+
destructiveHint: false,
|
|
8257
|
+
idempotentHint: true,
|
|
8258
|
+
openWorldHint: false
|
|
7931
8259
|
},
|
|
7932
8260
|
async ({ plan_id, response_format }) => {
|
|
7933
8261
|
const supabase = getSupabaseClient();
|
|
@@ -7992,25 +8320,32 @@ ${rawText.slice(0, 1e3)}`
|
|
|
7992
8320
|
);
|
|
7993
8321
|
server.tool(
|
|
7994
8322
|
"update_content_plan",
|
|
7995
|
-
"
|
|
8323
|
+
"Revise specific posts in a saved content plan -- edit captions, hooks, hashtags, schedule times, or mark posts as approved/rejected. Call after reviewing a plan with get_content_plan. When all posts are approved, the plan status auto-advances so it can be scheduled.",
|
|
7996
8324
|
{
|
|
7997
|
-
plan_id: z18.string().uuid(),
|
|
8325
|
+
plan_id: z18.string().uuid().describe("Content plan ID to update."),
|
|
7998
8326
|
post_updates: z18.array(
|
|
7999
8327
|
z18.object({
|
|
8000
|
-
post_id: z18.string(),
|
|
8001
|
-
caption: z18.string().optional(),
|
|
8002
|
-
title: z18.string().optional(),
|
|
8003
|
-
hashtags: z18.array(z18.string()).optional(),
|
|
8004
|
-
hook: z18.string().optional(),
|
|
8005
|
-
angle: z18.string().optional(),
|
|
8006
|
-
visual_direction: z18.string().optional(),
|
|
8007
|
-
media_url: z18.string().optional(),
|
|
8008
|
-
schedule_at: z18.string().optional(),
|
|
8009
|
-
platform: z18.string().optional(),
|
|
8010
|
-
status: z18.enum(["approved", "rejected", "needs_edit"]).optional()
|
|
8328
|
+
post_id: z18.string().describe("ID of the post to update within this plan."),
|
|
8329
|
+
caption: z18.string().optional().describe("Revised caption/body text."),
|
|
8330
|
+
title: z18.string().optional().describe("Revised post title."),
|
|
8331
|
+
hashtags: z18.array(z18.string()).optional().describe("Revised hashtags array."),
|
|
8332
|
+
hook: z18.string().optional().describe("Revised attention-grabbing opening line."),
|
|
8333
|
+
angle: z18.string().optional().describe("Revised content angle or perspective."),
|
|
8334
|
+
visual_direction: z18.string().optional().describe("Revised visual/media direction notes."),
|
|
8335
|
+
media_url: z18.string().optional().describe("Revised media URL (public or R2 signed URL)."),
|
|
8336
|
+
schedule_at: z18.string().optional().describe("Revised ISO 8601 UTC publish datetime."),
|
|
8337
|
+
platform: z18.string().optional().describe("Revised target platform."),
|
|
8338
|
+
status: z18.enum(["approved", "rejected", "needs_edit"]).optional().describe("Review status for this post.")
|
|
8011
8339
|
})
|
|
8012
|
-
).min(1),
|
|
8013
|
-
response_format: z18.enum(["text", "json"]).default("json")
|
|
8340
|
+
).min(1).describe("Array of post-level updates to apply."),
|
|
8341
|
+
response_format: z18.enum(["text", "json"]).default("json").describe("Response format. Defaults to json.")
|
|
8342
|
+
},
|
|
8343
|
+
{
|
|
8344
|
+
title: "Update Content Plan",
|
|
8345
|
+
readOnlyHint: false,
|
|
8346
|
+
destructiveHint: false,
|
|
8347
|
+
idempotentHint: true,
|
|
8348
|
+
openWorldHint: false
|
|
8014
8349
|
},
|
|
8015
8350
|
async ({ plan_id, post_updates, response_format }) => {
|
|
8016
8351
|
const supabase = getSupabaseClient();
|
|
@@ -8111,10 +8446,17 @@ ${rawText.slice(0, 1e3)}`
|
|
|
8111
8446
|
);
|
|
8112
8447
|
server.tool(
|
|
8113
8448
|
"submit_content_plan_for_approval",
|
|
8114
|
-
"
|
|
8449
|
+
"Submit an entire saved content plan for team review in one call -- creates approval items for every post and sets the plan to in_review status. Call after plan_content_week and any update_content_plan edits are done. Use list_plan_approvals to track reviewer decisions.",
|
|
8450
|
+
{
|
|
8451
|
+
plan_id: z18.string().uuid().describe("Content plan ID to submit for review."),
|
|
8452
|
+
response_format: z18.enum(["text", "json"]).default("json").describe("Response format. Defaults to json.")
|
|
8453
|
+
},
|
|
8115
8454
|
{
|
|
8116
|
-
|
|
8117
|
-
|
|
8455
|
+
title: "Submit Plan for Approval",
|
|
8456
|
+
readOnlyHint: false,
|
|
8457
|
+
destructiveHint: false,
|
|
8458
|
+
idempotentHint: true,
|
|
8459
|
+
openWorldHint: false
|
|
8118
8460
|
},
|
|
8119
8461
|
async ({ plan_id, response_format }) => {
|
|
8120
8462
|
const supabase = getSupabaseClient();
|
|
@@ -8238,21 +8580,28 @@ async function assertProjectAccess(supabase, userId, projectId) {
|
|
|
8238
8580
|
function registerPlanApprovalTools(server) {
|
|
8239
8581
|
server.tool(
|
|
8240
8582
|
"create_plan_approvals",
|
|
8241
|
-
"Create
|
|
8583
|
+
"Create individual approval items for posts you supply explicitly, useful when building a custom approval queue outside the standard plan workflow. Requires the post array as input. Use list_plan_approvals to check status afterward, and respond_plan_approval to approve or reject each item.",
|
|
8242
8584
|
{
|
|
8243
8585
|
plan_id: z19.string().uuid().describe("Content plan ID"),
|
|
8244
8586
|
posts: z19.array(
|
|
8245
8587
|
z19.object({
|
|
8246
|
-
id: z19.string(),
|
|
8247
|
-
platform: z19.string().optional(),
|
|
8248
|
-
caption: z19.string().optional(),
|
|
8249
|
-
title: z19.string().optional(),
|
|
8250
|
-
media_url: z19.string().optional(),
|
|
8251
|
-
schedule_at: z19.string().optional()
|
|
8588
|
+
id: z19.string().describe("Unique post identifier from the content plan."),
|
|
8589
|
+
platform: z19.string().optional().describe("Target platform (e.g. instagram, youtube)."),
|
|
8590
|
+
caption: z19.string().optional().describe("Post caption/body text."),
|
|
8591
|
+
title: z19.string().optional().describe("Post title, used by YouTube and LinkedIn articles."),
|
|
8592
|
+
media_url: z19.string().optional().describe("Public or R2 signed URL for the post media."),
|
|
8593
|
+
schedule_at: z19.string().optional().describe("ISO 8601 UTC datetime to publish (e.g. 2026-03-20T14:00:00Z).")
|
|
8252
8594
|
}).passthrough()
|
|
8253
8595
|
).min(1).describe("Posts to create approval entries for."),
|
|
8254
8596
|
project_id: z19.string().uuid().optional().describe("Project ID. Defaults to active project context."),
|
|
8255
|
-
response_format: z19.enum(["text", "json"]).optional()
|
|
8597
|
+
response_format: z19.enum(["text", "json"]).optional().describe("Response format. Defaults to text.")
|
|
8598
|
+
},
|
|
8599
|
+
{
|
|
8600
|
+
title: "Create Plan Approvals",
|
|
8601
|
+
readOnlyHint: false,
|
|
8602
|
+
destructiveHint: false,
|
|
8603
|
+
idempotentHint: false,
|
|
8604
|
+
openWorldHint: false
|
|
8256
8605
|
},
|
|
8257
8606
|
async ({ plan_id, posts, project_id, response_format }) => {
|
|
8258
8607
|
const supabase = getSupabaseClient();
|
|
@@ -8332,8 +8681,15 @@ function registerPlanApprovalTools(server) {
|
|
|
8332
8681
|
"List MCP-native approval items for a specific content plan.",
|
|
8333
8682
|
{
|
|
8334
8683
|
plan_id: z19.string().uuid().describe("Content plan ID"),
|
|
8335
|
-
status: z19.enum(["pending", "approved", "rejected", "edited"]).optional(),
|
|
8336
|
-
response_format: z19.enum(["text", "json"]).optional()
|
|
8684
|
+
status: z19.enum(["pending", "approved", "rejected", "edited"]).optional().describe("Filter approvals by status. Omit to return all statuses."),
|
|
8685
|
+
response_format: z19.enum(["text", "json"]).optional().describe("Response format. Defaults to text.")
|
|
8686
|
+
},
|
|
8687
|
+
{
|
|
8688
|
+
title: "List Plan Approvals",
|
|
8689
|
+
readOnlyHint: true,
|
|
8690
|
+
destructiveHint: false,
|
|
8691
|
+
idempotentHint: true,
|
|
8692
|
+
openWorldHint: false
|
|
8337
8693
|
},
|
|
8338
8694
|
async ({ plan_id, status, response_format }) => {
|
|
8339
8695
|
const supabase = getSupabaseClient();
|
|
@@ -8400,10 +8756,19 @@ function registerPlanApprovalTools(server) {
|
|
|
8400
8756
|
"Approve, reject, or edit a pending plan approval item.",
|
|
8401
8757
|
{
|
|
8402
8758
|
approval_id: z19.string().uuid().describe("Approval item ID"),
|
|
8403
|
-
decision: z19.enum(["approved", "rejected", "edited"]),
|
|
8404
|
-
edited_post: z19.record(z19.string(), z19.unknown()).optional()
|
|
8405
|
-
|
|
8406
|
-
|
|
8759
|
+
decision: z19.enum(["approved", "rejected", "edited"]).describe("Approval decision for this post."),
|
|
8760
|
+
edited_post: z19.record(z19.string(), z19.unknown()).optional().describe(
|
|
8761
|
+
'Revised post fields when decision is "edited" (e.g. {caption: "...", hashtags: [...]}).'
|
|
8762
|
+
),
|
|
8763
|
+
reason: z19.string().max(1e3).optional().describe("Optional reason for the decision, visible to the plan author."),
|
|
8764
|
+
response_format: z19.enum(["text", "json"]).optional().describe("Response format. Defaults to text.")
|
|
8765
|
+
},
|
|
8766
|
+
{
|
|
8767
|
+
title: "Respond to Plan Approval",
|
|
8768
|
+
readOnlyHint: false,
|
|
8769
|
+
destructiveHint: false,
|
|
8770
|
+
idempotentHint: true,
|
|
8771
|
+
openWorldHint: false
|
|
8407
8772
|
},
|
|
8408
8773
|
async ({ approval_id, decision, edited_post, reason, response_format }) => {
|
|
8409
8774
|
const supabase = getSupabaseClient();
|
|
@@ -8840,6 +9205,13 @@ function registerDiscoveryTools(server) {
|
|
|
8840
9205
|
'Detail level: "name" for just tool names, "summary" for names + descriptions, "full" for complete info including scope and module'
|
|
8841
9206
|
)
|
|
8842
9207
|
},
|
|
9208
|
+
{
|
|
9209
|
+
title: "Search Tools",
|
|
9210
|
+
readOnlyHint: true,
|
|
9211
|
+
destructiveHint: false,
|
|
9212
|
+
idempotentHint: true,
|
|
9213
|
+
openWorldHint: false
|
|
9214
|
+
},
|
|
8843
9215
|
async ({ query, module, scope, detail }) => {
|
|
8844
9216
|
let results = [...TOOL_CATALOG];
|
|
8845
9217
|
if (query) {
|