op-mcp 0.1.0

MCP server providing LLM access to 1Password CLI
Documentation
//! Authentication tools for 1Password

use rust_mcp_schema::schema_utils::CallToolError;
use rust_mcp_schema::CallToolResult;
use rust_mcp_sdk::macros::{mcp_tool, JsonSchema};
use serde::{Deserialize, Serialize};

use crate::op::OpClient;
use crate::tools::{json_result, op_error_to_tool_error, text_result};

// ============================================================================
// whoami Tool
// ============================================================================

/// Get information about the currently signed-in 1Password user.
#[mcp_tool(
    name = "whoami",
    description = "Get information about the currently signed-in 1Password user. Returns account UUID, email, and account URL."
)]
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct WhoamiTool {}

impl WhoamiTool {
    pub async fn call(&self, client: &OpClient) -> Result<CallToolResult, CallToolError> {
        let result = client.whoami().await.map_err(op_error_to_tool_error)?;
        json_result(&result)
    }
}

// ============================================================================
// signin Tool
// ============================================================================

/// Sign in to a 1Password account.
#[mcp_tool(
    name = "signin",
    description = "Sign in to a 1Password account. Note: This typically requires interactive authentication through the 1Password app or biometrics. In non-interactive environments, use a service account token instead."
)]
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct SigninTool {
    /// The account URL, shorthand, or email to sign in to. If not specified, attempts to sign in to the last used account.
    #[serde(default)]
    pub account: Option<String>,
}

impl SigninTool {
    pub async fn call(&self, client: &OpClient) -> Result<CallToolResult, CallToolError> {
        let result = client
            .signin(self.account.as_deref())
            .await
            .map_err(op_error_to_tool_error)?;
        text_result(result)
    }
}

// ============================================================================
// signout Tool
// ============================================================================

/// Sign out of a 1Password account.
#[mcp_tool(
    name = "signout",
    description = "Sign out of a 1Password account. This will end the current session. Use --all to sign out of all accounts."
)]
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct SignoutTool {
    /// The account URL, shorthand, or email to sign out of.
    #[serde(default)]
    pub account: Option<String>,

    /// If true, sign out of all accounts.
    #[serde(default)]
    pub all: bool,

    /// If true, forget the account after signing out (removes from device).
    #[serde(default)]
    pub forget: bool,
}

impl SignoutTool {
    pub async fn call(&self, client: &OpClient) -> Result<CallToolResult, CallToolError> {
        let result = client
            .signout(self.account.as_deref(), self.all, self.forget)
            .await
            .map_err(op_error_to_tool_error)?;
        text_result(result)
    }
}