kontext_dev_sdk/
server.rs1use std::future::Future;
2use std::pin::Pin;
3
4use crate::KontextDevClient;
5use crate::KontextDevConfig;
6use crate::KontextDevError;
7
8pub type IntegrationName = String;
9
10#[derive(Clone, Debug)]
11pub enum KnownIntegration {
12 Github,
13 Slack,
14 Notion,
15 Linear,
16 Google,
17 Custom(String),
18}
19
20impl From<KnownIntegration> for String {
21 fn from(value: KnownIntegration) -> Self {
22 match value {
23 KnownIntegration::Github => "github".to_string(),
24 KnownIntegration::Slack => "slack".to_string(),
25 KnownIntegration::Notion => "notion".to_string(),
26 KnownIntegration::Linear => "linear".to_string(),
27 KnownIntegration::Google => "google".to_string(),
28 KnownIntegration::Custom(value) => value,
29 }
30 }
31}
32
33#[derive(Clone, Debug)]
34pub struct IntegrationCredential {
35 pub integration_id: String,
36 pub token: String,
37 pub authorization: String,
38}
39
40#[derive(Clone, Debug)]
41pub struct IntegrationResolvedCredentials {
42 pub integration_id: String,
43 pub authorization: String,
44}
45
46#[derive(Clone, Debug, Default)]
47pub struct MiddlewareOptions {
48 pub resource_server_url: Option<String>,
49}
50
51#[derive(Clone, Debug)]
52pub struct KontextOptions {
53 pub config: KontextDevConfig,
54}
55
56pub type McpServerFactory<T> = fn() -> T;
57pub type McpServerOrFactory<T> = Result<T, McpServerFactory<T>>;
58
59pub trait OAuthTokenVerifier: Send + Sync {
60 fn verify<'a>(
61 &'a self,
62 token: &'a str,
63 ) -> Pin<Box<dyn Future<Output = Result<(), KontextDevError>> + Send + 'a>>;
64}
65
66#[derive(Clone)]
67pub struct Kontext {
68 client: KontextDevClient,
69}
70
71impl Kontext {
72 pub fn new(options: KontextOptions) -> Self {
73 Self {
74 client: KontextDevClient::new(options.config),
75 }
76 }
77
78 pub fn client(&self) -> &KontextDevClient {
79 &self.client
80 }
81
82 pub async fn require(
83 &self,
84 integration: impl Into<IntegrationName>,
85 gateway_access_token: &str,
86 ) -> Result<IntegrationResolvedCredentials, KontextDevError> {
87 let integration_id = integration.into();
88 let status = self
89 .client
90 .integration_connection_status(gateway_access_token, &integration_id)
91 .await?;
92
93 if !status.connected {
94 return Err(KontextDevError::IntegrationOAuthInit {
95 message: format!("integration `{integration_id}` is not connected for this user"),
96 });
97 }
98
99 Ok(IntegrationResolvedCredentials {
100 integration_id,
101 authorization: format!("Bearer {gateway_access_token}"),
102 })
103 }
104
105 pub async fn require_credentials(
106 &self,
107 integration: impl Into<IntegrationName>,
108 gateway_access_token: &str,
109 ) -> Result<IntegrationCredential, KontextDevError> {
110 let integration_id = integration.into();
111 let resolved = self
112 .require(integration_id.clone(), gateway_access_token)
113 .await?;
114
115 Ok(IntegrationCredential {
116 integration_id,
117 token: gateway_access_token.to_string(),
118 authorization: resolved.authorization,
119 })
120 }
121}