kontext_dev/
lib.rs

1use reqwest::Client;
2
3pub use kontext_dev_core::AccessToken;
4pub use kontext_dev_core::DEFAULT_SCOPE;
5pub use kontext_dev_core::DEFAULT_SERVER_NAME;
6pub use kontext_dev_core::KontextDevConfig;
7
8#[derive(Debug, thiserror::Error)]
9pub enum KontextDevError {
10    #[error(transparent)]
11    Core(#[from] kontext_dev_core::KontextDevCoreError),
12    #[error("Kontext-Dev token request failed for {token_url}")]
13    TokenRequest {
14        token_url: String,
15        source: reqwest::Error,
16    },
17    #[error("Kontext-Dev access token is empty")]
18    EmptyAccessToken,
19}
20
21pub fn build_mcp_url(
22    config: &KontextDevConfig,
23    access_token: &str,
24) -> Result<String, KontextDevError> {
25    kontext_dev_core::build_mcp_url(config, access_token).map_err(KontextDevError::from)
26}
27
28pub async fn request_access_token(
29    config: &KontextDevConfig,
30) -> Result<AccessToken, KontextDevError> {
31    let client = Client::new();
32    let response = client
33        .post(config.token_url.as_str())
34        .basic_auth(config.client_id.as_str(), Some(config.client_secret.as_str()))
35        .form(&[
36            ("grant_type", "client_credentials"),
37            ("scope", config.scope.as_str()),
38        ])
39        .send()
40        .await
41        .map_err(|source| KontextDevError::TokenRequest {
42            token_url: config.token_url.clone(),
43            source,
44        })?
45        .error_for_status()
46        .map_err(|source| KontextDevError::TokenRequest {
47            token_url: config.token_url.clone(),
48            source,
49        })?;
50
51    let token =
52        response
53            .json::<AccessToken>()
54            .await
55            .map_err(|source| KontextDevError::TokenRequest {
56                token_url: config.token_url.clone(),
57                source,
58            })?;
59
60    if token.access_token.is_empty() {
61        return Err(KontextDevError::EmptyAccessToken);
62    }
63
64    Ok(token)
65}