@@ -119,15 +119,29 @@ def get_table_info(table):
119
119
120
120
@mcp .tool ()
121
121
def run_sql (query : str ):
122
+ """Run a query in a Timeplus database"""
122
123
logger .info (f"Executing query: { query } " )
123
- future = QUERY_EXECUTOR .submit (execute_query , query )
124
124
try :
125
- result = future .result (timeout = SELECT_QUERY_TIMEOUT_SECS )
126
- return result
127
- except concurrent .futures .TimeoutError :
128
- logger .warning (f"Query timed out after { SELECT_QUERY_TIMEOUT_SECS } seconds: { query } " )
129
- future .cancel ()
130
- return f"Queries taking longer than { SELECT_QUERY_TIMEOUT_SECS } seconds are currently not supported."
125
+ future = QUERY_EXECUTOR .submit (execute_query , query )
126
+ try :
127
+ result = future .result (timeout = SELECT_QUERY_TIMEOUT_SECS )
128
+ # Check if we received an error structure from execute_query
129
+ if isinstance (result , dict ) and "error" in result :
130
+ logger .warning (f"Query failed: { result ['error' ]} " )
131
+ # MCP requires structured responses; string error messages can cause
132
+ # serialization issues leading to BrokenResourceError
133
+ return {"status" : "error" , "message" : f"Query failed: { result ['error' ]} " }
134
+ return result
135
+ except concurrent .futures .TimeoutError :
136
+ logger .warning (f"Query timed out after { SELECT_QUERY_TIMEOUT_SECS } seconds: { query } " )
137
+ future .cancel ()
138
+ # Return a properly structured response for timeout errors
139
+ return {"status" : "error" , "message" : f"Query timed out after { SELECT_QUERY_TIMEOUT_SECS } seconds" }
140
+ except Exception as e :
141
+ logger .error (f"Unexpected error in run_select_query: { str (e )} " )
142
+ # Catch all other exceptions and return them in a structured format
143
+ # to prevent MCP serialization failures
144
+ return {"status" : "error" , "message" : f"Unexpected error: { str (e )} " }
131
145
132
146
client = create_timeplus_client ()
133
147
try :
@@ -144,7 +158,9 @@ def run_sql(query: str):
144
158
return rows
145
159
except Exception as err :
146
160
logger .error (f"Error executing query: { err } " )
147
- return f"error running query: { err } "
161
+ # Return a structured dictionary rather than a string to ensure proper serialization
162
+ # by the MCP protocol. String responses for errors can cause BrokenResourceError.
163
+ return {"error" : str (err )}
148
164
149
165
@mcp .prompt ()
150
166
def generate_sql (requirements : str ) -> str :
0 commit comments