AI가 낡은 문서로 코딩하지 않게 해 주는 Context7, 설치법과 한계
Tools17분 읽기

AI가 낡은 문서로 코딩하지 않게 해 주는 Context7, 설치법과 한계

Context7은 코딩 에이전트가 프롬프트에 넣을 라이브러리의 버전별 문서를 질문마다 가져옵니다. 호출 흐름, 후보 고르기, 순위별 갱신 주기, 월 1,000회 한도, 문서가 지시가 되는 위험을 따라갑니다.

코딩 에이전트는 왜 이미 사라진 옵션을 그렇게 자신 있게 쓸까요? 모델이 부주의해서가 아니라 기억에 날짜가 박혀 있기 때문입니다. Next.js 16에서는 middleware.ts라는 파일 규칙의 이름이 proxy.ts로 바뀌었습니다. 이름이 바뀌기 전의 자료로 배운 모델에게 proxy.ts는 낯선 파일명이고, 이 낯섦을 메우는 일을 하는 도구가 Context7입니다.

Context7은 서버리스 데이터 서비스 업체 Upstash가 만들었습니다. 에이전트가 코드를 쓰기 전에 해당 라이브러리의 버전별 문서 조각을 받아 프롬프트에 넣어 줍니다. UTC 2026-10-26 기준으로 GitHub 별 63,718개, 포크 3,142개, MIT 라이선스이고 저장소는 2025-03-26에 만들어졌습니다. npm의 @upstash/context7-mcp 최신판은 4.4.4(10월 19일 게시)로 10월 16~22일 한 주 동안 내려받기가 약 44만 회였고, 명령줄 도구 ctx7는 0.8.2(10월 23일)입니다. 이 글은 설치 순서가 아니라 질문 하나를 따라갑니다. 그 문서는 어디서 와서, 얼마나 자주 새로워지고, 어떤 길로 프롬프트에 닿으며, 그 길에서 무엇을 조심해야 할까요.

이름이 바뀐 API는 모델의 기억에 없다

모델의 지식은 학습이 끝난 시점에서 멈춥니다. 라이브러리는 그 뒤에도 릴리스를 계속 냅니다. Context7 README는 이 간극에서 생기는 문제를 세 가지로 꼽습니다. 해묵은 예제, 존재하지 않는 API, 오래된 버전에 맞춘 답입니다. 세 번째가 까다로운 이유는 사용자가 쓰는 버전을 질문에 적어도 그 버전의 문서가 모델 안에 없으면 근거가 되지 못하기 때문입니다.

Next.js 16의 개명은 이 간극의 좋은 표본입니다. 편집부가 Context7에 /vercel/next.js/v16.2.9를 대상으로 “middleware 파일 규칙이 proxy로 바뀌었나”를 물었더니 업그레이드 가이드에서 잘라 온 조각이 돌아왔습니다. 파일 이름을 바꾸는 mv middleware.ts proxy.ts, 내보내기 이름 middleware도 proxy로 바꿔야 한다는 설명, 설정 플래그 skipMiddlewareUrlNormalize가 skipProxyUrlNormalize가 되었다는 설명, 그리고 이 변경을 자동으로 적용하는 middleware-to-proxy 코드모드가 들어 있었습니다. 기억에서 꺼낸 답과 문서에서 받은 답이 갈리는 지점이 바로 이런 이름 변경입니다.

쉽게 말하면

2년 전 판본의 요리책을 통째로 외운 요리사에게 오늘 들어온 주문을 맡기는 일과 같습니다. 대부분은 맞게 만들지만 그사이 바뀐 재료나 화력 설정은 자신 있게 틀립니다. Context7은 주문이 들어올 때마다 해당 요리의 최신 레시피 카드를 옆에서 꺼내 주는 조수입니다. 요리사의 실력은 그대로이고 참고하는 자료만 바뀝니다.

바뀌는 것은 모델이 아니라 프롬프트에 들어가는 자료라는 점을 기억해 두면 이 글의 나머지가 쉬워집니다. 자료가 낡았거나 틀렸다면 결과도 그만큼 낡거나 틀립니다. 그래서 이어지는 절은 자료가 어떻게 고르고, 쌓이고, 새로워지고, 믿을 만한지를 순서대로 봅니다.

질문 한 줄이 문서 조각 다섯 개로 돌아오기까지

사용자가 프롬프트에 use context7을 적거나 규칙이 걸려 있으면 에이전트는 코드를 쓰기 전에 도구를 두 번 부릅니다. 먼저 resolve-library-id에 라이브러리 이름(“Next.js”)과 사용자의 질문을 넘겨 Context7의 ID(/vercel/next.js 꼴)를 얻습니다. 그다음 query-docs에 그 ID와 한 개념으로 좁힌 질문을 넘기면 문서 조각과 코드 예제가 돌아옵니다. 질문을 두 번 보내는 이유는 이름만으로는 어느 라이브러리인지 정해지지 않기 때문입니다(다음 절).

그림 1에서 눈으로 따라갈 것은 화살표의 방향입니다. 사용자의 프롬프트는 에이전트까지만 가고, MCP 도구와 API로 나가는 것은 에이전트가 만든 이름과 질문입니다.

사용자, 에이전트, MCP 도구, Context7 API, 색인 사이에서 도구 호출 두 번이 오가는 순서 그림 1. 프롬프트 한 줄에서 현재 문서 기반 코드까지, 도구 호출 두 번의 순서

도구 설명문에는 모델에게 주는 지시가 들어 있습니다. 질문당 각 도구를 3번 넘게 부르지 말 것, query에 키나 비밀번호 같은 자격 증명을 넣지 말 것, 여러 주제는 나눠서 물을 것, 이름은 공식 표기(“Next.js”)로 쓸 것입니다. 두 도구는 REST 엔드포인트 하나씩에 대응하므로(GET /api/v2/libs/search, GET /api/v2/context) 에이전트 없이 터미널에서 같은 호출을 재현할 수 있습니다. 편집부가 UTC 2026-10-26에 키 없이 /vercel/next.js를 대상으로 호출한 결과는 이렇습니다.

GET /api/v2/context?libraryId=/vercel/next.js
    &query=proxy redirect unauthenticated users&type=txt
200 OK · text/plain · 약 8.4KB · 조각 5개

### Redirect with NextResponse.redirect in proxy
Source: https://github.com/vercel/next.js/blob/canary/docs/01-app/02-guides/redirecting.mdx
### Perform optimistic authentication checks in proxy
Source: https://github.com/vercel/next.js/blob/canary/docs/01-app/02-guides/authentication.mdx
### Protected vs public routes in proxy (auth redirects)
### NextResponse.redirect in Proxy
### Optimistic checks with Proxy (Optional)

첫 조각은 export function proxy(request: NextRequest)로 시작해 NextResponse.redirect(new URL('/login', request.url))로 로그인하지 않은 사용자를 돌려보내고 matcher로 적용 경로를 정하는 코드였고, 같은 코드의 JavaScript 판이 이어졌습니다. 조각마다 출처 주소(Source)가 붙어 있어서 에이전트가 쓴 코드가 어느 문서에서 나왔는지 사람이 따라가 볼 수 있습니다. 버전이 붙은 ID /vercel/next.js/v16.2.9로 보낸 앞 절의 개명 질문에서는 출처 주소가 blob/v16.2.9/...였습니다. 버전이 붙은 ID는 그 태그의 문서를 가리킵니다.

같은 이름의 후보 다섯 중에서 고르는 기준

“Next.js”라는 이름을 GET /api/v2/libs/search에 넣으면 후보 목록이 옵니다. 같은 날 편집부가 libraryName=next.js, query=proxy로 받은 응답의 상위 다섯 개는 아래와 같습니다. 응답에는 ID, 설명, 기본 브랜치, 마지막 갱신 날짜, 조각 수, 별, 신뢰 점수(trustScore), 벤치마크 점수(benchmarkScore), 색인된 버전 목록이 들어 있습니다.

id                          갱신        조각    별       신뢰  벤치마크
/vercel/next.js             2026-10-25  6,160   131,745  9.7   77.61
/websites/nextjs            2026-10-14  6,876   (없음)   10    70.96
/websites/deepwiki_vercel_next_js  2026-09-04   734   (없음)  9.9   29.6
/(개인 계정)/next.js        2026-09-06  7,322   0        5.3   86.49
/auth0/nextjs-auth0         2026-10-23  2,537   2,180    9.7   82.74

그림 2는 같은 값을 두 점수의 평면에 놓은 것입니다. 오른쪽 위가 두 점수가 모두 높은 쪽입니다.

다섯 후보를 신뢰 점수(가로)와 벤치마크 점수(세로)로 놓은 산점도 그림 2. ‘next.js’ 검색 후보 다섯 개의 점수 분포(편집부가 2026-10-26 응답에서 옮김)

이 응답에서 벤치마크 점수가 가장 높은 후보(86.49)는 별이 0개이고 신뢰 점수가 5.3인, 개인 계정 아래의 저장소입니다. 반대로 공식 저장소는 신뢰 9.7에 벤치마크 77.61입니다. 점수 하나만 따라가면 엉뚱한 후보가 앞에 서는 구성입니다. resolve-library-id의 설명문이 이름 유사도, 출처 평판, 문서 조각 수, 벤치마크 점수, 질문과의 관련도를 함께 보고 고르라고 지시하는 것과 맞아떨어집니다. 또 질문에 라이브러리 이름만 있으면 /auth0/nextjs-auth0처럼 이름이 겹치는 다른 라이브러리가 후보에 섞입니다.

이 단계를 건너뛰는 방법도 있습니다. 슬래시로 시작하는 ID를 프롬프트에 직접 적으면 후보 고르기가 생략됩니다.

Implement basic authentication with Supabase. use library /supabase/supabase for API and docs.

ID는 /org/project 또는 /org/project/버전 꼴이고, 버전은 후보 응답의 versions 목록에서 확인합니다. Next.js 후보에는 v16.2.9, v16.2.2, v16.1.6, v15.1.8, v13.5.11 같은 태그가 올라 있었습니다. 요청한 버전이 색인에 없을 때의 규칙은 문서에 구체적으로 적혀 있습니다.

  • 숫자가 맞는 준비된 태그가 있으면 그것을 줍니다(15를 물으면 v15.1.8).
  • 없으면 요청한 계열에서 더 새로운 최신 안정판을 줍니다(2.0.0을 물으면 v2.3.1, 1.0 미만에서는 같은 마이너).
  • 그것도 없으면 라이브러리의 현재 문서를 줍니다.

대체가 일어나면 텍스트 응답 맨 앞에 버전 안내가 붙고 JSON 응답에는 version 객체가 실려, 받은 문서가 요청한 버전과 다르다는 것을 알 수 있습니다. 공개 GitHub 라이브러리에서 색인에 없던 버전은 백그라운드 색인 대기열에 올라서 나중 요청에 답할 수 있게 됩니다. 브랜치나 채널 이름(/owner/repo/canary)이 색인에 없거나 내줄 문서가 전혀 없으면 404 version_not_found입니다. 예전 버전에 묶인 프로젝트를 유지보수하는 사람은 이 안내가 붙었는지 한 번 확인하는 습관이 필요합니다. 최신 문서가 오히려 틀린 답이 되는 경우이기 때문입니다.

색인은 미리, 갱신은 요청이 올 때

문서가 프롬프트에 닿으려면 먼저 색인에 있어야 합니다. 공개 GitHub 저장소는 소유자가 아니어도 context7.com/add-library에서 주소를 넣어 추가할 수 있습니다. 파싱 대상은 문서 파일(.md, .mdx, .markdown, .rst, .txt, .ipynb)이고, 코드 예제와 설명을 뽑아 조각으로 만듭니다. 문서가 있으면 원본 소스 파일은 색인하지 않으며, 문서가 거의 없는 공개 저장소는 소스에서 예제를 생성합니다. 저장소 말고도 웹사이트(크롤링), OpenAPI 명세, llms.txt 주소가 소스가 될 수 있고, 팀스페이스 쪽 API에는 PDF·Word 파일, Confluence 공간, Notion 페이지도 있습니다.

Git 저장소·웹사이트·llms.txt가 파싱을 거쳐 색인으로 가고, 질문이 올 때 API가 색인을 읽으며 오래됐으면 갱신을 시작하는 구조 그림 3. 왼쪽은 질문 전에 해 두는 일, 오른쪽은 질문이 올 때 일어나는 일

그림에서 화살표가 한 곳에서 거꾸로 가는 점이 중요합니다. 질문을 받은 API가 색인을 읽는 동시에, 색인이 낡았다고 판단하면 파싱 쪽으로 갱신 신호를 보냅니다. 갱신이 스케줄이 아니라 요청에 끌려가는 구조입니다.

소유자는 저장소 루트의 context7.json으로 무엇을 어떻게 읽힐지 정합니다. 값은 예시입니다.

{
  "$schema": "https://context7.com/schema/context7.json",
  "projectTitle": "Example SDK",
  "description": "Example SDK의 공식 문서와 예제",
  "folders": ["docs"],
  "excludeFolders": ["docs/archive"],
  "previousVersions": [{ "tag": "v1.2.0" }]
}

folders와 excludeFolders가 겹치면 제외가 이기고, 아무것도 정하지 않으면 변경 기록·라이선스·보관 폴더·여러 번역 폴더가 기본으로 빠집니다. 이전 버전은 previousVersions(태그)나 branchVersions(브랜치)로 함께 올립니다. 이 파일의 rules는 보안 절에서 다시 나옵니다.

영어가 아닌 문서는 어떻게 되나요?

색인 대상 문서는 영어가 기준입니다. 주로 다른 언어로 쓰인 페이지는 건너뛰고, 모든 문서가 건너뛰어지면 언어 불일치 오류로 파싱이 실패합니다. 영어 문서가 없는 라이브러리에서는 기대한 효과를 얻기 어렵습니다.

인기 순위가 갱신 주기를 정한다

색인이 한 번 만들어졌다고 끝은 아닙니다. 라이브러리가 요청될 때마다 시스템은 문서의 마지막 갱신 시각을 보고, 그 라이브러리의 인기 순위별 기준보다 오래됐으면 백그라운드에서 갱신을 시작합니다. 사용자는 갱신이 끝나기를 기다리지 않고 현재 문서를 바로 받습니다. 그림 4의 막대는 요청이 갱신을 부르기 전까지 문서가 최대 얼마나 묵을 수 있는지를 보여 줍니다.

인기 상위 100위는 1일, 1,000위는 15일, 5,000위는 30일, 그 밖은 45일까지 묵을 수 있음을 보이는 범위 차트 그림 4. 순위별 갱신 기준(마지막 갱신으로부터 며칠). 웹사이트 라이브러리는 이 값보다 조금 높은 기준을 씁니다

막대의 길이가 곧 새 릴리스를 못 따라가는 최대 시간이라는 점이 읽을 거리입니다. 상위 100위 라이브러리는 하루면 갱신 대상이지만 순위 밖 라이브러리는 새 버전이 나와도 45일 동안 옛 문서를 줄 수 있습니다. 게다가 갱신은 최근에 요청된 라이브러리에만 일어나고 비공개 소스에는 자동 갱신이 없습니다. 방금 나온 버전을 쓴다면 로그인한 상태에서 라이브러리 페이지의 새로고침이나 POST /api/v1/refresh로 직접 갱신을 요청할 수 있고, 소유자가 라이브러리를 인증(claim)하면 이 요청의 한도가 늘어납니다.

소유자라면 푸시마다 갱신하게 만드는 편이 확실합니다. 문서의 GitHub Actions 예시는 기본 브랜치에 푸시가 올라올 때 갱신 API를 한 번 부르는 방식입니다.

name: Refresh Context7 Docs
on:
  push:
    branches: [master]   # 기본 브랜치 이름에 맞춰 바꿈
jobs:
  refresh:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Context7 Refresh
        run: |
          curl -s -X POST https://context7.com/api/v1/refresh \
            -H "Content-Type: application/json" \
            -H "Authorization: Bearer ${{ secrets.CONTEXT7_API_KEY }}" \
            -d '{"libraryName": "/${{ github.repository }}"}'

갱신이 실패했을 때의 안전장치도 문서화되어 있습니다. 웹사이트를 다시 크롤링했는데 이전 페이지의 10%도 읽지 못하면(예: 사이트가 크롤러를 막은 경우) 새 버전으로 바꾸지 않고 이전 버전을 유지한 채 나중에 다시 시도합니다. 저장소가 삭제되거나 접근할 수 없게 돼도 마지막 색인본을 계속 제공하다가, 하루 이상 지난 뒤의 갱신에서도 접근이 안 되면 라이브러리 페이지와 관리 화면에 알림을 띄웁니다. 오래된 문서가 조용히 사라지는 대신 마지막 상태로 남는 방향입니다.

프롬프트에 한 줄을 붙이기까지의 설정

설정에는 세 갈래가 있습니다. 가장 쉬운 길은 마법사이고, 이미 MCP 설정을 손보는 데 익숙하다면 수동 등록이 가장 투명합니다. 키가 필요 없는 길로는 Claude Code 플러그인이 있습니다. README 맨 위에는 Claude, ChatGPT, Cursor, VS Code의 등록 페이지로 이어지는 설치 버튼도 있습니다.

npx ctx7 setup                          # Node.js 22.13 이상. 로그인 후 키 생성, 스킬 또는 MCP 설치
npx ctx7 setup --claude                 # Claude Code용, 방식은 대화로 선택
npx ctx7 setup --cli --claude --yes     # CLI + 스킬 방식, 확인 질문 생략
npx ctx7 setup --mcp --cursor --project # MCP 방식, 현재 프로젝트에만
npx ctx7 remove --cursor --cli          # 되돌리기

CLI 모드는 에이전트가 ctx7 library·ctx7 docs 명령을 쓰게 하는 find-docs 스킬을 설치하고, MCP 모드는 두 도구를 가진 서버를 등록합니다. 로그인은 OAuth 기기 인증이라 인증 링크와 짧은 코드가 나오고 링크는 어느 기기에서 열어도 되므로, SSH로 붙은 서버나 화면 없는 호스트에서도 됩니다. 플러그인은 두 줄입니다.

/plugin marketplace add upstash/context7
/plugin install context7@context7-marketplace

재시작 뒤 /mcp에서 브라우저로 로그인합니다. 이 플러그인은 CONTEXT7_API_KEY 환경변수를 읽지 않으므로 키로 자동화해야 하는 호스트에서는 ctx7 setup이나 수동 등록을 씁니다. 수동으로 붙일 때의 공식 예시는 아래와 같습니다.

# Claude Code, 원격 서버
claude mcp add --scope user --header "Authorization: Bearer YOUR_API_KEY" --transport http context7 https://mcp.context7.com/mcp

# Claude Code, 로컬 서버
claude mcp add --scope user context7 -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY

JSON 설정 파일을 쓰는 클라이언트(Cursor의 ~/.cursor/mcp.json 등)는 "url": "https://mcp.context7.com/mcp"와 "headers": { "Authorization": "Bearer YOUR_API_KEY" }를 mcpServers.context7 아래에 넣습니다. Codex는 ~/.codex/config.toml, VS Code는 .vscode/mcp.json입니다. OAuth를 지원하는 클라이언트는 주소 끝을 /mcp/oauth로 바꾸면 키 없이 연결되는데, OAuth는 원격 HTTP 연결에서만 되고 로컬 실행(stdio)은 API 키를 씁니다. 같은 서비스에는 계정을 관리하는 별도 서버(https://admin.mcp.context7.com/mcp)도 있지만 이것은 팀스페이스·라이브러리·사용량을 다루는 용도이고, 문서를 조회하는 서버와 다릅니다.

연결한 뒤의 입력 습관은 세 가지가 효과를 좌우합니다. 버전을 적고(“Next.js 16”), 아는 라이브러리는 ID를 직접 적고, 질문을 한 개념으로 좁힙니다. 매번 use context7을 쓰기 귀찮다면 ctx7 setup이 설치한 스킬이 대신 켜 주고, 스킬이 없다면 CLAUDE.md나 Cursor의 Rules에 규칙 한 줄을 넣습니다.

라이브러리·API 문서, 코드 생성, 설정 방법이 필요하면 내가 말하지 않아도 항상 Context7을 사용해.

터미널에서 직접 시험할 수도 있습니다. library와 docs는 로그인 없이 동작하고 --json으로 결과를 받을 수 있으며, --language를 주면 그 언어의 예제를 먼저 배치합니다.

ctx7 library react "How to clean up useEffect with async operations"
ctx7 docs /vercel/next.js/v16.2.9 "How to set up app router" --language TypeScript
ctx7 library react "hooks" --json | jq '.[0].id'

앱에 넣으려면 REST도 있습니다. GET /api/v3/search는 라이브러리 ID 없이 질문 하나로 관련 라이브러리(힌트는 최대 4개)를 골라 조각을 돌려주고, GET /api/v2/context는 ID를 알 때 씁니다. type=json이면 코드 조각과 설명 조각이 순위(rank)와 함께 오고, fast=true는 LLM 순위 재조정을 건너뛰어 정확도를 조금 내주고 속도를 얻습니다. 키는 ctx7sk로 시작하는 문자열을 Authorization: Bearer 헤더로 보냅니다.

월 1,000회와 좌석당 2,000회

요금제는 호출 횟수 기준입니다. 요금제 문서의 정의로 호출 하나는 Search API 또는 context 요청 한 번입니다. 호출 단위가 요청이므로 한도는 질문 수가 아니라 요청 수로 줄어듭니다. 에이전트가 질문 하나에 도구를 두 번 부르면 요청도 두 번 나갑니다. Free는 월 1,000회, Pro는 좌석당 월 2,000회를 포함하며 Pro의 좌석마다 따로 계산되어 남은 호출을 다른 좌석으로 넘기지 못합니다.

Free 1,000회, Pro 1·3·5좌석의 월 포함 호출 2,000·6,000·10,000회를 가로 막대로 비교한 차트 그림 5. 월 포함 호출 수. Pro 좌석 수에 따른 값과 월 요금은 편집부 계산(좌석당 $10, 좌석당 2,000회)

Free의 월 1,000회는 30일로 나누면 하루 약 33회이고 Pro 한 좌석은 약 67회입니다(편집부 계산). 질문마다 요청이 두 번 나간다고 가정하면(가정) 하루 열 질문이 20회이므로 가벼운 개인 사용은 Free 안에서 지나갈 수 있습니다. 실제 소모량은 대시보드 Overview 탭의 Requests로 일주일쯤 본 뒤 요금제를 고르는 편이 정확합니다. 다른 점은 표로 보면 한눈에 갈립니다.

항목 Free Pro Enterprise
월 요금 $0 $10 / 좌석 맞춤
한도를 다 쓴 뒤 다음 달까지 막힘(하루 20회 보너스 호출) 막히지 않고 추가분 과금 막히지 않고 추가분 과금
추가 호출 없음 $5 / 1,000회 $5 / 1,000회
비공개 저장소 불가 파싱 100만 토큰당 $5 파싱 100만 토큰당 $5
팀스페이스 구성원 1명(개인) 최대 10명 제한 없음
규칙(rules) 불가 가능 가능
SSO·자체 호스팅·전담 지원 불가 불가 가능

Free 계정의 포함 항목에는 공개 라이브러리 전부, 라이브러리 소유자 도구, 웹사이트용 Context7 Ask(3개)와 문서 사이트 서비스 Docs7 Free(3개)도 들어 있습니다. 월 지출 한도를 걸어 둔 팀스페이스가 한도에 닿으면 402가 돌아옵니다.

키 없이도 동작하지만 한도가 다릅니다. 편집부가 키 없이 보낸 요청의 응답 헤더에는 context7-quota-tier: anonymous, ratelimit-limit: 200이 찍혔고, 호출할 때마다 ratelimit-remaining이 줄었으며 ratelimit-reset은 UTC 2026-11-01 00:00이었습니다. 문서가 “낮은 한도”라고만 적은 부분의 실측 한 점이고, 한도는 조건에 따라 달라질 수 있습니다. 한도에 걸리면 429와 함께 Retry-After(초), RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset(Unix 시각) 헤더가 오므로 자동화에서는 이 값을 따라 기다리면 됩니다.

문서를 먹이는 다른 길

문서를 에이전트에 닿게 하는 길은 Context7만이 아닙니다. 가져오는 단위를 기준으로 나란히 놓으면 역할이 갈립니다.

방법 가져오는 단위 비용·인증 어울리는 때
공식 문서 주소를 직접 붙이기 사람이 고른 페이지 없음 확실한 출처 하나만 필요할 때, 매번 수동
llms.txt 사이트가 게시한 마크다운 안내 파일 없음 문서 사이트가 제공할 때
DeepWiki MCP 공개 저장소 하나의 위키 무료, 인증 없음(비공개는 별도 계정) 낯선 저장소의 구조를 파악할 때
Context7 라이브러리 이름·버전으로 찾은 문서 조각 무료 월 1,000회, 이후 Pro 여러 라이브러리의 버전별 사용법을 코딩 중에 계속 끌어올 때

llms.txt는 2024-09-03에 Jeremy Howard가 제안한 형식으로, 루트에 두는 마크다운 파일에 H1 제목과 링크 섹션을 적습니다. 게시하는 쪽이 만들어야 효과가 있습니다. DeepWiki MCP는 도구 세 개(위키 구조, 위키 내용, 질문)로 저장소 하나를 설명하고, Context7은 라이브러리의 사용법을 버전별 조각으로 가져옵니다. 둘은 경쟁이 아니어서 Context7은 llms.txt 주소를 색인 소스로 받을 수 있고, 문서 사이트가 llms.txt를 게시하면 Context7을 거쳐 에이전트에 닿는 길도 열립니다.

가져온 문서도 지시가 될 수 있다

Context7이 가져오는 문서는 사람이 쓴 글이면서 동시에 에이전트의 입력입니다. README도 프로젝트가 커뮤니티가 올린 것이라 정확성·완전성·보안을 보장하지 않는다고 밝히고, 의심스러운 내용은 프로젝트 페이지의 신고 버튼으로 알리게 합니다. 이 우려가 실제 사건으로 나타난 적이 있습니다. 2026-02-18에 보안업체 Noma의 연구팀 Noma Labs가 Context7의 맞춤 규칙(Custom Rules) 기능에서 찾은 문제(ContextCrush)를 Upstash에 알렸고, 보도에 따르면 다음 날 조치가 시작돼 2026-02-23에 규칙 정화와 추가 보호 장치가 도입됐습니다. 2026-03-05의 보도는 실제 공격에 쓰인 증거가 없다고 전했습니다.

문제의 구조는 단순했습니다. 라이브러리 소유자가 쓰는 규칙 문장이 걸러지지 않은 채 에이전트에 전달됐고, GitHub 계정만 있으면 라이브러리를 등록해 규칙에 지시를 심을 수 있었습니다. 연구팀의 시연에서는 에이전트가 .env 파일을 찾아 공격자의 저장소로 보내고 로컬 파일을 지우도록 유도됐습니다. 에이전트에게는 정당한 문서 지시와 악성 지시를 구별할 근거가 없었고, 당시 별은 약 5만 개, npm 내려받기는 800만 회를 넘겨 영향 범위가 넓었습니다. 신뢰 점수와 인기 배지가 조작될 수 있다는 지적도 함께 나왔습니다. 그림 2에서 본 점수들이 후보를 고르는 근거라는 점을 생각하면 가볍게 넘길 지적이 아닙니다.

현재 문서가 설명하는 방어는 층이 여럿입니다.

  • 소유자가 context7.json에 적는 rules는 검토 후 적용됩니다. 자격 증명을 읽거나 데이터를 밖으로 보내거나 내려받은 스크립트를 실행하게 하는 규칙은 거부되고, 하나라도 거부되면 새 규칙이 모두 적용되지 않으며 기존 규칙도 제거됩니다. 제목·설명에도 광고나 에이전트 지시는 허용되지 않습니다.
  • 색인 문서에는 프롬프트 인젝션과 악성 패턴을 찾는 전용 분류기가 돌고, 의심 내용은 추가 검증과 지속 검토 대상이 됩니다. 탐지 정확도 수치는 공개되어 있지 않습니다.
  • 팀스페이스는 정책 탭에서 소스 종류를 끄거나 라이브러리를 품질 필터·수동 선택으로 제한하고 “검증된 것만” 쓰게 할 수 있습니다. 검증 배지는 신뢰 점수 9 이상이거나 사용량 상위 100위이면 자동으로 붙고, 그 밖에는 소유자가 신청합니다.

어떤 방어도 문서 한 줄의 의도를 완벽히 가려내지는 못하므로 마지막 관문은 사용자입니다. 에이전트가 문서를 읽은 뒤 갑자기 환경 파일을 열거나 외부 주소로 요청을 보내려 한다면 문서 출처를 의심할 신호입니다. 그 요청은 승인하지 말고, 중요한 변경은 병합 전에 직접 읽으세요.

반대 방향도 짚어야 합니다. Context7의 데이터 안내에 따르면 밖으로 나가는 것은 에이전트가 만든 질의(query), 라이브러리 이름 또는 ID, API 키(있다면), MCP 클라이언트 이름·버전, 전송 방식(stdio 또는 http), 속도 제한용 클라이언트 IP입니다. 전체 프롬프트와 소스 코드, 대화 기록은 전송하지 않고 소스 파일을 저장하지 않는다고 밝힙니다. 질의는 익명으로 저장되어 검색 품질 측정에 쓰이고(Enterprise 팀스페이스 제외) API 로그는 30일 보관됩니다.

내 코드가 Context7 서버로 올라가나요?

공식 안내대로라면 소스 코드와 전체 프롬프트는 전송되지 않습니다. 다만 질의는 문장이어서, 코드 조각이나 비밀 값을 질문에 풀어 쓰면 그대로 나갑니다. 질문은 “Next.js 16에서 쿠키 기반 인증 리다이렉트를 어떻게 하나”처럼 일반적인 형태로 쓰고, API 키는 환경변수에 두며 ctx7sk로 시작하는 키가 저장소에 커밋되지 않게 하세요. 환경별로 키를 나누고 노출됐다면 바로 폐기합니다.

연결이 안 될 때 확인하는 순서

설치가 안 될 때는 범위를 좁히는 순서가 있습니다. 먼저 원격 서버가 살아 있는지, 그다음 키, 그다음 라이브러리 ID, 마지막으로 클라이언트 로그입니다. 대부분 세 번째까지 가기 전에 끝납니다. 문서의 빠른 점검 목록은 Node.js 20 이상 확인, 패키지를 @upstash/context7-mcp@latest로 갱신, ping 확인, 한도에 걸렸다면 키 추가, 정보를 모을 때 DEBUG=* 켜기입니다.

curl https://mcp.context7.com/ping        # {"status": "ok", "message": "pong"} 이면 정상
claude mcp list                            # Claude Code의 연결 목록
claude mcp logs context7                   # 로그
npx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp   # 서버 단독 점검
증상 문서가 안내하는 조치
요청 시간 초과(macOS·Windows) Node 실행 파일과 설치된 패키지 경로를 절대 경로로 지정하거나, Windows는 cmd /c npx ...로 실행
ERR_MODULE_NOT_FOUND npx 대신 bunx(또는 deno)로 실행
인증서·TLS 오류 --node-options=--experimental-fetch 플래그 추가
회사 프록시 https_proxy·HTTPS_PROXY 환경변수 설정 후 ping으로 재확인
401 키가 ctx7sk로 시작하는지, 전송 방식에 맞는 자리에 넣었는지 확인
404 /owner/repo 형식과 resolve-library-id 결과 확인
429 키를 만들어 Authorization: Bearer 헤더로 보내 한도를 높임
Codex 시작 시간 초과 startup_timeout_sec를 20에서 40으로

로컬에서 --transport http로 서버를 직접 띄운다면 4.2.0(10월 7일 게시)부터 모든 요청에 자격 증명이 기본으로 필요하고, 예전처럼 익명을 받으려면 MCP_AUTH_ENFORCEMENT=observe를 설정해야 합니다. Node.js는 MCP 로컬 서버가 20 이상, ctx7 CLI가 22.13 이상입니다. 원격 서버에 붙으면 로컬 Node 문제가 아예 사라지므로, 설치가 계속 꼬이면 원격 방식으로 바꾸는 것이 가장 빠른 해법입니다. 상세 로그가 필요하면 설정의 env에 "DEBUG": "*"를 넣습니다.

#Context7#Upstash#MCP#Claude Code#Cursor#코딩 에이전트