mcp: whether MaxLineLength rejects a message depends on how the stream is read
Los mantenedores suelen responder en 1 día
@Tangerg ya está trabajando en esto.
Desde el 6/11/2026.
Evaluación
Este issue todavía no se ha evaluado.
Descripción
Checklist
- I searched the existing issues, and this has not been reported before.
- This is a real problem that I ran into myself, using the latest release of the SDK.
- I ran into it in a production system, not in a toy example, a benchmark, or an automated or AI-driven scan of the code.
- I (a human) examined the relevant SDK code, and wrote or reviewed every line of this report. It is not unreviewed AI output.
- This report is brief and concise, and sticks to the facts needed to understand the problem.
What happened?
Whether MaxLineLength rejects an inbound message on IOTransport, StdioTransport or CommandTransport depends on how the reader splits the stream. In the program below, with a cap of 128 bytes, the same 153-byte message is accepted when the stream arrives in one read and rejected when it arrives one byte at a time.
frameLimitReader resets its count after each message, but json.Decoder reads ahead. Bytes of the next message that the decoder read while finishing the previous one are counted toward the previous one and then forgotten, so the next message can exceed the cap by that many bytes.
Expected: whether a message fits depends only on the message.
I'd like to fix this myself, by starting each message's count at the decoder's InputOffset instead of resetting it, so that bytes read ahead count toward the message they belong to.
AI assistance: the investigation was done with Claude; I reviewed the report and the SDK code.
How to reproduce
package main
import (
"context"
"fmt"
"io"
"strings"
"testing/iotest"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
type nopCloser struct{ io.Writer }
func (nopCloser) Close() error { return nil }
func main() {
// With MaxLineLength 128, the second message (153 bytes) should be rejected.
stream := `{"jsonrpc":"2.0","method":"first"}` + "\n" +
`{"jsonrpc":"2.0","method":"second","params":{"p":"` + strings.Repeat("x", 100) + `"}}` + "\n"
for _, r := range []struct {
name string
r io.Reader
}{
{"whole stream per read", strings.NewReader(stream)},
{"one byte per read", iotest.OneByteReader(strings.NewReader(stream))},
} {
t := &mcp.IOTransport{Reader: io.NopCloser(r.r), Writer: nopCloser{io.Discard}, MaxLineLength: 128}
conn, err := t.Connect(context.Background())
if err != nil {
panic(err)
}
if _, err := conn.Read(context.Background()); err != nil {
panic(err)
}
_, err = conn.Read(context.Background())
fmt.Printf("%s: second message: %v\n", r.name, err)
}
}
Output with v1.8.0:
whole stream per read: second message: <nil>
one byte per read: second message: inbound JSON-RPC frame exceeded the configured maximum line length
Where did you hit this?
Flame's plugin runtime talks MCP to plugin processes over pipes with IOTransport, setting MaxLineLength to its process protocol's frame budget; Frame, the plugin framework under it, sets MaxLineLength to -1 and admits whole frames in its own reader instead.
Go MCP SDK version
v1.8.0 (also on main at 449d945)
Go version
go version go1.27.3 darwin/arm64
Logs
No response
- Lenguaje dominante
- Go
- Estrellas
- 5.3k
- Forks
- 607
- Merge medio
- 1 d 11 h
- PR fusionados (30 d)
- 82
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de modelcontextprotocol/go-sdk
-
Expose generic `SendNotification` on `ServerSession` for custom protocol extensionsQuizá libre de nuevo Un pull request para esta issue se cerró sin fusionarse. Abiertoneeds investigation
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
modelcontextprotocol/go-sdk#745 · 13 comentarios · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Dificultad 3/5 1-2 días Aptitud para principiantes 62/100
modelcontextprotocol/go-sdk#1506 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
mcp: closing a session right after a cancelled call drops notifications/cancelled, so the server handler keeps runningPosiblemente ocupada @vshalpnjabi la tomó hoy. Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
modelcontextprotocol/go-sdk#1505 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
mcp: a canceled write on IOTransport/StdioTransport cannot leave the write queuePosiblemente ocupada @Tangerg la tomó hace 1 día. Abierto
modelcontextprotocol/go-sdk#1498 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
mcp: list_changed can only be broadcast; a server cannot notify one session (2026-07-28 subscriptions/listen)Posiblemente ocupada @huynle-dev la tomó hace 4 días. Abierto
Dificultad 4/5 1-2 días Aptitud para principiantes 32/100
modelcontextprotocol/go-sdk#1480 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 1 día
Todos los issues de modelcontextprotocol/go-sdk
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
adrianbrad/queue#92 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
agent-ready area:skills
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
jmbarzee/temporal-architect#444 ·
Los mantenedores suelen responder en 1 día
-
enhancement needs:sonnet ready-for-agent
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día