4881eeb7de
- claude_stream_go_core: lanza claude -p --output-format stream-json --verbose, decodifica NDJSON y emite eventos sinteticos (text_delta, tool_use, tool_result, result, error) por canal Go. 10 tests con fake claude bash. - mcp_server_stdio_go_infra: scaffold de MCP server JSON-RPC 2.0 sobre stdio (initialize, tools/list, tools/call, ping). Usuario registra tool defs y handler unico. 9 tests. Usadas por apps/kanban backend para reemplazar el chat HTTP one-shot con XML actions por WebSocket streaming + tool-use nativa. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.9 KiB
4.9 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path, params, output
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | tested | tests | test_file_path | file_path | params | output | |||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| mcp_server_stdio | function | go | infra | 1.0.0 | impure | func ServeMCP(ctx context.Context, opts MCPServerOpts) error | Ejecuta un servidor MCP (Model Context Protocol) sobre stdio implementando JSON-RPC 2.0. Lee de opts.In linea a linea, despacha initialize/tools/list/tools/call/ping al handler del usuario, y escribe respuestas a opts.Out. Retorna nil al cerrar stdin o al cancelar ctx. |
|
false | error_go_core |
|
true |
|
functions/infra/mcp_server_stdio_test.go | functions/infra/mcp_server_stdio.go |
|
nil cuando stdin se cierra o ctx se cancela. Error si ocurre un fallo irrecuperable de escritura en Out. |
Ejemplo
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"fn-registry/functions/infra"
)
func main() {
tools := []infra.MCPToolDef{
{
Name: "echo",
Description: "Echoes the input message back",
InputSchema: json.RawMessage(`{
"type": "object",
"properties": {
"msg": {"type": "string", "description": "message to echo"}
},
"required": ["msg"]
}`),
},
}
handler := func(ctx context.Context, name string, input json.RawMessage) (any, bool, error) {
switch name {
case "echo":
var args struct{ Msg string `json:"msg"` }
if err := json.Unmarshal(input, &args); err != nil {
return nil, false, err
}
return map[string]string{"result": args.Msg}, false, nil
default:
return nil, true, fmt.Errorf("unknown tool: %s", name)
}
}
err := infra.ServeMCP(context.Background(), infra.MCPServerOpts{
Name: "my-app-mcp",
Version: "1.0.0",
Tools: tools,
Handler: handler,
Logger: os.Stderr,
})
if err != nil {
fmt.Fprintln(os.Stderr, "mcp error:", err)
os.Exit(1)
}
}
Para usar como MCP server en Claude Desktop / claude -p, registrar el binario en .mcp.json:
{
"mcpServers": {
"my-app": {
"command": "/path/to/my-app-binary",
"args": ["--mcp"]
}
}
}
El binario detecta --mcp y llama ServeMCP en lugar del modo interactivo normal.
Notas
Protocolo soportado: MCP 2024-11-05, subset minimo suficiente para exponer tools a claude -p y Claude Desktop.
Metodos implementados:
initialize— handshake inicial; responde con protocolVersion, capabilities y serverInfo.initialized— notification enviada por el cliente tras el handshake; se ignora sin respuesta.tools/list— devuelve la lista de tools registradas.tools/call— invoca el Handler. Si handler.err != nil → JSON-RPC error -32603. Si isError=true → result.isError=true (error logico de la tool, no error de protocolo).ping— responde con{}.- Cualquier otro metodo → JSON-RPC error -32601 (method not found).
- Notifications (mensajes sin campo
id) → nunca se responden, ni siquiera con error.
Buffer del scanner: 4 MB para admitir schemas JSON grandes o resultados voluminosos.
Concurrencia: el bucle es secuencial hoy; los writes estan protegidos por mutex para que sea seguro si en el futuro se paraleliza el dispatch del handler.
Distincion notification vs request: la presencia del campo id en el JSON crudo (incluso si es null) indica request. La ausencia indica notification. Esto sigue la spec JSON-RPC 2.0.