kontext_dev_core/
lib.rs

1use serde::Deserialize;
2use serde::Serialize;
3use url::Url;
4
5pub const DEFAULT_SCOPE: &str = "mcp:invoke";
6pub const DEFAULT_SERVER_NAME: &str = "kontext-dev";
7
8fn default_scope() -> String {
9    DEFAULT_SCOPE.to_string()
10}
11
12fn default_server_name() -> String {
13    DEFAULT_SERVER_NAME.to_string()
14}
15
16#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
17pub struct KontextDevConfig {
18    pub mcp_url: String,
19    pub token_url: String,
20    pub client_id: String,
21    pub client_secret: String,
22    #[serde(default = "default_scope")]
23    pub scope: String,
24    #[serde(default = "default_server_name")]
25    pub server_name: String,
26}
27
28#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
29pub struct AccessToken {
30    pub access_token: String,
31    #[serde(default)]
32    pub expires_in: Option<i64>,
33}
34
35#[derive(Debug, thiserror::Error)]
36pub enum KontextDevCoreError {
37    #[error("Kontext-Dev access token is empty")]
38    EmptyAccessToken,
39    #[error("failed to parse {mcp_url}")]
40    InvalidMcpUrl {
41        mcp_url: String,
42        source: url::ParseError,
43    },
44}
45
46pub fn build_mcp_url(
47    config: &KontextDevConfig,
48    access_token: &str,
49) -> Result<String, KontextDevCoreError> {
50    if access_token.is_empty() {
51        return Err(KontextDevCoreError::EmptyAccessToken);
52    }
53
54    let mcp_url = config.mcp_url.as_str();
55    let mut url = Url::parse(mcp_url).map_err(|source| KontextDevCoreError::InvalidMcpUrl {
56        mcp_url: mcp_url.to_string(),
57        source,
58    })?;
59    url.query_pairs_mut()
60        .append_pair("access_key", access_token);
61    Ok(url.to_string())
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use pretty_assertions::assert_eq;
68
69    #[test]
70    fn build_mcp_url_appends_access_key() {
71        let config = KontextDevConfig {
72            mcp_url: "http://localhost:4000/mcp".to_string(),
73            token_url: "http://localhost:4444/oauth2/token".to_string(),
74            client_id: "client".to_string(),
75            client_secret: "secret".to_string(),
76            scope: default_scope(),
77            server_name: default_server_name(),
78        };
79
80        let url = build_mcp_url(&config, "token").expect("build_mcp_url failed");
81        assert_eq!(url, "http://localhost:4000/mcp?access_key=token");
82    }
83}