Skip to main content

agentox_core/checks/conformance/
unknown_method.rs

1//! CONF-006: Server returns -32601 (Method Not Found) for unknown methods.
2
3use crate::checks::runner::{Check, CheckContext};
4use crate::checks::types::{CheckCategory, CheckResult, Severity};
5use crate::protocol::jsonrpc::JsonRpcRequest;
6
7pub struct UnknownMethodHandling;
8
9const UNKNOWN_METHODS: &[&str] = &["nonexistent/method", "tools/nonexistent", "foo"];
10
11#[async_trait::async_trait]
12impl Check for UnknownMethodHandling {
13    fn id(&self) -> &str {
14        "CONF-006"
15    }
16
17    fn name(&self) -> &str {
18        "Unknown method handling"
19    }
20
21    fn category(&self) -> CheckCategory {
22        CheckCategory::Conformance
23    }
24
25    async fn run(&self, ctx: &mut CheckContext) -> Vec<CheckResult> {
26        let desc = "Server must return JSON-RPC error -32601 for unknown methods";
27        let mut results = Vec::new();
28
29        for method in UNKNOWN_METHODS {
30            let req =
31                JsonRpcRequest::new(ctx.session.next_id(), *method, Some(serde_json::json!({})));
32
33            match ctx.session.send_request(&req).await {
34                Ok(response) => {
35                    if let Some(error) = &response.error {
36                        if error.code != -32601 {
37                            results.push(CheckResult::fail(
38                                self.id(),
39                                self.name(),
40                                self.category(),
41                                Severity::Medium,
42                                desc,
43                                format!(
44                                    "Method \"{method}\": expected error code -32601, got {}",
45                                    error.code
46                                ),
47                            ));
48                        }
49                    } else {
50                        results.push(CheckResult::fail(
51                            self.id(),
52                            self.name(),
53                            self.category(),
54                            Severity::High,
55                            desc,
56                            format!(
57                                "Method \"{method}\": server returned success instead of error"
58                            ),
59                        ));
60                    }
61                }
62                Err(e) => {
63                    results.push(CheckResult::fail(
64                        self.id(),
65                        self.name(),
66                        self.category(),
67                        Severity::High,
68                        desc,
69                        format!("Method \"{method}\": transport error: {e}"),
70                    ));
71                }
72            }
73        }
74
75        if results.is_empty() {
76            results.push(CheckResult::pass(
77                self.id(),
78                self.name(),
79                self.category(),
80                desc,
81            ));
82        }
83
84        results
85    }
86}