github-mcp 0.5.2

GitHub v3 REST API MCP server, generated by mcpify.
Documentation
// GitHub v3 REST API MCP server — generated by mcpify. Do not hand-edit.

use async_trait::async_trait;

use super::super::auth_manager::header_location_for;
use super::super::auth_strategy::{AuthConfig, AuthStrategy, Credentials};
use super::super::errors::AuthError;
use crate::core::config_schema::AuthMethod;

#[derive(Debug, Default)]
pub struct ApiKeyStrategy;

#[async_trait]
impl AuthStrategy for ApiKeyStrategy {
    async fn authenticate(&self, config: &AuthConfig) -> anyhow::Result<Credentials> {
        let api_key = config
            .get("api_key")
            .ok_or_else(|| AuthError::MissingCredentials("api_key".to_string()))?;

        let mut credentials = Credentials::new();
        credentials.insert("api_key".to_string(), api_key.clone());
        // Carry the scheme's real configured header name (e.g.
        // `X-Octopus-ApiKey`) through so `AuthManager::apply_auth_headers`
        // uses it instead of falling back to the generic `X-Api-Key`
        // literal — same header name the HTTP-transport extractor already
        // uses via `header_location_for`.
        let (_, header_name) = header_location_for(AuthMethod::ApiKey);
        credentials.insert("request_header_name".to_string(), header_name.to_string());
        Ok(credentials)
    }

    fn validate_credentials(&self, credentials: &Credentials) -> bool {
        credentials
            .get("api_key")
            .is_some_and(|key| !key.is_empty())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn carries_the_configured_api_key_through() {
        let strategy = ApiKeyStrategy;
        let config = AuthConfig::from([("api_key".to_string(), "abc123".to_string())]);
        let credentials = strategy.authenticate(&config).await.unwrap();
        assert_eq!(credentials.get("api_key").unwrap(), "abc123");
    }

    #[tokio::test]
    async fn rejects_a_config_missing_the_api_key() {
        let strategy = ApiKeyStrategy;
        assert!(strategy.authenticate(&AuthConfig::new()).await.is_err());
    }

    #[test]
    fn rejects_an_empty_api_key_as_invalid() {
        let strategy = ApiKeyStrategy;
        let credentials = Credentials::from([("api_key".to_string(), String::new())]);
        assert!(!strategy.validate_credentials(&credentials));
    }
}