use serde_json::Value;
use super::{
types::{require_str, DispatchError},
McpServer,
};
pub(super) async fn dispatch_typeahead_tool(
server: &McpServer,
tool: &str,
args: &Value,
) -> Option<Result<Value, DispatchError>> {
if tool != "typeahead" {
return None;
}
Some(handle_typeahead(server, args).await)
}
async fn handle_typeahead(server: &McpServer, args: &Value) -> Result<Value, DispatchError> {
let index_id = server.resolve_index_id(args).ok_or_else(|| {
DispatchError::InvalidParams("missing required string field: index_id".into())
})?;
let query = require_str(args, "query")?;
let mut params: Vec<(&str, String)> = vec![("q", query.to_string())];
if let Some(limit) = args.get("limit").and_then(Value::as_u64) {
params.push(("limit", limit.to_string()));
}
if let Some(mode) = args.get("mode").and_then(Value::as_str) {
params.push(("mode", mode.to_string()));
}
server
.get_query(&format!("/indexes/{index_id}/typeahead"), ¶ms)
.await
}
#[cfg(test)]
mod tests_typeahead {
use super::*;
use serde_json::json;
#[test]
fn dispatch_returns_none_for_unknown_tool() {
let server = McpServer::new("http://127.0.0.1:9999");
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("rt");
let result = rt.block_on(dispatch_typeahead_tool(
&server,
"search_lexical",
&json!({}),
));
assert!(
result.is_none(),
"must return None for a non-typeahead tool name"
);
}
#[test]
fn handle_typeahead_missing_index_id_returns_invalid_params() {
let server = McpServer::new("http://127.0.0.1:9999");
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("rt");
let result = rt.block_on(dispatch_typeahead_tool(
&server,
"typeahead",
&json!({ "query": "fn" }),
));
match result {
Some(Err(DispatchError::InvalidParams(msg))) => {
assert!(
msg.contains("index_id"),
"error must mention index_id: {msg}"
);
}
other => panic!("expected Some(Err(InvalidParams)), got {other:?}"),
}
}
#[test]
fn handle_typeahead_missing_query_returns_invalid_params() {
let server = McpServer::new("http://127.0.0.1:9999");
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("rt");
let result = rt.block_on(dispatch_typeahead_tool(
&server,
"typeahead",
&json!({ "index_id": "myproject" }),
));
match result {
Some(Err(DispatchError::InvalidParams(msg))) => {
assert!(msg.contains("query"), "error must mention query: {msg}");
}
other => panic!("expected Some(Err(InvalidParams)), got {other:?}"),
}
}
}