The jsonrpc package provides low-level JSON-RPC v2 message handling utilities for MCP transport authors.
This package exposes core JSON-RPC v2 types and functions for encoding, decoding, and working with JSON-RPC messages. It is primarily used by custom transport implementations.
import "github.com/modelcontextprotocol/go-sdk/jsonrpc"Serializes a JSON-RPC message to its wire format.
func EncodeMessage(msg Message) ([]byte, error)Parameters:
msg: A JSON-RPC message (Request or Response)Returns:
[]byte: Serialized JSON byteserror: Error if serialization failsExample:
import "github.com/modelcontextprotocol/go-sdk/jsonrpc"
// Create a request
req := &jsonrpc.Request{
ID: jsonrpc.ID{Str: "1"},
Method: "tools/call",
Params: map[string]any{
"name": "greet",
"arguments": map[string]any{"name": "Alice"},
},
}
// Encode to wire format
data, err := jsonrpc.EncodeMessage(req)
if err != nil {
log.Fatal(err)
}
// data is now JSON bytes ready to send over the wireDeserializes JSON-RPC wire format data into a Message.
func DecodeMessage(data []byte) (Message, error)Parameters:
data: JSON-encoded message bytesReturns:
Message: Either a Request or Responseerror: Error if deserialization failsExample:
// Receive data from wire
data := []byte(`{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{}}`)
// Decode message
msg, err := jsonrpc.DecodeMessage(data)
if err != nil {
log.Fatal(err)
}
// Check message type
switch m := msg.(type) {
case *jsonrpc.Request:
fmt.Printf("Request: %s\n", m.Method)
case *jsonrpc.Response:
fmt.Printf("Response ID: %v\n", m.ID)
}Base interface for JSON-RPC messages.
type Message interface{}A Message is either a Request or Response.
Represents a JSON-RPC request.
type Request struct {
ID ID
Method string
Params any
}Fields:
ID: Unique identifier for the request (can be string, number, or null)Method: The method name to invokeParams: Method parameters (any JSON-serializable value)Note: The actual jsonrpc.Request type is a type alias to an internal implementation with additional fields. The above represents the logical structure.
Represents a JSON-RPC response.
type Response struct {
ID ID
Result any
Error *ResponseError
}Fields:
ID: Identifier matching the requestResult: Result value (present on success)Error: Error information (present on failure)Note: The actual jsonrpc.Response type is a type alias to an internal implementation. The above represents the logical structure.
Type representing a JSON-RPC request ID.
type ID struct {
// Can represent string, number, or null ID
}Request IDs can be:
Coerces a Go value to a JSON-RPC ID.
func MakeID(v any) (ID, error)Parameters:
v: Value to convert (should be nil, float64, or string)Returns:
ID: Converted IDerror: Error if value is not a valid ID typeExample:
// String ID
id1, _ := jsonrpc.MakeID("request-123")
// Numeric ID
id2, _ := jsonrpc.MakeID(float64(42))
// Null ID (for notifications)
id3, _ := jsonrpc.MakeID(nil)
// Invalid type - returns error
_, err := jsonrpc.MakeID(true)
if err != nil {
fmt.Println("Invalid ID type")
}The jsonrpc package is primarily used when implementing custom MCP transports. Here's an example of how it's used:
package main
import (
"context"
"fmt"
"io"
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
type MyTransport struct {
reader io.Reader
writer io.Writer
}
func (t *MyTransport) Connect(ctx context.Context) (mcp.Connection, error) {
return &myConnection{
reader: t.reader,
writer: t.writer,
}, nil
}
type myConnection struct {
reader io.Reader
writer io.Writer
}
func (c *myConnection) Read(ctx context.Context) (jsonrpc.Message, error) {
// Read data from transport
data := make([]byte, 4096)
n, err := c.reader.Read(data)
if err != nil {
return nil, err
}
// Decode JSON-RPC message
msg, err := jsonrpc.DecodeMessage(data[:n])
if err != nil {
return nil, fmt.Errorf("failed to decode message: %w", err)
}
return msg, nil
}
func (c *myConnection) Write(ctx context.Context, msg jsonrpc.Message) error {
// Encode JSON-RPC message
data, err := jsonrpc.EncodeMessage(msg)
if err != nil {
return fmt.Errorf("failed to encode message: %w", err)
}
// Write to transport
_, err = c.writer.Write(data)
return err
}
func (c *myConnection) Close() error {
// Clean up resources
return nil
}
func (c *myConnection) SessionID() string {
return "my-session-id"
}The jsonrpc package implements JSON-RPC 2.0 as specified in JSON-RPC 2.0 Specification.
Key features:
{
"jsonrpc": "2.0",
"id": "1",
"method": "tools/call",
"params": {
"name": "greet",
"arguments": {"name": "Alice"}
}
}{
"jsonrpc": "2.0",
"id": "1",
"result": {
"content": [
{"type": "text", "text": "Hello, Alice!"}
]
}
}{
"jsonrpc": "2.0",
"id": "1",
"error": {
"code": -32600,
"message": "Invalid Request",
"data": {}
}
}{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": "token-123",
"progress": 50,
"total": 100
}
}Use the jsonrpc package when:
For most applications, you don't need to use this package directly - the built-in transports and high-level mcp package API are sufficient.