Created
January 21, 2026 12:42
-
-
Save DawnBreather/246892998ee95c91ac0962ecb240a05e to your computer and use it in GitHub Desktop.
1Password MCP Server Installer for Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bun | |
| /** | |
| * 1Password MCP Server Installer | |
| * | |
| * Pulls the release from 1Password and installs globally for Claude Code. | |
| * | |
| * Usage: | |
| * bun run https://gist.githubusercontent.com/YOUR_USERNAME/GIST_ID/raw/install.ts | |
| * | |
| * Prerequisites: | |
| * - Bun installed (https://bun.sh) | |
| * - 1Password CLI installed and signed in | |
| * - Access to the Config vault | |
| */ | |
| import { $ } from "bun"; | |
| import { existsSync, mkdirSync } from "fs"; | |
| import { homedir, platform, arch } from "os"; | |
| import { join } from "path"; | |
| const VAULT = "Config"; | |
| const ITEM = "1password.mcp"; | |
| const MCP_BIN_DIR = join(homedir(), ".mcp", "bin"); | |
| const CLAUDE_CONFIG = join(homedir(), ".claude.json"); | |
| interface PlatformBinary { | |
| archivePath: string; | |
| binaryName: string; | |
| } | |
| function getPlatformBinary(): PlatformBinary { | |
| const os = platform(); | |
| const architecture = arch(); | |
| // Archive structure: onepassword-mcp-release/onepassword-mcp-{platform} | |
| const prefix = "onepassword-mcp-release"; | |
| if (os === "darwin") { | |
| if (architecture === "arm64") { | |
| return { archivePath: `${prefix}/onepassword-mcp-macos-aarch64`, binaryName: "onepassword-mcp" }; | |
| } else { | |
| return { archivePath: `${prefix}/onepassword-mcp-macos-x86_64`, binaryName: "onepassword-mcp" }; | |
| } | |
| } else if (os === "linux") { | |
| return { archivePath: `${prefix}/onepassword-mcp-linux-x86_64`, binaryName: "onepassword-mcp" }; | |
| } else if (os === "win32") { | |
| return { archivePath: `${prefix}/onepassword-mcp-windows-x86_64.exe`, binaryName: "onepassword-mcp.exe" }; | |
| } | |
| throw new Error(`Unsupported platform: ${os}/${architecture}`); | |
| } | |
| async function checkOpCli(): Promise<boolean> { | |
| try { | |
| await $`op --version`.quiet(); | |
| return true; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| async function checkOpSignedIn(): Promise<boolean> { | |
| try { | |
| await $`op account get`.quiet(); | |
| return true; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| async function downloadFromOp(tempDir: string): Promise<string> { | |
| const zipPath = join(tempDir, "release.zip"); | |
| console.log(`Downloading ${ITEM} from 1Password...`); | |
| await $`op document get ${ITEM} --vault ${VAULT} --out-file ${zipPath} --force`; | |
| return zipPath; | |
| } | |
| async function extractBinary(zipPath: string, platformBinary: PlatformBinary): Promise<string> { | |
| const tempExtract = join(homedir(), ".mcp", ".tmp-extract"); | |
| // Clean up any previous extract | |
| if (existsSync(tempExtract)) { | |
| await $`rm -rf ${tempExtract}`; | |
| } | |
| mkdirSync(tempExtract, { recursive: true }); | |
| console.log(`Extracting ${platformBinary.archivePath}...`); | |
| await $`unzip -o ${zipPath} -d ${tempExtract}`.quiet(); | |
| const binarySource = join(tempExtract, platformBinary.archivePath); | |
| if (!existsSync(binarySource)) { | |
| throw new Error(`Binary not found in archive: ${platformBinary.archivePath}`); | |
| } | |
| return binarySource; | |
| } | |
| async function installBinary(binarySource: string, binaryName: string): Promise<string> { | |
| mkdirSync(MCP_BIN_DIR, { recursive: true }); | |
| const destination = join(MCP_BIN_DIR, binaryName); | |
| console.log(`Installing to ${destination}...`); | |
| await $`cp ${binarySource} ${destination}`; | |
| await $`chmod +x ${destination}`; | |
| return destination; | |
| } | |
| function updateClaudeConfig(binaryPath: string): void { | |
| console.log(`Updating ${CLAUDE_CONFIG}...`); | |
| let config: Record<string, unknown> = {}; | |
| if (existsSync(CLAUDE_CONFIG)) { | |
| const content = require(CLAUDE_CONFIG); | |
| config = content; | |
| } | |
| if (!config.mcpServers) { | |
| config.mcpServers = {}; | |
| } | |
| (config.mcpServers as Record<string, unknown>)["1password"] = { | |
| type: "stdio", | |
| command: binaryPath, | |
| args: [], | |
| env: {} | |
| }; | |
| Bun.write(CLAUDE_CONFIG, JSON.stringify(config, null, 2) + "\n"); | |
| } | |
| async function cleanup(): Promise<void> { | |
| const tempExtract = join(homedir(), ".mcp", ".tmp-extract"); | |
| if (existsSync(tempExtract)) { | |
| await $`rm -rf ${tempExtract}`; | |
| } | |
| } | |
| async function main(): Promise<void> { | |
| console.log("1Password MCP Server Installer\n"); | |
| // Check prerequisites | |
| if (!await checkOpCli()) { | |
| console.error("Error: 1Password CLI (op) not found. Install from https://1password.com/downloads/command-line/"); | |
| process.exit(1); | |
| } | |
| if (!await checkOpSignedIn()) { | |
| console.error("Error: Not signed in to 1Password CLI. Run: op signin"); | |
| process.exit(1); | |
| } | |
| try { | |
| const platformBinary = getPlatformBinary(); | |
| console.log(`Detected platform: ${platform()}/${arch()}`); | |
| console.log(`Binary: ${platformBinary.archivePath}\n`); | |
| // Create temp directory | |
| const tempDir = join(homedir(), ".mcp", ".tmp"); | |
| mkdirSync(tempDir, { recursive: true }); | |
| // Download and extract | |
| const zipPath = await downloadFromOp(tempDir); | |
| const binarySource = await extractBinary(zipPath, platformBinary); | |
| // Install | |
| const installedPath = await installBinary(binarySource, platformBinary.binaryName); | |
| // Update Claude config | |
| updateClaudeConfig(installedPath); | |
| // Cleanup | |
| await cleanup(); | |
| await $`rm -rf ${join(homedir(), ".mcp", ".tmp")}`; | |
| console.log("\nInstallation complete!"); | |
| console.log(`Binary: ${installedPath}`); | |
| console.log(`Config: ${CLAUDE_CONFIG}`); | |
| console.log("\nRestart Claude Code or run /mcp to load the server."); | |
| } catch (error) { | |
| console.error(`\nInstallation failed: ${error}`); | |
| await cleanup(); | |
| process.exit(1); | |
| } | |
| } | |
| main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment