suparank 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/mcp-client.js +190 -35
  2. package/package.json +1 -1
package/mcp-client.js CHANGED
@@ -657,7 +657,18 @@ async function callBackendTool(toolName, args) {
657
657
  const TOOLS = [
658
658
  {
659
659
  name: 'keyword_research',
660
- description: 'Conduct keyword research and competitive analysis for SEO content. Analyzes search volume, difficulty, and opportunity. If no keyword provided, uses project primary keywords automatically.',
660
+ description: `Research keywords for SEO. Use ONLY when user specifically asks for keyword research WITHOUT wanting full article creation.
661
+
662
+ TRIGGERS - Use when user says:
663
+ - "find keywords for..."
664
+ - "research keywords about..."
665
+ - "what keywords should I target for..."
666
+ - "keyword ideas for..."
667
+ - "analyze keywords for..."
668
+
669
+ DO NOT USE when user wants to write/create content - use create_content instead (it includes keyword research automatically).
670
+
671
+ OUTCOME: List of keywords with search volume, difficulty, and recommendations.`,
661
672
  inputSchema: {
662
673
  type: 'object',
663
674
  properties: {
@@ -908,7 +919,23 @@ const TOOLS = [
908
919
  const ACTION_TOOLS = [
909
920
  {
910
921
  name: 'generate_image',
911
- description: 'Generate AI images using configured provider (fal.ai, Gemini Imagen, or wiro.ai). Requires image provider API key in ~/.suparank/credentials.json',
922
+ description: `Generate AI images. Use when user wants to create, generate, or regenerate images.
923
+
924
+ TRIGGERS - Use when user says:
925
+ - "create an image for..."
926
+ - "generate image of..."
927
+ - "make a picture of..."
928
+ - "I need an image for..."
929
+ - "regenerate the image"
930
+ - "new hero image"
931
+ - "create thumbnail for..."
932
+
933
+ NOTE: create_content automatically generates images. Use this tool for:
934
+ - Regenerating/replacing images
935
+ - Creating standalone images
936
+ - Custom image requests outside content workflow
937
+
938
+ OUTCOME: AI-generated image URL ready for use.`,
912
939
  inputSchema: {
913
940
  type: 'object',
914
941
  properties: {
@@ -1035,21 +1062,24 @@ const ACTION_TOOLS = [
1035
1062
  const ORCHESTRATOR_TOOLS = [
1036
1063
  {
1037
1064
  name: 'create_content',
1038
- description: `🚀 MAIN ENTRY POINT - Just tell me what content you want!
1039
-
1040
- Examples:
1041
- - "Write a blog post about AI tools"
1042
- - "Create 3 articles about SEO"
1043
- - "Write content for my project"
1044
-
1045
- I will automatically:
1046
- 1. Research keywords (using SEO MCP if available)
1047
- 2. Plan content structure
1048
- 3. Guide you through writing
1049
- 4. Generate images
1050
- 5. Publish to your configured CMS (Ghost/WordPress)
1051
-
1052
- No parameters needed - I use your project settings automatically!`,
1065
+ description: `PRIMARY TOOL for content creation. Use this when user wants to write, create, or generate any content.
1066
+
1067
+ TRIGGERS - Use when user says:
1068
+ - "write a blog post about..."
1069
+ - "create an article about..."
1070
+ - "I need content for..."
1071
+ - "help me write about..."
1072
+ - "generate a post on..."
1073
+ - "make content about..."
1074
+ - any request involving writing/creating/generating articles or blog posts
1075
+
1076
+ WORKFLOW (automatic 4-phase):
1077
+ 1. RESEARCH: Keywords, SEO strategy, content structure
1078
+ 2. CREATION: Outline, write full article, save to session
1079
+ 3. OPTIMIZATION: Quality check, GEO optimization for AI search
1080
+ 4. PUBLISHING: Generate images, publish to WordPress/Ghost
1081
+
1082
+ OUTCOME: Complete article written, optimized, and published to CMS.`,
1053
1083
  inputSchema: {
1054
1084
  type: 'object',
1055
1085
  properties: {
@@ -1078,7 +1108,16 @@ No parameters needed - I use your project settings automatically!`,
1078
1108
  },
1079
1109
  {
1080
1110
  name: 'save_content',
1081
- description: 'Save generated content to session for publishing. Call this after you finish writing an article.',
1111
+ description: `Save written article to session. Use after manually writing content outside create_content workflow.
1112
+
1113
+ TRIGGERS - Use when:
1114
+ - You wrote an article manually and need to save it
1115
+ - User says "save this article" / "save my content"
1116
+ - Saving edited/revised content
1117
+
1118
+ NOTE: create_content saves automatically. Only use this for manual saves.
1119
+
1120
+ OUTCOME: Article saved to session, ready for publishing.`,
1082
1121
  inputSchema: {
1083
1122
  type: 'object',
1084
1123
  properties: {
@@ -1105,7 +1144,21 @@ No parameters needed - I use your project settings automatically!`,
1105
1144
  },
1106
1145
  {
1107
1146
  name: 'publish_content',
1108
- description: 'Publish saved articles to configured CMS platforms. Publishes ALL unpublished articles in the session by default, or specific articles by index.',
1147
+ description: `Publish articles to WordPress/Ghost. Use when user wants to publish saved content.
1148
+
1149
+ TRIGGERS - Use when user says:
1150
+ - "publish my article"
1151
+ - "post this to WordPress/Ghost"
1152
+ - "publish to my blog"
1153
+ - "make it live"
1154
+ - "publish as draft"
1155
+
1156
+ NOTE: create_content publishes automatically. Use this for:
1157
+ - Manual publishing control
1158
+ - Re-publishing edited content
1159
+ - Publishing specific articles from session
1160
+
1161
+ OUTCOME: Article published to configured CMS platforms.`,
1109
1162
  inputSchema: {
1110
1163
  type: 'object',
1111
1164
  properties: {
@@ -1135,7 +1188,16 @@ No parameters needed - I use your project settings automatically!`,
1135
1188
  },
1136
1189
  {
1137
1190
  name: 'get_session',
1138
- description: 'Get current session state - see what content and images have been created.',
1191
+ description: `View current session status. Shows saved articles, images, and publishing state.
1192
+
1193
+ TRIGGERS - Use when user says:
1194
+ - "what's in my session"
1195
+ - "show my articles"
1196
+ - "what have I created"
1197
+ - "session status"
1198
+ - "list my saved content"
1199
+
1200
+ OUTCOME: List of all articles in session with their publish status.`,
1139
1201
  inputSchema: {
1140
1202
  type: 'object',
1141
1203
  properties: {}
@@ -1143,7 +1205,15 @@ No parameters needed - I use your project settings automatically!`,
1143
1205
  },
1144
1206
  {
1145
1207
  name: 'remove_article',
1146
- description: 'Remove specific article(s) from the session by number. Does not affect published articles.',
1208
+ description: `Remove article(s) from session. Does NOT delete published content.
1209
+
1210
+ TRIGGERS - Use when user says:
1211
+ - "remove article 2"
1212
+ - "delete the second article"
1213
+ - "remove that article"
1214
+ - "discard article..."
1215
+
1216
+ OUTCOME: Specified article(s) removed from session.`,
1147
1217
  inputSchema: {
1148
1218
  type: 'object',
1149
1219
  properties: {
@@ -1158,7 +1228,18 @@ No parameters needed - I use your project settings automatically!`,
1158
1228
  },
1159
1229
  {
1160
1230
  name: 'clear_session',
1161
- description: 'Clear all articles and reset session. Use with caution - this removes all unpublished content!',
1231
+ description: `Clear ALL content from session. DESTRUCTIVE - removes all unpublished articles!
1232
+
1233
+ TRIGGERS - Use when user says:
1234
+ - "clear my session"
1235
+ - "start fresh"
1236
+ - "remove all articles"
1237
+ - "reset everything"
1238
+ - "clear all content"
1239
+
1240
+ WARNING: Requires confirm: true. Does NOT affect already-published content.
1241
+
1242
+ OUTCOME: Empty session, ready for new content creation.`,
1162
1243
  inputSchema: {
1163
1244
  type: 'object',
1164
1245
  properties: {
@@ -1172,7 +1253,18 @@ No parameters needed - I use your project settings automatically!`,
1172
1253
  },
1173
1254
  {
1174
1255
  name: 'list_content',
1175
- description: 'List all previously saved content from ~/.suparank/content/. Shows articles that can be loaded back into session for further optimization.',
1256
+ description: `List all saved content from disk. Shows past articles that can be loaded back.
1257
+
1258
+ TRIGGERS - Use when user says:
1259
+ - "show my past articles"
1260
+ - "list saved content"
1261
+ - "what articles do I have"
1262
+ - "show previous content"
1263
+ - "find my old articles"
1264
+
1265
+ NOTE: Different from get_session - this shows DISK storage, not current session.
1266
+
1267
+ OUTCOME: List of saved article folders with titles and dates.`,
1176
1268
  inputSchema: {
1177
1269
  type: 'object',
1178
1270
  properties: {
@@ -1186,7 +1278,18 @@ No parameters needed - I use your project settings automatically!`,
1186
1278
  },
1187
1279
  {
1188
1280
  name: 'load_content',
1189
- description: 'Load a previously saved article back into the session. Use list_content first to see available articles. Once loaded, you can run optimization tools like quality_check, geo_optimize, internal_links, schema_generate on it.',
1281
+ description: `Load a saved article back into session for editing or re-publishing.
1282
+
1283
+ TRIGGERS - Use when user says:
1284
+ - "load my article about..."
1285
+ - "open the previous article"
1286
+ - "bring back that article"
1287
+ - "edit my old post about..."
1288
+ - "reload article..."
1289
+
1290
+ WORKFLOW: Run list_content first to see available articles, then load by folder name.
1291
+
1292
+ OUTCOME: Article loaded into session, ready for optimization or re-publishing.`,
1190
1293
  inputSchema: {
1191
1294
  type: 'object',
1192
1295
  properties: {
@@ -1265,6 +1368,21 @@ function buildWorkflowPlan(request, count, publishTo, withImages, project) {
1265
1368
 
1266
1369
  // Extract all settings from project.config (database schema)
1267
1370
  const targetWordCount = config.content?.default_word_count
1371
+
1372
+ // LOG ALL CONFIG VALUES FOR DEBUGGING
1373
+ log('=== PROJECT CONFIG VALUES ===')
1374
+ log(`Word Count Target: ${targetWordCount}`)
1375
+ log(`Reading Level: ${config.content?.reading_level}`)
1376
+ log(`Brand Voice: ${config.brand?.voice}`)
1377
+ log(`Target Audience: ${config.brand?.target_audience}`)
1378
+ log(`Primary Keywords: ${config.seo?.primary_keywords?.join(', ')}`)
1379
+ log(`Include Images: ${config.content?.include_images}`)
1380
+ log('=============================')
1381
+
1382
+ // CRITICAL: Validate word count is set
1383
+ if (!targetWordCount || targetWordCount < 100) {
1384
+ log(`WARNING: Word count not properly set! Got: ${targetWordCount}`)
1385
+ }
1268
1386
  const readingLevel = config.content?.reading_level
1269
1387
  const includeImages = config.content?.include_images
1270
1388
  const brandVoice = config.brand?.voice
@@ -1470,27 +1588,40 @@ Use format: [IMAGE: description of what image should show]` : '**Note:** Images
1470
1588
  action: 'content_write',
1471
1589
  instruction: `Write the COMPLETE article following your outline.
1472
1590
 
1473
- **⚠️ CRITICAL REQUIREMENTS (from project database):**
1474
- - Word count: **${targetWordCount} words MINIMUM** - Count your words!
1475
- - Reading level: **${readingLevelDisplay}** - Simple sentences, short paragraphs, no jargon
1591
+ ╔══════════════════════════════════════════════════════════════════╗
1592
+ ║ 🚨 MANDATORY WORD COUNT: ${targetWordCount} WORDS MINIMUM 🚨 ║
1593
+ ║ This is a strict requirement from the project settings. ║
1594
+ ║ The article will be REJECTED if under ${targetWordCount} words. ║
1595
+ ╚══════════════════════════════════════════════════════════════════╝
1596
+
1597
+ **Project Requirements (from Supabase database - DO NOT IGNORE):**
1598
+ - Word count: **${targetWordCount} words** (MINIMUM - not a suggestion!)
1599
+ - Reading level: **${readingLevelDisplay}** - Simple sentences, short paragraphs
1476
1600
  - Brand voice: ${brandVoice}
1477
1601
  - Target audience: ${targetAudience || 'General readers'}
1478
1602
 
1603
+ **To reach ${targetWordCount} words, you MUST:**
1604
+ - Write 8-10 substantial H2 sections (each 200-400 words)
1605
+ - Include detailed examples, statistics, and actionable advice
1606
+ - Add comprehensive FAQ section (5-8 questions)
1607
+ - Expand each point with thorough explanations
1608
+
1479
1609
  **Content Structure:**
1480
1610
  - Engaging hook in first 2 sentences
1481
- - All H2/H3 sections from your outline
1482
- - Statistics, examples, and actionable tips in each section
1611
+ - All H2/H3 sections from your outline (expand each thoroughly!)
1612
+ - Statistics, examples, and actionable tips in EVERY section
1483
1613
  ${shouldGenerateImages ? '- Image placeholders: [IMAGE: description] where images should go' : ''}
1484
- - FAQ section with 4-5 Q&As
1614
+ - FAQ section with 5-8 Q&As (detailed answers, not one-liners)
1485
1615
  - Strong conclusion with clear CTA
1486
1616
 
1487
- **After writing, call 'save_content' with:**
1617
+ **After writing ${targetWordCount}+ words, call 'save_content' with:**
1488
1618
  - title: Your SEO-optimized title
1489
1619
  - content: The full article (markdown)
1490
1620
  - keywords: Array of target keywords
1491
1621
  - meta_description: Your 150-160 char meta description
1492
1622
 
1493
- ⚠️ DO NOT proceed until you've written ${targetWordCount}+ words!`,
1623
+ STOP! Before calling save_content, verify you have ${targetWordCount}+ words.
1624
+ Count the words. If under ${targetWordCount}, ADD MORE CONTENT.`,
1494
1625
  store: 'article'
1495
1626
  })
1496
1627
 
@@ -1701,6 +1832,13 @@ async function executeOrchestratorTool(toolName, args, project) {
1701
1832
 
1702
1833
  let response = `# 🚀 Content Creation Workflow Started
1703
1834
 
1835
+ ╔══════════════════════════════════════════════════════════════════════════════╗
1836
+ ║ 📊 PROJECT REQUIREMENTS (from Supabase database) ║
1837
+ ║ Word Count: ${String(plan.settings.target_word_count).padEnd(6)} words (MINIMUM - strictly enforced!) ║
1838
+ ║ Brand Voice: ${String(plan.settings.brand_voice || 'Not set').substring(0, 50).padEnd(50)} ║
1839
+ ║ Target Audience: ${String(plan.settings.target_audience || 'Not set').substring(0, 45).padEnd(45)} ║
1840
+ ╚══════════════════════════════════════════════════════════════════════════════╝
1841
+
1704
1842
  ## Your Request
1705
1843
  "${plan.request}"
1706
1844
 
@@ -1708,7 +1846,7 @@ async function executeOrchestratorTool(toolName, args, project) {
1708
1846
  - **URL:** ${plan.project_info.url}
1709
1847
  - **Niche:** ${plan.project_info.niche}
1710
1848
 
1711
- ## Content Settings (from database)
1849
+ ## Content Settings (from database - DO NOT USE DEFAULTS)
1712
1850
  | Setting | Value |
1713
1851
  |---------|-------|
1714
1852
  | **Word Count** | ${plan.settings.target_word_count} words |
@@ -1804,7 +1942,12 @@ ${plan.steps[0].instruction}
1804
1942
 
1805
1943
  const workflow = sessionState.currentWorkflow
1806
1944
  const targetWordCount = workflow?.settings?.target_word_count
1807
- const wordCountOk = targetWordCount ? wordCount >= targetWordCount * 0.9 : true // Allow 10% tolerance
1945
+ // Only 5% tolerance - 2500 word target means minimum 2375 words
1946
+ const wordCountOk = targetWordCount ? wordCount >= targetWordCount * 0.95 : true
1947
+ const shortfall = targetWordCount ? targetWordCount - wordCount : 0
1948
+
1949
+ // Log word count check
1950
+ log(`Word count check: ${wordCount} words (target: ${targetWordCount}, ok: ${wordCountOk})`)
1808
1951
 
1809
1952
  // Find next step
1810
1953
  const imageStep = workflow?.steps?.find(s => s.action === 'generate_images')
@@ -1851,7 +1994,19 @@ Use \`publish_content\` to publish all unpublished articles, or \`get_session\`
1851
1994
  **Keywords:** ${keywords.join(', ') || 'none specified'}
1852
1995
  **Images:** ${newArticle.imageUrl ? '1 cover' : 'no cover'}${newArticle.inlineImages.length > 0 ? ` + ${newArticle.inlineImages.length} inline` : ''}
1853
1996
 
1854
- ${targetWordCount && !wordCountOk ? `⚠️ **Warning:** Article is ${targetWordCount - wordCount} words short of the ${targetWordCount} word target.\n` : ''}
1997
+ ${targetWordCount && !wordCountOk ? `
1998
+ ╔══════════════════════════════════════════════════════════════════════════╗
1999
+ ║ ⛔ WORD COUNT NOT MET - ${shortfall} WORDS SHORT! ║
2000
+ ║ Target: ${targetWordCount} words | Actual: ${wordCount} words ║
2001
+ ║ ║
2002
+ ║ The article does not meet the project's word count requirement. ║
2003
+ ║ Please EXPAND the content before publishing: ║
2004
+ ║ - Add more detailed explanations to each section ║
2005
+ ║ - Include additional examples and statistics ║
2006
+ ║ - Expand the FAQ section with more questions ║
2007
+ ║ - Add more H2 sections if needed ║
2008
+ ╚══════════════════════════════════════════════════════════════════════════╝
2009
+ ` : ''}
1855
2010
  ${!meta_description ? '⚠️ **Warning:** Meta description is missing. Add it for better SEO.\n' : ''}
1856
2011
  ${articlesListSection}${categoriesSection}
1857
2012
  ## Next Step${includeImages && imageStep ? ': Generate Images' : ': Ready to Publish or Continue'}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "suparank",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "AI-powered SEO content creation MCP - generate and publish optimized blog posts with Claude, ChatGPT, or Cursor",
5
5
  "main": "mcp-client.js",
6
6
  "type": "module",