@ -33,28 +33,10 @@ from datetime import datetime
import httpx
# DON'T redirect stderr - it may interfere with stdout/stdin pipes
# Commented out to test if this is causing the issue
# LOG_FILE = "/tmp/proxysql_mcp_bridge.log"
# stderr_log_file = open(LOG_FILE, "a", buffering=1)
# sys.stderr = stderr_log_file
# sys.__stderr__ = stderr_log_file
# Debug logging - write to file instead of stderr to avoid pipe interference
LOG_FILE = " /tmp/proxysql_mcp_bridge.log "
_log_file = open ( LOG_FILE , " a " , buffering = 1 )
def log_timestamp ( ) :
return datetime . now ( ) . strftime ( " % Y- % m- %d % H: % M: % S. %f " ) [ : - 3 ]
def debug_log ( msg : str ) :
""" Write to log file instead of stderr. """
timestamp = log_timestamp ( )
_log_file . write ( f " [ { timestamp } ] { msg } \n " )
_log_file . flush ( )
def log_separator ( char = " = " , length = 80 ) :
_log_file . write ( char * length + " \n " )
# Minimal logging to file for debugging
_log_file = open ( " /tmp/proxysql_mcp_bridge.log " , " a " , buffering = 1 )
def _log ( msg ) :
_log_file . write ( f " [ { datetime . now ( ) . strftime ( ' % H: % M: % S. %f ' ) [ : - 3 ] } ] { msg } \n " )
_log_file . flush ( )
@ -83,10 +65,6 @@ class ProxySQLMCPEndpoint:
async def _initialize ( self ) :
""" Initialize the MCP connection. """
log_separator ( " = " )
debug_log ( " [ProxySQLMCPEndpoint] Initializing connection to ProxySQL MCP server " )
log_separator ( " = " )
request = {
" jsonrpc " : " 2.0 " ,
" id " : 1 ,
@ -102,10 +80,6 @@ class ProxySQLMCPEndpoint:
}
response = await self . _call ( request )
self . _initialized = True
log_separator ( " = " )
debug_log ( " [ProxySQLMCPEndpoint] Initialization complete " )
log_separator ( " = " )
return response
async def _call ( self , request : Dict [ str , Any ] ) - > Dict [ str , Any ] :
@ -117,28 +91,12 @@ class ProxySQLMCPEndpoint:
if self . auth_token :
headers [ " Authorization " ] = f " Bearer { self . auth_token } "
log_separator ( " - " )
debug_log ( f " [HTTP REQUEST TO PROXYSQL MCP SERVER] " )
debug_log ( f " URL: { self . endpoint } " )
debug_log ( f " Headers: { json . dumps ( headers ) } " )
debug_log ( f " Body: { json . dumps ( request , indent = 2 ) } " )
log_separator ( " - " )
try :
r = await self . _client . post ( self . endpoint , json = request , headers = headers )
r . raise_for_status ( )
response = r . json ( )
log_separator ( " - " )
debug_log ( f " [HTTP RESPONSE FROM PROXYSQL MCP SERVER] " )
debug_log ( f " Status: { r . status_code } " )
debug_log ( f " Headers: { dict ( r . headers ) } " )
debug_log ( f " Body: { json . dumps ( response , indent = 2 ) } " )
log_separator ( " - " )
return response
return r . json ( )
except httpx . HTTPStatusError as e :
error_resp = {
return {
" jsonrpc " : " 2.0 " ,
" error " : {
" code " : - 32000 ,
@ -147,15 +105,8 @@ class ProxySQLMCPEndpoint:
} ,
" id " : request . get ( " id " , " " )
}
log_separator ( " - " )
debug_log ( f " [HTTP ERROR FROM PROXYSQL MCP SERVER] " )
debug_log ( f " Status: { e . response . status_code } " )
debug_log ( f " Response: { e . response . text } " )
debug_log ( f " Error Response: { json . dumps ( error_resp , indent = 2 ) } " )
log_separator ( " - " )
return error_resp
except Exception as e :
error_resp = {
return {
" jsonrpc " : " 2.0 " ,
" error " : {
" code " : - 32603 ,
@ -163,12 +114,6 @@ class ProxySQLMCPEndpoint:
} ,
" id " : request . get ( " id " , " " )
}
log_separator ( " - " )
debug_log ( f " [EXCEPTION DURING HTTP REQUEST] " )
debug_log ( f " Exception: { type ( e ) . __name__ } : { e } " )
debug_log ( f " Error Response: { json . dumps ( error_resp , indent = 2 ) } " )
log_separator ( " - " )
return error_resp
async def tools_list ( self ) - > Dict [ str , Any ] :
""" List available tools. """
@ -206,13 +151,6 @@ class StdioMCPServer:
async def run ( self ) :
""" Main server loop. """
log_separator ( " = " )
debug_log ( " [PROXYSQL MCP STDIO BRIDGE STARTING] " )
debug_log ( f " Endpoint: { self . proxysql_endpoint } " )
debug_log ( f " Auth Token: { ' ***SET*** ' if self . auth_token else ' NONE ' } " )
debug_log ( f " Verify SSL: { self . verify_ssl } " )
log_separator ( " = " )
async with ProxySQLMCPEndpoint ( self . proxysql_endpoint , self . auth_token , self . verify_ssl ) as client :
self . _proxysql = client
@ -220,47 +158,21 @@ class StdioMCPServer:
await self . _write_notification ( " notifications/initialized " )
# Main message loop
msg_count = 0
while True :
try :
line = await self . _readline ( )
if not line :
debug_log ( " [STDIN CLOSED - RECEIVED EOF] " )
break
msg_count + = 1
log_separator ( " = " )
debug_log ( f " [MESSAGE # { msg_count } - RECEIVED FROM STDIN] " )
debug_log ( f " Raw line: { repr ( line ) } " )
debug_log ( f " Parsed JSON: " )
try :
message = json . loads ( line )
debug_log ( f " { json . dumps ( message , indent = 4 ) } " )
except json . JSONDecodeError as e :
debug_log ( f " [INVALID JSON - { e } ] " )
raise
log_separator ( " = " )
message = json . loads ( line )
response = await self . _handle_message ( message )
if response :
log_separator ( " = " )
debug_log ( f " [MESSAGE # { msg_count } - SENDING TO STDOUT] " )
debug_log ( f " Response JSON: " )
debug_log ( f " { json . dumps ( response , indent = 4 ) } " )
log_separator ( " = " )
await self . _writeline ( response )
else :
debug_log ( f " [MESSAGE # { msg_count } - NO RESPONSE (notification only)] " )
except json . JSONDecodeError as e :
debug_log ( f " [JSON DECODE ERROR]: { e } " )
debug_log ( f " Invalid line: { repr ( line ) } " )
await self . _write_error ( - 32700 , f " Parse error: { e } " , " " )
except Exception as e :
debug_log ( f " [HANDLER ERROR]: { e } " )
import traceback
traceback . print_exc ( file = sys . stderr )
await self . _write_error ( - 32603 , f " Internal error: { e } " , " " )
async def _readline ( self ) - > Optional [ str ] :
@ -273,20 +185,10 @@ class StdioMCPServer:
async def _writeline ( self , data : Any ) :
""" Write JSON data to stdout. """
output = json . dumps ( data , ensure_ascii = False ) + " \n "
output_bytes = output . encode ( ' utf-8 ' )
debug_log ( f " [_writeline] Writing { len ( output_bytes ) } bytes to stdout " )
debug_log ( f " [_writeline] sys.stdout: { sys . stdout } " )
debug_log ( f " [_writeline] sys.stdout.buffer: { sys . stdout . buffer } " )
# Write directly to the binary buffer to avoid any TextIOWrapper issues
# This bypasses Python's text encoding layer and writes raw bytes
loop = asyncio . get_event_loop ( )
await loop . run_in_executor ( None , sys . stdout . buffer . write , output_bytes )
await loop . run_in_executor ( None , sys . stdout . buffer . flush )
debug_log ( f " [_writeline] Flush complete " )
output = json . dumps ( data , ensure_ascii = False ) + " \n "
await loop . run_in_executor ( None , sys . stdout . write , output )
await loop . run_in_executor ( None , sys . stdout . flush )
async def _write_notification ( self , method : str , params : Optional [ Dict [ str , Any ] ] = None ) :
""" Write a notification (no id). """
@ -296,7 +198,6 @@ class StdioMCPServer:
}
if params :
notification [ " params " ] = params
debug_log ( f " [NOTIFICATION] Sending: { json . dumps ( notification , indent = 4 ) } " )
await self . _writeline ( notification )
async def _write_response ( self , result : Any , req_id : str ) :
@ -326,8 +227,6 @@ class StdioMCPServer:
req_id = message . get ( " id " , " " )
params = message . get ( " params " , { } )
debug_log ( f " [HANDLE MESSAGE] method= ' { method } ' , id= ' { req_id } ' " )
if method == " initialize " :
return await self . _handle_initialize ( req_id , params )
elif method == " tools/list " :
@ -335,19 +234,14 @@ class StdioMCPServer:
elif method == " tools/call " :
return await self . _handle_tools_call ( req_id , params )
elif method == " ping " :
debug_log ( f " [ping] Responding with status=ok " )
return { " jsonrpc " : " 2.0 " , " result " : { " status " : " ok " } , " id " : req_id }
else :
debug_log ( f " [HANDLE MESSAGE] Unknown method: { method } " )
await self . _write_error ( - 32601 , f " Method not found: { method } " , req_id )
return None
async def _handle_initialize ( self , req_id : str , params : Dict [ str , Any ] ) - > Dict [ str , Any ] :
""" Handle initialize request. """
debug_log ( f " [initialize] Handling request with id= { req_id } " )
debug_log ( f " [initialize] Client params: { json . dumps ( params , indent = 4 ) } " )
result = {
return {
" jsonrpc " : " 2.0 " ,
" result " : {
" protocolVersion " : " 2024-11-05 " ,
@ -361,8 +255,6 @@ class StdioMCPServer:
} ,
" id " : req_id
}
debug_log ( f " [initialize] Sending response: { json . dumps ( result [ ' result ' ] , indent = 4 ) } " )
return result
async def _handle_tools_list ( self , req_id : str ) - > Dict [ str , Any ] :
""" Handle tools/list request - forward to ProxySQL. """
@ -375,6 +267,8 @@ class StdioMCPServer:
response = await self . _proxysql . tools_list ( )
# The response from ProxySQL is the full JSON-RPC response
# We need to extract the result and return it in our format
if " error " in response :
return {
" jsonrpc " : " 2.0 " ,
@ -400,20 +294,15 @@ class StdioMCPServer:
name = params . get ( " name " , " " )
arguments = params . get ( " arguments " , { } )
debug_log ( f " [tools/call] Calling tool= ' { name } ' with args: { json . dumps ( arguments ) } " )
response = await self . _proxysql . tools_call ( name , arguments , req_id )
if " error " in response :
debug_log ( f " [tools/call] Error from ProxySQL: { response [ ' error ' ] } " )
return {
" jsonrpc " : " 2.0 " ,
" error " : response [ " error " ] ,
" id " : req_id
}
# Simply pass through the result - no wrapping, no unwrapping
debug_log ( f " [tools/call] Returning result: { json . dumps ( response . get ( ' result ' , { } ) ) } " )
return {
" jsonrpc " : " 2.0 " ,
" result " : response . get ( " result " , { } ) ,
@ -422,21 +311,11 @@ class StdioMCPServer:
async def main ( ) :
log_separator ( " = " )
debug_log ( " [PROXYSQL MCP STDIO BRIDGE - MAIN STARTING] " )
log_separator ( " = " )
# Get configuration from environment
endpoint = os . getenv ( " PROXYSQL_MCP_ENDPOINT " , " https://127.0.0.1:6071/mcp/query " )
token = os . getenv ( " PROXYSQL_MCP_TOKEN " , " " )
insecure_ssl = os . getenv ( " PROXYSQL_MCP_INSECURE_SSL " , " 0 " ) . lower ( ) in ( " 1 " , " true " , " yes " )
debug_log ( f " [CONFIG] PROXYSQL_MCP_ENDPOINT: { endpoint } " )
debug_log ( f " [CONFIG] PROXYSQL_MCP_TOKEN: { ' ***SET*** ' if token else ' NOT SET ' } " )
debug_log ( f " [CONFIG] PROXYSQL_MCP_INSECURE_SSL: { insecure_ssl } " )
debug_log ( f " [CONFIG] LOG_FILE: { LOG_FILE } " )
log_separator ( " = " )
# Validate endpoint
if not endpoint :
sys . stderr . write ( " Error: PROXYSQL_MCP_ENDPOINT environment variable is required \n " )
@ -448,11 +327,9 @@ async def main():
try :
await server . run ( )
except KeyboardInterrupt :
debug_log ( " [MAIN] Interrupted by KeyboardInterrupt " )
pass
except Exception as e :
debug_log ( f " [MAIN] ERROR: { e } " )
import traceback
traceback . print_exc ( file = sys . stderr )
sys . stderr . write ( f " Error: { e } \n " )
sys . exit ( 1 )