들어가며
32차시에서 MCP의 어휘를 잡았다 — host/client/server, 데이터·전송 레이어, 세 primitive(Tools/Resources/Prompts), 세 전송 방식, 그리고 claude mcp add로 첫 서버를 붙이는 흐름. 그 차시 끝에서 GitHub·Sentry·Notion·PostgreSQL을 잠깐씩 보여 주긴 했지만, “연결 명령을 외우는 것”이 목표는 아니었다.
이번 33차시는 그 명령들을 실전에서 가장 많이 붙이는 서버로 옮긴다. 그런데 서버를 하나씩 늘어놓기 전에, 한 가지를 먼저 못 박고 가야 한다.
서버마다 claude mcp add 명령은 거의 똑같다. 실제로 갈리는 건 인증 방식이다.
이게 이 차시의 뼈대다. Sentry를 붙이든 GitHub를 붙이든 PostgreSQL을 붙이든, 명령의 모양은 32차시에서 본 그대로다. 막히는 지점은 항상 “이 서버는 어떻게 로그인하나”다. 그래서 이 차시는 서버를 알파벳순이 아니라 세 가지 인증 패턴으로 묶는다.
| 패턴 | 인증 | 대표 서버 |
|---|---|---|
| 1. OAuth 브라우저 로그인 | URL 등록 → /mcp → Authenticate → 브라우저 | Sentry, Notion, Linear |
| 2. 헤더에 정적 토큰 | --header "Authorization: Bearer ..." | GitHub |
| 3. stdio로 자격증명 싣기 | DSN·--env에 자격증명 직접 | PostgreSQL, Airtable |
이 셋을 구분하면 처음 보는 서버도 어디에 속하는지만 알면 바로 붙일 수 있다. Slack은 이 셋 위에 얹히는 특수 케이스 하나로 따로 다룬다.
세 패턴에 들어가기 전에, 인증이 전혀 없는 서버로 흐름을 먼저 검증하자.
워밍업 — 인증 없는 서버로 흐름부터 확인
새 서버를 붙일 때 가장 답답한 건 “연결이 안 됐는데 명령이 틀린 건지 인증이 안 된 건지 모르겠다”는 상황이다. 그래서 첫 연결은 인증이 없는 서버로 하는 게 좋다. 명령이 맞으면 곧장 연결되니, 흐름 자체를 검증할 수 있다.
Claude Code 공식 문서 서버가 딱 그 용도다. Claude Code 문서 전체를 전문 검색하는 호스팅 서버인데, 인증도 설정도 필요 없다.
claude mcp add --transport http claude-code-docs https://code.claude.com/docs/mcp
붙인 뒤 상태를 본다.
$ claude mcp list
claude-code-docs ✓ Connected
✓ Connected가 뜨면 명령 구문·전송 방식·네트워크가 모두 정상이라는 뜻이다. 이 상태에서 세션을 열고 시켜 본다.
> claude-code-docs 서버로 MCP_TIMEOUT이 뭐 하는 건지 찾아줘
평소엔 프롬프트에서 서버 이름을 댈 필요가 없다 — Claude가 알아서 관련 도구를 고른다. 여기선 이 답이 새 MCP 서버를 거쳐 나왔다는 걸 확인하려고 일부러 이름을 박았다. Claude 출력의 도구 호출에
claude-code-docs라벨이 붙으면 서버를 거친 것이다.
이 흐름 — add → list로 상태 확인 → 세션에서 사용 — 은 어떤 서버든 동일하다. 인증이 필요한 서버는 여기에 “브라우저 로그인” 한 단계가 끼는 것뿐이다. 그게 패턴 1이다.
claude mcp list의 상태 표시
앞으로 계속 볼 상태값들이다. 연결이 막혔을 때 어디서 막혔는지를 이 표시가 말해 준다.
| 상태 | 의미 |
|---|---|
✓ Connected | 정상. 바로 쓸 수 있다 |
! Needs authentication | 서버엔 닿았지만 브라우저 로그인이나 --header 토큰이 필요 |
✗ Failed to connect | 서버가 응답하지 않음 |
✗ Connection error | 연결 시도가 오류를 던짐 |
⏸ Pending approval | project 스코프 서버인데 아직 승인 안 함 |
! Needs authentication은 나쁜 신호가 아니다 — “명령은 맞았고 이제 로그인만 하면 된다”는 뜻이다. 패턴 1 서버를 붙이면 항상 이 상태를 한 번 거친다.
패턴 1 — OAuth 브라우저 로그인 (Sentry · Notion · Linear)
SaaS의 공식 MCP 서버가 압도적으로 많이 쓰는 방식이다. 흐름이 단순하다.
claude mcp add --transport http <name> <url>— URL만 등록claude mcp list→! Needs authentication- 세션에서
/mcp→ 서버 선택 →Authenticate - 브라우저가 열리고 해당 서비스에 로그인 → 승인
- Claude Code로 돌아오면
✓ Connected
토큰은 안전하게 저장되고(macOS는 시스템 키체인) 만료 시 자동 갱신된다. /mcp의 Clear authentication으로 권한을 회수할 수 있다. 추가 명령에는 인증이 들어 있지 않다 — claude mcp add는 서버 등록까지만 하고, 로그인은 세션 안 /mcp에서 마무리한다는 점이 핵심이다.
Sentry — 에러 모니터링
OAuth 패턴의 교과서 같은 예다.
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
그다음 세션에서 /mcp → sentry → Authenticate → 브라우저에서 Sentry 로그인. 연결되면 자연어로 시킨다.
> 최근 24시간 동안 가장 흔한 에러가 뭐야?
> 에러 ID abc123의 스택트레이스를 보여줘
> 이 새 에러들을 만든 배포가 어떤 거야?
마지막 질문이 MCP의 진가다 — “어떤 배포가 이 에러를 유입시켰나”는 Sentry의 릴리스 데이터와 에러를 교차해야 나오는 답이다. 사람이 대시보드를 뒤지며 맞춰 보던 걸 한 문장으로 시킨다.
Notion — 문서·위키
claude mcp add --transport http notion https://mcp.notion.com/mcp
동일하게 /mcp → Authenticate. 연결 후엔 워크스페이스의 문서를 읽고 쓰게 시킬 수 있다.
> 이번 스프린트 회고 페이지를 찾아서 액션 아이템을 요약해줘
> 방금 만든 API 변경사항을 "API Changelog" 페이지에 추가해줘
Linear — 이슈 트래킹
Linear도 같은 패턴이지만 두 가지를 짚는다.
claude mcp add --transport http linear-server https://mcp.linear.app/mcp
첫째, 공식 문서가 서버 이름으로 linear-server를 쓴다 — 이름은 사용자가 정하는 라벨이라 linear로 해도 동작은 같지만, 문서 예시를 그대로 따른다. 둘째, Linear의 MCP 서버는 OAuth 2.1 + 동적 클라이언트 등록(DCR) 을 쓴다. 무슨 뜻이냐면 — 별도로 OAuth 앱을 만들어 client ID를 발급받을 필요 없이, /mcp → Authenticate 한 번으로 끝난다는 것이다. (반대로 32차시에서 본 --client-id/--client-secret 사전 등록 방식은 DCR을 지원하지 않는 서버에서만 필요하다.)
> 나한테 할당된 이슈 중 이번 주 마감인 것들을 보여줘
> ENG-1042 이슈의 내용대로 구현하고 끝나면 상태를 In Review로 바꿔줘
Linear는 헤더에 토큰을 직접 넣는 방식(
Authorization: Bearer <token>)도 지원한다. 하지만 대화형으로 쓸 때는 OAuth가 더 간단하다. 헤더 토큰은 CI처럼 브라우저를 못 띄우는 환경에서 의미가 있다 — 그게 다음 패턴이다.
패턴 2 — 헤더에 정적 토큰 (GitHub)
일부 서버는 OAuth 대신 미리 발급한 토큰을 HTTP 헤더에 실어 인증한다. GitHub의 원격 MCP 서버가 대표적이다.
# 1. https://github.com/settings/personal-access-tokens 에서
# fine-grained PAT 발급 (Claude가 다룰 저장소에만 권한 부여)
# 2. 토큰을 헤더로 전달
claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \
--header "Authorization: Bearer YOUR_GITHUB_PAT"
여기서 중요한 건 fine-grained PAT를 쓰고, Claude가 작업할 저장소에만 권한을 좁히는 것이다. PAT는 그 자체로 GitHub 계정의 권한을 들고 있으니, 범위를 최소화하는 게 보안의 핵심이다. (GitHub의 원격 서버는 OAuth도 지원하지만, 공식 Claude Code 문서가 안내하는 방식은 이 PAT-헤더 방식이다.)
연결 후엔 자연어로 시킨다.
> PR #456을 리뷰하고 개선점을 제안해줘
> 방금 찾은 버그를 새 이슈로 만들어줘
> 나한테 할당된 열린 PR을 전부 보여줘
헤더가 거부되면 OAuth로 폴백하지 않는다 — 함정
이 패턴에서 가장 헷갈리는 지점이다. 일반적으로 서버가 401/403을 반환하면 Claude Code는 “인증이 필요하다”고 보고 OAuth 흐름을 띄운다. 그런데 headers.Authorization을 직접 설정해 둔 경우는 다르다. 서버가 그 헤더를 거부하면, Claude Code는 OAuth로 폴백하지 않고 연결을 곧장 failed로 떨군다.
이유는 분명하다 — “토큰을 줬는데 거부당했다”는 건 설정 오류지 “로그인이 필요하다”가 아니기 때문이다. 그러니 GitHub 연결이 failed로 뜨면 십중팔구 PAT가 잘못됐거나 만료됐거나 권한이 부족한 것이다. 토큰을 고치거나, 헤더를 빼고 OAuth 흐름을 쓰면 된다.
헤더 패턴은 GitHub 전용이 아니다
--header는 토큰 인증을 쓰는 어떤 HTTP 서버에든 쓴다. 사내 API 서버를 붙일 때도 같다.
claude mcp add --transport http secure-api https://api.example.com/mcp \
--header "Authorization: Bearer your-token"
헤더에 토큰을 평문으로 박는 게 꺼림칙하면, 32차시에서 본
.mcp.json의 환경 변수 확장(Bearer ${API_KEY})으로 분리할 수 있다. 토큰 자체를 동적으로 발급해야 하면headersHelper로 연결 시점에 스크립트를 돌려 헤더를 생성하는 방법도 있다 — 이건 35차시에서 다룬다.
패턴 3 — stdio로 자격증명 싣기 (PostgreSQL · Airtable)
앞의 둘은 원격(HTTP) 서버였다. 이 패턴은 다르다. Claude Code가 로컬에서 자식 프로세스로 서버를 직접 띄우고, 자격증명을 그 실행 명령에 실어 넘긴다. OAuth도 헤더도 없다.
PostgreSQL — @bytebase/dbhub
claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \
--dsn "postgresql://readonly:pass@prod.db.com:5432/analytics"
-- 뒤가 Claude Code가 실제로 띄울 명령이다(32차시에서 본 옵션 순서 규칙 그대로 — 옵션은 이름 앞, 명령은 -- 뒤). @bytebase/dbhub는 PostgreSQL뿐 아니라 MySQL·MariaDB·SQL Server·SQLite까지 지원하는 가벼운 DB 게이트웨이 MCP 서버다. read-only 모드, 행 수 제한, 쿼리 타임아웃 같은 가드레일을 내장한다.
연결 후엔 SQL을 한 줄도 안 쓰고 묻는다.
> 이번 달 총 매출이 얼마야?
> orders 테이블 스키마를 보여줘
> 최근 90일간 구매가 없는 고객을 찾아줘
여기서 DSN이 곧 보안 경계다
이 패턴의 핵심을 놓치면 안 된다. 패턴 1·2의 OAuth·PAT는 서비스가 권한을 통제했다. 패턴 3에는 그런 중간 인증층이 없다. Claude가 가지는 권한은 DSN에 적힌 DB 사용자의 권한 그 자체다.
그래서 위 예시가 readonly라는 사용자를 쓴 게 우연이 아니다. 프로덕션 DB를 붙일 때는 반드시 읽기 전용(read-only) 사용자로 연결해야 한다. 그래야 Claude가 — 혹은 prompt injection으로 조작된 요청이 — DROP TABLE이나 UPDATE를 시도해도 DB 단에서 막힌다. MCP가 막아 주는 게 아니라 DB의 권한 설정이 막는 것이다.
Airtable — stdio + --env API 키
같은 stdio 패턴이지만 자격증명을 DSN이 아니라 환경 변수로 넘기는 변형이다.
claude mcp add --transport stdio --env AIRTABLE_API_KEY=YOUR_KEY airtable \
-- npx -y airtable-mcp-server
--env KEY=value는 서버 이름 앞에 온다(이것도 옵션이라 -- 앞이다). stdio 서버는 Claude Code의 셸 환경을 자동으로 상속하지 않는 경우가 있으니, 필요한 자격증명은 --env로 명시적으로 넘기는 게 안전하다.
stdio 서버를 처음 띄울 때
✗ Failed to connect가 잠깐 뜰 수 있다 —npx가 패키지를 내려받는 중이라 그렇다. 잠시 뒤claude mcp list를 다시 돌리면 연결된다. 그래도 안 되면MCP_TIMEOUT=60000 claude로 시작 타임아웃을 늘린다.
Slack — 플러그인으로 배포되는 OAuth 서버
Slack은 앞의 세 패턴 위에 얹히는 특수 케이스다. 내부적으로는 패턴 1과 같은 HTTP OAuth 서버(https://mcp.slack.com/mcp)지만, Slack이 권장하는 설치 방식은 공식 플러그인이다.
claude plugin install slack
플러그인이 OAuth client ID와 콜백 포트를 미리 채워 두고, 로딩될 때 Slack 워크스페이스 OAuth 로그인을 띄운다. 직접 HTTP 서버로 붙이는 것도 가능하다.
claude mcp add --transport http slack https://mcp.slack.com/mcp
둘 중 무엇으로 붙이든 두 가지 전제 조건이 있다.
- 워크스페이스 admin 승인 — Slack의 MCP 통합은 워크스페이스 관리자가 허용해 둬야 개인이 연결할 수 있다. 회사 Slack이라면 본인 권한만으로는 안 될 수 있다.
- OAuth 스코프 — Slack은 넓은 권한을 요구할 수 있다. 보안팀이 승인한 최소 범위로 고정하려면
.mcp.json에서 스코프를 핀으로 박는다.
{
"mcpServers": {
"slack": {
"type": "http",
"url": "https://mcp.slack.com/mcp",
"oauth": {
"scopes": "channels:read chat:write search:read"
}
}
}
}
oauth.scopes는 공백으로 구분한 단일 문자열이고, 서버가 광고하는 스코프보다 우선한다. 즉 “이 서버에 줄 권한은 딱 이만큼”을 사용자가 강제할 수 있다. 비워 두면 서버가 요구하는 전체 스코프를 받는다.
> #incidents 채널에서 오늘 올라온 알림을 요약해줘
> 방금 만든 PR 링크를 #dev 채널에 공유해줘
진짜 가치 — 여러 서버를 한 문장으로 엮기
서버를 하나씩 붙이는 법을 봤으니, 왜 여럿을 붙이는지를 본다. MCP의 진가는 서버 하나가 아니라 여럿이 동시에 연결됐을 때 나온다. Claude가 자연어 요청을 보고 어떤 서버의 어떤 도구를 어떤 순서로 부를지 스스로 정한다.
공식 문서의 예시들이 이걸 그대로 보여 준다.
> JIRA 이슈 ENG-4521에 적힌 기능을 구현하고 GitHub에 PR을 만들어줘
> Sentry와 Statsig에서 ENG-4521 기능의 사용량을 확인해줘
> PostgreSQL에서 ENG-4521 기능을 쓴 사용자 10명의 이메일을 찾아줘
> Slack에 올라온 새 Figma 디자인으로 이메일 템플릿을 업데이트해줘
> 이 10명에게 피드백 세션 초대 Gmail 초안을 만들어줘
첫 줄 하나만 풀어 보자. “JIRA 이슈를 구현하고 GitHub에 PR을 만들어줘” 는 — JIRA 서버에서 이슈 본문을 읽고(Resources/Tools), 코드를 작성하고(내장 Edit 도구), GitHub 서버로 PR을 생성(Tools)하는 세 단계다. 사용자는 도구 이름도, 호출 순서도 짤 필요가 없다. 이게 32차시에서 말한 “사용자가 데이터를 떠 먹이는 흐름의 종료”의 실제 모습이다.
여기서 인증 패턴이 다시 의미를 가진다. 이 한 줄이 동작하려면 JIRA·GitHub·Sentry·PostgreSQL·Slack이 각자의 방식으로 인증돼 있어야 한다 — JIRA·Sentry는 OAuth, GitHub는 PAT 헤더, PostgreSQL은 read-only DSN. 패턴을 구분해 둔 이유가 이것이다.
어느 스코프에 붙일까 (34차시 예고)
서버를 붙일 때마다 따라오는 질문이 “이걸 --scope를 뭘로 줘야 하나”다. 32차시에서 셋을 정의했으니, 이번 차시의 서버들에 실전 기준만 짧게 적는다.
| 스코프 | 이 차시 서버 중 |
|---|---|
| local(기본) | 실험 중이거나 나만 쓰는 개인 DB·도구 |
| user | 모든 프로젝트에서 쓰는 개인 도구 (예: 내 Sentry, 내 Linear) |
| project | 팀 전원이 공유해야 하는 서버 (.mcp.json에 커밋) |
GitHub PAT나 DB 비밀번호처럼 개인 자격증명이 명령에 들어가는 서버는 project 스코프(.mcp.json git 커밋)에 그대로 넣으면 안 된다 — 평문 시크릿이 저장소에 올라간다. 팀 공유가 필요하면 자격증명은 환경 변수로 분리하고 .mcp.json엔 변수 이름만 둔다. 스코프의 저장 위치·우선순위·승인 흐름은 34차시에서 깊게 다룬다.
서버가 안 붙을 때 — curl로 서버가 살아 있는지부터
연결이 ✗ Failed to connect로 뜨면, 문제가 내 설정인지 서버 쪽인지부터 갈라야 한다. HTTP 서버는 curl -I로 1초 만에 확인된다.
curl -I https://mcp.sentry.dev/mcp
응답 코드가 문제의 종류를 말해 준다.
404또는405— 서버는 살아 있다. 많은 MCP 엔드포인트가 POST만 받기 때문에 이게 정상이다. 즉 URL·네트워크는 정상이고 다른 문제다.401또는403— 서버는 살아 있고 인증이 필요하다. 패턴 1이면/mcp→Authenticate, 패턴 2(GitHub류)면--header로 토큰을 넘긴다.- 응답 없음 — URL이 틀렸거나 네트워크 문제다.
PowerShell에서는
curl이Invoke-WebRequest의 별칭이라, 진짜 curl을 부르려면curl.exe를 써야 한다.
stdio 서버라면 curl 대신 설정된 명령을 터미널에서 직접 돌려 본다. 예컨대 dbhub라면 npx -y @bytebase/dbhub --dsn "..."를 직접 실행해 본다. 명령이 떠서 입력을 기다리면 서버 자체는 정상이니 — 이땐 -- 구분자를 빠뜨렸을 가능성이 높다. claude mcp get <name>으로 등록된 명령이 의도한 것과 같은지 확인한다.
흔한 함정
- 인증이 필요 없는 서버로 흐름을 먼저 검증해라 —
claude-code-docs로add→list→사용이 도는지 확인한 뒤 실전 서버로 넘어가면, 명령 오류와 인증 미완료를 헷갈리지 않는다. ! Needs authentication은 정상 신호다 — 패턴 1 서버는 항상 이 상태를 거친다.claude mcp add다음/mcp→Authenticate로 마무리.- GitHub는 PAT를 헤더에 박는다 (OAuth 아님) — 그리고 헤더가 거부되면 OAuth로 폴백하지 않고
failed로 떨어진다.failed면 토큰 문제다. - fine-grained PAT를 필요한 저장소에만 — PAT는 계정 권한을 그대로 들고 있다. 범위 최소화가 보안의 핵심.
- 프로덕션 DB는 read-only 사용자로 — stdio DB 서버에선 DSN의 DB 사용자 권한이 곧 보안 경계다. MCP가 막아 주지 않는다.
- stdio 서버의 첫 연결은 느릴 수 있다 —
npx가 패키지를 받는 동안failed로 보일 수 있다. 잠시 뒤 다시list하거나MCP_TIMEOUT을 늘려라. --env·--header·--transport는 이름 앞, 실제 명령은--뒤 — 32차시의 옵션 순서 규칙은 이 차시 서버 전부에 똑같이 적용된다.- Slack은 워크스페이스 admin 승인이 먼저 — 본인 권한만으론 연결이 안 될 수 있다. OAuth 스코프는
oauth.scopes로 좁혀라. project스코프에 평문 시크릿 금지 —.mcp.json은 git에 올라간다. PAT·DB 비번은 환경 변수로 분리.- 안 쓰는 서버는 제거해라 — 연결된 서버마다 도구 이름·서버 instruction이 매 세션 컨텍스트에 로드된다.
claude mcp remove <name>로 정리하면 컨텍스트가 그만큼 빈다. (서버가 많아질 때의 근본 해법인 Tool Search는 36차시에서.) curl -I로 서버 생사부터 —404/405=정상(살아 있음),401/403=인증 필요, 무응답=네트워크.- Anthropic Directory ≠ 보안 감사 — Directory 등록은 심사지 코드 감사가 아니다(32차시). 신뢰할 수 있는 출처의 서버만 붙여라. 외부 콘텐츠(이슈 본문 등)를 가져오는 서버는 prompt injection 위험이 있으니 30차시의 PreToolUse Hook을 함께 건다.
정리
핵심 요점
- 서버마다 명령은 비슷하고, 갈리는 건 인증이다 — 이 한 가지를 잡으면 처음 보는 서버도 패턴만 알면 붙인다.
- 패턴 1 — OAuth 브라우저 로그인 (Sentry·Notion·Linear). URL 등록 →
/mcp→Authenticate. Linear는 OAuth 2.1 + DCR이라 사전 앱 등록이 필요 없다. - 패턴 2 — 헤더에 정적 토큰 (GitHub). fine-grained PAT를
--header로. 헤더가 거부되면 OAuth로 폴백하지 않고failed— 토큰 문제라는 신호. - 패턴 3 — stdio로 자격증명 싣기 (PostgreSQL·Airtable). DSN·
--env에 직접. DB 사용자 권한이 곧 보안 경계 → read-only 원칙. - Slack은 특수 케이스 — HTTP OAuth 서버지만 공식 플러그인(
claude plugin install slack)으로 배포되고, 워크스페이스 admin 승인이 필요하다. - 워밍업은 인증 없는 서버로 —
claude-code-docs로 흐름을 먼저 검증. - 진짜 가치는 여러 서버를 한 문장으로 엮을 때 — JIRA→GitHub→Sentry→PostgreSQL→Slack을 Claude가 스스로 오케스트레이션한다.
- 막히면
curl -I로 서버 생사부터 —404/405=정상,401/403=인증, 무응답=네트워크.
다음 단계
다음 34차시는 MCP 서버 관리다. 이번에 붙인 서버들을 claude mcp list/get/remove로 다루는 법, 그리고 이 차시 내내 미뤄 둔 스코프(local/project/user)가 어디에 저장되고 어떻게 우선순위가 정해지는지, project 스코프의 승인 흐름까지 깊게 본다. 35차시는 .mcp.json 설정과 환경 변수 확장 — 이번에 본 평문 시크릿 문제의 해법이다. 36차시는 MCP 리소스(@ 멘션)와 Tool Search — 서버가 많아질 때 컨텍스트를 지키는 방법이다.
참고 자료
- Claude Code MCP 공식 문서 (전체 레퍼런스)
- MCP 연결 퀵스타트 (첫 서버 붙이기·트러블슈팅)
- Anthropic Directory (검토된 커넥터 목록)
- Linear MCP 서버 문서
- Slack MCP 서버 — Claude 연결 문서
- GitHub 공식 MCP 서버 (github/github-mcp-server)
- GitHub fine-grained PAT 발급
- DBHub — DB용 MCP 서버 (bytebase/dbhub)
- Claude Code Security (MCP 위험 모델·prompt injection)
- MCP 레퍼런스 서버 모음 (GitHub)