pub const CTXVM_MESSAGES_KIND: u16 = 25910;
pub const GIFT_WRAP_KIND: u16 = 1059;
pub const EPHEMERAL_GIFT_WRAP_KIND: u16 = 21059;
pub const RELAY_LIST_METADATA_KIND: u16 = 10002;
pub const SERVER_ANNOUNCEMENT_KIND: u16 = 11316;
pub const TOOLS_LIST_KIND: u16 = 11317;
pub const RESOURCES_LIST_KIND: u16 = 11318;
pub const RESOURCETEMPLATES_LIST_KIND: u16 = 11319;
pub const PROMPTS_LIST_KIND: u16 = 11320;
pub mod tags {
pub const PUBKEY: &str = "p";
pub const RELAY: &str = "r";
pub const EVENT_ID: &str = "e";
pub const CAPABILITY: &str = "cap";
pub const NAME: &str = "name";
pub const WEBSITE: &str = "website";
pub const PICTURE: &str = "picture";
pub const ABOUT: &str = "about";
pub const SUPPORT_ENCRYPTION: &str = "support_encryption";
pub const SUPPORT_ENCRYPTION_EPHEMERAL: &str = "support_encryption_ephemeral";
pub const SUPPORT_OVERSIZED_TRANSFER: &str = "support_oversized_transfer";
}
pub const MAX_MESSAGE_SIZE: usize = 1024 * 1024;
pub const DEFAULT_LRU_SIZE: usize = 5000;
pub const DEFAULT_TIMEOUT_MS: u64 = 30_000;
pub const DEFAULT_BOOTSTRAP_RELAY_URLS: &[&str] = &[
"wss://relay.damus.io",
"wss://relay.primal.net",
"wss://nos.lol",
"wss://relay.snort.social/",
"wss://nostr.mom/",
"wss://nostr.oxtr.dev/",
];
pub const INITIALIZE_METHOD: &str = "initialize";
pub const NOTIFICATIONS_INITIALIZED_METHOD: &str = "notifications/initialized";
pub const UNENCRYPTED_KINDS: &[u16] = &[
SERVER_ANNOUNCEMENT_KIND,
TOOLS_LIST_KIND,
RESOURCES_LIST_KIND,
RESOURCETEMPLATES_LIST_KIND,
PROMPTS_LIST_KIND,
];
#[cfg(feature = "rmcp")]
pub fn mcp_protocol_version() -> &'static str {
use std::sync::OnceLock;
static VERSION: OnceLock<String> = OnceLock::new();
VERSION
.get_or_init(|| rmcp::model::ProtocolVersion::LATEST.to_string())
.as_str()
}
#[cfg(not(feature = "rmcp"))]
pub const fn mcp_protocol_version() -> &'static str {
"2025-11-25"
}
const _: () = {
assert!(EPHEMERAL_GIFT_WRAP_KIND >= 20000);
assert!(EPHEMERAL_GIFT_WRAP_KIND < 30000);
assert!(CTXVM_MESSAGES_KIND >= 20000);
assert!(CTXVM_MESSAGES_KIND < 30000);
assert!(RELAY_LIST_METADATA_KIND >= 10000);
assert!(RELAY_LIST_METADATA_KIND < 20000);
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_kind_values_match_spec() {
assert_eq!(CTXVM_MESSAGES_KIND, 25910);
assert_eq!(GIFT_WRAP_KIND, 1059);
assert_eq!(EPHEMERAL_GIFT_WRAP_KIND, 21059);
assert_eq!(RELAY_LIST_METADATA_KIND, 10002);
assert_eq!(SERVER_ANNOUNCEMENT_KIND, 11316);
assert_eq!(TOOLS_LIST_KIND, 11317);
assert_eq!(RESOURCES_LIST_KIND, 11318);
assert_eq!(RESOURCETEMPLATES_LIST_KIND, 11319);
assert_eq!(PROMPTS_LIST_KIND, 11320);
}
#[test]
fn test_tag_values_match_ts_sdk() {
assert_eq!(tags::PUBKEY, "p");
assert_eq!(tags::RELAY, "r");
assert_eq!(tags::EVENT_ID, "e");
assert_eq!(tags::CAPABILITY, "cap");
assert_eq!(tags::NAME, "name");
assert_eq!(tags::WEBSITE, "website");
assert_eq!(tags::PICTURE, "picture");
assert_eq!(tags::ABOUT, "about");
assert_eq!(tags::SUPPORT_ENCRYPTION, "support_encryption");
assert_eq!(
tags::SUPPORT_ENCRYPTION_EPHEMERAL,
"support_encryption_ephemeral"
);
assert_eq!(
tags::SUPPORT_OVERSIZED_TRANSFER,
"support_oversized_transfer"
);
}
#[test]
fn test_announcement_kinds_in_addressable_range() {
for &kind in UNENCRYPTED_KINDS {
assert!(kind >= 11316);
assert!(kind <= 11320);
}
}
#[test]
fn test_bootstrap_relays_are_wss() {
for url in DEFAULT_BOOTSTRAP_RELAY_URLS {
assert!(
url.starts_with("wss://"),
"Bootstrap relay must use wss: {url}"
);
}
}
#[test]
fn test_bootstrap_relays_nonempty() {
assert!(
!DEFAULT_BOOTSTRAP_RELAY_URLS.is_empty(),
"Must have at least one bootstrap relay"
);
}
#[test]
fn test_mcp_method_constants() {
assert_eq!(INITIALIZE_METHOD, "initialize");
assert_eq!(
NOTIFICATIONS_INITIALIZED_METHOD,
"notifications/initialized"
);
}
#[test]
fn test_unencrypted_kinds_contains_all_announcements() {
assert!(UNENCRYPTED_KINDS.contains(&SERVER_ANNOUNCEMENT_KIND));
assert!(UNENCRYPTED_KINDS.contains(&TOOLS_LIST_KIND));
assert!(UNENCRYPTED_KINDS.contains(&RESOURCES_LIST_KIND));
assert!(UNENCRYPTED_KINDS.contains(&RESOURCETEMPLATES_LIST_KIND));
assert!(UNENCRYPTED_KINDS.contains(&PROMPTS_LIST_KIND));
}
#[test]
fn test_gift_wrap_not_in_unencrypted() {
assert!(!UNENCRYPTED_KINDS.contains(&GIFT_WRAP_KIND));
assert!(!UNENCRYPTED_KINDS.contains(&EPHEMERAL_GIFT_WRAP_KIND));
}
}