Last active 1 month ago

Query up-to-date, version-specific documentation for any programming library. Search for libraries and get relevant code examples and documentation.

Revision 0e081b1bedbf89f01460c51092f8c52ae0596208

Context7.py Raw
1#!/usr/bin/env python3
2"""Context7 extension - Query up-to-date documentation for any programming library"""
3
4import json
5import urllib.request
6import urllib.parse
7import os
8
9CONTEXT7_API = "https://context7.com/api"
10API_KEY = os.environ.get("CONTEXT7_API_KEY") # Optional, for higher rate limits
11
12def context7_get(endpoint, params=None):
13 """Make GET request to Context7 API"""
14 try:
15 url = f"{CONTEXT7_API}{endpoint}"
16 if params:
17 url += "?" + urllib.parse.urlencode(params)
18
19 headers = {
20 "X-Context7-Source": "mcp",
21 "Accept": "application/json"
22 }
23
24 # Add API key if available
25 if API_KEY:
26 headers["Authorization"] = f"Bearer {API_KEY}"
27
28 req = urllib.request.Request(url, headers=headers)
29 resp = urllib.request.urlopen(req, timeout=30)
30
31 content_type = resp.headers.get("Content-Type", "")
32 if "application/json" in content_type:
33 return json.loads(resp.read().decode())
34 else:
35 return resp.read().decode()
36 except Exception as e:
37 return {"error": str(e)}
38
39@register_tool(
40 "context7_search",
41 "Search for libraries by name (e.g., 'react', 'express', 'django')",
42 {"query": "string"}
43)
44def context7_search(args):
45 """Search for libraries in Context7"""
46 query = args.get("query", "")
47 if not query:
48 return "error: query required"
49
50 result = context7_get("/v1/search", {"query": query})
51
52 if isinstance(result, dict) and "error" in result:
53 return f"error: {result['error']}"
54
55 if isinstance(result, dict):
56 results = result.get("results", [])
57 else:
58 return f"error: Unexpected response format"
59
60 if not results:
61 return f"No libraries found for: {query}"
62
63 # Format results
64 output = f"Found {len(results)} libraries:\n\n"
65 for lib in results[:5]: # Top 5
66 output += f"{lib.get('title', 'Unknown')}\n"
67 output += f" ID: {lib.get('id', 'N/A')}\n"
68 if lib.get('description'):
69 output += f" {lib['description']}\n"
70 output += f" Snippets: {lib.get('totalSnippets', 0)}\n"
71 output += f" Trust Score: {lib.get('trustScore', 0)}\n"
72 if lib.get('versions'):
73 output += f" Versions: {', '.join(lib['versions'][:3])}\n"
74 output += "\n"
75
76 # Suggest using the top result
77 if results:
78 top_lib = results[0]
79 lib_id = top_lib.get('id', '')
80 output += f"To get documentation:\ncontext7_docs({{\"library_id\": \"{lib_id}\", \"topic\": \"your topic\"}})"
81
82 return output
83
84@register_tool(
85 "context7_docs",
86 "Get documentation for a library using its Context7 ID",
87 {"library_id": "string", "topic": "string?", "tokens": "number?"}
88)
89def context7_docs(args):
90 """Get library documentation from Context7"""
91 library_id = args.get("library_id", "")
92 topic = args.get("topic", "")
93 tokens = args.get("tokens", 5000)
94
95 if not library_id:
96 return "error: library_id required (use context7_search first)"
97
98 # Ensure minimum tokens
99 if tokens < 1000:
100 tokens = 1000
101
102 params = {
103 "tokens": tokens,
104 "type": "txt"
105 }
106 if topic:
107 params["topic"] = topic
108
109 result = context7_get(f"/v1{library_id}", params)
110
111 if isinstance(result, dict) and "error" in result:
112 return f"error: {result['error']}"
113
114 if not result or result == "null":
115 return f"No documentation found for {library_id}. Try using context7_search first."
116
117 return result
118