Initial commit
This commit is contained in:
14
.claude-plugin/plugin.json
Normal file
14
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "websearch-tools",
|
||||||
|
"description": "Smart web tool routing via hooks that redirect WebFetch/WebSearch to Tavily. Includes context7 MCP for library docs and a skill for tool selection.",
|
||||||
|
"version": "1.2.1",
|
||||||
|
"author": {
|
||||||
|
"name": "Fatih Akyon"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
],
|
||||||
|
"hooks": [
|
||||||
|
"./hooks"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# websearch-tools
|
||||||
|
|
||||||
|
Smart web tool routing via hooks that redirect WebFetch/WebSearch to Tavily. Includes context7 MCP for library docs and a skill for tool selection.
|
||||||
34
hooks/hooks.json
Normal file
34
hooks/hooks.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"description": "Web search and Tavily integration hooks",
|
||||||
|
"hooks": {
|
||||||
|
"PreToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "WebFetch",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/webfetch_to_tavily_extract.py"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": "WebSearch",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/websearch_to_tavily_search.py"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": "mcp__tavily__tavily-extract",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/tavily_extract_to_advanced.py"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
46
hooks/scripts/tavily_extract_to_advanced.py
Executable file
46
hooks/scripts/tavily_extract_to_advanced.py
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
PreToolUse hook: intercept mcp__tavily__tavily-extract
|
||||||
|
- Block GitHub URLs and suggest using GitHub MCP tools instead
|
||||||
|
- Otherwise, upgrade extract_depth to "advanced"
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
tool_input = data["tool_input"]
|
||||||
|
urls = tool_input.get("urls", [])
|
||||||
|
|
||||||
|
# Check for GitHub URLs
|
||||||
|
github_domains = ("github.com", "raw.githubusercontent.com", "gist.github.com")
|
||||||
|
github_urls = [url for url in urls if any(domain in url for domain in github_domains)]
|
||||||
|
|
||||||
|
if github_urls:
|
||||||
|
# Block and suggest GitHub MCP tools
|
||||||
|
print(json.dumps({
|
||||||
|
"systemMessage": "GitHub URL detected in Tavily extract tool. AI is directed to use GitHub MCP tools instead.",
|
||||||
|
"hookSpecificOutput": {
|
||||||
|
"hookEventName": "PreToolUse",
|
||||||
|
"permissionDecision": "deny",
|
||||||
|
"permissionDecisionReason": "GitHub URL detected. Please use GitHub MCP tools (mcp__github__*) for more robust data retrieval."
|
||||||
|
},
|
||||||
|
}, separators=(',', ':')))
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
# Always ensure extract_depth="advanced" for non-GitHub URLs
|
||||||
|
tool_input["extract_depth"] = "advanced"
|
||||||
|
|
||||||
|
# Allow the call to proceed
|
||||||
|
print(json.dumps({
|
||||||
|
"hookSpecificOutput": {
|
||||||
|
"hookEventName": "PreToolUse",
|
||||||
|
"permissionDecision": "allow",
|
||||||
|
"permissionDecisionReason": "Automatically upgrading Tavily extract to advanced mode for better content extraction"
|
||||||
|
}
|
||||||
|
}, separators=(',', ':')))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
except (KeyError, json.JSONDecodeError) as err:
|
||||||
|
print(f"hook-error: {err}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
23
hooks/scripts/webfetch_to_tavily_extract.py
Executable file
23
hooks/scripts/webfetch_to_tavily_extract.py
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
PreToolUse hook: intercept WebFetch → suggest using tavily-extract instead
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
url = data["tool_input"]["url"]
|
||||||
|
except (KeyError, json.JSONDecodeError) as err:
|
||||||
|
print(f"hook-error: {err}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(json.dumps({
|
||||||
|
"systemMessage": "WebFetch detected. AI is directed to use Tavily extract instead.",
|
||||||
|
"hookSpecificOutput": {
|
||||||
|
"hookEventName": "PreToolUse",
|
||||||
|
"permissionDecision": "deny",
|
||||||
|
"permissionDecisionReason": f"Please use mcp__tavily__tavily-extract with urls: ['{url}'] and extract_depth: 'advanced'"
|
||||||
|
}
|
||||||
|
}, separators=(',', ':')))
|
||||||
|
sys.exit(0)
|
||||||
24
hooks/scripts/websearch_to_tavily_search.py
Executable file
24
hooks/scripts/websearch_to_tavily_search.py
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
PreToolUse hook: intercept WebSearch → suggest using Tavily search instead
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
tool_input = data["tool_input"]
|
||||||
|
query = tool_input["query"]
|
||||||
|
except (KeyError, json.JSONDecodeError) as err:
|
||||||
|
print(f"hook-error: {err}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(json.dumps({
|
||||||
|
"systemMessage": "WebSearch detected. AI is directed to use Tavily search instead.",
|
||||||
|
"hookSpecificOutput": {
|
||||||
|
"hookEventName": "PreToolUse",
|
||||||
|
"permissionDecision": "deny",
|
||||||
|
"permissionDecisionReason": f"Please use mcp__tavily__tavily-search with query: '{query}'"
|
||||||
|
}
|
||||||
|
}, separators=(',', ':')))
|
||||||
|
sys.exit(0)
|
||||||
61
plugin.lock.json
Normal file
61
plugin.lock.json
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:fcakyon/claude-codex-settings:plugins/websearch-tools",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "3daa2b5dd45909cccf5270b0c3fa5c6ac0aa8aa6",
|
||||||
|
"treeHash": "e01bd8701c7767c6854e87b53500da994ab2610aa49bbf049e6e7c28cd0b729b",
|
||||||
|
"generatedAt": "2025-11-28T10:16:50.949294Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "websearch-tools",
|
||||||
|
"description": "Smart web tool routing via hooks that redirect WebFetch/WebSearch to Tavily. Includes context7 MCP for library docs and a skill for tool selection.",
|
||||||
|
"version": "1.2.1"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "1fe0726bb9aa50266c7ee33eff5abdbe00e1e8727f2f9737331968ab62f19a2e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/hooks.json",
|
||||||
|
"sha256": "b922d7c24ce3f5fdb6581ba8bb7da2523cde43f4fb851dc112e46d031dd075cd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/scripts/webfetch_to_tavily_extract.py",
|
||||||
|
"sha256": "ac3433d5a252e9c651138bac783bc6dc551c96e6e2dedefe336d702c9b11c6dd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/scripts/websearch_to_tavily_search.py",
|
||||||
|
"sha256": "25543d9601135aaf3e1a99fb184cc12b02c0faeee6443af80d1eab203dba88a6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/scripts/tavily_extract_to_advanced.py",
|
||||||
|
"sha256": "b0fa4377fa04fc3ad60f5b6b4b10bf39d1d7cfe6d03b53b3e0a4a36fa45e5947"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "46220c8dc463e12961cd427674d596154335619d21659396de356bfee40c7ffa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/tavily-usage/SKILL.md",
|
||||||
|
"sha256": "4ea803b1ba8db68521e8a28484962497a01bced49f313f6dbb1e00725586830a"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "e01bd8701c7767c6854e87b53500da994ab2610aa49bbf049e6e7c28cd0b729b"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
58
skills/tavily-usage/SKILL.md
Normal file
58
skills/tavily-usage/SKILL.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
name: tavily-usage
|
||||||
|
description: This skill should be used when user asks to "search the web", "fetch content from URL", "extract page content", "use Tavily search", "scrape this website", "get information from this link", or "web search for X".
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tavily Search and Extract
|
||||||
|
|
||||||
|
Use Tavily MCP tools for web search and content retrieval operations.
|
||||||
|
|
||||||
|
## Tool Selection
|
||||||
|
|
||||||
|
### Tavily Search (`mcp__tavily__tavily-search`)
|
||||||
|
|
||||||
|
Use for:
|
||||||
|
|
||||||
|
- Keyword-based searches across the web
|
||||||
|
- Finding relevant pages and content
|
||||||
|
- Quick answer gathering
|
||||||
|
- Multiple result discovery
|
||||||
|
|
||||||
|
**Best for**: Initial research, finding sources, broad queries
|
||||||
|
|
||||||
|
### Tavily Extract (`mcp__tavily__tavily-extract`)
|
||||||
|
|
||||||
|
Use for:
|
||||||
|
|
||||||
|
- Getting detailed content from specific URLs
|
||||||
|
- Deep analysis of page content
|
||||||
|
- Structured data extraction
|
||||||
|
- Following up on search results
|
||||||
|
|
||||||
|
**Best for**: In-depth analysis, specific URL content, detailed information
|
||||||
|
|
||||||
|
## Hook Behavior
|
||||||
|
|
||||||
|
`tavily_extract_to_advanced.py` hook automatically upgrades extract calls to advanced mode for better accuracy when needed.
|
||||||
|
|
||||||
|
## Integration Pattern
|
||||||
|
|
||||||
|
1. Use `mcp__tavily__tavily-search` for discovery phase
|
||||||
|
2. Analyze results to find relevant URLs
|
||||||
|
3. Use `mcp__tavily__tavily-extract` for detailed content on specific URLs
|
||||||
|
4. Process extracted content for user needs
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
Tavily MCP requires:
|
||||||
|
|
||||||
|
- `TAVILY_API_KEY` - API key from Tavily (tvly-...)
|
||||||
|
|
||||||
|
Configure in shell before using the plugin.
|
||||||
|
|
||||||
|
## Cost Considerations
|
||||||
|
|
||||||
|
- Search is cheaper than extract
|
||||||
|
- Use search to filter relevant URLs first
|
||||||
|
- Only extract URLs that are likely relevant
|
||||||
|
- Cache results when possible
|
||||||
Reference in New Issue
Block a user