liminal-cli 0.3.1

The liminal command: serve the network, maintain its stores, or serve its discovery MCP over stdio
Documentation
//! SDK-017 R1: both revisions negotiate; an `initialize` for any other is
//! answered with the legacy revision (MCP lifecycle), a modern request naming
//! an unknown one is refused by the named error, and a modern request without
//! its `_meta` fields is invalid params.

use serde_json::{Map, Value, json};

use super::super::framing::{INVALID_PARAMS, UNSUPPORTED_PROTOCOL_VERSION};
use super::{Era, LEGACY, MODERN, Refusal, Session};

fn params(value: &Value) -> Map<String, Value> {
    value.as_object().cloned().unwrap_or_default()
}

#[test]
fn modern_meta_selects_the_modern_era() -> Result<(), super::Refusal> {
    let session = Session::new();
    let era = session.era_of(&params(&json!({
        "_meta": {
            "io.modelcontextprotocol/protocolVersion": MODERN,
            "io.modelcontextprotocol/clientCapabilities": {},
        }
    })))?;
    assert_eq!(era, Era::Modern);
    Ok(())
}

#[test]
fn initialize_opens_the_legacy_session_and_bare_requests_follow() -> Result<(), super::Refusal> {
    let mut session = Session::new();
    assert_eq!(
        session.era_of(&Map::new()).map_err(|r| r.code),
        Err(INVALID_PARAMS)
    );
    let answer = session.initialize(&params(&json!({ "protocolVersion": LEGACY })))?;
    assert_eq!(answer["protocolVersion"], LEGACY);
    assert_eq!(session.era_of(&Map::new())?, Era::Legacy);
    Ok(())
}

#[test]
fn an_initialize_for_another_version_is_answered_with_the_legacy_version() -> Result<(), Refusal> {
    // MCP lifecycle: the server answers a version it supports and the client
    // decides; Claude Code asks for 2025-06-18 and speaks 2025-11-25.
    let mut session = Session::new();
    let answer = session.initialize(&params(&json!({ "protocolVersion": "2025-06-18" })))?;
    assert_eq!(answer["protocolVersion"], LEGACY);
    assert!(session.is_legacy());
    Ok(())
}

#[test]
fn a_modern_request_naming_an_unknown_version_is_refused() {
    let session = Session::new();
    let refusal = session
        .era_of(&params(&json!({
            "_meta": { "io.modelcontextprotocol/protocolVersion": "1900-01-01" }
        })))
        .err();
    assert_eq!(refusal.map(|r| r.code), Some(UNSUPPORTED_PROTOCOL_VERSION));
}

#[test]
fn modern_request_without_capabilities_is_invalid_params() {
    let session = Session::new();
    let refusal = session
        .era_of(&params(&json!({
            "_meta": { "io.modelcontextprotocol/protocolVersion": MODERN }
        })))
        .err();
    assert!(refusal.is_some(), "missing capabilities were accepted");
    let Some(refusal) = refusal else { return };
    assert_eq!(refusal.code, INVALID_PARAMS);
    assert!(
        refusal.message.contains("clientCapabilities"),
        "{}",
        refusal.message
    );
}