1Password MCP 서버: 클로드 코드로 .env 안전하게 관리하기
얼마 전 1Password 서비스 계정 글을 손보다가 1Password 설정 화면에서 낯선 체크박스를 하나 발견했습니다. Settings > Developer에 Integrate with MCP clients라는 항목이 생겨 있더라고요. 1Password가 직접 MCP 서버를 내놓은 건데요. 비밀번호 관리자가 AI 에이전트에게 문을 열어 준다니, 반갑기보다 먼저 걱정이 앞섰습니다. 🤔 에이전트가 내 API 키를 마음대로 꺼내 가면 어떡하죠?
직접 켜 보니 생각과는 다른 물건이었습니다. 이 서버는 시크릿 값을 에이전트에게 돌려주지 않도록 설계돼 있고, 대신 프로젝트의 .env 파일을 1Password로 옮겨 관리하는 일을 맡깁니다. 이 글에서는 1Password MCP 서버를 클로드 코드에 연결하고, 평문 .env를 1Password Environments로 옮겨 마운트(mount)하는 과정을 실제 화면과 함께 따라가 보겠습니다. 그리고 “값을 돌려주지 않는다”는 말이 어디까지 사실인지도 직접 확인해 보겠습니다.
이 글은 1Password for Mac 8.12.40, 클로드 코드 2.1, 1Password 플러그인 0.1.0을 기준으로 합니다.
1Password MCP 서버는 무엇을 할까?
1Password MCP 서버는 데스크톱 앱 안에서 도는 로컬 서버입니다. 클로드 코드 같은 MCP 클라이언트가 stdio로 붙어서 도구를 호출하는 구조인데요. MCP 자체가 낯설다면 먼저 읽고 오셔도 좋습니다.
이 서버가 다루는 대상은 볼트(vault)의 로그인 항목이 아니라 1Password Environments입니다. Environments는 프로젝트의 환경 변수를 볼트와 따로 모아 두는 기능인데, 쉽게 말해 .env 파일 하나를 1Password 안에 통째로 옮겨 둔 것이라고 보면 됩니다. MCP 서버가 노출하는 도구는 다음과 같습니다.
| 도구 | 하는 일 |
|---|---|
authenticate | 데스크톱 앱과 연결하고 계정 ID를 받아 옵니다 |
list_environments | Environment 목록을 조회합니다 |
create_environment | 새 Environment를 만듭니다 |
rename_environment | Environment 이름을 바꿉니다 |
list_variables | 변수 이름 목록을 조회합니다(값은 빠짐) |
append_variables | 변수를 추가하거나 고칩니다 |
create_local_env_file | Environment를 로컬 .env 파일로 마운트합니다 |
list_local_env_files | 마운트된 .env 파일 목록을 조회합니다 |
목록을 보면 값을 읽는 도구가 하나도 없습니다. 에이전트는 변수를 쓰고(append) 이름을 볼 수는 있지만, 저장된 값을 꺼낼 방법은 주어지지 않습니다. 1Password 문서도 에이전트가 요청하더라도 서버가 시크릿 값을 돌려줄 수 없게 설계했다고 설명합니다.
기능이 들어온 과정도 짚어 두겠습니다. 릴리스 노트를 보면 2026년 5월 8.12.21에서 Codex용 로컬 MCP 서버가 베타로 처음 등장했고, 그때는 Labs 메뉴에서 켜야 했습니다. 7월에 CLI, SDK, MCP 연동이 Settings > Developer의 한 섹션으로 묶였고, 8월 8.12.34에서 Labs 항목이 빠지면서 Developer 탭으로 완전히 옮겨졌습니다. 공식 문서 일부는 아직 Labs에서 켜라고 안내하니, 화면이 다르더라도 당황하지 마세요. 그리고 아직 베타이며 Mac과 Linux만 지원합니다.
데스크톱 앱에서 MCP 연동 켜기
1Password 앱에서 Settings > Developer로 이동하면 두 가지를 켜야 합니다.

우선 맨 아래 Developer Integrations 섹션의 Integrate with MCP clients가 MCP 서버를 실제로 켜는 스위치입니다. 이걸 체크하는 순간 앱이 /usr/local/bin에 1password-mcp 실행 파일 링크를 만들어 줍니다.
which 1password-mcp
/usr/local/bin/1password-mcp
MCP 클라이언트는 이 1password-mcp 명령을 실행해서 서버에 붙습니다. 그래서 이 체크박스를 켜기 전에는 PATH에서 명령을 찾지 못해 연결이 실패하는데, 이 순서 문제는 뒤에서 다시 다루겠습니다.
다음으로 맨 위의 Show 1Password Developer experience는 메인 창 사이드바에 Developer 메뉴를 보여 줍니다. 에이전트가 만든 Environment를 앱에서 눈으로 확인하려면 이 메뉴가 필요하니 함께 켜 두세요. 켜면 Record and display activity라는 하위 옵션도 함께 나타납니다.
사이드바의 Developer를 누르면 SSH 에이전트(SSH Agent), Environments, CLI, Watchtower, MCP Server가 카드로 모여 있습니다.

클로드 코드에 1Password 플러그인 설치하기
클로드 코드에서는 MCP 서버를 직접 등록하는 대신 1Password가 배포하는 플러그인을 설치합니다. 클로드 코드 세션에서 마켓플레이스를 추가하고 플러그인을 설치하면 됩니다.
/plugin marketplace add 1Password/1password-claude-plugin
/plugin install 1password@1password
터미널에서 바로 설치하고 싶다면 claude plugin 명령을 써도 됩니다.
claude plugin marketplace add 1Password/1password-claude-plugin
claude plugin install 1password@1password
플러그인이 무엇이고 마켓플레이스는 어떻게 동작하는지는 클로드 코드 플러그인 사용법에서 자세히 다뤘습니다.
이 플러그인을 설치하면 세 가지가 함께 등록됩니다. 첫째로 MCP 서버 설정입니다. 열어 보면 앞에서 본 1password-mcp 명령을 실행하는 단순한 stdio 설정이에요.
{
"mcpServers": {
"1password": {
"command": "1password-mcp",
"args": []
}
}
}
둘째로 1password-environments 스킬입니다. “.env를 가져와서 마운트해 줘” 같은 요청을 받았을 때 도구를 어떤 순서로 호출할지 알려 주는 작업 지침인데요. MCP 서버의 도구 설명만으로는 가져오기와 마운트를 잇는 흐름이 드러나지 않아서 따로 넣어 둔 것으로 보입니다.
셋째로 Bash 도구에 거는 PreToolUse 훅(hook)입니다. 에이전트가 셸 명령을 실행하기 직전에 1Password가 마운트해 둔 .env 파일이 제자리에 있고 활성화돼 있는지 검사합니다. 마운트가 빠졌거나 꺼져 있으면 명령 실행을 막고, 1Password가 설치돼 있지 않으면 그냥 통과시킵니다. 훅의 동작 원리는 클로드 코드 Hooks 글을 참고하세요.
설치 순서를 지키지 않으면 15분을 기다려야 한다
저는 순서를 거꾸로 했습니다. 앱에서 MCP 연동을 켜기 전에 플러그인부터 설치했더니 바로 이런 상태가 됐어요.
claude mcp list
plugin:1password:1password: 1password-mcp - ✘ Failed to connect — ENOENT: Executable not found in $PATH: "stdio"
1password-mcp가 아직 PATH에 없으니 당연한 결과입니다. 그래서 앱에서 체크박스를 켰고, 다시 확인하니 상태가 바뀌어 있었습니다.
plugin:1password:1password: 1password-mcp - ✔ Connected
그런데 정작 새 클로드 코드 세션에서는 1Password 도구가 하나도 보이지 않았습니다. 세션의 MCP 상태를 보니 이런 메시지가 남아 있더라고요.
Skipping connection (recent failure cached retries automatically in 15 min, or edit the plugin config to retry now)
클로드 코드는 연결에 실패한 MCP 서버를 15분 동안 기억해 두고 다시 시도하지 않습니다. 죽어 있는 서버에 세션마다 연결을 시도하느라 시작이 느려지는 걸 막으려는 장치인데요. claude mcp list는 이 캐시와 상관없이 매번 직접 연결해 보기 때문에 Connected로 나오고, 정작 세션은 캐시를 보고 건너뛰니 헷갈리기 쉽습니다. 메시지는 플러그인 설정을 고치면 바로 다시 시도한다고 하지만, 플러그인을 껐다 켜는 것으로는 풀리지 않았고 결국 15분을 기다려야 했습니다.
교훈은 간단합니다. 1Password 앱에서 Integrate with MCP clients를 먼저 켜고, 그다음에 플러그인을 설치하세요.
평문 .env를 1Password로 옮기기
이제 본론입니다. 실습용 프로젝트에 더미 값만 넣은 평문 .env를 하나 만들었습니다.
DATABASE_URL=postgres://demo:demo@localhost:5432/blog_demo
OPENAI_API_KEY=sk-demo-not-a-real-key
PORT=3000
그리고 클로드 코드에게 이렇게 부탁했습니다.
이 프로젝트의 .env를 1Password Environment 'blog-demo'로 가져오고 같은 경로에 마운트해줘.
클로드 코드는 먼저 1password-environments 스킬을 불러온 뒤, 도구를 다음 순서로 호출했습니다.
Read .env 파일에서 변수 이름과 값을 읽음
authenticate → {"account_id": "..."}
list_environments → 같은 이름의 Environment가 있는지 확인
create_environment → {"environmentId": "..."}
append_variables → DATABASE_URL, OPENAI_API_KEY는 숨김, PORT는 표시
list_local_env_files → 이 Environment의 기존 마운트 확인
create_local_env_file → 원래 .env 경로에 마운트
list_local_env_files → 마운트가 켜졌는지(isEnabled: true) 재확인
흥미로운 부분은 append_variables입니다. 에이전트가 변수 성격을 보고 API 키와 접속 문자열은 숨김(concealed)으로, PORT 같은 설정값은 표시로 나눠 저장했습니다. 다만 숨김은 1Password 화면에 값을 가려 보여 줄지만 정하는 옵션이고, 암호화는 모든 변수에 똑같이 적용됩니다.
여기서 눈여겨볼 점이 있습니다. 첫 단계에서 에이전트가 평문 .env를 Read 도구로 직접 읽었다는 사실인데요. 값을 1Password에 넘기려면 어쩔 수 없는 과정이지만, 그 순간 값은 이미 에이전트의 문맥에 들어갑니다. 1Password 문서가 가져온 시크릿은 반드시 교체(rotate)하라고 거듭 경고하는 이유이기도 합니다. 1Password로 옮기는 건 앞으로의 노출을 막을 뿐, Git 히스토리나 에이전트 대화 기록에 이미 남은 값까지 지워 주지는 않으니까요.
승인 창은 두 단계로 뜬다
도구를 호출하는 동안 1Password 앱이 승인 창을 두 번 띄웠습니다. 처음은 계정 단위 승인입니다.

Environment 목록을 보고 새로 만들어도 되는지 묻습니다. 요청한 앱 이름이 Orca Helper로 나오는 건 제가 클로드 코드를 Orca라는 앱 안에서 실행했기 때문입니다. 승인 창에는 클로드 코드를 띄운 앱의 이름이 표시되니, 터미널에서 실행했다면 그 터미널 이름이 보일 거예요.
Environment가 만들어지자 이번에는 그 Environment 단위로 다시 묻습니다.

권한이 체크박스로 나뉘어 있으니 필요한 것만 남기고 승인하면 됩니다. 예를 들어 Create/update environment secrets를 빼면 에이전트는 변수 이름만 볼 수 있고 값을 바꾸지는 못하게 됩니다.
한 번 승인하면 1Password가 잠길 때까지 다시 묻지 않습니다. 승인을 모두 거두고 싶다면 Settings > Developer의 Clear MCP Authorizations 버튼을 누르면 됩니다.
작업이 끝난 뒤 앱에서 Developer > Environments로 가 보면 blog-demo가 생겨 있습니다.

들어가 보면 변수 세 개와 함께 아래쪽 Connected to 영역에 로컬 .env 파일 연결이 보입니다. 앞에서 숨김으로 저장한 두 값은 가려져 있고 PORT만 그대로 보이죠.

마운트된 .env의 정체는 명명된 파이프
마운트가 끝난 .env는 더 이상 평범한 파일이 아닙니다.
stat -f "%Sp %z %N" .env
file .env
prw------- 0 .env
.env: fifo (named pipe)
권한 문자열 맨 앞의 p와 크기 0이 보이시나요? 1Password는 .env를 명명된 파이프(named pipe), 흔히 FIFO라고 부르는 특수 파일로 만듭니다. 디스크에는 내용이 전혀 저장되지 않고, 어떤 프로세스가 이 파일을 읽는 순간 1Password가 값을 흘려보내는 방식이에요.
cat .env
# This file was generated by 1Password. Any manual edits will be lost.
# Created from Environment: blog-demo
# For more information, visit: https://www.1password.dev/environments/local-env-file
DATABASE_URL=postgres://demo:demo@localhost:5432/blog_demo
OPENAI_API_KEY=sk-demo-not-a-real-key
PORT=3000
읽는 쪽에서 보면 평범한 .env와 다르지 않습니다. 그래서 dotenv 같은 라이브러리도 코드를 고칠 필요가 없습니다. 1Password 문서에는 Node.js, Python, Go, Rust, Docker Compose 등 주요 라이브러리와의 호환성 표가 정리돼 있습니다.
FIFO라서 생기는 부수 효과도 있습니다. 이 프로젝트에는 .gitignore가 없는데도 git status가 마운트된 .env를 아예 보여 주지 않았습니다. Git은 일반 파일과 디렉토리, 심볼릭 링크만 다루고 FIFO는 무시하기 때문이에요. 다만 이미 Git이 추적하던 .env가 있던 자리에 마운트한다면, 원래 파일을 지우는 커밋을 먼저 해 두라고 문서가 안내합니다.
반대로 주의할 점도 있습니다. Vite처럼 .env 변경을 감시하는 도구는 파이프를 열고 닫을 때 생기는 파일 시스템 이벤트를 수정으로 오인해 개발 서버를 끝없이 재시작할 수 있습니다. 이럴 때는 Vite 설정의 server.watch.ignored에 .env를 넣어 감시 대상에서 빼면 됩니다. 또 여러 프로세스가 동시에 읽는 상황은 고려되지 않아서, 에디터가 파일을 붙잡고 있으면 다른 프로세스의 읽기가 실패할 수 있습니다.
에이전트는 정말 값을 못 볼까?
여기까지 보면 “에이전트는 시크릿 값을 절대 못 본다”고 정리하고 싶어집니다. 그래서 직접 시험해 봤습니다. 새 클로드 코드 세션에 Bash로 cat .env를 실행해 달라고 했더니, 앞에서 본 출력이 값까지 그대로 돌아왔습니다. 😅
이건 버그가 아니라 설계의 경계입니다. MCP 서버가 약속하는 건 MCP 도구로는 값을 돌려주지 않는다는 것까지예요. 마운트된 .env는 1Password가 잠금 해제돼 있고 승인이 살아 있는 동안 어떤 프로세스든 읽을 수 있고, 1Password 문서도 파일을 읽는 프로세스를 구분하지 않는다고 밝히고 있습니다. 에이전트의 Bash도 그런 프로세스 중 하나일 뿐이죠. 플러그인의 훅 역시 마운트가 제대로 돼 있는지만 검사하고 이 명령은 그대로 통과시켰습니다.
[validate-mounted-env-files] Local .env file is valid and enabled
[validate-mounted-env-files] Decision: pass (no decision reported; normal permission flow applies)
그러니 값이 에이전트 문맥에 들어가는 걸 막고 싶다면 장치를 더 둬야 합니다. 우선 클로드 코드 권한 설정에서 Read(./.env)를 deny로 막아 내장 Read 도구가 읽지 못하게 할 수 있습니다. 하지만 클로드 코드 권한 설정에서 다뤘듯이 이 규칙은 Bash 하위 프로세스에는 적용되지 않아요. 셸까지 막으려면 클로드 코드 샌드박스로 파일 접근 자체를 제한해야 합니다. 그리고 1Password의 자동 잠금 시간을 짧게 잡아 두면 승인이 살아 있는 시간도 그만큼 줄어듭니다.
결국 1Password MCP 서버는 에이전트에게 시크릿을 숨기는 도구라기보다, 디스크에 평문 .env가 남지 않게 하고 에이전트의 작업마다 사람의 승인을 끼워 넣는 도구에 가깝습니다. 이 차이를 알고 쓰면 기대와 실제가 어긋날 일이 없습니다.
서비스 계정과는 무엇이 다를까?
1Password에는 자동화를 위한 길이 하나 더 있습니다. 1Password 서비스 계정으로 Touch ID 없이 시크릿 관리하기에서 다룬 서비스 계정이에요. 둘은 겹치는 것 같지만 푸는 문제가 다릅니다.
| 구분 | 서비스 계정 | MCP 서버 |
|---|---|---|
| 주 사용자 | 사람 없이 도는 스크립트, CI | 사람과 함께 일하는 AI 에이전트 |
| 인증 | OP_SERVICE_ACCOUNT_TOKEN 토큰 | 데스크톱 앱 승인 창(Touch ID) |
| 시크릿 값 접근 | op read로 값을 꺼냄 | 도구로는 꺼낼 수 없음 |
| 다루는 대상 | 볼트의 항목 | Environments와 로컬 .env 마운트 |
| 동작 조건 | 토큰만 있으면 어디서나 | 데스크톱 앱이 실행 중이고 잠금 해제 상태 |
Discord MCP 서버처럼 프로세스를 띄울 때 토큰 값이 꼭 필요하다면 여전히 서비스 계정과 op read가 맞는 도구입니다. 반대로 에이전트에게 프로젝트의 환경 변수 구성을 맡기되 값 관리는 1Password에 두고 싶다면 MCP 서버가 어울립니다. 터미널에서 op로 시크릿을 다루는 기본기는 1Password CLI 사용법을 참고하세요.
마치며
1Password MCP 서버를 클로드 코드에 연결해서 평문 .env를 Environment로 옮기고, 같은 자리에 명명된 파이프로 마운트하는 과정까지 따라가 봤습니다. 앱에서 MCP 연동을 먼저 켜고 플러그인은 그다음에 설치해야 15분 캐시에 걸리지 않는다는 점, 승인이 계정과 Environment 두 단계로 나뉜다는 점도 확인했죠.
다만 “MCP 도구가 값을 돌려주지 않는다”와 “에이전트가 값을 볼 수 없다”는 다른 이야기였습니다. 마운트된 .env는 잠금이 풀린 동안 누구나 읽을 수 있으니, 정말 숨기고 싶은 값이라면 권한 규칙과 샌드박스를 함께 챙기세요.
더 자세한 내용은 1Password Environments MCP Server 공식 문서를 참고하세요.
This work is licensed under CC BY 4.0