8
8
"""
9
9
10
10
import os
11
+ import sys
12
+ import logging
13
+ import traceback
11
14
from typing import Any , Dict
12
15
13
16
import httpx
14
17
from mcp .server .fastmcp import FastMCP
15
18
16
19
20
+ # Configure logging
21
+ logging .basicConfig (
22
+ level = logging .INFO ,
23
+ format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ,
24
+ handlers = [
25
+ logging .StreamHandler (sys .stderr )
26
+ ]
27
+ )
28
+ logger = logging .getLogger ("scrapegraph_mcp" )
29
+
30
+
17
31
class ScapeGraphClient :
18
32
"""Client for interacting with the ScapeGraph API."""
19
33
@@ -26,12 +40,14 @@ def __init__(self, api_key: str):
26
40
Args:
27
41
api_key: API key for ScapeGraph API
28
42
"""
43
+ logger .info ("Initializing ScapeGraphClient" )
29
44
self .api_key = api_key
30
45
self .headers = {
31
46
"SGAI-APIKEY" : api_key ,
32
47
"Content-Type" : "application/json"
33
48
}
34
49
self .client = httpx .Client (timeout = 60.0 )
50
+ logger .info ("ScapeGraphClient initialized successfully" )
35
51
36
52
def markdownify (self , website_url : str ) -> Dict [str , Any ]:
37
53
"""
@@ -43,18 +59,26 @@ def markdownify(self, website_url: str) -> Dict[str, Any]:
43
59
Returns:
44
60
Dictionary containing the markdown result
45
61
"""
62
+ logger .info (f"Calling markdownify for URL: { website_url } " )
46
63
url = f"{ self .BASE_URL } /markdownify"
47
64
data = {
48
65
"website_url" : website_url
49
66
}
50
67
51
- response = self .client .post (url , headers = self .headers , json = data )
52
-
53
- if response .status_code != 200 :
54
- error_msg = f"Error { response .status_code } : { response .text } "
55
- raise Exception (error_msg )
56
-
57
- return response .json ()
68
+ try :
69
+ logger .debug (f"Making POST request to { url } " )
70
+ response = self .client .post (url , headers = self .headers , json = data )
71
+
72
+ if response .status_code != 200 :
73
+ error_msg = f"Error { response .status_code } : { response .text } "
74
+ logger .error (f"API request failed: { error_msg } " )
75
+ raise Exception (error_msg )
76
+
77
+ logger .info ("markdownify request successful" )
78
+ return response .json ()
79
+ except Exception as e :
80
+ logger .error (f"Exception in markdownify: { str (e )} " )
81
+ raise
58
82
59
83
def smartscraper (self , user_prompt : str , website_url : str ) -> Dict [str , Any ]:
60
84
"""
@@ -67,19 +91,27 @@ def smartscraper(self, user_prompt: str, website_url: str) -> Dict[str, Any]:
67
91
Returns:
68
92
Dictionary containing the extracted data
69
93
"""
94
+ logger .info (f"Calling smartscraper for URL: { website_url } with prompt: { user_prompt } " )
70
95
url = f"{ self .BASE_URL } /smartscraper"
71
96
data = {
72
97
"user_prompt" : user_prompt ,
73
98
"website_url" : website_url
74
99
}
75
100
76
- response = self .client .post (url , headers = self .headers , json = data )
77
-
78
- if response .status_code != 200 :
79
- error_msg = f"Error { response .status_code } : { response .text } "
80
- raise Exception (error_msg )
81
-
82
- return response .json ()
101
+ try :
102
+ logger .debug (f"Making POST request to { url } " )
103
+ response = self .client .post (url , headers = self .headers , json = data )
104
+
105
+ if response .status_code != 200 :
106
+ error_msg = f"Error { response .status_code } : { response .text } "
107
+ logger .error (f"API request failed: { error_msg } " )
108
+ raise Exception (error_msg )
109
+
110
+ logger .info ("smartscraper request successful" )
111
+ return response .json ()
112
+ except Exception as e :
113
+ logger .error (f"Exception in smartscraper: { str (e )} " )
114
+ raise
83
115
84
116
def searchscraper (self , user_prompt : str ) -> Dict [str , Any ]:
85
117
"""
@@ -91,30 +123,57 @@ def searchscraper(self, user_prompt: str) -> Dict[str, Any]:
91
123
Returns:
92
124
Dictionary containing search results and reference URLs
93
125
"""
126
+ logger .info (f"Calling searchscraper with prompt: { user_prompt } " )
94
127
url = f"{ self .BASE_URL } /searchscraper"
95
128
data = {
96
129
"user_prompt" : user_prompt
97
130
}
98
131
99
- response = self .client .post (url , headers = self .headers , json = data )
100
-
101
- if response .status_code != 200 :
102
- error_msg = f"Error { response .status_code } : { response .text } "
103
- raise Exception (error_msg )
104
-
105
- return response .json ()
132
+ try :
133
+ logger .debug (f"Making POST request to { url } " )
134
+ response = self .client .post (url , headers = self .headers , json = data )
135
+
136
+ if response .status_code != 200 :
137
+ error_msg = f"Error { response .status_code } : { response .text } "
138
+ logger .error (f"API request failed: { error_msg } " )
139
+ raise Exception (error_msg )
140
+
141
+ logger .info ("searchscraper request successful" )
142
+ return response .json ()
143
+ except Exception as e :
144
+ logger .error (f"Exception in searchscraper: { str (e )} " )
145
+ raise
106
146
107
147
def close (self ) -> None :
108
148
"""Close the HTTP client."""
149
+ logger .info ("Closing ScapeGraphClient" )
109
150
self .client .close ()
151
+ logger .info ("ScapeGraphClient closed" )
152
+
110
153
154
+ # Log environment information
155
+ logger .info (f"Python version: { sys .version } " )
156
+ logger .info (f"Current working directory: { os .getcwd ()} " )
157
+ logger .info (f"PATH environment variable: { os .environ .get ('PATH' , 'Not set' )} " )
111
158
112
159
# Create MCP server
160
+ logger .info ("Creating MCP server" )
113
161
mcp = FastMCP ("ScapeGraph API MCP Server" )
162
+ logger .info ("MCP server created" )
114
163
115
164
# Default API key (will be overridden in main or by direct assignment)
116
165
default_api_key = os .environ .get ("SGAI_API_KEY" )
117
- scrapegraph_client = ScapeGraphClient (default_api_key ) if default_api_key else None
166
+ logger .info (f"SGAI_API_KEY environment variable is { 'set' if default_api_key else 'not set' } " )
167
+
168
+ scrapegraph_client = None
169
+ if default_api_key :
170
+ try :
171
+ logger .info ("Initializing ScapeGraphClient with default API key" )
172
+ scrapegraph_client = ScapeGraphClient (default_api_key )
173
+ logger .info ("ScapeGraphClient initialized successfully" )
174
+ except Exception as e :
175
+ logger .error (f"Failed to initialize ScapeGraphClient: { str (e )} " )
176
+ logger .error (traceback .format_exc ())
118
177
119
178
120
179
# Add tool for markdownify
@@ -129,12 +188,19 @@ def markdownify(website_url: str) -> Dict[str, Any]:
129
188
Returns:
130
189
Dictionary containing the markdown result
131
190
"""
191
+ logger .info (f"Tool markdownify called with URL: { website_url } " )
192
+
132
193
if scrapegraph_client is None :
194
+ logger .warning ("ScapeGraph client not initialized" )
133
195
return {"error" : "ScapeGraph client not initialized. Please provide an API key." }
134
196
135
197
try :
136
- return scrapegraph_client .markdownify (website_url )
198
+ result = scrapegraph_client .markdownify (website_url )
199
+ logger .info ("markdownify tool call successful" )
200
+ return result
137
201
except Exception as e :
202
+ logger .error (f"Error in markdownify tool: { str (e )} " )
203
+ logger .error (traceback .format_exc ())
138
204
return {"error" : str (e )}
139
205
140
206
@@ -154,12 +220,19 @@ def smartscraper(
154
220
Returns:
155
221
Dictionary containing the extracted data
156
222
"""
223
+ logger .info (f"Tool smartscraper called with URL: { website_url } and prompt: { user_prompt } " )
224
+
157
225
if scrapegraph_client is None :
226
+ logger .warning ("ScapeGraph client not initialized" )
158
227
return {"error" : "ScapeGraph client not initialized. Please provide an API key." }
159
228
160
229
try :
161
- return scrapegraph_client .smartscraper (user_prompt , website_url )
230
+ result = scrapegraph_client .smartscraper (user_prompt , website_url )
231
+ logger .info ("smartscraper tool call successful" )
232
+ return result
162
233
except Exception as e :
234
+ logger .error (f"Error in smartscraper tool: { str (e )} " )
235
+ logger .error (traceback .format_exc ())
163
236
return {"error" : str (e )}
164
237
165
238
@@ -177,20 +250,40 @@ def searchscraper(
177
250
Returns:
178
251
Dictionary containing search results and reference URLs
179
252
"""
253
+ logger .info (f"Tool searchscraper called with prompt: { user_prompt } " )
254
+
180
255
if scrapegraph_client is None :
256
+ logger .warning ("ScapeGraph client not initialized" )
181
257
return {"error" : "ScapeGraph client not initialized. Please provide an API key." }
182
258
183
259
try :
184
- return scrapegraph_client .searchscraper (user_prompt )
260
+ result = scrapegraph_client .searchscraper (user_prompt )
261
+ logger .info ("searchscraper tool call successful" )
262
+ return result
185
263
except Exception as e :
264
+ logger .error (f"Error in searchscraper tool: { str (e )} " )
265
+ logger .error (traceback .format_exc ())
186
266
return {"error" : str (e )}
187
267
188
268
189
269
def main () -> None :
190
270
"""Run the ScapeGraph MCP server."""
191
- print ("Starting ScapeGraph MCP server!" )
192
- # Run the server
193
- mcp .run (transport = "stdio" )
271
+ try :
272
+ logger .info ("Starting ScapeGraph MCP server!" )
273
+ print ("Starting ScapeGraph MCP server!" , file = sys .stderr )
274
+
275
+ # Log system information
276
+ logger .info (f"Python executable: { sys .executable } " )
277
+ logger .info (f"Arguments: { sys .argv } " )
278
+
279
+ # Run the server
280
+ logger .info ("Running MCP server with stdio transport" )
281
+ mcp .run (transport = "stdio" )
282
+ except Exception as e :
283
+ logger .critical (f"Fatal error in main: { str (e )} " )
284
+ logger .critical (traceback .format_exc ())
285
+ print (f"Fatal error: { str (e )} " , file = sys .stderr )
286
+ sys .exit (1 )
194
287
195
288
196
289
if __name__ == "__main__" :
0 commit comments