thorbit-content-mcp 0.1.2 → 0.1.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../bin/thorbit-content-mcp.ts","../../src/content-onpage-api-client.ts","../../src/content-onpage-mcp-env.ts","../../src/content-onpage-mcp-server.ts","../../src/content-onpage-mcp-response-formatters.ts","../../src/content-onpage-mcp-tool-schemas.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { ThorbitContentOnPageApiClient } from '../src/content-onpage-api-client.js'\nimport { resolveThorbitContentOnPageMcpEnv } from '../src/content-onpage-mcp-env.js'\nimport { buildThorbitContentOnPageMcpServer } from '../src/content-onpage-mcp-server.js'\n\nasync function main() {\n const env = resolveThorbitContentOnPageMcpEnv()\n const client = new ThorbitContentOnPageApiClient(env)\n const server = buildThorbitContentOnPageMcpServer(client)\n await server.connect(new StdioServerTransport())\n}\n\nmain().catch(error => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n})\n","import type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nexport type ThorbitContentOnPageMcpEnvelope =\n | {\n ok: true\n result: unknown\n warnings?: string[]\n requestId: string\n usage?: Record<string, unknown>\n }\n | {\n ok: false\n error: {\n code: string\n message: string\n details?: unknown\n }\n requestId: string\n }\n\nexport class ThorbitContentOnPageApiClient {\n private readonly baseUrl: string\n private readonly apiKey: string\n\n constructor(options: { baseUrl: string; apiKey: string }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.apiKey = options.apiKey\n }\n\n async callTool(toolName: ThorbitContentOnPageMcpToolName, input: unknown): Promise<ThorbitContentOnPageMcpEnvelope> {\n const response = await fetch(`${this.baseUrl}/api/v1/mcp/content-onpage/${toolName}`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input ?? {}),\n })\n\n const body = await response.json().catch(() => null) as ThorbitContentOnPageMcpEnvelope | null\n if (body && typeof body === 'object' && 'ok' in body) return body\n\n return {\n ok: false,\n requestId: 'unavailable',\n error: {\n code: response.ok ? 'invalid_response' : `http_${response.status}`,\n message: response.ok ? 'Thorbit returned an invalid MCP response' : `Thorbit API request failed with HTTP ${response.status}`,\n },\n }\n }\n}\n","import { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type ThorbitContentOnPageMcpEnv = {\n apiKey: string\n baseUrl: string\n}\n\nfunction readApiKeyFile(): string | undefined {\n const explicitPath = process.env.THORBIT_CONTENT_MCP_KEY_PATH?.trim()\n const paths = [explicitPath, join(homedir(), '.thorbit-content-mcp-key')].filter(Boolean) as string[]\n for (const path of paths) {\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n continue\n }\n }\n return undefined\n}\n\nexport function resolveThorbitContentOnPageMcpEnv(): ThorbitContentOnPageMcpEnv {\n const apiKey = (\n process.env.THORBIT_API_KEY ||\n process.env.THORBIT_MCP_API_KEY ||\n process.env.THORBIT_CONTENT_MCP_API_KEY ||\n readApiKeyFile()\n )?.trim()\n\n if (!apiKey) {\n throw new Error('THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-content-mcp-key is required')\n }\n\n return {\n apiKey,\n baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_CONTENT_MCP_BASE_URL || 'https://thorbit.ai').trim(),\n }\n}\n","import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodRawShape } from 'zod'\nimport type { ThorbitContentOnPageApiClient } from './content-onpage-api-client.js'\nimport { formatThorbitContentOnPageMcpToolResult } from './content-onpage-mcp-response-formatters.js'\nimport {\n ThorbitContentExtractUrlInputSchema,\n ThorbitContentHarvestSerpInputSchema,\n ThorbitContentRedditResearchInputSchema,\n ThorbitOnPageGetAnalysisInputSchema,\n ThorbitOnPageStartAnalysisInputSchema,\n} from './content-onpage-mcp-tool-schemas.js'\nimport type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nconst VERSION = '0.1.2'\n\ntype ThorbitContentOnPageToolConfig<InputArgs extends ZodRawShape> = {\n title: string\n description: string\n inputSchema: InputArgs\n annotations: ToolAnnotations\n}\n\nfunction readOnlyAnnotations(title: string, openWorldHint = true) {\n return {\n title,\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint,\n }\n}\n\nfunction writeAnnotations(title: string, openWorldHint = false) {\n return {\n title,\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint,\n }\n}\n\nexport function buildThorbitContentOnPageMcpServer(client: ThorbitContentOnPageApiClient): McpServer {\n const server = new McpServer({ name: 'thorbit-content-mcp', version: VERSION })\n\n server.registerResource(\n 'analysis',\n new ResourceTemplate('thorbit-content://analyses/{analysisPublicId}', { list: undefined }),\n {\n title: 'Thorbit On-Page Analysis',\n description: 'Status, score, signal counts, and summary for one Thorbit on-page analysis.',\n mimeType: 'application/json',\n },\n async (uri, variables) => {\n const analysisPublicId = Array.isArray(variables.analysisPublicId)\n ? variables.analysisPublicId[0]\n : variables.analysisPublicId\n const envelope = await client.callTool('thorbit_onpage_get_analysis', { analysisPublicId: String(analysisPublicId) })\n return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(envelope, null, 2) }] }\n },\n )\n\n function registerTool<T extends ThorbitContentOnPageMcpToolName>(\n toolName: T,\n config: ThorbitContentOnPageToolConfig<ZodRawShape>,\n ): void {\n server.registerTool(toolName, config, async (input) => {\n const envelope = await client.callTool(toolName, input)\n return formatThorbitContentOnPageMcpToolResult(toolName, envelope)\n })\n }\n\n registerTool('thorbit_content_extract_url', {\n title: 'Extract URL For Content Analysis',\n description: 'Extract a public URL through MCP Scraper only. Use this before content audits, source ingestion, outline planning, or on-page comparisons. Browser fallback is enabled by default for JS-heavy pages.',\n inputSchema: ThorbitContentExtractUrlInputSchema,\n annotations: readOnlyAnnotations('Extract URL For Content Analysis'),\n })\n\n registerTool('thorbit_content_harvest_serp', {\n title: 'Harvest SERP And PAA Evidence',\n description: 'Harvest Google SERP/PAA evidence through MCP Scraper only. Returns the full evidence surface from MCP Scraper: PAA flat questions, PAA tree, organic SERP, local pack, videos/shorts, forums, whatPeopleSaying, AI Overview text/citations/sections, AI Mode, entity IDs, stats, diagnostics, and retry attempts. Split topic from location when possible. Keep proxyMode as location for US city/state SERPs so MCP Scraper rotates fresh residential proxy IDs and browser sessions across retryable CAPTCHA, proxy tunnel, proxy availability, and location-mismatch failures. Pass proxyZip for known city-center ZIP targeting and debug true when retry/proxy diagnostics are needed.',\n inputSchema: ThorbitContentHarvestSerpInputSchema,\n annotations: readOnlyAnnotations('Harvest SERP And PAA Evidence'),\n })\n\n registerTool('thorbit_content_reddit_research', {\n title: 'Research Reddit With MCP Scraper Browser Agent',\n description: 'Find Reddit candidates through MCP Scraper SERP harvest, then read selected posts through MCP Scraper browser-agent by default. Use for authentic audience language, objections, pain points, and questions. Keep proxyMode as location and pass location/proxyZip when the Reddit research has a local market. Do not use generic web scraping fallbacks for Reddit.',\n inputSchema: ThorbitContentRedditResearchInputSchema,\n annotations: readOnlyAnnotations('Research Reddit With Browser Agent'),\n })\n\n registerTool('thorbit_onpage_start_analysis', {\n title: 'Start Thorbit On-Page Analysis',\n description: 'Start a Thorbit on-page analysis for a project keyword. Can run keyword-only analysis or score provided inline content. Hosted Thorbit dispatches the durable analysis workflow and meters usage against the MCP API key.',\n inputSchema: ThorbitOnPageStartAnalysisInputSchema,\n annotations: writeAnnotations('Start Thorbit On-Page Analysis'),\n })\n\n registerTool('thorbit_onpage_get_analysis', {\n title: 'Read Thorbit On-Page Analysis',\n description: 'Read persisted on-page analysis status, score, signal counts, and content report summary by analysis public ID. Use after thorbit_onpage_start_analysis to poll durable results.',\n inputSchema: ThorbitOnPageGetAnalysisInputSchema,\n annotations: readOnlyAnnotations('Read Thorbit On-Page Analysis', false),\n })\n\n return server\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ThorbitContentOnPageMcpEnvelope } from './content-onpage-api-client.js'\nimport type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nexport function formatThorbitContentOnPageMcpToolResult(\n toolName: ThorbitContentOnPageMcpToolName,\n envelope: ThorbitContentOnPageMcpEnvelope,\n): CallToolResult {\n const text = JSON.stringify({\n toolName,\n ...envelope,\n }, null, 2)\n return {\n content: [{ type: 'text', text }],\n isError: !envelope.ok,\n }\n}\n","import { z } from 'zod'\n\nexport const ThorbitContentExtractUrlInputSchema = {\n url: z.string().url().describe('Public URL to extract through MCP Scraper.'),\n browserFallback: z.boolean().default(true).describe('Use MCP Scraper browser fallback for JS-heavy pages. Default true.'),\n extractBranding: z.boolean().default(false).describe('Ask MCP Scraper to extract brand colors, fonts, logo, and favicon when supported.'),\n downloadMedia: z.boolean().default(false).describe('Ask MCP Scraper to download page media when supported.'),\n maxCharacters: z.number().int().min(500).max(500000).default(80000).describe('Maximum extracted content characters returned to the MCP caller.'),\n}\n\nconst McpScraperProxyModeSchema = z.enum(['location', 'configured', 'none'])\nconst McpScraperSerpDeviceSchema = z.enum(['desktop', 'mobile'])\n\nexport const ThorbitContentHarvestSerpInputSchema = {\n query: z.string().min(1).max(400).describe('Core search topic. Separate location when possible, e.g. query=\"best CRM\" and location=\"Denver, CO\".'),\n location: z.string().min(1).max(160).optional().describe('Optional search location, such as Denver, CO. Required for precise residential proxy targeting.'),\n gl: z.string().length(2).optional().describe('Optional Google country code, such as us.'),\n hl: z.string().min(2).max(12).optional().describe('Optional Google interface language, such as en.'),\n device: McpScraperSerpDeviceSchema.default('desktop').describe('SERP device context. Use desktop by default; use mobile only when requested.'),\n maxQuestions: z.number().int().min(1).max(200).default(30).describe('Maximum PAA questions when serpOnly is false.'),\n includeSerp: z.boolean().default(true).describe('Include organic SERP results. Default true.'),\n serpOnly: z.boolean().default(false).describe('Use fast SERP-only mode when PAA expansion is not needed.'),\n proxyMode: McpScraperProxyModeSchema.default('location').describe('MCP Scraper proxy mode. Use location by default for US city/state SERPs so MCP Scraper rotates fresh residential proxy IDs and browser sessions across retryable CAPTCHA/proxy/location failures.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting. Use when a specific ZIP or city-center ZIP is known.'),\n debug: z.boolean().default(false).describe('Include sanitized MCP Scraper browser/proxy/location diagnostics and attempt telemetry. Use true when debugging CAPTCHA, proxy selection, or localization.'),\n pages: z.number().int().min(1).max(2).default(1).describe('Number of Google result pages to fetch in SERP-only mode.'),\n}\n\nexport const ThorbitContentRedditResearchInputSchema = {\n query: z.string().min(1).max(400).describe('Topic, product, service, or pain point to research on Reddit.'),\n location: z.string().min(1).max(160).optional().describe('Optional location to bias MCP Scraper SERP discovery and residential proxy targeting.'),\n gl: z.string().length(2).optional().describe('Optional Google country code, such as us.'),\n hl: z.string().min(2).max(12).optional().describe('Optional Google interface language, such as en.'),\n device: McpScraperSerpDeviceSchema.default('desktop').describe('SERP device context for Reddit discovery.'),\n proxyMode: McpScraperProxyModeSchema.default('location').describe('MCP Scraper proxy mode for Reddit discovery. Use location by default so MCP Scraper owns CAPTCHA/proxy retries.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting.'),\n debug: z.boolean().default(false).describe('Include sanitized MCP Scraper retry/proxy diagnostics for Reddit discovery.'),\n maxPosts: z.number().int().min(1).max(10).default(5).describe('Maximum Reddit posts to read with MCP Scraper browser-agent.'),\n readWithBrowserAgent: z.boolean().default(true).describe('Keep true. Reads Reddit candidates through MCP Scraper browser-agent.'),\n profile: z.string().min(1).max(128).optional().describe('Optional MCP Scraper browser-agent saved profile name.'),\n}\n\nexport const ThorbitOnPageStartAnalysisInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n keyword: z.string().min(1).max(200).describe('Target keyword or query for on-page analysis.'),\n force: z.boolean().default(false).describe('Force restart if an analysis is already running.'),\n source: z.discriminatedUnion('mode', [\n z.object({ mode: z.literal('keyword_only') }).strict(),\n z.object({\n mode: z.literal('inline_content'),\n title: z.string().min(1).max(255).optional(),\n text: z.string().min(20).max(500000),\n sourceUrl: z.string().url().optional(),\n }).strict(),\n ]).default({ mode: 'keyword_only' }).describe('Use keyword_only for research-only analysis or inline_content to score provided content.'),\n}\n\nexport const ThorbitOnPageGetAnalysisInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID returned by thorbit_onpage_start_analysis.'),\n}\n\nexport const ThorbitContentOnPageMcpToolInputSchemas = {\n thorbit_content_extract_url: ThorbitContentExtractUrlInputSchema,\n thorbit_content_harvest_serp: ThorbitContentHarvestSerpInputSchema,\n thorbit_content_reddit_research: ThorbitContentRedditResearchInputSchema,\n thorbit_onpage_start_analysis: ThorbitOnPageStartAnalysisInputSchema,\n thorbit_onpage_get_analysis: ThorbitOnPageGetAnalysisInputSchema,\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../bin/thorbit-content-mcp.ts","../../src/content-onpage-api-client.ts","../../src/content-onpage-mcp-env.ts","../../src/content-onpage-mcp-server.ts","../../src/content-onpage-mcp-response-formatters.ts","../../src/content-onpage-mcp-tool-schemas.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { ThorbitContentOnPageApiClient } from '../src/content-onpage-api-client.js'\nimport { resolveThorbitContentOnPageMcpEnv } from '../src/content-onpage-mcp-env.js'\nimport { buildThorbitContentOnPageMcpServer } from '../src/content-onpage-mcp-server.js'\n\nasync function main() {\n const env = resolveThorbitContentOnPageMcpEnv()\n const client = new ThorbitContentOnPageApiClient(env)\n const server = buildThorbitContentOnPageMcpServer(client)\n await server.connect(new StdioServerTransport())\n}\n\nmain().catch(error => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n})\n","import type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nexport type ThorbitContentOnPageMcpEnvelope =\n | {\n ok: true\n result: unknown\n warnings?: string[]\n requestId: string\n usage?: Record<string, unknown>\n }\n | {\n ok: false\n error: {\n code: string\n message: string\n details?: unknown\n }\n requestId: string\n }\n\nexport class ThorbitContentOnPageApiClient {\n private readonly baseUrl: string\n private readonly apiKey: string\n\n constructor(options: { baseUrl: string; apiKey: string }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.apiKey = options.apiKey\n }\n\n async callTool(toolName: ThorbitContentOnPageMcpToolName, input: unknown): Promise<ThorbitContentOnPageMcpEnvelope> {\n const response = await fetch(`${this.baseUrl}/api/v1/mcp/content-onpage/${toolName}`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input ?? {}),\n })\n\n const body = await response.json().catch(() => null) as ThorbitContentOnPageMcpEnvelope | null\n if (body && typeof body === 'object' && 'ok' in body) return body\n\n return {\n ok: false,\n requestId: 'unavailable',\n error: {\n code: response.ok ? 'invalid_response' : `http_${response.status}`,\n message: response.ok ? 'Thorbit returned an invalid MCP response' : `Thorbit API request failed with HTTP ${response.status}`,\n },\n }\n }\n}\n","import { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type ThorbitContentOnPageMcpEnv = {\n apiKey: string\n baseUrl: string\n}\n\nfunction readApiKeyFile(): string | undefined {\n const explicitPath = process.env.THORBIT_CONTENT_MCP_KEY_PATH?.trim()\n const paths = [explicitPath, join(homedir(), '.thorbit-content-mcp-key')].filter(Boolean) as string[]\n for (const path of paths) {\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n continue\n }\n }\n return undefined\n}\n\nexport function resolveThorbitContentOnPageMcpEnv(): ThorbitContentOnPageMcpEnv {\n const apiKey = (\n process.env.THORBIT_API_KEY ||\n process.env.THORBIT_MCP_API_KEY ||\n process.env.THORBIT_CONTENT_MCP_API_KEY ||\n readApiKeyFile()\n )?.trim()\n\n if (!apiKey) {\n throw new Error('THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-content-mcp-key is required')\n }\n\n return {\n apiKey,\n baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_CONTENT_MCP_BASE_URL || 'https://thorbit.ai').trim(),\n }\n}\n","import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodRawShape } from 'zod'\nimport type { ThorbitContentOnPageApiClient } from './content-onpage-api-client.js'\nimport { formatThorbitContentOnPageMcpToolResult } from './content-onpage-mcp-response-formatters.js'\nimport {\n ThorbitContentOpportunitiesListInputSchema,\n ThorbitContentExtractUrlInputSchema,\n ThorbitContentHarvestSerpInputSchema,\n ThorbitContentPipelineGetInputSchema,\n ThorbitContentPipelineImproveInputSchema,\n ThorbitContentPipelineResumeInputSchema,\n ThorbitContentPipelineStartFromBriefInputSchema,\n ThorbitContentPipelineStartInputSchema,\n ThorbitContentRedditResearchInputSchema,\n ThorbitOnPageApplyEditsInputSchema,\n ThorbitOnPageGenerateBriefInputSchema,\n ThorbitOnPageGenerateStrategyInputSchema,\n ThorbitOnPageGetEditorContentInputSchema,\n ThorbitOnPageGetAnalysisInputSchema,\n ThorbitOnPageListSourcesInputSchema,\n ThorbitOnPageProposeEditsInputSchema,\n ThorbitOnPageRescoreAnalysisInputSchema,\n ThorbitOnPageStartAnalysisInputSchema,\n ThorbitOnPageUpdateEditStatusInputSchema,\n} from './content-onpage-mcp-tool-schemas.js'\nimport type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nconst VERSION = '0.1.3'\n\ntype ThorbitContentOnPageToolConfig<InputArgs extends ZodRawShape> = {\n title: string\n description: string\n inputSchema: InputArgs\n annotations: ToolAnnotations\n}\n\nfunction readOnlyAnnotations(title: string, openWorldHint = true) {\n return {\n title,\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint,\n }\n}\n\nfunction writeAnnotations(title: string, openWorldHint = false) {\n return {\n title,\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint,\n }\n}\n\nexport function buildThorbitContentOnPageMcpServer(client: ThorbitContentOnPageApiClient): McpServer {\n const server = new McpServer({ name: 'thorbit-content-mcp', version: VERSION })\n\n server.registerResource(\n 'analysis',\n new ResourceTemplate('thorbit-content://analyses/{analysisPublicId}', { list: undefined }),\n {\n title: 'Thorbit On-Page Analysis',\n description: 'Status, score, signal counts, and summary for one Thorbit on-page analysis.',\n mimeType: 'application/json',\n },\n async (uri, variables) => {\n const analysisPublicId = Array.isArray(variables.analysisPublicId)\n ? variables.analysisPublicId[0]\n : variables.analysisPublicId\n const envelope = await client.callTool('thorbit_onpage_get_analysis', { analysisPublicId: String(analysisPublicId) })\n return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(envelope, null, 2) }] }\n },\n )\n\n function registerTool<T extends ThorbitContentOnPageMcpToolName>(\n toolName: T,\n config: ThorbitContentOnPageToolConfig<ZodRawShape>,\n ): void {\n server.registerTool(toolName, config, async (input) => {\n const envelope = await client.callTool(toolName, input)\n return formatThorbitContentOnPageMcpToolResult(toolName, envelope)\n })\n }\n\n registerTool('thorbit_content_extract_url', {\n title: 'Extract URL For Content Analysis',\n description: 'Extract a public URL through MCP Scraper only. Use this before content audits, source ingestion, outline planning, or on-page comparisons. Browser fallback is enabled by default for JS-heavy pages.',\n inputSchema: ThorbitContentExtractUrlInputSchema,\n annotations: readOnlyAnnotations('Extract URL For Content Analysis'),\n })\n\n registerTool('thorbit_content_harvest_serp', {\n title: 'Harvest SERP And PAA Evidence',\n description: 'Harvest Google SERP/PAA evidence through MCP Scraper only. Returns the full evidence surface from MCP Scraper: PAA flat questions, PAA tree, organic SERP, local pack, videos/shorts, forums, whatPeopleSaying, AI Overview text/citations/sections, AI Mode, entity IDs, stats, diagnostics, and retry attempts. Split topic from location when possible. Keep proxyMode as location for US city/state SERPs so MCP Scraper rotates fresh residential proxy IDs and browser sessions across retryable CAPTCHA, proxy tunnel, proxy availability, and location-mismatch failures. Pass proxyZip for known city-center ZIP targeting and debug true when retry/proxy diagnostics are needed.',\n inputSchema: ThorbitContentHarvestSerpInputSchema,\n annotations: readOnlyAnnotations('Harvest SERP And PAA Evidence'),\n })\n\n registerTool('thorbit_content_reddit_research', {\n title: 'Research Reddit With MCP Scraper Browser Agent',\n description: 'Find Reddit candidates through MCP Scraper SERP harvest, then read selected posts through MCP Scraper browser-agent by default. Use for authentic audience language, objections, pain points, and questions. Keep proxyMode as location and pass location/proxyZip when the Reddit research has a local market. Do not use generic web scraping fallbacks for Reddit.',\n inputSchema: ThorbitContentRedditResearchInputSchema,\n annotations: readOnlyAnnotations('Research Reddit With Browser Agent'),\n })\n\n registerTool('thorbit_content_opportunities_list', {\n title: 'List Content Opportunities',\n 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.',\n inputSchema: ThorbitContentOpportunitiesListInputSchema,\n annotations: readOnlyAnnotations('List Content Opportunities', false),\n })\n\n registerTool('thorbit_content_pipeline_start', {\n title: 'Start Content Pipeline',\n 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.',\n inputSchema: ThorbitContentPipelineStartInputSchema,\n annotations: writeAnnotations('Start Content Pipeline'),\n })\n\n registerTool('thorbit_content_pipeline_get', {\n title: 'Read Content Pipeline',\n 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.',\n inputSchema: ThorbitContentPipelineGetInputSchema,\n annotations: readOnlyAnnotations('Read Content Pipeline', false),\n })\n\n registerTool('thorbit_content_pipeline_resume', {\n title: 'Resume Content Pipeline',\n description: 'Resume a paused Thorbit content pipeline after strategy or brief review, optionally appending user instructions before the next phase dispatch.',\n inputSchema: ThorbitContentPipelineResumeInputSchema,\n annotations: writeAnnotations('Resume Content Pipeline'),\n })\n\n registerTool('thorbit_content_pipeline_start_from_brief', {\n title: 'Start Writing From Brief',\n 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.',\n inputSchema: ThorbitContentPipelineStartFromBriefInputSchema,\n annotations: writeAnnotations('Start Writing From Brief'),\n })\n\n registerTool('thorbit_content_pipeline_improve', {\n title: 'Improve Existing Content',\n 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.',\n inputSchema: ThorbitContentPipelineImproveInputSchema,\n annotations: writeAnnotations('Improve Existing Content'),\n })\n\n registerTool('thorbit_onpage_list_sources', {\n title: 'List On-Page Source Options',\n 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.',\n inputSchema: ThorbitOnPageListSourcesInputSchema,\n annotations: readOnlyAnnotations('List On-Page Source Options', false),\n })\n\n registerTool('thorbit_onpage_start_analysis', {\n title: 'Start Thorbit On-Page Analysis',\n 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.',\n inputSchema: ThorbitOnPageStartAnalysisInputSchema,\n annotations: writeAnnotations('Start Thorbit On-Page Analysis'),\n })\n\n registerTool('thorbit_onpage_get_analysis', {\n title: 'Read Thorbit On-Page Analysis',\n 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.',\n inputSchema: ThorbitOnPageGetAnalysisInputSchema,\n annotations: readOnlyAnnotations('Read Thorbit On-Page Analysis', false),\n })\n\n registerTool('thorbit_onpage_get_editor_content', {\n title: 'Read On-Page Editor Content',\n 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.',\n inputSchema: ThorbitOnPageGetEditorContentInputSchema,\n annotations: readOnlyAnnotations('Read On-Page Editor Content', false),\n })\n\n registerTool('thorbit_onpage_rescore_analysis', {\n title: 'Re-Score On-Page Content',\n 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.',\n inputSchema: ThorbitOnPageRescoreAnalysisInputSchema,\n annotations: writeAnnotations('Re-Score On-Page Content'),\n })\n\n registerTool('thorbit_onpage_generate_brief', {\n title: 'Generate On-Page Brief',\n description: 'Generate or return the Thorbit final writer brief for a completed on-page analysis. Persists brief content and structured brief data for later writing.',\n inputSchema: ThorbitOnPageGenerateBriefInputSchema,\n annotations: writeAnnotations('Generate On-Page Brief'),\n })\n\n registerTool('thorbit_onpage_generate_strategy', {\n title: 'Generate On-Page Strategy',\n description: 'Generate and persist the Thorbit on-page strategy document for a completed analysis, optionally using article content as context.',\n inputSchema: ThorbitOnPageGenerateStrategyInputSchema,\n annotations: writeAnnotations('Generate On-Page Strategy'),\n })\n\n registerTool('thorbit_onpage_propose_edits', {\n title: 'Propose On-Page Edits',\n 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.',\n inputSchema: ThorbitOnPageProposeEditsInputSchema,\n annotations: writeAnnotations('Propose On-Page Edits'),\n })\n\n registerTool('thorbit_onpage_update_edit_status', {\n title: 'Accept Or Reject On-Page Edit',\n description: 'Accept or reject one proposed edit in an on-page edit session before applying edits to the Thorbit content piece.',\n inputSchema: ThorbitOnPageUpdateEditStatusInputSchema,\n annotations: writeAnnotations('Accept Or Reject On-Page Edit'),\n })\n\n registerTool('thorbit_onpage_apply_edits', {\n title: 'Apply On-Page Edits',\n description: 'Apply all accepted on-page edits to the editable Thorbit content piece and create before/after content version snapshots.',\n inputSchema: ThorbitOnPageApplyEditsInputSchema,\n annotations: writeAnnotations('Apply On-Page Edits'),\n })\n\n return server\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ThorbitContentOnPageMcpEnvelope } from './content-onpage-api-client.js'\nimport type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nexport function formatThorbitContentOnPageMcpToolResult(\n toolName: ThorbitContentOnPageMcpToolName,\n envelope: ThorbitContentOnPageMcpEnvelope,\n): CallToolResult {\n const text = JSON.stringify({\n toolName,\n ...envelope,\n }, null, 2)\n return {\n content: [{ type: 'text', text }],\n isError: !envelope.ok,\n }\n}\n","import { z } from 'zod'\n\nexport const ThorbitContentExtractUrlInputSchema = {\n url: z.string().url().describe('Public URL to extract through MCP Scraper.'),\n browserFallback: z.boolean().default(true).describe('Use MCP Scraper browser fallback for JS-heavy pages. Default true.'),\n extractBranding: z.boolean().default(false).describe('Ask MCP Scraper to extract brand colors, fonts, logo, and favicon when supported.'),\n downloadMedia: z.boolean().default(false).describe('Ask MCP Scraper to download page media when supported.'),\n maxCharacters: z.number().int().min(500).max(500000).default(80000).describe('Maximum extracted content characters returned to the MCP caller.'),\n}\n\nconst McpScraperProxyModeSchema = z.enum(['location', 'configured', 'none'])\nconst McpScraperSerpDeviceSchema = z.enum(['desktop', 'mobile'])\nconst PipelineModeSchema = z.enum(['brief', 'write', 'optimize'])\nconst ContentPipelineSourceKindSchema = z.enum([\n 'search-console-query',\n 'topic-map-node',\n 'data-hub-roadmap',\n 'ranked-keyword',\n 'competitor-keyword',\n 'eics-entity',\n 'phrase-question',\n 'manual-keyword',\n])\n\nconst ContentPipelineSourceRefSchema = z.object({\n sourceKind: ContentPipelineSourceKindSchema,\n keyword: z.string().min(1).max(200),\n sourcePublicId: z.string().min(1).max(128).optional(),\n title: z.string().min(1).max(300).optional(),\n reason: z.string().min(1).max(1000).optional(),\n sourceUrl: z.string().url().optional(),\n metrics: z.record(z.string(), z.unknown()).optional(),\n selectedAt: z.string().datetime().optional(),\n}).strict()\n\nexport const ThorbitContentHarvestSerpInputSchema = {\n query: z.string().min(1).max(400).describe('Core search topic. Separate location when possible, e.g. query=\"best CRM\" and location=\"Denver, CO\".'),\n location: z.string().min(1).max(160).optional().describe('Optional search location, such as Denver, CO. Required for precise residential proxy targeting.'),\n gl: z.string().length(2).optional().describe('Optional Google country code, such as us.'),\n hl: z.string().min(2).max(12).optional().describe('Optional Google interface language, such as en.'),\n device: McpScraperSerpDeviceSchema.default('desktop').describe('SERP device context. Use desktop by default; use mobile only when requested.'),\n maxQuestions: z.number().int().min(1).max(200).default(30).describe('Maximum PAA questions when serpOnly is false.'),\n includeSerp: z.boolean().default(true).describe('Include organic SERP results. Default true.'),\n serpOnly: z.boolean().default(false).describe('Use fast SERP-only mode when PAA expansion is not needed.'),\n proxyMode: McpScraperProxyModeSchema.default('location').describe('MCP Scraper proxy mode. Use location by default for US city/state SERPs so MCP Scraper rotates fresh residential proxy IDs and browser sessions across retryable CAPTCHA/proxy/location failures.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting. Use when a specific ZIP or city-center ZIP is known.'),\n debug: z.boolean().default(false).describe('Include sanitized MCP Scraper browser/proxy/location diagnostics and attempt telemetry. Use true when debugging CAPTCHA, proxy selection, or localization.'),\n pages: z.number().int().min(1).max(2).default(1).describe('Number of Google result pages to fetch in SERP-only mode.'),\n}\n\nexport const ThorbitContentRedditResearchInputSchema = {\n query: z.string().min(1).max(400).describe('Topic, product, service, or pain point to research on Reddit.'),\n location: z.string().min(1).max(160).optional().describe('Optional location to bias MCP Scraper SERP discovery and residential proxy targeting.'),\n gl: z.string().length(2).optional().describe('Optional Google country code, such as us.'),\n hl: z.string().min(2).max(12).optional().describe('Optional Google interface language, such as en.'),\n device: McpScraperSerpDeviceSchema.default('desktop').describe('SERP device context for Reddit discovery.'),\n proxyMode: McpScraperProxyModeSchema.default('location').describe('MCP Scraper proxy mode for Reddit discovery. Use location by default so MCP Scraper owns CAPTCHA/proxy retries.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting.'),\n debug: z.boolean().default(false).describe('Include sanitized MCP Scraper retry/proxy diagnostics for Reddit discovery.'),\n maxPosts: z.number().int().min(1).max(10).default(5).describe('Maximum Reddit posts to read with MCP Scraper browser-agent.'),\n readWithBrowserAgent: z.boolean().default(true).describe('Keep true. Reads Reddit candidates through MCP Scraper browser-agent.'),\n profile: z.string().min(1).max(128).optional().describe('Optional MCP Scraper browser-agent saved profile name.'),\n}\n\nconst ThorbitOnPageSourceSelectionSchema = z.discriminatedUnion('mode', [\n z.object({ mode: z.literal('keyword_only') }).strict(),\n z.object({\n mode: z.literal('inline_content'),\n title: z.string().min(1).max(255).optional(),\n text: z.string().min(20).max(500000),\n sourceUrl: z.string().url().optional(),\n }).strict(),\n z.object({ mode: z.literal('content_piece'), contentPiecePublicId: z.string().min(1) }).strict(),\n z.object({\n mode: z.literal('wordpress_plugin_page'),\n connectionPublicId: z.string().min(1),\n externalPostId: z.number().int().positive(),\n }).strict(),\n z.object({\n mode: z.literal('wordpress_api_page'),\n connectionPublicId: z.string().min(1),\n connectionPagePublicId: z.string().min(1),\n }).strict(),\n z.object({\n mode: z.literal('project_website_scrape'),\n websitePagePublicId: z.string().min(1),\n }).strict(),\n])\n\nexport const ThorbitContentOpportunitiesListInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n sourceKind: ContentPipelineSourceKindSchema.optional().describe('Optional content opportunity source kind filter.'),\n limit: z.number().int().min(1).max(100).default(10).describe('Maximum opportunities per source.'),\n}\n\nexport const ThorbitContentPipelineStartInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n keyword: z.string().min(1).max(200).describe('Target keyword or query for the content pipeline.'),\n mode: PipelineModeSchema.describe('Content pipeline mode: brief, write, or optimize.'),\n reviewBrief: z.boolean().default(false).describe('Pause after brief generation for review before writing.'),\n notes: z.string().max(500).optional().describe('Optional writing or strategy instructions.'),\n existingContentPiecePublicId: z.string().min(1).optional().describe('Required for optimize mode. Existing Thorbit content piece public ID.'),\n writingStyleId: z.number().int().positive().optional().describe('Optional Thorbit writing style ID.'),\n maxIterations: z.number().int().min(0).max(3).optional().describe('Optional verification/improvement iteration cap.'),\n analysisPublicId: z.string().min(1).optional().describe('Optional related on-page analysis public ID.'),\n source: ContentPipelineSourceRefSchema.optional().describe('Optional persisted content opportunity source reference.'),\n}\n\nexport const ThorbitContentPipelineGetInputSchema = {\n jobPublicId: z.string().min(1).describe('Content pipeline workflow job public ID.'),\n includePhaseData: z.boolean().default(true).describe('Include raw workflow phaseData in addition to the normalized run view.'),\n}\n\nexport const ThorbitContentPipelineResumeInputSchema = {\n jobPublicId: z.string().min(1).describe('Paused content pipeline workflow job public ID.'),\n userInstructions: z.string().max(4000).default('').describe('Optional instructions to append before resuming.'),\n}\n\nexport const ThorbitContentPipelineStartFromBriefInputSchema = {\n briefPublicId: z.string().min(1).describe('Approved Thorbit brief public ID.'),\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID associated with the brief.'),\n writingStyleId: z.number().int().positive().optional().describe('Optional Thorbit writing style ID.'),\n}\n\nexport const ThorbitContentPipelineImproveInputSchema = {\n jobOrPiecePublicId: z.string().min(1).describe('Existing content pipeline job public ID or content piece public ID to improve.'),\n}\n\nexport const ThorbitOnPageListSourcesInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n kind: z.enum(['keyword', 'wordpress_plugin', 'wordpress_api', 'project_website_scrape']).optional().describe('Optional source kind filter.'),\n search: z.string().max(200).optional().describe('Optional search string for page/title/url filtering.'),\n limit: z.number().int().min(1).max(100).default(25).describe('Maximum source options to return.'),\n offset: z.number().int().min(0).default(0).describe('Pagination offset.'),\n connectionPublicId: z.string().min(1).optional().describe('Optional WordPress connection public ID filter.'),\n}\n\nexport const ThorbitOnPageStartAnalysisInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n keyword: 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.'),\n force: z.boolean().default(false).describe('Force restart if an analysis is already running.'),\n 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.'),\n}\n\nexport const ThorbitOnPageGetAnalysisInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID returned by thorbit_onpage_start_analysis.'),\n detail: 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.'),\n includeBrief: z.boolean().default(true).describe('Include persisted brief content and structured brief data when available.'),\n includeStrategy: z.boolean().default(true).describe('Include persisted strategy content when available.'),\n includeRawAnalysisData: z.boolean().default(false).describe('Include raw analysisData JSON. Automatically included for detail=full.'),\n}\n\nexport const ThorbitOnPageGetEditorContentInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID.'),\n}\n\nexport const ThorbitOnPageRescoreAnalysisInputSchema = {\n analysisPublicId: z.string().min(1).describe('Completed on-page analysis public ID.'),\n editorContentPiecePublicId: z.string().min(1).optional().describe('Editable content piece public ID returned by thorbit_onpage_get_editor_content.'),\n contentPiecePublicId: z.string().min(1).optional().describe('Alternate content piece public ID to score.'),\n}\n\nexport const ThorbitOnPageGenerateBriefInputSchema = {\n analysisPublicId: z.string().min(1).describe('Completed on-page analysis public ID.'),\n regenerate: z.boolean().default(false).describe('Regenerate an existing brief instead of returning it.'),\n}\n\nexport const ThorbitOnPageGenerateStrategyInputSchema = {\n analysisPublicId: z.string().min(1).describe('Completed on-page analysis public ID.'),\n articleContent: z.string().min(20).max(500000).optional().describe('Optional article content to include in strategy generation.'),\n}\n\nexport const ThorbitOnPageProposeEditsInputSchema = {\n analysisPublicId: z.string().min(1).describe('Completed full-mode on-page analysis public ID.'),\n}\n\nexport const ThorbitOnPageUpdateEditStatusInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID with a proposed edit session.'),\n editId: z.string().min(1).describe('Edit ID from thorbit_onpage_propose_edits.'),\n status: z.enum(['accepted', 'rejected']).describe('Accept or reject this proposed edit.'),\n}\n\nexport const ThorbitOnPageApplyEditsInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID with accepted edits.'),\n}\n\nexport const ThorbitContentOnPageMcpToolInputSchemas = {\n thorbit_content_extract_url: ThorbitContentExtractUrlInputSchema,\n thorbit_content_harvest_serp: ThorbitContentHarvestSerpInputSchema,\n thorbit_content_reddit_research: ThorbitContentRedditResearchInputSchema,\n thorbit_content_opportunities_list: ThorbitContentOpportunitiesListInputSchema,\n thorbit_content_pipeline_start: ThorbitContentPipelineStartInputSchema,\n thorbit_content_pipeline_get: ThorbitContentPipelineGetInputSchema,\n thorbit_content_pipeline_resume: ThorbitContentPipelineResumeInputSchema,\n thorbit_content_pipeline_start_from_brief: ThorbitContentPipelineStartFromBriefInputSchema,\n thorbit_content_pipeline_improve: ThorbitContentPipelineImproveInputSchema,\n thorbit_onpage_list_sources: ThorbitOnPageListSourcesInputSchema,\n thorbit_onpage_start_analysis: ThorbitOnPageStartAnalysisInputSchema,\n thorbit_onpage_get_analysis: ThorbitOnPageGetAnalysisInputSchema,\n thorbit_onpage_get_editor_content: ThorbitOnPageGetEditorContentInputSchema,\n thorbit_onpage_rescore_analysis: ThorbitOnPageRescoreAnalysisInputSchema,\n thorbit_onpage_generate_brief: ThorbitOnPageGenerateBriefInputSchema,\n thorbit_onpage_generate_strategy: ThorbitOnPageGenerateStrategyInputSchema,\n thorbit_onpage_propose_edits: ThorbitOnPageProposeEditsInputSchema,\n thorbit_onpage_update_edit_status: ThorbitOnPageUpdateEditStatusInputSchema,\n thorbit_onpage_apply_edits: ThorbitOnPageApplyEditsInputSchema,\n}\n"],"mappings":"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","names":[]}
@@ -87,6 +87,27 @@ var ThorbitContentExtractUrlInputSchema = {
87
87
  };
88
88
  var McpScraperProxyModeSchema = z.enum(["location", "configured", "none"]);
89
89
  var McpScraperSerpDeviceSchema = z.enum(["desktop", "mobile"]);
90
+ var PipelineModeSchema = z.enum(["brief", "write", "optimize"]);
91
+ var ContentPipelineSourceKindSchema = z.enum([
92
+ "search-console-query",
93
+ "topic-map-node",
94
+ "data-hub-roadmap",
95
+ "ranked-keyword",
96
+ "competitor-keyword",
97
+ "eics-entity",
98
+ "phrase-question",
99
+ "manual-keyword"
100
+ ]);
101
+ var ContentPipelineSourceRefSchema = z.object({
102
+ sourceKind: ContentPipelineSourceKindSchema,
103
+ keyword: z.string().min(1).max(200),
104
+ sourcePublicId: z.string().min(1).max(128).optional(),
105
+ title: z.string().min(1).max(300).optional(),
106
+ reason: z.string().min(1).max(1e3).optional(),
107
+ sourceUrl: z.string().url().optional(),
108
+ metrics: z.record(z.string(), z.unknown()).optional(),
109
+ selectedAt: z.string().datetime().optional()
110
+ }).strict();
90
111
  var ThorbitContentHarvestSerpInputSchema = {
91
112
  query: z.string().min(1).max(400).describe('Core search topic. Separate location when possible, e.g. query="best CRM" and location="Denver, CO".'),
92
113
  location: z.string().min(1).max(160).optional().describe("Optional search location, such as Denver, CO. Required for precise residential proxy targeting."),
@@ -114,26 +135,114 @@ var ThorbitContentRedditResearchInputSchema = {
114
135
  readWithBrowserAgent: z.boolean().default(true).describe("Keep true. Reads Reddit candidates through MCP Scraper browser-agent."),
115
136
  profile: z.string().min(1).max(128).optional().describe("Optional MCP Scraper browser-agent saved profile name.")
116
137
  };
138
+ var ThorbitOnPageSourceSelectionSchema = z.discriminatedUnion("mode", [
139
+ z.object({ mode: z.literal("keyword_only") }).strict(),
140
+ z.object({
141
+ mode: z.literal("inline_content"),
142
+ title: z.string().min(1).max(255).optional(),
143
+ text: z.string().min(20).max(5e5),
144
+ sourceUrl: z.string().url().optional()
145
+ }).strict(),
146
+ z.object({ mode: z.literal("content_piece"), contentPiecePublicId: z.string().min(1) }).strict(),
147
+ z.object({
148
+ mode: z.literal("wordpress_plugin_page"),
149
+ connectionPublicId: z.string().min(1),
150
+ externalPostId: z.number().int().positive()
151
+ }).strict(),
152
+ z.object({
153
+ mode: z.literal("wordpress_api_page"),
154
+ connectionPublicId: z.string().min(1),
155
+ connectionPagePublicId: z.string().min(1)
156
+ }).strict(),
157
+ z.object({
158
+ mode: z.literal("project_website_scrape"),
159
+ websitePagePublicId: z.string().min(1)
160
+ }).strict()
161
+ ]);
162
+ var ThorbitContentOpportunitiesListInputSchema = {
163
+ projectPublicId: z.string().min(1).describe("Thorbit project public ID."),
164
+ sourceKind: ContentPipelineSourceKindSchema.optional().describe("Optional content opportunity source kind filter."),
165
+ limit: z.number().int().min(1).max(100).default(10).describe("Maximum opportunities per source.")
166
+ };
167
+ var ThorbitContentPipelineStartInputSchema = {
168
+ projectPublicId: z.string().min(1).describe("Thorbit project public ID."),
169
+ keyword: z.string().min(1).max(200).describe("Target keyword or query for the content pipeline."),
170
+ mode: PipelineModeSchema.describe("Content pipeline mode: brief, write, or optimize."),
171
+ reviewBrief: z.boolean().default(false).describe("Pause after brief generation for review before writing."),
172
+ notes: z.string().max(500).optional().describe("Optional writing or strategy instructions."),
173
+ existingContentPiecePublicId: z.string().min(1).optional().describe("Required for optimize mode. Existing Thorbit content piece public ID."),
174
+ writingStyleId: z.number().int().positive().optional().describe("Optional Thorbit writing style ID."),
175
+ maxIterations: z.number().int().min(0).max(3).optional().describe("Optional verification/improvement iteration cap."),
176
+ analysisPublicId: z.string().min(1).optional().describe("Optional related on-page analysis public ID."),
177
+ source: ContentPipelineSourceRefSchema.optional().describe("Optional persisted content opportunity source reference.")
178
+ };
179
+ var ThorbitContentPipelineGetInputSchema = {
180
+ jobPublicId: z.string().min(1).describe("Content pipeline workflow job public ID."),
181
+ includePhaseData: z.boolean().default(true).describe("Include raw workflow phaseData in addition to the normalized run view.")
182
+ };
183
+ var ThorbitContentPipelineResumeInputSchema = {
184
+ jobPublicId: z.string().min(1).describe("Paused content pipeline workflow job public ID."),
185
+ userInstructions: z.string().max(4e3).default("").describe("Optional instructions to append before resuming.")
186
+ };
187
+ var ThorbitContentPipelineStartFromBriefInputSchema = {
188
+ briefPublicId: z.string().min(1).describe("Approved Thorbit brief public ID."),
189
+ analysisPublicId: z.string().min(1).describe("On-page analysis public ID associated with the brief."),
190
+ writingStyleId: z.number().int().positive().optional().describe("Optional Thorbit writing style ID.")
191
+ };
192
+ var ThorbitContentPipelineImproveInputSchema = {
193
+ jobOrPiecePublicId: z.string().min(1).describe("Existing content pipeline job public ID or content piece public ID to improve.")
194
+ };
195
+ var ThorbitOnPageListSourcesInputSchema = {
196
+ projectPublicId: z.string().min(1).describe("Thorbit project public ID."),
197
+ kind: z.enum(["keyword", "wordpress_plugin", "wordpress_api", "project_website_scrape"]).optional().describe("Optional source kind filter."),
198
+ search: z.string().max(200).optional().describe("Optional search string for page/title/url filtering."),
199
+ limit: z.number().int().min(1).max(100).default(25).describe("Maximum source options to return."),
200
+ offset: z.number().int().min(0).default(0).describe("Pagination offset."),
201
+ connectionPublicId: z.string().min(1).optional().describe("Optional WordPress connection public ID filter.")
202
+ };
117
203
  var ThorbitOnPageStartAnalysisInputSchema = {
118
204
  projectPublicId: z.string().min(1).describe("Thorbit project public ID."),
119
- keyword: z.string().min(1).max(200).describe("Target keyword or query for on-page analysis."),
205
+ keyword: 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."),
120
206
  force: z.boolean().default(false).describe("Force restart if an analysis is already running."),
121
- source: z.discriminatedUnion("mode", [
122
- z.object({ mode: z.literal("keyword_only") }).strict(),
123
- z.object({
124
- mode: z.literal("inline_content"),
125
- title: z.string().min(1).max(255).optional(),
126
- text: z.string().min(20).max(5e5),
127
- sourceUrl: z.string().url().optional()
128
- }).strict()
129
- ]).default({ mode: "keyword_only" }).describe("Use keyword_only for research-only analysis or inline_content to score provided content.")
207
+ 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.")
130
208
  };
131
209
  var ThorbitOnPageGetAnalysisInputSchema = {
132
- analysisPublicId: z.string().min(1).describe("On-page analysis public ID returned by thorbit_onpage_start_analysis.")
210
+ analysisPublicId: z.string().min(1).describe("On-page analysis public ID returned by thorbit_onpage_start_analysis."),
211
+ detail: 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."),
212
+ includeBrief: z.boolean().default(true).describe("Include persisted brief content and structured brief data when available."),
213
+ includeStrategy: z.boolean().default(true).describe("Include persisted strategy content when available."),
214
+ includeRawAnalysisData: z.boolean().default(false).describe("Include raw analysisData JSON. Automatically included for detail=full.")
215
+ };
216
+ var ThorbitOnPageGetEditorContentInputSchema = {
217
+ analysisPublicId: z.string().min(1).describe("On-page analysis public ID.")
218
+ };
219
+ var ThorbitOnPageRescoreAnalysisInputSchema = {
220
+ analysisPublicId: z.string().min(1).describe("Completed on-page analysis public ID."),
221
+ editorContentPiecePublicId: z.string().min(1).optional().describe("Editable content piece public ID returned by thorbit_onpage_get_editor_content."),
222
+ contentPiecePublicId: z.string().min(1).optional().describe("Alternate content piece public ID to score.")
223
+ };
224
+ var ThorbitOnPageGenerateBriefInputSchema = {
225
+ analysisPublicId: z.string().min(1).describe("Completed on-page analysis public ID."),
226
+ regenerate: z.boolean().default(false).describe("Regenerate an existing brief instead of returning it.")
227
+ };
228
+ var ThorbitOnPageGenerateStrategyInputSchema = {
229
+ analysisPublicId: z.string().min(1).describe("Completed on-page analysis public ID."),
230
+ articleContent: z.string().min(20).max(5e5).optional().describe("Optional article content to include in strategy generation.")
231
+ };
232
+ var ThorbitOnPageProposeEditsInputSchema = {
233
+ analysisPublicId: z.string().min(1).describe("Completed full-mode on-page analysis public ID.")
234
+ };
235
+ var ThorbitOnPageUpdateEditStatusInputSchema = {
236
+ analysisPublicId: z.string().min(1).describe("On-page analysis public ID with a proposed edit session."),
237
+ editId: z.string().min(1).describe("Edit ID from thorbit_onpage_propose_edits."),
238
+ status: z.enum(["accepted", "rejected"]).describe("Accept or reject this proposed edit.")
239
+ };
240
+ var ThorbitOnPageApplyEditsInputSchema = {
241
+ analysisPublicId: z.string().min(1).describe("On-page analysis public ID with accepted edits.")
133
242
  };
134
243
 
135
244
  // src/content-onpage-mcp-server.ts
136
- var VERSION = "0.1.2";
245
+ var VERSION = "0.1.3";
137
246
  function readOnlyAnnotations(title, openWorldHint = true) {
138
247
  return {
139
248
  title,
@@ -192,18 +301,102 @@ function buildThorbitContentOnPageMcpServer(client) {
192
301
  inputSchema: ThorbitContentRedditResearchInputSchema,
193
302
  annotations: readOnlyAnnotations("Research Reddit With Browser Agent")
194
303
  });
304
+ registerTool("thorbit_content_opportunities_list", {
305
+ title: "List Content Opportunities",
306
+ 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.",
307
+ inputSchema: ThorbitContentOpportunitiesListInputSchema,
308
+ annotations: readOnlyAnnotations("List Content Opportunities", false)
309
+ });
310
+ registerTool("thorbit_content_pipeline_start", {
311
+ title: "Start Content Pipeline",
312
+ 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.",
313
+ inputSchema: ThorbitContentPipelineStartInputSchema,
314
+ annotations: writeAnnotations("Start Content Pipeline")
315
+ });
316
+ registerTool("thorbit_content_pipeline_get", {
317
+ title: "Read Content Pipeline",
318
+ 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.",
319
+ inputSchema: ThorbitContentPipelineGetInputSchema,
320
+ annotations: readOnlyAnnotations("Read Content Pipeline", false)
321
+ });
322
+ registerTool("thorbit_content_pipeline_resume", {
323
+ title: "Resume Content Pipeline",
324
+ description: "Resume a paused Thorbit content pipeline after strategy or brief review, optionally appending user instructions before the next phase dispatch.",
325
+ inputSchema: ThorbitContentPipelineResumeInputSchema,
326
+ annotations: writeAnnotations("Resume Content Pipeline")
327
+ });
328
+ registerTool("thorbit_content_pipeline_start_from_brief", {
329
+ title: "Start Writing From Brief",
330
+ 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.",
331
+ inputSchema: ThorbitContentPipelineStartFromBriefInputSchema,
332
+ annotations: writeAnnotations("Start Writing From Brief")
333
+ });
334
+ registerTool("thorbit_content_pipeline_improve", {
335
+ title: "Improve Existing Content",
336
+ 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.",
337
+ inputSchema: ThorbitContentPipelineImproveInputSchema,
338
+ annotations: writeAnnotations("Improve Existing Content")
339
+ });
340
+ registerTool("thorbit_onpage_list_sources", {
341
+ title: "List On-Page Source Options",
342
+ 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.",
343
+ inputSchema: ThorbitOnPageListSourcesInputSchema,
344
+ annotations: readOnlyAnnotations("List On-Page Source Options", false)
345
+ });
195
346
  registerTool("thorbit_onpage_start_analysis", {
196
347
  title: "Start Thorbit On-Page Analysis",
197
- description: "Start a Thorbit on-page analysis for a project keyword. Can run keyword-only analysis or score provided inline content. Hosted Thorbit dispatches the durable analysis workflow and meters usage against the MCP API key.",
348
+ 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.",
198
349
  inputSchema: ThorbitOnPageStartAnalysisInputSchema,
199
350
  annotations: writeAnnotations("Start Thorbit On-Page Analysis")
200
351
  });
201
352
  registerTool("thorbit_onpage_get_analysis", {
202
353
  title: "Read Thorbit On-Page Analysis",
203
- description: "Read persisted on-page analysis status, score, signal counts, and content report summary by analysis public ID. Use after thorbit_onpage_start_analysis to poll durable results.",
354
+ 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.",
204
355
  inputSchema: ThorbitOnPageGetAnalysisInputSchema,
205
356
  annotations: readOnlyAnnotations("Read Thorbit On-Page Analysis", false)
206
357
  });
358
+ registerTool("thorbit_onpage_get_editor_content", {
359
+ title: "Read On-Page Editor Content",
360
+ 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.",
361
+ inputSchema: ThorbitOnPageGetEditorContentInputSchema,
362
+ annotations: readOnlyAnnotations("Read On-Page Editor Content", false)
363
+ });
364
+ registerTool("thorbit_onpage_rescore_analysis", {
365
+ title: "Re-Score On-Page Content",
366
+ 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.",
367
+ inputSchema: ThorbitOnPageRescoreAnalysisInputSchema,
368
+ annotations: writeAnnotations("Re-Score On-Page Content")
369
+ });
370
+ registerTool("thorbit_onpage_generate_brief", {
371
+ title: "Generate On-Page Brief",
372
+ description: "Generate or return the Thorbit final writer brief for a completed on-page analysis. Persists brief content and structured brief data for later writing.",
373
+ inputSchema: ThorbitOnPageGenerateBriefInputSchema,
374
+ annotations: writeAnnotations("Generate On-Page Brief")
375
+ });
376
+ registerTool("thorbit_onpage_generate_strategy", {
377
+ title: "Generate On-Page Strategy",
378
+ description: "Generate and persist the Thorbit on-page strategy document for a completed analysis, optionally using article content as context.",
379
+ inputSchema: ThorbitOnPageGenerateStrategyInputSchema,
380
+ annotations: writeAnnotations("Generate On-Page Strategy")
381
+ });
382
+ registerTool("thorbit_onpage_propose_edits", {
383
+ title: "Propose On-Page Edits",
384
+ 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.",
385
+ inputSchema: ThorbitOnPageProposeEditsInputSchema,
386
+ annotations: writeAnnotations("Propose On-Page Edits")
387
+ });
388
+ registerTool("thorbit_onpage_update_edit_status", {
389
+ title: "Accept Or Reject On-Page Edit",
390
+ description: "Accept or reject one proposed edit in an on-page edit session before applying edits to the Thorbit content piece.",
391
+ inputSchema: ThorbitOnPageUpdateEditStatusInputSchema,
392
+ annotations: writeAnnotations("Accept Or Reject On-Page Edit")
393
+ });
394
+ registerTool("thorbit_onpage_apply_edits", {
395
+ title: "Apply On-Page Edits",
396
+ description: "Apply all accepted on-page edits to the editable Thorbit content piece and create before/after content version snapshots.",
397
+ inputSchema: ThorbitOnPageApplyEditsInputSchema,
398
+ annotations: writeAnnotations("Apply On-Page Edits")
399
+ });
207
400
  return server;
208
401
  }
209
402
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../bin/thorbit-content-mcp.ts","../../src/content-onpage-api-client.ts","../../src/content-onpage-mcp-env.ts","../../src/content-onpage-mcp-server.ts","../../src/content-onpage-mcp-response-formatters.ts","../../src/content-onpage-mcp-tool-schemas.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { ThorbitContentOnPageApiClient } from '../src/content-onpage-api-client.js'\nimport { resolveThorbitContentOnPageMcpEnv } from '../src/content-onpage-mcp-env.js'\nimport { buildThorbitContentOnPageMcpServer } from '../src/content-onpage-mcp-server.js'\n\nasync function main() {\n const env = resolveThorbitContentOnPageMcpEnv()\n const client = new ThorbitContentOnPageApiClient(env)\n const server = buildThorbitContentOnPageMcpServer(client)\n await server.connect(new StdioServerTransport())\n}\n\nmain().catch(error => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n})\n","import type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nexport type ThorbitContentOnPageMcpEnvelope =\n | {\n ok: true\n result: unknown\n warnings?: string[]\n requestId: string\n usage?: Record<string, unknown>\n }\n | {\n ok: false\n error: {\n code: string\n message: string\n details?: unknown\n }\n requestId: string\n }\n\nexport class ThorbitContentOnPageApiClient {\n private readonly baseUrl: string\n private readonly apiKey: string\n\n constructor(options: { baseUrl: string; apiKey: string }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.apiKey = options.apiKey\n }\n\n async callTool(toolName: ThorbitContentOnPageMcpToolName, input: unknown): Promise<ThorbitContentOnPageMcpEnvelope> {\n const response = await fetch(`${this.baseUrl}/api/v1/mcp/content-onpage/${toolName}`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input ?? {}),\n })\n\n const body = await response.json().catch(() => null) as ThorbitContentOnPageMcpEnvelope | null\n if (body && typeof body === 'object' && 'ok' in body) return body\n\n return {\n ok: false,\n requestId: 'unavailable',\n error: {\n code: response.ok ? 'invalid_response' : `http_${response.status}`,\n message: response.ok ? 'Thorbit returned an invalid MCP response' : `Thorbit API request failed with HTTP ${response.status}`,\n },\n }\n }\n}\n","import { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type ThorbitContentOnPageMcpEnv = {\n apiKey: string\n baseUrl: string\n}\n\nfunction readApiKeyFile(): string | undefined {\n const explicitPath = process.env.THORBIT_CONTENT_MCP_KEY_PATH?.trim()\n const paths = [explicitPath, join(homedir(), '.thorbit-content-mcp-key')].filter(Boolean) as string[]\n for (const path of paths) {\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n continue\n }\n }\n return undefined\n}\n\nexport function resolveThorbitContentOnPageMcpEnv(): ThorbitContentOnPageMcpEnv {\n const apiKey = (\n process.env.THORBIT_API_KEY ||\n process.env.THORBIT_MCP_API_KEY ||\n process.env.THORBIT_CONTENT_MCP_API_KEY ||\n readApiKeyFile()\n )?.trim()\n\n if (!apiKey) {\n throw new Error('THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-content-mcp-key is required')\n }\n\n return {\n apiKey,\n baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_CONTENT_MCP_BASE_URL || 'https://thorbit.ai').trim(),\n }\n}\n","import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodRawShape } from 'zod'\nimport type { ThorbitContentOnPageApiClient } from './content-onpage-api-client.js'\nimport { formatThorbitContentOnPageMcpToolResult } from './content-onpage-mcp-response-formatters.js'\nimport {\n ThorbitContentExtractUrlInputSchema,\n ThorbitContentHarvestSerpInputSchema,\n ThorbitContentRedditResearchInputSchema,\n ThorbitOnPageGetAnalysisInputSchema,\n ThorbitOnPageStartAnalysisInputSchema,\n} from './content-onpage-mcp-tool-schemas.js'\nimport type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nconst VERSION = '0.1.2'\n\ntype ThorbitContentOnPageToolConfig<InputArgs extends ZodRawShape> = {\n title: string\n description: string\n inputSchema: InputArgs\n annotations: ToolAnnotations\n}\n\nfunction readOnlyAnnotations(title: string, openWorldHint = true) {\n return {\n title,\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint,\n }\n}\n\nfunction writeAnnotations(title: string, openWorldHint = false) {\n return {\n title,\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint,\n }\n}\n\nexport function buildThorbitContentOnPageMcpServer(client: ThorbitContentOnPageApiClient): McpServer {\n const server = new McpServer({ name: 'thorbit-content-mcp', version: VERSION })\n\n server.registerResource(\n 'analysis',\n new ResourceTemplate('thorbit-content://analyses/{analysisPublicId}', { list: undefined }),\n {\n title: 'Thorbit On-Page Analysis',\n description: 'Status, score, signal counts, and summary for one Thorbit on-page analysis.',\n mimeType: 'application/json',\n },\n async (uri, variables) => {\n const analysisPublicId = Array.isArray(variables.analysisPublicId)\n ? variables.analysisPublicId[0]\n : variables.analysisPublicId\n const envelope = await client.callTool('thorbit_onpage_get_analysis', { analysisPublicId: String(analysisPublicId) })\n return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(envelope, null, 2) }] }\n },\n )\n\n function registerTool<T extends ThorbitContentOnPageMcpToolName>(\n toolName: T,\n config: ThorbitContentOnPageToolConfig<ZodRawShape>,\n ): void {\n server.registerTool(toolName, config, async (input) => {\n const envelope = await client.callTool(toolName, input)\n return formatThorbitContentOnPageMcpToolResult(toolName, envelope)\n })\n }\n\n registerTool('thorbit_content_extract_url', {\n title: 'Extract URL For Content Analysis',\n description: 'Extract a public URL through MCP Scraper only. Use this before content audits, source ingestion, outline planning, or on-page comparisons. Browser fallback is enabled by default for JS-heavy pages.',\n inputSchema: ThorbitContentExtractUrlInputSchema,\n annotations: readOnlyAnnotations('Extract URL For Content Analysis'),\n })\n\n registerTool('thorbit_content_harvest_serp', {\n title: 'Harvest SERP And PAA Evidence',\n description: 'Harvest Google SERP/PAA evidence through MCP Scraper only. Returns the full evidence surface from MCP Scraper: PAA flat questions, PAA tree, organic SERP, local pack, videos/shorts, forums, whatPeopleSaying, AI Overview text/citations/sections, AI Mode, entity IDs, stats, diagnostics, and retry attempts. Split topic from location when possible. Keep proxyMode as location for US city/state SERPs so MCP Scraper rotates fresh residential proxy IDs and browser sessions across retryable CAPTCHA, proxy tunnel, proxy availability, and location-mismatch failures. Pass proxyZip for known city-center ZIP targeting and debug true when retry/proxy diagnostics are needed.',\n inputSchema: ThorbitContentHarvestSerpInputSchema,\n annotations: readOnlyAnnotations('Harvest SERP And PAA Evidence'),\n })\n\n registerTool('thorbit_content_reddit_research', {\n title: 'Research Reddit With MCP Scraper Browser Agent',\n description: 'Find Reddit candidates through MCP Scraper SERP harvest, then read selected posts through MCP Scraper browser-agent by default. Use for authentic audience language, objections, pain points, and questions. Keep proxyMode as location and pass location/proxyZip when the Reddit research has a local market. Do not use generic web scraping fallbacks for Reddit.',\n inputSchema: ThorbitContentRedditResearchInputSchema,\n annotations: readOnlyAnnotations('Research Reddit With Browser Agent'),\n })\n\n registerTool('thorbit_onpage_start_analysis', {\n title: 'Start Thorbit On-Page Analysis',\n description: 'Start a Thorbit on-page analysis for a project keyword. Can run keyword-only analysis or score provided inline content. Hosted Thorbit dispatches the durable analysis workflow and meters usage against the MCP API key.',\n inputSchema: ThorbitOnPageStartAnalysisInputSchema,\n annotations: writeAnnotations('Start Thorbit On-Page Analysis'),\n })\n\n registerTool('thorbit_onpage_get_analysis', {\n title: 'Read Thorbit On-Page Analysis',\n description: 'Read persisted on-page analysis status, score, signal counts, and content report summary by analysis public ID. Use after thorbit_onpage_start_analysis to poll durable results.',\n inputSchema: ThorbitOnPageGetAnalysisInputSchema,\n annotations: readOnlyAnnotations('Read Thorbit On-Page Analysis', false),\n })\n\n return server\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ThorbitContentOnPageMcpEnvelope } from './content-onpage-api-client.js'\nimport type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nexport function formatThorbitContentOnPageMcpToolResult(\n toolName: ThorbitContentOnPageMcpToolName,\n envelope: ThorbitContentOnPageMcpEnvelope,\n): CallToolResult {\n const text = JSON.stringify({\n toolName,\n ...envelope,\n }, null, 2)\n return {\n content: [{ type: 'text', text }],\n isError: !envelope.ok,\n }\n}\n","import { z } from 'zod'\n\nexport const ThorbitContentExtractUrlInputSchema = {\n url: z.string().url().describe('Public URL to extract through MCP Scraper.'),\n browserFallback: z.boolean().default(true).describe('Use MCP Scraper browser fallback for JS-heavy pages. Default true.'),\n extractBranding: z.boolean().default(false).describe('Ask MCP Scraper to extract brand colors, fonts, logo, and favicon when supported.'),\n downloadMedia: z.boolean().default(false).describe('Ask MCP Scraper to download page media when supported.'),\n maxCharacters: z.number().int().min(500).max(500000).default(80000).describe('Maximum extracted content characters returned to the MCP caller.'),\n}\n\nconst McpScraperProxyModeSchema = z.enum(['location', 'configured', 'none'])\nconst McpScraperSerpDeviceSchema = z.enum(['desktop', 'mobile'])\n\nexport const ThorbitContentHarvestSerpInputSchema = {\n query: z.string().min(1).max(400).describe('Core search topic. Separate location when possible, e.g. query=\"best CRM\" and location=\"Denver, CO\".'),\n location: z.string().min(1).max(160).optional().describe('Optional search location, such as Denver, CO. Required for precise residential proxy targeting.'),\n gl: z.string().length(2).optional().describe('Optional Google country code, such as us.'),\n hl: z.string().min(2).max(12).optional().describe('Optional Google interface language, such as en.'),\n device: McpScraperSerpDeviceSchema.default('desktop').describe('SERP device context. Use desktop by default; use mobile only when requested.'),\n maxQuestions: z.number().int().min(1).max(200).default(30).describe('Maximum PAA questions when serpOnly is false.'),\n includeSerp: z.boolean().default(true).describe('Include organic SERP results. Default true.'),\n serpOnly: z.boolean().default(false).describe('Use fast SERP-only mode when PAA expansion is not needed.'),\n proxyMode: McpScraperProxyModeSchema.default('location').describe('MCP Scraper proxy mode. Use location by default for US city/state SERPs so MCP Scraper rotates fresh residential proxy IDs and browser sessions across retryable CAPTCHA/proxy/location failures.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting. Use when a specific ZIP or city-center ZIP is known.'),\n debug: z.boolean().default(false).describe('Include sanitized MCP Scraper browser/proxy/location diagnostics and attempt telemetry. Use true when debugging CAPTCHA, proxy selection, or localization.'),\n pages: z.number().int().min(1).max(2).default(1).describe('Number of Google result pages to fetch in SERP-only mode.'),\n}\n\nexport const ThorbitContentRedditResearchInputSchema = {\n query: z.string().min(1).max(400).describe('Topic, product, service, or pain point to research on Reddit.'),\n location: z.string().min(1).max(160).optional().describe('Optional location to bias MCP Scraper SERP discovery and residential proxy targeting.'),\n gl: z.string().length(2).optional().describe('Optional Google country code, such as us.'),\n hl: z.string().min(2).max(12).optional().describe('Optional Google interface language, such as en.'),\n device: McpScraperSerpDeviceSchema.default('desktop').describe('SERP device context for Reddit discovery.'),\n proxyMode: McpScraperProxyModeSchema.default('location').describe('MCP Scraper proxy mode for Reddit discovery. Use location by default so MCP Scraper owns CAPTCHA/proxy retries.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting.'),\n debug: z.boolean().default(false).describe('Include sanitized MCP Scraper retry/proxy diagnostics for Reddit discovery.'),\n maxPosts: z.number().int().min(1).max(10).default(5).describe('Maximum Reddit posts to read with MCP Scraper browser-agent.'),\n readWithBrowserAgent: z.boolean().default(true).describe('Keep true. Reads Reddit candidates through MCP Scraper browser-agent.'),\n profile: z.string().min(1).max(128).optional().describe('Optional MCP Scraper browser-agent saved profile name.'),\n}\n\nexport const ThorbitOnPageStartAnalysisInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n keyword: z.string().min(1).max(200).describe('Target keyword or query for on-page analysis.'),\n force: z.boolean().default(false).describe('Force restart if an analysis is already running.'),\n source: z.discriminatedUnion('mode', [\n z.object({ mode: z.literal('keyword_only') }).strict(),\n z.object({\n mode: z.literal('inline_content'),\n title: z.string().min(1).max(255).optional(),\n text: z.string().min(20).max(500000),\n sourceUrl: z.string().url().optional(),\n }).strict(),\n ]).default({ mode: 'keyword_only' }).describe('Use keyword_only for research-only analysis or inline_content to score provided content.'),\n}\n\nexport const ThorbitOnPageGetAnalysisInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID returned by thorbit_onpage_start_analysis.'),\n}\n\nexport const ThorbitContentOnPageMcpToolInputSchemas = {\n thorbit_content_extract_url: ThorbitContentExtractUrlInputSchema,\n thorbit_content_harvest_serp: ThorbitContentHarvestSerpInputSchema,\n thorbit_content_reddit_research: ThorbitContentRedditResearchInputSchema,\n thorbit_onpage_start_analysis: ThorbitOnPageStartAnalysisInputSchema,\n thorbit_onpage_get_analysis: ThorbitOnPageGetAnalysisInputSchema,\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../bin/thorbit-content-mcp.ts","../../src/content-onpage-api-client.ts","../../src/content-onpage-mcp-env.ts","../../src/content-onpage-mcp-server.ts","../../src/content-onpage-mcp-response-formatters.ts","../../src/content-onpage-mcp-tool-schemas.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { ThorbitContentOnPageApiClient } from '../src/content-onpage-api-client.js'\nimport { resolveThorbitContentOnPageMcpEnv } from '../src/content-onpage-mcp-env.js'\nimport { buildThorbitContentOnPageMcpServer } from '../src/content-onpage-mcp-server.js'\n\nasync function main() {\n const env = resolveThorbitContentOnPageMcpEnv()\n const client = new ThorbitContentOnPageApiClient(env)\n const server = buildThorbitContentOnPageMcpServer(client)\n await server.connect(new StdioServerTransport())\n}\n\nmain().catch(error => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n})\n","import type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nexport type ThorbitContentOnPageMcpEnvelope =\n | {\n ok: true\n result: unknown\n warnings?: string[]\n requestId: string\n usage?: Record<string, unknown>\n }\n | {\n ok: false\n error: {\n code: string\n message: string\n details?: unknown\n }\n requestId: string\n }\n\nexport class ThorbitContentOnPageApiClient {\n private readonly baseUrl: string\n private readonly apiKey: string\n\n constructor(options: { baseUrl: string; apiKey: string }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.apiKey = options.apiKey\n }\n\n async callTool(toolName: ThorbitContentOnPageMcpToolName, input: unknown): Promise<ThorbitContentOnPageMcpEnvelope> {\n const response = await fetch(`${this.baseUrl}/api/v1/mcp/content-onpage/${toolName}`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input ?? {}),\n })\n\n const body = await response.json().catch(() => null) as ThorbitContentOnPageMcpEnvelope | null\n if (body && typeof body === 'object' && 'ok' in body) return body\n\n return {\n ok: false,\n requestId: 'unavailable',\n error: {\n code: response.ok ? 'invalid_response' : `http_${response.status}`,\n message: response.ok ? 'Thorbit returned an invalid MCP response' : `Thorbit API request failed with HTTP ${response.status}`,\n },\n }\n }\n}\n","import { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type ThorbitContentOnPageMcpEnv = {\n apiKey: string\n baseUrl: string\n}\n\nfunction readApiKeyFile(): string | undefined {\n const explicitPath = process.env.THORBIT_CONTENT_MCP_KEY_PATH?.trim()\n const paths = [explicitPath, join(homedir(), '.thorbit-content-mcp-key')].filter(Boolean) as string[]\n for (const path of paths) {\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n continue\n }\n }\n return undefined\n}\n\nexport function resolveThorbitContentOnPageMcpEnv(): ThorbitContentOnPageMcpEnv {\n const apiKey = (\n process.env.THORBIT_API_KEY ||\n process.env.THORBIT_MCP_API_KEY ||\n process.env.THORBIT_CONTENT_MCP_API_KEY ||\n readApiKeyFile()\n )?.trim()\n\n if (!apiKey) {\n throw new Error('THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-content-mcp-key is required')\n }\n\n return {\n apiKey,\n baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_CONTENT_MCP_BASE_URL || 'https://thorbit.ai').trim(),\n }\n}\n","import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodRawShape } from 'zod'\nimport type { ThorbitContentOnPageApiClient } from './content-onpage-api-client.js'\nimport { formatThorbitContentOnPageMcpToolResult } from './content-onpage-mcp-response-formatters.js'\nimport {\n ThorbitContentOpportunitiesListInputSchema,\n ThorbitContentExtractUrlInputSchema,\n ThorbitContentHarvestSerpInputSchema,\n ThorbitContentPipelineGetInputSchema,\n ThorbitContentPipelineImproveInputSchema,\n ThorbitContentPipelineResumeInputSchema,\n ThorbitContentPipelineStartFromBriefInputSchema,\n ThorbitContentPipelineStartInputSchema,\n ThorbitContentRedditResearchInputSchema,\n ThorbitOnPageApplyEditsInputSchema,\n ThorbitOnPageGenerateBriefInputSchema,\n ThorbitOnPageGenerateStrategyInputSchema,\n ThorbitOnPageGetEditorContentInputSchema,\n ThorbitOnPageGetAnalysisInputSchema,\n ThorbitOnPageListSourcesInputSchema,\n ThorbitOnPageProposeEditsInputSchema,\n ThorbitOnPageRescoreAnalysisInputSchema,\n ThorbitOnPageStartAnalysisInputSchema,\n ThorbitOnPageUpdateEditStatusInputSchema,\n} from './content-onpage-mcp-tool-schemas.js'\nimport type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nconst VERSION = '0.1.3'\n\ntype ThorbitContentOnPageToolConfig<InputArgs extends ZodRawShape> = {\n title: string\n description: string\n inputSchema: InputArgs\n annotations: ToolAnnotations\n}\n\nfunction readOnlyAnnotations(title: string, openWorldHint = true) {\n return {\n title,\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint,\n }\n}\n\nfunction writeAnnotations(title: string, openWorldHint = false) {\n return {\n title,\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint,\n }\n}\n\nexport function buildThorbitContentOnPageMcpServer(client: ThorbitContentOnPageApiClient): McpServer {\n const server = new McpServer({ name: 'thorbit-content-mcp', version: VERSION })\n\n server.registerResource(\n 'analysis',\n new ResourceTemplate('thorbit-content://analyses/{analysisPublicId}', { list: undefined }),\n {\n title: 'Thorbit On-Page Analysis',\n description: 'Status, score, signal counts, and summary for one Thorbit on-page analysis.',\n mimeType: 'application/json',\n },\n async (uri, variables) => {\n const analysisPublicId = Array.isArray(variables.analysisPublicId)\n ? variables.analysisPublicId[0]\n : variables.analysisPublicId\n const envelope = await client.callTool('thorbit_onpage_get_analysis', { analysisPublicId: String(analysisPublicId) })\n return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(envelope, null, 2) }] }\n },\n )\n\n function registerTool<T extends ThorbitContentOnPageMcpToolName>(\n toolName: T,\n config: ThorbitContentOnPageToolConfig<ZodRawShape>,\n ): void {\n server.registerTool(toolName, config, async (input) => {\n const envelope = await client.callTool(toolName, input)\n return formatThorbitContentOnPageMcpToolResult(toolName, envelope)\n })\n }\n\n registerTool('thorbit_content_extract_url', {\n title: 'Extract URL For Content Analysis',\n description: 'Extract a public URL through MCP Scraper only. Use this before content audits, source ingestion, outline planning, or on-page comparisons. Browser fallback is enabled by default for JS-heavy pages.',\n inputSchema: ThorbitContentExtractUrlInputSchema,\n annotations: readOnlyAnnotations('Extract URL For Content Analysis'),\n })\n\n registerTool('thorbit_content_harvest_serp', {\n title: 'Harvest SERP And PAA Evidence',\n description: 'Harvest Google SERP/PAA evidence through MCP Scraper only. Returns the full evidence surface from MCP Scraper: PAA flat questions, PAA tree, organic SERP, local pack, videos/shorts, forums, whatPeopleSaying, AI Overview text/citations/sections, AI Mode, entity IDs, stats, diagnostics, and retry attempts. Split topic from location when possible. Keep proxyMode as location for US city/state SERPs so MCP Scraper rotates fresh residential proxy IDs and browser sessions across retryable CAPTCHA, proxy tunnel, proxy availability, and location-mismatch failures. Pass proxyZip for known city-center ZIP targeting and debug true when retry/proxy diagnostics are needed.',\n inputSchema: ThorbitContentHarvestSerpInputSchema,\n annotations: readOnlyAnnotations('Harvest SERP And PAA Evidence'),\n })\n\n registerTool('thorbit_content_reddit_research', {\n title: 'Research Reddit With MCP Scraper Browser Agent',\n description: 'Find Reddit candidates through MCP Scraper SERP harvest, then read selected posts through MCP Scraper browser-agent by default. Use for authentic audience language, objections, pain points, and questions. Keep proxyMode as location and pass location/proxyZip when the Reddit research has a local market. Do not use generic web scraping fallbacks for Reddit.',\n inputSchema: ThorbitContentRedditResearchInputSchema,\n annotations: readOnlyAnnotations('Research Reddit With Browser Agent'),\n })\n\n registerTool('thorbit_content_opportunities_list', {\n title: 'List Content Opportunities',\n 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.',\n inputSchema: ThorbitContentOpportunitiesListInputSchema,\n annotations: readOnlyAnnotations('List Content Opportunities', false),\n })\n\n registerTool('thorbit_content_pipeline_start', {\n title: 'Start Content Pipeline',\n 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.',\n inputSchema: ThorbitContentPipelineStartInputSchema,\n annotations: writeAnnotations('Start Content Pipeline'),\n })\n\n registerTool('thorbit_content_pipeline_get', {\n title: 'Read Content Pipeline',\n 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.',\n inputSchema: ThorbitContentPipelineGetInputSchema,\n annotations: readOnlyAnnotations('Read Content Pipeline', false),\n })\n\n registerTool('thorbit_content_pipeline_resume', {\n title: 'Resume Content Pipeline',\n description: 'Resume a paused Thorbit content pipeline after strategy or brief review, optionally appending user instructions before the next phase dispatch.',\n inputSchema: ThorbitContentPipelineResumeInputSchema,\n annotations: writeAnnotations('Resume Content Pipeline'),\n })\n\n registerTool('thorbit_content_pipeline_start_from_brief', {\n title: 'Start Writing From Brief',\n 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.',\n inputSchema: ThorbitContentPipelineStartFromBriefInputSchema,\n annotations: writeAnnotations('Start Writing From Brief'),\n })\n\n registerTool('thorbit_content_pipeline_improve', {\n title: 'Improve Existing Content',\n 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.',\n inputSchema: ThorbitContentPipelineImproveInputSchema,\n annotations: writeAnnotations('Improve Existing Content'),\n })\n\n registerTool('thorbit_onpage_list_sources', {\n title: 'List On-Page Source Options',\n 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.',\n inputSchema: ThorbitOnPageListSourcesInputSchema,\n annotations: readOnlyAnnotations('List On-Page Source Options', false),\n })\n\n registerTool('thorbit_onpage_start_analysis', {\n title: 'Start Thorbit On-Page Analysis',\n 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.',\n inputSchema: ThorbitOnPageStartAnalysisInputSchema,\n annotations: writeAnnotations('Start Thorbit On-Page Analysis'),\n })\n\n registerTool('thorbit_onpage_get_analysis', {\n title: 'Read Thorbit On-Page Analysis',\n 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.',\n inputSchema: ThorbitOnPageGetAnalysisInputSchema,\n annotations: readOnlyAnnotations('Read Thorbit On-Page Analysis', false),\n })\n\n registerTool('thorbit_onpage_get_editor_content', {\n title: 'Read On-Page Editor Content',\n 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.',\n inputSchema: ThorbitOnPageGetEditorContentInputSchema,\n annotations: readOnlyAnnotations('Read On-Page Editor Content', false),\n })\n\n registerTool('thorbit_onpage_rescore_analysis', {\n title: 'Re-Score On-Page Content',\n 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.',\n inputSchema: ThorbitOnPageRescoreAnalysisInputSchema,\n annotations: writeAnnotations('Re-Score On-Page Content'),\n })\n\n registerTool('thorbit_onpage_generate_brief', {\n title: 'Generate On-Page Brief',\n description: 'Generate or return the Thorbit final writer brief for a completed on-page analysis. Persists brief content and structured brief data for later writing.',\n inputSchema: ThorbitOnPageGenerateBriefInputSchema,\n annotations: writeAnnotations('Generate On-Page Brief'),\n })\n\n registerTool('thorbit_onpage_generate_strategy', {\n title: 'Generate On-Page Strategy',\n description: 'Generate and persist the Thorbit on-page strategy document for a completed analysis, optionally using article content as context.',\n inputSchema: ThorbitOnPageGenerateStrategyInputSchema,\n annotations: writeAnnotations('Generate On-Page Strategy'),\n })\n\n registerTool('thorbit_onpage_propose_edits', {\n title: 'Propose On-Page Edits',\n 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.',\n inputSchema: ThorbitOnPageProposeEditsInputSchema,\n annotations: writeAnnotations('Propose On-Page Edits'),\n })\n\n registerTool('thorbit_onpage_update_edit_status', {\n title: 'Accept Or Reject On-Page Edit',\n description: 'Accept or reject one proposed edit in an on-page edit session before applying edits to the Thorbit content piece.',\n inputSchema: ThorbitOnPageUpdateEditStatusInputSchema,\n annotations: writeAnnotations('Accept Or Reject On-Page Edit'),\n })\n\n registerTool('thorbit_onpage_apply_edits', {\n title: 'Apply On-Page Edits',\n description: 'Apply all accepted on-page edits to the editable Thorbit content piece and create before/after content version snapshots.',\n inputSchema: ThorbitOnPageApplyEditsInputSchema,\n annotations: writeAnnotations('Apply On-Page Edits'),\n })\n\n return server\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ThorbitContentOnPageMcpEnvelope } from './content-onpage-api-client.js'\nimport type { ThorbitContentOnPageMcpToolName } from './content-onpage-mcp-tool-names.js'\n\nexport function formatThorbitContentOnPageMcpToolResult(\n toolName: ThorbitContentOnPageMcpToolName,\n envelope: ThorbitContentOnPageMcpEnvelope,\n): CallToolResult {\n const text = JSON.stringify({\n toolName,\n ...envelope,\n }, null, 2)\n return {\n content: [{ type: 'text', text }],\n isError: !envelope.ok,\n }\n}\n","import { z } from 'zod'\n\nexport const ThorbitContentExtractUrlInputSchema = {\n url: z.string().url().describe('Public URL to extract through MCP Scraper.'),\n browserFallback: z.boolean().default(true).describe('Use MCP Scraper browser fallback for JS-heavy pages. Default true.'),\n extractBranding: z.boolean().default(false).describe('Ask MCP Scraper to extract brand colors, fonts, logo, and favicon when supported.'),\n downloadMedia: z.boolean().default(false).describe('Ask MCP Scraper to download page media when supported.'),\n maxCharacters: z.number().int().min(500).max(500000).default(80000).describe('Maximum extracted content characters returned to the MCP caller.'),\n}\n\nconst McpScraperProxyModeSchema = z.enum(['location', 'configured', 'none'])\nconst McpScraperSerpDeviceSchema = z.enum(['desktop', 'mobile'])\nconst PipelineModeSchema = z.enum(['brief', 'write', 'optimize'])\nconst ContentPipelineSourceKindSchema = z.enum([\n 'search-console-query',\n 'topic-map-node',\n 'data-hub-roadmap',\n 'ranked-keyword',\n 'competitor-keyword',\n 'eics-entity',\n 'phrase-question',\n 'manual-keyword',\n])\n\nconst ContentPipelineSourceRefSchema = z.object({\n sourceKind: ContentPipelineSourceKindSchema,\n keyword: z.string().min(1).max(200),\n sourcePublicId: z.string().min(1).max(128).optional(),\n title: z.string().min(1).max(300).optional(),\n reason: z.string().min(1).max(1000).optional(),\n sourceUrl: z.string().url().optional(),\n metrics: z.record(z.string(), z.unknown()).optional(),\n selectedAt: z.string().datetime().optional(),\n}).strict()\n\nexport const ThorbitContentHarvestSerpInputSchema = {\n query: z.string().min(1).max(400).describe('Core search topic. Separate location when possible, e.g. query=\"best CRM\" and location=\"Denver, CO\".'),\n location: z.string().min(1).max(160).optional().describe('Optional search location, such as Denver, CO. Required for precise residential proxy targeting.'),\n gl: z.string().length(2).optional().describe('Optional Google country code, such as us.'),\n hl: z.string().min(2).max(12).optional().describe('Optional Google interface language, such as en.'),\n device: McpScraperSerpDeviceSchema.default('desktop').describe('SERP device context. Use desktop by default; use mobile only when requested.'),\n maxQuestions: z.number().int().min(1).max(200).default(30).describe('Maximum PAA questions when serpOnly is false.'),\n includeSerp: z.boolean().default(true).describe('Include organic SERP results. Default true.'),\n serpOnly: z.boolean().default(false).describe('Use fast SERP-only mode when PAA expansion is not needed.'),\n proxyMode: McpScraperProxyModeSchema.default('location').describe('MCP Scraper proxy mode. Use location by default for US city/state SERPs so MCP Scraper rotates fresh residential proxy IDs and browser sessions across retryable CAPTCHA/proxy/location failures.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting. Use when a specific ZIP or city-center ZIP is known.'),\n debug: z.boolean().default(false).describe('Include sanitized MCP Scraper browser/proxy/location diagnostics and attempt telemetry. Use true when debugging CAPTCHA, proxy selection, or localization.'),\n pages: z.number().int().min(1).max(2).default(1).describe('Number of Google result pages to fetch in SERP-only mode.'),\n}\n\nexport const ThorbitContentRedditResearchInputSchema = {\n query: z.string().min(1).max(400).describe('Topic, product, service, or pain point to research on Reddit.'),\n location: z.string().min(1).max(160).optional().describe('Optional location to bias MCP Scraper SERP discovery and residential proxy targeting.'),\n gl: z.string().length(2).optional().describe('Optional Google country code, such as us.'),\n hl: z.string().min(2).max(12).optional().describe('Optional Google interface language, such as en.'),\n device: McpScraperSerpDeviceSchema.default('desktop').describe('SERP device context for Reddit discovery.'),\n proxyMode: McpScraperProxyModeSchema.default('location').describe('MCP Scraper proxy mode for Reddit discovery. Use location by default so MCP Scraper owns CAPTCHA/proxy retries.'),\n proxyZip: z.string().regex(/^\\d{5}$/).optional().describe('Optional US ZIP override for residential location proxy targeting.'),\n debug: z.boolean().default(false).describe('Include sanitized MCP Scraper retry/proxy diagnostics for Reddit discovery.'),\n maxPosts: z.number().int().min(1).max(10).default(5).describe('Maximum Reddit posts to read with MCP Scraper browser-agent.'),\n readWithBrowserAgent: z.boolean().default(true).describe('Keep true. Reads Reddit candidates through MCP Scraper browser-agent.'),\n profile: z.string().min(1).max(128).optional().describe('Optional MCP Scraper browser-agent saved profile name.'),\n}\n\nconst ThorbitOnPageSourceSelectionSchema = z.discriminatedUnion('mode', [\n z.object({ mode: z.literal('keyword_only') }).strict(),\n z.object({\n mode: z.literal('inline_content'),\n title: z.string().min(1).max(255).optional(),\n text: z.string().min(20).max(500000),\n sourceUrl: z.string().url().optional(),\n }).strict(),\n z.object({ mode: z.literal('content_piece'), contentPiecePublicId: z.string().min(1) }).strict(),\n z.object({\n mode: z.literal('wordpress_plugin_page'),\n connectionPublicId: z.string().min(1),\n externalPostId: z.number().int().positive(),\n }).strict(),\n z.object({\n mode: z.literal('wordpress_api_page'),\n connectionPublicId: z.string().min(1),\n connectionPagePublicId: z.string().min(1),\n }).strict(),\n z.object({\n mode: z.literal('project_website_scrape'),\n websitePagePublicId: z.string().min(1),\n }).strict(),\n])\n\nexport const ThorbitContentOpportunitiesListInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n sourceKind: ContentPipelineSourceKindSchema.optional().describe('Optional content opportunity source kind filter.'),\n limit: z.number().int().min(1).max(100).default(10).describe('Maximum opportunities per source.'),\n}\n\nexport const ThorbitContentPipelineStartInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n keyword: z.string().min(1).max(200).describe('Target keyword or query for the content pipeline.'),\n mode: PipelineModeSchema.describe('Content pipeline mode: brief, write, or optimize.'),\n reviewBrief: z.boolean().default(false).describe('Pause after brief generation for review before writing.'),\n notes: z.string().max(500).optional().describe('Optional writing or strategy instructions.'),\n existingContentPiecePublicId: z.string().min(1).optional().describe('Required for optimize mode. Existing Thorbit content piece public ID.'),\n writingStyleId: z.number().int().positive().optional().describe('Optional Thorbit writing style ID.'),\n maxIterations: z.number().int().min(0).max(3).optional().describe('Optional verification/improvement iteration cap.'),\n analysisPublicId: z.string().min(1).optional().describe('Optional related on-page analysis public ID.'),\n source: ContentPipelineSourceRefSchema.optional().describe('Optional persisted content opportunity source reference.'),\n}\n\nexport const ThorbitContentPipelineGetInputSchema = {\n jobPublicId: z.string().min(1).describe('Content pipeline workflow job public ID.'),\n includePhaseData: z.boolean().default(true).describe('Include raw workflow phaseData in addition to the normalized run view.'),\n}\n\nexport const ThorbitContentPipelineResumeInputSchema = {\n jobPublicId: z.string().min(1).describe('Paused content pipeline workflow job public ID.'),\n userInstructions: z.string().max(4000).default('').describe('Optional instructions to append before resuming.'),\n}\n\nexport const ThorbitContentPipelineStartFromBriefInputSchema = {\n briefPublicId: z.string().min(1).describe('Approved Thorbit brief public ID.'),\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID associated with the brief.'),\n writingStyleId: z.number().int().positive().optional().describe('Optional Thorbit writing style ID.'),\n}\n\nexport const ThorbitContentPipelineImproveInputSchema = {\n jobOrPiecePublicId: z.string().min(1).describe('Existing content pipeline job public ID or content piece public ID to improve.'),\n}\n\nexport const ThorbitOnPageListSourcesInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n kind: z.enum(['keyword', 'wordpress_plugin', 'wordpress_api', 'project_website_scrape']).optional().describe('Optional source kind filter.'),\n search: z.string().max(200).optional().describe('Optional search string for page/title/url filtering.'),\n limit: z.number().int().min(1).max(100).default(25).describe('Maximum source options to return.'),\n offset: z.number().int().min(0).default(0).describe('Pagination offset.'),\n connectionPublicId: z.string().min(1).optional().describe('Optional WordPress connection public ID filter.'),\n}\n\nexport const ThorbitOnPageStartAnalysisInputSchema = {\n projectPublicId: z.string().min(1).describe('Thorbit project public ID.'),\n keyword: 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.'),\n force: z.boolean().default(false).describe('Force restart if an analysis is already running.'),\n 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.'),\n}\n\nexport const ThorbitOnPageGetAnalysisInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID returned by thorbit_onpage_start_analysis.'),\n detail: 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.'),\n includeBrief: z.boolean().default(true).describe('Include persisted brief content and structured brief data when available.'),\n includeStrategy: z.boolean().default(true).describe('Include persisted strategy content when available.'),\n includeRawAnalysisData: z.boolean().default(false).describe('Include raw analysisData JSON. Automatically included for detail=full.'),\n}\n\nexport const ThorbitOnPageGetEditorContentInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID.'),\n}\n\nexport const ThorbitOnPageRescoreAnalysisInputSchema = {\n analysisPublicId: z.string().min(1).describe('Completed on-page analysis public ID.'),\n editorContentPiecePublicId: z.string().min(1).optional().describe('Editable content piece public ID returned by thorbit_onpage_get_editor_content.'),\n contentPiecePublicId: z.string().min(1).optional().describe('Alternate content piece public ID to score.'),\n}\n\nexport const ThorbitOnPageGenerateBriefInputSchema = {\n analysisPublicId: z.string().min(1).describe('Completed on-page analysis public ID.'),\n regenerate: z.boolean().default(false).describe('Regenerate an existing brief instead of returning it.'),\n}\n\nexport const ThorbitOnPageGenerateStrategyInputSchema = {\n analysisPublicId: z.string().min(1).describe('Completed on-page analysis public ID.'),\n articleContent: z.string().min(20).max(500000).optional().describe('Optional article content to include in strategy generation.'),\n}\n\nexport const ThorbitOnPageProposeEditsInputSchema = {\n analysisPublicId: z.string().min(1).describe('Completed full-mode on-page analysis public ID.'),\n}\n\nexport const ThorbitOnPageUpdateEditStatusInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID with a proposed edit session.'),\n editId: z.string().min(1).describe('Edit ID from thorbit_onpage_propose_edits.'),\n status: z.enum(['accepted', 'rejected']).describe('Accept or reject this proposed edit.'),\n}\n\nexport const ThorbitOnPageApplyEditsInputSchema = {\n analysisPublicId: z.string().min(1).describe('On-page analysis public ID with accepted edits.'),\n}\n\nexport const ThorbitContentOnPageMcpToolInputSchemas = {\n thorbit_content_extract_url: ThorbitContentExtractUrlInputSchema,\n thorbit_content_harvest_serp: ThorbitContentHarvestSerpInputSchema,\n thorbit_content_reddit_research: ThorbitContentRedditResearchInputSchema,\n thorbit_content_opportunities_list: ThorbitContentOpportunitiesListInputSchema,\n thorbit_content_pipeline_start: ThorbitContentPipelineStartInputSchema,\n thorbit_content_pipeline_get: ThorbitContentPipelineGetInputSchema,\n thorbit_content_pipeline_resume: ThorbitContentPipelineResumeInputSchema,\n thorbit_content_pipeline_start_from_brief: ThorbitContentPipelineStartFromBriefInputSchema,\n thorbit_content_pipeline_improve: ThorbitContentPipelineImproveInputSchema,\n thorbit_onpage_list_sources: ThorbitOnPageListSourcesInputSchema,\n thorbit_onpage_start_analysis: ThorbitOnPageStartAnalysisInputSchema,\n thorbit_onpage_get_analysis: ThorbitOnPageGetAnalysisInputSchema,\n thorbit_onpage_get_editor_content: ThorbitOnPageGetEditorContentInputSchema,\n thorbit_onpage_rescore_analysis: ThorbitOnPageRescoreAnalysisInputSchema,\n thorbit_onpage_generate_brief: ThorbitOnPageGenerateBriefInputSchema,\n thorbit_onpage_generate_strategy: ThorbitOnPageGenerateStrategyInputSchema,\n thorbit_onpage_propose_edits: ThorbitOnPageProposeEditsInputSchema,\n thorbit_onpage_update_edit_status: ThorbitOnPageUpdateEditStatusInputSchema,\n thorbit_onpage_apply_edits: ThorbitOnPageApplyEditsInputSchema,\n}\n"],"mappings":"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","names":[]}