use rust_mcp_schema::{
Implementation, InitializeResult, ServerCapabilities, ServerCapabilitiesTools,
LATEST_PROTOCOL_VERSION,
};
use rust_mcp_sdk::mcp_server::{server_runtime, ServerRuntime};
use rust_mcp_sdk::{McpServer, StdioTransport, TransportOptions};
use tracing::{error, info};
use tracing_subscriber::EnvFilter;
use op_mcp::{OnePasswordHandler, OpClient};
const SERVER_NAME: &str = "op-mcp";
const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION");
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
init_logging();
info!(
name = SERVER_NAME,
version = SERVER_VERSION,
"Starting 1Password MCP Server"
);
let op_client = match OpClient::new() {
Ok(client) => {
info!("Found op CLI");
client
}
Err(e) => {
error!("Failed to find op CLI: {}", e);
eprintln!("Error: {}", e);
eprintln!(
"Please install the 1Password CLI from: https://1password.com/downloads/command-line/"
);
std::process::exit(1);
}
};
if !op_client.is_authenticated().await {
error!("Not signed in to 1Password");
eprintln!("Error: Not signed in to 1Password");
eprintln!("Please sign in using the 1Password app or run `op signin`");
}
let server_details = InitializeResult {
server_info: Implementation {
name: SERVER_NAME.to_string(),
version: SERVER_VERSION.to_string(),
},
capabilities: ServerCapabilities {
tools: Some(ServerCapabilitiesTools { list_changed: None }),
..Default::default()
},
meta: None,
instructions: Some(
"This server provides secure access to 1Password vaults and secrets. \
Use the available tools to list vaults, view items, and read secrets. \
By default, sensitive fields are hidden - use reveal=true to show passwords."
.to_string(),
),
protocol_version: LATEST_PROTOCOL_VERSION.to_string(),
};
let transport = StdioTransport::new(TransportOptions::default())?;
let handler = OnePasswordHandler::new(op_client);
let server: ServerRuntime = server_runtime::create_server(server_details, transport, handler);
info!("Server initialized, waiting for connections");
server.start().await?;
info!("Server shutting down");
Ok(())
}
fn init_logging() {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
EnvFilter::new("warn,op_mcp=info")
});
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_writer(std::io::stderr)
.with_target(true)
.with_level(true)
.init();
}