diff --git a/pkg/jsonrpc/json.go b/pkg/jsonrpc/json.go
index ba5bc5f201bafb99887ae8971556eea2cbfc1dba..3b3d9f69b42fd687dcf13a998adc87491c4ef99f 100644
--- a/pkg/jsonrpc/json.go
+++ b/pkg/jsonrpc/json.go
@@ -22,10 +22,11 @@ func NewNull() json.RawMessage {
 // A value of this type can a JSON-RPC request, notification, successful response or
 // error response. Which one it is depends on the fields.
 type Message struct {
-	ID     *ID             `json:"id,omitempty"`
-	Method string          `json:"method,omitempty"`
-	Params json.RawMessage `json:"params,omitempty"`
-	Error  error           `json:"error,omitempty"`
+	ID         *ID                        `json:"id,omitempty"`
+	Method     string                     `json:"method,omitempty"`
+	Params     json.RawMessage            `json:"params,omitempty"`
+	Error      error                      `json:"error,omitempty"`
+	Extensions map[string]json.RawMessage `json:"-"`
 
 	Result io.ReadCloser `json:"result,omitempty"`
 }
@@ -70,6 +71,13 @@ func MarshalMessage(m *Message, enc *jx.Encoder) (err error) {
 				}
 			})
 		}
+		if m.Extensions != nil {
+			for k, v := range m.Extensions {
+				e.Field(k, func(e *jx.Encoder) {
+					e.Raw(v)
+				})
+			}
+		}
 	})
 	if err != nil {
 		return err
@@ -84,6 +92,15 @@ func MarshalMessage(m *Message, enc *jx.Encoder) (err error) {
 func UnmarshalMessage(m *Message, dec *jx.Decoder) error {
 	err := dec.Obj(func(d *jx.Decoder, key string) (err error) {
 		switch key {
+		default:
+			raw, err := d.Raw()
+			if err != nil {
+				return err
+			}
+			if m.Extensions == nil {
+				m.Extensions = make(map[string]json.RawMessage)
+			}
+			m.Extensions[key] = json.RawMessage(raw)
 		case "jsonrpc":
 			value, err := d.Str()
 			if err != nil {
diff --git a/pkg/jsonrpc/reqresp.go b/pkg/jsonrpc/reqresp.go
index 67a5cbe7004547a1cadcd52a9093297730e43464..1cf53e7564319191edfcbc17f52d8664da39b1b0 100644
--- a/pkg/jsonrpc/reqresp.go
+++ b/pkg/jsonrpc/reqresp.go
@@ -20,10 +20,11 @@ type StreamingResponseWriter interface {
 }
 
 type Request struct {
-	ID     *ID             `json:"id,omitempty"`
-	Method string          `json:"method,omitempty"`
-	Params json.RawMessage `json:"params,omitempty"`
-	Peer   PeerInfo        `json:"-"`
+	ID         *ID                        `json:"id,omitempty"`
+	Method     string                     `json:"method,omitempty"`
+	Params     json.RawMessage            `json:"params,omitempty"`
+	Peer       PeerInfo                   `json:"-"`
+	Extensions map[string]json.RawMessage `json:"-"`
 
 	ctx context.Context
 }
@@ -87,6 +88,12 @@ func (r Request) MarshalJSON() ([]byte, error) {
 			e.FieldStart("params")
 			e.Raw(r.Params)
 		}
+		if r.Extensions != nil {
+			for k, v := range r.Extensions {
+				e.FieldStart(k)
+				e.Raw(v)
+			}
+		}
 	})
 	return enc.Bytes(), nil
 }