feat: implement logging/setLevel and silence STDIO

- Add `logging/setLevel` JSON-RPC method
- Define `LogLevel` enum and `SetLevelParams` struct
- Silence startup messages in STDIO transport
- Suppress console logging during STDIO JSON-RPC errors
This commit is contained in:
Mahmoud-Emad
2025-09-14 14:13:21 +03:00
parent 5914ee766f
commit b90a118e4e
6 changed files with 57 additions and 12 deletions

Binary file not shown.

View File

@@ -177,11 +177,9 @@ fn main() {
println(' Use JSON-RPC endpoint: http://localhost:${port}/jsonrpc')
println('')
} else {
println('📟 MCP Inspector Server - STDIO Mode')
println('====================================')
println('Ready for JSON-RPC messages on stdin...')
println('')
println('💡 Tip: Run with --http --port 9000 for HTTP mode')
// In STDIO mode, we should be completely silent to avoid interfering with JSON-RPC communication
// The MCP Inspector captures both stdout and stderr, so any output can cause parsing errors
// If you need to see startup messages, run with --http mode instead
}
server.start()!

View File

@@ -87,6 +87,14 @@ fn create_tools_call_wrapper(mut server Server) jsonrpc.ProcedureHandler {
}
}
fn create_logging_set_level_wrapper(mut server Server) jsonrpc.ProcedureHandler {
return fn [mut server] (request jsonrpc.Request) !jsonrpc.Response {
original_json := '{"jsonrpc":"${request.jsonrpc}","method":"${request.method}","params":${request.params},"id":${request.id}}'
response_str := server.logging_set_level_handler(original_json)!
return jsonrpc.decode_response(response_str)!
}
}
@[params]
pub struct ServerParams {
pub:
@@ -122,6 +130,8 @@ pub fn new_server(backend Backend, params ServerParams) !&Server {
// Core handlers
'initialize': create_initialize_wrapper(mut server)
'notifications/initialized': create_initialized_notification_wrapper()
// Logging handlers
'logging/setLevel': create_logging_set_level_wrapper(mut server)
// Resource handlers
'resources/list': create_resources_list_wrapper(mut server)
'resources/read': create_resources_read_wrapper(mut server)

37
lib/mcp/handler_logging.v Normal file
View File

@@ -0,0 +1,37 @@
module mcp
import x.json2
import freeflowuniverse.herolib.schemas.jsonrpc
// LogLevel represents the logging levels supported by MCP
pub enum LogLevel {
debug
info
notice
warning
error
critical
alert
emergency
}
// SetLevelParams represents the parameters for the logging/setLevel method
pub struct SetLevelParams {
pub:
level LogLevel
}
// logging_set_level_handler handles the logging/setLevel request
// This is a stub implementation that accepts the request but doesn't actually change logging behavior
fn (mut s Server) logging_set_level_handler(data string) !string {
// Decode the request with SetLevelParams
request := jsonrpc.decode_request_generic[SetLevelParams](data)!
// For now, we just acknowledge the request without actually implementing logging level changes
// In a full implementation, this would configure the server's logging system
// Create a success response with empty object (logging/setLevel returns {} on success)
empty_map := map[string]string{}
response := jsonrpc.new_response_generic[map[string]string](request.id, empty_map)
return response.encode()
}

View File

@@ -17,7 +17,7 @@ pub mut:
// start starts the MCP server using the configured transport
pub fn (mut s Server) start() ! {
log.info('Starting MCP server')
// Note: Removed log.info() as it interferes with STDIO transport JSON-RPC communication
s.transport.start(&s.handler)!
}

View File

@@ -25,7 +25,8 @@ pub fn (mut t StdioTransport) start(handler &jsonrpc.Handler) ! {
unsafe {
t.handler = handler
}
console.print_debug('Starting MCP server with STDIO transport')
// Note: In STDIO mode, we should not print any debug messages to stdout
// as it interferes with JSON-RPC communication
for {
// Read a message from stdin
@@ -37,23 +38,22 @@ pub fn (mut t StdioTransport) start(handler &jsonrpc.Handler) ! {
// Parse the JSON-RPC request
request := jsonrpc.decode_request(message) or {
console.print_stderr('Invalid JSON-RPC request: ${err}')
// Note: Removed stderr logging as it can interfere with MCP Inspector
// Try to extract the request ID for error response
id := jsonrpc.decode_request_id(message) or { 0 }
// Create an invalid request error response
error_response := jsonrpc.new_error(id, jsonrpc.invalid_request).encode()
print(error_response)
println(error_response)
continue
}
// Handle the message using the JSON-RPC handler
response := t.handler.handle(request) or {
console.print_stderr('message: ${message}')
console.print_stderr('Error handling message: ${err}')
// Note: Removed stderr logging as it can interfere with MCP Inspector
// Create an internal error response
error_response := jsonrpc.new_error(request.id, jsonrpc.internal_error).encode()
console.print_debug(error_response)
println(error_response)
continue
}