fallow-mcp 3.7.1

MCP server for fallow codebase intelligence (exposes fallow as typed tools to AI agents)
Documentation
use std::collections::BTreeMap;

use super::super::FallowMcp;

const DESCRIPTION_FIXTURE: &str = include_str!("fixtures/tool-descriptions.json");
const SERVER_SOURCE: &str = include_str!("../mod.rs");

fn live_tool_descriptions() -> BTreeMap<String, String> {
    let server = FallowMcp::new();
    server
        .tool_router
        .list_all()
        .iter()
        .map(|tool| {
            (
                tool.name.to_string(),
                tool.description.as_deref().unwrap_or_default().to_owned(),
            )
        })
        .collect()
}

fn descriptions_match(fixture: &str, live: &BTreeMap<String, String>) -> bool {
    serde_json::from_str::<BTreeMap<String, String>>(fixture)
        .is_ok_and(|expected| expected.eq(live))
}

#[test]
fn live_tool_descriptions_match_the_checked_fixture() {
    let live = live_tool_descriptions();
    assert!(
        descriptions_match(DESCRIPTION_FIXTURE, &live),
        "live MCP tool descriptions changed; update the checked fixture only for an intentional wire-contract change"
    );
}

#[test]
fn description_contract_detects_punctuation_and_whitespace_drift() {
    let live = BTreeMap::from([("example".to_owned(), "alpha beta".to_owned())]);

    assert!(!descriptions_match(r#"{"example":"alpha beta."}"#, &live));
    assert!(!descriptions_match(r#"{"example":"alpha  beta"}"#, &live));
}

#[test]
fn tool_attributes_take_descriptions_from_method_docs() {
    assert!(
        !SERVER_SOURCE.contains("description ="),
        "tool descriptions must live in method docs, not #[tool] arguments"
    );
}