hive-rank 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bin/install.js +7 -7
- package/commands/backlinks.md +84 -0
- package/commands/glossary.md +40 -0
- package/commands/schema.md +78 -0
- package/dist/hooks/capture-seo-data.js +44 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ npx hive-rank
|
|
|
17
17
|
Or add the MCP server directly:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
claude mcp add --transport
|
|
20
|
+
claude mcp add --transport http hive-rank https://mcp.hive-rank.com/mcp
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## What you get
|
|
@@ -35,7 +35,7 @@ claude mcp add --transport sse hive-rank https://mcp.hive-rank.com/mcp
|
|
|
35
35
|
|
|
36
36
|
### 15 Slash Commands
|
|
37
37
|
|
|
38
|
-
Research commands
|
|
38
|
+
Research commands:
|
|
39
39
|
|
|
40
40
|
- `/hive:kickstart [domain]` — Bootstrap your SEO research
|
|
41
41
|
- `/hive:baseline [domain] [keywords...]` — Establish baseline rankings
|
package/bin/install.js
CHANGED
|
@@ -98,10 +98,10 @@ function registerMcpServer() {
|
|
|
98
98
|
spawnSync('claude', ['mcp', 'remove', oldName], { stdio: 'pipe' });
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
// Register remote MCP server via
|
|
101
|
+
// Register remote MCP server via Streamable HTTP
|
|
102
102
|
const result = spawnSync(
|
|
103
103
|
'claude',
|
|
104
|
-
['mcp', 'add', '--scope', 'user', '--transport', '
|
|
104
|
+
['mcp', 'add', '--scope', 'user', '--transport', 'http', MCP_NAME, MCP_URL],
|
|
105
105
|
{ stdio: 'pipe', timeout: 10000 }
|
|
106
106
|
);
|
|
107
107
|
|
|
@@ -130,7 +130,7 @@ function registerMcpServer() {
|
|
|
130
130
|
|
|
131
131
|
if (!config.mcpServers) config.mcpServers = {};
|
|
132
132
|
config.mcpServers[MCP_NAME] = {
|
|
133
|
-
type: '
|
|
133
|
+
type: 'http',
|
|
134
134
|
url: MCP_URL
|
|
135
135
|
};
|
|
136
136
|
|
|
@@ -262,7 +262,7 @@ if (FLAG_HELP) {
|
|
|
262
262
|
What it does:
|
|
263
263
|
1. Copies dist + commands to ~/.hive-rank/
|
|
264
264
|
2. Registers hooks in ~/.claude/settings.json
|
|
265
|
-
3. Registers remote MCP server via \`claude mcp add\` (
|
|
265
|
+
3. Registers remote MCP server via \`claude mcp add\` (HTTP transport)
|
|
266
266
|
4. Installs slash commands to ~/.claude/commands/hive/
|
|
267
267
|
|
|
268
268
|
Config locations:
|
|
@@ -421,7 +421,7 @@ async function install() {
|
|
|
421
421
|
|
|
422
422
|
if (FLAG_DRY_RUN) {
|
|
423
423
|
if (hasClaudeCli()) {
|
|
424
|
-
dryLog(`Would run: claude mcp add --scope user --transport
|
|
424
|
+
dryLog(`Would run: claude mcp add --scope user --transport http ${MCP_NAME} ${MCP_URL}`);
|
|
425
425
|
} else {
|
|
426
426
|
dryLog('Would register MCP server in ~/.claude.json');
|
|
427
427
|
}
|
|
@@ -429,7 +429,7 @@ async function install() {
|
|
|
429
429
|
log('Registering remote MCP server...');
|
|
430
430
|
const mcpMethod = registerMcpServer();
|
|
431
431
|
if (mcpMethod === 'cli') {
|
|
432
|
-
success('MCP server registered via `claude mcp add` (
|
|
432
|
+
success('MCP server registered via `claude mcp add` (HTTP transport)');
|
|
433
433
|
} else if (mcpMethod === 'direct') {
|
|
434
434
|
success('MCP server registered in ~/.claude.json');
|
|
435
435
|
} else {
|
|
@@ -506,7 +506,7 @@ async function install() {
|
|
|
506
506
|
|
|
507
507
|
Config:
|
|
508
508
|
Hooks: ${SETTINGS_FILE}
|
|
509
|
-
MCP server: ${MCP_URL} (via
|
|
509
|
+
MCP server: ${MCP_URL} (via HTTP)
|
|
510
510
|
Commands: ${COMMANDS_DIR}/
|
|
511
511
|
|
|
512
512
|
To uninstall: node ~/.hive-rank/bin/install.js --uninstall
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backlinks
|
|
3
|
+
description: Analyze backlink opportunities for a domain
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- mcp: hive-rank
|
|
6
|
+
tools:
|
|
7
|
+
- hive_domain
|
|
8
|
+
- hive_search
|
|
9
|
+
- hive_rankings
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Backlink Opportunity Analysis
|
|
13
|
+
|
|
14
|
+
Analyze backlink opportunities for: $ARGUMENTS
|
|
15
|
+
|
|
16
|
+
## Instructions
|
|
17
|
+
|
|
18
|
+
You are a link building strategist. Conduct a thorough backlink opportunity analysis for the given domain or topic area. Provide actionable strategies the user can execute.
|
|
19
|
+
|
|
20
|
+
### 1. Domain Link Profile Assessment
|
|
21
|
+
|
|
22
|
+
Start by evaluating the domain's current backlink situation:
|
|
23
|
+
- What type of site is this? (SaaS, e-commerce, blog, local business, etc.)
|
|
24
|
+
- What kinds of content would naturally attract links in this niche?
|
|
25
|
+
- What is the competitive landscape for links in this space?
|
|
26
|
+
|
|
27
|
+
Use `hive_domain` to understand the domain's current search presence and competitive position.
|
|
28
|
+
|
|
29
|
+
### 2. Competitor Link Source Analysis
|
|
30
|
+
|
|
31
|
+
Identify where competitors in this space typically earn backlinks:
|
|
32
|
+
- **Resource pages** — directories, tool lists, and curated resource pages in the niche
|
|
33
|
+
- **Guest posting targets** — blogs and publications that accept contributor content
|
|
34
|
+
- **Industry roundups** — newsletters, weekly digests, and "best of" lists
|
|
35
|
+
- **Partnership opportunities** — complementary (non-competing) businesses for co-marketing
|
|
36
|
+
- **News and PR** — journalists, bloggers, and publications covering this space
|
|
37
|
+
|
|
38
|
+
Use `hive_rankings` to identify which competitors rank well and are worth analyzing.
|
|
39
|
+
|
|
40
|
+
For each source type, provide 3-5 specific, actionable suggestions with the reasoning behind why they would be effective.
|
|
41
|
+
|
|
42
|
+
### 3. Unlinked Brand Mention Opportunities
|
|
43
|
+
|
|
44
|
+
Suggest strategies for finding and converting unlinked mentions:
|
|
45
|
+
- Search operators to find unlinked mentions (e.g., `"brand name" -site:yourdomain.com`)
|
|
46
|
+
- Types of content where unlinked mentions commonly occur (forums, reviews, comparison posts)
|
|
47
|
+
- Outreach template approach for converting mentions into links
|
|
48
|
+
- Tools and techniques for monitoring new brand mentions
|
|
49
|
+
|
|
50
|
+
### 4. Link-Worthy Content Strategies
|
|
51
|
+
|
|
52
|
+
Recommend content types proven to attract backlinks in this niche:
|
|
53
|
+
- **Original research and data** — surveys, studies, industry benchmarks
|
|
54
|
+
- **Visual assets** — infographics, diagrams, charts that others embed
|
|
55
|
+
- **Free tools and calculators** — interactive resources people link to
|
|
56
|
+
- **Definitive guides** — comprehensive resources that become go-to references
|
|
57
|
+
- **Newsjacking** — timely commentary on industry news and trends
|
|
58
|
+
|
|
59
|
+
For each strategy, explain what to create and why it would earn links.
|
|
60
|
+
|
|
61
|
+
### 5. Link Building Action Plan
|
|
62
|
+
|
|
63
|
+
Provide a prioritized 30-day action plan:
|
|
64
|
+
- **Week 1:** Quick wins (unlinked mentions, broken link opportunities, existing relationships)
|
|
65
|
+
- **Week 2:** Outreach campaign setup (prospect lists, email templates, tracking)
|
|
66
|
+
- **Week 3:** Content creation for link magnets (start the highest-ROI piece)
|
|
67
|
+
- **Week 4:** Active outreach and relationship building
|
|
68
|
+
|
|
69
|
+
### 6. Links to Avoid
|
|
70
|
+
|
|
71
|
+
Warn about link building tactics that can harm the site:
|
|
72
|
+
- Paid links without `rel="sponsored"`
|
|
73
|
+
- Private blog networks (PBNs)
|
|
74
|
+
- Excessive reciprocal link exchanges
|
|
75
|
+
- Low-quality directory submissions
|
|
76
|
+
- Exact-match anchor text over-optimization
|
|
77
|
+
|
|
78
|
+
## Guidelines
|
|
79
|
+
|
|
80
|
+
- Focus on sustainable, white-hat link building strategies
|
|
81
|
+
- Prioritize recommendations by effort vs. impact
|
|
82
|
+
- Be specific with suggestions — generic advice like "create great content" is not helpful
|
|
83
|
+
- Consider the domain's size and resources when making recommendations
|
|
84
|
+
- Use Hive Rank's crowdsourced SERP data to identify which competitors are ranking well and worth analyzing for backlink sources
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: glossary
|
|
3
|
+
description: Look up any SEO term and get a clear definition
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- mcp: hive-rank
|
|
6
|
+
tools:
|
|
7
|
+
- hive_search
|
|
8
|
+
- hive_stats
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# SEO Glossary Lookup
|
|
12
|
+
|
|
13
|
+
Look up and explain the SEO term: $ARGUMENTS
|
|
14
|
+
|
|
15
|
+
## Instructions
|
|
16
|
+
|
|
17
|
+
You are an SEO educator. The user wants to understand an SEO term or concept. Provide a clear, practical explanation following this structure:
|
|
18
|
+
|
|
19
|
+
### 1. Definition
|
|
20
|
+
Give a concise, jargon-free definition of the term. If the term has multiple meanings in SEO, cover each one.
|
|
21
|
+
|
|
22
|
+
### 2. Why It Matters
|
|
23
|
+
Explain why this concept is important for SEO performance. Be specific about the impact on rankings, traffic, or visibility.
|
|
24
|
+
|
|
25
|
+
### 3. Practical Example
|
|
26
|
+
Provide a real-world example showing how this concept works in practice. Use a concrete scenario a website owner or marketer would recognize.
|
|
27
|
+
|
|
28
|
+
### 4. AI Search Relevance
|
|
29
|
+
If this concept is relevant to AI-powered search (ChatGPT, Perplexity, Google AI Overviews, etc.), explain how it applies in that context. AI search engines process and surface content differently than traditional search — highlight any differences in how this term applies. If the term has no particular AI search relevance, skip this section.
|
|
30
|
+
|
|
31
|
+
### 5. Quick Action
|
|
32
|
+
Give one specific, actionable step the user can take right now related to this concept.
|
|
33
|
+
|
|
34
|
+
## Guidelines
|
|
35
|
+
|
|
36
|
+
- Keep the explanation accessible to someone new to SEO, but don't oversimplify for advanced concepts
|
|
37
|
+
- Use concrete numbers and examples where possible
|
|
38
|
+
- Avoid circular definitions (don't define a term using the term itself)
|
|
39
|
+
- If the term is commonly confused with another term, clarify the distinction
|
|
40
|
+
- Reference how Hive Rank data (crowdsourced SERP intelligence) can help track or measure this concept when relevant
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: schema
|
|
3
|
+
description: Generate JSON-LD schema markup for any content type
|
|
4
|
+
allowed-tools: []
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# JSON-LD Schema Markup Generator
|
|
8
|
+
|
|
9
|
+
Generate JSON-LD structured data markup for: $ARGUMENTS
|
|
10
|
+
|
|
11
|
+
## Instructions
|
|
12
|
+
|
|
13
|
+
You are a structured data specialist. Generate complete, valid JSON-LD schema markup based on the user's request.
|
|
14
|
+
|
|
15
|
+
### Step 1: Identify the Schema Type
|
|
16
|
+
|
|
17
|
+
Determine the most appropriate schema type from the user's description. Common types include:
|
|
18
|
+
|
|
19
|
+
- **Article** / **BlogPosting** / **NewsArticle** — for written content
|
|
20
|
+
- **Product** — for product pages with pricing, reviews, availability
|
|
21
|
+
- **FAQPage** — for frequently asked questions
|
|
22
|
+
- **HowTo** — for step-by-step guides and tutorials
|
|
23
|
+
- **Organization** / **LocalBusiness** — for company and business pages
|
|
24
|
+
- **BreadcrumbList** — for navigation breadcrumbs
|
|
25
|
+
- **WebSite** with **SearchAction** — for sitelinks search box
|
|
26
|
+
- **Person** — for author or profile pages
|
|
27
|
+
- **Event** — for events with dates, locations, ticket info
|
|
28
|
+
- **Recipe** — for recipe pages
|
|
29
|
+
- **VideoObject** — for video content
|
|
30
|
+
- **SoftwareApplication** — for apps and tools
|
|
31
|
+
- **Review** / **AggregateRating** — for review content
|
|
32
|
+
|
|
33
|
+
If the user hasn't specified a type, ask them. If they describe their content, infer the best type and explain your choice.
|
|
34
|
+
|
|
35
|
+
### Step 2: Generate the Markup
|
|
36
|
+
|
|
37
|
+
Output a complete, valid JSON-LD script tag:
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<script type="application/ld+json">
|
|
41
|
+
{
|
|
42
|
+
"@context": "https://schema.org",
|
|
43
|
+
"@type": "...",
|
|
44
|
+
...
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Requirements:**
|
|
50
|
+
- Include ALL required properties for the chosen type per Google's structured data guidelines
|
|
51
|
+
- Include recommended properties that improve rich result eligibility
|
|
52
|
+
- Use realistic placeholder values clearly marked with brackets like `[Your Title Here]`
|
|
53
|
+
- Nest related types properly (e.g., `author` as a `Person` object, not a plain string)
|
|
54
|
+
- Include `@id` properties for entities that may be referenced elsewhere on the site
|
|
55
|
+
|
|
56
|
+
### Step 3: Explain the Markup
|
|
57
|
+
|
|
58
|
+
After the JSON-LD block, briefly explain:
|
|
59
|
+
- Which rich result this schema is eligible for in Google Search
|
|
60
|
+
- Any required properties the user must fill in with real data
|
|
61
|
+
- Common mistakes to avoid with this schema type
|
|
62
|
+
- How to test the markup (mention Google's Rich Results Test)
|
|
63
|
+
|
|
64
|
+
### Step 4: AI Search Considerations
|
|
65
|
+
|
|
66
|
+
Note any structured data practices that help with AI search visibility:
|
|
67
|
+
- Clear entity relationships help AI models understand your content
|
|
68
|
+
- Comprehensive schema helps your content get cited in AI-generated answers
|
|
69
|
+
- Proper use of `sameAs` links helps establish entity authority
|
|
70
|
+
|
|
71
|
+
## Guidelines
|
|
72
|
+
|
|
73
|
+
- Always validate against https://schema.org specifications
|
|
74
|
+
- Follow Google's structured data guidelines for rich result eligibility
|
|
75
|
+
- Do not include deprecated properties
|
|
76
|
+
- Use ISO 8601 format for dates
|
|
77
|
+
- Use proper nesting rather than flat structures
|
|
78
|
+
- If multiple schema types apply to a single page, show how to combine them using `@graph`
|
|
@@ -135,15 +135,16 @@ async function contributeToHive(hiveConfig, toolName, toolInput, parsedResponse)
|
|
|
135
135
|
signal: controller.signal
|
|
136
136
|
});
|
|
137
137
|
if (!response.ok) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
);
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const data = await response.json();
|
|
142
|
+
return data;
|
|
143
|
+
} catch {
|
|
144
|
+
return null;
|
|
146
145
|
}
|
|
146
|
+
} catch {
|
|
147
|
+
return null;
|
|
147
148
|
} finally {
|
|
148
149
|
clearTimeout(timeout);
|
|
149
150
|
}
|
|
@@ -391,13 +392,47 @@ async function main() {
|
|
|
391
392
|
debugLog(`Parsed WebFetch response`);
|
|
392
393
|
}
|
|
393
394
|
const { contributeToHive: contributeToHive2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
394
|
-
await contributeToHive2(
|
|
395
|
+
const result = await contributeToHive2(
|
|
395
396
|
{ enabled: true, endpoint: config.endpoint, contributorId: config.contributorId },
|
|
396
397
|
tool_name,
|
|
397
398
|
tool_input,
|
|
398
399
|
parsedResponse
|
|
399
400
|
);
|
|
400
401
|
debugLog("Contribution sent");
|
|
402
|
+
if (result?.contributor) {
|
|
403
|
+
const hiveDir = path.join(os.homedir(), ".hive-rank");
|
|
404
|
+
try {
|
|
405
|
+
fs.mkdirSync(hiveDir, { recursive: true });
|
|
406
|
+
} catch {
|
|
407
|
+
}
|
|
408
|
+
const feedbackPath = path.join(hiveDir, "last-feedback.json");
|
|
409
|
+
let showFull = true;
|
|
410
|
+
try {
|
|
411
|
+
const prev = JSON.parse(fs.readFileSync(feedbackPath, "utf-8"));
|
|
412
|
+
if (prev.sessionId === hookInput.session_id) showFull = false;
|
|
413
|
+
} catch {
|
|
414
|
+
}
|
|
415
|
+
if (showFull) {
|
|
416
|
+
const c = result.contributor;
|
|
417
|
+
const totalContributors = result.network?.contributors ?? 0;
|
|
418
|
+
const topPercent = Math.max(1, 100 - c.percentile);
|
|
419
|
+
const streakPart = c.streak > 0 ? ` | streak: ${c.streak} day${c.streak !== 1 ? "s" : ""}` : "";
|
|
420
|
+
const rankPart = totalContributors > 0 ? ` | rank #${c.rank} of ${totalContributors.toLocaleString()} (top ${topPercent}%)` : "";
|
|
421
|
+
process.stderr.write(`[hive] +${result.inserted} observations${streakPart}${rankPart}
|
|
422
|
+
`);
|
|
423
|
+
fs.writeFileSync(feedbackPath, JSON.stringify({ sessionId: hookInput.session_id, timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
424
|
+
} else {
|
|
425
|
+
process.stderr.write(`[hive] +${result.inserted}
|
|
426
|
+
`);
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
fs.writeFileSync(
|
|
430
|
+
path.join(hiveDir, "last-receipt.json"),
|
|
431
|
+
JSON.stringify({ timestamp: (/* @__PURE__ */ new Date()).toISOString(), inserted: result.inserted, contributor: result.contributor, network: result.network })
|
|
432
|
+
);
|
|
433
|
+
} catch {
|
|
434
|
+
}
|
|
435
|
+
}
|
|
401
436
|
} catch (error) {
|
|
402
437
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
403
438
|
debugLog(`Error: ${errorMsg}`);
|
package/package.json
CHANGED