thorbit-content-mcp 0.1.2 → 0.1.4
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/README.md +17 -3
- package/dist/bin/thorbit-content-mcp-install.cjs +7 -4
- package/dist/bin/thorbit-content-mcp-install.cjs.map +1 -1
- package/dist/bin/thorbit-content-mcp-install.js +7 -4
- package/dist/bin/thorbit-content-mcp-install.js.map +1 -1
- package/dist/bin/thorbit-content-mcp.cjs +207 -14
- package/dist/bin/thorbit-content-mcp.cjs.map +1 -1
- package/dist/bin/thorbit-content-mcp.js +207 -14
- package/dist/bin/thorbit-content-mcp.js.map +1 -1
- package/dist/index.cjs +222 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +222 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Thorbit Content MCP
|
|
2
2
|
|
|
3
|
-
Local stdio MCP server for Thorbit content research
|
|
3
|
+
Local stdio MCP server for Thorbit content research, on-page analysis, and content pipeline work. The package proxies tool calls to hosted Thorbit API routes; hosted Thorbit handles API-key auth, metering, MCP Scraper extraction, MCP Scraper SERP/PAA harvests, MCP Scraper browser-agent Reddit reads, durable on-page analysis, brief/strategy/edit/rescore actions, and content pipeline workflows.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -60,8 +60,22 @@ npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --key-path ~/.c
|
|
|
60
60
|
- `thorbit_content_extract_url`: extract a URL through MCP Scraper.
|
|
61
61
|
- `thorbit_content_harvest_serp`: harvest SERP/PAA evidence through MCP Scraper. Returns PAA flat questions, PAA tree, organic SERP, local pack, videos/shorts, forums, whatPeopleSaying, AI Overview text/citations/sections, AI Mode, entity IDs, stats, diagnostics, retry attempts, and the raw MCP Scraper result. Supports MCP Scraper `proxyMode`, `proxyZip`, `device`, `pages`, and `debug` controls.
|
|
62
62
|
- `thorbit_content_reddit_research`: discover Reddit candidates with MCP Scraper SERP and read posts through MCP Scraper browser-agent by default. Supports the same SERP proxy controls for discovery.
|
|
63
|
-
- `
|
|
64
|
-
- `
|
|
63
|
+
- `thorbit_content_opportunities_list`: list persisted content opportunity candidates for a project.
|
|
64
|
+
- `thorbit_content_pipeline_start`: start the Thorbit content pipeline in `brief`, `write`, or `optimize` mode.
|
|
65
|
+
- `thorbit_content_pipeline_get`: read a content pipeline job and normalized run view.
|
|
66
|
+
- `thorbit_content_pipeline_resume`: resume a paused content pipeline after brief or strategy review.
|
|
67
|
+
- `thorbit_content_pipeline_start_from_brief`: start writing from an approved Thorbit brief.
|
|
68
|
+
- `thorbit_content_pipeline_improve`: start an improvement loop for an existing job or content piece.
|
|
69
|
+
- `thorbit_onpage_list_sources`: list selectable on-page analysis sources: keyword, WordPress Plugin, WordPress API, and project website scrape.
|
|
70
|
+
- `thorbit_onpage_start_analysis`: start durable Thorbit on-page analysis for keyword-only, inline content, content pieces, WordPress Plugin pages, WordPress API pages, or project website scrape pages.
|
|
71
|
+
- `thorbit_onpage_get_analysis`: read persisted analysis status, score, signal counts, brief, strategy, editor state, and optional full analysis surfaces.
|
|
72
|
+
- `thorbit_onpage_get_editor_content`: read or materialize editable content for an analysis.
|
|
73
|
+
- `thorbit_onpage_rescore_analysis`: re-score editable content against an existing completed analysis.
|
|
74
|
+
- `thorbit_onpage_generate_brief`: return an existing final writer brief, or queue brief generation and poll with `thorbit_onpage_get_analysis`.
|
|
75
|
+
- `thorbit_onpage_generate_strategy`: generate and persist the on-page strategy document.
|
|
76
|
+
- `thorbit_onpage_propose_edits`: propose targeted content edits from analysis gaps.
|
|
77
|
+
- `thorbit_onpage_update_edit_status`: accept or reject one proposed edit.
|
|
78
|
+
- `thorbit_onpage_apply_edits`: apply accepted edits and create before/after content versions.
|
|
65
79
|
|
|
66
80
|
For US city/state SERP or Reddit discovery, keep `proxyMode` at the default `location` and pass `location` plus `proxyZip` when a city-center ZIP is known. MCP Scraper owns retryable CAPTCHA, proxy tunnel, proxy availability, and location-mismatch retries with fresh residential proxy/browser attempts. Set `debug: true` when you need sanitized attempt telemetry in the Thorbit response.
|
|
67
81
|
|
|
@@ -292,14 +292,14 @@ function renderInstallInstructions(options) {
|
|
|
292
292
|
].join("\n");
|
|
293
293
|
return [
|
|
294
294
|
renderBanner(color),
|
|
295
|
-
paint("MCP Scraper research
|
|
295
|
+
paint("MCP Scraper research, on-page analysis, and content pipeline tools for MCP agents.", ansi.slate, color),
|
|
296
296
|
"",
|
|
297
297
|
`${paint("1.", ansi.terracotta, color)} Generate an API key in Thorbit Settings -> MCPs with content/onpage scopes.`,
|
|
298
298
|
`${paint("2.", ansi.terracotta, color)} Add this server config to your MCP client:`,
|
|
299
299
|
"",
|
|
300
300
|
json,
|
|
301
301
|
"",
|
|
302
|
-
`${paint("3.", ansi.terracotta, color)} Restart your MCP client, then call ${paint("thorbit_content_harvest_serp", ansi.green, color)} or ${paint("
|
|
302
|
+
`${paint("3.", ansi.terracotta, color)} Restart your MCP client, then call ${paint("thorbit_content_harvest_serp", ansi.green, color)}, ${paint("thorbit_onpage_start_analysis", ansi.green, color)}, or ${paint("thorbit_content_pipeline_start", ansi.green, color)}.`,
|
|
303
303
|
"",
|
|
304
304
|
keySetup,
|
|
305
305
|
"",
|
|
@@ -307,8 +307,11 @@ function renderInstallInstructions(options) {
|
|
|
307
307
|
" thorbit_content_extract_url Extract a URL through MCP Scraper.",
|
|
308
308
|
" thorbit_content_harvest_serp Harvest full SERP/PAA evidence through MCP Scraper.",
|
|
309
309
|
" thorbit_content_reddit_research Read Reddit through MCP Scraper browser-agent.",
|
|
310
|
-
" thorbit_onpage_start_analysis Start durable Thorbit on-page analysis.",
|
|
311
|
-
"
|
|
310
|
+
" thorbit_onpage_start_analysis Start durable Thorbit on-page analysis from any supported source.",
|
|
311
|
+
" thorbit_onpage_generate_brief Queue or return the final writer brief.",
|
|
312
|
+
" thorbit_onpage_propose_edits Propose targeted on-page content edits.",
|
|
313
|
+
" thorbit_content_pipeline_start Start brief/write/optimize content pipeline workflows.",
|
|
314
|
+
" thorbit_content_pipeline_get Read content pipeline jobs and run views.",
|
|
312
315
|
"",
|
|
313
316
|
paint("Raw JSON:", ansi.slate, color),
|
|
314
317
|
" npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --json --api-key thbt_mcp_...",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../bin/thorbit-content-mcp-install.ts"],"sourcesContent":["import { realpathSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nexport type InstallOptions = {\n apiKey: string\n baseUrl?: string\n keyPath?: string\n serverName: string\n json: boolean\n color: boolean\n help: boolean\n}\n\nexport function readArg(name: string, argv = process.argv.slice(2)): string | undefined {\n const prefix = `--${name}=`\n const inline = argv.find(arg => arg.startsWith(prefix))\n if (inline) return inline.slice(prefix.length)\n const index = argv.indexOf(`--${name}`)\n return index >= 0 ? argv[index + 1] : undefined\n}\n\nexport function hasFlag(name: string, argv = process.argv.slice(2)): boolean {\n return argv.includes(`--${name}`)\n}\n\nexport function resolveInstallOptions(argv = process.argv.slice(2)): InstallOptions {\n return {\n apiKey: readArg('api-key', argv) ?? process.env.THORBIT_API_KEY ?? process.env.THORBIT_MCP_API_KEY ?? 'thbt_mcp_...',\n baseUrl: readArg('base-url', argv) ?? process.env.THORBIT_BASE_URL,\n keyPath: readArg('key-path', argv) ?? process.env.THORBIT_CONTENT_MCP_KEY_PATH,\n serverName: readArg('server-name', argv) ?? 'thorbit-content',\n json: hasFlag('json', argv),\n color: !hasFlag('no-color', argv),\n help: hasFlag('help', argv) || hasFlag('h', argv),\n }\n}\n\nexport function buildMcpConfig(options: InstallOptions) {\n const env: Record<string, string> = options.keyPath\n ? { THORBIT_CONTENT_MCP_KEY_PATH: options.keyPath }\n : { THORBIT_API_KEY: options.apiKey }\n\n if (options.baseUrl) {\n env.THORBIT_BASE_URL = options.baseUrl.replace(/\\/$/, '')\n }\n\n return {\n mcpServers: {\n [options.serverName]: {\n command: 'npx',\n args: ['-y', 'thorbit-content-mcp@latest'],\n env,\n },\n },\n }\n}\n\nconst ansi = {\n reset: '\\u001b[0m',\n bold: '\\u001b[1m',\n dim: '\\u001b[2m',\n terracotta: '\\u001b[38;2;198;90;54m',\n cardBg: '\\u001b[48;2;31;31;31m',\n cardBorder: '\\u001b[38;2;108;66;50m',\n clay: '\\u001b[38;2;226;138;92m',\n cream: '\\u001b[38;2;255;244;230m',\n green: '\\u001b[38;2;75;181;67m',\n shadow: '\\u001b[38;2;116;70;56m',\n slate: '\\u001b[38;2;174;181;195m',\n wire: '\\u001b[38;2;198;90;54m',\n}\n\nfunction paint(value: string, code: string, enabled: boolean): string {\n return enabled ? `${code}${value}${ansi.reset}` : value\n}\n\nexport function renderHelp(color: boolean): string {\n return [\n renderBanner(color),\n '',\n 'Usage:',\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install [options]',\n '',\n 'Options:',\n ' --api-key <key> Thorbit MCP API key from Settings -> MCPs.',\n ' --key-path <path> File containing the API key. Preferred for shared machines and servers.',\n ' --base-url <url> Thorbit app URL. Defaults to https://thorbit.ai.',\n ' --server-name <name> MCP client server name. Defaults to thorbit-content.',\n ' --json Print only MCP client JSON.',\n ' --no-color Disable ANSI color.',\n ' --help Show this help.',\n '',\n ].join('\\n')\n}\n\nexport function renderBanner(color: boolean): string {\n return color ? renderReferenceCardBanner() : renderAsciiBanner()\n}\n\nconst cardWidth = 104\n\ntype CardTone = 'title' | 'mark' | 'wire' | 'caption' | 'blank'\ntype CardPart = {\n color: string\n text: string\n}\n\nconst thorbitPixelLetters: Record<string, string[]> = {\n T: [\n '1111111',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n ],\n H: [\n '110011',\n '110011',\n '110011',\n '111111',\n '110011',\n '110011',\n '110011',\n ],\n O: [\n '011110',\n '110011',\n '110011',\n '110011',\n '110011',\n '110011',\n '011110',\n ],\n R: [\n '111110',\n '110011',\n '110011',\n '111110',\n '110110',\n '110011',\n '110011',\n ],\n B: [\n '111110',\n '110011',\n '110011',\n '111110',\n '110011',\n '110011',\n '111110',\n ],\n I: [\n '1111',\n '0110',\n '0110',\n '0110',\n '0110',\n '0110',\n '1111',\n ],\n}\n\nfunction renderReferenceCardBanner(): string {\n const heading = justifyCardContent(' Plain text', '⧉', cardWidth)\n\n return [\n `${ansi.cardBorder}╭${'─'.repeat(cardWidth + 2)}╮${ansi.reset}`,\n renderCardLine(heading, 'title'),\n renderCardLine('', 'blank'),\n ...renderLayeredPixelWordmarkCardLines('THORBIT'),\n renderCardLine('', 'blank'),\n renderCardLine(' THORBIT CONTENT MCP', 'caption'),\n `${ansi.cardBorder}╰${'─'.repeat(cardWidth + 2)}╯${ansi.reset}`,\n ].join('\\n')\n}\n\nfunction renderAsciiBanner(): string {\n const contentWidth = 96\n const border = `+${'-'.repeat(contentWidth + 2)}+`\n const cardLine = (content = '') => `| ${content.padEnd(contentWidth)} |`\n const title = 'Plain text'\n const copy = '[copy]'\n const lines = [\n border,\n cardLine(`${title}${' '.repeat(contentWidth - title.length - copy.length)}${copy}`),\n cardLine(),\n ...renderAsciiWordmark('THORBIT').map(line => cardLine(` ${line}`)),\n cardLine(),\n cardLine(' THORBIT CONTENT MCP'),\n border,\n ]\n\n return lines.join('\\n')\n}\n\nfunction renderCardLine(content: string, tone: CardTone): string {\n const foreground = {\n title: ansi.cream,\n mark: ansi.clay,\n wire: ansi.wire,\n caption: ansi.terracotta,\n blank: ansi.slate,\n }[tone]\n return renderCardLineParts([{ color: foreground, text: content }])\n}\n\nfunction renderCardLineParts(parts: CardPart[]): string {\n const visibleWidth = parts.reduce((width, part) => width + part.text.length, 0)\n const padding = ' '.repeat(Math.max(0, cardWidth - visibleWidth))\n return [\n `${ansi.cardBorder}│${ansi.reset}`,\n ansi.cardBg,\n ' ',\n ...parts.map(part => `${part.color}${part.text}`),\n padding,\n ' ',\n ansi.reset,\n `${ansi.cardBorder}│${ansi.reset}`,\n ].join('')\n}\n\nfunction justifyCardContent(left: string, right: string, width: number): string {\n return `${left}${' '.repeat(Math.max(1, width - left.length - right.length))}${right}`\n}\n\nfunction buildPixelWordmarkMatrix(word: string): boolean[][] {\n const rows: boolean[][] = Array.from({ length: 7 }, () => [])\n for (let rowIndex = 0; rowIndex < 7; rowIndex += 1) {\n word.split('').forEach((letter, letterIndex) => {\n const pattern = thorbitPixelLetters[letter]\n if (!pattern) return\n if (letterIndex > 0) rows[rowIndex].push(false)\n rows[rowIndex].push(...pattern[rowIndex].split('').map(cell => cell === '1'))\n })\n }\n return rows\n}\n\nfunction renderLayeredPixelWordmarkCardLines(word: string): string[] {\n const matrix = buildPixelWordmarkMatrix(word)\n const wordmarkWidth = Math.max(...matrix.map(row => row.length))\n const shadowOffsetX = 1\n const shadowOffsetY = -1\n const outputRows = matrix.length + Math.abs(Math.min(0, shadowOffsetY))\n const outputWidth = wordmarkWidth + shadowOffsetX\n\n return Array.from({ length: outputRows }, (_, outputRowIndex) => {\n const rowParts: CardPart[] = [{ color: ansi.slate, text: ' ' }]\n\n for (let columnIndex = 0; columnIndex < outputWidth; columnIndex += 1) {\n const foregroundRow = outputRowIndex - Math.abs(Math.min(0, shadowOffsetY))\n const hasForeground = foregroundRow >= 0 && Boolean(matrix[foregroundRow]?.[columnIndex])\n const shadowSourceRow = outputRowIndex - shadowOffsetY - Math.abs(Math.min(0, shadowOffsetY))\n const shadowSourceColumn = columnIndex - shadowOffsetX\n const hasShadow = shadowSourceRow >= 0 && shadowSourceColumn >= 0\n && Boolean(matrix[shadowSourceRow]?.[shadowSourceColumn])\n\n if (hasForeground) {\n appendCardPart(rowParts, ansi.clay, '██')\n } else if (hasShadow) {\n appendCardPart(rowParts, ansi.shadow, '░░')\n } else {\n appendCardPart(rowParts, ansi.slate, ' ')\n }\n }\n\n return renderCardLineParts(rowParts)\n })\n}\n\nfunction appendCardPart(parts: CardPart[], color: string, text: string): void {\n const previous = parts[parts.length - 1]\n if (previous?.color === color) {\n previous.text += text\n return\n }\n parts.push({ color, text })\n}\n\nfunction renderAsciiWordmark(word: string): string[] {\n const matrix = buildPixelWordmarkMatrix(word)\n const rows: string[] = []\n for (const matrixRow of matrix) {\n rows.push(matrixRow.map(cell => (cell ? '#' : ' ')).join(''))\n }\n return rows\n}\n\nexport function renderInstallInstructions(options: InstallOptions): string {\n const color = options.color\n const json = JSON.stringify(buildMcpConfig(options), null, 2)\n const keySetup = options.keyPath\n ? [\n paint('Key file mode', ansi.terracotta, color),\n ` chmod 600 ${options.keyPath}`,\n ].join('\\n')\n : [\n paint('Safer key-file option', ansi.terracotta, color),\n ' mkdir -p ~/.config/thorbit',\n \" printf '%s\\\\n' 'thbt_mcp_...' > ~/.config/thorbit/content-mcp-key\",\n ' chmod 600 ~/.config/thorbit/content-mcp-key',\n '',\n ' Then run:',\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --key-path ~/.config/thorbit/content-mcp-key',\n ].join('\\n')\n\n return [\n renderBanner(color),\n paint('MCP Scraper research and on-page analysis for MCP agents.', ansi.slate, color),\n '',\n `${paint('1.', ansi.terracotta, color)} Generate an API key in Thorbit Settings -> MCPs with content/onpage scopes.`,\n `${paint('2.', ansi.terracotta, color)} Add this server config to your MCP client:`,\n '',\n json,\n '',\n `${paint('3.', ansi.terracotta, color)} Restart your MCP client, then call ${paint('thorbit_content_harvest_serp', ansi.green, color)} or ${paint('thorbit_content_reddit_research', ansi.green, color)}.`,\n '',\n keySetup,\n '',\n paint('Tools', ansi.terracotta, color),\n ' thorbit_content_extract_url Extract a URL through MCP Scraper.',\n ' thorbit_content_harvest_serp Harvest full SERP/PAA evidence through MCP Scraper.',\n ' thorbit_content_reddit_research Read Reddit through MCP Scraper browser-agent.',\n ' thorbit_onpage_start_analysis Start durable Thorbit on-page analysis.',\n ' thorbit_onpage_get_analysis Read analysis status and summary.',\n '',\n paint('Raw JSON:', ansi.slate, color),\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --json --api-key thbt_mcp_...',\n '',\n ].join('\\n')\n}\n\nexport function main(): void {\n const options = resolveInstallOptions()\n if (options.help) {\n process.stdout.write(renderHelp(options.color))\n return\n }\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(buildMcpConfig(options), null, 2)}\\n`)\n return\n }\n\n process.stdout.write(renderInstallInstructions(options))\n}\n\nfunction isMainModule(): boolean {\n const entry = process.argv[1]\n if (!entry) return false\n try {\n return realpathSync(entry) === realpathSync(fileURLToPath(import.meta.url))\n } catch {\n return false\n }\n}\n\nif (isMainModule()) main()\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../bin/thorbit-content-mcp-install.ts"],"sourcesContent":["import { realpathSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nexport type InstallOptions = {\n apiKey: string\n baseUrl?: string\n keyPath?: string\n serverName: string\n json: boolean\n color: boolean\n help: boolean\n}\n\nexport function readArg(name: string, argv = process.argv.slice(2)): string | undefined {\n const prefix = `--${name}=`\n const inline = argv.find(arg => arg.startsWith(prefix))\n if (inline) return inline.slice(prefix.length)\n const index = argv.indexOf(`--${name}`)\n return index >= 0 ? argv[index + 1] : undefined\n}\n\nexport function hasFlag(name: string, argv = process.argv.slice(2)): boolean {\n return argv.includes(`--${name}`)\n}\n\nexport function resolveInstallOptions(argv = process.argv.slice(2)): InstallOptions {\n return {\n apiKey: readArg('api-key', argv) ?? process.env.THORBIT_API_KEY ?? process.env.THORBIT_MCP_API_KEY ?? 'thbt_mcp_...',\n baseUrl: readArg('base-url', argv) ?? process.env.THORBIT_BASE_URL,\n keyPath: readArg('key-path', argv) ?? process.env.THORBIT_CONTENT_MCP_KEY_PATH,\n serverName: readArg('server-name', argv) ?? 'thorbit-content',\n json: hasFlag('json', argv),\n color: !hasFlag('no-color', argv),\n help: hasFlag('help', argv) || hasFlag('h', argv),\n }\n}\n\nexport function buildMcpConfig(options: InstallOptions) {\n const env: Record<string, string> = options.keyPath\n ? { THORBIT_CONTENT_MCP_KEY_PATH: options.keyPath }\n : { THORBIT_API_KEY: options.apiKey }\n\n if (options.baseUrl) {\n env.THORBIT_BASE_URL = options.baseUrl.replace(/\\/$/, '')\n }\n\n return {\n mcpServers: {\n [options.serverName]: {\n command: 'npx',\n args: ['-y', 'thorbit-content-mcp@latest'],\n env,\n },\n },\n }\n}\n\nconst ansi = {\n reset: '\\u001b[0m',\n bold: '\\u001b[1m',\n dim: '\\u001b[2m',\n terracotta: '\\u001b[38;2;198;90;54m',\n cardBg: '\\u001b[48;2;31;31;31m',\n cardBorder: '\\u001b[38;2;108;66;50m',\n clay: '\\u001b[38;2;226;138;92m',\n cream: '\\u001b[38;2;255;244;230m',\n green: '\\u001b[38;2;75;181;67m',\n shadow: '\\u001b[38;2;116;70;56m',\n slate: '\\u001b[38;2;174;181;195m',\n wire: '\\u001b[38;2;198;90;54m',\n}\n\nfunction paint(value: string, code: string, enabled: boolean): string {\n return enabled ? `${code}${value}${ansi.reset}` : value\n}\n\nexport function renderHelp(color: boolean): string {\n return [\n renderBanner(color),\n '',\n 'Usage:',\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install [options]',\n '',\n 'Options:',\n ' --api-key <key> Thorbit MCP API key from Settings -> MCPs.',\n ' --key-path <path> File containing the API key. Preferred for shared machines and servers.',\n ' --base-url <url> Thorbit app URL. Defaults to https://thorbit.ai.',\n ' --server-name <name> MCP client server name. Defaults to thorbit-content.',\n ' --json Print only MCP client JSON.',\n ' --no-color Disable ANSI color.',\n ' --help Show this help.',\n '',\n ].join('\\n')\n}\n\nexport function renderBanner(color: boolean): string {\n return color ? renderReferenceCardBanner() : renderAsciiBanner()\n}\n\nconst cardWidth = 104\n\ntype CardTone = 'title' | 'mark' | 'wire' | 'caption' | 'blank'\ntype CardPart = {\n color: string\n text: string\n}\n\nconst thorbitPixelLetters: Record<string, string[]> = {\n T: [\n '1111111',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n ],\n H: [\n '110011',\n '110011',\n '110011',\n '111111',\n '110011',\n '110011',\n '110011',\n ],\n O: [\n '011110',\n '110011',\n '110011',\n '110011',\n '110011',\n '110011',\n '011110',\n ],\n R: [\n '111110',\n '110011',\n '110011',\n '111110',\n '110110',\n '110011',\n '110011',\n ],\n B: [\n '111110',\n '110011',\n '110011',\n '111110',\n '110011',\n '110011',\n '111110',\n ],\n I: [\n '1111',\n '0110',\n '0110',\n '0110',\n '0110',\n '0110',\n '1111',\n ],\n}\n\nfunction renderReferenceCardBanner(): string {\n const heading = justifyCardContent(' Plain text', '⧉', cardWidth)\n\n return [\n `${ansi.cardBorder}╭${'─'.repeat(cardWidth + 2)}╮${ansi.reset}`,\n renderCardLine(heading, 'title'),\n renderCardLine('', 'blank'),\n ...renderLayeredPixelWordmarkCardLines('THORBIT'),\n renderCardLine('', 'blank'),\n renderCardLine(' THORBIT CONTENT MCP', 'caption'),\n `${ansi.cardBorder}╰${'─'.repeat(cardWidth + 2)}╯${ansi.reset}`,\n ].join('\\n')\n}\n\nfunction renderAsciiBanner(): string {\n const contentWidth = 96\n const border = `+${'-'.repeat(contentWidth + 2)}+`\n const cardLine = (content = '') => `| ${content.padEnd(contentWidth)} |`\n const title = 'Plain text'\n const copy = '[copy]'\n const lines = [\n border,\n cardLine(`${title}${' '.repeat(contentWidth - title.length - copy.length)}${copy}`),\n cardLine(),\n ...renderAsciiWordmark('THORBIT').map(line => cardLine(` ${line}`)),\n cardLine(),\n cardLine(' THORBIT CONTENT MCP'),\n border,\n ]\n\n return lines.join('\\n')\n}\n\nfunction renderCardLine(content: string, tone: CardTone): string {\n const foreground = {\n title: ansi.cream,\n mark: ansi.clay,\n wire: ansi.wire,\n caption: ansi.terracotta,\n blank: ansi.slate,\n }[tone]\n return renderCardLineParts([{ color: foreground, text: content }])\n}\n\nfunction renderCardLineParts(parts: CardPart[]): string {\n const visibleWidth = parts.reduce((width, part) => width + part.text.length, 0)\n const padding = ' '.repeat(Math.max(0, cardWidth - visibleWidth))\n return [\n `${ansi.cardBorder}│${ansi.reset}`,\n ansi.cardBg,\n ' ',\n ...parts.map(part => `${part.color}${part.text}`),\n padding,\n ' ',\n ansi.reset,\n `${ansi.cardBorder}│${ansi.reset}`,\n ].join('')\n}\n\nfunction justifyCardContent(left: string, right: string, width: number): string {\n return `${left}${' '.repeat(Math.max(1, width - left.length - right.length))}${right}`\n}\n\nfunction buildPixelWordmarkMatrix(word: string): boolean[][] {\n const rows: boolean[][] = Array.from({ length: 7 }, () => [])\n for (let rowIndex = 0; rowIndex < 7; rowIndex += 1) {\n word.split('').forEach((letter, letterIndex) => {\n const pattern = thorbitPixelLetters[letter]\n if (!pattern) return\n if (letterIndex > 0) rows[rowIndex].push(false)\n rows[rowIndex].push(...pattern[rowIndex].split('').map(cell => cell === '1'))\n })\n }\n return rows\n}\n\nfunction renderLayeredPixelWordmarkCardLines(word: string): string[] {\n const matrix = buildPixelWordmarkMatrix(word)\n const wordmarkWidth = Math.max(...matrix.map(row => row.length))\n const shadowOffsetX = 1\n const shadowOffsetY = -1\n const outputRows = matrix.length + Math.abs(Math.min(0, shadowOffsetY))\n const outputWidth = wordmarkWidth + shadowOffsetX\n\n return Array.from({ length: outputRows }, (_, outputRowIndex) => {\n const rowParts: CardPart[] = [{ color: ansi.slate, text: ' ' }]\n\n for (let columnIndex = 0; columnIndex < outputWidth; columnIndex += 1) {\n const foregroundRow = outputRowIndex - Math.abs(Math.min(0, shadowOffsetY))\n const hasForeground = foregroundRow >= 0 && Boolean(matrix[foregroundRow]?.[columnIndex])\n const shadowSourceRow = outputRowIndex - shadowOffsetY - Math.abs(Math.min(0, shadowOffsetY))\n const shadowSourceColumn = columnIndex - shadowOffsetX\n const hasShadow = shadowSourceRow >= 0 && shadowSourceColumn >= 0\n && Boolean(matrix[shadowSourceRow]?.[shadowSourceColumn])\n\n if (hasForeground) {\n appendCardPart(rowParts, ansi.clay, '██')\n } else if (hasShadow) {\n appendCardPart(rowParts, ansi.shadow, '░░')\n } else {\n appendCardPart(rowParts, ansi.slate, ' ')\n }\n }\n\n return renderCardLineParts(rowParts)\n })\n}\n\nfunction appendCardPart(parts: CardPart[], color: string, text: string): void {\n const previous = parts[parts.length - 1]\n if (previous?.color === color) {\n previous.text += text\n return\n }\n parts.push({ color, text })\n}\n\nfunction renderAsciiWordmark(word: string): string[] {\n const matrix = buildPixelWordmarkMatrix(word)\n const rows: string[] = []\n for (const matrixRow of matrix) {\n rows.push(matrixRow.map(cell => (cell ? '#' : ' ')).join(''))\n }\n return rows\n}\n\nexport function renderInstallInstructions(options: InstallOptions): string {\n const color = options.color\n const json = JSON.stringify(buildMcpConfig(options), null, 2)\n const keySetup = options.keyPath\n ? [\n paint('Key file mode', ansi.terracotta, color),\n ` chmod 600 ${options.keyPath}`,\n ].join('\\n')\n : [\n paint('Safer key-file option', ansi.terracotta, color),\n ' mkdir -p ~/.config/thorbit',\n \" printf '%s\\\\n' 'thbt_mcp_...' > ~/.config/thorbit/content-mcp-key\",\n ' chmod 600 ~/.config/thorbit/content-mcp-key',\n '',\n ' Then run:',\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --key-path ~/.config/thorbit/content-mcp-key',\n ].join('\\n')\n\n return [\n renderBanner(color),\n paint('MCP Scraper research, on-page analysis, and content pipeline tools for MCP agents.', ansi.slate, color),\n '',\n `${paint('1.', ansi.terracotta, color)} Generate an API key in Thorbit Settings -> MCPs with content/onpage scopes.`,\n `${paint('2.', ansi.terracotta, color)} Add this server config to your MCP client:`,\n '',\n json,\n '',\n `${paint('3.', ansi.terracotta, color)} Restart your MCP client, then call ${paint('thorbit_content_harvest_serp', ansi.green, color)}, ${paint('thorbit_onpage_start_analysis', ansi.green, color)}, or ${paint('thorbit_content_pipeline_start', ansi.green, color)}.`,\n '',\n keySetup,\n '',\n paint('Tools', ansi.terracotta, color),\n ' thorbit_content_extract_url Extract a URL through MCP Scraper.',\n ' thorbit_content_harvest_serp Harvest full SERP/PAA evidence through MCP Scraper.',\n ' thorbit_content_reddit_research Read Reddit through MCP Scraper browser-agent.',\n ' thorbit_onpage_start_analysis Start durable Thorbit on-page analysis from any supported source.',\n ' thorbit_onpage_generate_brief Queue or return the final writer brief.',\n ' thorbit_onpage_propose_edits Propose targeted on-page content edits.',\n ' thorbit_content_pipeline_start Start brief/write/optimize content pipeline workflows.',\n ' thorbit_content_pipeline_get Read content pipeline jobs and run views.',\n '',\n paint('Raw JSON:', ansi.slate, color),\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --json --api-key thbt_mcp_...',\n '',\n ].join('\\n')\n}\n\nexport function main(): void {\n const options = resolveInstallOptions()\n if (options.help) {\n process.stdout.write(renderHelp(options.color))\n return\n }\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(buildMcpConfig(options), null, 2)}\\n`)\n return\n }\n\n process.stdout.write(renderInstallInstructions(options))\n}\n\nfunction isMainModule(): boolean {\n const entry = process.argv[1]\n if (!entry) return false\n try {\n return realpathSync(entry) === realpathSync(fileURLToPath(import.meta.url))\n } catch {\n return false\n }\n}\n\nif (isMainModule()) main()\n"],"mappings":"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","names":[]}
|
|
@@ -261,14 +261,14 @@ function renderInstallInstructions(options) {
|
|
|
261
261
|
].join("\n");
|
|
262
262
|
return [
|
|
263
263
|
renderBanner(color),
|
|
264
|
-
paint("MCP Scraper research
|
|
264
|
+
paint("MCP Scraper research, on-page analysis, and content pipeline tools for MCP agents.", ansi.slate, color),
|
|
265
265
|
"",
|
|
266
266
|
`${paint("1.", ansi.terracotta, color)} Generate an API key in Thorbit Settings -> MCPs with content/onpage scopes.`,
|
|
267
267
|
`${paint("2.", ansi.terracotta, color)} Add this server config to your MCP client:`,
|
|
268
268
|
"",
|
|
269
269
|
json,
|
|
270
270
|
"",
|
|
271
|
-
`${paint("3.", ansi.terracotta, color)} Restart your MCP client, then call ${paint("thorbit_content_harvest_serp", ansi.green, color)} or ${paint("
|
|
271
|
+
`${paint("3.", ansi.terracotta, color)} Restart your MCP client, then call ${paint("thorbit_content_harvest_serp", ansi.green, color)}, ${paint("thorbit_onpage_start_analysis", ansi.green, color)}, or ${paint("thorbit_content_pipeline_start", ansi.green, color)}.`,
|
|
272
272
|
"",
|
|
273
273
|
keySetup,
|
|
274
274
|
"",
|
|
@@ -276,8 +276,11 @@ function renderInstallInstructions(options) {
|
|
|
276
276
|
" thorbit_content_extract_url Extract a URL through MCP Scraper.",
|
|
277
277
|
" thorbit_content_harvest_serp Harvest full SERP/PAA evidence through MCP Scraper.",
|
|
278
278
|
" thorbit_content_reddit_research Read Reddit through MCP Scraper browser-agent.",
|
|
279
|
-
" thorbit_onpage_start_analysis Start durable Thorbit on-page analysis.",
|
|
280
|
-
"
|
|
279
|
+
" thorbit_onpage_start_analysis Start durable Thorbit on-page analysis from any supported source.",
|
|
280
|
+
" thorbit_onpage_generate_brief Queue or return the final writer brief.",
|
|
281
|
+
" thorbit_onpage_propose_edits Propose targeted on-page content edits.",
|
|
282
|
+
" thorbit_content_pipeline_start Start brief/write/optimize content pipeline workflows.",
|
|
283
|
+
" thorbit_content_pipeline_get Read content pipeline jobs and run views.",
|
|
281
284
|
"",
|
|
282
285
|
paint("Raw JSON:", ansi.slate, color),
|
|
283
286
|
" npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --json --api-key thbt_mcp_...",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../bin/thorbit-content-mcp-install.ts"],"sourcesContent":["import { realpathSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nexport type InstallOptions = {\n apiKey: string\n baseUrl?: string\n keyPath?: string\n serverName: string\n json: boolean\n color: boolean\n help: boolean\n}\n\nexport function readArg(name: string, argv = process.argv.slice(2)): string | undefined {\n const prefix = `--${name}=`\n const inline = argv.find(arg => arg.startsWith(prefix))\n if (inline) return inline.slice(prefix.length)\n const index = argv.indexOf(`--${name}`)\n return index >= 0 ? argv[index + 1] : undefined\n}\n\nexport function hasFlag(name: string, argv = process.argv.slice(2)): boolean {\n return argv.includes(`--${name}`)\n}\n\nexport function resolveInstallOptions(argv = process.argv.slice(2)): InstallOptions {\n return {\n apiKey: readArg('api-key', argv) ?? process.env.THORBIT_API_KEY ?? process.env.THORBIT_MCP_API_KEY ?? 'thbt_mcp_...',\n baseUrl: readArg('base-url', argv) ?? process.env.THORBIT_BASE_URL,\n keyPath: readArg('key-path', argv) ?? process.env.THORBIT_CONTENT_MCP_KEY_PATH,\n serverName: readArg('server-name', argv) ?? 'thorbit-content',\n json: hasFlag('json', argv),\n color: !hasFlag('no-color', argv),\n help: hasFlag('help', argv) || hasFlag('h', argv),\n }\n}\n\nexport function buildMcpConfig(options: InstallOptions) {\n const env: Record<string, string> = options.keyPath\n ? { THORBIT_CONTENT_MCP_KEY_PATH: options.keyPath }\n : { THORBIT_API_KEY: options.apiKey }\n\n if (options.baseUrl) {\n env.THORBIT_BASE_URL = options.baseUrl.replace(/\\/$/, '')\n }\n\n return {\n mcpServers: {\n [options.serverName]: {\n command: 'npx',\n args: ['-y', 'thorbit-content-mcp@latest'],\n env,\n },\n },\n }\n}\n\nconst ansi = {\n reset: '\\u001b[0m',\n bold: '\\u001b[1m',\n dim: '\\u001b[2m',\n terracotta: '\\u001b[38;2;198;90;54m',\n cardBg: '\\u001b[48;2;31;31;31m',\n cardBorder: '\\u001b[38;2;108;66;50m',\n clay: '\\u001b[38;2;226;138;92m',\n cream: '\\u001b[38;2;255;244;230m',\n green: '\\u001b[38;2;75;181;67m',\n shadow: '\\u001b[38;2;116;70;56m',\n slate: '\\u001b[38;2;174;181;195m',\n wire: '\\u001b[38;2;198;90;54m',\n}\n\nfunction paint(value: string, code: string, enabled: boolean): string {\n return enabled ? `${code}${value}${ansi.reset}` : value\n}\n\nexport function renderHelp(color: boolean): string {\n return [\n renderBanner(color),\n '',\n 'Usage:',\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install [options]',\n '',\n 'Options:',\n ' --api-key <key> Thorbit MCP API key from Settings -> MCPs.',\n ' --key-path <path> File containing the API key. Preferred for shared machines and servers.',\n ' --base-url <url> Thorbit app URL. Defaults to https://thorbit.ai.',\n ' --server-name <name> MCP client server name. Defaults to thorbit-content.',\n ' --json Print only MCP client JSON.',\n ' --no-color Disable ANSI color.',\n ' --help Show this help.',\n '',\n ].join('\\n')\n}\n\nexport function renderBanner(color: boolean): string {\n return color ? renderReferenceCardBanner() : renderAsciiBanner()\n}\n\nconst cardWidth = 104\n\ntype CardTone = 'title' | 'mark' | 'wire' | 'caption' | 'blank'\ntype CardPart = {\n color: string\n text: string\n}\n\nconst thorbitPixelLetters: Record<string, string[]> = {\n T: [\n '1111111',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n ],\n H: [\n '110011',\n '110011',\n '110011',\n '111111',\n '110011',\n '110011',\n '110011',\n ],\n O: [\n '011110',\n '110011',\n '110011',\n '110011',\n '110011',\n '110011',\n '011110',\n ],\n R: [\n '111110',\n '110011',\n '110011',\n '111110',\n '110110',\n '110011',\n '110011',\n ],\n B: [\n '111110',\n '110011',\n '110011',\n '111110',\n '110011',\n '110011',\n '111110',\n ],\n I: [\n '1111',\n '0110',\n '0110',\n '0110',\n '0110',\n '0110',\n '1111',\n ],\n}\n\nfunction renderReferenceCardBanner(): string {\n const heading = justifyCardContent(' Plain text', '⧉', cardWidth)\n\n return [\n `${ansi.cardBorder}╭${'─'.repeat(cardWidth + 2)}╮${ansi.reset}`,\n renderCardLine(heading, 'title'),\n renderCardLine('', 'blank'),\n ...renderLayeredPixelWordmarkCardLines('THORBIT'),\n renderCardLine('', 'blank'),\n renderCardLine(' THORBIT CONTENT MCP', 'caption'),\n `${ansi.cardBorder}╰${'─'.repeat(cardWidth + 2)}╯${ansi.reset}`,\n ].join('\\n')\n}\n\nfunction renderAsciiBanner(): string {\n const contentWidth = 96\n const border = `+${'-'.repeat(contentWidth + 2)}+`\n const cardLine = (content = '') => `| ${content.padEnd(contentWidth)} |`\n const title = 'Plain text'\n const copy = '[copy]'\n const lines = [\n border,\n cardLine(`${title}${' '.repeat(contentWidth - title.length - copy.length)}${copy}`),\n cardLine(),\n ...renderAsciiWordmark('THORBIT').map(line => cardLine(` ${line}`)),\n cardLine(),\n cardLine(' THORBIT CONTENT MCP'),\n border,\n ]\n\n return lines.join('\\n')\n}\n\nfunction renderCardLine(content: string, tone: CardTone): string {\n const foreground = {\n title: ansi.cream,\n mark: ansi.clay,\n wire: ansi.wire,\n caption: ansi.terracotta,\n blank: ansi.slate,\n }[tone]\n return renderCardLineParts([{ color: foreground, text: content }])\n}\n\nfunction renderCardLineParts(parts: CardPart[]): string {\n const visibleWidth = parts.reduce((width, part) => width + part.text.length, 0)\n const padding = ' '.repeat(Math.max(0, cardWidth - visibleWidth))\n return [\n `${ansi.cardBorder}│${ansi.reset}`,\n ansi.cardBg,\n ' ',\n ...parts.map(part => `${part.color}${part.text}`),\n padding,\n ' ',\n ansi.reset,\n `${ansi.cardBorder}│${ansi.reset}`,\n ].join('')\n}\n\nfunction justifyCardContent(left: string, right: string, width: number): string {\n return `${left}${' '.repeat(Math.max(1, width - left.length - right.length))}${right}`\n}\n\nfunction buildPixelWordmarkMatrix(word: string): boolean[][] {\n const rows: boolean[][] = Array.from({ length: 7 }, () => [])\n for (let rowIndex = 0; rowIndex < 7; rowIndex += 1) {\n word.split('').forEach((letter, letterIndex) => {\n const pattern = thorbitPixelLetters[letter]\n if (!pattern) return\n if (letterIndex > 0) rows[rowIndex].push(false)\n rows[rowIndex].push(...pattern[rowIndex].split('').map(cell => cell === '1'))\n })\n }\n return rows\n}\n\nfunction renderLayeredPixelWordmarkCardLines(word: string): string[] {\n const matrix = buildPixelWordmarkMatrix(word)\n const wordmarkWidth = Math.max(...matrix.map(row => row.length))\n const shadowOffsetX = 1\n const shadowOffsetY = -1\n const outputRows = matrix.length + Math.abs(Math.min(0, shadowOffsetY))\n const outputWidth = wordmarkWidth + shadowOffsetX\n\n return Array.from({ length: outputRows }, (_, outputRowIndex) => {\n const rowParts: CardPart[] = [{ color: ansi.slate, text: ' ' }]\n\n for (let columnIndex = 0; columnIndex < outputWidth; columnIndex += 1) {\n const foregroundRow = outputRowIndex - Math.abs(Math.min(0, shadowOffsetY))\n const hasForeground = foregroundRow >= 0 && Boolean(matrix[foregroundRow]?.[columnIndex])\n const shadowSourceRow = outputRowIndex - shadowOffsetY - Math.abs(Math.min(0, shadowOffsetY))\n const shadowSourceColumn = columnIndex - shadowOffsetX\n const hasShadow = shadowSourceRow >= 0 && shadowSourceColumn >= 0\n && Boolean(matrix[shadowSourceRow]?.[shadowSourceColumn])\n\n if (hasForeground) {\n appendCardPart(rowParts, ansi.clay, '██')\n } else if (hasShadow) {\n appendCardPart(rowParts, ansi.shadow, '░░')\n } else {\n appendCardPart(rowParts, ansi.slate, ' ')\n }\n }\n\n return renderCardLineParts(rowParts)\n })\n}\n\nfunction appendCardPart(parts: CardPart[], color: string, text: string): void {\n const previous = parts[parts.length - 1]\n if (previous?.color === color) {\n previous.text += text\n return\n }\n parts.push({ color, text })\n}\n\nfunction renderAsciiWordmark(word: string): string[] {\n const matrix = buildPixelWordmarkMatrix(word)\n const rows: string[] = []\n for (const matrixRow of matrix) {\n rows.push(matrixRow.map(cell => (cell ? '#' : ' ')).join(''))\n }\n return rows\n}\n\nexport function renderInstallInstructions(options: InstallOptions): string {\n const color = options.color\n const json = JSON.stringify(buildMcpConfig(options), null, 2)\n const keySetup = options.keyPath\n ? [\n paint('Key file mode', ansi.terracotta, color),\n ` chmod 600 ${options.keyPath}`,\n ].join('\\n')\n : [\n paint('Safer key-file option', ansi.terracotta, color),\n ' mkdir -p ~/.config/thorbit',\n \" printf '%s\\\\n' 'thbt_mcp_...' > ~/.config/thorbit/content-mcp-key\",\n ' chmod 600 ~/.config/thorbit/content-mcp-key',\n '',\n ' Then run:',\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --key-path ~/.config/thorbit/content-mcp-key',\n ].join('\\n')\n\n return [\n renderBanner(color),\n paint('MCP Scraper research and on-page analysis for MCP agents.', ansi.slate, color),\n '',\n `${paint('1.', ansi.terracotta, color)} Generate an API key in Thorbit Settings -> MCPs with content/onpage scopes.`,\n `${paint('2.', ansi.terracotta, color)} Add this server config to your MCP client:`,\n '',\n json,\n '',\n `${paint('3.', ansi.terracotta, color)} Restart your MCP client, then call ${paint('thorbit_content_harvest_serp', ansi.green, color)} or ${paint('thorbit_content_reddit_research', ansi.green, color)}.`,\n '',\n keySetup,\n '',\n paint('Tools', ansi.terracotta, color),\n ' thorbit_content_extract_url Extract a URL through MCP Scraper.',\n ' thorbit_content_harvest_serp Harvest full SERP/PAA evidence through MCP Scraper.',\n ' thorbit_content_reddit_research Read Reddit through MCP Scraper browser-agent.',\n ' thorbit_onpage_start_analysis Start durable Thorbit on-page analysis.',\n ' thorbit_onpage_get_analysis Read analysis status and summary.',\n '',\n paint('Raw JSON:', ansi.slate, color),\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --json --api-key thbt_mcp_...',\n '',\n ].join('\\n')\n}\n\nexport function main(): void {\n const options = resolveInstallOptions()\n if (options.help) {\n process.stdout.write(renderHelp(options.color))\n return\n }\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(buildMcpConfig(options), null, 2)}\\n`)\n return\n }\n\n process.stdout.write(renderInstallInstructions(options))\n}\n\nfunction isMainModule(): boolean {\n const entry = process.argv[1]\n if (!entry) return false\n try {\n return realpathSync(entry) === realpathSync(fileURLToPath(import.meta.url))\n } catch {\n return false\n }\n}\n\nif (isMainModule()) main()\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../bin/thorbit-content-mcp-install.ts"],"sourcesContent":["import { realpathSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nexport type InstallOptions = {\n apiKey: string\n baseUrl?: string\n keyPath?: string\n serverName: string\n json: boolean\n color: boolean\n help: boolean\n}\n\nexport function readArg(name: string, argv = process.argv.slice(2)): string | undefined {\n const prefix = `--${name}=`\n const inline = argv.find(arg => arg.startsWith(prefix))\n if (inline) return inline.slice(prefix.length)\n const index = argv.indexOf(`--${name}`)\n return index >= 0 ? argv[index + 1] : undefined\n}\n\nexport function hasFlag(name: string, argv = process.argv.slice(2)): boolean {\n return argv.includes(`--${name}`)\n}\n\nexport function resolveInstallOptions(argv = process.argv.slice(2)): InstallOptions {\n return {\n apiKey: readArg('api-key', argv) ?? process.env.THORBIT_API_KEY ?? process.env.THORBIT_MCP_API_KEY ?? 'thbt_mcp_...',\n baseUrl: readArg('base-url', argv) ?? process.env.THORBIT_BASE_URL,\n keyPath: readArg('key-path', argv) ?? process.env.THORBIT_CONTENT_MCP_KEY_PATH,\n serverName: readArg('server-name', argv) ?? 'thorbit-content',\n json: hasFlag('json', argv),\n color: !hasFlag('no-color', argv),\n help: hasFlag('help', argv) || hasFlag('h', argv),\n }\n}\n\nexport function buildMcpConfig(options: InstallOptions) {\n const env: Record<string, string> = options.keyPath\n ? { THORBIT_CONTENT_MCP_KEY_PATH: options.keyPath }\n : { THORBIT_API_KEY: options.apiKey }\n\n if (options.baseUrl) {\n env.THORBIT_BASE_URL = options.baseUrl.replace(/\\/$/, '')\n }\n\n return {\n mcpServers: {\n [options.serverName]: {\n command: 'npx',\n args: ['-y', 'thorbit-content-mcp@latest'],\n env,\n },\n },\n }\n}\n\nconst ansi = {\n reset: '\\u001b[0m',\n bold: '\\u001b[1m',\n dim: '\\u001b[2m',\n terracotta: '\\u001b[38;2;198;90;54m',\n cardBg: '\\u001b[48;2;31;31;31m',\n cardBorder: '\\u001b[38;2;108;66;50m',\n clay: '\\u001b[38;2;226;138;92m',\n cream: '\\u001b[38;2;255;244;230m',\n green: '\\u001b[38;2;75;181;67m',\n shadow: '\\u001b[38;2;116;70;56m',\n slate: '\\u001b[38;2;174;181;195m',\n wire: '\\u001b[38;2;198;90;54m',\n}\n\nfunction paint(value: string, code: string, enabled: boolean): string {\n return enabled ? `${code}${value}${ansi.reset}` : value\n}\n\nexport function renderHelp(color: boolean): string {\n return [\n renderBanner(color),\n '',\n 'Usage:',\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install [options]',\n '',\n 'Options:',\n ' --api-key <key> Thorbit MCP API key from Settings -> MCPs.',\n ' --key-path <path> File containing the API key. Preferred for shared machines and servers.',\n ' --base-url <url> Thorbit app URL. Defaults to https://thorbit.ai.',\n ' --server-name <name> MCP client server name. Defaults to thorbit-content.',\n ' --json Print only MCP client JSON.',\n ' --no-color Disable ANSI color.',\n ' --help Show this help.',\n '',\n ].join('\\n')\n}\n\nexport function renderBanner(color: boolean): string {\n return color ? renderReferenceCardBanner() : renderAsciiBanner()\n}\n\nconst cardWidth = 104\n\ntype CardTone = 'title' | 'mark' | 'wire' | 'caption' | 'blank'\ntype CardPart = {\n color: string\n text: string\n}\n\nconst thorbitPixelLetters: Record<string, string[]> = {\n T: [\n '1111111',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n '0011000',\n ],\n H: [\n '110011',\n '110011',\n '110011',\n '111111',\n '110011',\n '110011',\n '110011',\n ],\n O: [\n '011110',\n '110011',\n '110011',\n '110011',\n '110011',\n '110011',\n '011110',\n ],\n R: [\n '111110',\n '110011',\n '110011',\n '111110',\n '110110',\n '110011',\n '110011',\n ],\n B: [\n '111110',\n '110011',\n '110011',\n '111110',\n '110011',\n '110011',\n '111110',\n ],\n I: [\n '1111',\n '0110',\n '0110',\n '0110',\n '0110',\n '0110',\n '1111',\n ],\n}\n\nfunction renderReferenceCardBanner(): string {\n const heading = justifyCardContent(' Plain text', '⧉', cardWidth)\n\n return [\n `${ansi.cardBorder}╭${'─'.repeat(cardWidth + 2)}╮${ansi.reset}`,\n renderCardLine(heading, 'title'),\n renderCardLine('', 'blank'),\n ...renderLayeredPixelWordmarkCardLines('THORBIT'),\n renderCardLine('', 'blank'),\n renderCardLine(' THORBIT CONTENT MCP', 'caption'),\n `${ansi.cardBorder}╰${'─'.repeat(cardWidth + 2)}╯${ansi.reset}`,\n ].join('\\n')\n}\n\nfunction renderAsciiBanner(): string {\n const contentWidth = 96\n const border = `+${'-'.repeat(contentWidth + 2)}+`\n const cardLine = (content = '') => `| ${content.padEnd(contentWidth)} |`\n const title = 'Plain text'\n const copy = '[copy]'\n const lines = [\n border,\n cardLine(`${title}${' '.repeat(contentWidth - title.length - copy.length)}${copy}`),\n cardLine(),\n ...renderAsciiWordmark('THORBIT').map(line => cardLine(` ${line}`)),\n cardLine(),\n cardLine(' THORBIT CONTENT MCP'),\n border,\n ]\n\n return lines.join('\\n')\n}\n\nfunction renderCardLine(content: string, tone: CardTone): string {\n const foreground = {\n title: ansi.cream,\n mark: ansi.clay,\n wire: ansi.wire,\n caption: ansi.terracotta,\n blank: ansi.slate,\n }[tone]\n return renderCardLineParts([{ color: foreground, text: content }])\n}\n\nfunction renderCardLineParts(parts: CardPart[]): string {\n const visibleWidth = parts.reduce((width, part) => width + part.text.length, 0)\n const padding = ' '.repeat(Math.max(0, cardWidth - visibleWidth))\n return [\n `${ansi.cardBorder}│${ansi.reset}`,\n ansi.cardBg,\n ' ',\n ...parts.map(part => `${part.color}${part.text}`),\n padding,\n ' ',\n ansi.reset,\n `${ansi.cardBorder}│${ansi.reset}`,\n ].join('')\n}\n\nfunction justifyCardContent(left: string, right: string, width: number): string {\n return `${left}${' '.repeat(Math.max(1, width - left.length - right.length))}${right}`\n}\n\nfunction buildPixelWordmarkMatrix(word: string): boolean[][] {\n const rows: boolean[][] = Array.from({ length: 7 }, () => [])\n for (let rowIndex = 0; rowIndex < 7; rowIndex += 1) {\n word.split('').forEach((letter, letterIndex) => {\n const pattern = thorbitPixelLetters[letter]\n if (!pattern) return\n if (letterIndex > 0) rows[rowIndex].push(false)\n rows[rowIndex].push(...pattern[rowIndex].split('').map(cell => cell === '1'))\n })\n }\n return rows\n}\n\nfunction renderLayeredPixelWordmarkCardLines(word: string): string[] {\n const matrix = buildPixelWordmarkMatrix(word)\n const wordmarkWidth = Math.max(...matrix.map(row => row.length))\n const shadowOffsetX = 1\n const shadowOffsetY = -1\n const outputRows = matrix.length + Math.abs(Math.min(0, shadowOffsetY))\n const outputWidth = wordmarkWidth + shadowOffsetX\n\n return Array.from({ length: outputRows }, (_, outputRowIndex) => {\n const rowParts: CardPart[] = [{ color: ansi.slate, text: ' ' }]\n\n for (let columnIndex = 0; columnIndex < outputWidth; columnIndex += 1) {\n const foregroundRow = outputRowIndex - Math.abs(Math.min(0, shadowOffsetY))\n const hasForeground = foregroundRow >= 0 && Boolean(matrix[foregroundRow]?.[columnIndex])\n const shadowSourceRow = outputRowIndex - shadowOffsetY - Math.abs(Math.min(0, shadowOffsetY))\n const shadowSourceColumn = columnIndex - shadowOffsetX\n const hasShadow = shadowSourceRow >= 0 && shadowSourceColumn >= 0\n && Boolean(matrix[shadowSourceRow]?.[shadowSourceColumn])\n\n if (hasForeground) {\n appendCardPart(rowParts, ansi.clay, '██')\n } else if (hasShadow) {\n appendCardPart(rowParts, ansi.shadow, '░░')\n } else {\n appendCardPart(rowParts, ansi.slate, ' ')\n }\n }\n\n return renderCardLineParts(rowParts)\n })\n}\n\nfunction appendCardPart(parts: CardPart[], color: string, text: string): void {\n const previous = parts[parts.length - 1]\n if (previous?.color === color) {\n previous.text += text\n return\n }\n parts.push({ color, text })\n}\n\nfunction renderAsciiWordmark(word: string): string[] {\n const matrix = buildPixelWordmarkMatrix(word)\n const rows: string[] = []\n for (const matrixRow of matrix) {\n rows.push(matrixRow.map(cell => (cell ? '#' : ' ')).join(''))\n }\n return rows\n}\n\nexport function renderInstallInstructions(options: InstallOptions): string {\n const color = options.color\n const json = JSON.stringify(buildMcpConfig(options), null, 2)\n const keySetup = options.keyPath\n ? [\n paint('Key file mode', ansi.terracotta, color),\n ` chmod 600 ${options.keyPath}`,\n ].join('\\n')\n : [\n paint('Safer key-file option', ansi.terracotta, color),\n ' mkdir -p ~/.config/thorbit',\n \" printf '%s\\\\n' 'thbt_mcp_...' > ~/.config/thorbit/content-mcp-key\",\n ' chmod 600 ~/.config/thorbit/content-mcp-key',\n '',\n ' Then run:',\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --key-path ~/.config/thorbit/content-mcp-key',\n ].join('\\n')\n\n return [\n renderBanner(color),\n paint('MCP Scraper research, on-page analysis, and content pipeline tools for MCP agents.', ansi.slate, color),\n '',\n `${paint('1.', ansi.terracotta, color)} Generate an API key in Thorbit Settings -> MCPs with content/onpage scopes.`,\n `${paint('2.', ansi.terracotta, color)} Add this server config to your MCP client:`,\n '',\n json,\n '',\n `${paint('3.', ansi.terracotta, color)} Restart your MCP client, then call ${paint('thorbit_content_harvest_serp', ansi.green, color)}, ${paint('thorbit_onpage_start_analysis', ansi.green, color)}, or ${paint('thorbit_content_pipeline_start', ansi.green, color)}.`,\n '',\n keySetup,\n '',\n paint('Tools', ansi.terracotta, color),\n ' thorbit_content_extract_url Extract a URL through MCP Scraper.',\n ' thorbit_content_harvest_serp Harvest full SERP/PAA evidence through MCP Scraper.',\n ' thorbit_content_reddit_research Read Reddit through MCP Scraper browser-agent.',\n ' thorbit_onpage_start_analysis Start durable Thorbit on-page analysis from any supported source.',\n ' thorbit_onpage_generate_brief Queue or return the final writer brief.',\n ' thorbit_onpage_propose_edits Propose targeted on-page content edits.',\n ' thorbit_content_pipeline_start Start brief/write/optimize content pipeline workflows.',\n ' thorbit_content_pipeline_get Read content pipeline jobs and run views.',\n '',\n paint('Raw JSON:', ansi.slate, color),\n ' npx -y -p thorbit-content-mcp@latest thorbit-content-mcp-install --json --api-key thbt_mcp_...',\n '',\n ].join('\\n')\n}\n\nexport function main(): void {\n const options = resolveInstallOptions()\n if (options.help) {\n process.stdout.write(renderHelp(options.color))\n return\n }\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(buildMcpConfig(options), null, 2)}\\n`)\n return\n }\n\n process.stdout.write(renderInstallInstructions(options))\n}\n\nfunction isMainModule(): boolean {\n const entry = process.argv[1]\n if (!entry) return false\n try {\n return realpathSync(entry) === realpathSync(fileURLToPath(import.meta.url))\n } catch {\n return false\n }\n}\n\nif (isMainModule()) main()\n"],"mappings":"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","names":[]}
|
|
@@ -88,6 +88,27 @@ var ThorbitContentExtractUrlInputSchema = {
|
|
|
88
88
|
};
|
|
89
89
|
var McpScraperProxyModeSchema = import_zod.z.enum(["location", "configured", "none"]);
|
|
90
90
|
var McpScraperSerpDeviceSchema = import_zod.z.enum(["desktop", "mobile"]);
|
|
91
|
+
var PipelineModeSchema = import_zod.z.enum(["brief", "write", "optimize"]);
|
|
92
|
+
var ContentPipelineSourceKindSchema = import_zod.z.enum([
|
|
93
|
+
"search-console-query",
|
|
94
|
+
"topic-map-node",
|
|
95
|
+
"data-hub-roadmap",
|
|
96
|
+
"ranked-keyword",
|
|
97
|
+
"competitor-keyword",
|
|
98
|
+
"eics-entity",
|
|
99
|
+
"phrase-question",
|
|
100
|
+
"manual-keyword"
|
|
101
|
+
]);
|
|
102
|
+
var ContentPipelineSourceRefSchema = import_zod.z.object({
|
|
103
|
+
sourceKind: ContentPipelineSourceKindSchema,
|
|
104
|
+
keyword: import_zod.z.string().min(1).max(200),
|
|
105
|
+
sourcePublicId: import_zod.z.string().min(1).max(128).optional(),
|
|
106
|
+
title: import_zod.z.string().min(1).max(300).optional(),
|
|
107
|
+
reason: import_zod.z.string().min(1).max(1e3).optional(),
|
|
108
|
+
sourceUrl: import_zod.z.string().url().optional(),
|
|
109
|
+
metrics: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
|
|
110
|
+
selectedAt: import_zod.z.string().datetime().optional()
|
|
111
|
+
}).strict();
|
|
91
112
|
var ThorbitContentHarvestSerpInputSchema = {
|
|
92
113
|
query: import_zod.z.string().min(1).max(400).describe('Core search topic. Separate location when possible, e.g. query="best CRM" and location="Denver, CO".'),
|
|
93
114
|
location: import_zod.z.string().min(1).max(160).optional().describe("Optional search location, such as Denver, CO. Required for precise residential proxy targeting."),
|
|
@@ -115,26 +136,114 @@ var ThorbitContentRedditResearchInputSchema = {
|
|
|
115
136
|
readWithBrowserAgent: import_zod.z.boolean().default(true).describe("Keep true. Reads Reddit candidates through MCP Scraper browser-agent."),
|
|
116
137
|
profile: import_zod.z.string().min(1).max(128).optional().describe("Optional MCP Scraper browser-agent saved profile name.")
|
|
117
138
|
};
|
|
139
|
+
var ThorbitOnPageSourceSelectionSchema = import_zod.z.discriminatedUnion("mode", [
|
|
140
|
+
import_zod.z.object({ mode: import_zod.z.literal("keyword_only") }).strict(),
|
|
141
|
+
import_zod.z.object({
|
|
142
|
+
mode: import_zod.z.literal("inline_content"),
|
|
143
|
+
title: import_zod.z.string().min(1).max(255).optional(),
|
|
144
|
+
text: import_zod.z.string().min(20).max(5e5),
|
|
145
|
+
sourceUrl: import_zod.z.string().url().optional()
|
|
146
|
+
}).strict(),
|
|
147
|
+
import_zod.z.object({ mode: import_zod.z.literal("content_piece"), contentPiecePublicId: import_zod.z.string().min(1) }).strict(),
|
|
148
|
+
import_zod.z.object({
|
|
149
|
+
mode: import_zod.z.literal("wordpress_plugin_page"),
|
|
150
|
+
connectionPublicId: import_zod.z.string().min(1),
|
|
151
|
+
externalPostId: import_zod.z.number().int().positive()
|
|
152
|
+
}).strict(),
|
|
153
|
+
import_zod.z.object({
|
|
154
|
+
mode: import_zod.z.literal("wordpress_api_page"),
|
|
155
|
+
connectionPublicId: import_zod.z.string().min(1),
|
|
156
|
+
connectionPagePublicId: import_zod.z.string().min(1)
|
|
157
|
+
}).strict(),
|
|
158
|
+
import_zod.z.object({
|
|
159
|
+
mode: import_zod.z.literal("project_website_scrape"),
|
|
160
|
+
websitePagePublicId: import_zod.z.string().min(1)
|
|
161
|
+
}).strict()
|
|
162
|
+
]);
|
|
163
|
+
var ThorbitContentOpportunitiesListInputSchema = {
|
|
164
|
+
projectPublicId: import_zod.z.string().min(1).describe("Thorbit project public ID."),
|
|
165
|
+
sourceKind: ContentPipelineSourceKindSchema.optional().describe("Optional content opportunity source kind filter."),
|
|
166
|
+
limit: import_zod.z.number().int().min(1).max(100).default(10).describe("Maximum opportunities per source.")
|
|
167
|
+
};
|
|
168
|
+
var ThorbitContentPipelineStartInputSchema = {
|
|
169
|
+
projectPublicId: import_zod.z.string().min(1).describe("Thorbit project public ID."),
|
|
170
|
+
keyword: import_zod.z.string().min(1).max(200).describe("Target keyword or query for the content pipeline."),
|
|
171
|
+
mode: PipelineModeSchema.describe("Content pipeline mode: brief, write, or optimize."),
|
|
172
|
+
reviewBrief: import_zod.z.boolean().default(false).describe("Pause after brief generation for review before writing."),
|
|
173
|
+
notes: import_zod.z.string().max(500).optional().describe("Optional writing or strategy instructions."),
|
|
174
|
+
existingContentPiecePublicId: import_zod.z.string().min(1).optional().describe("Required for optimize mode. Existing Thorbit content piece public ID."),
|
|
175
|
+
writingStyleId: import_zod.z.number().int().positive().optional().describe("Optional Thorbit writing style ID."),
|
|
176
|
+
maxIterations: import_zod.z.number().int().min(0).max(3).optional().describe("Optional verification/improvement iteration cap."),
|
|
177
|
+
analysisPublicId: import_zod.z.string().min(1).optional().describe("Optional related on-page analysis public ID."),
|
|
178
|
+
source: ContentPipelineSourceRefSchema.optional().describe("Optional persisted content opportunity source reference.")
|
|
179
|
+
};
|
|
180
|
+
var ThorbitContentPipelineGetInputSchema = {
|
|
181
|
+
jobPublicId: import_zod.z.string().min(1).describe("Content pipeline workflow job public ID."),
|
|
182
|
+
includePhaseData: import_zod.z.boolean().default(true).describe("Include raw workflow phaseData in addition to the normalized run view.")
|
|
183
|
+
};
|
|
184
|
+
var ThorbitContentPipelineResumeInputSchema = {
|
|
185
|
+
jobPublicId: import_zod.z.string().min(1).describe("Paused content pipeline workflow job public ID."),
|
|
186
|
+
userInstructions: import_zod.z.string().max(4e3).default("").describe("Optional instructions to append before resuming.")
|
|
187
|
+
};
|
|
188
|
+
var ThorbitContentPipelineStartFromBriefInputSchema = {
|
|
189
|
+
briefPublicId: import_zod.z.string().min(1).describe("Approved Thorbit brief public ID."),
|
|
190
|
+
analysisPublicId: import_zod.z.string().min(1).describe("On-page analysis public ID associated with the brief."),
|
|
191
|
+
writingStyleId: import_zod.z.number().int().positive().optional().describe("Optional Thorbit writing style ID.")
|
|
192
|
+
};
|
|
193
|
+
var ThorbitContentPipelineImproveInputSchema = {
|
|
194
|
+
jobOrPiecePublicId: import_zod.z.string().min(1).describe("Existing content pipeline job public ID or content piece public ID to improve.")
|
|
195
|
+
};
|
|
196
|
+
var ThorbitOnPageListSourcesInputSchema = {
|
|
197
|
+
projectPublicId: import_zod.z.string().min(1).describe("Thorbit project public ID."),
|
|
198
|
+
kind: import_zod.z.enum(["keyword", "wordpress_plugin", "wordpress_api", "project_website_scrape"]).optional().describe("Optional source kind filter."),
|
|
199
|
+
search: import_zod.z.string().max(200).optional().describe("Optional search string for page/title/url filtering."),
|
|
200
|
+
limit: import_zod.z.number().int().min(1).max(100).default(25).describe("Maximum source options to return."),
|
|
201
|
+
offset: import_zod.z.number().int().min(0).default(0).describe("Pagination offset."),
|
|
202
|
+
connectionPublicId: import_zod.z.string().min(1).optional().describe("Optional WordPress connection public ID filter.")
|
|
203
|
+
};
|
|
118
204
|
var ThorbitOnPageStartAnalysisInputSchema = {
|
|
119
205
|
projectPublicId: import_zod.z.string().min(1).describe("Thorbit project public ID."),
|
|
120
|
-
keyword: import_zod.z.string().min(1).max(200).describe("Target keyword or query for
|
|
206
|
+
keyword: import_zod.z.string().min(1).max(200).optional().describe("Target keyword or query. Required for keyword-only and inline-content analysis; can be inferred for selected stored sources."),
|
|
121
207
|
force: import_zod.z.boolean().default(false).describe("Force restart if an analysis is already running."),
|
|
122
|
-
source:
|
|
123
|
-
import_zod.z.object({ mode: import_zod.z.literal("keyword_only") }).strict(),
|
|
124
|
-
import_zod.z.object({
|
|
125
|
-
mode: import_zod.z.literal("inline_content"),
|
|
126
|
-
title: import_zod.z.string().min(1).max(255).optional(),
|
|
127
|
-
text: import_zod.z.string().min(20).max(5e5),
|
|
128
|
-
sourceUrl: import_zod.z.string().url().optional()
|
|
129
|
-
}).strict()
|
|
130
|
-
]).default({ mode: "keyword_only" }).describe("Use keyword_only for research-only analysis or inline_content to score provided content.")
|
|
208
|
+
source: ThorbitOnPageSourceSelectionSchema.default({ mode: "keyword_only" }).describe("Source to analyze: keyword_only, inline_content, content_piece, wordpress_plugin_page, wordpress_api_page, or project_website_scrape.")
|
|
131
209
|
};
|
|
132
210
|
var ThorbitOnPageGetAnalysisInputSchema = {
|
|
133
|
-
analysisPublicId: import_zod.z.string().min(1).describe("On-page analysis public ID returned by thorbit_onpage_start_analysis.")
|
|
211
|
+
analysisPublicId: import_zod.z.string().min(1).describe("On-page analysis public ID returned by thorbit_onpage_start_analysis."),
|
|
212
|
+
detail: import_zod.z.enum(["summary", "standard", "full"]).default("standard").describe("Analysis detail level. Use full for SERP, competitors, clusters, entities, demand, brief, strategy, and raw analysis data."),
|
|
213
|
+
includeBrief: import_zod.z.boolean().default(true).describe("Include persisted brief content and structured brief data when available."),
|
|
214
|
+
includeStrategy: import_zod.z.boolean().default(true).describe("Include persisted strategy content when available."),
|
|
215
|
+
includeRawAnalysisData: import_zod.z.boolean().default(false).describe("Include raw analysisData JSON. Automatically included for detail=full.")
|
|
216
|
+
};
|
|
217
|
+
var ThorbitOnPageGetEditorContentInputSchema = {
|
|
218
|
+
analysisPublicId: import_zod.z.string().min(1).describe("On-page analysis public ID.")
|
|
219
|
+
};
|
|
220
|
+
var ThorbitOnPageRescoreAnalysisInputSchema = {
|
|
221
|
+
analysisPublicId: import_zod.z.string().min(1).describe("Completed on-page analysis public ID."),
|
|
222
|
+
editorContentPiecePublicId: import_zod.z.string().min(1).optional().describe("Editable content piece public ID returned by thorbit_onpage_get_editor_content."),
|
|
223
|
+
contentPiecePublicId: import_zod.z.string().min(1).optional().describe("Alternate content piece public ID to score.")
|
|
224
|
+
};
|
|
225
|
+
var ThorbitOnPageGenerateBriefInputSchema = {
|
|
226
|
+
analysisPublicId: import_zod.z.string().min(1).describe("Completed on-page analysis public ID. Returns an existing brief immediately, or queues generation and returns a job ID plus a thorbit_onpage_get_analysis poll target."),
|
|
227
|
+
regenerate: import_zod.z.boolean().default(false).describe("Regenerate an existing brief instead of returning it. Regeneration queues work and should be polled with thorbit_onpage_get_analysis.")
|
|
228
|
+
};
|
|
229
|
+
var ThorbitOnPageGenerateStrategyInputSchema = {
|
|
230
|
+
analysisPublicId: import_zod.z.string().min(1).describe("Completed on-page analysis public ID."),
|
|
231
|
+
articleContent: import_zod.z.string().min(20).max(5e5).optional().describe("Optional article content to include in strategy generation.")
|
|
232
|
+
};
|
|
233
|
+
var ThorbitOnPageProposeEditsInputSchema = {
|
|
234
|
+
analysisPublicId: import_zod.z.string().min(1).describe("Completed full-mode on-page analysis public ID.")
|
|
235
|
+
};
|
|
236
|
+
var ThorbitOnPageUpdateEditStatusInputSchema = {
|
|
237
|
+
analysisPublicId: import_zod.z.string().min(1).describe("On-page analysis public ID with a proposed edit session."),
|
|
238
|
+
editId: import_zod.z.string().min(1).describe("Edit ID from thorbit_onpage_propose_edits."),
|
|
239
|
+
status: import_zod.z.enum(["accepted", "rejected"]).describe("Accept or reject this proposed edit.")
|
|
240
|
+
};
|
|
241
|
+
var ThorbitOnPageApplyEditsInputSchema = {
|
|
242
|
+
analysisPublicId: import_zod.z.string().min(1).describe("On-page analysis public ID with accepted edits.")
|
|
134
243
|
};
|
|
135
244
|
|
|
136
245
|
// src/content-onpage-mcp-server.ts
|
|
137
|
-
var VERSION = "0.1.
|
|
246
|
+
var VERSION = "0.1.3";
|
|
138
247
|
function readOnlyAnnotations(title, openWorldHint = true) {
|
|
139
248
|
return {
|
|
140
249
|
title,
|
|
@@ -193,18 +302,102 @@ function buildThorbitContentOnPageMcpServer(client) {
|
|
|
193
302
|
inputSchema: ThorbitContentRedditResearchInputSchema,
|
|
194
303
|
annotations: readOnlyAnnotations("Research Reddit With Browser Agent")
|
|
195
304
|
});
|
|
305
|
+
registerTool("thorbit_content_opportunities_list", {
|
|
306
|
+
title: "List Content Opportunities",
|
|
307
|
+
description: "List persisted Thorbit content opportunity candidates for a project. Use this before starting content pipeline work from GSC, topic-map, roadmap, ranked keyword, competitor, entity, or question sources.",
|
|
308
|
+
inputSchema: ThorbitContentOpportunitiesListInputSchema,
|
|
309
|
+
annotations: readOnlyAnnotations("List Content Opportunities", false)
|
|
310
|
+
});
|
|
311
|
+
registerTool("thorbit_content_pipeline_start", {
|
|
312
|
+
title: "Start Content Pipeline",
|
|
313
|
+
description: "Start the Thorbit content pipeline in brief, write, or optimize mode. Supports persisted opportunity sources, approved project context, writing style IDs, brief review pauses, existing content optimization, and metered durable workflow dispatch.",
|
|
314
|
+
inputSchema: ThorbitContentPipelineStartInputSchema,
|
|
315
|
+
annotations: writeAnnotations("Start Content Pipeline")
|
|
316
|
+
});
|
|
317
|
+
registerTool("thorbit_content_pipeline_get", {
|
|
318
|
+
title: "Read Content Pipeline",
|
|
319
|
+
description: "Read a Thorbit content pipeline workflow job and normalized content creation run view, including phase, next actions, brief/article markdown, writer sections, model call telemetry, publication summary, and optional raw phaseData.",
|
|
320
|
+
inputSchema: ThorbitContentPipelineGetInputSchema,
|
|
321
|
+
annotations: readOnlyAnnotations("Read Content Pipeline", false)
|
|
322
|
+
});
|
|
323
|
+
registerTool("thorbit_content_pipeline_resume", {
|
|
324
|
+
title: "Resume Content Pipeline",
|
|
325
|
+
description: "Resume a paused Thorbit content pipeline after strategy or brief review, optionally appending user instructions before the next phase dispatch.",
|
|
326
|
+
inputSchema: ThorbitContentPipelineResumeInputSchema,
|
|
327
|
+
annotations: writeAnnotations("Resume Content Pipeline")
|
|
328
|
+
});
|
|
329
|
+
registerTool("thorbit_content_pipeline_start_from_brief", {
|
|
330
|
+
title: "Start Writing From Brief",
|
|
331
|
+
description: "Start the Thorbit write pipeline directly from an approved brief and its on-page analysis. Use after thorbit_onpage_generate_brief or an existing approved Thorbit brief.",
|
|
332
|
+
inputSchema: ThorbitContentPipelineStartFromBriefInputSchema,
|
|
333
|
+
annotations: writeAnnotations("Start Writing From Brief")
|
|
334
|
+
});
|
|
335
|
+
registerTool("thorbit_content_pipeline_improve", {
|
|
336
|
+
title: "Improve Existing Content",
|
|
337
|
+
description: "Start a Thorbit improvement loop for an existing content pipeline job or content piece. Scores the article, identifies gaps, rewrites, and re-scores through the durable content pipeline.",
|
|
338
|
+
inputSchema: ThorbitContentPipelineImproveInputSchema,
|
|
339
|
+
annotations: writeAnnotations("Improve Existing Content")
|
|
340
|
+
});
|
|
341
|
+
registerTool("thorbit_onpage_list_sources", {
|
|
342
|
+
title: "List On-Page Source Options",
|
|
343
|
+
description: "List source options that can feed on-page analysis: keyword-only, WordPress Plugin pages, WordPress API synced pages, and project website scrape pages. Use before selecting a stored page source for analysis.",
|
|
344
|
+
inputSchema: ThorbitOnPageListSourcesInputSchema,
|
|
345
|
+
annotations: readOnlyAnnotations("List On-Page Source Options", false)
|
|
346
|
+
});
|
|
196
347
|
registerTool("thorbit_onpage_start_analysis", {
|
|
197
348
|
title: "Start Thorbit On-Page Analysis",
|
|
198
|
-
description: "Start a Thorbit on-page analysis for a project
|
|
349
|
+
description: "Start a Thorbit on-page analysis for a project. Supports keyword-only, inline content, existing Thorbit content pieces, WordPress Plugin pages, WordPress API synced pages, and project website scrape pages. Hosted Thorbit resolves source content, infers keywords when possible, dispatches the durable analysis workflow, and meters usage against the MCP API key.",
|
|
199
350
|
inputSchema: ThorbitOnPageStartAnalysisInputSchema,
|
|
200
351
|
annotations: writeAnnotations("Start Thorbit On-Page Analysis")
|
|
201
352
|
});
|
|
202
353
|
registerTool("thorbit_onpage_get_analysis", {
|
|
203
354
|
title: "Read Thorbit On-Page Analysis",
|
|
204
|
-
description: "Read persisted on-page analysis status, score, signal counts,
|
|
355
|
+
description: "Read persisted on-page analysis status, score, signal counts, brief, strategy, editor state, and optional full analysis surfaces: SERP, competitors, topic/demand clusters, Reddit/YouTube, entities, PMI, scoring, content reports, proposed edits, and raw analysisData.",
|
|
205
356
|
inputSchema: ThorbitOnPageGetAnalysisInputSchema,
|
|
206
357
|
annotations: readOnlyAnnotations("Read Thorbit On-Page Analysis", false)
|
|
207
358
|
});
|
|
359
|
+
registerTool("thorbit_onpage_get_editor_content", {
|
|
360
|
+
title: "Read On-Page Editor Content",
|
|
361
|
+
description: "Read or materialize editable content for a completed on-page analysis. Creates an editable Thorbit draft from the selected stored source when needed, then returns content piece ID, text, word count, source URL, and stale-score state.",
|
|
362
|
+
inputSchema: ThorbitOnPageGetEditorContentInputSchema,
|
|
363
|
+
annotations: readOnlyAnnotations("Read On-Page Editor Content", false)
|
|
364
|
+
});
|
|
365
|
+
registerTool("thorbit_onpage_rescore_analysis", {
|
|
366
|
+
title: "Re-Score On-Page Content",
|
|
367
|
+
description: "Re-score a completed on-page analysis against the current editable content piece without re-running expensive SERP and competitor collection. Returns a page-analysis-rescore job ID for progress polling.",
|
|
368
|
+
inputSchema: ThorbitOnPageRescoreAnalysisInputSchema,
|
|
369
|
+
annotations: writeAnnotations("Re-Score On-Page Content")
|
|
370
|
+
});
|
|
371
|
+
registerTool("thorbit_onpage_generate_brief", {
|
|
372
|
+
title: "Generate On-Page Brief",
|
|
373
|
+
description: "Return an existing Thorbit final writer brief immediately, or queue brief generation for a completed on-page analysis and return a job ID plus a thorbit_onpage_get_analysis poll target. Persists brief content and structured brief data for later writing.",
|
|
374
|
+
inputSchema: ThorbitOnPageGenerateBriefInputSchema,
|
|
375
|
+
annotations: writeAnnotations("Generate On-Page Brief")
|
|
376
|
+
});
|
|
377
|
+
registerTool("thorbit_onpage_generate_strategy", {
|
|
378
|
+
title: "Generate On-Page Strategy",
|
|
379
|
+
description: "Generate and persist the Thorbit on-page strategy document for a completed analysis, optionally using article content as context.",
|
|
380
|
+
inputSchema: ThorbitOnPageGenerateStrategyInputSchema,
|
|
381
|
+
annotations: writeAnnotations("Generate On-Page Strategy")
|
|
382
|
+
});
|
|
383
|
+
registerTool("thorbit_onpage_propose_edits", {
|
|
384
|
+
title: "Propose On-Page Edits",
|
|
385
|
+
description: "Ask Thorbit to propose 3-8 targeted content edits from the completed analysis gaps and editable content. Persists an edit session with pending/invalid edits.",
|
|
386
|
+
inputSchema: ThorbitOnPageProposeEditsInputSchema,
|
|
387
|
+
annotations: writeAnnotations("Propose On-Page Edits")
|
|
388
|
+
});
|
|
389
|
+
registerTool("thorbit_onpage_update_edit_status", {
|
|
390
|
+
title: "Accept Or Reject On-Page Edit",
|
|
391
|
+
description: "Accept or reject one proposed edit in an on-page edit session before applying edits to the Thorbit content piece.",
|
|
392
|
+
inputSchema: ThorbitOnPageUpdateEditStatusInputSchema,
|
|
393
|
+
annotations: writeAnnotations("Accept Or Reject On-Page Edit")
|
|
394
|
+
});
|
|
395
|
+
registerTool("thorbit_onpage_apply_edits", {
|
|
396
|
+
title: "Apply On-Page Edits",
|
|
397
|
+
description: "Apply all accepted on-page edits to the editable Thorbit content piece and create before/after content version snapshots.",
|
|
398
|
+
inputSchema: ThorbitOnPageApplyEditsInputSchema,
|
|
399
|
+
annotations: writeAnnotations("Apply On-Page Edits")
|
|
400
|
+
});
|
|
208
401
|
return server;
|
|
209
402
|
}
|
|
210
403
|
|