@socialneuron/mcp-server 1.5.1 → 1.5.2

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 CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to `@socialneuron/mcp-server` will be documented in this file.
4
4
 
5
+ ## [1.5.2] - 2026-03-20
6
+
7
+ ### Added
8
+ - **Error recovery hints**: All 47 error paths now include actionable recovery guidance — agents know what to call next when something fails (e.g., "Call get_credit_balance to check remaining credits" or "Verify platform OAuth with list_connected_accounts").
9
+ - Central `formatToolError()` helper with 9 error categories: rate limits, credits, OAuth, generation, not-found, access, SSRF, scheduling, and plan validation.
10
+ - 18 new tests for error recovery formatting.
11
+
5
12
  ## [1.5.1] - 2026-03-20
6
13
 
7
14
  ### Added
package/dist/http.js CHANGED
@@ -853,6 +853,41 @@ function checkRateLimit(category, key) {
853
853
 
854
854
  // src/tools/ideation.ts
855
855
  init_supabase();
856
+
857
+ // src/lib/tool-errors.ts
858
+ function formatToolError(rawMessage) {
859
+ const msg = rawMessage.toLowerCase();
860
+ if (msg.includes("rate limit") || msg.includes("too many requests")) {
861
+ return `${rawMessage} Reduce request frequency or wait before retrying.`;
862
+ }
863
+ if (msg.includes("insufficient credit") || msg.includes("budget") || msg.includes("spending cap")) {
864
+ return `${rawMessage} Call get_credit_balance to check remaining credits. Consider a cheaper model or wait for monthly refresh.`;
865
+ }
866
+ if (msg.includes("oauth") || msg.includes("token expired") || msg.includes("not connected") || msg.includes("reconnect")) {
867
+ return `${rawMessage} Call list_connected_accounts to check status. User may need to reconnect at socialneuron.com/settings/connections.`;
868
+ }
869
+ if (msg.includes("generation failed") || msg.includes("failed to start") || msg.includes("no job id") || msg.includes("could not be parsed")) {
870
+ return `${rawMessage} Try simplifying the prompt, using a different model, or check credits with get_credit_balance.`;
871
+ }
872
+ if (msg.includes("not found") || msg.includes("no ") && msg.includes(" found")) {
873
+ return `${rawMessage} Verify the ID is correct \u2014 use the corresponding list tool to find valid IDs.`;
874
+ }
875
+ if (msg.includes("not accessible") || msg.includes("unauthorized") || msg.includes("permission")) {
876
+ return `${rawMessage} Check API key scopes with get_credit_balance. A higher-tier plan may be required.`;
877
+ }
878
+ if (msg.includes("ssrf") || msg.includes("url blocked")) {
879
+ return `${rawMessage} The URL was blocked for security. Use a publicly accessible HTTPS URL.`;
880
+ }
881
+ if (msg.includes("failed to schedule") || msg.includes("scheduling failed")) {
882
+ return `${rawMessage} Verify platform OAuth is active with list_connected_accounts, then retry.`;
883
+ }
884
+ if (msg.includes("no posts") || msg.includes("plan") && msg.includes("has no")) {
885
+ return `${rawMessage} Generate a plan with plan_content_week first, then save with save_content_plan.`;
886
+ }
887
+ return rawMessage;
888
+ }
889
+
890
+ // src/tools/ideation.ts
856
891
  function registerIdeationTools(server) {
857
892
  server.tool(
858
893
  "generate_content",
@@ -1026,7 +1061,7 @@ Content Type: ${content_type}`;
1026
1061
  content: [
1027
1062
  {
1028
1063
  type: "text",
1029
- text: `Content generation failed: ${error}`
1064
+ text: formatToolError(`Content generation failed: ${error}`)
1030
1065
  }
1031
1066
  ],
1032
1067
  isError: true
@@ -1091,7 +1126,7 @@ Content Type: ${content_type}`;
1091
1126
  content: [
1092
1127
  {
1093
1128
  type: "text",
1094
- text: `Failed to fetch trends: ${error}`
1129
+ text: formatToolError(`Failed to fetch trends: ${error}`)
1095
1130
  }
1096
1131
  ],
1097
1132
  isError: true
@@ -1259,7 +1294,7 @@ ${content}`,
1259
1294
  content: [
1260
1295
  {
1261
1296
  type: "text",
1262
- text: `Content adaptation failed: ${error}`
1297
+ text: formatToolError(`Content adaptation failed: ${error}`)
1263
1298
  }
1264
1299
  ],
1265
1300
  isError: true
@@ -1333,7 +1368,7 @@ function sanitizeDbError(error) {
1333
1368
  init_request_context();
1334
1369
 
1335
1370
  // src/lib/version.ts
1336
- var MCP_VERSION = "1.5.1";
1371
+ var MCP_VERSION = "1.5.2";
1337
1372
 
1338
1373
  // src/tools/content.ts
1339
1374
  var MAX_CREDITS_PER_RUN = Math.max(
@@ -1573,7 +1608,7 @@ function registerContentTools(server) {
1573
1608
  content: [
1574
1609
  {
1575
1610
  type: "text",
1576
- text: `Video generation failed to start: ${error}`
1611
+ text: formatToolError(`Video generation failed to start: ${error}`)
1577
1612
  }
1578
1613
  ],
1579
1614
  isError: true
@@ -1590,7 +1625,7 @@ function registerContentTools(server) {
1590
1625
  content: [
1591
1626
  {
1592
1627
  type: "text",
1593
- text: "Video generation failed: no job ID returned."
1628
+ text: formatToolError("Video generation failed: no job ID returned.")
1594
1629
  }
1595
1630
  ],
1596
1631
  isError: true
@@ -1766,7 +1801,7 @@ function registerContentTools(server) {
1766
1801
  content: [
1767
1802
  {
1768
1803
  type: "text",
1769
- text: `Image generation failed to start: ${error}`
1804
+ text: formatToolError(`Image generation failed to start: ${error}`)
1770
1805
  }
1771
1806
  ],
1772
1807
  isError: true
@@ -1783,7 +1818,7 @@ function registerContentTools(server) {
1783
1818
  content: [
1784
1819
  {
1785
1820
  type: "text",
1786
- text: "Image generation failed: no job ID returned."
1821
+ text: formatToolError("Image generation failed: no job ID returned.")
1787
1822
  }
1788
1823
  ],
1789
1824
  isError: true
@@ -1907,7 +1942,7 @@ function registerContentTools(server) {
1907
1942
  content: [
1908
1943
  {
1909
1944
  type: "text",
1910
- text: `Failed to look up job: ${sanitizeDbError(jobError)}`
1945
+ text: formatToolError(`Failed to look up job: ${sanitizeDbError(jobError)}`)
1911
1946
  }
1912
1947
  ],
1913
1948
  isError: true
@@ -1924,7 +1959,7 @@ function registerContentTools(server) {
1924
1959
  content: [
1925
1960
  {
1926
1961
  type: "text",
1927
- text: `No job found with ID "${job_id}". The ID may be incorrect or the job has expired.`
1962
+ text: formatToolError(`No job found with ID "${job_id}". The ID may be incorrect or the job has expired.`)
1928
1963
  }
1929
1964
  ],
1930
1965
  isError: true
@@ -2172,7 +2207,7 @@ Return ONLY valid JSON in this exact format:
2172
2207
  content: [
2173
2208
  {
2174
2209
  type: "text",
2175
- text: `Storyboard generation failed: ${error}`
2210
+ text: formatToolError(`Storyboard generation failed: ${error}`)
2176
2211
  }
2177
2212
  ],
2178
2213
  isError: true
@@ -2307,7 +2342,7 @@ Return ONLY valid JSON in this exact format:
2307
2342
  content: [
2308
2343
  {
2309
2344
  type: "text",
2310
- text: `Voiceover generation failed: ${error}`
2345
+ text: formatToolError(`Voiceover generation failed: ${error}`)
2311
2346
  }
2312
2347
  ],
2313
2348
  isError: true
@@ -2324,7 +2359,7 @@ Return ONLY valid JSON in this exact format:
2324
2359
  content: [
2325
2360
  {
2326
2361
  type: "text",
2327
- text: "Voiceover generation failed: no audio URL returned."
2362
+ text: formatToolError("Voiceover generation failed: no audio URL returned.")
2328
2363
  }
2329
2364
  ],
2330
2365
  isError: true
@@ -2487,7 +2522,7 @@ Return ONLY valid JSON in this exact format:
2487
2522
  content: [
2488
2523
  {
2489
2524
  type: "text",
2490
- text: `Carousel generation failed: ${error}`
2525
+ text: formatToolError(`Carousel generation failed: ${error}`)
2491
2526
  }
2492
2527
  ],
2493
2528
  isError: true
@@ -2834,7 +2869,7 @@ Created with Social Neuron`;
2834
2869
  content: [
2835
2870
  {
2836
2871
  type: "text",
2837
- text: `Failed to schedule post: ${error}`
2872
+ text: formatToolError(`Failed to schedule post: ${error}`)
2838
2873
  }
2839
2874
  ],
2840
2875
  isError: true
@@ -2922,7 +2957,7 @@ Created with Social Neuron`;
2922
2957
  content: [
2923
2958
  {
2924
2959
  type: "text",
2925
- text: `Failed to list connected accounts: ${sanitizeDbError(error)}`
2960
+ text: formatToolError(`Failed to list connected accounts: ${sanitizeDbError(error)}`)
2926
2961
  }
2927
2962
  ],
2928
2963
  isError: true
@@ -3021,7 +3056,7 @@ Created with Social Neuron`;
3021
3056
  content: [
3022
3057
  {
3023
3058
  type: "text",
3024
- text: `Failed to list posts: ${sanitizeDbError(error)}`
3059
+ text: formatToolError(`Failed to list posts: ${sanitizeDbError(error)}`)
3025
3060
  }
3026
3061
  ],
3027
3062
  isError: true
@@ -3226,7 +3261,7 @@ Created with Social Neuron`;
3226
3261
  });
3227
3262
  return {
3228
3263
  content: [
3229
- { type: "text", text: `Failed to find slots: ${message}` }
3264
+ { type: "text", text: formatToolError(`Failed to find slots: ${message}`) }
3230
3265
  ],
3231
3266
  isError: true
3232
3267
  };
@@ -3296,7 +3331,7 @@ Created with Social Neuron`;
3296
3331
  content: [
3297
3332
  {
3298
3333
  type: "text",
3299
- text: `Failed to load content plan: ${sanitizeDbError(storedError)}`
3334
+ text: formatToolError(`Failed to load content plan: ${sanitizeDbError(storedError)}`)
3300
3335
  }
3301
3336
  ],
3302
3337
  isError: true
@@ -3307,7 +3342,7 @@ Created with Social Neuron`;
3307
3342
  content: [
3308
3343
  {
3309
3344
  type: "text",
3310
- text: `No content plan found for plan_id=${plan_id}`
3345
+ text: formatToolError(`No content plan found for plan_id=${plan_id}`)
3311
3346
  }
3312
3347
  ],
3313
3348
  isError: true
@@ -3322,7 +3357,7 @@ Created with Social Neuron`;
3322
3357
  content: [
3323
3358
  {
3324
3359
  type: "text",
3325
- text: `Stored plan ${plan_id} has no posts array.`
3360
+ text: formatToolError(`Stored plan ${plan_id} has no posts array.`)
3326
3361
  }
3327
3362
  ],
3328
3363
  isError: true
@@ -3361,7 +3396,7 @@ Created with Social Neuron`;
3361
3396
  content: [
3362
3397
  {
3363
3398
  type: "text",
3364
- text: `Failed to load plan approvals: ${sanitizeDbError(approvalsError)}`
3399
+ text: formatToolError(`Failed to load plan approvals: ${sanitizeDbError(approvalsError)}`)
3365
3400
  }
3366
3401
  ],
3367
3402
  isError: true
@@ -3796,7 +3831,7 @@ Created with Social Neuron`;
3796
3831
  content: [
3797
3832
  {
3798
3833
  type: "text",
3799
- text: `Batch scheduling failed: ${message}`
3834
+ text: formatToolError(`Batch scheduling failed: ${message}`)
3800
3835
  }
3801
3836
  ],
3802
3837
  isError: true
@@ -3887,7 +3922,7 @@ function registerAnalyticsTools(server) {
3887
3922
  content: [
3888
3923
  {
3889
3924
  type: "text",
3890
- text: `Failed to fetch user-scoped posts: ${sanitizeDbError(postsError)}`
3925
+ text: formatToolError(`Failed to fetch user-scoped posts: ${sanitizeDbError(postsError)}`)
3891
3926
  }
3892
3927
  ],
3893
3928
  isError: true
@@ -3934,7 +3969,7 @@ function registerAnalyticsTools(server) {
3934
3969
  content: [
3935
3970
  {
3936
3971
  type: "text",
3937
- text: `Failed to fetch analytics: ${sanitizeDbError(simpleError)}`
3972
+ text: formatToolError(`Failed to fetch analytics: ${sanitizeDbError(simpleError)}`)
3938
3973
  }
3939
3974
  ],
3940
3975
  isError: true
@@ -4064,7 +4099,7 @@ function registerAnalyticsTools(server) {
4064
4099
  content: [
4065
4100
  {
4066
4101
  type: "text",
4067
- text: `Error refreshing analytics: ${error}`
4102
+ text: formatToolError(`Error refreshing analytics: ${error}`)
4068
4103
  }
4069
4104
  ],
4070
4105
  isError: true
@@ -4451,7 +4486,7 @@ function registerBrandTools(server) {
4451
4486
  content: [
4452
4487
  {
4453
4488
  type: "text",
4454
- text: `Brand extraction failed: ${error}`
4489
+ text: formatToolError(`Brand extraction failed: ${error}`)
4455
4490
  }
4456
4491
  ],
4457
4492
  isError: true
@@ -4561,7 +4596,7 @@ function registerBrandTools(server) {
4561
4596
  content: [
4562
4597
  {
4563
4598
  type: "text",
4564
- text: `Failed to load brand profile: ${sanitizeDbError(error)}`
4599
+ text: formatToolError(`Failed to load brand profile: ${sanitizeDbError(error)}`)
4565
4600
  }
4566
4601
  ],
4567
4602
  isError: true
@@ -4692,7 +4727,7 @@ function registerBrandTools(server) {
4692
4727
  content: [
4693
4728
  {
4694
4729
  type: "text",
4695
- text: `Failed to save brand profile: ${sanitizeDbError(error)}`
4730
+ text: formatToolError(`Failed to save brand profile: ${sanitizeDbError(error)}`)
4696
4731
  }
4697
4732
  ],
4698
4733
  isError: true
@@ -4868,7 +4903,7 @@ Version: ${payload.version ?? "N/A"}`
4868
4903
  content: [
4869
4904
  {
4870
4905
  type: "text",
4871
- text: `Failed to update platform voice: ${saveError.message}`
4906
+ text: formatToolError(`Failed to update platform voice: ${saveError.message}`)
4872
4907
  }
4873
4908
  ],
4874
4909
  isError: true
@@ -6065,7 +6100,7 @@ function registerCommentsTools(server) {
6065
6100
  if (error) {
6066
6101
  return {
6067
6102
  content: [
6068
- { type: "text", text: `Error listing comments: ${error}` }
6103
+ { type: "text", text: formatToolError(`Error listing comments: ${error}`) }
6069
6104
  ],
6070
6105
  isError: true
6071
6106
  };
@@ -6169,7 +6204,7 @@ function registerCommentsTools(server) {
6169
6204
  content: [
6170
6205
  {
6171
6206
  type: "text",
6172
- text: `Error replying to comment: ${error}`
6207
+ text: formatToolError(`Error replying to comment: ${error}`)
6173
6208
  }
6174
6209
  ],
6175
6210
  isError: true
@@ -6255,7 +6290,7 @@ function registerCommentsTools(server) {
6255
6290
  });
6256
6291
  return {
6257
6292
  content: [
6258
- { type: "text", text: `Error posting comment: ${error}` }
6293
+ { type: "text", text: formatToolError(`Error posting comment: ${error}`) }
6259
6294
  ],
6260
6295
  isError: true
6261
6296
  };
@@ -6342,7 +6377,7 @@ function registerCommentsTools(server) {
6342
6377
  content: [
6343
6378
  {
6344
6379
  type: "text",
6345
- text: `Error moderating comment: ${error}`
6380
+ text: formatToolError(`Error moderating comment: ${error}`)
6346
6381
  }
6347
6382
  ],
6348
6383
  isError: true
@@ -6431,7 +6466,7 @@ function registerCommentsTools(server) {
6431
6466
  });
6432
6467
  return {
6433
6468
  content: [
6434
- { type: "text", text: `Error deleting comment: ${error}` }
6469
+ { type: "text", text: formatToolError(`Error deleting comment: ${error}`) }
6435
6470
  ],
6436
6471
  isError: true
6437
6472
  };
@@ -6705,7 +6740,7 @@ function registerCreditsTools(server) {
6705
6740
  content: [
6706
6741
  {
6707
6742
  type: "text",
6708
- text: `Failed to fetch credit balance: ${sanitizeDbError(profileResult.error)}`
6743
+ text: formatToolError(`Failed to fetch credit balance: ${sanitizeDbError(profileResult.error)}`)
6709
6744
  }
6710
6745
  ],
6711
6746
  isError: true
@@ -7346,7 +7381,7 @@ function registerExtractionTools(server) {
7346
7381
  content: [
7347
7382
  {
7348
7383
  type: "text",
7349
- text: `Failed to extract YouTube video: ${error ?? "No data returned"}`
7384
+ text: formatToolError(`Failed to extract YouTube video: ${error ?? "No data returned"}`)
7350
7385
  }
7351
7386
  ],
7352
7387
  isError: true
@@ -7386,7 +7421,7 @@ function registerExtractionTools(server) {
7386
7421
  content: [
7387
7422
  {
7388
7423
  type: "text",
7389
- text: `Failed to extract YouTube channel: ${error ?? "No data returned"}`
7424
+ text: formatToolError(`Failed to extract YouTube channel: ${error ?? "No data returned"}`)
7390
7425
  }
7391
7426
  ],
7392
7427
  isError: true
@@ -7417,7 +7452,7 @@ function registerExtractionTools(server) {
7417
7452
  content: [
7418
7453
  {
7419
7454
  type: "text",
7420
- text: `Failed to extract URL content: ${error ?? "No data returned"}`
7455
+ text: formatToolError(`Failed to extract URL content: ${error ?? "No data returned"}`)
7421
7456
  }
7422
7457
  ],
7423
7458
  isError: true
@@ -7474,7 +7509,7 @@ function registerExtractionTools(server) {
7474
7509
  });
7475
7510
  return {
7476
7511
  content: [
7477
- { type: "text", text: `Extraction failed: ${message}` }
7512
+ { type: "text", text: formatToolError(`Extraction failed: ${message}`) }
7478
7513
  ],
7479
7514
  isError: true
7480
7515
  };
@@ -7972,7 +8007,7 @@ ${ideationContext.promptInjection.slice(0, 1500)}` : "",
7972
8007
  content: [
7973
8008
  {
7974
8009
  type: "text",
7975
- text: `Plan generation failed: ${aiError ?? "No response from AI"}`
8010
+ text: formatToolError(`Plan generation failed: ${aiError ?? "No response from AI"}`)
7976
8011
  }
7977
8012
  ],
7978
8013
  isError: true
@@ -7992,10 +8027,10 @@ ${ideationContext.promptInjection.slice(0, 1500)}` : "",
7992
8027
  content: [
7993
8028
  {
7994
8029
  type: "text",
7995
- text: `AI response could not be parsed as JSON.
8030
+ text: formatToolError(`AI response could not be parsed as JSON.
7996
8031
 
7997
8032
  Raw output (first 1000 chars):
7998
- ${rawText.slice(0, 1e3)}`
8033
+ ${rawText.slice(0, 1e3)}`)
7999
8034
  }
8000
8035
  ],
8001
8036
  isError: true
@@ -8122,7 +8157,7 @@ ${rawText.slice(0, 1e3)}`
8122
8157
  content: [
8123
8158
  {
8124
8159
  type: "text",
8125
- text: `Plan generation failed: ${message}`
8160
+ text: formatToolError(`Plan generation failed: ${message}`)
8126
8161
  }
8127
8162
  ],
8128
8163
  isError: true
@@ -8235,7 +8270,7 @@ ${rawText.slice(0, 1e3)}`
8235
8270
  content: [
8236
8271
  {
8237
8272
  type: "text",
8238
- text: `Failed to save content plan: ${message}`
8273
+ text: formatToolError(`Failed to save content plan: ${message}`)
8239
8274
  }
8240
8275
  ],
8241
8276
  isError: true
@@ -8268,7 +8303,7 @@ ${rawText.slice(0, 1e3)}`
8268
8303
  content: [
8269
8304
  {
8270
8305
  type: "text",
8271
- text: `Failed to load content plan: ${sanitizeDbError(error)}`
8306
+ text: formatToolError(`Failed to load content plan: ${sanitizeDbError(error)}`)
8272
8307
  }
8273
8308
  ],
8274
8309
  isError: true
@@ -8279,7 +8314,7 @@ ${rawText.slice(0, 1e3)}`
8279
8314
  content: [
8280
8315
  {
8281
8316
  type: "text",
8282
- text: `No content plan found for plan_id=${plan_id}`
8317
+ text: formatToolError(`No content plan found for plan_id=${plan_id}`)
8283
8318
  }
8284
8319
  ],
8285
8320
  isError: true
@@ -8367,7 +8402,7 @@ ${rawText.slice(0, 1e3)}`
8367
8402
  content: [
8368
8403
  {
8369
8404
  type: "text",
8370
- text: `No content plan found for plan_id=${plan_id}`
8405
+ text: formatToolError(`No content plan found for plan_id=${plan_id}`)
8371
8406
  }
8372
8407
  ],
8373
8408
  isError: true
@@ -8411,7 +8446,7 @@ ${rawText.slice(0, 1e3)}`
8411
8446
  content: [
8412
8447
  {
8413
8448
  type: "text",
8414
- text: `Failed to update content plan: ${sanitizeDbError(saveError)}`
8449
+ text: formatToolError(`Failed to update content plan: ${sanitizeDbError(saveError)}`)
8415
8450
  }
8416
8451
  ],
8417
8452
  isError: true
@@ -8478,7 +8513,7 @@ ${rawText.slice(0, 1e3)}`
8478
8513
  content: [
8479
8514
  {
8480
8515
  type: "text",
8481
- text: `No content plan found for plan_id=${plan_id}`
8516
+ text: formatToolError(`No content plan found for plan_id=${plan_id}`)
8482
8517
  }
8483
8518
  ],
8484
8519
  isError: true
@@ -8491,7 +8526,7 @@ ${rawText.slice(0, 1e3)}`
8491
8526
  content: [
8492
8527
  {
8493
8528
  type: "text",
8494
- text: `Plan ${plan_id} has no posts to submit.`
8529
+ text: formatToolError(`Plan ${plan_id} has no posts to submit.`)
8495
8530
  }
8496
8531
  ],
8497
8532
  isError: true
@@ -8511,7 +8546,7 @@ ${rawText.slice(0, 1e3)}`
8511
8546
  content: [
8512
8547
  {
8513
8548
  type: "text",
8514
- text: `Failed to create approvals: ${sanitizeDbError(approvalError)}`
8549
+ text: formatToolError(`Failed to create approvals: ${sanitizeDbError(approvalError)}`)
8515
8550
  }
8516
8551
  ],
8517
8552
  isError: true
@@ -8523,7 +8558,7 @@ ${rawText.slice(0, 1e3)}`
8523
8558
  content: [
8524
8559
  {
8525
8560
  type: "text",
8526
- text: `Failed to update plan status: ${sanitizeDbError(statusError)}`
8561
+ text: formatToolError(`Failed to update plan status: ${sanitizeDbError(statusError)}`)
8527
8562
  }
8528
8563
  ],
8529
8564
  isError: true
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var MCP_VERSION;
14
14
  var init_version = __esm({
15
15
  "src/lib/version.ts"() {
16
16
  "use strict";
17
- MCP_VERSION = "1.5.1";
17
+ MCP_VERSION = "1.5.2";
18
18
  }
19
19
  });
20
20
 
@@ -3895,6 +3895,41 @@ function checkRateLimit(category, key) {
3895
3895
 
3896
3896
  // src/tools/ideation.ts
3897
3897
  init_supabase();
3898
+
3899
+ // src/lib/tool-errors.ts
3900
+ function formatToolError(rawMessage) {
3901
+ const msg = rawMessage.toLowerCase();
3902
+ if (msg.includes("rate limit") || msg.includes("too many requests")) {
3903
+ return `${rawMessage} Reduce request frequency or wait before retrying.`;
3904
+ }
3905
+ if (msg.includes("insufficient credit") || msg.includes("budget") || msg.includes("spending cap")) {
3906
+ return `${rawMessage} Call get_credit_balance to check remaining credits. Consider a cheaper model or wait for monthly refresh.`;
3907
+ }
3908
+ if (msg.includes("oauth") || msg.includes("token expired") || msg.includes("not connected") || msg.includes("reconnect")) {
3909
+ return `${rawMessage} Call list_connected_accounts to check status. User may need to reconnect at socialneuron.com/settings/connections.`;
3910
+ }
3911
+ if (msg.includes("generation failed") || msg.includes("failed to start") || msg.includes("no job id") || msg.includes("could not be parsed")) {
3912
+ return `${rawMessage} Try simplifying the prompt, using a different model, or check credits with get_credit_balance.`;
3913
+ }
3914
+ if (msg.includes("not found") || msg.includes("no ") && msg.includes(" found")) {
3915
+ return `${rawMessage} Verify the ID is correct \u2014 use the corresponding list tool to find valid IDs.`;
3916
+ }
3917
+ if (msg.includes("not accessible") || msg.includes("unauthorized") || msg.includes("permission")) {
3918
+ return `${rawMessage} Check API key scopes with get_credit_balance. A higher-tier plan may be required.`;
3919
+ }
3920
+ if (msg.includes("ssrf") || msg.includes("url blocked")) {
3921
+ return `${rawMessage} The URL was blocked for security. Use a publicly accessible HTTPS URL.`;
3922
+ }
3923
+ if (msg.includes("failed to schedule") || msg.includes("scheduling failed")) {
3924
+ return `${rawMessage} Verify platform OAuth is active with list_connected_accounts, then retry.`;
3925
+ }
3926
+ if (msg.includes("no posts") || msg.includes("plan") && msg.includes("has no")) {
3927
+ return `${rawMessage} Generate a plan with plan_content_week first, then save with save_content_plan.`;
3928
+ }
3929
+ return rawMessage;
3930
+ }
3931
+
3932
+ // src/tools/ideation.ts
3898
3933
  function registerIdeationTools(server2) {
3899
3934
  server2.tool(
3900
3935
  "generate_content",
@@ -4068,7 +4103,7 @@ Content Type: ${content_type}`;
4068
4103
  content: [
4069
4104
  {
4070
4105
  type: "text",
4071
- text: `Content generation failed: ${error}`
4106
+ text: formatToolError(`Content generation failed: ${error}`)
4072
4107
  }
4073
4108
  ],
4074
4109
  isError: true
@@ -4133,7 +4168,7 @@ Content Type: ${content_type}`;
4133
4168
  content: [
4134
4169
  {
4135
4170
  type: "text",
4136
- text: `Failed to fetch trends: ${error}`
4171
+ text: formatToolError(`Failed to fetch trends: ${error}`)
4137
4172
  }
4138
4173
  ],
4139
4174
  isError: true
@@ -4301,7 +4336,7 @@ ${content}`,
4301
4336
  content: [
4302
4337
  {
4303
4338
  type: "text",
4304
- text: `Content adaptation failed: ${error}`
4339
+ text: formatToolError(`Content adaptation failed: ${error}`)
4305
4340
  }
4306
4341
  ],
4307
4342
  isError: true
@@ -4612,7 +4647,7 @@ function registerContentTools(server2) {
4612
4647
  content: [
4613
4648
  {
4614
4649
  type: "text",
4615
- text: `Video generation failed to start: ${error}`
4650
+ text: formatToolError(`Video generation failed to start: ${error}`)
4616
4651
  }
4617
4652
  ],
4618
4653
  isError: true
@@ -4629,7 +4664,7 @@ function registerContentTools(server2) {
4629
4664
  content: [
4630
4665
  {
4631
4666
  type: "text",
4632
- text: "Video generation failed: no job ID returned."
4667
+ text: formatToolError("Video generation failed: no job ID returned.")
4633
4668
  }
4634
4669
  ],
4635
4670
  isError: true
@@ -4805,7 +4840,7 @@ function registerContentTools(server2) {
4805
4840
  content: [
4806
4841
  {
4807
4842
  type: "text",
4808
- text: `Image generation failed to start: ${error}`
4843
+ text: formatToolError(`Image generation failed to start: ${error}`)
4809
4844
  }
4810
4845
  ],
4811
4846
  isError: true
@@ -4822,7 +4857,7 @@ function registerContentTools(server2) {
4822
4857
  content: [
4823
4858
  {
4824
4859
  type: "text",
4825
- text: "Image generation failed: no job ID returned."
4860
+ text: formatToolError("Image generation failed: no job ID returned.")
4826
4861
  }
4827
4862
  ],
4828
4863
  isError: true
@@ -4946,7 +4981,7 @@ function registerContentTools(server2) {
4946
4981
  content: [
4947
4982
  {
4948
4983
  type: "text",
4949
- text: `Failed to look up job: ${sanitizeDbError(jobError)}`
4984
+ text: formatToolError(`Failed to look up job: ${sanitizeDbError(jobError)}`)
4950
4985
  }
4951
4986
  ],
4952
4987
  isError: true
@@ -4963,7 +4998,7 @@ function registerContentTools(server2) {
4963
4998
  content: [
4964
4999
  {
4965
5000
  type: "text",
4966
- text: `No job found with ID "${job_id}". The ID may be incorrect or the job has expired.`
5001
+ text: formatToolError(`No job found with ID "${job_id}". The ID may be incorrect or the job has expired.`)
4967
5002
  }
4968
5003
  ],
4969
5004
  isError: true
@@ -5211,7 +5246,7 @@ Return ONLY valid JSON in this exact format:
5211
5246
  content: [
5212
5247
  {
5213
5248
  type: "text",
5214
- text: `Storyboard generation failed: ${error}`
5249
+ text: formatToolError(`Storyboard generation failed: ${error}`)
5215
5250
  }
5216
5251
  ],
5217
5252
  isError: true
@@ -5346,7 +5381,7 @@ Return ONLY valid JSON in this exact format:
5346
5381
  content: [
5347
5382
  {
5348
5383
  type: "text",
5349
- text: `Voiceover generation failed: ${error}`
5384
+ text: formatToolError(`Voiceover generation failed: ${error}`)
5350
5385
  }
5351
5386
  ],
5352
5387
  isError: true
@@ -5363,7 +5398,7 @@ Return ONLY valid JSON in this exact format:
5363
5398
  content: [
5364
5399
  {
5365
5400
  type: "text",
5366
- text: "Voiceover generation failed: no audio URL returned."
5401
+ text: formatToolError("Voiceover generation failed: no audio URL returned.")
5367
5402
  }
5368
5403
  ],
5369
5404
  isError: true
@@ -5526,7 +5561,7 @@ Return ONLY valid JSON in this exact format:
5526
5561
  content: [
5527
5562
  {
5528
5563
  type: "text",
5529
- text: `Carousel generation failed: ${error}`
5564
+ text: formatToolError(`Carousel generation failed: ${error}`)
5530
5565
  }
5531
5566
  ],
5532
5567
  isError: true
@@ -5752,7 +5787,7 @@ Created with Social Neuron`;
5752
5787
  content: [
5753
5788
  {
5754
5789
  type: "text",
5755
- text: `Failed to schedule post: ${error}`
5790
+ text: formatToolError(`Failed to schedule post: ${error}`)
5756
5791
  }
5757
5792
  ],
5758
5793
  isError: true
@@ -5840,7 +5875,7 @@ Created with Social Neuron`;
5840
5875
  content: [
5841
5876
  {
5842
5877
  type: "text",
5843
- text: `Failed to list connected accounts: ${sanitizeDbError(error)}`
5878
+ text: formatToolError(`Failed to list connected accounts: ${sanitizeDbError(error)}`)
5844
5879
  }
5845
5880
  ],
5846
5881
  isError: true
@@ -5939,7 +5974,7 @@ Created with Social Neuron`;
5939
5974
  content: [
5940
5975
  {
5941
5976
  type: "text",
5942
- text: `Failed to list posts: ${sanitizeDbError(error)}`
5977
+ text: formatToolError(`Failed to list posts: ${sanitizeDbError(error)}`)
5943
5978
  }
5944
5979
  ],
5945
5980
  isError: true
@@ -6144,7 +6179,7 @@ Created with Social Neuron`;
6144
6179
  });
6145
6180
  return {
6146
6181
  content: [
6147
- { type: "text", text: `Failed to find slots: ${message}` }
6182
+ { type: "text", text: formatToolError(`Failed to find slots: ${message}`) }
6148
6183
  ],
6149
6184
  isError: true
6150
6185
  };
@@ -6214,7 +6249,7 @@ Created with Social Neuron`;
6214
6249
  content: [
6215
6250
  {
6216
6251
  type: "text",
6217
- text: `Failed to load content plan: ${sanitizeDbError(storedError)}`
6252
+ text: formatToolError(`Failed to load content plan: ${sanitizeDbError(storedError)}`)
6218
6253
  }
6219
6254
  ],
6220
6255
  isError: true
@@ -6225,7 +6260,7 @@ Created with Social Neuron`;
6225
6260
  content: [
6226
6261
  {
6227
6262
  type: "text",
6228
- text: `No content plan found for plan_id=${plan_id}`
6263
+ text: formatToolError(`No content plan found for plan_id=${plan_id}`)
6229
6264
  }
6230
6265
  ],
6231
6266
  isError: true
@@ -6240,7 +6275,7 @@ Created with Social Neuron`;
6240
6275
  content: [
6241
6276
  {
6242
6277
  type: "text",
6243
- text: `Stored plan ${plan_id} has no posts array.`
6278
+ text: formatToolError(`Stored plan ${plan_id} has no posts array.`)
6244
6279
  }
6245
6280
  ],
6246
6281
  isError: true
@@ -6279,7 +6314,7 @@ Created with Social Neuron`;
6279
6314
  content: [
6280
6315
  {
6281
6316
  type: "text",
6282
- text: `Failed to load plan approvals: ${sanitizeDbError(approvalsError)}`
6317
+ text: formatToolError(`Failed to load plan approvals: ${sanitizeDbError(approvalsError)}`)
6283
6318
  }
6284
6319
  ],
6285
6320
  isError: true
@@ -6714,7 +6749,7 @@ Created with Social Neuron`;
6714
6749
  content: [
6715
6750
  {
6716
6751
  type: "text",
6717
- text: `Batch scheduling failed: ${message}`
6752
+ text: formatToolError(`Batch scheduling failed: ${message}`)
6718
6753
  }
6719
6754
  ],
6720
6755
  isError: true
@@ -6807,7 +6842,7 @@ function registerAnalyticsTools(server2) {
6807
6842
  content: [
6808
6843
  {
6809
6844
  type: "text",
6810
- text: `Failed to fetch user-scoped posts: ${sanitizeDbError(postsError)}`
6845
+ text: formatToolError(`Failed to fetch user-scoped posts: ${sanitizeDbError(postsError)}`)
6811
6846
  }
6812
6847
  ],
6813
6848
  isError: true
@@ -6854,7 +6889,7 @@ function registerAnalyticsTools(server2) {
6854
6889
  content: [
6855
6890
  {
6856
6891
  type: "text",
6857
- text: `Failed to fetch analytics: ${sanitizeDbError(simpleError)}`
6892
+ text: formatToolError(`Failed to fetch analytics: ${sanitizeDbError(simpleError)}`)
6858
6893
  }
6859
6894
  ],
6860
6895
  isError: true
@@ -6984,7 +7019,7 @@ function registerAnalyticsTools(server2) {
6984
7019
  content: [
6985
7020
  {
6986
7021
  type: "text",
6987
- text: `Error refreshing analytics: ${error}`
7022
+ text: formatToolError(`Error refreshing analytics: ${error}`)
6988
7023
  }
6989
7024
  ],
6990
7025
  isError: true
@@ -7373,7 +7408,7 @@ function registerBrandTools(server2) {
7373
7408
  content: [
7374
7409
  {
7375
7410
  type: "text",
7376
- text: `Brand extraction failed: ${error}`
7411
+ text: formatToolError(`Brand extraction failed: ${error}`)
7377
7412
  }
7378
7413
  ],
7379
7414
  isError: true
@@ -7483,7 +7518,7 @@ function registerBrandTools(server2) {
7483
7518
  content: [
7484
7519
  {
7485
7520
  type: "text",
7486
- text: `Failed to load brand profile: ${sanitizeDbError(error)}`
7521
+ text: formatToolError(`Failed to load brand profile: ${sanitizeDbError(error)}`)
7487
7522
  }
7488
7523
  ],
7489
7524
  isError: true
@@ -7614,7 +7649,7 @@ function registerBrandTools(server2) {
7614
7649
  content: [
7615
7650
  {
7616
7651
  type: "text",
7617
- text: `Failed to save brand profile: ${sanitizeDbError(error)}`
7652
+ text: formatToolError(`Failed to save brand profile: ${sanitizeDbError(error)}`)
7618
7653
  }
7619
7654
  ],
7620
7655
  isError: true
@@ -7790,7 +7825,7 @@ Version: ${payload.version ?? "N/A"}`
7790
7825
  content: [
7791
7826
  {
7792
7827
  type: "text",
7793
- text: `Failed to update platform voice: ${saveError.message}`
7828
+ text: formatToolError(`Failed to update platform voice: ${saveError.message}`)
7794
7829
  }
7795
7830
  ],
7796
7831
  isError: true
@@ -8991,7 +9026,7 @@ function registerCommentsTools(server2) {
8991
9026
  if (error) {
8992
9027
  return {
8993
9028
  content: [
8994
- { type: "text", text: `Error listing comments: ${error}` }
9029
+ { type: "text", text: formatToolError(`Error listing comments: ${error}`) }
8995
9030
  ],
8996
9031
  isError: true
8997
9032
  };
@@ -9095,7 +9130,7 @@ function registerCommentsTools(server2) {
9095
9130
  content: [
9096
9131
  {
9097
9132
  type: "text",
9098
- text: `Error replying to comment: ${error}`
9133
+ text: formatToolError(`Error replying to comment: ${error}`)
9099
9134
  }
9100
9135
  ],
9101
9136
  isError: true
@@ -9181,7 +9216,7 @@ function registerCommentsTools(server2) {
9181
9216
  });
9182
9217
  return {
9183
9218
  content: [
9184
- { type: "text", text: `Error posting comment: ${error}` }
9219
+ { type: "text", text: formatToolError(`Error posting comment: ${error}`) }
9185
9220
  ],
9186
9221
  isError: true
9187
9222
  };
@@ -9268,7 +9303,7 @@ function registerCommentsTools(server2) {
9268
9303
  content: [
9269
9304
  {
9270
9305
  type: "text",
9271
- text: `Error moderating comment: ${error}`
9306
+ text: formatToolError(`Error moderating comment: ${error}`)
9272
9307
  }
9273
9308
  ],
9274
9309
  isError: true
@@ -9357,7 +9392,7 @@ function registerCommentsTools(server2) {
9357
9392
  });
9358
9393
  return {
9359
9394
  content: [
9360
- { type: "text", text: `Error deleting comment: ${error}` }
9395
+ { type: "text", text: formatToolError(`Error deleting comment: ${error}`) }
9361
9396
  ],
9362
9397
  isError: true
9363
9398
  };
@@ -9633,7 +9668,7 @@ function registerCreditsTools(server2) {
9633
9668
  content: [
9634
9669
  {
9635
9670
  type: "text",
9636
- text: `Failed to fetch credit balance: ${sanitizeDbError(profileResult.error)}`
9671
+ text: formatToolError(`Failed to fetch credit balance: ${sanitizeDbError(profileResult.error)}`)
9637
9672
  }
9638
9673
  ],
9639
9674
  isError: true
@@ -10279,7 +10314,7 @@ function registerExtractionTools(server2) {
10279
10314
  content: [
10280
10315
  {
10281
10316
  type: "text",
10282
- text: `Failed to extract YouTube video: ${error ?? "No data returned"}`
10317
+ text: formatToolError(`Failed to extract YouTube video: ${error ?? "No data returned"}`)
10283
10318
  }
10284
10319
  ],
10285
10320
  isError: true
@@ -10319,7 +10354,7 @@ function registerExtractionTools(server2) {
10319
10354
  content: [
10320
10355
  {
10321
10356
  type: "text",
10322
- text: `Failed to extract YouTube channel: ${error ?? "No data returned"}`
10357
+ text: formatToolError(`Failed to extract YouTube channel: ${error ?? "No data returned"}`)
10323
10358
  }
10324
10359
  ],
10325
10360
  isError: true
@@ -10350,7 +10385,7 @@ function registerExtractionTools(server2) {
10350
10385
  content: [
10351
10386
  {
10352
10387
  type: "text",
10353
- text: `Failed to extract URL content: ${error ?? "No data returned"}`
10388
+ text: formatToolError(`Failed to extract URL content: ${error ?? "No data returned"}`)
10354
10389
  }
10355
10390
  ],
10356
10391
  isError: true
@@ -10407,7 +10442,7 @@ function registerExtractionTools(server2) {
10407
10442
  });
10408
10443
  return {
10409
10444
  content: [
10410
- { type: "text", text: `Extraction failed: ${message}` }
10445
+ { type: "text", text: formatToolError(`Extraction failed: ${message}`) }
10411
10446
  ],
10412
10447
  isError: true
10413
10448
  };
@@ -10909,7 +10944,7 @@ ${ideationContext.promptInjection.slice(0, 1500)}` : "",
10909
10944
  content: [
10910
10945
  {
10911
10946
  type: "text",
10912
- text: `Plan generation failed: ${aiError ?? "No response from AI"}`
10947
+ text: formatToolError(`Plan generation failed: ${aiError ?? "No response from AI"}`)
10913
10948
  }
10914
10949
  ],
10915
10950
  isError: true
@@ -10929,10 +10964,10 @@ ${ideationContext.promptInjection.slice(0, 1500)}` : "",
10929
10964
  content: [
10930
10965
  {
10931
10966
  type: "text",
10932
- text: `AI response could not be parsed as JSON.
10967
+ text: formatToolError(`AI response could not be parsed as JSON.
10933
10968
 
10934
10969
  Raw output (first 1000 chars):
10935
- ${rawText.slice(0, 1e3)}`
10970
+ ${rawText.slice(0, 1e3)}`)
10936
10971
  }
10937
10972
  ],
10938
10973
  isError: true
@@ -11059,7 +11094,7 @@ ${rawText.slice(0, 1e3)}`
11059
11094
  content: [
11060
11095
  {
11061
11096
  type: "text",
11062
- text: `Plan generation failed: ${message}`
11097
+ text: formatToolError(`Plan generation failed: ${message}`)
11063
11098
  }
11064
11099
  ],
11065
11100
  isError: true
@@ -11172,7 +11207,7 @@ ${rawText.slice(0, 1e3)}`
11172
11207
  content: [
11173
11208
  {
11174
11209
  type: "text",
11175
- text: `Failed to save content plan: ${message}`
11210
+ text: formatToolError(`Failed to save content plan: ${message}`)
11176
11211
  }
11177
11212
  ],
11178
11213
  isError: true
@@ -11205,7 +11240,7 @@ ${rawText.slice(0, 1e3)}`
11205
11240
  content: [
11206
11241
  {
11207
11242
  type: "text",
11208
- text: `Failed to load content plan: ${sanitizeDbError(error)}`
11243
+ text: formatToolError(`Failed to load content plan: ${sanitizeDbError(error)}`)
11209
11244
  }
11210
11245
  ],
11211
11246
  isError: true
@@ -11216,7 +11251,7 @@ ${rawText.slice(0, 1e3)}`
11216
11251
  content: [
11217
11252
  {
11218
11253
  type: "text",
11219
- text: `No content plan found for plan_id=${plan_id}`
11254
+ text: formatToolError(`No content plan found for plan_id=${plan_id}`)
11220
11255
  }
11221
11256
  ],
11222
11257
  isError: true
@@ -11304,7 +11339,7 @@ ${rawText.slice(0, 1e3)}`
11304
11339
  content: [
11305
11340
  {
11306
11341
  type: "text",
11307
- text: `No content plan found for plan_id=${plan_id}`
11342
+ text: formatToolError(`No content plan found for plan_id=${plan_id}`)
11308
11343
  }
11309
11344
  ],
11310
11345
  isError: true
@@ -11348,7 +11383,7 @@ ${rawText.slice(0, 1e3)}`
11348
11383
  content: [
11349
11384
  {
11350
11385
  type: "text",
11351
- text: `Failed to update content plan: ${sanitizeDbError(saveError)}`
11386
+ text: formatToolError(`Failed to update content plan: ${sanitizeDbError(saveError)}`)
11352
11387
  }
11353
11388
  ],
11354
11389
  isError: true
@@ -11415,7 +11450,7 @@ ${rawText.slice(0, 1e3)}`
11415
11450
  content: [
11416
11451
  {
11417
11452
  type: "text",
11418
- text: `No content plan found for plan_id=${plan_id}`
11453
+ text: formatToolError(`No content plan found for plan_id=${plan_id}`)
11419
11454
  }
11420
11455
  ],
11421
11456
  isError: true
@@ -11428,7 +11463,7 @@ ${rawText.slice(0, 1e3)}`
11428
11463
  content: [
11429
11464
  {
11430
11465
  type: "text",
11431
- text: `Plan ${plan_id} has no posts to submit.`
11466
+ text: formatToolError(`Plan ${plan_id} has no posts to submit.`)
11432
11467
  }
11433
11468
  ],
11434
11469
  isError: true
@@ -11448,7 +11483,7 @@ ${rawText.slice(0, 1e3)}`
11448
11483
  content: [
11449
11484
  {
11450
11485
  type: "text",
11451
- text: `Failed to create approvals: ${sanitizeDbError(approvalError)}`
11486
+ text: formatToolError(`Failed to create approvals: ${sanitizeDbError(approvalError)}`)
11452
11487
  }
11453
11488
  ],
11454
11489
  isError: true
@@ -11460,7 +11495,7 @@ ${rawText.slice(0, 1e3)}`
11460
11495
  content: [
11461
11496
  {
11462
11497
  type: "text",
11463
- text: `Failed to update plan status: ${sanitizeDbError(statusError)}`
11498
+ text: formatToolError(`Failed to update plan status: ${sanitizeDbError(statusError)}`)
11464
11499
  }
11465
11500
  ],
11466
11501
  isError: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@socialneuron/mcp-server",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "MCP server for Social Neuron - AI content creation platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",