DeepWiki.py
· 3.1 KiB · Python
Raw
#!/usr/bin/env python3
"""DeepWiki extension - MCP HTTP client for GitHub repo documentation"""
import json
import urllib.request
import ssl
import time
def mcp_call(tool_name, arguments):
"""Make MCP JSON-RPC call to DeepWiki"""
url = "https://mcp.deepwiki.com/mcp"
request_id = str(int(time.time() * 1000))
data = {
"jsonrpc": "2.0",
"id": request_id,
"method": "tools/call",
"params": {
"name": tool_name,
"arguments": arguments
}
}
try:
# Create SSL context that doesn't verify certificates for mitmproxy
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
req = urllib.request.Request(
url,
json.dumps(data).encode(),
{
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream"
}
)
resp = urllib.request.urlopen(req, timeout=60, context=ssl_context)
# Handle SSE response
response_text = resp.read().decode()
# Parse SSE format: extract JSON from "data: " lines
for line in response_text.split('\n'):
if line.startswith('data: '):
data_str = line[6:].strip() # Skip "data: " prefix
# Skip ping events
if data_str == "ping":
continue
try:
result = json.loads(data_str)
if "error" in result:
return f"error: {result['error'].get('message', str(result['error']))}"
# Extract text from MCP response
content = result.get("result", {}).get("content", [])
if content:
texts = [item["text"] for item in content if item.get("type") == "text"]
if texts:
return "\n".join(texts)
except json.JSONDecodeError:
continue
return "error: No valid data in response"
except Exception as e:
return f"error: {type(e).__name__}: {e}"
@register_tool(
"deepwiki_ask",
"Ask questions about GitHub repo",
{"repo": "string", "question": "string"}
)
def deepwiki_ask(args):
"""Ask a question about a GitHub repository (format: owner/repo)"""
return mcp_call("ask_question", {
"repoName": args["repo"],
"question": args["question"]
})
@register_tool(
"deepwiki_structure",
"Get repo documentation structure",
{"repo": "string"}
)
def deepwiki_structure(args):
"""Get documentation structure/topics for a GitHub repository (format: owner/repo)"""
return mcp_call("read_wiki_structure", {
"repoName": args["repo"]
})
@register_tool(
"deepwiki_contents",
"Get repo documentation contents",
{"repo": "string"}
)
def deepwiki_contents(args):
"""Get full documentation contents for a GitHub repository (format: owner/repo)"""
return mcp_call("read_wiki_contents", {
"repoName": args["repo"]
})
| 1 | #!/usr/bin/env python3 |
| 2 | """DeepWiki extension - MCP HTTP client for GitHub repo documentation""" |
| 3 | |
| 4 | import json |
| 5 | import urllib.request |
| 6 | import ssl |
| 7 | import time |
| 8 | |
| 9 | def mcp_call(tool_name, arguments): |
| 10 | """Make MCP JSON-RPC call to DeepWiki""" |
| 11 | url = "https://mcp.deepwiki.com/mcp" |
| 12 | request_id = str(int(time.time() * 1000)) |
| 13 | |
| 14 | data = { |
| 15 | "jsonrpc": "2.0", |
| 16 | "id": request_id, |
| 17 | "method": "tools/call", |
| 18 | "params": { |
| 19 | "name": tool_name, |
| 20 | "arguments": arguments |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | try: |
| 25 | # Create SSL context that doesn't verify certificates for mitmproxy |
| 26 | ssl_context = ssl.create_default_context() |
| 27 | ssl_context.check_hostname = False |
| 28 | ssl_context.verify_mode = ssl.CERT_NONE |
| 29 | |
| 30 | req = urllib.request.Request( |
| 31 | url, |
| 32 | json.dumps(data).encode(), |
| 33 | { |
| 34 | "Content-Type": "application/json", |
| 35 | "Accept": "application/json, text/event-stream" |
| 36 | } |
| 37 | ) |
| 38 | resp = urllib.request.urlopen(req, timeout=60, context=ssl_context) |
| 39 | |
| 40 | # Handle SSE response |
| 41 | response_text = resp.read().decode() |
| 42 | |
| 43 | # Parse SSE format: extract JSON from "data: " lines |
| 44 | for line in response_text.split('\n'): |
| 45 | if line.startswith('data: '): |
| 46 | data_str = line[6:].strip() # Skip "data: " prefix |
| 47 | |
| 48 | # Skip ping events |
| 49 | if data_str == "ping": |
| 50 | continue |
| 51 | |
| 52 | try: |
| 53 | result = json.loads(data_str) |
| 54 | |
| 55 | if "error" in result: |
| 56 | return f"error: {result['error'].get('message', str(result['error']))}" |
| 57 | |
| 58 | # Extract text from MCP response |
| 59 | content = result.get("result", {}).get("content", []) |
| 60 | if content: |
| 61 | texts = [item["text"] for item in content if item.get("type") == "text"] |
| 62 | if texts: |
| 63 | return "\n".join(texts) |
| 64 | except json.JSONDecodeError: |
| 65 | continue |
| 66 | |
| 67 | return "error: No valid data in response" |
| 68 | except Exception as e: |
| 69 | return f"error: {type(e).__name__}: {e}" |
| 70 | |
| 71 | @register_tool( |
| 72 | "deepwiki_ask", |
| 73 | "Ask questions about GitHub repo", |
| 74 | {"repo": "string", "question": "string"} |
| 75 | ) |
| 76 | def deepwiki_ask(args): |
| 77 | """Ask a question about a GitHub repository (format: owner/repo)""" |
| 78 | return mcp_call("ask_question", { |
| 79 | "repoName": args["repo"], |
| 80 | "question": args["question"] |
| 81 | }) |
| 82 | |
| 83 | @register_tool( |
| 84 | "deepwiki_structure", |
| 85 | "Get repo documentation structure", |
| 86 | {"repo": "string"} |
| 87 | ) |
| 88 | def deepwiki_structure(args): |
| 89 | """Get documentation structure/topics for a GitHub repository (format: owner/repo)""" |
| 90 | return mcp_call("read_wiki_structure", { |
| 91 | "repoName": args["repo"] |
| 92 | }) |
| 93 | |
| 94 | @register_tool( |
| 95 | "deepwiki_contents", |
| 96 | "Get repo documentation contents", |
| 97 | {"repo": "string"} |
| 98 | ) |
| 99 | def deepwiki_contents(args): |
| 100 | """Get full documentation contents for a GitHub repository (format: owner/repo)""" |
| 101 | return mcp_call("read_wiki_contents", { |
| 102 | "repoName": args["repo"] |
| 103 | }) |
| 104 |