Skip to content

Instantly share code, notes, and snippets.

@DawnBreather
Created January 21, 2026 12:42
Show Gist options
  • Select an option

  • Save DawnBreather/246892998ee95c91ac0962ecb240a05e to your computer and use it in GitHub Desktop.

Select an option

Save DawnBreather/246892998ee95c91ac0962ecb240a05e to your computer and use it in GitHub Desktop.
1Password MCP Server Installer for Claude Code
#!/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