diff --git a/examples/mpc/inspector/README.md b/examples/mpc/inspector/README.md index 10b36413..3f831153 100644 --- a/examples/mpc/inspector/README.md +++ b/examples/mpc/inspector/README.md @@ -24,15 +24,33 @@ server.start()! ## Running Example +### Option 1: Using the example script (Recommended) + 1. `bash example.sh` -2. `open localhost:5173` +2. The MCP inspector will open automatically in your browser +3. The inspector should connect automatically to the V server + +### Option 2: Manual configuration + +1. Start the MCP inspector: `npx @modelcontextprotocol/inspector` +2. Open `localhost:5173` in your browser +3. Configure inspector: + - Transport type: `STDIO` + - Command: `` + - Arguments: (leave empty) +4. Click "Connect" + +### Option 3: Using V directly + +1. Start the MCP inspector: `npx @modelcontextprotocol/inspector` +2. Open `localhost:5173` in your browser 3. Configure inspector: - Transport type: `STDIO` - Command: `v` - - Arguments: `-w -n run /Users/timurgordon/code/github/freeflowuniverse/herolib/lib/mcp/v_do/vdo.v` -4. Connect + - Arguments: `run ` +4. Click "Connect" ## Output Expected output: -![Inspector Screenshot](inspector_screenshot.png) \ No newline at end of file +![Inspector Screenshot](inspector_screenshot.png) diff --git a/examples/mpc/inspector/example.sh b/examples/mpc/inspector/example.sh old mode 100644 new mode 100755 index 281d6319..b0799d5b --- a/examples/mpc/inspector/example.sh +++ b/examples/mpc/inspector/example.sh @@ -1,3 +1,11 @@ #!/bin/bash -npx @modelcontextprotocol/inspector node build/index.js \ No newline at end of file +# Get the absolute path to the server.vsh file +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SERVER_PATH="$SCRIPT_DIR/server.vsh" + +# Make sure the server script is executable +chmod +x "$SERVER_PATH" + +# Start the MCP inspector with the V server +npx @modelcontextprotocol/inspector "$SERVER_PATH" \ No newline at end of file diff --git a/examples/mpc/inspector/server b/examples/mpc/inspector/server new file mode 100755 index 00000000..982df9a9 Binary files /dev/null and b/examples/mpc/inspector/server differ diff --git a/examples/mpc/inspector/server.vsh b/examples/mpc/inspector/server.vsh new file mode 100755 index 00000000..5c5e699d --- /dev/null +++ b/examples/mpc/inspector/server.vsh @@ -0,0 +1,120 @@ +#!/usr/bin/env -S v -n -w -cg -d use_openssl -enable-globals run + +import freeflowuniverse.herolib.mcp +import freeflowuniverse.herolib.schemas.jsonrpc +import freeflowuniverse.herolib.schemas.jsonschema +import x.json2 + +// Example custom tool handler function +fn my_custom_handler(arguments map[string]json2.Any) !mcp.ToolCallResult { + return mcp.ToolCallResult{ + is_error: false + content: [ + mcp.ToolContent{ + typ: 'text' + text: 'Hello from custom handler! Arguments: ${arguments}' + }, + ] + } +} + +// Example of calculating 2 numbers +fn calculate(arguments map[string]json2.Any) !mcp.ToolCallResult { + // Check if num1 exists and can be converted to a number + if 'num1' !in arguments { + return mcp.ToolCallResult{ + is_error: true + content: [ + mcp.ToolContent{ + typ: 'text' + text: 'Missing num1 parameter' + }, + ] + } + } + + // Try to get num1 as a number (JSON numbers can be int, i64, or f64) + num1 := arguments['num1'].f64() + + // Check if num2 exists and can be converted to a number + if 'num2' !in arguments { + return mcp.ToolCallResult{ + is_error: true + content: [ + mcp.ToolContent{ + typ: 'text' + text: 'Missing num2 parameter' + }, + ] + } + } + + // Try to get num2 as a number + num2 := arguments['num2'].f64() + + // Calculate the result + result := num1 + num2 + // Return the result + return mcp.ToolCallResult{ + is_error: false + content: [ + mcp.ToolContent{ + typ: 'text' + text: 'Result: ${result} (${num1} + ${num2})' + }, + ] + } +} + +// Create a backend with custom tools and handlers +backend := mcp.MemoryBackend{ + tools: { + 'custom_method': mcp.Tool{ + name: 'custom_method' + description: 'A custom example tool' + input_schema: jsonschema.Schema{ + typ: 'object' + properties: { + 'message': jsonschema.SchemaRef(jsonschema.Schema{ + typ: 'string' + description: 'A message to process' + }) + } + required: ['message'] + } + } + 'calculate': mcp.Tool{ + name: 'calculate' + description: 'Calculates the sum of two numbers' + input_schema: jsonschema.Schema{ + typ: 'object' + properties: { + 'num1': jsonschema.SchemaRef(jsonschema.Schema{ + typ: 'number' + description: 'The first number' + }) + 'num2': jsonschema.SchemaRef(jsonschema.Schema{ + typ: 'number' + description: 'The second number' + }) + } + required: ['num1', 'num2'] + } + } + } + tool_handlers: { + 'custom_method': my_custom_handler + 'calculate': calculate + } +} + +// Create and start the server +mut server := mcp.new_server(backend, mcp.ServerParams{ + config: mcp.ServerConfiguration{ + server_info: mcp.ServerInfo{ + name: 'inspector_example' + version: '1.0.0' + } + } +})! +server.start()! diff --git a/lib/ai/mcp/server.v b/lib/ai/mcp/server.v index c2055f11..247f4252 100644 --- a/lib/ai/mcp/server.v +++ b/lib/ai/mcp/server.v @@ -41,15 +41,16 @@ pub fn (mut s Server) start() ! { continue } - // Send the response - s.send(response) + // Send the response only if it's not empty (notifications return empty responses) + if response.len > 0 { + s.send(response) + } } } // send sends a response to the client pub fn (mut s Server) send(response string) { // Send the response - log.error('Sending response: ${response}') println(response) flush_stdout() } diff --git a/lib/mcp/server.v b/lib/mcp/server.v index c2055f11..247f4252 100644 --- a/lib/mcp/server.v +++ b/lib/mcp/server.v @@ -41,15 +41,16 @@ pub fn (mut s Server) start() ! { continue } - // Send the response - s.send(response) + // Send the response only if it's not empty (notifications return empty responses) + if response.len > 0 { + s.send(response) + } } } // send sends a response to the client pub fn (mut s Server) send(response string) { // Send the response - log.error('Sending response: ${response}') println(response) flush_stdout() } diff --git a/lib/schemas/jsonrpc/handler.v b/lib/schemas/jsonrpc/handler.v index cbcbbd4c..2ea78e82 100644 --- a/lib/schemas/jsonrpc/handler.v +++ b/lib/schemas/jsonrpc/handler.v @@ -68,7 +68,6 @@ pub fn (handler Handler) handler(client &websocket.Client, message string) strin // - The JSON-RPC response as a string, or an error if processing fails pub fn (handler Handler) handle(message string) !string { // Extract the method name from the request - log.error('debugzo1') method := decode_request_method(message)! // log.info('Handling remote procedure call to method: ${method}') // Look up the procedure handler for the requested method @@ -77,8 +76,6 @@ pub fn (handler Handler) handle(message string) !string { return method_not_found } - log.error('debugzo3') - // Execute the procedure handler with the request payload response := procedure_func(message) or { panic(err) } return response