Documentation
¶
Index ¶
- Constants
- Variables
- func BuildPromptsAnnouncement[T any](ctx context.Context, signer casnostr.Signer, result PromptsListResult[T]) (*casnostr.Event, error)
- func BuildResourceTemplatesAnnouncement[T any](ctx context.Context, signer casnostr.Signer, ...) (*casnostr.Event, error)
- func BuildResourcesAnnouncement[T any](ctx context.Context, signer casnostr.Signer, result ResourcesListResult[T]) (*casnostr.Event, error)
- func BuildServerAnnouncement[C any](ctx context.Context, signer casnostr.Signer, info ServerInitializeInfo[C], ...) (*casnostr.Event, error)
- func BuildToolsAnnouncement[T any](ctx context.Context, signer casnostr.Signer, result ToolsListResult[T]) (*casnostr.Event, error)
- func EncodeCEP22Frame(notification CEP22Notification) ([]byte, error)
- func EncodeCEP41Frame(notification CEP41Notification) ([]byte, error)
- func Method(domain, op string) string
- func ProgressToken(params json.RawMessage) string
- func PublishWrap(ctx context.Context, relayURLs []string, signer casnostr.Signer, ...) (*casnostr.Event, error)
- func Unwrap(ctx context.Context, signer casnostr.Signer, outer *casnostr.Event) (*casnostr.Event, error)
- func UnwrapNIP59(ctx context.Context, signer casnostr.Signer, outer *casnostr.Event) (*casnostr.Event, error)
- func Wrap(ctx context.Context, signer casnostr.Signer, recipientPubkey string, ...) (*casnostr.Event, *casnostr.Event, error)
- func WrapEventNIP59(ctx context.Context, signer casnostr.Signer, recipientPubkey string, ...) (*casnostr.Event, *casnostr.Event, error)
- func WrapPayloadNIP59(ctx context.Context, signer casnostr.Signer, recipientPubkey string, ...) (*casnostr.Event, *casnostr.Event, error)
- func WrapWithKind(ctx context.Context, signer casnostr.Signer, recipientPubkey string, ...) (*casnostr.Event, *casnostr.Event, error)
- type CEP22AbortFrame
- type CEP22AcceptFrame
- type CEP22ChunkFrame
- type CEP22EndFrame
- type CEP22Frame
- type CEP22FrameKind
- type CEP22Notification
- type CEP22StartFrame
- type CEP22Validator
- type CEP41AbortFrame
- type CEP41AcceptFrame
- type CEP41ChunkFrame
- type CEP41CloseFrame
- type CEP41Frame
- type CEP41FrameKind
- type CEP41Notification
- type CEP41PingFrame
- type CEP41PongFrame
- type CEP41StartFrame
- type CEP41Validator
- type DiscoveryMetadata
- type EnvelopeFormat
- type Error
- type GiftWrapKind
- type Handler
- type ImplementationInfo
- type Meta
- type Notification
- type Params
- type PromptsListResult
- type Registry
- type Request
- type ResourceTemplatesListResult
- type ResourcesListResult
- type Response
- type ServerInitializeInfo
- type ToolsListResult
Constants ¶
const ( JSONRPCVersion = "2.0" ParseErrorCode = -32700 InvalidRequestCode = -32600 MethodNotFoundCode = -32601 InvalidParamsCode = -32602 InternalErrorCode = -32603 )
Variables ¶
var ( // ErrNotGiftWrap reports an outer event whose kind is neither 1059 nor // 21059. ErrNotGiftWrap = errors.New("event is not a ContextVM gift wrap kind") // ErrNotNIP59 reports a gift wrap whose decrypted payload is not a signed // kind-13 seal, i.e. the event is not a NIP-59 envelope. Dual-read callers // use errors.Is(err, ErrNotNIP59) to decide whether to retry with the // legacy direct-encryption decoder. ErrNotNIP59 = errors.New("gift wrap does not contain a NIP-59 seal") )
var ( ErrInvalidFrame = errors.New("contextvm: invalid frame") ErrProgressTokenMismatch = errors.New("contextvm: progress token mismatch") ErrNonMonotonicProgress = errors.New("contextvm: non-monotonic progress") ErrNonContiguousChunk = errors.New("contextvm: non-contiguous chunk index") ErrTransferTerminal = errors.New("contextvm: transfer is terminal") ErrTransferAborted = errors.New("contextvm: transfer aborted") ErrDigestMismatch = errors.New("contextvm: digest mismatch") )
Functions ¶
func BuildPromptsAnnouncement ¶ added in v1.3.0
func BuildResourceTemplatesAnnouncement ¶ added in v1.3.0
func BuildResourcesAnnouncement ¶ added in v1.3.0
func BuildServerAnnouncement ¶ added in v1.3.0
func BuildServerAnnouncement[C any](ctx context.Context, signer casnostr.Signer, info ServerInitializeInfo[C], metadata DiscoveryMetadata) (*casnostr.Event, error)
func BuildToolsAnnouncement ¶ added in v1.3.0
func EncodeCEP22Frame ¶ added in v1.3.0
func EncodeCEP22Frame(notification CEP22Notification) ([]byte, error)
func EncodeCEP41Frame ¶ added in v1.3.0
func EncodeCEP41Frame(notification CEP41Notification) ([]byte, error)
func ProgressToken ¶
func ProgressToken(params json.RawMessage) string
func PublishWrap ¶
func PublishWrap(ctx context.Context, relayURLs []string, signer casnostr.Signer, recipientPubkey string, payload any) (*casnostr.Event, error)
PublishWrap publishes a CEP-4 simplified direct-encryption envelope (NOT NIP-59; see Wrap) to the given relays and returns the outer event.
func Unwrap ¶
func Unwrap(ctx context.Context, signer casnostr.Signer, outer *casnostr.Event) (*casnostr.Event, error)
Unwrap verifies and decrypts an addressed stored (1059) or ephemeral (21059) envelope produced by Wrap/WrapWithKind. The inner CAS_INTENT is signature-checked; response intents may correlate with an e tag and therefore are not required to carry an inner p.
This reads only the CEP-4 simplified direct-encryption envelope (NOT NIP-59 rumor/seal): it expects the decrypted gift-wrap content to be a signed CAS_INTENT, so it rejects conformant NIP-59 envelopes, whose content is a kind-13 seal. Use UnwrapNIP59 for conformant envelopes, or UnwrapAny to accept both during a migration window.
func UnwrapNIP59 ¶ added in v1.3.0
func UnwrapNIP59(ctx context.Context, signer casnostr.Signer, outer *casnostr.Event) (*casnostr.Event, error)
UnwrapNIP59 validates and decrypts every layer of a standards-conformant NIP-59 envelope addressed to the signer, for stored (1059) and ephemeral (21059) gift wraps.
It enforces, in order: the outer kind, the outer id/signature, a sole recipient p tag naming the signer, a decryptable and correctly signed kind-13 seal, a decryptable CAS_INTENT rumor, that the rumor is unsigned, that the rumor's author matches the seal's author, and that the rumor's id is its own canonical id.
The returned rumor is unsigned by construction — its authenticity comes from the seal, not from a rumor signature — so callers must not run nostr.VerifyEvent on it. Its PubKey is nonetheless authenticated, because it is required to equal the author of the verified seal. Its id is the correlation identifier.
Deliberately NOT checked, because NIP-59 makes them meaningless or leaves them to the application:
- seal and gift-wrap created_at, which NIP-59 requires senders to randomize into the past specifically to defeat timing correlation; freshness policy belongs to the caller and must key off application data, not these fields;
- replay, since NIP-59 has no replay protection — deduplicate on the returned rumor id;
- a recipient p tag on the rumor itself, since responses correlate by e tag;
- seal tags, which NIP-59 says must be empty but whose presence cannot affect this decode, as the seal is signature-verified and only its content and author are consumed.
Legacy CEP-4-shaped direct-encryption envelopes are rejected with an error satisfying errors.Is(err, ErrNotNIP59). Diagnostics never contain decrypted payload data.
func Wrap ¶
func Wrap(ctx context.Context, signer casnostr.Signer, recipientPubkey string, payload any) (*casnostr.Event, *casnostr.Event, error)
Wrap builds a signed CAS_INTENT inner event and encrypts it directly into a kind-1059 envelope. Use WrapWithKind for ephemeral kind 21059 delivery.
This is a direct-encryption envelope in the shape of CEP-4 ("NIP-59 gift wrap pattern with no rumor"), NOT NIP-59: there is no unsigned rumor and no kind-13 seal. Earlier revisions of this comment described it as "NIP-59 gift wrap", which was wrong; the wire format is unchanged.
It also deviates from CEP-4 itself: CEP-4 specifies an outer event signed by a random one-time key, whereas this helper signs the outer with the same application signer as the inner event. The sender's pubkey is therefore exposed on the outer event, which neither CEP-4 nor NIP-59 intends. Only the recipient p tag is meant to be observable.
Migration: new code should use WrapEventNIP59 / WrapPayloadNIP59, which produce the standards-conformant envelope and interoperate with any NIP-59 reader. Readers that must accept both shapes during cutover can use UnwrapAny. These direct-encryption helpers keep working and their behaviour is frozen; they are scheduled for deprecation once deployed writers have aged out, and for removal no earlier than the next major version. See docs/nip59-envelope-migration.md.
func WrapEventNIP59 ¶ added in v1.3.0
func WrapEventNIP59(ctx context.Context, signer casnostr.Signer, recipientPubkey string, inner *casnostr.Event, wrapKind GiftWrapKind) (*casnostr.Event, *casnostr.Event, error)
WrapEventNIP59 applies the standard NIP-59 construction to an already-built ContextVM intent, preserving the caller's tags (method, correlation "e", recipient "p", and any application metadata) rather than synthesising a new event from a payload.
The supplied event is treated as a template: it is copied, re-authored to the signer's pubkey, stripped of any signature, and canonicalised by recomputing its id. The result is the unsigned rumor. That rumor is encrypted into a signed kind-13 seal, which is encrypted again into a gift wrap signed by a freshly generated, single-use key, so the outer event never exposes the sender's identity.
wrapKind selects StoredGiftWrap (1059) or EphemeralGiftWrap (21059).
It returns the outer gift wrap and the canonical rumor. The rumor's id is the stable correlation identifier: it is exactly what UnwrapNIP59 and the standard nip59.GiftUnwrap return on the receiving side.
func WrapPayloadNIP59 ¶ added in v1.3.0
func WrapPayloadNIP59(ctx context.Context, signer casnostr.Signer, recipientPubkey string, payload any, wrapKind GiftWrapKind) (*casnostr.Event, *casnostr.Event, error)
WrapPayloadNIP59 builds a minimal CAS_INTENT rumor carrying the JSON-encoded payload and a single recipient tag, then applies the standard NIP-59 envelope. It is the conformant counterpart of WrapWithKind; prefer WrapEventNIP59 whenever the caller has method or correlation tags to preserve.
func WrapWithKind ¶ added in v1.3.0
func WrapWithKind(ctx context.Context, signer casnostr.Signer, recipientPubkey string, payload any, wrapKind GiftWrapKind) (*casnostr.Event, *casnostr.Event, error)
WrapWithKind builds the CEP-4 simplified direct-encryption envelope (NOT NIP-59 rumor/seal) with a stored (1059) or ephemeral (21059) outer kind. See Wrap for the format and migration notes; the conformant equivalent is WrapPayloadNIP59, or WrapEventNIP59 when the caller has an already-built intent whose tags must be preserved.
Types ¶
type CEP22AbortFrame ¶ added in v1.3.0
type CEP22AbortFrame struct {
Reason string
}
func (CEP22AbortFrame) Kind ¶ added in v1.3.0
func (CEP22AbortFrame) Kind() CEP22FrameKind
type CEP22AcceptFrame ¶ added in v1.3.0
type CEP22AcceptFrame struct{}
func (CEP22AcceptFrame) Kind ¶ added in v1.3.0
func (CEP22AcceptFrame) Kind() CEP22FrameKind
type CEP22ChunkFrame ¶ added in v1.3.0
type CEP22ChunkFrame struct {
Data string
}
func (CEP22ChunkFrame) Kind ¶ added in v1.3.0
func (CEP22ChunkFrame) Kind() CEP22FrameKind
type CEP22EndFrame ¶ added in v1.3.0
type CEP22EndFrame struct{}
func (CEP22EndFrame) Kind ¶ added in v1.3.0
func (CEP22EndFrame) Kind() CEP22FrameKind
type CEP22Frame ¶ added in v1.3.0
type CEP22Frame interface {
Kind() CEP22FrameKind
// contains filtered or unexported methods
}
type CEP22FrameKind ¶ added in v1.3.0
type CEP22FrameKind string
CEP22FrameKind is the closed CEP-22 oversized-transfer vocabulary.
const ( CEP22FrameStart CEP22FrameKind = "start" CEP22FrameAccept CEP22FrameKind = "accept" CEP22FrameChunk CEP22FrameKind = "chunk" CEP22FrameEnd CEP22FrameKind = "end" CEP22FrameAbort CEP22FrameKind = "abort" )
type CEP22Notification ¶ added in v1.3.0
type CEP22Notification struct {
ProgressToken string
Progress uint64
Total *uint64
Message string
Frame CEP22Frame
}
CEP22Notification is an MCP notifications/progress message carrying one CEP-22 oversized-transfer frame.
func DecodeCEP22Frame ¶ added in v1.3.0
func DecodeCEP22Frame(data []byte) (CEP22Notification, error)
type CEP22StartFrame ¶ added in v1.3.0
type CEP22StartFrame struct {
CompletionMode string
Digest string
TotalBytes uint64
TotalChunks uint64
}
func (CEP22StartFrame) Kind ¶ added in v1.3.0
func (CEP22StartFrame) Kind() CEP22FrameKind
type CEP22Validator ¶ added in v1.3.0
type CEP22Validator struct {
// contains filtered or unexported fields
}
func NewCEP22Validator ¶ added in v1.3.0
func NewCEP22Validator(requestParams json.RawMessage, requireAccept bool) (*CEP22Validator, error)
func (*CEP22Validator) Validate ¶ added in v1.3.0
func (validator *CEP22Validator) Validate(notification CEP22Notification) (json.RawMessage, bool, error)
Validate accepts frames in logical stream order. It intentionally does not buffer relay-reordered frames. The returned payload is non-nil only after a valid CEP-22 end frame completes bounded reassembly.
type CEP41AbortFrame ¶ added in v1.3.0
type CEP41AbortFrame struct {
Reason string
}
func (CEP41AbortFrame) Kind ¶ added in v1.3.0
func (CEP41AbortFrame) Kind() CEP41FrameKind
type CEP41AcceptFrame ¶ added in v1.3.0
type CEP41AcceptFrame struct{}
func (CEP41AcceptFrame) Kind ¶ added in v1.3.0
func (CEP41AcceptFrame) Kind() CEP41FrameKind
type CEP41ChunkFrame ¶ added in v1.3.0
func (CEP41ChunkFrame) Kind ¶ added in v1.3.0
func (CEP41ChunkFrame) Kind() CEP41FrameKind
type CEP41CloseFrame ¶ added in v1.3.0
type CEP41CloseFrame struct {
LastChunkIndex *uint64
}
func (CEP41CloseFrame) Kind ¶ added in v1.3.0
func (CEP41CloseFrame) Kind() CEP41FrameKind
type CEP41Frame ¶ added in v1.3.0
type CEP41Frame interface {
Kind() CEP41FrameKind
// contains filtered or unexported methods
}
type CEP41FrameKind ¶ added in v1.3.0
type CEP41FrameKind string
CEP41FrameKind is the closed CEP-41 open-stream vocabulary. It is intentionally distinct from CEP22FrameKind.
const ( CEP41FrameStart CEP41FrameKind = "start" CEP41FrameAccept CEP41FrameKind = "accept" CEP41FrameChunk CEP41FrameKind = "chunk" CEP41FramePing CEP41FrameKind = "ping" CEP41FramePong CEP41FrameKind = "pong" CEP41FrameClose CEP41FrameKind = "close" CEP41FrameAbort CEP41FrameKind = "abort" )
type CEP41Notification ¶ added in v1.3.0
type CEP41Notification struct {
ProgressToken string
Progress uint64
Total *uint64
Message string
Frame CEP41Frame
}
CEP41Notification is an MCP notifications/progress message carrying one CEP-41 open-stream frame.
func DecodeCEP41Frame ¶ added in v1.3.0
func DecodeCEP41Frame(data []byte) (CEP41Notification, error)
type CEP41PingFrame ¶ added in v1.3.0
type CEP41PingFrame struct {
Nonce string
}
func (CEP41PingFrame) Kind ¶ added in v1.3.0
func (CEP41PingFrame) Kind() CEP41FrameKind
type CEP41PongFrame ¶ added in v1.3.0
type CEP41PongFrame struct {
Nonce string
}
func (CEP41PongFrame) Kind ¶ added in v1.3.0
func (CEP41PongFrame) Kind() CEP41FrameKind
type CEP41StartFrame ¶ added in v1.3.0
type CEP41StartFrame struct {
Metadata map[string]json.RawMessage
}
CEP41StartFrame preserves optional application-defined advisory fields. Reserved keys type and frameType cannot be supplied in Metadata.
func (CEP41StartFrame) Kind ¶ added in v1.3.0
func (CEP41StartFrame) Kind() CEP41FrameKind
type CEP41Validator ¶ added in v1.3.0
type CEP41Validator struct {
// contains filtered or unexported fields
}
func NewCEP41Validator ¶ added in v1.3.0
func NewCEP41Validator(requestParams json.RawMessage, requireAccept bool) (*CEP41Validator, error)
func (*CEP41Validator) Validate ¶ added in v1.3.0
func (validator *CEP41Validator) Validate(notification CEP41Notification) (bool, error)
Validate accepts CEP-41 frames in logical stream order. progress orders all frames; chunkIndex independently proves contiguous payload delivery.
type DiscoveryMetadata ¶ added in v1.3.0
type DiscoveryMetadata struct {
Name string
About string
Picture string
Website string
SupportEncryption bool
}
DiscoveryMetadata maps the optional CEP-6 server discovery tags.
type EnvelopeFormat ¶ added in v1.3.0
type EnvelopeFormat string
EnvelopeFormat identifies which ContextVM envelope shape produced an inner event, so that dual-read consumers can log, meter, and eventually reject the legacy format.
const ( // EnvelopeFormatNIP59 is the standards-conformant rumor/seal/gift-wrap // envelope produced by WrapEventNIP59. EnvelopeFormatNIP59 EnvelopeFormat = "nip59" // EnvelopeFormatLegacyDirect is the CEP-4 simplified direct-encryption // envelope produced by Wrap/WrapWithKind. It has no rumor and no seal. EnvelopeFormatLegacyDirect EnvelopeFormat = "cep4-direct" )
func UnwrapAny ¶ added in v1.3.0
func UnwrapAny(ctx context.Context, signer casnostr.Signer, outer *casnostr.Event) (*casnostr.Event, EnvelopeFormat, error)
UnwrapAny is the migration helper for readers that must accept both envelope shapes while writers are being cut over. It tries the conformant NIP-59 decoder first and falls back to the legacy direct-encryption decoder only when the payload is provably not a NIP-59 envelope.
The returned EnvelopeFormat tells the caller which shape was accepted, so a deployment can meter legacy traffic and switch to UnwrapNIP59 alone once it reaches zero. Note that the two decoders return different objects: an unsigned rumor for EnvelopeFormatNIP59, and a signed CAS_INTENT for EnvelopeFormatLegacyDirect. Callers must therefore not blindly run nostr.VerifyEvent on the result, which would always fail for a rumor.
In both cases the returned event's PubKey is authenticated — by the seal signature for NIP-59, by the inner event's own signature for the legacy format — so authorization may be based on it regardless of format. Accepting both shapes is thus not an authenticity downgrade; it is a privacy one, since the legacy outer event exposes the sender. Callers that have finished their cutover should switch to UnwrapNIP59, or reject EnvelopeFormatLegacyDirect explicitly.
type Error ¶
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
Data json.RawMessage `json:"data,omitempty"`
}
type GiftWrapKind ¶ added in v1.3.0
type GiftWrapKind int
GiftWrapKind selects the outer transport kind: stored (1059) or ephemeral (21059). It applies to both the legacy direct-encryption helpers below and the conformant NIP-59 helpers in nip59.go.
const ( StoredGiftWrap GiftWrapKind = GiftWrapKind(cascadia.NIP59_GIFT_WRAP) EphemeralGiftWrap GiftWrapKind = GiftWrapKind(cascadia.NIP59_EPHEMERAL_GIFT_WRAP) )
type ImplementationInfo ¶ added in v1.3.0
ImplementationInfo is the MCP serverInfo object used by initialize.
type Notification ¶
type PromptsListResult ¶ added in v1.3.0
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
func NewRegistry ¶
func NewRegistry() *Registry
type Request ¶
type Request struct {
JSONRPC string `json:"jsonrpc"`
ID json.RawMessage `json:"id,omitempty"`
Method string `json:"method"`
Params json.RawMessage `json:"params,omitempty"`
}
func NewRequest ¶
func (Request) IDOrNull ¶
func (r Request) IDOrNull() json.RawMessage
type ResourceTemplatesListResult ¶ added in v1.3.0
type ResourcesListResult ¶ added in v1.3.0
type Response ¶
type Response struct {
JSONRPC string `json:"jsonrpc"`
ID json.RawMessage `json:"id,omitempty"`
Result any `json:"result,omitempty"`
Error *Error `json:"error,omitempty"`
}
func NewErrorResponse ¶
func NewErrorResponse(id json.RawMessage, code int, message string) Response
func NewResponse ¶
func NewResponse(id json.RawMessage, result any) Response
type ServerInitializeInfo ¶ added in v1.3.0
type ServerInitializeInfo[C any] struct { ProtocolVersion string `json:"protocolVersion"` Capabilities C `json:"capabilities"` ServerInfo ImplementationInfo `json:"serverInfo"` Instructions string `json:"instructions,omitempty"` }
ServerInitializeInfo is the result-shaped content of a kind-11316 announcement. C lets callers retain their MCP capability model.