MCPcopy Index your code
hub / github.com/github/github-mcp-server / executeServerCommand

Function executeServerCommand

cmd/mcpcurl/main.go:381–454  ·  view source on GitHub ↗

executeServerCommand runs the specified command, performs the MCP initialization handshake, sends the JSON request to stdin, and returns the response from stdout.

(cmdStr, jsonRequest string)

Source from the content-addressed store, hash-verified

379// executeServerCommand runs the specified command, performs the MCP initialization
380// handshake, sends the JSON request to stdin, and returns the response from stdout.
381func executeServerCommand(cmdStr, jsonRequest string) (string, error) {
382 // Split the command string into command and arguments
383 cmdParts := strings.Fields(cmdStr)
384 if len(cmdParts) == 0 {
385 return "", fmt.Errorf("empty command")
386 }
387
388 cmd := exec.Command(cmdParts[0], cmdParts[1:]...) //nolint:gosec //mcpcurl is a test command that needs to execute arbitrary shell commands
389
390 // Setup stdin pipe
391 stdin, err := cmd.StdinPipe()
392 if err != nil {
393 return "", fmt.Errorf("failed to create stdin pipe: %w", err)
394 }
395
396 // Setup stdout pipe for line-by-line reading
397 stdoutPipe, err := cmd.StdoutPipe()
398 if err != nil {
399 return "", fmt.Errorf("failed to create stdout pipe: %w", err)
400 }
401
402 // Stderr still uses a buffer
403 var stderr strings.Builder
404 cmd.Stderr = &stderr
405
406 // Start the command
407 if err := cmd.Start(); err != nil {
408 return "", fmt.Errorf("failed to start command: %w", err)
409 }
410
411 // Ensure the child process is cleaned up on every return path.
412 // stdin must be closed before Wait so the server sees EOF and exits;
413 // its non-zero exit status on EOF is expected, so we ignore the error.
414 defer func() {
415 _ = stdin.Close()
416 _ = cmd.Wait()
417 }()
418
419 // Use a scanner with a large buffer for reading JSON-RPC responses
420 scanner := bufio.NewScanner(stdoutPipe)
421 scanner.Buffer(make([]byte, 0, 1024*1024), 1024*1024) // 1MB max line size
422
423 // Step 1: Send MCP initialize request
424 initReq, err := buildInitializeRequest()
425 if err != nil {
426 return "", fmt.Errorf("failed to build initialize request: %w", err)
427 }
428 if _, err := io.WriteString(stdin, initReq+"\n"); err != nil {
429 return "", fmt.Errorf("failed to write initialize request: %w", err)
430 }
431
432 // Step 2: Read initialize response (skip any server notifications)
433 if _, err := readJSONRPCResponse(scanner); err != nil {
434 return "", fmt.Errorf("failed to read initialize response: %w, stderr: %s", err, stderr.String())
435 }
436
437 // Step 3: Send initialized notification
438 if _, err := io.WriteString(stdin, buildInitializedNotification()+"\n"); err != nil {

Callers 3

main.goFile · 0.85
mainFunction · 0.85
addCommandFromToolFunction · 0.85

Calls 6

buildInitializeRequestFunction · 0.85
readJSONRPCResponseFunction · 0.85
StartMethod · 0.80
CloseMethod · 0.80
StringMethod · 0.45

Tested by

no test coverage detected