use zammad_api::api::{KbAnswerPatch, KbCategoryPatch, NewKbAnswer, NewKbCategory};
use zammad_api::{Auth, Client};
#[tokio::main]
async fn main() -> zammad_api::Result<()> {
let url = std::env::var("ZAMMAD_URL").unwrap();
let token = std::env::var("ZAMMAD_API_TOKEN").unwrap();
let z = Client::builder().url(url).auth(Auth::bearer(token)).build()?;
let kb = z.knowledge_base();
let mut cleanup_category: Option<u64> = None;
let mut cleanup_answer: Option<u64> = None;
let run = async {
println!("=== list knowledge bases ===");
let kbs = kb.list_knowledge_bases().await?;
let kb_id = kbs
.first()
.map(|k| k.id)
.ok_or_else(|| zammad_api::Error::Config("no knowledge bases found".into()))?;
println!(" using kb {kb_id}");
println!("=== create category ===");
let cat = kb
.create_category(
kb_id,
NewKbCategory {
title: "__mcp_write_smoke_cat".into(),
icon: None,
parent_id: None,
},
)
.await?;
let cat_id = cat.id;
cleanup_category = Some(cat_id);
println!(" id={cat_id} title={:?}", cat.title);
println!("=== list/get category ===");
let cats = kb.list_categories().await?;
println!(" {} categories", cats.len());
let fetched = kb.get_category(cat_id).await?;
println!(" id={cat_id} title={:?}", fetched.title);
println!("=== update category ===");
let updated = kb
.update_category(
cat_id,
KbCategoryPatch {
title: Some("__mcp_write_smoke_cat (edited)".into()),
..Default::default()
},
)
.await?;
println!(" title={:?}", updated.title);
println!("=== create published answer ===");
let created = kb
.create_answer(NewKbAnswer {
category_id: cat_id,
title: "__mcp_write_smoke".into(),
body: "<p>original body</p>".into(),
published: true,
})
.await?;
let id = created.id;
cleanup_answer = Some(id);
if !created.published {
return Err(zammad_api::Error::Api {
status: 0,
message: "answer was not published after create".into(),
});
}
println!(" id={id} published={} title={:?}", created.published, created.title);
println!(" body={:?}", created.body);
println!("=== update title+body ===");
let updated = kb
.update_answer(
id,
KbAnswerPatch {
title: Some("__mcp_write_smoke (edited)".into()),
body: Some("<p>edited body</p>".into()),
..Default::default()
},
)
.await?;
println!(" title={:?} body={:?}", updated.title, updated.body);
println!("=== unpublish ===");
let unpubd = kb
.update_answer(
id,
KbAnswerPatch {
published: Some(false),
..Default::default()
},
)
.await?;
if unpubd.published {
return Err(zammad_api::Error::Api {
status: 0,
message: "answer was still published after unpublish".into(),
});
}
println!(" published={}", unpubd.published);
println!("=== delete answer ===");
kb.delete_answer(id).await?;
cleanup_answer = None;
println!("=== delete category ===");
kb.delete_category(cat_id).await?;
cleanup_category = None;
Ok(())
};
if let Err(e) = run.await {
if let Some(id) = cleanup_category {
println!("CLEANUP_CATEGORY_ID={id}");
}
if let Some(id) = cleanup_answer {
println!("CLEANUP_ANSWER_ID={id}");
}
return Err(e);
}
println!("OK — nothing to clean up");
Ok(())
}