use serde_json::{Map, Value, json};
use super::jsonrpc::{self, INVALID_PARAMS, Incoming, METHOD_NOT_FOUND};
use super::tools;
use crate::debug::catalog;
const PROTOCOL_VERSION: &str = "2025-06-18";
const SUPPORTED: [&str; 3] = ["2025-06-18", "2025-03-26", "2024-11-05"];
const SERVER_NAME: &str = "concinnity";
type Failure = (i64, String);
pub(super) trait Executor {
fn call(&self, name: &str, arguments: &Map<String, Value>) -> Value;
}
pub(super) struct Server<E> {
execute: E,
}
impl<E: Executor> Server<E> {
pub(super) fn new(execute: E) -> Self {
Self { execute }
}
pub(super) fn handle(&self, message: &str) -> Option<Value> {
match jsonrpc::parse(message) {
Incoming::Call { id, method, params } => Some(match self.answer(&method, ¶ms) {
Ok(result) => jsonrpc::result(&id, result),
Err((code, message)) => jsonrpc::error(&id, code, &message),
}),
Incoming::Invalid { id, code, message } => Some(jsonrpc::error(&id, code, &message)),
Incoming::Silent => None,
}
}
fn answer(&self, method: &str, params: &Value) -> Result<Value, Failure> {
match method {
"initialize" => Ok(initialize(params)),
"ping" => Ok(json!({})),
"tools/list" => Ok(json!({ "tools": tools::list() })),
"tools/call" => self.call(params),
other => Err((METHOD_NOT_FOUND, format!("unknown method: {other}"))),
}
}
fn call(&self, params: &Value) -> Result<Value, Failure> {
let name = params
.get("name")
.and_then(Value::as_str)
.ok_or_else(|| (INVALID_PARAMS, "tools/call needs a tool name".to_string()))?;
if catalog::find(name).is_none() {
return Err((INVALID_PARAMS, format!("unknown tool: {name}")));
}
let arguments = params.get("arguments").cloned().unwrap_or(Value::Null);
let arguments = tools::arguments(&arguments).map_err(|e| (INVALID_PARAMS, e))?;
Ok(self.execute.call(name, &arguments))
}
}
fn initialize(params: &Value) -> Value {
let offered = params.get("protocolVersion").and_then(Value::as_str);
let version = offered
.filter(|v| SUPPORTED.contains(v))
.unwrap_or(PROTOCOL_VERSION);
json!({
"protocolVersion": version,
"capabilities": { "tools": {} },
"serverInfo": { "name": SERVER_NAME, "version": env!("CARGO_PKG_VERSION") },
})
}
#[cfg(test)]
mod tests {
use std::cell::RefCell;
use super::*;
struct Fake {
seen: RefCell<Vec<Value>>,
result: Value,
}
impl Fake {
fn answering(result: Value) -> Self {
Self {
seen: RefCell::new(Vec::new()),
result,
}
}
}
impl Executor for &Fake {
fn call(&self, name: &str, arguments: &Map<String, Value>) -> Value {
self.seen.borrow_mut().push(json!({
"name": name,
"arguments": Value::Object(arguments.clone()),
}));
self.result.clone()
}
}
struct Always;
impl Executor for Always {
fn call(&self, _name: &str, _arguments: &Map<String, Value>) -> Value {
tools::text_result(r#"{"ok":true}"#, false)
}
}
fn ok_server() -> Server<Always> {
Server::new(Always)
}
fn answer<E: Executor>(server: &Server<E>, message: &str) -> Value {
server.handle(message).expect("a call is always answered")
}
#[test]
fn initialize_reports_tools_and_this_server() {
let reply = answer(
&ok_server(),
r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}"#,
);
let result = &reply["result"];
assert_eq!(result["protocolVersion"], PROTOCOL_VERSION);
assert_eq!(result["capabilities"]["tools"], json!({}));
assert_eq!(result["serverInfo"]["name"], SERVER_NAME);
assert_eq!(result["serverInfo"]["version"], env!("CARGO_PKG_VERSION"));
}
#[test]
fn initialize_echoes_an_older_version_the_server_still_speaks() {
let reply = answer(
&ok_server(),
r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05"}}"#,
);
assert_eq!(reply["result"]["protocolVersion"], "2024-11-05");
}
#[test]
fn initialize_falls_back_when_the_offered_version_is_unknown() {
for params in [r#"{"protocolVersion":"1999-01-01"}"#, "{}"] {
let line =
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"initialize","params":{params}}}"#);
let reply = answer(&ok_server(), &line);
assert_eq!(reply["result"]["protocolVersion"], PROTOCOL_VERSION);
}
}
#[test]
fn the_initialized_notification_is_not_answered() {
assert!(
ok_server()
.handle(r#"{"jsonrpc":"2.0","method":"notifications/initialized"}"#)
.is_none()
);
}
#[test]
fn ping_answers_an_empty_result() {
let reply = answer(&ok_server(), r#"{"jsonrpc":"2.0","id":2,"method":"ping"}"#);
assert_eq!(reply["id"], json!(2));
assert_eq!(reply["result"], json!({}));
}
#[test]
fn tools_list_matches_the_catalog_one_to_one() {
let reply = answer(
&ok_server(),
r#"{"jsonrpc":"2.0","id":3,"method":"tools/list"}"#,
);
let tools = reply["result"]["tools"]
.as_array()
.expect("tools is an array");
assert_eq!(tools.len(), catalog::all().len());
for (tool, command) in tools.iter().zip(catalog::all()) {
assert_eq!(tool["name"], command.name);
assert_eq!(tool["description"], command.description);
assert_eq!(tool["inputSchema"], command.schema());
}
}
#[test]
fn a_tool_call_forwards_the_verb_and_its_arguments() {
let fake = Fake::answering(tools::text_result(r#"{"ok":true,"id":4}"#, false));
let reply = answer(
&Server::new(&fake),
r#"{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"decal-remove","arguments":{"id":4}}}"#,
);
assert_eq!(
fake.seen.borrow()[0],
json!({ "name": "decal-remove", "arguments": { "id": 4 } })
);
assert_eq!(reply["result"]["isError"], json!(false));
assert_eq!(
reply["result"]["content"][0]["text"],
r#"{"ok":true,"id":4}"#
);
}
#[test]
fn a_tool_call_without_arguments_carries_an_empty_object() {
let fake = Fake::answering(tools::text_result(r#"{"ok":true}"#, false));
answer(
&Server::new(&fake),
r#"{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"ping"}}"#,
);
assert_eq!(
fake.seen.borrow()[0],
json!({ "name": "ping", "arguments": {} })
);
}
#[test]
fn an_executor_failure_is_an_error_result_not_a_protocol_error() {
let fake = Fake::answering(tools::text_result("cannot connect", true));
let reply = answer(
&Server::new(&fake),
r#"{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"state"}}"#,
);
assert!(reply.get("error").is_none());
assert_eq!(reply["result"]["isError"], json!(true));
assert_eq!(reply["result"]["content"][0]["text"], "cannot connect");
}
#[test]
fn an_unknown_tool_never_reaches_the_executor() {
let fake = Fake::answering(tools::text_result(r#"{"ok":true}"#, false));
let reply = answer(
&Server::new(&fake),
r#"{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"launch"}}"#,
);
assert_eq!(reply["error"]["code"], json!(INVALID_PARAMS));
assert!(fake.seen.borrow().is_empty());
}
#[test]
fn malformed_call_params_are_still_answered() {
for params in ["{}", r#"{"name":"ping","arguments":[1]}"#, r#"{"name":7}"#] {
let line =
format!(r#"{{"jsonrpc":"2.0","id":11,"method":"tools/call","params":{params}}}"#);
let reply = answer(&ok_server(), &line);
assert_eq!(reply["id"], json!(11), "{params}");
assert_eq!(reply["error"]["code"], json!(INVALID_PARAMS), "{params}");
}
}
#[test]
fn an_unknown_method_answers_with_the_same_id() {
let reply = answer(
&ok_server(),
r#"{"jsonrpc":"2.0","id":"abc","method":"resources/list"}"#,
);
assert_eq!(reply["id"], json!("abc"));
assert_eq!(reply["error"]["code"], json!(METHOD_NOT_FOUND));
}
#[test]
fn unreadable_messages_answer_only_when_there_is_an_id() {
assert!(ok_server().handle("{not json at all").is_some());
assert!(ok_server().handle(r#"{"jsonrpc":"2.0"}"#).is_none());
}
}