[
  {
    "path": ".changeset/README.md",
    "content": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works\nwith multi-package repos, or single-package repos to help you version and publish your code. You can\nfind the full documentation for it [in our repository](https://github.com/changesets/changesets)\n\nWe have a quick list of common questions to get you started engaging with this project in\n[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)\n"
  },
  {
    "path": ".changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@3.1.1/schema.json\",\n  \"changelog\": \"@changesets/cli/changelog\",\n  \"commit\": false,\n  \"fixed\": [],\n  \"linked\": [],\n  \"access\": \"public\",\n  \"baseBranch\": \"master\",\n  \"updateInternalDependencies\": \"patch\",\n  \"ignore\": [],\n  \"snapshot\": {\n    \"useCalculatedVersion\": true,\n    \"prereleaseTemplate\": \"{tag}-{datetime}\"\n  }\n}\n"
  },
  {
    "path": ".changeset/warm-eagles-fly.md",
    "content": "---\n\"ctx7\": patch\n---\n\nUse ~/.agents/skills instead of ~/.config/agents/skills for global universal skill installs\n"
  },
  {
    "path": ".claude-plugin/marketplace.json",
    "content": "{\n  \"name\": \"context7-marketplace\",\n  \"owner\": {\n    \"name\": \"Upstash\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"context7-plugin\",\n      \"source\": \"./plugins/claude/context7\",\n      \"description\": \"Up-to-date documentation lookup. Pull version-specific documentation and code examples directly from source repositories into your LLM context.\",\n      \"version\": \"1.0.0\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug Report\ndescription: Report a bug or issue with Context7 MCP\ntitle: \"[Bug]: \"\nlabels: [\"bug\", \"needs-triage\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to report this issue! Please fill out the form below to help us investigate.\n\n  - type: dropdown\n    id: client\n    attributes:\n      label: MCP Client\n      description: Which MCP client are you using?\n      options:\n        - Cursor\n        - Claude Desktop\n        - Claude Code\n        - Windsurf\n        - VS Code\n        - Cline\n        - Zed\n        - Other (specify in description)\n    validations:\n      required: true\n\n  - type: input\n    id: version\n    attributes:\n      label: Context7 MCP Version\n      description: Which version of Context7 MCP are you using? (Check package.json or npm list)\n      placeholder: e.g., 1.0.21\n    validations:\n      required: true\n\n  - type: textarea\n    id: description\n    attributes:\n      label: Bug Description\n      description: A clear description of what the bug is\n      placeholder: When I try to...\n    validations:\n      required: true\n\n  - type: textarea\n    id: steps\n    attributes:\n      label: Steps to Reproduce\n      description: Steps to reproduce the behavior\n      placeholder: |\n        1. Install Context7 MCP via...\n        2. Run the command...\n        3. See error...\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected\n    attributes:\n      label: Expected Behavior\n      description: What you expected to happen\n    validations:\n      required: true\n\n  - type: textarea\n    id: actual\n    attributes:\n      label: Actual Behavior\n      description: What actually happened\n    validations:\n      required: true\n\n  - type: textarea\n    id: logs\n    attributes:\n      label: Error Messages / Logs\n      description: Please copy and paste any relevant error messages or logs\n      render: shell\n\n  - type: dropdown\n    id: transport\n    attributes:\n      label: Transport Method\n      description: Which transport method are you using?\n      options:\n        - stdio (default)\n        - http\n        - SSE (deprecated)\n    validations:\n      required: true\n\n  - type: input\n    id: node-version\n    attributes:\n      label: Node.js Version\n      description: Output of `node --version`\n      placeholder: e.g., v20.10.0\n\n  - type: input\n    id: os\n    attributes:\n      label: Operating System\n      description: Which OS are you running?\n      placeholder: e.g., macOS 14.2, Windows 11, Ubuntu 22.04\n\n  - type: textarea\n    id: config\n    attributes:\n      label: Configuration\n      description: Your Context7 MCP configuration (remove any API keys!)\n      render: json\n      placeholder: |\n        {\n          \"mcpServers\": {\n            \"context7\": {\n              \"command\": \"npx\",\n              \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n            }\n          }\n        }\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: Additional Context\n      description: Any other context about the problem (proxy settings, firewalls, etc.)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/documentation.yml",
    "content": "name: Documentation Issue\ndescription: Report incorrect or missing documentation\ntitle: \"[Docs]: \"\nlabels: [\"documentation\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Found an issue with Context7 documentation? Let us know!\n\n  - type: dropdown\n    id: doc-type\n    attributes:\n      label: Documentation Type\n      description: Where is the issue?\n      options:\n        - README\n        - Installation instructions\n        - API documentation\n        - Library-specific docs\n        - Configuration examples\n    validations:\n      required: true\n\n  - type: textarea\n    id: issue\n    attributes:\n      label: Issue Description\n      description: What's wrong or missing?\n    validations:\n      required: true\n\n  - type: input\n    id: location\n    attributes:\n      label: Documentation Location\n      description: Link or section name where the issue exists\n      placeholder: e.g., README.md line 45, or \"Installation via Smithery\" section\n\n  - type: textarea\n    id: suggestion\n    attributes:\n      label: Suggested Fix\n      description: How should it be corrected or what should be added?\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: Additional Context\n      description: Any other relevant information\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Feature Request\ndescription: Suggest a new feature or improvement\ntitle: \"[Feature]: \"\nlabels: [\"enhancement\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for suggesting a feature! We appreciate your input.\n\n  - type: textarea\n    id: problem\n    attributes:\n      label: Problem Description\n      description: Is your feature request related to a problem? Please describe.\n      placeholder: I'm frustrated when...\n    validations:\n      required: true\n\n  - type: textarea\n    id: solution\n    attributes:\n      label: Proposed Solution\n      description: Describe the solution you'd like\n      placeholder: I would like Context7 to...\n    validations:\n      required: true\n\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Alternatives Considered\n      description: Describe any alternative solutions or features you've considered\n\n  - type: dropdown\n    id: priority\n    attributes:\n      label: Priority\n      description: How important is this feature to you?\n      options:\n        - Nice to have\n        - Would improve my workflow\n        - Blocking my usage\n    validations:\n      required: true\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: Additional Context\n      description: Add any other context, screenshots, or examples about the feature request\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: npm\n    directory: /\n    schedule:\n      interval: monthly\n  - package-ecosystem: bun\n    directory: /\n    schedule:\n      interval: monthly\n  - package-ecosystem: docker\n    directory: /\n    schedule:\n      interval: monthly\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interval: monthly\n"
  },
  {
    "path": ".github/workflows/canary-release.yml",
    "content": "name: Canary Release\n\non:\n  workflow_dispatch:\n    inputs:\n      branch:\n        description: \"Branch to release from (defaults to current branch)\"\n        required: false\n        type: string\n\njobs:\n  canary-release:\n    name: Canary Release\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.branch || github.ref }}\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: \"20\"\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v4\n        with:\n          version: 10\n\n      - name: Configure npm authentication\n        run: |\n          echo \"//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}\" > ~/.npmrc\n\n      - name: Install Dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Build all packages\n        run: pnpm build\n\n      - name: Publish Snapshot\n        run: pnpm release:snapshot\n        env:\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/changeset-check.yml",
    "content": "name: Changeset Check\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened, labeled, unlabeled]\n\njobs:\n  check:\n    name: Check for Changeset\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n\n      - name: Check for changeset\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const { execSync } = require('child_process');\n\n            const labels = context.payload.pull_request.labels.map(l => l.name);\n            if (labels.includes('skip-changeset')) {\n              console.log('Skipping changeset check for PR with skip-changeset label');\n              return;\n            }\n\n            const baseSha = context.payload.pull_request.base.sha;\n            const headSha = context.payload.pull_request.head.sha;\n\n            const diff = execSync(\n              `git diff --name-only ${baseSha}...${headSha}`,\n              { encoding: 'utf-8' }\n            );\n\n            const hasChangeset = diff\n              .split('\\n')\n              .some(file => file.startsWith('.changeset/') && file.endsWith('.md') && !file.includes('README'));\n\n            if (!hasChangeset) {\n              core.setFailed(\n                'No changeset found. Please add a changeset using `pnpm changeset` or add the \"skip-changeset\" label if this PR doesn\\'t need one (e.g., docs, CI changes).'\n              );\n            } else {\n              console.log('Changeset found!');\n            }\n"
  },
  {
    "path": ".github/workflows/ecr-deploy.yml",
    "content": "name: Deploy to AWS ECR\n\non:\n  workflow_dispatch:\n    inputs:\n      version:\n        description: \"Docker image version tag (e.g., v0.0.22)\"\n        required: true\n        type: string\n\njobs:\n  build-and-push:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v6\n\n      - name: Configure AWS credentials\n        uses: aws-actions/configure-aws-credentials@v5\n        with:\n          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}\n          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n          aws-region: ${{ secrets.AWS_REGION }}\n\n      - name: Login to Amazon ECR\n        id: login-ecr\n        uses: aws-actions/amazon-ecr-login@v2\n\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v3\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Build and push Docker image\n        id: build-push\n        uses: docker/build-push-action@v6\n        with:\n          context: .\n          file: packages/mcp/Dockerfile\n          platforms: linux/amd64,linux/arm64\n          push: true\n          tags: |\n            ${{ secrets.ECR_REGISTRY }}/${{ secrets.ECR_REPOSITORY }}:${{ inputs.version }}\n          cache-from: type=gha\n          cache-to: type=gha,mode=max\n\n      - name: Create GitHub Summary\n        run: |\n          echo \"## Docker Image Deployed Successfully\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"**Image Tag:** \\`${{ inputs.version }}\\`\" >> $GITHUB_STEP_SUMMARY\n          echo \"**Platforms:** \\`linux/amd64\\`, \\`linux/arm64\\`\" >> $GITHUB_STEP_SUMMARY\n          echo \"**Digest:** \\`${{ steps.build-push.outputs.digest }}\\`\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"**Status:** ✅ Image pushed to AWS ECR\" >> $GITHUB_STEP_SUMMARY\n"
  },
  {
    "path": ".github/workflows/mcp-registry.yml",
    "content": "name: Publish to MCP Registry\n\non:\n  workflow_dispatch:\n    inputs:\n      version:\n        description: \"Version to publish (defaults to package.json version)\"\n        required: false\n        type: string\n\njobs:\n  publish-mcp:\n    name: Publish to MCP Registry\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write # Required for OIDC authentication with MCP Registry\n      contents: read\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v6\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: lts/*\n\n      - name: Set version\n        run: |\n          if [ -n \"${{ inputs.version }}\" ]; then\n            VERSION=\"${{ inputs.version }}\"\n            # Remove 'v' prefix if it exists\n            VERSION=\"${VERSION#v}\"\n          else\n            VERSION=$(node -p \"require('./packages/mcp/package.json').version\")\n          fi\n          echo \"VERSION=$VERSION\" >> $GITHUB_ENV\n          echo \"Publishing version: $VERSION\"\n\n      - name: Update package version in server.json\n        run: |\n          echo $(jq --arg v \"${{ env.VERSION }}\" '.version = $v | .packages[0].version = $v' server.json) > server.json\n\n      - name: Validate server.json\n        run: npx mcp-registry-validator validate server.json\n\n      - name: Install MCP Publisher\n        run: |\n          curl -L \"https://github.com/modelcontextprotocol/registry/releases/download/v1.4.0/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz\" | tar xz mcp-publisher\n\n      - name: Login to MCP Registry\n        run: ./mcp-publisher login github-oidc\n\n      - name: Publish to MCP Registry\n        run: ./mcp-publisher publish\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches:\n      - master\n\nconcurrency: ${{ github.workflow }}-${{ github.ref }}\n\njobs:\n  release:\n    name: Release\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      pull-requests: write\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v6\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: \"20\"\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v4\n        with:\n          version: 10\n\n      - name: Configure npm authentication\n        run: |\n          echo \"//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}\" > ~/.npmrc\n\n      - name: Install Dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Build all packages\n        run: pnpm build\n\n      - name: Create Release PR or Publish\n        id: changesets\n        uses: changesets/action@v1\n        with:\n          publish: pnpm release\n          commit: \"chore(release): version packages\"\n          title: \"chore(release): version packages\"\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non:\n  pull_request:\n  push:\n    branches: [master]\n  workflow_dispatch:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: \"20\"\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v4\n        with:\n          version: 10\n\n      - name: Get pnpm store directory\n        id: pnpm-cache\n        shell: bash\n        run: |\n          echo \"STORE_PATH=$(pnpm store path)\" >> $GITHUB_OUTPUT\n\n      - name: Cache pnpm dependencies\n        uses: actions/cache@v5\n        with:\n          path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n\n      - name: Install Dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Lint\n        run: pnpm lint:check\n\n      - name: Format\n        run: pnpm format:check\n\n      - name: Build\n        run: pnpm build\n\n      - name: Typecheck\n        run: pnpm typecheck\n\n      - name: Test\n        run: pnpm test\n        env:\n          AWS_REGION: ${{ secrets.AWS_REGION }}\n          AWS_BEARER_TOKEN_BEDROCK: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}\n          CONTEXT7_API_KEY: ${{ secrets.CONTEXT7_API_KEY }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore\n\n# Logs\n\nlogs\n_.log\nnpm-debug.log_\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Caches\n\n.cache\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\n\nreport.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json\n\n# Runtime data\n\npids\n_.pid\n_.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\n\nlib-cov\n\n# Coverage directory used by tools like istanbul\n\ncoverage\n*.lcov\n\n# nyc test coverage\n\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n\n.grunt\n\n# Bower dependency directory (https://bower.io/)\n\nbower_components\n\n# node-waf configuration\n\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\n\nbuild/Release\n\n# Dependency directories\n\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\n\nweb_modules/\n\n# TypeScript cache\n\n*.tsbuildinfo\n\n# Optional npm cache directory\n\n.npm\n\n# Optional eslint cache\n\n.eslintcache\n\n# Optional stylelint cache\n\n.stylelintcache\n\n# Microbundle cache\n\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n\n.node_repl_history\n\n# Output of 'npm pack'\n\n*.tgz\n\n# Yarn Integrity file\n\n.yarn-integrity\n\n# dotenv environment variable files\n\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n\n.parcel-cache\n\n# Next.js build output\n\n.next\nout\n\n# Nuxt.js build / generate output\n\n.nuxt\ndist\n\n# Gatsby files\n\n# Comment in the public line in if your project uses Gatsby and not Next.js\n\n# https://nextjs.org/blog/next-9-1#public-directory-support\n\n# public\n\n# vuepress build output\n\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n\n.temp\n\n# Docusaurus cache and generated files\n\n.docusaurus\n\n# Serverless directories\n\n.serverless/\n\n# FuseBox cache\n\n.fusebox/\n\n# DynamoDB Local files\n\n.dynamodb/\n\n# TernJS port file\n\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n\n.vscode-test\n\n# yarn v2\n\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n# IntelliJ based IDEs\n.idea\n\n.mcp.json\n.cursor\n!plugins/cursor/context7/.cursor\n.opencode\n.claude\n.agents\n\n# Finder (MacOS) folder config\n.DS_Store\npackage-lock.json\n\nprompt.txt\n\nreports\nreports-old\nsrc/test/questions*\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Dependencies\nnode_modules\n\n# Lock files\npnpm-lock.yaml\npackage-lock.json\nyarn.lock\nbun.lockb\n\n# Build outputs\ndist\nbuild\n.next\nout\n\n# Logs\n*.log\n\n# Environment files\n.env\n.env.*\n\n# IDE\n.vscode\n.idea\n\n# Changesets\n.changeset/*.md\n\n# Documentation\ndocs\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2021 Upstash, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "![Cover](https://github.com/upstash/context7/blob/master/public/cover.png?raw=true)\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n# Context7 Platform - Up-to-date Code Docs For Any Prompt\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [![NPM Version](https://img.shields.io/npm/v/%40upstash%2Fcontext7-mcp?color=red)](https://www.npmjs.com/package/@upstash/context7-mcp) [![MIT licensed](https://img.shields.io/npm/l/%40upstash%2Fcontext7-mcp)](./LICENSE)\n\n[![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./i18n/README.zh-TW.md) [![简体中文](https://img.shields.io/badge/docs-简体中文-yellow)](./i18n/README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./i18n/README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./i18n/README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./i18n/README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./i18n/README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./i18n/README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./i18n/README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./i18n/README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./i18n/README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./i18n/README.ru.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./i18n/README.uk.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./i18n/README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./i18n/README.ar.md) [![Tiếng Việt](https://img.shields.io/badge/docs-Tiếng%20Việt-red)](./i18n/README.vi.md)\n\n## ❌ Without Context7\n\nLLMs rely on outdated or generic information about the libraries you use. You get:\n\n- ❌ Code examples are outdated and based on year-old training data\n- ❌ Hallucinated APIs that don't even exist\n- ❌ Generic answers for old package versions\n\n## ✅ With Context7\n\nContext7 pulls up-to-date, version-specific documentation and code examples straight from the source — and places them directly into your prompt.\n\n```txt\nCreate a Next.js middleware that checks for a valid JWT in cookies\nand redirects unauthenticated users to `/login`. use context7\n```\n\n```txt\nConfigure a Cloudflare Worker script to cache\nJSON API responses for five minutes. use context7\n```\n\n```txt\nShow me the Supabase auth API for email/password sign-up.\n```\n\nContext7 fetches up-to-date code examples and documentation right into your LLM's context. No tab-switching, no hallucinated APIs that don't exist, no outdated code generation.\n\nWorks in two modes:\n\n- **CLI + Skills** — installs a skill that guides your agent to fetch docs using `ctx7` CLI commands (no MCP required)\n- **MCP** — registers a Context7 MCP server so your agent can call documentation tools natively\n\n## Installation\n\n> [!NOTE]\n> **API Key Recommended**: Get a free API key at [context7.com/dashboard](https://context7.com/dashboard) for higher rate limits.\n\nSet up Context7 for your coding agents with a single command:\n\n```bash\nnpx ctx7 setup\n```\n\nAuthenticates via OAuth, generates an API key, and installs the appropriate skill. You can choose between CLI + Skills or MCP mode. Use `--cursor`, `--claude`, or `--opencode` to target a specific agent.\n\n**[Manual Installation / Other Clients →](https://context7.com/docs/resources/all-clients)**\n\n## Important Tips\n\n### Use Library Id\n\nIf you already know exactly which library you want to use, add its Context7 ID to your prompt. That way, Context7 can skip the library-matching step and directly retrieve docs.\n\n```txt\nImplement basic authentication with Supabase. use library /supabase/supabase for API and docs.\n```\n\nThe slash syntax tells Context7 exactly which library to load docs for.\n\n### Specify a Version\n\nTo get documentation for a specific library version, just mention the version in your prompt:\n\n```txt\nHow do I set up Next.js 14 middleware? use context7\n```\n\nContext7 will automatically match the appropriate version.\n\n### Add a Rule\n\nIf you installed via `ctx7 setup`, a skill is configured automatically that triggers Context7 for library-related questions. To set up a rule manually instead, add one to your coding agent:\n\n- **Cursor**: `Cursor Settings > Rules`\n- **Claude Code**: `CLAUDE.md`\n- Or the equivalent in your coding agent\n\n**Example rule:**\n\n```txt\nAlways use Context7 when I need library/API documentation, code generation, setup or configuration steps without me having to explicitly ask.\n```\n\n## Available Tools\n\n### CLI Commands\n\n- `ctx7 library <name> <query>`: Searches the Context7 index by library name and returns matching libraries with their IDs.\n- `ctx7 docs <libraryId> <query>`: Retrieves documentation for a library using a Context7-compatible library ID (e.g., `/mongodb/docs`, `/vercel/next.js`).\n\n### MCP Tools\n\n- `resolve-library-id`: Resolves a general library name into a Context7-compatible library ID.\n  - `query` (required): The user's question or task (used to rank results by relevance)\n  - `libraryName` (required): The name of the library to search for\n- `query-docs`: Retrieves documentation for a library using a Context7-compatible library ID.\n  - `libraryId` (required): Exact Context7-compatible library ID (e.g., `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (required): The question or task to get relevant documentation for\n\n## More Documentation\n\n- [CLI Reference](https://context7.com/docs/clients/cli) - Full CLI documentation\n- [MCP Clients](https://context7.com/docs/resources/all-clients) - Manual MCP installation for 30+ clients\n- [Adding Libraries](https://context7.com/docs/adding-libraries) - Submit your library to Context7\n- [Troubleshooting](https://context7.com/docs/resources/troubleshooting) - Common issues and solutions\n- [API Reference](https://context7.com/docs/api-guide) - REST API documentation\n- [Developer Guide](https://context7.com/docs/resources/developer) - Run Context7 MCP locally\n\n## Disclaimer\n\n1- Context7 projects are community-contributed and while we strive to maintain high quality, we cannot guarantee the accuracy, completeness, or security of all library documentation. Projects listed in Context7 are developed and maintained by their respective owners, not by Context7. If you encounter any suspicious, inappropriate, or potentially harmful content, please use the \"Report\" button on the project page to notify us immediately. We take all reports seriously and will review flagged content promptly to maintain the integrity and safety of our platform. By using Context7, you acknowledge that you do so at your own discretion and risk.\n\n2- This repository hosts the MCP server’s source code. The supporting components — API backend, parsing engine, and crawling engine — are private and not part of this repository.\n\n## 🤝 Connect with Us\n\nStay updated and join our community:\n\n- 📢 Follow us on [X](https://x.com/context7ai) for the latest news and updates\n- 🌐 Visit our [Website](https://context7.com)\n- 💬 Join our [Discord Community](https://upstash.com/discord)\n\n## 📺 Context7 In Media\n\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 License\n\nMIT\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nThe following versions of Context7 MCP are currently supported with security updates:\n\n| Version | Supported          |\n| ------- | ------------------ |\n| 1.0.x   | :white_check_mark: |\n\nWe recommend always using the latest version (`@upstash/context7-mcp@latest`) to ensure you have the most recent security patches and features.\n\n## Reporting a Vulnerability\n\nWe take the security of Context7 seriously. If you discover a security vulnerability, please report it responsibly.\n\n### How to Report\n\n- Please use GitHub's [private vulnerability reporting](https://github.com/upstash/context7/security/advisories/new) feature to submit your report\n- Alternatively, you can email security concerns to [context7@upstash.com](mailto:context7@upstash.com)\n\n### What to Include\n\n- A description of the vulnerability\n- Steps to reproduce the issue\n- Potential impact of the vulnerability\n- Any suggested fixes (optional)\n\n### What to Expect\n\n- **Initial Response**: We aim to acknowledge your report within 48 hours\n- **Status Updates**: You can expect updates on the progress every 5-7 business days\n- **Resolution Timeline**: We strive to resolve critical vulnerabilities within 30 days\n\n### After Reporting\n\n- If the vulnerability is accepted, we will work on a fix and coordinate disclosure with you\n- We will credit reporters in our release notes (unless you prefer to remain anonymous)\n- If the report is declined, we will provide an explanation\n\n### Please Do Not\n\n- Disclose the vulnerability publicly before we have addressed it\n- Exploit the vulnerability beyond what is necessary to demonstrate it\n"
  },
  {
    "path": "docs/adding-libraries.mdx",
    "content": "---\ntitle: Library Owners\n---\n\nContext7 allows you to add your favorite libraries and frameworks so developers always receive current, trustworthy documentation inside their coding environment.\n\n\n## Claiming Your Library\n\nIf you're the library owner, you can claim your library on Context7 to unlock a web-based admin panel for managing configuration. This allows you to:\n\n- Edit settings through a user interface instead of committing file changes\n- Invite team members to collaborate on configuration\n- Add and manage multiple versions of your library documentation\n- Get higher rate limits for refresh operations\n\n**[Learn more about claiming libraries →](/howto/claiming-libraries)**\n\n## Who Can Manage Configuration?\n\n- **Library authors**: Claim ownership via `context7.json` and manage settings through the admin panel, or add configuration directly to your repository\n- **Contributors**: Submit pull requests to add or update the configuration\n\n## Quick Submission\n\nThe fastest way to add a library is through our web interface:\n\n**[Submit a Library ->](https://context7.com/add-library?tab=github)**\n\n1. Paste the GitHub repository URL.\n2. (Optional) Adjust folders and exclusions.\n3. Submit and let Context7 parse and index the documentation.\n\n<Note>\n  For private repositories, see the [Private Repositories](/howto/private-repositories) guide.\n  Requires a Pro or Enterprise plan.\n</Note>\n\n## Advanced Configuration with `context7.json`\n\nFor more control over how Context7 parses and presents your library, you can add a `context7.json` file to the root of your repository. This file works similarly to `robots.txt` and tells Context7 how to handle your project.\n\n### Configuration Fields\n\nHere's an example `context7.json` file with all available options:\n\n```json\n{\n  \"$schema\": \"https://context7.com/schema/context7.json\",\n  \"projectTitle\": \"Upstash Ratelimit\",\n  \"description\": \"Ratelimiting library based on Upstash Redis\",\n  \"folders\": [],\n  \"excludeFolders\": [\"src\"],\n  \"excludeFiles\": [],\n  \"rules\": [\"Use Upstash Redis as a database\", \"Use single region set up\"],\n  \"previousVersions\": [\n    {\n      \"tag\": \"v1.2.1\"\n    }\n  ]\n}\n```\n\n<Note>\n  **Pro Tip**: Including the `$schema` field enables autocomplete, validation, and helpful tooltips\n  in modern code editors like VS Code, making it easier to create and maintain your configuration.\n</Note>\n\n## Field Descriptions\n\n- **`projectTitle`** (string): Suggested display name for your project in Context7. Only used when the LLM cannot generate a name with high confidence.\n\n- **`description`** (string): Suggested description for your project in Context7. Only used when the LLM cannot generate a description with high confidence.\n\n- **`branch`** (string): The name of the git branch to parse. If not provided, the default branch will be used.\n\n- **`folders`** (array): Specific folder paths to include when parsing. If empty, Context7 scans the entire repository. Root-level markdown files are always included.\n\n- **`excludeFolders`** (array): Patterns to exclude from documentation parsing. Supports simple names, paths, and glob patterns (see Exclusion Patterns below).\n\n- **`excludeFiles`** (array): Specific file names to exclude. Use only the filename, not the full path. Examples: `CHANGELOG.md`, license files, or non-documentation content.\n\n- **`rules`** (array): Best practices or important guidelines that coding agents should follow when using your library. These appear as recommendations in the documentation context provided to coding agents.\n\n- **`previousVersions`** (array): Information about previous versions of your library that should also be available in Context7.\n  - **`tag`**: The Git tag or version identifier\n\n- **`branchVersions`** (array): Information about previous versions (branch-based) of your library that should also\n  be available in Context7.\n  - **`branch`**: The Git branch\n\n### Exclusion Patterns\n\nThe `excludeFolders` parameter supports various pattern types for flexible exclusion:\n\n- **Simple folder names**: `\"node_modules\"` - Excludes any folder named \"node_modules\" anywhere in the tree\n- **Root-specific patterns**: `\"./xyz\"` - Excludes the folder only at repository root (e.g., excludes `/xyz` but not `/dist/xyz`)\n- **Path patterns**: `\"app-sdk/v2.3\"` - Excludes specific paths and everything under them\n- **Glob patterns**: `\"*.test\"`, `\"temp*\"` - Excludes folders matching the pattern\n- **Globstar patterns**: `\"**/dist\"`, `\"docs/**/internal\"` - Advanced path matching\n- **Complex patterns**: `\"src/**/*.test.js\"` - Exclude test files in the src directory\n\nExamples:\n\n- `\"node_modules\"` - Excludes all node_modules folders anywhere\n- `\"./build\"` - Excludes the build folder only at root (not `src/build`)\n- `\"app-sdk/v2.3\"` - Excludes the app-sdk/v2.3 path and all its contents\n- `\"*.test\"` - Excludes folders ending with .test\n- `\"docs/**/internal\"` - Excludes any \"internal\" folder under docs\n- `\"**/temp\"` - Excludes any folder named \"temp\" anywhere\n\n### Default Exclusions\n\nIf you don't specify `excludeFiles` or `excludeFolders` in your `context7.json` file, Context7 uses these default patterns:\n\n#### Default Excluded Files\n\n```\nCHANGELOG.md, changelog.md, CHANGELOG.mdx, changelog.mdx\nLICENSE.md, license.md\nCODE_OF_CONDUCT.md, code_of_conduct.md\n```\n\n#### Default Excluded Folders\n\n```\n*archive*, *archived*, old, docs/old, *deprecated*, *legacy*\n*previous*, *outdated*, *superseded*\ni18n/zh*, i18n/es*, i18n/fr*, i18n/de*, i18n/ja*, i18n/ko*\ni18n/ru*, i18n/pt*, i18n/it*, i18n/ar*, i18n/hi*, i18n/tr*\ni18n/nl*, i18n/pl*, i18n/sv*, i18n/vi*, i18n/th*\nzh-cn, zh-tw, zh-hk, zh-mo, zh-sg\n```\n\nThese defaults help coding agents avoid irrelevant, outdated, and non-technical content.\n\n\n## Need Help?\nIf you encounter issues or need assistance adding your project, please [open an issue](https://github.com/upstash/context7/issues/new/choose) or reach out to our community.\n"
  },
  {
    "path": "docs/agentic-tools/ai-sdk/agents/context7-agent.mdx",
    "content": "---\ntitle: \"Context7Agent\"\nsidebarTitle: \"Context7Agent\"\ndescription: \"Pre-built AI agent for documentation lookup workflows\"\n---\n\nThe `Context7Agent` class is a pre-configured AI agent that handles the complete documentation lookup workflow automatically. It combines both `resolveLibraryId` and `queryDocs` tools with an optimized system prompt.\n\n## Usage\n\n```typescript\nimport { Context7Agent } from \"@upstash/context7-tools-ai-sdk\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\n\nconst agent = new Context7Agent({\n  model: anthropic(\"claude-sonnet-4-20250514\"),\n});\n\nconst { text } = await agent.generate({\n  prompt: \"How do I use React Server Components?\",\n});\n\nconsole.log(text);\n```\n\n## Configuration\n\n```typescript\nnew Context7Agent(config?: Context7AgentConfig)\n```\n\n### Parameters\n\n<ParamField path=\"config\" type=\"Context7AgentConfig\" optional>\n  Configuration options for the agent.\n\n  <Expandable title=\"properties\">\n    <ParamField path=\"model\" type=\"LanguageModel\" optional>\n      Language model to use. Must be a LanguageModel instance from an AI SDK provider.\n\n      Examples:\n      - `anthropic('claude-sonnet-4-20250514')`\n      - `openai('gpt-5.2')`\n      - `google('gemini-1.5-pro')`\n    </ParamField>\n    <ParamField path=\"apiKey\" type=\"string\" optional>\n      Context7 API key. If not provided, uses the `CONTEXT7_API_KEY` environment variable.\n    </ParamField>\n    <ParamField path=\"system\" type=\"string\" optional>\n      Custom system prompt. Overrides the default `AGENT_PROMPT`.\n    </ParamField>\n    <ParamField path=\"stopWhen\" type=\"StopCondition\" optional default=\"stepCountIs(5)\">\n      Condition for when the agent should stop. Defaults to stopping after 5 steps.\n    </ParamField>\n\n  </Expandable>\n</ParamField>\n\n### Returns\n\n`Context7Agent` extends the AI SDK `Agent` class and provides `generate()` and `stream()` methods.\n\n## Agent Workflow\n\nThe agent follows a structured multi-step workflow:\n\n```mermaid\nflowchart TD\n    A[User Query] --> B[Extract Library Name]\n    B --> C[Call resolveLibraryId]\n    C --> D{Results Found?}\n    D -->|Yes| E[Select Best Match]\n    D -->|No| F[Report No Results]\n    E --> G[Call queryDocs]\n    G --> H{Sufficient Context?}\n    H -->|Yes| I[Generate Response]\n    H -->|No| J[Fetch More Docs]\n    J --> H\n    I --> K[Return Answer with Examples]\n```\n\n### Step-by-Step\n\n1. **Extract library name** - Identifies the library/framework from the user's query\n2. **Resolve library** - Calls `resolveLibraryId` to find the Context7 library ID\n3. **Select best match** - Analyzes results based on reputation, coverage, and relevance\n4. **Fetch documentation** - Calls `queryDocs` with the selected library ID and user's query\n5. **Query if needed** - Makes additional queries if initial context is insufficient\n6. **Generate response** - Provides an answer with code examples from the documentation\n\n## Examples\n\n### Basic Usage\n\n```typescript\nimport { Context7Agent } from \"@upstash/context7-tools-ai-sdk\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\n\nconst agent = new Context7Agent({\n  model: anthropic(\"claude-sonnet-4-20250514\"),\n});\n\nconst { text } = await agent.generate({\n  prompt: \"How do I set up authentication in Next.js?\",\n});\n\nconsole.log(text);\n```\n\n### With OpenAI\n\n```typescript\nimport { Context7Agent } from \"@upstash/context7-tools-ai-sdk\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst agent = new Context7Agent({\n  model: openai(\"gpt-5.2\"),\n});\n\nconst { text } = await agent.generate({\n  prompt: \"Explain Tanstack Query's useQuery hook\",\n});\n```\n\n### Streaming Responses\n\n```typescript\nimport { Context7Agent } from \"@upstash/context7-tools-ai-sdk\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\n\nconst agent = new Context7Agent({\n  model: anthropic(\"claude-sonnet-4-20250514\"),\n});\n\nconst { textStream } = await agent.stream({\n  prompt: \"How do I create a Supabase Edge Function?\",\n});\n\nfor await (const chunk of textStream) {\n  process.stdout.write(chunk);\n}\n```\n\n### Custom Configuration\n\n```typescript\nimport { Context7Agent } from \"@upstash/context7-tools-ai-sdk\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\nimport { stepCountIs } from \"ai\";\n\nconst agent = new Context7Agent({\n  model: anthropic(\"claude-sonnet-4-20250514\"),\n  apiKey: process.env.CONTEXT7_API_KEY,\n  stopWhen: stepCountIs(8), // Allow more steps for complex queries\n});\n```\n\n### Custom System Prompt\n\n```typescript\nimport { Context7Agent, AGENT_PROMPT } from \"@upstash/context7-tools-ai-sdk\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst agent = new Context7Agent({\n  model: openai(\"gpt-5.2\"),\n  system: `${AGENT_PROMPT}\n\nAdditional instructions:\n- Always include TypeScript examples\n- Mention version compatibility when relevant\n- Suggest related documentation topics`,\n});\n```\n\n## Comparison: Agent vs Tools\n\n| Feature       | Context7Agent        | Individual Tools     |\n| ------------- | -------------------- | -------------------- |\n| Setup         | Single configuration | Configure each tool  |\n| Workflow      | Automatic multi-step | Manual orchestration |\n| System prompt | Optimized default    | You provide          |\n| Customization | Limited              | Full control         |\n| Best for      | Quick integration    | Custom workflows     |\n\n### When to Use the Agent\n\n- Rapid prototyping\n- Standard documentation lookup use cases\n- When you want sensible defaults\n\n### When to Use Individual Tools\n\n- Custom agentic workflows\n- Integration with other tools\n- Fine-grained control over the process\n- Custom system prompts with specific behavior\n\n## Related\n\n- [resolveLibraryId](/agentic-tools/ai-sdk/tools/resolve-library-id) - The library search tool used by the agent\n- [queryDocs](/agentic-tools/ai-sdk/tools/query-docs) - The documentation fetch tool used by the agent\n- [Getting Started](/agentic-tools/ai-sdk/getting-started) - Overview of the AI SDK integration\n"
  },
  {
    "path": "docs/agentic-tools/ai-sdk/getting-started.mdx",
    "content": "---\ntitle: \"Getting Started\"\nsidebarTitle: \"Getting Started\"\ndescription: \"Add Context7 documentation tools to your Vercel AI SDK applications\"\n---\n\n`@upstash/context7-tools-ai-sdk` provides [Vercel AI SDK](https://sdk.vercel.ai/) compatible tools and agents that give your AI applications access to up-to-date library documentation.\n\nWhen building AI-powered applications with the Vercel AI SDK, your models often need accurate information about libraries and frameworks. Instead of relying on potentially outdated training data, Context7 tools let your AI fetch current documentation on-demand, ensuring responses include correct API usage, current best practices, and working code examples.\n\nThe package gives you two ways to integrate:\n\n1. **Individual tools** (`resolveLibraryId` and `queryDocs`) that you add to your existing `generateText` or `streamText` calls\n2. **A pre-built agent** (`Context7Agent`) that handles the entire documentation lookup workflow automatically\n\nBoth approaches work with any AI provider supported by the Vercel AI SDK, including OpenAI, Anthropic, Google, and others.\n\n## Installation\n\n<CodeGroup>\n```bash npm\nnpm install @upstash/context7-tools-ai-sdk\n```\n\n```bash pnpm\npnpm add @upstash/context7-tools-ai-sdk\n```\n\n```bash yarn\nyarn add @upstash/context7-tools-ai-sdk\n```\n\n```bash bun\nbun add @upstash/context7-tools-ai-sdk\n```\n\n</CodeGroup>\n\n## Prerequisites\n\nYou'll need:\n\n1. A Context7 API key from the [Context7 Dashboard](https://context7.com/dashboard)\n2. An AI provider SDK (e.g., `@ai-sdk/openai`, `@ai-sdk/anthropic`)\n\n## Configuration\n\nSet your Context7 API key as an environment variable:\n\n```bash\nCONTEXT7_API_KEY=ctx7sk-...\n```\n\nThe tools and agents will automatically use this key.\n\n## Quick Start\n\n### Using Tools with generateText\n\nThe simplest way to add documentation lookup to your AI application:\n\n```typescript\nimport { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { text } = await generateText({\n  model: openai(\"gpt-5.2\"),\n  prompt: \"How do I create a server action in Next.js?\",\n  tools: {\n    resolveLibraryId: resolveLibraryId(),\n    queryDocs: queryDocs(),\n  },\n  stopWhen: stepCountIs(5),\n});\n\nconsole.log(text);\n```\n\n### Using the Context7 Agent\n\nFor a more streamlined experience, use the pre-configured agent:\n\n```typescript\nimport { Context7Agent } from \"@upstash/context7-tools-ai-sdk\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\n\nconst agent = new Context7Agent({\n  model: anthropic(\"claude-sonnet-4-20250514\"),\n});\n\nconst { text } = await agent.generate({\n  prompt: \"How do I use React Server Components?\",\n});\n\nconsole.log(text);\n```\n\n### Using Tools with streamText\n\nFor streaming responses:\n\n```typescript\nimport { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\nimport { streamText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { textStream } = streamText({\n  model: openai(\"gpt-5.2\"),\n  prompt: \"Explain how to use Tanstack Query for data fetching\",\n  tools: {\n    resolveLibraryId: resolveLibraryId(),\n    queryDocs: queryDocs(),\n  },\n  stopWhen: stepCountIs(5),\n});\n\nfor await (const chunk of textStream) {\n  process.stdout.write(chunk);\n}\n```\n\n## Explicit Configuration\n\nYou can also pass the API key directly if needed:\n\n```typescript\nimport { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\n\nconst tools = {\n  resolveLibraryId: resolveLibraryId({ apiKey: \"your-api-key\" }),\n  queryDocs: queryDocs({ apiKey: \"your-api-key\" }),\n};\n```\n\n## How It Works\n\nThe tools follow a two-step workflow:\n\n1. **`resolveLibraryId`** - Searches Context7's database to find the correct library ID for a given query (e.g., \"react\" → `/reactjs/react.dev`)\n\n2. **`queryDocs`** - Fetches documentation for the resolved library using the user's query to retrieve relevant content\n\nThe AI model orchestrates these tools automatically based on the user's prompt, fetching relevant documentation before generating a response.\n\n## Next Steps\n\n<CardGroup cols={2}>\n  <Card\n    title=\"resolveLibraryId\"\n    icon=\"magnifying-glass\"\n    href=\"/agentic-tools/ai-sdk/tools/resolve-library-id\"\n  >\n    Search for libraries and get Context7-compatible IDs\n  </Card>\n  <Card title=\"queryDocs\" icon=\"book\" href=\"/agentic-tools/ai-sdk/tools/query-docs\">\n    Fetch documentation for a specific library\n  </Card>\n  <Card title=\"Context7Agent\" icon=\"robot\" href=\"/agentic-tools/ai-sdk/agents/context7-agent\">\n    Use the pre-built documentation agent\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/agentic-tools/ai-sdk/tools/query-docs.mdx",
    "content": "---\ntitle: \"queryDocs\"\nsidebarTitle: \"queryDocs\"\ndescription: \"Fetch up-to-date documentation for a specific library\"\n---\n\nThe `queryDocs` tool fetches documentation for a library using its Context7-compatible library ID and a query. This tool is typically called after `resolveLibraryId` has identified the correct library.\n\n## Usage\n\n```typescript\nimport { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { text } = await generateText({\n  model: openai(\"gpt-5.2\"),\n  prompt: \"How do I use React Server Components?\",\n  tools: {\n    resolveLibraryId: resolveLibraryId(),\n    queryDocs: queryDocs(),\n  },\n  stopWhen: stepCountIs(5),\n});\n```\n\n## Configuration\n\n```typescript\nqueryDocs(config?: Context7ToolsConfig)\n```\n\n### Parameters\n\n<ParamField path=\"config\" type=\"Context7ToolsConfig\" optional>\n  Configuration options for the tool.\n\n  <Expandable title=\"properties\">\n    <ParamField path=\"apiKey\" type=\"string\" optional>\n      Context7 API key. If not provided, uses the `CONTEXT7_API_KEY` environment variable.\n    </ParamField>\n  </Expandable>\n</ParamField>\n\n### Returns\n\nReturns an AI SDK `tool` that can be used with `generateText`, `streamText`, or agents.\n\n## Tool Behavior\n\nWhen the AI model calls this tool, it:\n\n1. Takes a library ID and query from the model\n2. Fetches documentation from Context7's API\n3. Returns the documentation content\n\n### Input Schema\n\nThe tool accepts the following inputs from the AI model:\n\n<ParamField path=\"libraryId\" type=\"string\" required>\n  Context7-compatible library ID (e.g., `/reactjs/react.dev`, `/vercel/next.js`)\n</ParamField>\n\n<ParamField path=\"query\" type=\"string\" required>\n  The question or task you need help with. Be specific and include relevant details. Good: \"How to set up authentication with JWT in Express.js\" or \"React useEffect cleanup function examples\". Bad: \"auth\" or \"hooks\".\n</ParamField>\n\n### Output Format\n\nOn success, the tool returns the documentation as plain text, formatted for easy consumption by the AI model:\n\n```\n# Server Components\n\nServer Components let you write UI that can be rendered and optionally cached on the server.\n\n## Example\n\n\\`\\`\\`tsx\nasync function ServerComponent() {\n  const data = await fetchData();\n  return <div>{data}</div>;\n}\n\\`\\`\\`\n\n---\n\n# Using Server Components with Client Components\n\nYou can import Server Components into Client Components...\n```\n\n#### On Failure\n\n```\nNo documentation found for library \"/invalid/library\". This might have happened because you used an invalid Context7-compatible library ID. Use 'resolveLibraryId' to get a valid ID.\n```\n\n## Examples\n\n### Basic Usage with Both Tools\n\n```typescript\nimport { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { text } = await generateText({\n  model: openai(\"gpt-5.2\"),\n  prompt: \"Show me how to set up routing in Next.js App Router\",\n  tools: {\n    resolveLibraryId: resolveLibraryId(),\n    queryDocs: queryDocs(),\n  },\n  stopWhen: stepCountIs(5),\n});\n\n// The model will:\n// 1. Call resolveLibraryId to get the library ID\n// 2. Call queryDocs({ libraryId: \"/vercel/next.js\", query: \"routing in App Router\" })\n// 3. Generate a response using the fetched documentation\n```\n\n### With Custom Configuration\n\n```typescript\nimport { queryDocs } from \"@upstash/context7-tools-ai-sdk\";\n\nconst tool = queryDocs({\n  apiKey: process.env.CONTEXT7_API_KEY,\n});\n```\n\n### Direct Library ID (Skip resolveLibraryId)\n\nIf the user provides a library ID directly, the model can skip the resolution step:\n\n```typescript\nimport { queryDocs } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { text } = await generateText({\n  model: openai(\"gpt-5.2\"),\n  prompt: \"Using /vercel/next.js, explain middleware\",\n  tools: {\n    queryDocs: queryDocs(),\n  },\n  stopWhen: stepCountIs(3),\n});\n\n// The model recognizes the /org/project format and calls queryDocs directly\n```\n\n### Multi-Step Documentation Lookup\n\nFor comprehensive documentation, the model can make multiple queries:\n\n```typescript\nimport { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\n\nconst { text } = await generateText({\n  model: anthropic(\"claude-sonnet-4-20250514\"),\n  prompt: \"Give me a comprehensive guide to Supabase authentication\",\n  tools: {\n    resolveLibraryId: resolveLibraryId(),\n    queryDocs: queryDocs(),\n  },\n  stopWhen: stepCountIs(8), // Allow more steps for multiple queries\n});\n\n// The model may call queryDocs multiple times with different queries\n// to gather comprehensive documentation\n```\n\n## Version-Specific Documentation\n\nLibrary IDs can include version specifiers:\n\n```typescript\n// Latest version\n\"/vercel/next.js\";\n\n// Specific version\n\"/vercel/next.js/v14.3.0-canary.87\";\n```\n\nThe model can request documentation for specific versions when the user asks about a particular version.\n\n## Related\n\n- [resolveLibraryId](/agentic-tools/ai-sdk/tools/resolve-library-id) - Search for libraries and get their IDs\n- [Context7Agent](/agentic-tools/ai-sdk/agents/context7-agent) - Pre-built agent that handles the full workflow\n"
  },
  {
    "path": "docs/agentic-tools/ai-sdk/tools/resolve-library-id.mdx",
    "content": "---\ntitle: \"resolveLibraryId\"\nsidebarTitle: \"resolveLibraryId\"\ndescription: \"Search for libraries and resolve them to Context7-compatible IDs\"\n---\n\nThe `resolveLibraryId` tool searches Context7's library database and returns matching results with their Context7-compatible library IDs. This is typically the first step in a documentation lookup workflow.\n\n## Usage\n\n```typescript\nimport { resolveLibraryId } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { text } = await generateText({\n  model: openai(\"gpt-5.2\"),\n  prompt: \"Find documentation for React hooks\",\n  tools: {\n    resolveLibraryId: resolveLibraryId(),\n  },\n  stopWhen: stepCountIs(3),\n});\n```\n\n## Configuration\n\n```typescript\nresolveLibraryId(config?: Context7ToolsConfig)\n```\n\n### Parameters\n\n<ParamField path=\"config\" type=\"Context7ToolsConfig\" optional>\n  Configuration options for the tool.\n\n  <Expandable title=\"properties\">\n    <ParamField path=\"apiKey\" type=\"string\" optional>\n      Context7 API key. If not provided, uses the `CONTEXT7_API_KEY` environment variable.\n    </ParamField>\n  </Expandable>\n</ParamField>\n\n### Returns\n\nReturns an AI SDK `tool` that can be used with `generateText`, `streamText`, or agents.\n\n## Tool Behavior\n\nWhen the AI model calls this tool, it:\n\n1. Takes a `query` and `libraryName` parameter from the model\n2. Searches Context7's database for matching libraries\n3. Returns formatted results including:\n   - Library ID (e.g., `/reactjs/react.dev`)\n   - Title and description\n   - Number of code snippets available\n   - Source reputation score\n   - Available versions\n\n### Input Schema\n\nThe tool accepts the following input from the AI model:\n\n<ParamField path=\"query\" type=\"string\" required>\n  The user's original question or task. This is used to rank library results by relevance to what the user is trying to accomplish.\n</ParamField>\n\n<ParamField path=\"libraryName\" type=\"string\" required>\n  Library name to search for (e.g., \"react\", \"next.js\", \"vue\")\n</ParamField>\n\n### Output Format\n\nOn success, the tool returns the search results as plain text, formatted for easy consumption by the AI model:\n\n```\n- Title: React Documentation\n- Context7-compatible library ID: /reactjs/react.dev\n- Description: The library for web and native user interfaces\n- Code Snippets: 1250\n- Trust Score: High\n- Benchmark Score: 98\n- Versions: 19.0.0, 18.3.1, 18.2.0\n----------\n- Title: React Native\n- Context7-compatible library ID: /facebook/react-native\n- Description: A framework for building native applications using React\n- Code Snippets: 890\n- Trust Score: High\n- Benchmark Score: 95\n- Versions: 0.76.0, 0.75.4\n```\n\nOn failure:\n\n```\nNo libraries found matching \"unknown-lib\". Try a different search term or check the library name.\n```\n\n## Examples\n\n### Basic Usage\n\n```typescript\nimport { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { text, toolCalls } = await generateText({\n  model: openai(\"gpt-5.2\"),\n  prompt: \"What libraries are available for React?\",\n  tools: {\n    resolveLibraryId: resolveLibraryId(),\n    queryDocs: queryDocs(),\n  },\n  stopWhen: stepCountIs(5),\n});\n\n// The model will call resolveLibraryId and receive a list of matching libraries\nconsole.log(text);\n```\n\n### With Custom API Key\n\n```typescript\nimport { resolveLibraryId } from \"@upstash/context7-tools-ai-sdk\";\n\nconst tool = resolveLibraryId({\n  apiKey: process.env.CONTEXT7_API_KEY,\n});\n```\n\n### Inspecting Tool Calls\n\n```typescript\nimport { resolveLibraryId } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { toolCalls, toolResults } = await generateText({\n  model: openai(\"gpt-5.2\"),\n  prompt: \"Find the official Next.js documentation\",\n  tools: {\n    resolveLibraryId: resolveLibraryId(),\n  },\n  stopWhen: stepCountIs(3),\n});\n\n// See what the model searched for\nfor (const call of toolCalls) {\n  console.log(\"Searched for:\", call.args.libraryName);\n}\n\n// See the results\nfor (const result of toolResults) {\n  console.log(\"Found:\", result.result);\n}\n```\n\n## Selection Guidance\n\nThe tool's description instructs the AI model to select libraries based on:\n\n1. **Name similarity** - Exact matches are prioritized\n2. **Description relevance** - How well the description matches the query intent\n3. **Documentation coverage** - Libraries with more code snippets are preferred\n4. **Source reputation** - High/Medium reputation sources are more authoritative\n5. **Benchmark score** - Quality indicator (100 is the highest)\n\n## Related\n\n- [queryDocs](/agentic-tools/ai-sdk/tools/query-docs) - Fetch documentation using the resolved library ID\n- [Context7Agent](/agentic-tools/ai-sdk/agents/context7-agent) - Pre-built agent that handles the full workflow\n"
  },
  {
    "path": "docs/agentic-tools/overview.mdx",
    "content": "---\ntitle: \"Overview\"\nsidebarTitle: \"Overview\"\ndescription: \"Build AI agents with up-to-date library documentation\"\n---\n\n# Agentic Tools\n\nContext7 provides tools and integrations that give your AI agents access to accurate, up-to-date library documentation. Instead of relying on potentially outdated training data, your agents can fetch real-time documentation to answer questions and generate code.\n\n## Why Agentic Tools?\n\nAI agents often struggle with:\n\n- **Outdated knowledge** - Training data becomes stale, leading to deprecated API usage\n- **Hallucinated APIs** - Models confidently suggest methods that don't exist\n- **Version mismatches** - Code examples from old versions that no longer work\n\nContext7's agentic tools solve these problems by giving your agents direct access to current documentation during inference.\n\n## Available Integrations\n\n<CardGroup cols={1}>\n  <Card\n    title=\"Vercel AI SDK\"\n    icon=\"wand-magic-sparkles\"\n    href=\"/agentic-tools/ai-sdk/getting-started\"\n  >\n    Add Context7 tools to your AI SDK workflows with `generateText`, `streamText`, or use the\n    pre-built `Context7Agent` for automatic documentation lookup.\n  </Card>\n</CardGroup>\n\n## How It Works\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Agent\n    participant Context7\n    participant Docs\n\n    User->>Agent: \"How do I use React Server Components?\"\n    Agent->>Context7: resolveLibraryId(query: \"React Server Components\", libraryName: \"react\")\n    Context7-->>Agent: Library ID: /reactjs/react.dev\n    Agent->>Context7: queryDocs(libraryId: \"/reactjs/react.dev\", query: \"server components\")\n    Context7->>Docs: Fetch latest documentation\n    Docs-->>Context7: Current docs with examples\n    Context7-->>Agent: Documentation content\n    Agent->>User: Answer with accurate, up-to-date code examples\n```\n\n## Use Cases\n\n<AccordionGroup>\n  <Accordion title=\"Documentation-Aware Chatbots\" icon=\"comments\">\n    Build chatbots that answer framework questions with accurate, version-specific information:\n\n    ```typescript\n    import { generateText, stepCountIs } from \"ai\";\n    import { openai } from \"@ai-sdk/openai\";\n    import { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\n\n    const { text } = await generateText({\n      model: openai(\"gpt-5.2\"),\n      prompt: \"How do I set up authentication in Next.js 15?\",\n      tools: {\n        resolveLibraryId: resolveLibraryId(),\n        queryDocs: queryDocs(),\n      },\n      stopWhen: stepCountIs(5),\n    });\n    ```\n\n  </Accordion>\n\n  <Accordion title=\"Code Generation Pipelines\" icon=\"code\">\n    Ensure generated code uses current APIs and best practices:\n\n    ```typescript\n    import { Context7Agent } from \"@upstash/context7-tools-ai-sdk\";\n    import { anthropic } from \"@ai-sdk/anthropic\";\n\n    const agent = new Context7Agent({\n      model: anthropic(\"claude-sonnet-4-20250514\"),\n    });\n\n    const { text } = await agent.generate({\n      prompt: \"Generate a Supabase Edge Function that handles webhooks\",\n    });\n    ```\n\n  </Accordion>\n\n  <Accordion title=\"Code Review Agents\" icon=\"magnifying-glass-chart\">\n    Build code review agents that verify implementations against current API documentation:\n\n    ```typescript\n    import { generateText, stepCountIs } from \"ai\";\n    import { anthropic } from \"@ai-sdk/anthropic\";\n    import { resolveLibraryId, queryDocs } from \"@upstash/context7-tools-ai-sdk\";\n\n    const codeToReview = `\n      const { data } = await supabase\n        .from('users')\n        .select('*')\n        .eq('id', userId)\n        .single();\n    `;\n\n    const { text } = await generateText({\n      model: anthropic(\"claude-sonnet-4-20250514\"),\n      prompt: `Review this Supabase code for correctness and best practices:\n\n    ${codeToReview}\n\n    Check against the latest Supabase documentation.`,\n      tools: {\n        resolveLibraryId: resolveLibraryId(),\n        queryDocs: queryDocs(),\n      },\n      stopWhen: stepCountIs(5),\n    });\n\n    // Agent fetches current Supabase docs to verify:\n    // - Correct method signatures\n    // - Deprecated patterns\n    // - Security best practices\n    // - Error handling recommendations\n    ```\n\n  </Accordion>\n</AccordionGroup>\n"
  },
  {
    "path": "docs/api-guide.mdx",
    "content": "---\ntitle: API Guide\ndescription: Authentication, rate limits, best practices, and integration guides for the Context7 API\n---\n\n## Authentication\n\nAll API requests require authentication using an API key. Include your API key in the `Authorization` header:\n\n```bash\nAuthorization: Bearer CONTEXT7_API_KEY\n```\n\nGet your API key at [context7.com/dashboard](https://context7.com/dashboard). Learn more about [creating and managing API keys](/howto/api-keys).\n\n\n## API Methods\n\nContext7 provides two core API methods for retrieving documentation context.\n\n### Search Library\n\nSearch for available libraries by name. Use this to find the correct library ID before fetching documentation.\n\n**Endpoint:** `GET /api/v2/libs/search`\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `query` | string | Yes | Your question or task (used for relevance ranking) |\n| `libraryName` | string | Yes | Library name to search for (e.g., \"react\", \"nextjs\") |\n\n**Response:** Returns an array of matching libraries:\n\n```json\n[\n  {\n    \"id\": \"/facebook/react\",\n    \"name\": \"React\",\n    \"description\": \"A JavaScript library for building user interfaces\",\n    \"totalSnippets\": 1250,\n    \"trustScore\": 95,\n    \"benchmarkScore\": 88,\n    \"versions\": [\"v18.2.0\", \"v17.0.2\"]\n  }\n]\n```\n\n**Example:**\n\n```bash\ncurl \"https://context7.com/api/v2/libs/search?libraryName=react&query=hooks\" \\\n  -H \"Authorization: Bearer CONTEXT7_API_KEY\"\n```\n\n### Get Context\n\nRetrieve documentation context for a specific library. Returns relevant documentation snippets based on your query.\n\n**Endpoint:** `GET /api/v2/context`\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `query` | string | Yes | Your question or task (used for relevance ranking) |\n| `libraryId` | string | Yes | Library identifier from search (e.g., `/facebook/react`) |\n| `type` | string | No | Response format: `json` (default) or `txt` |\n\n**Response (JSON format):** Returns an array of documentation snippets:\n\n```json\n[\n  {\n    \"title\": \"Using the Effect Hook\",\n    \"content\": \"The Effect Hook lets you perform side effects...\",\n    \"source\": \"react.dev/reference/react/useEffect\"\n  }\n]\n```\n\n**Response (Text format):** Returns plain text ready for LLM prompts.\n\n**Example:**\n\n```bash\n# JSON format (default)\ncurl \"https://context7.com/api/v2/context?libraryId=/facebook/react&query=useEffect\" \\\n  -H \"Authorization: Bearer CONTEXT7_API_KEY\"\n\n# Text format\ncurl \"https://context7.com/api/v2/context?libraryId=/facebook/react&query=useEffect&type=txt\" \\\n  -H \"Authorization: Bearer CONTEXT7_API_KEY\"\n```\n\n### Complete Workflow Example\n\n```python\nimport requests\n\nheaders = {\"Authorization\": \"Bearer CONTEXT7_API_KEY\"}\n\n# Step 1: Search for the library\nsearch_response = requests.get(\n    \"https://context7.com/api/v2/libs/search\",\n    headers=headers,\n    params={\"libraryName\": \"react\", \"query\": \"I need to manage state\"}\n)\nlibraries = search_response.json()\nbest_match = libraries[0]\nprint(f\"Found: {best_match['name']} ({best_match['id']})\")\n\n# Step 2: Get documentation context\ncontext_response = requests.get(\n    \"https://context7.com/api/v2/context\",\n    headers=headers,\n    params={\"libraryId\": best_match[\"id\"], \"query\": \"How do I use useState?\"}\n)\ndocs = context_response.json()\n\nfor doc in docs:\n    print(f\"Title: {doc['title']}\")\n    print(f\"Content: {doc['content'][:200]}...\")\n```\n\n<Info>\n  For TypeScript SDK usage with additional features, see [Search Library](/sdks/ts/commands/search-library) and [Get Context](/sdks/ts/commands/get-context).\n</Info>\n\n## Rate Limits\n\n- **Without API key**: Low rate limits and no custom configuration\n- **With API key**: Higher limits based on your plan\n- View current usage and reset windows in the [dashboard](https://context7.com/dashboard).\n\nWhen you exceed rate limits, the API returns a `429` status code:\n\n```json\n{\n  \"error\": \"Too many requests\",\n  \"status\": 429\n}\n```\n\n## Best Practices\n\n### Be Specific with Queries\n\nUse detailed, natural language queries for better results:\n\n```bash\n# Good - specific question\ncurl \"https://context7.com/api/v2/context?libraryId=/vercel/next.js&query=How%20to%20implement%20authentication%20with%20middleware\" \\\n  -H \"Authorization: Bearer CONTEXT7_API_KEY\"\n\n# Less optimal - vague query\ncurl \"https://context7.com/api/v2/context?libraryId=/vercel/next.js&query=auth\" \\\n  -H \"Authorization: Bearer CONTEXT7_API_KEY\"\n```\n\n### Cache Responses\n\nStore documentation locally to reduce API calls and improve performance. Documentation updates are relatively infrequent, so caching for several hours or days is usually appropriate.\n\n### Handle Rate Limits\n\nImplement exponential backoff for rate limit errors:\n\n```python\nimport time\nimport requests\n\ndef fetch_with_retry(url, headers, max_retries=3):\n    for attempt in range(max_retries):\n        response = requests.get(url, headers=headers)\n\n        if response.status_code == 429:\n            # Wait before retrying with exponential backoff\n            time.sleep(2 ** attempt)\n            continue\n\n        return response\n\n    raise Exception(\"Max retries exceeded\")\n```\n\n### Use Specific Versions\n\nSpecify exact versions for consistent results across deployments:\n\n```bash\n# Pin to a specific version\ncurl \"https://context7.com/api/v2/context?libraryId=/vercel/next.js/v15.1.8&query=app%20router\" \\\n  -H \"Authorization: Bearer CONTEXT7_API_KEY\"\n```\n\n## Error Handling\n\nThe Context7 API uses standard HTTP status codes:\n\n| Code | Description                               | Action                                       |\n| ---- | ----------------------------------------- | -------------------------------------------- |\n| 200  | Success                                   | Process the response normally                |\n| 202  | Accepted - Library not finalized          | Wait and retry later                         |\n| 301  | Moved - Library redirected                | Use the new library ID from `redirectUrl`    |\n| 400  | Bad Request - Invalid parameters          | Check query parameters                       |\n| 401  | Unauthorized - Invalid API key            | Check your API key format (starts with `ctx7sk`) |\n| 403  | Forbidden - Access denied                 | Check library access permissions             |\n| 404  | Not Found - Library doesn't exist         | Verify the library ID                        |\n| 422  | Unprocessable - Library too large/no code | Try a different library                      |\n| 429  | Too Many Requests - Rate limit exceeded   | Wait for `Retry-After` header, then retry    |\n| 500  | Internal Server Error                     | Retry with backoff                           |\n| 503  | Service Unavailable - Search failed       | Retry later                                  |\n\n### Error Response Format\n\nAll errors return a JSON object with these fields:\n\n```json\n{\n  \"error\": \"library_not_found\",\n  \"message\": \"Library \\\"/owner/repo\\\" not found.\"\n}\n```\n\n## SDK and Libraries\n\nFor TypeScript SDK installation and usage, see the [Getting Started guide](/sdks/ts/getting-started).\n"
  },
  {
    "path": "docs/clients/claude-code.mdx",
    "content": "---\ntitle: Claude Code\ndescription: Using Context7 with Claude Code\n---\n\nContext7 integrates with Claude Code to provide current library documentation instead of relying on training data. Claude Code supports skills, agents, and commands that make documentation lookups more powerful.\n\n## Installation\n\nRun the setup command to configure Context7 for Claude Code:\n\n```bash\nnpx ctx7 setup --claude\n```\n\nThis flow authenticates via OAuth, generates an API key, and installs the appropriate skill. You can choose between CLI or MCP mode.\n\n<Tip>\nIf you're setting up Claude Code on a remote server, headless VM, or over SSH, use an existing API key instead:\n\n```bash\nnpx ctx7 setup --claude --api-key YOUR_API_KEY\n```\n\nThe default OAuth flow redirects back to `localhost`, which only works when the browser can reach the same machine that's running `ctx7 setup`.\n</Tip>\n\nCreate or manage API keys in the [Context7 dashboard](https://context7.com/dashboard). For manual MCP installation or other configuration options, see [All MCP Clients](/resources/all-clients).\n\n---\n\n## Using Context7\n\nWith `ctx7 setup`, a skill is installed that triggers automatically when you ask about libraries — no need to say \"use context7\". You can also invoke it explicitly:\n\n```\nuse context7 to show me how to set up middleware in Next.js 15\nuse context7 for Prisma query examples with relations\nuse context7 for the Supabase syntax for row-level security\n```\n\nIf you know the library ID, use it directly to skip resolution:\n\n```\nuse context7 with /supabase/supabase for authentication docs\nuse context7 with /vercel/next.js for app router setup\n```\n\n<Tip>\nWith the [Context7 plugin](#the-context7-plugin) installed, you get additional agents and commands on top of the skill.\n</Tip>\n\n---\n\n## The Context7 Plugin\n\nThe full Context7 plugin for Claude Code includes more than just the MCP server:\n\n<CardGroup cols={2}>\n<Card title=\"MCP Server\" icon=\"server\">\nThe tools for fetching documentation (`resolve-library-id`, `query-docs`)\n</Card>\n<Card title=\"Skills\" icon=\"sparkles\">\nAuto-triggers documentation lookups when you ask about libraries\n</Card>\n<Card title=\"Agents\" icon=\"robot\">\nA `docs-researcher` agent for focused lookups that keep context lean\n</Card>\n<Card title=\"Commands\" icon=\"terminal\">\n`/context7:docs` for manual documentation queries\n</Card>\n</CardGroup>\n\n### Installing the Plugin\n\nThe plugin is available from the Context7 marketplace. Run these commands in Claude Code:\n\n```\n/plugin marketplace add upstash/context7\n/plugin install context7-plugin@context7-marketplace\n```\n\nThis adds the Context7 marketplace and installs the plugin with skills, agents, and commands.\n\n### Skills\n\n#### Documentation Lookup Skill\n\nThis skill triggers automatically when you ask about libraries, frameworks, or need code examples. You don't need to type \"use context7\" — the skill recognizes when documentation would help.\n\n<AccordionGroup>\n<Accordion title=\"What triggers the skill\">\n- Setup questions: \"How do I configure Next.js middleware?\"\n- Code generation: \"Write a Prisma query for user relations\"\n- API references: \"What are the Supabase auth methods?\"\n- Framework mentions: React, Vue, Svelte, Express, Tailwind, etc.\n</Accordion>\n<Accordion title=\"How it works\">\n1. **Resolve**: Finds the library ID using `resolve-library-id` with your question as context\n2. **Select**: Picks the best match based on name accuracy and quality scores\n3. **Fetch**: Calls `query-docs` with the library ID and your specific question\n4. **Return**: Provides code examples and explanations from current documentation\n</Accordion>\n</AccordionGroup>\n\n### Agents\n\n#### docs-researcher Agent\n\nWhen you're in the middle of a long task and don't want documentation tool calls cluttering your context, spawn the `docs-researcher` agent. It runs in a separate context and returns just the answer.\n\n<Tabs>\n<Tab title=\"When to Use\" icon=\"question\">\n- You need docs but want to keep your main context clean\n- You're working on something complex and context is getting long\n- You want a focused answer without side effects\n</Tab>\n<Tab title=\"Examples\" icon=\"code\">\n```\nspawn docs-researcher to look up React hooks documentation\nspawn docs-researcher: how do I set up Prisma with PostgreSQL?\nspawn docs-researcher to find Tailwind CSS grid utilities\n```\n</Tab>\n</Tabs>\n\nThe agent uses the same tools (`resolve-library-id` and `query-docs`) but runs on a lighter model (Sonnet) to keep things fast.\n\n#### When to Use Agents vs Inline Tools\n\n| Scenario | Use |\n|----------|-----|\n| Deep into a task with long context | Agent |\n| Want to avoid context bloat | Agent |\n| Context is short | Inline tools |\n| Want docs visible in conversation | Inline tools |\n\n### Commands\n\n#### /context7:docs\n\nManual command for documentation lookups.\n\n**Format:**\n```\n/context7:docs <library> [query]\n```\n\n**Examples:**\n\n<Tabs>\n<Tab title=\"Basic\" icon=\"search\">\n```\n/context7:docs react hooks\n/context7:docs next.js authentication\n/context7:docs prisma relations\n```\n</Tab>\n<Tab title=\"With Library ID\" icon=\"link\">\n```\n/context7:docs /vercel/next.js app router\n/context7:docs /supabase/supabase row level security\n```\n\nUsing a library ID directly skips the resolution step.\n</Tab>\n</Tabs>\n\n**When to use:**\n- You know exactly which library and topic you need\n- You want a quick lookup without explaining your full context\n- You're testing what documentation is available\n\n"
  },
  {
    "path": "docs/clients/cli.mdx",
    "content": "---\ntitle: CLI\ndescription: The ctx7 CLI — fetch library documentation, manage skills, and configure Context7 MCP from your terminal\n---\n\nThe `ctx7` CLI is the command-line interface for Context7. It does three things:\n\n- **Fetch library documentation** — resolve any library by name and query its up-to-date docs directly in your terminal, without opening a browser\n- **Manage AI coding skills** — install, search, generate, and remove skills from the Context7 registry\n- **Configure Context7 MCP** — set up the MCP server for Claude Code, Cursor, or OpenCode with a single command\n\nThe CLI is useful both as a standalone tool (fetching docs while you code) and as a setup utility (wiring up Context7 for your AI coding agent).\n\n## Installation\n\nRequires Node.js 18 or later.\n\n<Tabs>\n  <Tab title=\"npx (no install)\">\n    Run ctx7 directly without installing anything. Useful for one-off commands or trying it out.\n\n    ```bash\n    npx ctx7 --help\n    npx ctx7 library react\n    ```\n  </Tab>\n  <Tab title=\"Global install\">\n    Install globally for faster access — no `npx` prefix needed on every command.\n\n    ```bash\n    npm install -g ctx7\n\n    # Verify installation\n    ctx7 --version\n    ```\n  </Tab>\n</Tabs>\n\n---\n\n## Query Library Documentation\n\nFetching docs is a two-step process: first resolve the library name to get its Context7 ID, then use that ID to query documentation.\n\n### Step 1 — ctx7 library\n\nSearches the Context7 index by name and returns matching libraries. Pass a `query` describing what you're trying to do — this ranks results by relevance and helps when a library name is ambiguous or shared across multiple packages.\n\n```bash\nctx7 library react \"How to clean up useEffect with async operations\"\nctx7 library nextjs \"How to set up app router with middleware\"\nctx7 library prisma \"How to define one-to-many relations with cascade delete\"\n```\n\nEach result includes:\n\n| Field | Description |\n|-------|-------------|\n| **Library ID** | The identifier to pass to `ctx7 docs` (format: `/org/project`) |\n| **Code Snippets** | Number of indexed code examples — higher means more documentation coverage |\n| **Source Reputation** | Authority indicator: High, Medium, Low, or Unknown |\n| **Benchmark Score** | Quality score from 0 to 100 |\n| **Versions** | Version-specific IDs when available (format: `/org/project/version`) |\n\nWhen multiple results come back, the best match is usually the one with the closest name, highest snippet count, and strongest reputation. If you need docs for a specific version, pick the matching version ID from the list.\n\n```bash\n# Fetch docs for a specific version\nctx7 docs /vercel/next.js/v14.3.0-canary.87 \"How to set up app router\"\n\n# Output as JSON for scripting\nctx7 library react \"How to use hooks for state management\" --json | jq '.[0].id'\n```\n\n### Step 2 — ctx7 docs\n\nTakes a library ID and a natural-language question, and returns relevant code snippets and explanations from the indexed documentation.\n\n```bash\nctx7 docs /facebook/react \"How to clean up useEffect with async operations\"\nctx7 docs /vercel/next.js \"How to add middleware that redirects unauthenticated users\"\nctx7 docs /prisma/prisma \"How to define one-to-many relations with cascade delete\"\n```\n\n<Note>\nLibrary IDs always start with `/`. Running `ctx7 docs react \"hooks\"` will fail — always use the full ID returned by `ctx7 library` in Step 1.\n</Note>\n\nQueries work best when they're specific. Describe what you're trying to accomplish rather than using single keywords — `\"How to set up authentication with JWT in Express.js\"` returns much better results than `\"auth\"`.\n\nThe output contains two types of content: **code snippets** (titled, with language-tagged blocks) and **info snippets** (prose explanations with breadcrumb context). Both are formatted for readability in the terminal.\n\n```bash\n# Output as structured JSON\nctx7 docs /facebook/react \"How to use hooks for state management\" --json\n\n# Pipe to other tools — output is clean when not in a TTY (no spinners or colors)\nctx7 docs /facebook/react \"How to use hooks for state management\" | head -50\nctx7 docs /vercel/next.js \"How to add middleware for route protection\" | grep -A 10 \"middleware\"\n```\n\n---\n\n## Setup\n\nConfigure Context7 for your AI coding agent. On first run, prompts you to choose between two modes:\n\n- **MCP server** — registers the Context7 MCP server in your agent's config so it can call `resolve-library-id` and `get-library-docs` tools natively\n- **CLI + Skills** — installs a `docs` skill that guides your agent to fetch up-to-date library docs using `ctx7` CLI commands (no MCP required)\n\n### ctx7 setup\n\n```bash\n# Interactive — prompts for mode, then agent/install target\nctx7 setup\n\n# Skip the mode prompt\nctx7 setup --mcp            # MCP server mode\nctx7 setup --cli            # CLI + Skills mode\n\n# Target a specific agent (MCP mode)\nctx7 setup --claude\nctx7 setup --cursor\nctx7 setup --opencode\n\n# Target a specific install location (CLI + Skills mode)\nctx7 setup --cli --claude       # Claude Code (~/.claude/skills)\nctx7 setup --cli --cursor       # Cursor (~/.cursor/skills)\nctx7 setup --cli --universal    # Universal (~/.agents/skills)\nctx7 setup --cli --antigravity  # Antigravity (~/.config/agent/skills)\n\n# Configure for current project only (default is global)\nctx7 setup --project\n\n# Skip confirmation prompts\nctx7 setup --yes\n```\n\n**Authentication options:**\n\n```bash\n# Use an existing API key (works for both MCP and CLI + Skills mode)\nctx7 setup --api-key YOUR_API_KEY\n\n# Use OAuth endpoint — MCP mode only (IDE handles the auth flow)\nctx7 setup --oauth\n```\n\nWithout `--api-key` or `--oauth`, setup opens a browser for OAuth login. MCP mode additionally generates a new API key after login. `--oauth` is MCP-only — use it when an IDE handles the auth flow on your behalf.\n\n**What gets written — MCP mode:**\n\n| File | Purpose |\n|------|---------|\n| `.mcp.json` / `.cursor/mcp.json` / `.opencode.json` | MCP server entry |\n| Agent rules directory | Rule file — instructs the agent to use Context7 for library docs |\n| Agent skills directory | `context7-mcp` skill |\n\n**What gets written — CLI + Skills mode:**\n\n| File | Purpose |\n|------|---------|\n| Agent skills directory | `docs` skill — guides the agent to use `ctx7 library` and `ctx7 docs` commands |\n\n---\n\n## Authentication\n\nMost commands work without authentication. Log in to unlock skill generation and higher rate limits on documentation commands.\n\n### Commands\n\n```bash\n# Log in (opens browser for OAuth)\nctx7 login\n\n# Log in without opening the browser (prints URL instead)\nctx7 login --no-browser\n\n# Check current login status\nctx7 whoami\n\n# Log out\nctx7 logout\n```\n\n### API Key\n\nSet an API key via environment variable to skip interactive login entirely — useful for CI or scripting:\n\n```bash\nexport CONTEXT7_API_KEY=your_key\n```\n\n### When is authentication required?\n\n| Feature | Required |\n|---------|----------|\n| `ctx7 library` / `ctx7 docs` | No — login gives higher rate limits |\n| `ctx7 skills install / search / suggest / list / remove` | No |\n| `ctx7 skills generate` | Yes |\n| `ctx7 setup` | Yes — unless `--api-key` is passed (`--oauth` also skips login for MCP mode) |\n\n---\n\n## Skills\n\nManage AI coding skills from the Context7 registry. See [Skills](/skills) for a full explanation of what skills are, the registry, trust scores, and skill file structure.\n\n### ctx7 skills install\n\nInstall skills from any GitHub repository. Repository format is `/owner/repo`.\n\n```bash\n# Interactive — pick from a list\nctx7 skills install /anthropics/skills\n\n# Install a specific skill by name\nctx7 skills install /anthropics/skills pdf\n\n# Install all skills without prompting\nctx7 skills install /anthropics/skills --all\n```\n\n**Target a specific AI coding assistant:**\n\n```bash\nctx7 skills install /anthropics/skills pdf --claude      # Claude Code\nctx7 skills install /anthropics/skills pdf --cursor      # Cursor\nctx7 skills install /anthropics/skills pdf --universal   # Universal (.agents/skills/)\nctx7 skills install /anthropics/skills pdf --antigravity\n```\n\n**Install globally** (available across all projects):\n\n```bash\nctx7 skills install /anthropics/skills pdf --global\nctx7 skills install /anthropics/skills --all --global\n```\n\n<Note>\nWhen installing to multiple clients, the skill files are created in your primary client's directory and symlinked to the others.\n</Note>\n\nAlias: `ctx7 si /anthropics/skills pdf`\n\n### ctx7 skills search\n\nFind skills across all indexed repositories by keyword. Shows an interactive list — select to install directly.\n\n```bash\nctx7 skills search pdf\nctx7 skills search typescript testing\nctx7 skills search react nextjs\n```\n\nAlias: `ctx7 ss pdf`\n\n### ctx7 skills suggest\n\nAuto-detects your project dependencies and recommends relevant skills from the registry.\n\n```bash\n# Scan current project\nctx7 skills suggest\n\n# Target a specific client\nctx7 skills suggest --claude\nctx7 skills suggest --cursor\n\n# Install suggestions globally\nctx7 skills suggest --global\n```\n\nScans: `package.json`, `requirements.txt`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `Gemfile`.\n\nAlias: `ctx7 ssg`\n\n### ctx7 skills generate\n\nGenerate a custom skill tailored to your stack using AI. **Requires login.**\n\n```bash\nctx7 skills generate\n\n# Generate and install to a specific client\nctx7 skills generate --claude\nctx7 skills generate --cursor\nctx7 skills generate --universal\n\n# Generate as a global skill\nctx7 skills generate --global\n```\n\n**Generation flow:**\n\n1. Describe the expertise you want (e.g., \"OAuth authentication with NextAuth.js\")\n2. Select relevant libraries from search results\n3. Answer 3 clarifying questions to focus the skill\n4. Review the generated skill and request changes if needed\n5. Choose where to install it\n\n<Tip>\nDescribe best practices and constraints, not step-by-step tutorials. \"TypeScript strict mode patterns\" generates a more useful skill than \"how to write TypeScript.\"\n</Tip>\n\n**Weekly limits:** Free accounts get 6 generations/week, Pro accounts get 10.\n\nAliases: `ctx7 skills gen`, `ctx7 skills g`\n\n### ctx7 skills list\n\nView skills installed in your project or globally.\n\n```bash\nctx7 skills list                   # All detected clients\nctx7 skills list --claude\nctx7 skills list --cursor\nctx7 skills list --global\n```\n\n### ctx7 skills info\n\nPreview all available skills in a repository without installing.\n\n```bash\nctx7 skills info /anthropics/skills\n```\n\n### ctx7 skills remove\n\nUninstall a skill by name.\n\n```bash\nctx7 skills remove pdf\nctx7 skills remove pdf --claude\nctx7 skills remove pdf --global\n```\n\nAliases: `ctx7 skills rm`, `ctx7 skills delete`\n\n---\n\n## Shortcuts\n\n| Shortcut | Full command |\n|----------|-------------|\n| `ctx7 si` | `ctx7 skills install` |\n| `ctx7 ss` | `ctx7 skills search` |\n| `ctx7 ssg` | `ctx7 skills suggest` |\n| `ctx7 skills i` | `ctx7 skills install` |\n| `ctx7 skills s` | `ctx7 skills search` |\n| `ctx7 skills ls` | `ctx7 skills list` |\n| `ctx7 skills rm` | `ctx7 skills remove` |\n| `ctx7 skills gen` | `ctx7 skills generate` |\n| `ctx7 skills g` | `ctx7 skills generate` |\n\n---\n\n## Telemetry\n\nThe CLI collects anonymous usage data to help improve the product. To disable:\n\n```bash\n# For a single command\nCTX7_TELEMETRY_DISABLED=1 ctx7 skills search pdf\n\n# Permanently — add to ~/.bashrc or ~/.zshrc\nexport CTX7_TELEMETRY_DISABLED=1\n```\n\n---\n\n## Next Steps\n\n<CardGroup cols={2}>\n  <Card title=\"Browse Skills\" icon=\"magnifying-glass\" href=\"https://context7.com/skills\">\n    Explore the skills registry\n  </Card>\n  <Card title=\"Skills Guide\" icon=\"book\" href=\"/skills\">\n    Learn about skill file structure, trust scores, and the registry\n  </Card>\n  <Card title=\"Claude Code\" icon=\"terminal\" href=\"/clients/claude-code\">\n    Set up Context7 in Claude Code\n  </Card>\n  <Card title=\"All Clients\" icon=\"grid\" href=\"/resources/all-clients\">\n    Installation for every supported editor\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/clients/cursor.mdx",
    "content": "---\ntitle: Cursor\ndescription: Using Context7 with Cursor\n---\n\nContext7 brings up-to-date library documentation directly into Cursor. Instead of getting outdated code examples from training data, you get current documentation from source repositories.\n\n## Installation\n\nRun the setup command to configure Context7 for Cursor:\n\n```bash\nnpx ctx7 setup --cursor\n```\n\nAuthenticates via OAuth, generates an API key, and installs the appropriate skill. You can choose between CLI or MCP mode.\n\nFor manual MCP installation or other configuration options, see [All MCP Clients](/resources/all-clients).\n\n---\n\n## Setting Up Rules\n\nWith `ctx7 setup`, a skill is installed that triggers Context7 automatically. If you prefer to use a rule instead, add one in Cursor.\n\n<Tabs>\n<Tab title=\"Cursor Settings\" icon=\"settings\">\n<Steps>\n<Step title=\"Open Settings\">\nGo to `Cursor` → `Settings...` → `Cursor Settings` → `Rules and Commands`. You can also press `Cmd+Shift+P` (or `Ctrl+Shift+P` on Windows/Linux) and type \"Cursor Settings\".\n\n<Frame>\n  <img src=\"/images/clients/cursor/rules.png\" alt=\"Cursor Rules and Commands\" />\n</Frame>\n</Step>\n<Step title=\"Add the Rule\">\n```\nAlways use Context7 MCP when I ask about library documentation,\nAPI references, or need code examples from external packages.\n```\n</Step>\n</Steps>\n</Tab>\n<Tab title=\".cursorrules File\" icon=\"file\">\nCreate a `.cursorrules` file in your project root:\n\n```\n# Context7 Integration\n\nWhen the user asks about:\n- Library APIs or documentation\n- Framework setup or configuration\n- Code examples for external packages\n- How to use a specific library feature\n\nAutomatically use Context7 MCP to fetch current documentation. Don't rely on training data for library-specific code.\n```\n\nThis makes Context7 part of your project's standard workflow and can be version-controlled.\n\n</Tab>\n</Tabs>\n\n---\n\n## Using Context7\n\nAdd \"use context7\" to your prompts to fetch current documentation:\n\n```\nuse context7 to show me how to set up middleware in Next.js 15\nuse context7 for Prisma query examples with relations\nuse context7 for the Supabase syntax for row-level security\n```\n\nIf you know the library ID, use it directly to skip resolution:\n\n```\nuse context7 with /supabase/supabase for authentication docs\nuse context7 with /vercel/next.js for app router setup\n```\n\n---\n\n## Tips\n\n<AccordionGroup>\n<Accordion title=\"Project vs Global Config\">\nUse **global config** (`~/.cursor/mcp.json`) when:\n- You want Context7 available in all projects\n- You're using a personal API key\n\nUse **project config** (`.cursor/mcp.json`) when:\n\n- The project has specific Context7 requirements\n- You want to share the setup with teammates\n- Different projects need different API keys\n</Accordion>\n\n<Accordion title=\"Combining with Cursor Composer\">\nContext7 works well with Cursor's Composer feature. When you're building something that involves external libraries:\n\n1. Start with a prompt that mentions the libraries you need\n2. Context7 fetches the relevant docs\n3. Composer uses those docs to generate accurate code\n\nThis is especially useful for newer library versions that might not be in Cursor's training data.\n\n</Accordion>\n\n<Accordion title=\"Getting Better Results\">\n- Be specific about what you're trying to do, not just which library\n- Mention versions when they matter\n- If the first result isn't right, ask for a different part of the docs\n\n```\n# Good\nHow do I handle file uploads with the Supabase Storage API?\n\n# Less specific\nHow does Supabase storage work?\n```\n\n</Accordion>\n</AccordionGroup>\n"
  },
  {
    "path": "docs/clients/opencode.mdx",
    "content": "---\ntitle: OpenCode\ndescription: Using Context7 with OpenCode\n---\n\nContext7 integrates with [OpenCode](https://opencode.ai/) to provide current library documentation instead of relying on training data. Get accurate, up-to-date code examples directly in your coding sessions.\n\n<Info>\nFor more details on MCP server configuration in OpenCode, see the [OpenCode MCP documentation](https://opencode.ai/docs/mcp-servers/).\n</Info>\n\n## Installation\n\nRun the setup command to configure Context7 for OpenCode:\n\n```bash\nnpx ctx7 setup --opencode\n```\n\nAuthenticates via OAuth, generates an API key, and installs the appropriate skill. You can choose between CLI or MCP mode.\n\nFor manual MCP installation or other configuration options, see [All MCP Clients](/resources/all-clients).\n\n---\n\n## Using Context7\n\nWith `ctx7 setup`, a skill is installed that triggers automatically when you ask about libraries. You can also invoke it explicitly:\n\n```\nuse context7 to show me how to set up middleware in Next.js 15\nuse context7 for Prisma query examples with relations\nuse context7 for the Supabase syntax for row-level security\n```\n\nIf you know the library ID, use it directly to skip resolution:\n\n```\nuse context7 with /supabase/supabase for authentication docs\nuse context7 with /vercel/next.js for app router setup\n```\n\nYou can also add instructions to your `AGENTS.md` file:\n\n```markdown AGENTS.md\nWhen you need to search docs, use Context7.\n```\n\n---\n\n## Tips\n\n<AccordionGroup>\n<Accordion title=\"Getting Better Results\">\n- Be specific about what you're trying to do, not just which library\n- Mention versions when they matter\n- If the first result isn't right, ask for a different part of the docs\n\n```\n# Good\nHow do I handle file uploads with the Supabase Storage API?\n\n# Less specific\nHow does Supabase storage work?\n```\n</Accordion>\n\n<Accordion title=\"Project-Level Configuration\">\nYou can place your `opencode.json` in your project directory to have project-specific configurations. This is useful when:\n\n- Different projects need different API keys\n- You want to share the config with your team via version control\n- A project requires specific Context7 settings\n</Accordion>\n\n</AccordionGroup>\n"
  },
  {
    "path": "docs/contact.mdx",
    "content": "---\ntitle: Contact\nurl: https://context7.com/contact\n---\n"
  },
  {
    "path": "docs/docs.json",
    "content": "{\n  \"$schema\": \"https://mintlify.com/docs.json\",\n  \"theme\": \"mint\",\n  \"name\": \"Context7 MCP\",\n  \"description\": \"Up-to-date code docs for any prompt.\",\n  \"colors\": {\n    \"primary\": \"#10B981\",\n    \"light\": \"#ECFDF5\",\n    \"dark\": \"#064E3B\"\n  },\n  \"contextual\": {\n    \"options\": [\n      \"copy\",\n      \"view\",\n      \"chatgpt\",\n      \"claude\"\n    ]\n  },\n  \"navigation\": {\n    \"groups\": [\n      {\n        \"group\": \"Overview\",\n        \"pages\": [\n          \"overview\",\n          \"installation\",\n          \"plans-pricing\",\n          \"clients/cli\",\n          \"adding-libraries\",\n          \"api-guide\",\n          \"skills\",\n          \"tips\"\n        ]\n      },\n      {\n        \"group\": \"How To\",\n        \"pages\": [\n          {\n            \"group\": \"Authentication\",\n            \"pages\": [\n              \"howto/api-keys\",\n              \"howto/oauth\"\n            ]\n          },\n          \"howto/claiming-libraries\",\n          \"howto/chat-widget\",\n          \"howto/verification\",\n          \"howto/private-repositories\",\n          \"howto/teamspace\",\n          \"howto/usage\"\n        ]\n      },\n      {\n        \"group\": \"Enterprise\",\n        \"pages\": [\n          \"enterprise\",\n          {\n            \"group\": \"On-Premise\",\n            \"pages\": [\n              \"enterprise/on-premise\",\n              {\n                \"group\": \"Deployment\",\n                \"pages\": [\n                  \"enterprise/deployment/docker\",\n                  \"enterprise/deployment/kubernetes\"\n                ]\n              }\n            ]\n          },\n          \"resources/security\"\n        ]\n      },\n      {\n        \"group\": \"Clients\",\n        \"pages\": [\n          \"clients/claude-code\",\n          \"clients/cursor\",\n          \"clients/opencode\",\n          \"resources/all-clients\"\n        ]\n      },\n      {\n        \"group\": \"SDKs\",\n        \"pages\": [\n          {\n            \"group\": \"TypeScript\",\n            \"pages\": [\n              \"sdks/ts/getting-started\",\n              {\n                \"group\": \"Commands\",\n                \"pages\": [\n                  \"sdks/ts/commands/search-library\",\n                  \"sdks/ts/commands/get-context\"\n                ]\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"group\": \"Agentic Tools\",\n        \"pages\": [\n          \"agentic-tools/overview\",\n          {\n            \"group\": \"Vercel AI SDK\",\n            \"pages\": [\n              \"agentic-tools/ai-sdk/getting-started\",\n              {\n                \"group\": \"Tools\",\n                \"pages\": [\n                  \"agentic-tools/ai-sdk/tools/resolve-library-id\",\n                  \"agentic-tools/ai-sdk/tools/query-docs\"\n                ]\n              },\n              {\n                \"group\": \"Agents\",\n                \"pages\": [\n                  \"agentic-tools/ai-sdk/agents/context7-agent\"\n                ]\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"group\": \"API Reference\",\n        \"openapi\": \"openapi.json\"\n      },\n      {\n        \"group\": \"Integrations\",\n        \"pages\": [\n          \"integrations/code-rabbit\"\n        ]\n      },\n      {\n        \"group\": \"Resources\",\n        \"pages\": [\n          \"resources/developer\",\n          \"resources/security\",\n          \"resources/troubleshooting\"\n        ]\n      }\n    ]\n  },\n  \"api\": {\n    \"playground\": {\n      \"display\": \"simple\"\n    }\n  },\n  \"logo\": {\n    \"light\": \"/public/logo/logo.svg\",\n    \"dark\": \"/public/logo/logo-dark.svg\",\n    \"href\": \"https://context7.com\"\n  },\n  \"favicon\": \"/public/favicon.ico\",\n  \"navbar\": {\n    \"links\": [\n      {\n        \"label\": \"Contact\",\n        \"href\": \"https://context7.com/contact\"\n      },\n      {\n        \"label\": \"GitHub\",\n        \"href\": \"https://github.com/upstash/context7\"\n      }\n    ],\n    \"primary\": {\n      \"type\": \"button\",\n      \"label\": \"Dashboard\",\n      \"href\": \"https://context7.com\"\n    }\n  },\n  \"footer\": {\n    \"socials\": {\n      \"x\": \"https://x.com/context7ai\",\n      \"github\": \"https://github.com/upstash/context7\",\n      \"discord\": \"https://upstash.com/discord\"\n    },\n    \"links\": [\n      {\n        \"header\": \"Resources\",\n        \"items\": [\n          {\n            \"label\": \"Website\",\n            \"href\": \"https://context7.com\"\n          },\n          {\n            \"label\": \"Submit a Library\",\n            \"href\": \"https://context7.com/add-library\"\n          },\n          {\n            \"label\": \"Dashboard\",\n            \"href\": \"https://context7.com/dashboard\"\n          }\n        ]\n      },\n      {\n        \"header\": \"Community\",\n        \"items\": [\n          {\n            \"label\": \"GitHub\",\n            \"href\": \"https://github.com/upstash/context7\"\n          },\n          {\n            \"label\": \"Discord\",\n            \"href\": \"https://upstash.com/discord\"\n          },\n          {\n            \"label\": \"Twitter\",\n            \"href\": \"https://x.com/context7ai\"\n          }\n        ]\n      }\n    ]\n  }\n}"
  },
  {
    "path": "docs/enterprise/deployment/docker.mdx",
    "content": "---\ntitle: \"Docker Deployment\"\nsidebarTitle: \"Docker\"\n---\n\nDeploy Context7 On-Premise with Docker Compose. This guide assumes you have completed the [On-Premise setup](/enterprise/on-premise) and have a valid license key.\n\n## Prerequisites\n\n- Docker and Docker Compose installed\n- Context7 license key\n\n## Registry Authentication\n\nContext7 Enterprise images are hosted on `ghcr.io` and require authentication. Log in using your license key:\n\n```bash\nLICENSE_KEY=\"<your-license-key>\"\n\nTOKEN=$(curl -s -H \"Authorization: Bearer $LICENSE_KEY\" \\\n  https://context7.com/api/v1/license/registry-token | jq -r '.token')\n\ndocker login ghcr.io -u x-access-token -p $TOKEN\n```\n\nDocker stores these credentials locally. `docker compose` will use them automatically when pulling the image. You can also pull manually:\n\n```bash\ndocker pull ghcr.io/context7/enterprise:latest\n```\n\n## Docker Compose\n\nCreate a `docker-compose.yml`:\n\n```yaml\nservices:\n  context7:\n    image: ghcr.io/context7/enterprise:latest\n    container_name: context7\n    restart: unless-stopped\n    ports:\n      - \"3000:3000\"\n    volumes:\n      - context7-data:/data\n    environment:\n      - LICENSE_KEY=${LICENSE_KEY}\n\nvolumes:\n  context7-data:\n    driver: local\n```\n\n<Warning>\nThe `context7-data` volume is critical. It stores your SQLite database (configuration, credentials, indexed libraries) and all vector embeddings. Without a persistent volume, all data is lost when the container restarts or is recreated. Never run without a volume mount in production.\n</Warning>\n\nCreate a `.env` file in the same directory:\n\n```bash\nLICENSE_KEY=ctx7sk-...\n```\n\nStart the service:\n\n```bash\ndocker compose up -d\n```\n\nOnce the container is running, open `http://localhost:3000` in your browser to complete the setup wizard.\n\n## Operations\n\n### Updating\n\nIf your registry login has expired, re-authenticate first:\n\n```bash\nLICENSE_KEY=\"<your-license-key>\"\n\nTOKEN=$(curl -s -H \"Authorization: Bearer $LICENSE_KEY\" \\\n  https://context7.com/api/v1/license/registry-token | jq -r '.token')\n\ndocker login ghcr.io -u x-access-token -p $TOKEN\n```\n\nThen pull the latest image and restart the container:\n\n```bash\ndocker compose pull\ndocker compose up -d\n```\n\nData persists in the named Docker volume across updates.\n\n### Health Check\n\n```bash\ncurl http://localhost:3000/api/health\n```\n\nExample response:\n\n```json\n{\n  \"status\": \"healthy\",\n  \"version\": \"1.0.0\",\n  \"setup\": \"complete\",\n  \"license\": \"configured\",\n  \"licenseInfo\": {\n    \"valid\": true,\n    \"teamSize\": 10,\n    \"expiresAt\": \"2026-06-01T00:00:00.000Z\"\n  },\n  \"repos_parsed\": 5,\n  \"uptime\": 3600,\n  \"connectivity\": {\n    \"llm\": \"configured\",\n    \"llm_provider\": \"openai\",\n    \"embedding\": \"configured\",\n    \"embedding_provider\": \"openai\",\n    \"github\": \"configured\",\n    \"gitlab\": \"not configured\"\n  }\n}\n```\n\n## Connecting AI Clients\n\nOnce deployed, point your MCP clients to your deployment URL. See [Connecting Your AI Client](/enterprise/on-premise#connecting-your-ai-client) for client-specific instructions.\n"
  },
  {
    "path": "docs/enterprise/deployment/kubernetes.mdx",
    "content": "---\ntitle: \"Kubernetes Deployment\"\nsidebarTitle: \"Kubernetes\"\n---\n\nDeploy Context7 On-Premise on Kubernetes using raw manifests. This guide assumes you have completed the [On-Premise setup](/enterprise/on-premise) and have a valid license key.\n\n## Prerequisites\n\n- Kubernetes cluster (v1.24+)\n- `kubectl` configured for your cluster\n- A StorageClass that supports `ReadWriteOnce` volumes\n- Context7 license key\n\n## Registry Authentication\n\nContext7 Enterprise images are hosted on `ghcr.io` and require authentication. Create an image pull secret using your license key:\n\n```bash\nLICENSE_KEY=\"<your-license-key>\"\n\n# Get a registry token from Context7\nTOKEN=$(curl -s -H \"Authorization: Bearer $LICENSE_KEY\" \\\n  https://context7.com/api/v1/license/registry-token | jq -r '.token')\n\n# Create the namespace and secrets\nkubectl create namespace context7\n\nkubectl create secret docker-registry context7-registry \\\n  --namespace context7 \\\n  --docker-server=ghcr.io \\\n  --docker-username=x-access-token \\\n  --docker-password=\"$TOKEN\" \\\n  --dry-run=client -o yaml | kubectl apply -f -\n\nkubectl create secret generic context7-config \\\n  --namespace context7 \\\n  --from-literal=LICENSE_KEY=\"$LICENSE_KEY\" \\\n  --dry-run=client -o yaml | kubectl apply -f -\n```\n\n## Manifests\n\nContext7 Enterprise runs as a single-replica StatefulSet with persistent storage. The manifests below define the core resources: a StatefulSet for the application, a Service for internal routing, and an Ingress for external access.\n\n### StatefulSet\n\nContext7 uses SQLite and LanceDB for local storage, which require a persistent volume. This means it must run as a **StatefulSet with a single replica** since SQLite does not support concurrent writers.\n\n```yaml statefulset.yaml\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: context7\n  namespace: context7\nspec:\n  serviceName: context7\n  replicas: 1\n  selector:\n    matchLabels:\n      app: context7\n  template:\n    metadata:\n      labels:\n        app: context7\n    spec:\n      imagePullSecrets:\n        - name: context7-registry\n      terminationGracePeriodSeconds: 60\n      containers:\n        - name: context7\n          image: ghcr.io/context7/enterprise:latest\n          imagePullPolicy: Always\n          ports:\n            - containerPort: 3000\n              name: http\n          env:\n            - name: LICENSE_KEY\n              valueFrom:\n                secretKeyRef:\n                  name: context7-config\n                  key: LICENSE_KEY\n          volumeMounts:\n            - name: data\n              mountPath: /data\n          resources:\n            requests:\n              cpu: \"1\"\n              memory: \"2Gi\"\n            limits:\n              cpu: \"4\"\n              memory: \"8Gi\"\n          startupProbe:\n            httpGet:\n              path: /api/health\n              port: http\n            initialDelaySeconds: 5\n            periodSeconds: 5\n            failureThreshold: 12\n          livenessProbe:\n            httpGet:\n              path: /api/health\n              port: http\n            periodSeconds: 30\n            timeoutSeconds: 5\n            failureThreshold: 3\n          readinessProbe:\n            httpGet:\n              path: /api/health\n              port: http\n            periodSeconds: 10\n            timeoutSeconds: 5\n            failureThreshold: 3\n  volumeClaimTemplates:\n    - metadata:\n        name: data\n      spec:\n        # storageClassName: gp3  # Set this if your cluster has no default StorageClass\n        accessModes: [\"ReadWriteOnce\"]\n        resources:\n          requests:\n            storage: 10Gi\n```\n\n<Note>\n  **Storage class:** If your cluster does not have a default StorageClass, the PVC will stay in `Pending` and the pod won't start. Uncomment `storageClassName` and set it to a StorageClass available in your cluster (e.g. `gp3` on AWS EKS, `standard` on GKE, `default` on AKS). Run `kubectl get sc` to see available options.\n</Note>\n\n<Note>\n  **Resource sizing:** The defaults above (1 CPU / 2 GiB request) work for light usage. If you are parsing many large repositories concurrently, increase the limits. Parsing is CPU and memory intensive due to LLM calls and vector indexing.\n</Note>\n\n<Warning>\n  Do not set `replicas` higher than 1. Context7 uses SQLite which only supports a single writer. Running multiple replicas will cause database lock errors.\n</Warning>\n\n### Service\n\n```yaml service.yaml\napiVersion: v1\nkind: Service\nmetadata:\n  name: context7\n  namespace: context7\nspec:\n  selector:\n    app: context7\n  ports:\n    - port: 3000\n      targetPort: http\n      protocol: TCP\n      name: http\n  type: ClusterIP\n```\n\n### Ingress\n\n```yaml ingress.yaml\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: context7\n  namespace: context7\n  annotations:\n    nginx.ingress.kubernetes.io/proxy-body-size: \"50m\"\nspec:\n  ingressClassName: nginx\n  tls:\n    - hosts:\n        - context7.internal.yourcompany.com\n      secretName: context7-tls\n  rules:\n    - host: context7.internal.yourcompany.com\n      http:\n        paths:\n          - path: /\n            pathType: Prefix\n            backend:\n              service:\n                name: context7\n                port:\n                  number: 3000\n```\n\nReplace `context7.internal.yourcompany.com` with your actual hostname and `context7-tls` with your TLS secret.\n\n## Apply Everything\n\nAfter creating the namespace and secrets in the [Registry Authentication](#registry-authentication) step, apply the manifests:\n\n```bash\nkubectl apply -f statefulset.yaml\nkubectl apply -f service.yaml\nkubectl apply -f ingress.yaml\n```\n\nVerify the pod is running:\n\n```bash\nkubectl get pods -n context7\nkubectl logs -n context7 context7-0\n```\n\nOnce the pod is ready, open your Ingress hostname in a browser to complete the setup wizard.\n\n## Networking Requirements\n\nContext7 requires outbound connectivity to the following:\n\n| Destination | Purpose |\n|---|---|\n| `ghcr.io` | Container image pulls (`imagePullPolicy: Always`) |\n| `context7.com` | License validation |\n| Your LLM provider (e.g. `api.openai.com`) | AI inference and embeddings |\n| `github.com` / `gitlab.com` | Repository cloning |\n\nIf you use NetworkPolicies, ensure egress to these endpoints is allowed:\n\n```yaml networkpolicy.yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: context7-egress\n  namespace: context7\nspec:\n  podSelector:\n    matchLabels:\n      app: context7\n  policyTypes:\n    - Egress\n  egress:\n    - {} # Allow all egress (simplest)\n```\n\nFor stricter policies, allow egress on port 443 to the specific domains listed above, and ensure egress to `kube-dns` on port 53 (UDP/TCP) is permitted for DNS resolution.\n\n## Operations\n\n### Updating\n\nPull the latest image and restart:\n\n```bash\nkubectl rollout restart statefulset/context7 -n context7\n```\n\nTo pin a specific version:\n\n```bash\nkubectl set image statefulset/context7 \\\n  context7=ghcr.io/context7/enterprise:1.2.0 \\\n  -n context7\n```\n\nIf your registry token has expired, refresh it before restarting:\n\n```bash\nLICENSE_KEY=\"<your-license-key>\"\n\nTOKEN=$(curl -s -H \"Authorization: Bearer $LICENSE_KEY\" \\\n  https://context7.com/api/v1/license/registry-token | jq -r '.token')\n\nkubectl create secret docker-registry context7-registry \\\n  --namespace context7 \\\n  --docker-server=ghcr.io \\\n  --docker-username=x-access-token \\\n  --docker-password=\"$TOKEN\" \\\n  --dry-run=client -o yaml | kubectl apply -f -\n```\n\n### Health Monitoring\n\nThe `/api/health` endpoint returns structured JSON with license status, connectivity, and parsed repo count. Point your monitoring stack at it:\n\n```bash\nkubectl exec -n context7 context7-0 -- \\\n  wget -qO- http://localhost:3000/api/health\n```\n\nExample response:\n\n```json\n{\n  \"status\": \"healthy\",\n  \"version\": \"1.0.0\",\n  \"setup\": \"complete\",\n  \"license\": \"configured\",\n  \"licenseInfo\": {\n    \"valid\": true,\n    \"teamSize\": 10,\n    \"expiresAt\": \"2026-06-01T00:00:00.000Z\"\n  },\n  \"repos_parsed\": 5,\n  \"uptime\": 3600,\n  \"connectivity\": {\n    \"llm\": \"configured\",\n    \"llm_provider\": \"openai\",\n    \"embedding\": \"configured\",\n    \"embedding_provider\": \"openai\",\n    \"github\": \"configured\",\n    \"gitlab\": \"not configured\"\n  }\n}\n```\n\n### Logs\n\n```bash\n# Follow logs\nkubectl logs -f -n context7 context7-0\n\n# Check license and startup status\nkubectl logs -n context7 context7-0 | head -20\n```\n\n## Troubleshooting\n\n### Pod is in CrashLoopBackOff\n\nContext7 validates your license key on startup. If the key is missing, invalid, or expired, the server exits immediately before the health endpoint is available. This means Kubernetes will report `CrashLoopBackOff` rather than a failed probe.\n\nCheck the logs first:\n\n```bash\nkubectl logs -n context7 context7-0\n```\n\nLook for `[license]` messages in the first few lines. Common causes:\n\n- **Missing or incorrect `LICENSE_KEY`** in the `context7-config` secret\n- **No outbound connectivity** to `context7.com` for license validation\n- **Expired license**: contact [context7@upstash.com](mailto:context7@upstash.com) to renew\n\n<Note>\n  The startup probe only comes into play after the license is validated. If the pod is crash-looping, the issue is always upstream of the probe. Check logs, not probe events.\n</Note>\n\n## Connecting AI Clients\n\nOnce deployed, point your MCP clients to your Ingress URL. See [Connecting Your AI Client](/enterprise/on-premise#connecting-your-ai-client) for client-specific instructions. Replace `localhost:3000` with your Kubernetes Ingress hostname.\n"
  },
  {
    "path": "docs/enterprise/on-premise.mdx",
    "content": "---\ntitle: \"On-Premise Deployment\"\nsidebarTitle: \"Getting Started\"\n---\n\nContext7 On-Premise lets you run the full Context7 stack inside your own infrastructure. Your code, documentation, and embeddings never leave your environment.\n\n## What's Included\n\n- Full Context7 parsing and indexing pipeline\n- Local vector storage (no external vector DB required)\n- Built-in MCP server. Works with any MCP-compatible AI client\n- Web UI for managing indexed libraries and configuration\n- REST API compatible with the public Context7 API\n- Private GitHub and GitLab repository ingestion\n\n<Frame>\n  ![On-Premise Architecture](/images/on-premise-architecture.png)\n</Frame>\n\n## Setup\n\n<Steps>\n\n<Step title=\"Request a trial\">\n\nGo to [context7.com/plans](https://context7.com/plans) and click **On-Premise Trial**. Fill out the request form. No credit card required. You'll receive a 30-day full-featured license key via email once approved.\n\n</Step>\n\n<Step title=\"Deploy\">\n\nFollow the deployment guide for your platform:\n\n<CardGroup cols={2}>\n  <Card title=\"Docker\" icon=\"docker\" href=\"/enterprise/deployment/docker\">\n    Deploy with Docker Compose\n  </Card>\n  <Card title=\"Kubernetes\" icon=\"dharmachakra\" href=\"/enterprise/deployment/kubernetes\">\n    Deploy on Kubernetes with raw manifests\n  </Card>\n</CardGroup>\n\n</Step>\n\n<Step title=\"Complete the setup wizard\">\n\nOpen `http://localhost:3000` in your browser. On first launch, the setup wizard guides you through configuring:\n\n1. **AI Provider** - Choose OpenAI, Anthropic, Gemini, or a custom OpenAI-compatible endpoint. Enter your API key and model name.\n2. **Embedding Provider** - Use the same provider as your LLM, or configure a separate one for embeddings.\n3. **Git Tokens** - Add a GitHub and/or GitLab token for the platforms you use.\n\nAll configuration is stored locally in the embedded database and can be updated later from the Settings page.\n\n</Step>\n\n<Step title=\"Ingest your first repository\">\n\nFrom the dashboard, click **Add Repository** and enter a GitHub or GitLab URL. Once ingestion completes, your private docs are ready to query.\n\nYou can also add libraries via the REST API:\n\n```bash\ncurl -X POST http://localhost:3000/api/parse \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://github.com/your-org/your-repo\"}'\n```\n\n</Step>\n\n</Steps>\n\n## Connecting Your AI Client\n\nPoint your MCP client at your deployment URL. Replace `https://context7.internal.yourcompany.com` with your actual host.\n\n### Claude Code\n\n```bash\nclaude mcp add --scope user --transport http context7 https://context7.internal.yourcompany.com/mcp\n```\n\n### Cursor\n\nAdd to `~/.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://context7.internal.yourcompany.com/mcp\"\n    }\n  }\n}\n```\n\n### Opencode\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"remote\",\n      \"url\": \"https://context7.internal.yourcompany.com/mcp\",\n      \"enabled\": true\n    }\n  }\n}\n```\n\nFor other clients, see [All Clients](/resources/all-clients).\n\n## Configuration\n\n### Environment Variables\n\nThese are set in your `docker-compose.yml` or `.env` file before starting the container.\n\n| Variable | Required | Description |\n|---|---|---|\n| `LICENSE_KEY` | Yes | License key issued by Upstash |\n| `PORT` | No | HTTP port (default: `3000`) |\n| `DATA_DIR` | No | Data directory inside the container (default: `./data`) |\n\n<Note>\nAI provider keys, model settings, and git tokens are **not** set via environment variables. They are configured through the setup wizard and can be updated anytime from the Settings page in the web UI.\n</Note>\n\n### AI Provider Settings\n\nConfigured via the **Settings** page in the web UI.\n\n| Setting | Description |\n|---|---|\n| LLM Provider | `openai`, `anthropic`, `gemini`, or custom |\n| LLM API Key | API key for your chosen provider |\n| LLM Model | Model name (e.g. `gpt-4o`, `claude-sonnet-4-5`, `gemini-2.5-flash`) |\n| LLM Base URL | Custom OpenAI-compatible endpoint (for local models or proxies) |\n\n#### Examples\n\n<Tabs>\n  <Tab title=\"OpenRouter\">\n    ```\n    Provider: custom\n    Base URL: https://openrouter.ai/api/v1\n    Model: openai/gpt-4o\n    API Key: sk-or-v1-...\n    ```\n  </Tab>\n  <Tab title=\"Local Model (Ollama, vLLM)\">\n    ```\n    Provider: custom\n    Base URL: http://host.docker.internal:11434/v1\n    Model: llama3.2\n    API Key: ollama\n    ```\n  </Tab>\n</Tabs>\n\n### Embedding Settings\n\nBy default, Context7 uses the same provider as your LLM for generating embeddings. You can configure a separate embedding provider if needed.\n\n| Setting | Description |\n|---|---|\n| Embedding Provider | `openai` or `gemini` |\n| Embedding API Key | Separate API key for embeddings (falls back to LLM API key) |\n| Embedding Model | Embedding model name (e.g. `text-embedding-3-small`) |\n| Embedding Base URL | Custom embedding endpoint |\n\n### Git Access Tokens\n\nConfigured via the **Settings** page in the web UI.\n\n| Setting | Description |\n|---|---|\n| GitHub Token | GitHub Personal Access Token. Required for GitHub repositories |\n| GitLab Token | GitLab token. Required for GitLab repositories |\n\nYou only need tokens for the platforms you use. If you only parse GitLab repos, you don't need a GitHub token, and vice versa. Create tokens with `repo` scope (GitHub) or `read_repository` scope (GitLab) for private repository access.\n\n## Access Control\n\nAdmin credentials are set during first login (default: `admin` / `admin`). Change these immediately after setup via **Settings > Change Credentials**.\n\nThe Settings page lets you control which operations are available without authentication.\n\n| Permission | Default | Description |\n|---|---|---|\n| Allow anonymous parse | Off | Allow unauthenticated users to trigger parsing |\n| Allow anonymous refresh | Off | Allow unauthenticated users to refresh libraries |\n| Allow anonymous delete | Off | Allow unauthenticated users to delete libraries |\n| Allow anonymous support bundle | Off | Allow unauthenticated support bundle downloads |\n\nWhen a permission is off, the operation requires admin login. The MCP endpoint and search API are always publicly accessible.\n\n## Web UI\n\nOpen your deployment URL in a browser to access the dashboard. From here you can:\n\n- Add and remove libraries\n- Trigger re-indexing\n- Monitor parsing status and logs\n- Update AI provider settings, git tokens, and permissions\n- Test MCP connectivity\n- Change admin credentials\n\n## Operations\n\nFor updating, health checks, and other operational tasks, see the deployment guide for your platform:\n\n- [Docker Operations](/enterprise/deployment/docker#operations)\n- [Kubernetes Operations](/enterprise/deployment/kubernetes#operations)\n\n## Support\n\nFor license issues, upgrade requests, or deployment questions, contact [context7@upstash.com](mailto:context7@upstash.com).\n"
  },
  {
    "path": "docs/enterprise.mdx",
    "content": "---\ntitle: Enterprise\nsidebarTitle: Overview\n---\n\nContext7 Enterprise converts your internal documentation into structured, high-quality context optimized for LLMs — enabling human developers, coding agents, and engineering leaders to build faster and operate with clarity.\n\n## Core Use Cases\n\n### Assist Human Developers\n\nCut onboarding time and reduce internal support load.\n\n- Faster onboarding and fewer interruptions\n- Immediate API/service reference inside IDEs\n- Always-up-to-date documentation context\n- Reduced Slack/Teams dependency\n\n### Power Coding Agents With Correct Documentation\n\nLet your agents write correct code on the first try.\n\n- Supply agents with accurate repo + docs context\n- Reduce hallucinations and incorrect API calls\n- Enable autonomous generation, refactoring, and analysis\n- Feed structured context into LangGraph/agent frameworks\n\n### Engineering Management & Knowledge Governance\n\nOne source of truth. Zero stale docs.\n\n- Enforce documentation and context rules across projects\n- Automatically parse APIs, RST/Sphinx, MDX, OpenAPI\n- Detect outdated or inconsistent sections\n- Maintain a single source of truth across engineering\n\n## Enterprise Features\n\n- **SOC 2 certified** cloud infrastructure\n- **SSO** (SAML / OIDC)\n- Unlimited seats and teamspaces\n- Custom volume expansions and high-usage plans\n- Private GitHub / GitLab / Bitbucket repository ingestion\n- Professional support with response time SLA\n- Self-hosted deployment options available\n\n## Security & Compliance\n\nContext7 runs on **SOC 2 Type II** compliant infrastructure provided by [Upstash](https://upstash.com). Key security highlights include:\n\n- **Privacy-first architecture** — your original prompts and code never leave your AI assistant. Only MCP-formulated search queries reach the Context7 API, and sensitive data is stripped before transmission.\n- **Encryption** at rest and in transit (TLS 1.2+)\n- **VPC isolation**, RBAC, DDoS protection, and 24/7 monitoring\n- **API key security** — cryptographically generated, hashed, encrypted, and rate-limited\n- **Enterprise SSO** — supports SAML 2.0, OAuth 2.0, and OpenID Connect (OIDC)\n- **GDPR compliant** with data access, deletion, and portability rights\n- Data stored in the US and EU with cross-border transfers following GDPR and EU-U.S. Data Privacy Framework\n- **ISO 27001** certification in progress\n- Open-source MCP server — publicly auditable at [github.com/upstash/context7](https://github.com/upstash/context7)\n\nEnterprise customers can also disable query storage, use their own LLM provider for code extraction and private library ranking, and limit context retrieval to privately indexed documentation only.\n\nFor full details, see the [Security](/resources/security) page and the [Upstash Trust Center](https://trust.upstash.com/).\n\n## Quality & Safety\n\nContext7 is built with retrieval quality and trust at its core:\n\n- **Benchmark-driven retrieval** — a library benchmark system generates developer-style questions and measures how effectively each library answers them. Scores are publicly visible and help prioritize better-performing libraries during retrieval.\n- **Trust scores** — every library receives a trust score based on repository signals (stars, activity, account age) and website signals (TLS, domain authority, backlinks). This ensures reliable, well-established libraries are surfaced first.\n- **Deduplication** — exact match checking and cosine similarity filtering remove redundant code snippets and overlapping documentation content.\n- **Version-aware parsing** — a version analyzer detects multi-version documentation structures, ensuring only current docs are stored by default while older versions remain accessible.\n- **Prompt injection protection** — a two-pass detection pipeline combining complementary stages blocks malicious documentation content while minimizing false positives. Pipelines are regularly updated to address evolving attack methods.\n- **Minimal data ingestion** — Context7 does not ingest user code, conversation history, or other sensitive data.\n\nFor more details, see the [Quality and Safety in Context7](https://upstash.com/blog/context7-quality-and-safety) blog post.\n\n## Pricing\n\nFor pricing details and custom plans, [contact us](mailto:context7@upstash.com).\n\n## About Upstash\n\nContext7 is built by [Upstash](https://upstash.com), a serverless data platform powering 80,000+ active databases worldwide. Upstash delivers managed Redis, Vector, Queue, and Search services — processing 850+ billion requests per month with 99.99%+ uptime. Backed by Andreessen Horowitz (a16z) and headquartered in California, Upstash brings deep distributed systems expertise. Context7 follows the same engineering, reliability, and security standards.\n\n## Contact\n\n<CardGroup cols={2}>\n  <Card title=\"Email\" icon=\"envelope\" href=\"mailto:context7@upstash.com\">\n    context7@upstash.com\n  </Card>\n  <Card title=\"Website\" icon=\"globe\" href=\"https://context7.com\">\n    context7.com\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/howto/api-keys.mdx",
    "content": "---\ntitle: API Keys\ndescription: Create and manage API keys for Context7 authentication\n---\n\nAPI keys authenticate your requests to Context7's documentation services.\n\n## Managing API Keys\n\n![API Keys card showing list of keys with details](/images/dashboard/api-keys-card.png)\n\n### Creating API Keys\n\nGenerate a new API key in four simple steps:\n\n1. **Click \"Create API Key\"** in the API Keys card\n2. **Enter a name** (optional but recommended)\n   - Use descriptive names like \"Cursor\", \"Claude\", \"VS Code\", or \"Windsurf\"\n   - This helps you identify keys later\n3. **Copy the key immediately**\n   - Keys are shown only once for security\n   - Format: `ctx7sk-**********************`\n4. **Use in your requests or add to your MCP configuration**:\n\n```bash\ncurl \"https://context7.com/api/v2/context?libraryId=/vercel/next.js&query=routing\" \\\n  -H \"Authorization: Bearer YOUR_API_KEY\"\n```\n\n<Warning>Store your API key securely. You won't be able to see it again after creation.</Warning>\n\n### Revoking Keys\n\nRemove API keys you no longer need:\n\n1. **Click the delete button** next to the key\n2. **Confirm deletion** in the modal\n3. **Key deactivates immediately** - all requests using it will fail\n\n<Note>\n  Revoking a key is permanent and cannot be undone. Update any applications using the key before\n  revoking.\n</Note>\n"
  },
  {
    "path": "docs/howto/chat-widget.mdx",
    "content": "---\ntitle: Chat Widget\ndescription: Embed an AI-powered chat assistant on your documentation site\n---\n\nAdd an AI chat widget to your documentation site so visitors can ask questions and get instant answers powered by your library's documentation on Context7.\n\nThe widget is a lightweight JavaScript snippet that renders a floating chat button. When clicked, it opens a chat panel where users can ask questions about your library and receive AI-generated answers grounded in your documentation.\n\n<Note>The chat widget is available to library owners who have [claimed their library](/howto/claiming-libraries).</Note>\n\n## How It Works\n\n1. A visitor clicks the chat bubble on your site\n2. They type a question about your library\n3. The widget searches your library's documentation on Context7\n4. An AI model generates an answer using the relevant documentation\n5. The response streams back in real time with markdown formatting\n\n## Setup\n\n<Steps>\n  <Step title=\"Claim Your Library\">\n    You must be a verified owner of the library on Context7. If you haven't claimed it yet, follow the [Claim Your Library](/howto/claiming-libraries) guide.\n  </Step>\n\n  <Step title=\"Enable the Widget\">\n    Navigate to your library's admin page:\n\n    ```\n    https://context7.com/{owner}/{repo}/admin\n    ```\n\n    Open the **Chat** tab and toggle **Widget enabled** on.\n  </Step>\n\n  <Step title=\"Add Allowed Domains\">\n    Add the domains where the widget will be embedded. The widget will only work on domains you explicitly allow.\n\n    Examples:\n    - `docs.example.com` — exact domain match\n    - `*.example.com` — matches all subdomains (e.g., `docs.example.com`, `blog.example.com`)\n    - `example.com` — matches the root domain only\n\n    <Warning>\n      The widget will not work on any external site until you add at least one allowed domain.\n    </Warning>\n  </Step>\n\n  <Step title=\"Save Settings\">\n    Click **Save** to persist your widget configuration.\n  </Step>\n\n  <Step title=\"Add the Script Tag\">\n    Copy the embed code from the admin panel and add it to your site's HTML:\n\n    ```html\n    <script\n      src=\"https://context7.com/widget.js\"\n      data-library=\"/owner/repo\"\n    ></script>\n    ```\n\n    Place this tag in your root layout or HTML file so the widget loads on every page. The script loads asynchronously and does not block page rendering.\n  </Step>\n</Steps>\n\n## Adding with AI\n\nYou can use an AI coding assistant to add the widget automatically. Copy the following prompt and paste it into Claude Code, Cursor, or any AI coding assistant. Replace `/owner/repo` with your library identifier. The assistant will detect your framework and place the script tag in the correct location.\n\n```\nAdd the Context7 chat widget to my documentation site. This is a lightweight\nJavaScript widget that adds an AI-powered chat assistant to any webpage. It\nloads asynchronously and renders a floating chat button.\n\nThe widget is loaded via a script tag:\n<script src=\"https://context7.com/widget.js\" data-library=\"/owner/repo\"></script>\n\nDetect which framework this project uses and add the widget accordingly. Place\nit in the root layout or HTML file so it loads on every page.\n\nOptional attributes: data-color (hex color, default #059669), data-position\n(bottom-right or bottom-left), data-placeholder (input placeholder text).\n```\n\n## Framework Examples\n\n<Tabs>\n  <Tab title=\"Next.js\">\n    Use the `next/script` component in your root layout so the widget loads on every page:\n\n    ```tsx app/layout.tsx\n    import Script from \"next/script\";\n\n    export default function RootLayout({ children }) {\n      return (\n        <html lang=\"en\">\n          <body>\n            {children}\n            <Script\n              src=\"https://context7.com/widget.js\"\n              data-library=\"/owner/repo\"\n              strategy=\"afterInteractive\"\n            />\n          </body>\n        </html>\n      );\n    }\n    ```\n  </Tab>\n\n  <Tab title=\"Docusaurus\">\n    Add the script to the `scripts` array in your Docusaurus config:\n\n    ```js docusaurus.config.js\n    export default {\n      // ...other config\n      scripts: [\n        {\n          src: \"https://context7.com/widget.js\",\n          \"data-library\": \"/owner/repo\",\n          async: true,\n        },\n      ],\n    };\n    ```\n  </Tab>\n\n</Tabs>\n\n## Customization\n\nThe widget supports optional attributes for customization:\n\n| Attribute            | Description                            | Default              |\n| -------------------- | -------------------------------------- | -------------------- |\n| `data-library`       | Your library identifier (required)     | —                    |\n| `data-color`         | Brand color for the widget (hex code)  | `#059669`            |\n| `data-position`      | Widget position on the page            | `bottom-right`       |\n| `data-placeholder`   | Placeholder text in the input field    | `Ask about the docs...` |\n\n### Examples\n\n**Custom color and position:**\n\n```html\n<script\n  src=\"https://context7.com/widget.js\"\n  data-library=\"/vercel/next.js\"\n  data-color=\"#0070F3\"\n  data-position=\"bottom-left\"\n></script>\n```\n\n**Custom placeholder text:**\n\n```html\n<script\n  src=\"https://context7.com/widget.js\"\n  data-library=\"/vercel/next.js\"\n  data-placeholder=\"Ask me anything about Next.js...\"\n></script>\n```\n\n### Position Options\n\n| Value          | Description                       |\n| -------------- | --------------------------------- |\n| `bottom-right` | Fixed to the bottom-right corner  |\n| `bottom-left`  | Fixed to the bottom-left corner   |\n\n## Domain Configuration\n\n### Allowed Domains\n\nYou can configure up to **20 allowed domains** per library. The widget validates the requesting origin against this list on every chat request.\n\n| Pattern            | Matches                                             |\n| ------------------ | --------------------------------------------------- |\n| `docs.example.com` | Only `docs.example.com`                             |\n| `*.example.com`    | Any subdomain: `docs.example.com`, `blog.example.com`, and `example.com` itself |\n| `example.com`      | Only the root domain `example.com`                  |\n\n<Note>\n  Domain validation is enforced server-side. Requests from domains not in your allowed list are rejected with a 403 error.\n</Note>\n\n### Adding and Removing Domains\n\nManage domains from the **Chat** tab on your library's admin page:\n\n1. Click **Add domain** to add a new entry\n2. Enter the domain (e.g., `docs.example.com` or `*.example.com`)\n3. Click **Save** to apply changes\n\nTo remove a domain, click the trash icon next to it and save.\n"
  },
  {
    "path": "docs/howto/claiming-libraries.mdx",
    "content": "---\ntitle: Claim Your Library\ndescription: Verify ownership and manage your library's configuration via the admin panel\n---\n\nAs a library owner, you can claim your library on Context7 to unlock advanced configuration options through a web-based admin panel. This gives you full control over how your documentation is parsed and presented to developers.\n\n<Note>Library claiming is available for Git repositories, websites, and llms.txt sources.</Note>\n\n## Why Claim Your Library?\n\nClaiming ownership provides several benefits:\n\n- **Web-based configuration**: Edit settings through a user-friendly interface instead of committing changes\n- **Teamspace management**: All project members can manage the library configuration\n- **Version management**: Add and manage multiple versions of your library documentation\n- **Usage analytics**: View metrics on how developers use your library's documentation\n- **Higher refresh limits**: Get higher rate limits for refresh operations to better manage your content\n- **Apply for verification**: Only owners can apply for the verified badge. [Learn more about verification](/howto/verification)\n\n## Claiming Process\n\n<Steps>\n  <Step title=\"Navigate to the Admin Page\">\n    You can access the admin page in two ways:\n\n    **From the Dashboard:**\n    Find your library in the dashboard and click the \"Manage\" button to open the admin configuration page.\n\n    <Frame>\n      <img src=\"/images/dashboard/admin/library-manage-button.png\" alt=\"Manage button on library card\" />\n    </Frame>\n\n    **Via Direct URL:**\n    Go directly to your library's admin page at:\n\n    ```\n    https://context7.com/{owner}/{repo}/admin\n    ```\n\n    For example: `https://context7.com/vercel/next.js/admin`\n\n  </Step>\n\n  <Step title=\"Open the Claim Modal\">\n    If you haven't claimed the library yet, you'll see a \"Claim Library\" button in the header. Click it to open the claiming modal.\n\n    <Frame>\n      <img src=\"/images/dashboard/admin/claim-library-button.png\" alt=\"Claim Library button\" />\n    </Frame>\n\n  </Step>\n\n  <Step title=\"Get Your Public Key\">\n    In the claiming modal, you'll see a generated `context7.json` configuration with your unique public key:\n\n    <Frame>\n      <img src=\"/images/dashboard/admin/claim-modal.png\" alt=\"Claim library modal\" />\n    </Frame>\n\n    The modal provides a JSON snippet like this:\n\n    ```json\n    {\n      \"url\": \"https://context7.com/vercel/next.js\",\n      \"public_key\": \"pk_abc123xyz...\"\n    }\n    ```\n\n    Click \"Copy\" to copy the configuration to your clipboard.\n\n  </Step>\n\n  <Step title=\"Host the context7.json File\">\n    <Tabs>\n      <Tab title=\"Git Repository\">\n        Create a `context7.json` file in the **root** of your repository with the copied content:\n\n        ```json\n        {\n          \"url\": \"https://context7.com/vercel/next.js\",\n          \"public_key\": \"pk_abc123xyz...\"\n        }\n        ```\n\n        <Warning>\n          The `url` must exactly match your library's URL on Context7, and the `public_key` must match the key shown in the modal.\n        </Warning>\n\n        Commit and push the file to your repository's default branch.\n      </Tab>\n      <Tab title=\"Website / llms.txt\">\n        Host the `context7.json` file anywhere under your library's base URL so it is publicly reachable. For example:\n\n        ```\n        https://docs.example.com/mylib/context7.json\n        ```\n\n        The file must contain the copied content:\n\n        ```json\n        {\n          \"url\": \"https://context7.com/websites/mylib\",\n          \"public_key\": \"pk_abc123xyz...\"\n        }\n        ```\n\n        <Warning>\n          The `url` must exactly match your library's URL on Context7, and the `public_key` must match the key shown in the modal.\n        </Warning>\n\n        Once the file is live, paste the full URL to your hosted `context7.json` into the input field shown in the modal.\n      </Tab>\n    </Tabs>\n  </Step>\n\n  <Step title=\"Verify Ownership\">\n    Click \"Claim Library\". Context7 will fetch your `context7.json`, verify the URL and public key, and grant you access to the admin panel.\n  </Step>\n</Steps>\n\n## Admin Panel Overview\n\nAfter claiming your library, the admin page shows a full configuration editor with five main tabs:\n\n- **Configuration**: Edit all library settings\n- **Chat**: Embed an AI chat assistant on your documentation site\n- **Benchmark**: Evaluation of the quality of your library's documentation\n- **Metrics**: View usage statistics\n- **Versions**: Manage different versions and tags of your library\n\n## Configuration Fields\n\n### Basic Information\n\nThese fields are available for all library types.\n\n| Field             | Description                                                                                               | Limits             |\n| ----------------- | --------------------------------------------------------------------------------------------------------- | ------------------ |\n| **Project Title** | Display name for your library in Context7. Used when the LLM cannot generate a name with high confidence. | Max 100 characters |\n| **Description**   | Brief description of your library's purpose.                                                              | Max 500 characters |\n\n### Source Settings\n\n<Tabs>\n  <Tab title=\"Git Repository\">\n    | Field                  | Description                                                                               | Limits                          |\n    | ---------------------- | ----------------------------------------------------------------------------------------- | ------------------------------- |\n    | **Branch**             | Git branch to parse. Leave empty for default branch.                                      | Max 100 characters              |\n    | **Folders to Include** | Specific folder paths to include when parsing. Leave empty to scan the entire repository. | Max 50 folders, 255 chars each  |\n    | **Folders to Exclude** | Folder paths or patterns to exclude from parsing. Supports glob patterns.                 | Max 50 patterns, 255 chars each |\n    | **Files to Exclude**   | Specific file names to exclude (filename only, not full path).                            | Max 100 files, 255 chars each   |\n\n    #### Exclusion Pattern Examples\n\n    The exclusion fields support various pattern types:\n\n    ```\n    node_modules     → Excludes any folder named \"node_modules\" anywhere\n    ./build          → Excludes \"build\" only at repository root\n    **/dist          → Excludes any \"dist\" folder anywhere (globstar)\n    docs/**/internal → Excludes \"internal\" folders under docs\n    *.test           → Excludes folders ending with .test\n    ```\n\n    <Note>\n      `excludeFiles` only accepts filenames, not paths. Use `CHANGELOG.md` instead of\n      `docs/CHANGELOG.md`.\n    </Note>\n  </Tab>\n  <Tab title=\"Website\">\n    | Field                        | Description                                                                                      | Limits                          |\n    | ---------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------- |\n    | **Base URL**                 | The root URL to crawl for documentation.                                                         | Max 100 characters              |\n    | **Display URL**              | Optional URL shown to users instead of the base URL.                                             | Max 500 characters              |\n    | **Keep Hash (URL Fragments)**| Whether to treat URLs with different hash fragments as distinct pages. Disabled by default.      | Boolean                         |\n    | **Keep Query Parameters**    | Whether to treat URLs with different query strings as distinct pages. Enabled by default.        | Boolean                         |\n    | **Exclude URLs**             | URL patterns to exclude from crawling. Supports wildcards.                                       | Max 100 patterns                |\n  </Tab>\n</Tabs>\n\n### AI Instructions\n\n| Field            | Description                                                                     | Limits                       |\n| ---------------- | ------------------------------------------------------------------------------- | ---------------------------- |\n| **Custom Rules** | Best practices and guidelines for AI coding assistants when using your library. | Max 50 rules, 255 chars each |\n\nExample rules:\n\n- \"Always use TypeScript for better type safety\"\n- \"Import components from the main package, not internal paths\"\n- \"Use environment variables for API keys, never hardcode them\"\n\n### Advanced Settings\n\nAvailable for Git repositories and websites.\n\n| Field                                | Description                                                                                                                                    | Limits  |\n| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------- |\n| **Skip Automatic Version Detection** | By default, outdated library versions are automatically detected and excluded from indexing. Enable to include all versions regardless of age. | Boolean |\n| **Redirect URL**      | Redirect users to a different library. Leave empty to disable.                                              | Max 500 characters |\n| **Disallow Indexing** | Opt-out from Context7. When enabled, documentation content is removed and the library becomes inaccessible. | Boolean            |\n\n## Managing Versions\n\nThe Versions tab lets you configure previous versions of your library that should be available in Context7.\n\n<Frame>\n  <img src=\"/images/dashboard/admin/managing-versions.png\" alt=\"Versions tab\" />\n</Frame>\n\nYou can add versions using either:\n\n- **Git tags**: Reference a specific release tag (e.g., `v1.2.0`)\n- **Git branches**: Reference a branch for version-specific documentation (e.g., `release-1.x`)\n\n| Limit            | Value             |\n| ---------------- | ----------------- |\n| Maximum versions | 20                |\n| Tag/branch name  | Max 50 characters |\n\n## Library Metrics\n\nThe Metrics tab provides insights into how developers are using your library through Context7.\n\n<Frame>\n  <img src=\"/images/dashboard/admin/library-metrics.png\" alt=\"Metrics tab\" />\n</Frame>\n\n### Usage Statistics\n\nAt the top of the metrics page, you'll see key usage numbers:\n\n| Metric                 | Description                                                           |\n| ---------------------- | --------------------------------------------------------------------- |\n| **Page Views**         | Number of times your library page was viewed on Context7              |\n| **API Requests (TXT)** | Documentation requests via the REST API                               |\n| **MCP Requests**       | Documentation requests via the MCP server (from AI coding assistants) |\n\nThe metrics page also includes a usage chart showing trends over time, topic queries showing what developers ask about, and country distribution of requests.\n\n<Note>All team members can view and edit library settings. See [Teamspace Management](/howto/teamspace) for role details.</Note>\n\n## Removing Ownership\n\n<Steps>\n  <Step title=\"Go to the Admin Page\">\n    Navigate to your library's admin page at `https://context7.com/admin/{owner}/{repo}`.\n  </Step>\n  <Step title=\"Open the Ownership Menu\">Click the ownership menu in the header area.</Step>\n  <Step title=\"Remove Ownership\">Select \"Remove Ownership\" and confirm the action.</Step>\n</Steps>\n\n<Warning>\n  Removing ownership keeps the admin configuration intact. Another user can claim the library and\n  inherit the existing settings.\n</Warning>\n\n## Troubleshooting\n\n### \"context7.json not found\"\n\nEnsure the file is:\n\n- Named exactly `context7.json` (lowercase)\n- Located in the repository root, not a subdirectory\n- Committed and pushed to the default branch\n\n### \"URL mismatch\"\n\nThe `url` field in your `context7.json` must exactly match:\n\n```\nhttps://context7.com/{owner}/{repo}\n```\n\nCheck for typos, case sensitivity, and trailing slashes.\n\n### \"Public key mismatch\"\n\nThe `public_key` in your file must match the key shown in the claiming modal. Copy the entire key including the `pk_` prefix.\n\n### Changes not appearing\n\nAfter saving configuration changes, you may need to:\n\n- Manually trigger a refresh from the library page\n- Clear any cached documentation on your end\n\n"
  },
  {
    "path": "docs/howto/oauth.mdx",
    "content": "---\ntitle: OAuth\ndescription: Authenticate with Context7 MCP server using OAuth 2.0\n---\n\n<Note>\n  OAuth is only available for remote HTTP connections. For local MCP connections using stdio\n  transport, use [API key authentication](/howto/api-keys) instead.\n</Note>\n\nContext7 MCP server supports OAuth 2.0 authentication for MCP clients that implement the [MCP OAuth specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization).\n\n## Why Use OAuth?\n\n| Feature                    | OAuth | API Keys |\n| -------------------------- | ----- | -------- |\n| No manual key management   | ✅    | ❌       |\n| Automatic token refresh    | ✅    | ❌       |\n| Works with stdio transport | ❌    | ✅       |\n\n## Configuration\n\nTo use OAuth, change the endpoint from `/mcp` to `/mcp/oauth` in your client configuration:\n\n```diff\n- \"url\": \"https://mcp.context7.com/mcp\"\n+ \"url\": \"https://mcp.context7.com/mcp/oauth\"\n```\n\n## How It Works\n\n1. Your MCP client connects to the OAuth endpoint\n2. You're redirected to Context7 to sign in\n3. After signing in, you're redirected back to your client\n4. Your client automatically handles token refresh\n\n<Warning>\n**Authentication required after setup.** Most clients won't authenticate automatically. After adding the OAuth endpoint, you'll need to explicitly authenticate through your client's MCP settings. For example, in Claude Code run `/mcp`, select the server, and choose \"Authenticate\".\n</Warning>\n\n## Client Support\n\nOAuth authentication requires your MCP client to support the [MCP OAuth specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization). If your client doesn't support OAuth, use [API key authentication](/howto/api-keys) instead.\n"
  },
  {
    "path": "docs/howto/private-repositories.mdx",
    "content": "---\ntitle: Add Private Repositories\ndescription: Add and manage private repository documentation\n---\n\nAdd your private GitHub, GitLab, or Bitbucket repositories to Context7 to make your internal documentation available to AI coding assistants.\n\n![Private Repositories card showing a table of added repositories](/images/dashboard/private-repos-card.png)\n\n## Adding Private Repositories\n\nFollow these steps to add a private repository:\n\n1. Go to the [Add Library](https://context7.com/add-library) page\n2. **Connect your account**\n   - Choose GitHub, GitLab, or Bitbucket\n   - Authorize Context7 to access your repositories\n3. **Select a repository** from your account\n4. **Submit** for parsing\n\n<Note>You must have a Pro or Enterprise plan to add private repositories.</Note>\n\n## Repository Management\n\n### Refreshing Documentation\n\nKeep your private documentation up to date:\n\n1. **Click \"Refresh\"** next to the repository\n2. Context7 re-parses the repository\n3. **You're only charged for changed content** - cached pages are free\n\n**When to refresh**:\n\n- After major documentation updates\n- After releasing new features\n- When you notice outdated information\n\n<Tip>Refresh private repos only after significant documentation changes to minimize costs.</Tip>\n\n### Removing Repositories\n\nTo remove a private repository:\n\n1. **Click \"Remove\"** next to the repository\n2. **Confirm deletion** in the modal\n3. Repository documentation becomes unavailable immediately\n\n<Warning>\n  This action is permanent. The repository will no longer be accessible via the API.\n</Warning>\n\n## Permissions\n\nAccess to private repository management is restricted by role. Only Owners and Admins can add, refresh, or remove private repositories. Developers can view repository documentation but cannot manage repositories.\n\nSee [Teamspace Management](/howto/teamspace#roles) for the complete permissions table.\n\n## Configuration\n\n### Using `context7.json`\n\nAdd a `context7.json` file to your repository root for better control over parsing:\n\n```json\n{\n  \"$schema\": \"https://context7.com/schema/context7.json\",\n  \"projectTitle\": \"Your Project Name\",\n  \"description\": \"Brief description of your project\",\n  \"folders\": [\"docs\", \"guides\"],\n  \"excludeFolders\": [\"tests\", \"dist\", \"node_modules\"],\n  \"excludeFiles\": [\"CHANGELOG.md\"],\n  \"rules\": [\"Always validate user input\", \"Use TypeScript strict mode\"]\n}\n```\n\nSee the [Adding Libraries](/adding-libraries) page for complete configuration options.\n"
  },
  {
    "path": "docs/howto/teamspace.mdx",
    "content": "---\ntitle: Manage Your Teamspace\ndescription: Invite members and manage teamspace permissions\n---\n\nAdd team members, assign roles, and manage access to your Context7 dashboard from the [members tab](https://context7.com/dashboard?tab=members).\n\n![Members tab displaying team members list with owner, admins, and developers](/images/dashboard/members-tab.png)\n\n## Creating a Teamspace\n\n![Create teamspace dropdown](/images/dashboard/user-dropdown.png)\n\n1. Click \"Create a teamspace\" from the top left dropdown\n2. Enter teamspace name\n\n<Note>You must have a Pro or Enterprise plan to create a teamspace. Only the teamspace owner needs a paid plan — invited members don't need their own subscription. Once added, all members automatically benefit from the team's Pro or Enterprise limits.</Note>\n\n## Roles\n\n| Permission            | Owner | Admin | Developer |\n| --------------------- | ----- | ----- | --------- |\n| View dashboard        | ✓     | ✓     | ✓         |\n| Create API keys       | ✓     | ✓     | ✓         |\n| Manage team members   | ✓     | ✓     | ✗         |\n| Manage library access | ✓     | ✓     | ✗         |\n| Manage private repos  | ✓     | ✓     | ✗         |\n| Rename teamspace      | ✓     | ✗     | ✗         |\n| Delete teamspace      | ✓     | ✗     | ✗         |\n\n## Inviting Members\n\n1. Enter member email\n2. Select role (Developer or Admin)\n3. Click \"Add\"\n4. Member receives an invitation email\n5. Once they sign in, they are automatically added to the teamspace\n\n<Note>The invitation will remain pending until they sign in.</Note>\n\n## Teamspace Settings\n\nIf you are the owner of the teamspace, you can rename or delete the teamspace under the overview tab.\n\n![Teamspace management card](/images/dashboard/team-management-card.png)\n\n<Warning>Deleting a teamspace is permanent. All members lose access immediately.</Warning>\n\n## Limits\n\n| Plan       | Max Members       |\n| ---------- | ----------------- |\n| Free       | 1 (personal only) |\n| Pro        | 10                |\n| Enterprise | Unlimited         |\n"
  },
  {
    "path": "docs/howto/usage.mdx",
    "content": "---\ntitle: Monitor Usage\ndescription: Monitor your Context7 API usage and track costs\n---\n\nTrack your Context7 usage with real-time metrics from the Overview tab.\n\n![Usage statistics card showing metrics and cost breakdown](/images/dashboard/usage-stats.png)\n\n## Metrics Overview\n\nContext7 tracks four key metrics to help you understand your usage patterns:\n\n### Search & Query Requests\n\nThe total number of API calls made to Context7:\n\n- **Search Requests**: Library search queries\n- **Query Requests**: Documentation retrieval calls\n\n### Query Tokens\n\nThe total number of tokens returned in API responses. This reflects how much documentation content you've retrieved.\n\n<Tip>Search requests, Query requests, and Query tokens do not affect cost.</Tip>\n\n### Parsing Tokens\n\nThe total tokens processed when parsing private repository documentation (Pro and Enterprise only).\n\n**How it works**:\n\n- Charged when adding a new private repository\n- Charged for changed content when refreshing\n- No charge for cached content when refreshing\n\n**Cost**: $25 per 1M tokens\n\n### Total Cost\n\nYour monthly cost in USD (Pro and Enterprise only).\n\n**Calculation**:\n\n```\nTotal Cost = Parsing Cost + Teamspace Cost\n\nParsing Cost = (Parsing Tokens / 1,000,000) × $25\nTeamspace Cost = Number of Members × $7\n```\n\n**Example**:\n\n- Teamspace: 4 members\n- Parsing: 800K tokens this month\n- Cost: (800K / 1M × $25) + (4 × $7) = $20 + $28 = **$48**\n\nHover over the Total Cost to see the detailed breakdown.\n\n## Reporting Periods\n\n**Free Plan**: Metrics display daily usage (resets every 24 hours)\n\n**Pro & Enterprise Plans**: Metrics display monthly usage (resets on your billing date)\n"
  },
  {
    "path": "docs/howto/verification.mdx",
    "content": "---\ntitle: Library Verification\ndescription: Get your library verified to increase visibility and build trust with developers\n---\n\nVerified libraries receive a special badge that signals quality and trustworthiness to developers. Verification helps your library rank higher in search results and gives users confidence that your documentation is reliable.\n\n<Note>Only library owners can apply for verification. You must [claim your library](/howto/claiming-libraries) before applying.</Note>\n\n## Why Get Verified?\n\nVerification provides several benefits for your library:\n\n- **Higher search ranking**: Verified libraries are prioritized in search results and recommendations\n- **Trust badge**: A verified badge is displayed on your library page, building confidence with users\n- **Increased visibility**: Verified libraries appear more prominently across Context7\n- **Broader access**: Teamspaces can restrict their library access to \"verified only\" - without verification, your library won't be accessible to these users\n\n## Verification Badge\n\nOnce verified, your library displays a green checkmark badge next to its name:\n\n<Frame>\n  <img src=\"/images/howto/verification/verification-badge.png\" alt=\"Verified badge on library\" />\n</Frame>\n\nThis badge appears on:\n- Your library's main page\n- Search results\n- Library listings and tables\n- Skills associated with your library\n\n## How to Get Verified\n\nThere are two paths to verification:\n\n### Automatic Verification\n\nLibraries are automatically verified when they meet certain quality thresholds:\n\n- **High trust score**: Libraries with a trust score of 9 or above. Trust score is calculated based on the GitHub organization/user profile, considering factors like total stars, number of repositories, account age, recent activity, followers, and profile completeness.\n- **Top 100 libraries**: Most-used libraries by API requests\n- **Top 100 skills**: Libraries with the most-installed skills\n\nAutomatic verification is checked daily. If your library qualifies, it will be verified automatically without any action required.\n\n### Manual Verification\n\nIf your library doesn't qualify for automatic verification, you can apply manually:\n\n<Steps>\n  <Step title=\"Claim Your Library\">\n    You must be a verified owner of the library. See [Claim Your Library](/howto/claiming-libraries) for instructions.\n  </Step>\n\n  <Step title=\"Go to the Admin Page\">\n    Navigate to your library's admin page at:\n\n    ```\n    https://context7.com/{owner}/{repo}/admin\n    ```\n  </Step>\n\n  <Step title=\"Apply for Verification\">\n    If your library is not yet verified, you'll see a banner at the top of the configuration page with an \"Apply for Verification\" button. Click it to start the process.\n\n    <Frame>\n      <img src=\"/images/howto/verification/apply-button.png\" alt=\"Apply for Verification button\" />\n    </Frame>\n  </Step>\n\n  <Step title=\"Instant Quality Check\">\n    When you initiate a verification request, Context7 automatically checks a set of quality criteria. If your library meets **any one** of the following criteria, it is verified instantly — no form required:\n\n    - **Trust score above 7**: Calculated from your GitHub organization/user profile, including stars, repository count, account age, recent activity, followers, and profile completeness.\n    - **250+ GitHub stars** *(repositories only)*: Indicates a strong and established community.\n    - **Top 1% by popularity ranking**: Your library is among the most in-demand sources indexed on Context7.\n    - **200+ referring domains** *(websites and llms.txt sources only)*: Your source is cited or linked to by more than 200 unique external domains, demonstrating broad recognition across the web.\n\n    If any of these thresholds are met, verification is granted immediately.\n  </Step>\n\n  <Step title=\"Complete the Application\">\n    If none of the quality thresholds are met, you'll be prompted to fill out the verification application form:\n\n    | Field | Description | Required |\n    | --- | --- | --- |\n    | **Website/Docs URL** | Link to your library's official website or documentation | Yes |\n    | **Library Description** | Brief description of what your library does | Yes |\n    | **Developer Value** | How your library helps developers | No |\n\n    <Frame>\n      <img src=\"/images/howto/verification/apply-modal.png\" alt=\"Verification application modal\" />\n    </Frame>\n  </Step>\n\n  <Step title=\"Submit for Review\">\n    Click \"Submit Application\" to send your request. Your application will be reviewed immediately.\n  </Step>\n</Steps>\n\n## Verification Requirements\n\nTo be approved for manual verification, your library should:\n\n- **Be a legitimate project**: Real libraries with actual users and documentation\n- **Have quality documentation**: Well-organized, up-to-date documentation that helps developers\n- **Be actively maintained**: Regular updates and responsive to issues\n- **Follow best practices**: Clear README, proper licensing, and good code organization\n\n<Note>\n  Verification is free and always will be. We verify libraries based on quality, not payment.\n</Note>\n\n## Verification Status\n\nYou can check your library's verification status on the admin page:\n\n| Status | Description |\n| --- | --- |\n| **Verified** | Green badge displayed, full verification benefits |\n| **Not Verified** | No badge, apply to get verified |\n\n## Skills and Verification\n\nSkills inherit the verification status of their parent library. When your library is verified:\n\n- All skills associated with your library display the verified badge\n- Skills rank higher in skill search results\n\n## FAQ\n\n### How long does manual verification take?\n\nIf your library meets one of the quality thresholds, verification is instant. Otherwise, your application is reviewed immediately after submission. If it's not automatically accepted, you can [open a GitHub issue](https://github.com/upstash/context7/issues/new/choose) to request a manual review.\n\n### Can verification be revoked?\n\nYes, in rare cases. Verification may be revoked if:\n- The library becomes abandoned or unmaintained\n- Documentation quality significantly degrades\n- The library violates Context7's terms of service\n\n### Does verification cost anything?\n\nNo. Verification is completely free and based solely on library quality.\n\n### I was automatically verified. Can I lose it?\n\nAutomatic verification is recalculated daily. If your library no longer meets the automatic criteria, you'll retain your verification status but may need to apply manually if it's ever revoked.\n\n### My library is popular but not verified. Why?\n\nAutomatic verification considers multiple factors including trust score, usage statistics, and skill installs. When you apply manually, Context7 also checks quality criterias like GitHub stars, popularity ranking, and referring domains. If you believe your library meets any of these thresholds, please apply manually and the check will run immediately.\n\n## Need Help?\n\nIf you have questions about verification or encounter issues with the application process:\n\n- [Open a GitHub issue](https://github.com/upstash/context7/issues/new/choose)\n- Join our [Discord community](https://upstash.com/discord)\n- Contact us at [support@context7.com](mailto:support@context7.com)\n"
  },
  {
    "path": "docs/installation.mdx",
    "content": "---\ntitle: Installation\nurl: https://github.com/upstash/context7#installation\n---\n\n"
  },
  {
    "path": "docs/integrations/code-rabbit.mdx",
    "content": "---\ntitle: CodeRabbit\nsidebarTitle: CodeRabbit\ndescription: AI-powered code review tool\n---\n\n[CodeRabbit](https://coderabbit.ai) is an AI-powered code review tool that automatically reviews pull requests. By connecting Context7 as an MCP server, CodeRabbit can access up-to-date library documentation during reviews, helping it verify implementations against the latest API references and best practices.\n\n## Setup\n\n<Steps>\n  <Step title=\"Navigate to MCP Servers\">\n    Go to your [CodeRabbit dashboard](https://app.coderabbit.ai) and navigate to **Integrations** → **MCP Servers**.\n\n    ![Integrations tab](/images/integrations/coderabbit/integrations-tab.png)\n  </Step>\n  <Step title=\"Add Context7\">\n    Click the **Add** button next to **Context7** MCP server.\n\n    Add the following header for higher rate limits:\n\n    | Header | Value |\n    |--------|-------|\n    | `CONTEXT7_API_KEY` | Your API key from the [Context7 dashboard](https://context7.com/dashboard) |\n\n    ```json\n    {\n      \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n    }\n    ```\n\n    ![Add server modal](/images/integrations/coderabbit/add-server-modal.png)\n  </Step>\n  <Step title=\"Connect\">\n    Click the **Connect** button to connect the server.\n\n    ![Server connected](/images/integrations/coderabbit/server-connected.png)\n  </Step>\n  <Step title=\"Enable for Public Repos\">\n    To use Context7 with public repositories, go to **Organization Settings** → **Configuration** → **Knowledge Base**. In the MCP section, select **Enabled** instead of **Auto** and click **Apply Changes**.\n\n    ![Update MCP settings](/images/integrations/coderabbit/update-mcp-settings.png)\n  </Step>\n</Steps>\n\n## Usage Guidance\n\nIn the **Usage Guidance** field, you can instruct CodeRabbit on how to use Context7 during reviews. For example:\n\n```\nUse Context7 to look up documentation for any libraries used in the code being reviewed.\nVerify that API usage matches the latest documentation and flag any deprecated patterns.\n```\n\n## How It Works\n\nOnce connected, CodeRabbit will query Context7 for relevant library documentation when reviewing pull requests. This helps CodeRabbit:\n\n- Verify correct API usage against the latest documentation\n- Identify deprecated methods or patterns\n- Suggest improvements based on library best practices\n- Provide more accurate and informed review comments\n"
  },
  {
    "path": "docs/openapi.json",
    "content": "{\n  \"openapi\": \"3.0.0\",\n  \"info\": {\n    \"title\": \"Context7 Public API\",\n    \"description\": \"The Context7 Public API provides programmatic access to library documentation and search functionality. Get up-to-date documentation and code examples for any library.\",\n    \"version\": \"2.0.0\",\n    \"contact\": {\n      \"name\": \"Context7 Support\",\n      \"url\": \"https://context7.com\",\n      \"email\": \"support@context7.com\"\n    }\n  },\n  \"servers\": [\n    {\n      \"url\": \"https://context7.com/api\",\n      \"description\": \"Production server\"\n    }\n  ],\n  \"paths\": {\n    \"/v2/libs/search\": {\n      \"get\": {\n        \"summary\": \"Search for libraries\",\n        \"description\": \"Search for libraries by name with intelligent LLM-powered ranking based on your query context.\",\n        \"operationId\": \"searchLibraries\",\n        \"tags\": [\"Search\"],\n        \"parameters\": [\n          {\n            \"$ref\": \"#/components/parameters/LibraryNameParam\"\n          },\n          {\n            \"$ref\": \"#/components/parameters/QueryParam\"\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"Search results ranked by relevance\",\n            \"content\": {\n              \"application/json\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/SearchResponse\"\n                },\n                \"example\": {\n                  \"results\": [\n                    {\n                      \"id\": \"/facebook/react\",\n                      \"title\": \"React\",\n                      \"description\": \"A JavaScript library for building user interfaces\",\n                      \"branch\": \"main\",\n                      \"lastUpdateDate\": \"2025-01-15T10:30:00.000Z\",\n                      \"state\": \"finalized\",\n                      \"totalTokens\": 500000,\n                      \"totalSnippets\": 2500,\n                      \"stars\": 220000,\n                      \"trustScore\": 10,\n                      \"benchmarkScore\": 95.5,\n                      \"versions\": [\"v18.2.0\", \"v17.0.2\"]\n                    }\n                  ]\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"503\": {\n            \"$ref\": \"#/components/responses/ServiceUnavailableError\"\n          }\n        },\n        \"security\": [\n          {},\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/context\": {\n      \"get\": {\n        \"summary\": \"Get documentation context\",\n        \"description\": \"Retrieve intelligent, LLM-reranked documentation context for natural language queries. Returns the most relevant code snippets and documentation for your specific question.\",\n        \"operationId\": \"getContext\",\n        \"tags\": [\"Context\"],\n        \"parameters\": [\n          {\n            \"$ref\": \"#/components/parameters/LibraryIdParam\"\n          },\n          {\n            \"$ref\": \"#/components/parameters/QueryParam\"\n          },\n          {\n            \"$ref\": \"#/components/parameters/TypeParam\"\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"Documentation context\",\n            \"content\": {\n              \"application/json\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/ContextResponse\"\n                },\n                \"example\": {\n                  \"codeSnippets\": [\n                    {\n                      \"codeTitle\": \"Middleware Authentication Example\",\n                      \"codeDescription\": \"Shows how to implement authentication checks in Next.js middleware\",\n                      \"codeLanguage\": \"typescript\",\n                      \"codeTokens\": 150,\n                      \"codeId\": \"https://github.com/vercel/next.js/blob/canary/docs/middleware.mdx#_snippet_0\",\n                      \"pageTitle\": \"Middleware\",\n                      \"codeList\": [\n                        {\n                          \"language\": \"typescript\",\n                          \"code\": \"import { NextResponse } from 'next/server'\\nimport type { NextRequest } from 'next/server'\\n\\nexport function middleware(request: NextRequest) {\\n  const token = request.cookies.get('token')\\n  if (!token) {\\n    return NextResponse.redirect(new URL('/login', request.url))\\n  }\\n  return NextResponse.next()\\n}\"\n                        }\n                      ]\n                    }\n                  ],\n                  \"infoSnippets\": [\n                    {\n                      \"pageId\": \"https://github.com/vercel/next.js/blob/canary/docs/middleware.mdx\",\n                      \"breadcrumb\": \"Routing > Middleware\",\n                      \"content\": \"Middleware allows you to run code before a request is completed...\",\n                      \"contentTokens\": 200\n                    }\n                  ]\n                }\n              },\n              \"text/plain\": {\n                \"schema\": {\n                  \"type\": \"string\"\n                },\n                \"example\": \"### Middleware Authentication Example\\n\\nSource: https://github.com/vercel/next.js/blob/canary/docs/middleware.mdx\\n\\nShows how to implement authentication checks in Next.js middleware\\n\\n```typescript\\nimport { NextResponse } from 'next/server'\\n...\\n```\"\n              }\n            }\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"403\": {\n            \"$ref\": \"#/components/responses/ForbiddenError\"\n          },\n          \"404\": {\n            \"$ref\": \"#/components/responses/NotFoundError\"\n          },\n          \"202\": {\n            \"$ref\": \"#/components/responses/AcceptedError\"\n          },\n          \"301\": {\n            \"$ref\": \"#/components/responses/RedirectError\"\n          },\n          \"422\": {\n            \"$ref\": \"#/components/responses/UnprocessableEntityError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          }\n        },\n        \"security\": [\n          {},\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/add/repo/github\": {\n      \"post\": {\n        \"summary\": \"Add a GitHub repository\",\n        \"description\": \"Submit a GitHub repository for documentation processing. Supports private repos via a gitToken or by connecting your GitHub account at https://context7.com/add-library.\",\n        \"operationId\": \"addGitHubRepo\",\n        \"tags\": [\"Add Library\"],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/AddRepoRequest\"\n              },\n              \"example\": {\n                \"docsRepoUrl\": \"https://github.com/vercel/next.js\"\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"$ref\": \"#/components/responses/AddLibrarySuccess\"\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"403\": {\n            \"$ref\": \"#/components/responses/ForbiddenError\"\n          },\n          \"404\": {\n            \"$ref\": \"#/components/responses/NotFoundError\"\n          },\n          \"409\": {\n            \"$ref\": \"#/components/responses/DuplicateError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"504\": {\n            \"$ref\": \"#/components/responses/GatewayTimeoutError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/add/repo/gitlab\": {\n      \"post\": {\n        \"summary\": \"Add a GitLab repository\",\n        \"description\": \"Submit a GitLab repository for documentation processing. Supports private repos via a gitToken or by connecting your GitLab account at https://context7.com/add-library.\",\n        \"operationId\": \"addGitLabRepo\",\n        \"tags\": [\"Add Library\"],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/AddRepoRequest\"\n              },\n              \"example\": {\n                \"docsRepoUrl\": \"https://gitlab.com/owner/repo\"\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"$ref\": \"#/components/responses/AddLibrarySuccess\"\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"403\": {\n            \"$ref\": \"#/components/responses/ForbiddenError\"\n          },\n          \"404\": {\n            \"$ref\": \"#/components/responses/NotFoundError\"\n          },\n          \"409\": {\n            \"$ref\": \"#/components/responses/DuplicateError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"504\": {\n            \"$ref\": \"#/components/responses/GatewayTimeoutError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/add/repo/bitbucket\": {\n      \"post\": {\n        \"summary\": \"Add a Bitbucket repository\",\n        \"description\": \"Submit a Bitbucket repository for documentation processing. Supports private repos via a gitToken or by connecting your Bitbucket account at https://context7.com/add-library.\",\n        \"operationId\": \"addBitbucketRepo\",\n        \"tags\": [\"Add Library\"],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/AddRepoRequest\"\n              },\n              \"example\": {\n                \"docsRepoUrl\": \"https://bitbucket.org/owner/repo\"\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"$ref\": \"#/components/responses/AddLibrarySuccess\"\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"403\": {\n            \"$ref\": \"#/components/responses/ForbiddenError\"\n          },\n          \"404\": {\n            \"$ref\": \"#/components/responses/NotFoundError\"\n          },\n          \"409\": {\n            \"$ref\": \"#/components/responses/DuplicateError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"504\": {\n            \"$ref\": \"#/components/responses/GatewayTimeoutError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/add/repo/git\": {\n      \"post\": {\n        \"summary\": \"Add from other Git providers\",\n        \"description\": \"Submit a repository from any Git provider not covered by the dedicated GitHub, GitLab, or Bitbucket endpoints. Supports Gitea, Forgejo, Codeberg, self-hosted GitLab, and other Git servers. For private repos, provide a personal access token via the gitToken field.\",\n        \"operationId\": \"addGitRepo\",\n        \"tags\": [\"Add Library\"],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"type\": \"object\",\n                \"required\": [\"docsRepoUrl\"],\n                \"properties\": {\n                  \"docsRepoUrl\": {\n                    \"type\": \"string\",\n                    \"format\": \"uri\",\n                    \"description\": \"The Git repository URL\"\n                  },\n                  \"gitToken\": {\n                    \"type\": \"string\",\n                    \"description\": \"Personal access token for private repositories\"\n                  },\n                  \"private\": {\n                    \"type\": \"boolean\",\n                    \"description\": \"Whether the repository is private\"\n                  },\n                  \"skipBenchmark\": {\n                    \"type\": \"boolean\",\n                    \"description\": \"Skip benchmark quality scoring after parsing\"\n                  },\n                  \"skipContextGeneration\": {\n                    \"type\": \"boolean\",\n                    \"description\": \"Skip automatic default context generation\"\n                  },\n                  \"skipVersionFiltering\": {\n                    \"type\": \"boolean\",\n                    \"description\": \"Skip filtering out version-specific documentation pages\"\n                  }\n                }\n              },\n              \"example\": {\n                \"docsRepoUrl\": \"https://codeberg.org/owner/repo\"\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"$ref\": \"#/components/responses/AddLibrarySuccess\"\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"403\": {\n            \"$ref\": \"#/components/responses/ForbiddenError\"\n          },\n          \"404\": {\n            \"$ref\": \"#/components/responses/NotFoundError\"\n          },\n          \"409\": {\n            \"$ref\": \"#/components/responses/DuplicateError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"504\": {\n            \"$ref\": \"#/components/responses/GatewayTimeoutError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/add/openapi\": {\n      \"post\": {\n        \"summary\": \"Add an OpenAPI specification by URL\",\n        \"description\": \"Submit an OpenAPI specification URL for documentation processing.\",\n        \"operationId\": \"addOpenApi\",\n        \"tags\": [\n          \"Add Library\"\n        ],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"type\": \"object\",\n                \"required\": [\n                  \"openApiUrl\"\n                ],\n                \"properties\": {\n                  \"openApiUrl\": {\n                    \"type\": \"string\",\n                    \"format\": \"uri\",\n                    \"description\": \"URL pointing to an OpenAPI specification (JSON or YAML)\"\n                  }\n                }\n              },\n              \"example\": {\n                \"openApiUrl\": \"https://api.example.com/openapi.json\"\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"$ref\": \"#/components/responses/AddLibrarySuccess\"\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"504\": {\n            \"$ref\": \"#/components/responses/GatewayTimeoutError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/add/llmstxt\": {\n      \"post\": {\n        \"summary\": \"Add an llms.txt file\",\n        \"description\": \"Submit an llms.txt file URL for documentation processing.\",\n        \"operationId\": \"addLlmsTxt\",\n        \"tags\": [\n          \"Add Library\"\n        ],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"type\": \"object\",\n                \"required\": [\n                  \"llmstxtUrl\"\n                ],\n                \"properties\": {\n                  \"llmstxtUrl\": {\n                    \"type\": \"string\",\n                    \"format\": \"uri\",\n                    \"description\": \"URL pointing to an llms.txt, llms-full.txt, or llms-small.txt file\"\n                  }\n                }\n              },\n              \"example\": {\n                \"llmstxtUrl\": \"https://docs.example.com/llms.txt\"\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"$ref\": \"#/components/responses/AddLibrarySuccess\"\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"504\": {\n            \"$ref\": \"#/components/responses/GatewayTimeoutError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/add/website\": {\n      \"post\": {\n        \"summary\": \"Add a website\",\n        \"description\": \"Submit a website URL for documentation processing.\",\n        \"operationId\": \"addWebsite\",\n        \"tags\": [\n          \"Add Library\"\n        ],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"type\": \"object\",\n                \"required\": [\n                  \"websiteUrl\"\n                ],\n                \"properties\": {\n                  \"websiteUrl\": {\n                    \"type\": \"string\",\n                    \"format\": \"uri\",\n                    \"description\": \"The website URL to process\"\n                  },\n                  \"websiteBaseUrl\": {\n                    \"type\": \"string\",\n                    \"format\": \"uri\",\n                    \"description\": \"Base URL to limit crawling scope. Only pages starting with this URL will be indexed.\"\n                  }\n                }\n              },\n              \"example\": {\n                \"websiteUrl\": \"https://docs.example.com\"\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"$ref\": \"#/components/responses/AddLibrarySuccess\"\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"422\": {\n            \"$ref\": \"#/components/responses/UnprocessableEntityError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"504\": {\n            \"$ref\": \"#/components/responses/GatewayTimeoutError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v2/add/openapi-upload\": {\n      \"post\": {\n        \"summary\": \"Upload an OpenAPI specification file\",\n        \"description\": \"Upload an OpenAPI specification file (JSON or YAML) for documentation processing. Requires a team project. File size limit is 10MB.\",\n        \"operationId\": \"addOpenApiUpload\",\n        \"tags\": [\"Add Library\"],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"multipart/form-data\": {\n              \"schema\": {\n                \"type\": \"object\",\n                \"required\": [\"openapiFile\"],\n                \"properties\": {\n                  \"openapiFile\": {\n                    \"type\": \"string\",\n                    \"format\": \"binary\",\n                    \"description\": \"The OpenAPI specification file (.json, .yaml, or .yml)\"\n                  },\n                  \"libraryTitle\": {\n                    \"type\": \"string\",\n                    \"description\": \"Custom title for the library\"\n                  },\n                  \"description\": {\n                    \"type\": \"string\",\n                    \"description\": \"Description of the library\"\n                  },\n                  \"skipBenchmark\": {\n                    \"type\": \"string\",\n                    \"enum\": [\"true\"],\n                    \"description\": \"Set to 'true' to skip benchmark quality scoring\"\n                  },\n                  \"force\": {\n                    \"type\": \"string\",\n                    \"enum\": [\"true\"],\n                    \"description\": \"Set to 'true' to force reprocessing\"\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"$ref\": \"#/components/responses/AddLibrarySuccess\"\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"403\": {\n            \"$ref\": \"#/components/responses/ForbiddenError\"\n          },\n          \"404\": {\n            \"$ref\": \"#/components/responses/NotFoundError\"\n          },\n          \"409\": {\n            \"$ref\": \"#/components/responses/DuplicateError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          },\n          \"504\": {\n            \"$ref\": \"#/components/responses/GatewayTimeoutError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    },\n    \"/v1/refresh\": {\n      \"post\": {\n        \"summary\": \"Refresh a library\",\n        \"description\": \"Trigger a refresh of an existing library to fetch the latest documentation. Library owners have dedicated refresh limits.\",\n        \"operationId\": \"refreshLibrary\",\n        \"tags\": [\"Refresh\"],\n        \"requestBody\": {\n          \"required\": true,\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"type\": \"object\",\n                \"required\": [\"libraryName\"],\n                \"properties\": {\n                  \"libraryName\": {\n                    \"type\": \"string\",\n                    \"description\": \"Library identifier in `/owner/repo` format\"\n                  },\n                  \"branch\": {\n                    \"type\": \"string\",\n                    \"description\": \"Optional branch name to refresh\"\n                  },\n                  \"gitToken\": {\n                    \"type\": \"string\",\n                    \"description\": \"Optional Git access token for refreshing private repositories. If not provided, the stored OAuth token will be used.\"\n                  }\n                }\n              },\n              \"example\": {\n                \"libraryName\": \"/vercel/next.js\"\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"description\": \"Refresh started successfully\",\n            \"content\": {\n              \"application/json\": {\n                \"schema\": {\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"message\": {\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\"message\"]\n                },\n                \"example\": {\n                  \"message\": \"Refresh started successfully\"\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"$ref\": \"#/components/responses/BadRequestError\"\n          },\n          \"401\": {\n            \"$ref\": \"#/components/responses/UnauthorizedError\"\n          },\n          \"403\": {\n            \"$ref\": \"#/components/responses/ForbiddenError\"\n          },\n          \"404\": {\n            \"$ref\": \"#/components/responses/NotFoundError\"\n          },\n          \"429\": {\n            \"$ref\": \"#/components/responses/RateLimitError\"\n          },\n          \"500\": {\n            \"$ref\": \"#/components/responses/InternalServerError\"\n          }\n        },\n        \"security\": [\n          {\n            \"bearerAuth\": []\n          }\n        ]\n      }\n    }\n  },\n  \"components\": {\n    \"securitySchemes\": {\n      \"bearerAuth\": {\n        \"type\": \"http\",\n        \"scheme\": \"bearer\",\n        \"description\": \"Get your API key at [context7.com/dashboard](https://context7.com/dashboard). Treat your API key like a password and store it securely.\"\n      }\n    },\n    \"parameters\": {\n      \"LibraryNameParam\": {\n        \"name\": \"libraryName\",\n        \"in\": \"query\",\n        \"description\": \"Library name to search for (e.g., 'react', 'nextjs', 'express')\",\n        \"required\": true,\n        \"schema\": {\n          \"type\": \"string\",\n          \"minLength\": 1,\n          \"maxLength\": 500\n        },\n        \"example\": \"react\"\n      },\n      \"QueryParam\": {\n        \"name\": \"query\",\n        \"in\": \"query\",\n        \"description\": \"User's original question or task - used for intelligent relevance ranking\",\n        \"required\": true,\n        \"schema\": {\n          \"type\": \"string\",\n          \"minLength\": 1,\n          \"maxLength\": 500\n        },\n        \"example\": \"How to manage state with hooks\"\n      },\n      \"LibraryIdParam\": {\n        \"name\": \"libraryId\",\n        \"in\": \"query\",\n        \"description\": \"Context7-compatible library ID in format `/owner/repo`, `/owner/repo/version`, or `/owner/repo@version`\",\n        \"required\": true,\n        \"schema\": {\n          \"type\": \"string\",\n          \"minLength\": 1,\n          \"maxLength\": 500,\n          \"pattern\": \"^/[^/]+/[^/]+([/@][^/]+)?$\"\n        },\n        \"examples\": {\n          \"basic\": {\n            \"summary\": \"Basic library ID\",\n            \"value\": \"/vercel/next.js\"\n          },\n          \"withVersion\": {\n            \"summary\": \"With specific version (slash)\",\n            \"value\": \"/vercel/next.js/v14.3.0\"\n          },\n          \"withVersionAt\": {\n            \"summary\": \"With specific version (@ syntax)\",\n            \"value\": \"/vercel/next.js@v14.3.0\"\n          }\n        }\n      },\n      \"TypeParam\": {\n        \"name\": \"type\",\n        \"in\": \"query\",\n        \"description\": \"Response format type\",\n        \"required\": false,\n        \"schema\": {\n          \"type\": \"string\",\n          \"enum\": [\"json\", \"txt\"],\n          \"default\": \"txt\"\n        },\n        \"example\": \"json\"\n      }\n    },\n    \"schemas\": {\n      \"Library\": {\n        \"type\": \"object\",\n        \"description\": \"Library metadata\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"string\",\n            \"description\": \"Library ID in format `/owner/repo`\",\n            \"example\": \"/vercel/next.js\"\n          },\n          \"title\": {\n            \"type\": \"string\",\n            \"description\": \"Display name of the library\",\n            \"example\": \"Next.js\"\n          },\n          \"description\": {\n            \"type\": \"string\",\n            \"description\": \"Short description\",\n            \"example\": \"The React Framework\"\n          },\n          \"branch\": {\n            \"type\": \"string\",\n            \"description\": \"Git branch being tracked\",\n            \"example\": \"canary\"\n          },\n          \"lastUpdateDate\": {\n            \"type\": \"string\",\n            \"format\": \"date-time\",\n            \"description\": \"ISO 8601 timestamp of last update\",\n            \"example\": \"2025-01-15T10:30:00.000Z\"\n          },\n          \"state\": {\n            \"type\": \"string\",\n            \"enum\": [\"finalized\", \"initial\", \"processing\", \"error\", \"delete\"],\n            \"description\": \"Processing state of the library\",\n            \"example\": \"finalized\"\n          },\n          \"totalTokens\": {\n            \"type\": \"integer\",\n            \"description\": \"Total tokens in documentation\",\n            \"example\": 607822\n          },\n          \"totalSnippets\": {\n            \"type\": \"integer\",\n            \"description\": \"Number of code snippets\",\n            \"example\": 3629\n          },\n          \"stars\": {\n            \"type\": \"integer\",\n            \"description\": \"GitHub stars count\",\n            \"example\": 131745\n          },\n          \"trustScore\": {\n            \"type\": \"integer\",\n            \"description\": \"Source reputation score (0-10)\",\n            \"minimum\": 0,\n            \"maximum\": 10,\n            \"example\": 10\n          },\n          \"benchmarkScore\": {\n            \"type\": \"number\",\n            \"description\": \"Quality indicator score (0-100)\",\n            \"minimum\": 0,\n            \"maximum\": 100,\n            \"example\": 95.5\n          },\n          \"versions\": {\n            \"type\": \"array\",\n            \"description\": \"Available version tags\",\n            \"items\": {\n              \"type\": \"string\"\n            },\n            \"example\": [\"v15.1.8\", \"v14.3.0\"]\n          }\n        }\n      },\n      \"SearchResponse\": {\n        \"type\": \"object\",\n        \"description\": \"Search results response\",\n        \"properties\": {\n          \"results\": {\n            \"type\": \"array\",\n            \"description\": \"Array of matching libraries ranked by relevance\",\n            \"items\": {\n              \"$ref\": \"#/components/schemas/Library\"\n            }\n          }\n        },\n        \"required\": [\"results\"]\n      },\n      \"CodeSnippet\": {\n        \"type\": \"object\",\n        \"description\": \"A code snippet from library documentation\",\n        \"properties\": {\n          \"codeTitle\": {\n            \"type\": \"string\",\n            \"description\": \"Title of the code snippet\"\n          },\n          \"codeDescription\": {\n            \"type\": \"string\",\n            \"description\": \"Description of what the code does\"\n          },\n          \"codeLanguage\": {\n            \"type\": \"string\",\n            \"description\": \"Primary programming language\"\n          },\n          \"codeTokens\": {\n            \"type\": \"integer\",\n            \"description\": \"Token count for the snippet\"\n          },\n          \"codeId\": {\n            \"type\": \"string\",\n            \"description\": \"URL to source location\"\n          },\n          \"pageTitle\": {\n            \"type\": \"string\",\n            \"description\": \"Title of the documentation page\"\n          },\n          \"codeList\": {\n            \"type\": \"array\",\n            \"description\": \"Code examples in different languages\",\n            \"items\": {\n              \"$ref\": \"#/components/schemas/CodeExample\"\n            }\n          }\n        },\n        \"required\": [\n          \"codeTitle\",\n          \"codeDescription\",\n          \"codeLanguage\",\n          \"codeTokens\",\n          \"codeId\",\n          \"pageTitle\",\n          \"codeList\"\n        ]\n      },\n      \"CodeExample\": {\n        \"type\": \"object\",\n        \"description\": \"A single code example\",\n        \"properties\": {\n          \"language\": {\n            \"type\": \"string\",\n            \"description\": \"Programming language\"\n          },\n          \"code\": {\n            \"type\": \"string\",\n            \"description\": \"The actual code content\"\n          }\n        },\n        \"required\": [\"language\", \"code\"]\n      },\n      \"InfoSnippet\": {\n        \"type\": \"object\",\n        \"description\": \"A documentation snippet\",\n        \"properties\": {\n          \"pageId\": {\n            \"type\": \"string\",\n            \"description\": \"URL to source page\"\n          },\n          \"breadcrumb\": {\n            \"type\": \"string\",\n            \"description\": \"Navigation breadcrumb path\"\n          },\n          \"content\": {\n            \"type\": \"string\",\n            \"description\": \"The documentation content\"\n          },\n          \"contentTokens\": {\n            \"type\": \"integer\",\n            \"description\": \"Token count for the content\"\n          }\n        },\n        \"required\": [\"content\", \"contentTokens\"]\n      },\n      \"ContextResponse\": {\n        \"type\": \"object\",\n        \"description\": \"Documentation context response\",\n        \"properties\": {\n          \"codeSnippets\": {\n            \"type\": \"array\",\n            \"description\": \"Relevant code snippets\",\n            \"items\": {\n              \"$ref\": \"#/components/schemas/CodeSnippet\"\n            }\n          },\n          \"infoSnippets\": {\n            \"type\": \"array\",\n            \"description\": \"Relevant documentation snippets\",\n            \"items\": {\n              \"$ref\": \"#/components/schemas/InfoSnippet\"\n            }\n          },\n          \"rules\": {\n            \"type\": \"object\",\n            \"description\": \"Optional library-specific rules and guidelines\",\n            \"properties\": {\n              \"global\": {\n                \"type\": \"array\",\n                \"description\": \"Global team rules\",\n                \"items\": {\n                  \"type\": \"string\"\n                }\n              },\n              \"libraryOwn\": {\n                \"type\": \"array\",\n                \"description\": \"Rules defined by the library owner\",\n                \"items\": {\n                  \"type\": \"string\"\n                }\n              },\n              \"libraryTeam\": {\n                \"type\": \"array\",\n                \"description\": \"Library-specific rules from the team\",\n                \"items\": {\n                  \"type\": \"string\"\n                }\n              }\n            }\n          }\n        },\n        \"required\": [\"codeSnippets\", \"infoSnippets\"]\n      },\n      \"Error\": {\n        \"type\": \"object\",\n        \"description\": \"Standard error response\",\n        \"properties\": {\n          \"error\": {\n            \"type\": \"string\",\n            \"description\": \"Error code identifier\"\n          },\n          \"message\": {\n            \"type\": \"string\",\n            \"description\": \"Human-readable error message\"\n          }\n        },\n        \"required\": [\"error\", \"message\"]\n      },\n      \"AddRepoRequest\": {\n        \"type\": \"object\",\n        \"description\": \"Request body for adding a Git repository\",\n        \"required\": [\"docsRepoUrl\"],\n        \"properties\": {\n          \"docsRepoUrl\": {\n            \"type\": \"string\",\n            \"format\": \"uri\",\n            \"description\": \"The repository URL\"\n          },\n          \"gitToken\": {\n            \"type\": \"string\",\n            \"description\": \"Personal access token for private repositories. If not provided, the token from your OAuth connection at https://context7.com/add-library is used.\"\n          },\n          \"private\": {\n            \"type\": \"boolean\",\n            \"description\": \"Whether the repository is private\"\n          },\n          \"skipBenchmark\": {\n            \"type\": \"boolean\",\n            \"description\": \"Skip benchmark quality scoring after parsing\"\n          },\n          \"skipContextGeneration\": {\n            \"type\": \"boolean\",\n            \"description\": \"Skip automatic default context generation\"\n          },\n          \"skipVersionFiltering\": {\n            \"type\": \"boolean\",\n            \"description\": \"Skip filtering out version-specific documentation pages\"\n          }\n        }\n      },\n      \"AddLibraryResponse\": {\n        \"type\": \"object\",\n        \"description\": \"Response after successfully submitting a library\",\n        \"properties\": {\n          \"libraryName\": {\n            \"type\": \"string\",\n            \"description\": \"The library identifier assigned (e.g., /owner/repo)\"\n          },\n          \"message\": {\n            \"type\": \"string\",\n            \"description\": \"Human-readable success message\"\n          }\n        },\n        \"required\": [\"libraryName\", \"message\"]\n      },\n      \"RedirectErrorResponse\": {\n        \"allOf\": [\n          {\n            \"$ref\": \"#/components/schemas/Error\"\n          },\n          {\n            \"type\": \"object\",\n            \"properties\": {\n              \"redirectUrl\": {\n                \"type\": \"string\",\n                \"description\": \"New location of the library\"\n              }\n            }\n          }\n        ]\n      }\n    },\n    \"responses\": {\n      \"BadRequestError\": {\n        \"description\": \"Bad Request - Invalid input parameters\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"examples\": {\n              \"validationError\": {\n                \"summary\": \"Validation error\",\n                \"value\": {\n                  \"error\": \"validation_error\",\n                  \"message\": \"Library name is required\"\n                }\n              },\n              \"invalidLibraryId\": {\n                \"summary\": \"Invalid library ID format\",\n                \"value\": {\n                  \"error\": \"invalid_library_id\",\n                  \"message\": \"Invalid library ID format. Expected: /owner/repo or /owner/repo/version\"\n                }\n              }\n            }\n          }\n        }\n      },\n      \"ForbiddenError\": {\n        \"description\": \"Forbidden - Insufficient permissions or plan restrictions\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"examples\": {\n              \"accessDenied\": {\n                \"summary\": \"Library not in allowed list\",\n                \"value\": {\n                  \"error\": \"access_denied\",\n                  \"message\": \"Access denied: Library /owner/repo is not included in your allowed libraries\"\n                }\n              },\n              \"insufficientRole\": {\n                \"summary\": \"Insufficient team role\",\n                \"value\": {\n                  \"error\": \"forbidden\",\n                  \"message\": \"Only team owners and admins can add private repositories\"\n                }\n              },\n              \"planRequired\": {\n                \"summary\": \"Plan upgrade required\",\n                \"value\": {\n                  \"error\": \"forbidden\",\n                  \"message\": \"Private repositories require a pro plan or team. Upgrade at https://context7.com/plans\"\n                }\n              }\n            }\n          }\n        }\n      },\n      \"NotFoundError\": {\n        \"description\": \"Not Found - Resource doesn't exist\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"examples\": {\n              \"libraryNotFound\": {\n                \"summary\": \"Library not found\",\n                \"value\": {\n                  \"error\": \"library_not_found\",\n                  \"message\": \"Library \\\"/owner/repo\\\" not found. Please check the library ID or your access permissions.\"\n                }\n              },\n              \"tagNotFound\": {\n                \"summary\": \"Version tag not found\",\n                \"value\": {\n                  \"error\": \"tag_not_found\",\n                  \"message\": \"Tag \\\"v1.0.0\\\" not found for library \\\"/owner/repo\\\". Available tags: v2.0.0, v1.5.0\"\n                }\n              },\n              \"noSnippetsFound\": {\n                \"summary\": \"No snippets found\",\n                \"value\": {\n                  \"error\": \"no_snippets_found\",\n                  \"message\": \"Could not fetch documentation snippets from the library.\"\n                }\n              },\n              \"teamNotFound\": {\n                \"summary\": \"Team not found\",\n                \"value\": {\n                  \"error\": \"team_not_found\",\n                  \"message\": \"Team not found or access denied\"\n                }\n              },\n              \"userNotFound\": {\n                \"summary\": \"User not found\",\n                \"value\": {\n                  \"error\": \"user_not_found\",\n                  \"message\": \"User not found\"\n                }\n              }\n            }\n          }\n        }\n      },\n      \"InternalServerError\": {\n        \"description\": \"Internal Server Error\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"example\": {\n              \"error\": \"internal_error\",\n              \"message\": \"An error occurred while processing your request\"\n            }\n          }\n        }\n      },\n      \"ServiceUnavailableError\": {\n        \"description\": \"Service Unavailable - Search failed or no results\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"examples\": {\n              \"searchFailed\": {\n                \"summary\": \"Search service failure\",\n                \"value\": {\n                  \"error\": \"search_failed\",\n                  \"message\": \"Search failed: Service temporarily unavailable\"\n                }\n              },\n              \"noLibrariesFound\": {\n                \"summary\": \"No libraries matched\",\n                \"value\": {\n                  \"error\": \"no_libraries_found\",\n                  \"message\": \"No libraries found matching your search query.\"\n                }\n              }\n            }\n          }\n        }\n      },\n      \"AcceptedError\": {\n        \"description\": \"Accepted - Library not yet finalized\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"example\": {\n              \"error\": \"library_not_finalized\",\n              \"message\": \"Library /owner/repo not finalized yet.\"\n            }\n          }\n        }\n      },\n      \"RedirectError\": {\n        \"description\": \"Moved Permanently - Library has been redirected\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/RedirectErrorResponse\"\n            },\n            \"example\": {\n              \"error\": \"library_redirected\",\n              \"message\": \"Library /owner/repo has been redirected to this library: /new-owner/new-repo.\",\n              \"redirectUrl\": \"/new-owner/new-repo\"\n            }\n          }\n        }\n      },\n      \"UnprocessableEntityError\": {\n        \"description\": \"Unprocessable Entity - Library is too large or has no code\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"examples\": {\n              \"tooLarge\": {\n                \"summary\": \"Library too large\",\n                \"value\": {\n                  \"error\": \"library_too_large\",\n                  \"message\": \"Library /owner/repo is too large to process.\"\n                }\n              },\n              \"noCode\": {\n                \"summary\": \"No code found\",\n                \"value\": {\n                  \"error\": \"no_code_found\",\n                  \"message\": \"Library /owner/repo has no or too few snippets found in documentation files.\"\n                }\n              }\n            }\n          }\n        }\n      },\n      \"UnauthorizedError\": {\n        \"description\": \"Unauthorized - Invalid or missing API key\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"example\": {\n              \"error\": \"invalid_api_key\",\n              \"message\": \"Invalid API key. Please check your API key. API keys should start with 'ctx7sk' prefix.\"\n            }\n          }\n        }\n      },\n      \"AddLibrarySuccess\": {\n        \"description\": \"Library submitted successfully for processing\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/AddLibraryResponse\"\n            },\n            \"example\": {\n              \"libraryName\": \"/owner/repo\",\n              \"message\": \"Repository submitted successfully\"\n            }\n          }\n        }\n      },\n      \"DuplicateError\": {\n        \"description\": \"Conflict - Resource already exists\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"example\": {\n              \"error\": \"duplicate_repo\",\n              \"message\": \"This private repository is already in your team\"\n            }\n          }\n        }\n      },\n      \"RateLimitError\": {\n        \"description\": \"Too Many Requests - Rate limit exceeded\",\n        \"headers\": {\n          \"Retry-After\": {\n            \"description\": \"Seconds until rate limit resets\",\n            \"schema\": {\n              \"type\": \"integer\"\n            }\n          },\n          \"RateLimit-Limit\": {\n            \"description\": \"Request limit\",\n            \"schema\": {\n              \"type\": \"integer\"\n            }\n          },\n          \"RateLimit-Remaining\": {\n            \"description\": \"Remaining requests\",\n            \"schema\": {\n              \"type\": \"integer\"\n            }\n          },\n          \"RateLimit-Reset\": {\n            \"description\": \"Unix timestamp when limit resets\",\n            \"schema\": {\n              \"type\": \"integer\"\n            }\n          }\n        },\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"example\": {\n              \"error\": \"rate_limit_exceeded\",\n              \"message\": \"Rate limit exceeded. Please try again later.\"\n            }\n          }\n        }\n      },\n      \"GatewayTimeoutError\": {\n        \"description\": \"Gateway Timeout - Processing timed out waiting for logs\",\n        \"content\": {\n          \"application/json\": {\n            \"schema\": {\n              \"$ref\": \"#/components/schemas/Error\"\n            },\n            \"example\": {\n              \"error\": \"timeout\",\n              \"message\": \"Request timed out. Please try again.\"\n            }\n          }\n        }\n      }\n    }\n  },\n  \"tags\": [\n    {\n      \"name\": \"Search\",\n      \"description\": \"Search for libraries in the Context7 database\"\n    },\n    {\n      \"name\": \"Context\",\n      \"description\": \"Retrieve documentation context for queries\"\n    },\n    {\n      \"name\": \"Add Library\",\n      \"description\": \"Submit new libraries for documentation processing\"\n    },\n    {\n      \"name\": \"Refresh\",\n      \"description\": \"Refresh existing libraries to fetch latest documentation\"\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/overview.mdx",
    "content": "---\ntitle: Intro\nsidebarTitle: Intro\n---\n\nContext7 brings up-to-date, version-specific documentation and code examples directly into your AI coding assistant. That means no more outdated code or hallucinated APIs.\n\n## ❌ Without Context7\n\nLLMs rely on outdated or generic information about the libraries you use:\n\n- ❌ Code examples based on old training data\n- ❌ Hallucinated APIs that don't even exist\n- ❌ Generic answers for old package versions\n\n## ✅ With Context7\n\nContext7 MCP pulls up-to-date, version-specific documentation and code examples straight from the source — and places them directly into your prompt.\n\nAdd `use context7` to your prompt in Cursor:\n\n```txt\nCreate a Next.js middleware that checks for a valid JWT in cookies and redirects unauthenticated users to `/login`. use context7\n```\n\n```txt\nConfigure a Cloudflare Worker script to cache JSON API responses for five minutes. use context7\n```\n\nContext7 grounds your LLM with up-to-date documentation, ensuring that it always writes high quality code.\n\n- 1️⃣ Write your prompt naturally\n- 2️⃣ Add `use context7` to your prompt\n- 3️⃣ Get working code with current APIs\n\nNo tab-switching, no hallucinated APIs that don't exist, no outdated code generation.\n\n## Next Steps\n\n<CardGroup cols={1}>\n  <Card title=\"Install Context7\" icon=\"download\" href=\"https://github.com/upstash/context7#installation\">\n    Get set up in 2 minutes with your preferred AI coding assistant\n  </Card>\n  <Card title=\"Troubleshooting\" icon=\"wrench\" href=\"/resources/troubleshooting\">\n    Common issues and solutions\n  </Card>\n  <Card title=\"Get an API Key\" icon=\"key\" href=\"https://context7.com/dashboard\">\n    Unlock higher rate limits and use your private repositories\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/plans-pricing.mdx",
    "content": "---\ntitle: Plans & Pricing\nurl: https://context7.com/plans\n---\n\n"
  },
  {
    "path": "docs/resources/all-clients.mdx",
    "content": "---\ntitle: MCP Clients\ndescription: Installation examples for MCP clients\n---\n\nContext7 supports all MCP clients. Below are configuration examples for popular clients. If your client isn't listed, check its documentation for MCP server installation.\n\n<Tip>\nLooking for the easiest way to get started? Use `npx ctx7 setup` to configure Context7 automatically. See the [CLI docs](/clients/cli) for more details.\n</Tip>\n\n<Note>\nFor detailed guides including rules, skills, agents, and best practices, see the dedicated client pages:\n- [Cursor](/clients/cursor) - Rules setup, Composer integration, tips\n- [Claude Code](/clients/claude-code) - Skills, agents, commands, plugin installation\n</Note>\n\n## OAuth Authentication\n\nContext7 MCP server supports OAuth 2.0 authentication for MCP clients that implement the [MCP OAuth specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization).\n\nTo use OAuth, change the endpoint from `/mcp` to `/mcp/oauth` in your client configuration:\n\n```diff\n- \"url\": \"https://mcp.context7.com/mcp\"\n+ \"url\": \"https://mcp.context7.com/mcp/oauth\"\n```\n\nOAuth is only available for remote HTTP connections. For local MCP connections using stdio transport, use API key authentication instead.\n\n<AccordionGroup>\n\n<Accordion title=\"Claude Code\">\n\nRun this command. See [Claude Code MCP docs](https://docs.anthropic.com/en/docs/claude-code/mcp) for more info.\n\n#### Local Server Connection\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY\n```\n\n#### Remote Server Connection\n\n```sh\nclaude mcp add --scope user --header \"CONTEXT7_API_KEY: YOUR_API_KEY\" --transport http context7 https://mcp.context7.com/mcp\n```\n\n</Accordion>\n\n<Accordion title=\"Cursor\">\n\nGo to: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\n\nPasting the following configuration into your Cursor `~/.cursor/mcp.json` file is the recommended approach. You may also install in a specific project by creating `.cursor/mcp.json` in your project folder. See [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol) for more info.\n\nSince Cursor 1.0, you can click the install button below for instant one-click installation.\n\n#### Remote Server Connection\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Opencode\">\n\nAdd this to your Opencode configuration file. See [Opencode MCP docs](https://opencode.ai/docs/mcp-servers) for more info.\n\n#### Remote Server Connection\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"headers\": {\n      \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n    },\n    \"enabled\": true\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"OpenAI Codex\">\n\nSee [OpenAI Codex MCP docs](https://developers.openai.com/codex/mcp) for more info.\n\n#### Using CLI\n\n```sh\ncodex mcp add context7 -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY\n```\n\n#### Local Server Connection\n\nAdd this to your Codex configuration file (`~/.codex/config.toml` or `.codex/config.toml`).\n\n```toml\n[mcp_servers.context7]\ncommand = \"npx\"\nargs = [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\nstartup_timeout_sec = 20\n```\n\n#### Remote Server Connection\n\n```toml\n[mcp_servers.context7]\nurl = \"https://mcp.context7.com/mcp\"\nhttp_headers = { \"CONTEXT7_API_KEY\" = \"YOUR_API_KEY\" }\n```\n\n<Note>\nIf you see startup timeout errors, try increasing `startup_timeout_sec` to `40`.\n</Note>\n\n</Accordion>\n\n<Accordion title=\"Google Antigravity\">\n\nAdd this to your Antigravity MCP config file. See [Antigravity MCP docs](https://antigravity.google/docs/mcp) for more info.\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"VS Code\">\n\n[<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\" />](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Install in VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Context7%20MCP&color=24bfa5\" />](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n\nAdd this to your VS Code MCP config file (`.vscode/mcp.json`). See [VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for more info.\n\n#### Remote Server Connection\n\n```json\n{\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Kiro\">\n\nSee [Kiro Model Context Protocol Documentation](https://kiro.dev/docs/mcp/configuration/) for details.\n\n1. Navigate `Kiro` > `MCP Servers`\n2. Add a new MCP server by clicking the `+ Add` button.\n3. Paste the configuration:\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n4. Click `Save` to apply.\n\n</Accordion>\n\n<Accordion title=\"Kilo Code\">\n\nYou can configure the Context7 MCP server in **Kilo Code** using either the UI or by editing your project's MCP configuration file.\n\nKilo Code supports two configuration levels:\n\n- **Global MCP Configuration** — stored in `mcp_settings.json`\n- **Project-level MCP Configuration** — stored in `.kilocode/mcp.json` (recommended)\n\n### Configure via Kilo Code UI\n\n1. Open **Kilo Code**.\n2. Click the **Settings** icon in the top-right corner.\n3. Navigate to **Settings → MCP Servers**.\n4. Click **Add Server**.\n5. Choose **HTTP Server** (Streamable HTTP Transport).\n6. Enter the details:\n   - **URL**: `https://mcp.context7.com/mcp`\n   - **Headers → Add Header**\n     - **Key:** `Authorization`\n     - **Value:** `Bearer YOUR_API_KEY`\n7. Click **Save**.\n\n### Manual Configuration\n\nCreate `.kilocode/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      },\n      \"alwaysAllow\": [],\n      \"disabled\": false\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Roo Code\">\n\nAdd this to your Roo Code MCP configuration file. See [Roo Code MCP docs](https://docs.roocode.com/features/mcp/using-mcp-in-roo) for more info.\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Windsurf\">\n\nAdd this to your Windsurf MCP config file. See [Windsurf MCP docs](https://docs.windsurf.com/windsurf/cascade/mcp) for more info.\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Claude Desktop\">\n\n#### Remote Server Connection\n\nOpen Claude Desktop and navigate to Settings > Connectors > Add Custom Connector. Enter the name as `Context7` and the remote MCP server URL as `https://mcp.context7.com/mcp`.\n\n#### Local Server Connection\n\nOpen Claude Desktop developer settings and edit your `claude_desktop_config.json` file. See [Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user) for more info.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"ChatGPT (Web)\">\n\nChatGPT supports MCP servers through remote connectors via [Developer Mode](https://platform.openai.com/docs/guides/developer-mode) (beta). Available for Pro, Plus, Team, Enterprise, and Edu plans.\n\n#### 1. Enable Developer Mode\n\nGo to: `Settings` → `Apps` → `Advanced settings` → Enable `Developer Mode`\n\n#### 2. Create an App\n\nGo to: `Settings` → `Apps` → `Create App`\n\nFill in the following:\n\n| Field              | Value                                                                                       |\n| ------------------ | ------------------------------------------------------------------------------------------- |\n| **Name**           | `Context7`                                                                                  |\n| **Description**    | `Fetch up-to-date documentation and code examples for any library directly from the source` |\n| **MCP Server URL** | `https://mcp.context7.com/mcp/oauth`                                                       |\n\n> Accept the security notice and complete the one-time OAuth authorization.\n\n#### 3. Use in a Conversation\n\nStart a new chat → Click the plus icon → Hover over `More` → Select the `Context7` app.\n\nAlternatively, you can say `use context7` in your prompt and ChatGPT will automatically use the `Context7` app.\n\nSee [OpenAI MCP docs](https://platform.openai.com/docs/mcp) for more info.\n\n</Accordion>\n\n<Accordion title=\"ChatGPT (Desktop)\">\n\nThe ChatGPT desktop app shares apps configured on the web. Set up the app on [chatgpt.com](https://chatgpt.com) first.\n\n#### 1. Enable Developer Mode (on the Web)\n\nGo to: `Settings` → `Apps` → `Advanced settings` → Enable `Developer Mode`\n\n#### 2. Create an App (on the Web)\n\nGo to: `Settings` → `Apps` → `Create App`\n\nFill in the following:\n\n| Field              | Value                                                                                       |\n| ------------------ | ------------------------------------------------------------------------------------------- |\n| **Name**           | `Context7`                                                                                  |\n| **Description**    | `Fetch up-to-date documentation and code examples for any library directly from the source` |\n| **MCP Server URL** | `https://mcp.context7.com/mcp/oauth`                                                       |\n\n> Accept the security notice and complete the one-time OAuth authorization.\n\n#### 3. Use in the Desktop App\n\nOpen the ChatGPT desktop app → Start a new chat → ChatGPT will automatically use the `Context7` app when you ask it to.\n\nApps configured on the web are automatically available in the desktop app.\n\nSee [OpenAI MCP docs](https://platform.openai.com/docs/mcp) for more info.\n\n</Accordion>\n\n<Accordion title=\"Trae\">\n\nUse the Add manually feature and fill in the JSON configuration. See [Trae documentation](https://docs.trae.ai/ide/model-context-protocol?_lang=en) for more details.\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Cline\">\n\nYou can easily install Context7 through the [Cline MCP Server Marketplace](https://cline.bot/mcp-marketplace) by following these instructions:\n\n1. Open **Cline**.\n2. Click the hamburger menu icon to enter the **MCP Servers** section.\n3. Use the search bar within the **Marketplace** tab to find _Context7_.\n4. Click the **Install** button.\n\nOr you can directly edit MCP servers configuration:\n\n1. Open **Cline**.\n2. Click the hamburger menu icon to enter the **MCP Servers** section.\n3. Choose **Remote Servers** tab.\n4. Click the **Edit Configuration** button.\n5. Add context7 to `mcpServers`:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"type\": \"streamableHttp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Augment Code\">\n\nTo configure Context7 MCP in Augment Code, you can use either the graphical interface or manual configuration.\n\n### Using the Augment Code UI\n\n1. Click the hamburger menu.\n2. Select **Settings**.\n3. Navigate to the **Tools** section.\n4. Click the **+ Add MCP** button.\n5. Enter the following command:\n\n   ```\n   npx -y @upstash/context7-mcp@latest\n   ```\n\n6. Name the MCP: **Context7**.\n7. Click the **Add** button.\n\n### Manual Configuration\n\n1. Press Cmd/Ctrl Shift P or go to the hamburger menu in the Augment panel\n2. Select Edit Settings\n3. Under Advanced, click Edit in settings.json\n4. Add the server configuration to the `mcpServers` array in the `augment.advanced` object\n\n```json\n\"augment.advanced\": {\n  \"mcpServers\": [\n    {\n      \"name\": \"context7\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  ]\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Gemini CLI\">\n\nSee [Gemini CLI Configuration](https://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html) for details.\n\n1. Open the Gemini CLI settings file at `~/.gemini/settings.json`\n2. Add the following to the `mcpServers` object:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"httpUrl\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\",\n        \"Accept\": \"application/json, text/event-stream\"\n      }\n    }\n  }\n}\n```\n\nOr, for a local server:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Using Bun or Deno\">\n\nUse these alternatives to run the local Context7 MCP server with other runtimes.\n\n#### Bun\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n#### Deno\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\n        \"run\",\n        \"--allow-env=NO_DEPRECATION,TRACE_DEPRECATION\",\n        \"--allow-net\",\n        \"npm:@upstash/context7-mcp\"\n      ]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Copilot Coding Agent\">\n\nAdd the following configuration to Repository->Settings->Copilot->Coding agent->MCP configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\n\nSee the [official GitHub documentation](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp) for more info.\n\n</Accordion>\n\n<Accordion title=\"Copilot CLI\">\n\nOpen `~/.copilot/mcp-config.json` and add:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\n\nOr, for a local server:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Amazon Q Developer CLI\">\n\nAdd this to your Amazon Q Developer CLI configuration file. See [Amazon Q Developer CLI docs](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html) for more details.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Warp\">\n\nSee [Warp Model Context Protocol Documentation](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server) for details.\n\n1. Navigate `Settings` > `AI` > `Manage MCP servers`.\n2. Add a new MCP server by clicking the `+ Add` button.\n3. Paste the configuration:\n\n```json\n{\n  \"Context7\": {\n    \"command\": \"npx\",\n    \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n    \"env\": {},\n    \"working_directory\": null,\n    \"start_on_launch\": true\n  }\n}\n```\n\n4. Click `Save`.\n\n</Accordion>\n\n<Accordion title=\"Amp\">\n\nRun this command in your terminal. See [Amp MCP docs](https://ampcode.com/manual#mcp) for more info.\n\n#### Without API Key (Basic Usage)\n\n```sh\namp mcp add context7 https://mcp.context7.com/mcp\n```\n\n#### With API Key (Higher Rate Limits & Private Repos)\n\n```sh\namp mcp add context7 --header \"CONTEXT7_API_KEY=YOUR_API_KEY\" https://mcp.context7.com/mcp\n```\n\n</Accordion>\n\n<Accordion title=\"Zed\">\n\nIt can be installed via [Zed Extensions](https://zed.dev/extensions?query=Context7) or you can add this to your Zed `settings.json`. See [Zed Context Server docs](https://zed.dev/docs/assistant/context-servers) for more info.\n\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Smithery\">\n\nTo install Context7 MCP Server for any client automatically via [Smithery](https://smithery.ai/server/@upstash/context7-mcp):\n\n```bash\nnpx -y @smithery/cli@latest install @upstash/context7-mcp --client <CLIENT_NAME> --key <YOUR_SMITHERY_KEY>\n```\n\nYou can find your Smithery key in the [Smithery.ai webpage](https://smithery.ai/server/@upstash/context7-mcp).\n\n</Accordion>\n\n<Accordion title=\"JetBrains AI Assistant\">\n\nSee [JetBrains AI Assistant Documentation](https://www.jetbrains.com/help/ai-assistant/configure-an-mcp-server.html) for more details.\n\n1. In JetBrains IDEs, go to `Settings` -> `Tools` -> `AI Assistant` -> `Model Context Protocol (MCP)`\n2. Click `+ Add`.\n3. Select the **HTTP** or **STDIO** tab and paste the JSON configuration.\n4. Click `Apply` to save changes.\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Qwen Code\">\n\nSee [Qwen Code MCP Configuration](https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/) for details.\n\n### Using CLI Command\n\nBy default, configurations are saved to the project scope (`.qwen/settings.json`). Use the `--scope user` flag to save to the user scope (`~/.qwen/settings.json`) instead.\n\n#### Remote Server Connection\n```sh\nqwen mcp add --transport http context7 https://mcp.context7.com/mcp \\\n  --header \"CONTEXT7_API_KEY: YOUR_API_KEY\" \\\n  --header \"Accept: application/json, text/event-stream\"\n```\n\n#### Local Server Connection\n```sh\nqwen mcp add context7 npx -y @upstash/context7-mcp --api-key YOUR_API_KEY\n```\n\n### Manual Configuration\n\n1. Open the Qwen Code settings file at `~/.qwen/settings.json` (user scope) or `.qwen/settings.json` (project scope)\n2. Add the following to the `mcpServers` object:\n\n#### Remote Server Connection\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"httpUrl\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\",\n        \"Accept\": \"application/json, text/event-stream\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Using Docker\">\n\n1. Create a `Dockerfile`:\n\n```Dockerfile\nFROM node:18-alpine\nWORKDIR /app\nRUN npm install -g @upstash/context7-mcp\nCMD [\"context7-mcp\"]\n```\n\n2. Build the image:\n\n```bash\ndocker build -t context7-mcp .\n```\n\n3. Configure your MCP client:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n      \"transportType\": \"stdio\"\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Windows\">\n\nThe configuration on Windows is slightly different. Use `cmd` to run npx:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"LM Studio\">\n\nSee [LM Studio MCP Support](https://lmstudio.ai/blog/lmstudio-v0.3.17) for more information.\n\n#### One-click install:\n\n[![Add MCP Server context7 to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJdfQ%3D%3D)\n\n#### Manual set-up:\n\n1. Navigate to `Program` (right side) > `Install` > `Edit mcp.json`.\n2. Paste the configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n3. Click `Save`.\n\n</Accordion>\n\n<Accordion title=\"Visual Studio 2022\">\n\nSee [Visual Studio MCP Servers documentation](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022) for details.\n\n```json\n{\n  \"inputs\": [],\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\nOr, for a local server:\n\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"stdio\",\n        \"command\": \"npx\",\n        \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n      }\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Crush\">\n\nAdd this to your Crush configuration file. See [Crush MCP docs](https://github.com/charmbracelet/crush#mcps) for more info.\n\n#### Remote Server Connection\n\n```json\n{\n  \"$schema\": \"https://charm.land/crush.json\",\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"$schema\": \"https://charm.land/crush.json\",\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"BoltAI\">\n\nOpen the \"Settings\" page, navigate to \"Plugins,\" and enter:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\nSee [BoltAI's Documentation](https://docs.boltai.com/docs/plugins/mcp-servers) for more info.\n\n</Accordion>\n\n<Accordion title=\"Rovo Dev CLI\">\n\nEdit your Rovo Dev CLI MCP config:\n\n```bash\nacli rovodev mcp\n```\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Zencoder\">\n\n1. Go to the Zencoder menu (...)\n2. Select Agent tools\n3. Click on Add custom MCP\n4. Add the name and configuration:\n\n```json\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n}\n```\n\n5. Click Install.\n\n</Accordion>\n\n<Accordion title=\"Qodo Gen\">\n\nSee [Qodo Gen docs](https://docs.qodo.ai/qodo-documentation/qodo-gen/qodo-gen-chat/agentic-mode/agentic-tools-mcps) for more details.\n\n1. Open Qodo Gen chat panel in VSCode or IntelliJ.\n2. Click Connect more tools.\n3. Click + Add new MCP.\n4. Add the configuration:\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n</Accordion>\n\n<Accordion title=\"Perplexity Desktop\">\n\nSee [Local and Remote MCPs for Perplexity](https://www.perplexity.ai/help-center/en/articles/11502712-local-and-remote-mcps-for-perplexity) for more information.\n\n1. Navigate `Perplexity` > `Settings`\n2. Select `Connectors`.\n3. Click `Add Connector`.\n4. Select `Advanced`.\n5. Enter Server Name: `Context7`\n6. Paste:\n\n```json\n{\n  \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n  \"command\": \"npx\",\n  \"env\": {}\n}\n```\n\n7. Click `Save`.\n\n</Accordion>\n\n<Accordion title=\"Factory\">\n\nFactory's droid supports MCP servers through its CLI. See [Factory MCP docs](https://docs.factory.ai/cli/configuration/mcp) for more info.\n\n#### Remote Server Connection\n\n```sh\ndroid mcp add context7 https://mcp.context7.com/mcp --type http --header \"CONTEXT7_API_KEY: YOUR_API_KEY\"\n```\n\n#### Local Server Connection\n\n```sh\ndroid mcp add context7 \"npx -y @upstash/context7-mcp\" --env CONTEXT7_API_KEY=YOUR_API_KEY\n```\n\n</Accordion>\n\n<Accordion title=\"Emdash\">\n\n[Emdash](https://github.com/generalaction/emdash) is an orchestration layer for running multiple coding agents in parallel.\n\n**What Emdash provides:**\n\n- Global toggle: Settings → MCP → \"Enable Context7 MCP\"\n- Per-workspace enable: The Context7 button in the ProviderBar\n\n**What you still need to do:**\nConfigure your coding agent (Codex, Claude Code, Cursor, etc.) to connect to Context7 MCP. Emdash does not modify your agent's config.\n\nSee the [Emdash repository](https://github.com/generalaction/emdash) for more information.\n\n</Accordion>\n\n<Accordion title=\"Desktop Extension\">\n\nInstall the [context7.mcpb](https://github.com/upstash/context7/tree/master/mcpb/context7.mcpb) file and add it to your client. See [MCP bundles docs](https://github.com/anthropics/mcpb#mcp-bundles-mcpb) for more info.\n\n</Accordion>\n\n</AccordionGroup>\n"
  },
  {
    "path": "docs/resources/developer.mdx",
    "content": "---\ntitle: Developer Guide\ndescription: Set up and run Context7 MCP locally for development\n---\n\nThis guide covers how to set up the Context7 MCP server locally for development and testing.\n\n## Getting Started\n\nClone the project and install dependencies:\n\n```bash\ngit clone https://github.com/upstash/context7.git\ncd context7\npnpm i\n```\n\nBuild:\n\n```bash\npnpm run build\n```\n\nRun the server:\n\n```bash\nnode packages/mcp/dist/index.js\n```\n\n## CLI Arguments\n\n`context7-mcp` accepts the following CLI flags:\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| `--transport <stdio\\|http>` | Transport to use. Use `http` for remote HTTP server or `stdio` for local integration. | `stdio` |\n| `--port <number>` | Port to listen on when using `http` transport. | `3000` |\n| `--api-key <key>` | API key for authentication (or set `CONTEXT7_API_KEY` env var). | - |\n\n<Note>\n  Get your API key by creating an account at [context7.com/dashboard](https://context7.com/dashboard).\n</Note>\n\n### Examples\n\nHTTP transport on port 8080:\n\n```bash\nnode packages/mcp/dist/index.js --transport http --port 8080\n```\n\nStdio transport with API key:\n\n```bash\nnode packages/mcp/dist/index.js --transport stdio --api-key YOUR_API_KEY\n```\n\n## Environment Variables\n\nYou can use the `CONTEXT7_API_KEY` environment variable instead of passing the `--api-key` flag. This is useful for:\n\n- Storing API keys securely in `.env` files\n- Integration with MCP server setups that use dotenv\n- Tools that prefer environment variable configuration\n\n<Warning>\n  The `--api-key` CLI flag takes precedence over the environment variable when both are provided.\n</Warning>\n\n### Using .env File\n\n```bash\n# .env\nCONTEXT7_API_KEY=your_api_key_here\n```\n\n### MCP Configuration with Environment Variable\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n      \"env\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n## Local Development Configuration\n\nWhen developing locally, use this configuration to run from source:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7/src/index.ts\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n## Testing with MCP Inspector\n\nTest your setup using the MCP Inspector:\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n\nThis opens an interactive inspector to verify Context7 tools are working correctly.\n"
  },
  {
    "path": "docs/resources/security.mdx",
    "content": "---\ntitle: Security\n---\n\nContext7 takes security and privacy seriously. This page outlines our security practices, data handling, and compliance measures.\n\n## Highlights\n\n- Your original prompts stay with your AI assistant; Context7 only receives search queries formulated by the MCP client, which is instructed to strip sensitive data before sending\n- Documentation is indexed inside SOC 2 compliant infrastructure operated by Upstash\n- API keys are encrypted, rate limited, and easy to rotate from your dashboard\n- Enterprise customers can enable SSO (SAML, OAuth, OIDC) and receive dedicated audit trails\n- The [Context7 Addendum](https://upstash.com/trust/context7addendum.pdf), [Upstash Terms and Privacy Policy](https://upstash.com/docs/common/help/legal) applies to all users; see [trust.upstash.com](https://trust.upstash.com/) for full infrastructure compliance details, certifications\n\n## Privacy-First Architecture\n\n### Query Privacy\n\n**Your original prompts and code stay with your AI assistant.**\n\nWhen you use Context7 through an MCP client, the AI assistant (not the user directly) formulates search queries to retrieve relevant documentation. Here is what happens:\n\n1. Your prompt is processed locally by your AI assistant (e.g., Cursor, Claude Code)\n2. The AI assistant formulates a search query and library name based on your request\n3. Only these formulated queries are sent to the Context7 API — your full prompt, source code, and conversation history are never transmitted\n4. The MCP tool descriptions explicitly instruct the AI assistant to strip sensitive information (API keys, passwords, credentials, personal data, and proprietary code) from queries before sending\n\n**What is sent to the Context7 API:**\n\n- `query` — a search query formulated by the MCP client (not your original prompt)\n- `libraryName` or `libraryId` — the library to look up\n- API key (if provided, for authentication)\n- MCP client name and version (e.g., IDE info, for analytics)\n- Transport type (`stdio` or `http`)\n- Client IP address, encrypted with AES-256-CBC (HTTP transport only, for rate limiting)\n\n<Note>\n  The MCP client formulates search queries on your behalf and is instructed not to include\n  sensitive or confidential information. Your full prompts, code, and conversation context\n  remain with your AI assistant and are never sent to Context7.\n</Note>\n\n### Use of MCP Queries\n\nThe search queries formulated by the MCP client (not your original prompts) are used server-side in two ways:\n\n**Documentation Reranking**\n\nMCP-formulated queries are passed to LLMs to rerank and select the most relevant documentation for your request. Context7 uses well-known, trusted LLM providers for this purpose — including **OpenAI**, **Google Gemini**, and **Anthropic**.\n\n**Benchmarking and Quality Improvement**\n\nMCP-formulated queries are anonymously stored and used to benchmark retrieval accuracy and improve the documentation matching pipeline over time.\n\n**Enterprise Controls**\n\n- On-premise Enterprise plans can use their own LLM provider for code extraction and private library ranking\n- On-premise Enterprise plans can disable public documentation usage, limiting context retrieval to privately indexed documentation only\n- Enterprise plans can disable query storage for benchmarking — however, this may affect the quality of context retrieval over time\n\nContact our sales team at [context7.com](https://context7.com/contact) for Enterprise and on-premise plan details.\n\n### Customizing What Is Shared\n\nThe Context7 MCP server is [open source](https://github.com/upstash/context7). If you want full control over what is sent as the `query` parameter, you can:\n\n1. Fork the [Context7 MCP repository](https://github.com/upstash/context7)\n2. Edit the tool input descriptions in [`packages/mcp/src/index.ts`](https://github.com/upstash/context7/blob/master/packages/mcp/src/index.ts) — these descriptions instruct the AI assistant on how to formulate the query\n3. Build and run your custom MCP server locally\n\n<Warning>\n  The `query` parameter is used server-side for LLM-based reranking of documentation results. Modifying, redacting, or omitting the query can significantly reduce the relevance and quality of returned documentation.\n</Warning>\n\n### Data Storage\n\n**Context7 does not store your source files.**\n\n- We only index and store **documentation** and **code examples** from repositories\n- Your code, and source files are not stored or shared\n- All indexed content is stored in a secure vector database optimized for retrieval\n\n**What we store:**\n\n- Library documentation\n- Code examples from documentation\n- Metadata about indexed libraries\n- Queries formulated by the MCP client\n\n**What we don't store:**\n\n- Your source code\n- Your original prompts or conversations\n- Your conversations with AI assistants\n\n## Infrastructure Security\n\n### SOC 2 Compliance\n\nContext7 runs on **SOC 2 compliant infrastructure** provided by Upstash.\n\n- Type II SOC 2 certified infrastructure\n- Regular security audits and assessments\n- Continuous monitoring and compliance checks\n- Industry-standard security controls\n\n### Managed by Upstash\n\nContext7's infrastructure is managed by the experienced Upstash team:\n\n- 24/7 infrastructure monitoring\n- Automated security patching\n- DDoS protection and mitigation\n- Redundant backups and disaster recovery\n- Enterprise-grade reliability and uptime\n\n### Upstash Security Practices\n\nAll security practices and certificates of Upstash apply to Context7 products:\n\n- **Data Encryption**: Encryption at rest and in transit (TLS 1.2+)\n- **Network Security**: VPC isolation, firewall rules, and network segmentation\n- **Access Control**: Role-based access control (RBAC) and least privilege principles\n- **Audit Logging**: Comprehensive logging of all system activities\n- **Incident Response**: Documented incident response procedures\n- **Vulnerability Management**: Regular security scanning and penetration testing\n\nLearn more about Upstash security: [trust.upstash.com](https://trust.upstash.com/)\n\n## Authentication and Access Control\n\n### API Key Security\n\n- API keys use cryptographic random generation\n- Keys are hashed and encrypted in our database\n- Keys can be rotated at any time from your dashboard\n- Rate limiting prevents abuse and unauthorized access\n\n### Enterprise SSO\n\n**Single Sign-On (SSO) is available for Enterprise plans.**\n\nSupported SSO providers:\n\n- SAML 2.0\n- OAuth 2.0\n- OpenID Connect (OIDC)\n\nEnterprise features include:\n\n- Centralized user management\n- Teamspace access controls\n- Audit logs for compliance\n- Custom authentication policies\n\nContact our sales team at [context7.com](https://context7.com) for Enterprise plan details.\n\n## Data Protection\n\n### Privacy by Design\n\n- **Data Minimization**: We only collect and store what's necessary\n- **Purpose Limitation**: Documentation data is used only for documentation retrieval\n- **Storage Limitation**: Automated cleanup of outdated data\n- **Transparency**: Clear documentation of what we collect and why\n\n### GDPR Compliance\n\nContext7 provides:\n\n- The right to access your data\n- The right to delete your data\n- Data portability options\n- Clear consent mechanisms\n- Privacy-first data processing\n\n## Data Residency\n\nAll indexed documentation and metadata are stored within Upstash's SOC 2 compliant infrastructure in the United States and the European Union. \nCross-border data transfers comply with the EU General Data Protection Regulation (GDPR) and the EU-U.S. Data Privacy Framework (DPF), and enterprise customers can request region-specific data residency to meet local regulatory requirements.\n\n## Rate Limiting and Abuse Prevention\n\n- IP-based rate limiting for anonymous requests\n- API key-based rate limiting with tiered limits\n- Automatic detection and blocking of abusive patterns\n- Protection against DDoS and scraping attacks\n\n## Prompt Injection Detection\n\nContext7 indexes documentation from public and private repositories. To protect against malicious content being served to AI assistants, Context7 employs a **two-pass prompt injection detection pipeline**.\n\n- **Complementary detection stages** — two independent classifiers run in sequence, combining different detection approaches to maximize coverage while minimizing false positives\n- **Skills.md pipeline** — a separate but related detection pipeline is used for [Skills](/skills) files, adapted to their distinct structure and intent\n- **Continuous monitoring** — flagged content is tracked and reviewed on an ongoing basis\n- **Regular updates** — classifier pipelines are updated to address evolving attack methods and new injection techniques\n\nThis ensures that documentation retrieved through Context7 is safe to consume by both human developers and AI coding agents.\n\nFor more details on how Context7 handles quality and safety, see the [Quality and Safety in Context7](https://upstash.com/blog/context7-quality-and-safety) blog post.\n\n## Secure Development Practices\n\n- Regular security code reviews\n- Automated dependency scanning\n- Secure CI/CD pipelines\n- Principle of least privilege for all systems\n- Security testing in development lifecycle\n\n## Reporting Security Issues\n\nIf you discover a security vulnerability:\n\n1. **Do not** publicly disclose the issue\n2. Report via [GitHub Security](https://github.com/upstash/context7/security)\n3. Include detailed steps to reproduce the issue\n4. Allow reasonable time for us to address the issue\n\nWe take all security reports seriously and will respond promptly.\n\n## Transparency and Compliance\n\n### Open Source\n\nThe Context7 MCP server is open source:\n\n- Code is publicly available on GitHub\n- Community can audit and contribute\n- Transparent implementation and practices\n\nRepository: [github.com/upstash/context7](https://github.com/upstash/context7)\n\n### Compliance Certifications\n\nContext7 benefits from Upstash's compliance certifications:\n\n- SOC 2 Type II\n- GDPR compliant\n- ISO 27001 (in progress)\n\n## Best Practices for Users\n\n### Secure Your API Keys\n\n- Never commit API keys to version control\n- Use environment variables for key storage\n- Rotate keys regularly\n- Use different keys for different environments\n- Revoke unused or compromised keys immediately\n\n### Private Repositories\n\nFor private repository access:\n\n- Only grant minimum required permissions\n- Use dedicated API keys for private repos\n- Regularly audit access permissions\n- Consider using GitHub Apps with fine-grained permissions\n\n### Network Security\n\n- Use HTTPS for all API communications (enforced)\n- Configure proxy settings securely if behind a firewall\n- Monitor API usage for unusual patterns\n- Implement request timeouts and retries\n\n## Data Retention\n\n- **Library Documentation**: Retained while the library is active and public\n- **API Logs**: Retained for 30 days for debugging and analytics\n- **User Data**: Retained according to your account status\n- **Deleted Data**: Permanently removed within 30 days of deletion request\n\n## Questions and Support\n\nFor security-related questions:\n\n- Contact us through [GitHub Issues](https://github.com/upstash/context7/issues)\n- Join our [Discord Community](https://upstash.com/discord)\n- Enterprise customers: Contact your dedicated support team\n\nFor privacy policy details, visit: [context7.com/privacy](https://context7.com/privacy)\n\n---\n\n**Last Updated**: February 2026\n\nWe continuously improve our security practices. Check this page regularly for updates.\n"
  },
  {
    "path": "docs/resources/troubleshooting.mdx",
    "content": "---\ntitle: Troubleshooting\n---\n\nThis guide helps you resolve common issues when setting up or using Context7 MCP.\n\n## Quick Checklist\n\n- Confirm Node.js v18+ is installed (`node --version`)\n- Update to the latest Context7 MCP package (`@upstash/context7-mcp@latest`)\n- Verify connectivity with `curl https://mcp.context7.com/ping`\n- Add your API key to the configuration if you hit rate limits\n- Enable debug logs (`DEBUG=*`) before collecting support information\n\n<Tip>\n  **Skip Node.js issues entirely**: Use the remote server connection instead of local npx. Most MCP clients support connecting to `https://mcp.context7.com/mcp` directly, which requires no local Node.js installation. See [All MCP Clients](/resources/all-clients) for configuration examples.\n</Tip>\n\n## Common Fixes\n\n### Use Latest Version\n\nAdd `@latest` to ensure you're using the most recent version:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n### Module Not Found / Use Alternative Runtimes\n\nIf you encounter `ERR_MODULE_NOT_FOUND`, try `bunx` or `deno` instead of `npx`:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-env=NO_DEPRECATION,TRACE_DEPRECATION\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n### ESM Resolution Issues\n\nFor `Error: Cannot find module 'uriTemplate.js'`, use the `--experimental-vm-modules` flag:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n\n### TLS/Certificate Issues\n\nUse the `--experimental-fetch` flag:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-fetch\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n### Node.js Version\n\nEnsure you're using Node.js v18 or higher (`node --version`).\n\n## Platform-Specific Issues\n\n### Windows Issues\n\n#### Request Timeout Errors\n\nOn Windows, some users may encounter request timeout errors with the default configuration. Try using the full path to Node.js and the installed package:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"C:\\\\Program Files\\\\nodejs\\\\node.exe\",\n      \"args\": [\n        \"C:\\\\Users\\\\yourname\\\\AppData\\\\Roaming\\\\npm\\\\node_modules\\\\@upstash\\\\context7-mcp\\\\dist\\\\index.js\",\n        \"--transport\",\n        \"stdio\",\n        \"--api-key\",\n        \"YOUR_API_KEY\"\n      ]\n    }\n  }\n}\n```\n\nAlternatively, use this configuration with `cmd`:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n### macOS Issues\n\n#### Request Timeout Errors\n\nOn macOS, some users may encounter the same request timeout errors. Use the full path to Node.js and the installed package:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"/Users/yourname/.nvm/versions/node/v22.14.0/bin/node\",\n      \"args\": [\n        \"/Users/yourname/.nvm/versions/node/v22.14.0/lib/node_modules/@upstash/context7-mcp/dist/index.js\",\n        \"--transport\",\n        \"stdio\",\n        \"--api-key\",\n        \"YOUR_API_KEY\"\n      ]\n    }\n  }\n}\n```\n\n<Note>\n  Replace `yourname` and the Node.js version (`v22.14.0`) with your actual username and installed\n  Node.js version.\n</Note>\n\n## API and Connection Issues\n\n### Rate Limiting\n\nIf you encounter rate limit errors:\n\n- **Get an API key**: Sign up at [context7.com/dashboard](https://context7.com/dashboard) for higher rate limits\n- **Add the API key to your configuration**:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n### Authentication Errors\n\nIf you see `401 Unauthorized` errors:\n\n1. **Verify your API key** is correct and starts with `ctx7sk`\n2. **Check the header format** - ensure the API key is properly set:\n\nFor HTTP transport:\n\n```json\n{\n  \"headers\": {\n    \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n  }\n}\n```\n\nFor stdio transport:\n\n```json\n{\n  \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n}\n```\n\n### Library Not Found\n\nIf you get `404 Not Found` errors:\n\n1. **Verify the library ID** format is correct: `/owner/repo` or `/owner/repo/version`\n2. **Search for the library** first using `resolve-library-id` tool\n3. **Check if the library exists** at [context7.com](https://context7.com)\n\n## MCP Client-Specific Issues\n\n### Cursor\n\n- Make sure you're using Cursor 1.0 or later for the best MCP support\n- Try both global (`~/.cursor/mcp.json`) and project-specific (`.cursor/mcp.json`) configurations\n- Restart Cursor after changing the MCP configuration\n\n### VS Code\n\n- Ensure you have the latest version of VS Code with MCP support\n- Check that the Copilot extension is installed and updated\n- Restart VS Code after configuration changes\n\n### Claude Code\n\n- Verify the MCP server is added correctly with `claude mcp list`\n- Check logs with `claude mcp logs context7`\n- Try removing and re-adding the server\n\n## Configure HTTPS Proxy\n\nIf you're behind a corporate proxy, configure Context7 to route through it.\n\n### Set Environment Variables\n\n<AccordionGroup>\n  <Accordion title=\"Linux/macOS\" icon=\"terminal\">\n    ```bash\n    export https_proxy=http://proxy.example.com:8080\n    export HTTPS_PROXY=http://proxy.example.com:8080\n    ```\n\n    With authentication:\n    ```bash\n    export https_proxy=http://username:password@proxy.example.com:8080\n    ```\n\n  </Accordion>\n\n  <Accordion title=\"Windows (Command Prompt)\" icon=\"windows\">\n    ```cmd\n    set https_proxy=http://proxy.example.com:8080\n    set HTTPS_PROXY=http://proxy.example.com:8080\n    ```\n\n    With authentication:\n    ```cmd\n    set https_proxy=http://username:password@proxy.example.com:8080\n    ```\n\n  </Accordion>\n\n  <Accordion title=\"Windows (PowerShell)\" icon=\"windows\">\n    ```powershell\n    $env:https_proxy = \"http://proxy.example.com:8080\"\n    $env:HTTPS_PROXY = \"http://proxy.example.com:8080\"\n    ```\n  </Accordion>\n</AccordionGroup>\n\n### Or Configure in MCP Settings\n\nAdd proxy directly to your MCP configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"env\": {\n        \"https_proxy\": \"http://proxy.example.com:8080\",\n        \"HTTPS_PROXY\": \"http://proxy.example.com:8080\"\n      }\n    }\n  }\n}\n```\n\nBoth lowercase and uppercase environment variables are supported.\n\n<Tip>\n  After updating proxy settings, run `curl https://mcp.context7.com/ping` to confirm outbound\n  connectivity before restarting your IDE.\n</Tip>\n\n## Debugging Tips\n\n### Enable Verbose Logging\n\nAdd debug output to your configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"env\": {\n        \"DEBUG\": \"*\"\n      }\n    }\n  }\n}\n```\n\n### Test with MCP Inspector\n\nTest your setup independently:\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n\nThis opens an interactive inspector to test Context7 tools.\n\n### Check Server Status\n\nTest that the remote server is reachable:\n\n```bash\ncurl https://mcp.context7.com/ping\n```\n\nExpected response: `{\"status\": \"ok\", \"message\": \"pong\"}`\n\n## Additional Support\n\nIf these solutions don't resolve your issue:\n\n1. **Check GitHub Issues**: Search for similar problems at [github.com/upstash/context7/issues](https://github.com/upstash/context7/issues)\n2. **Create a new issue**: Include your:\n   - Operating system and version\n   - Node.js version (`node --version`)\n   - MCP client and version\n   - Configuration (remove sensitive data like API keys)\n   - Error messages and logs\n3. **Join Discord**: Get help from the community at [upstash.com/discord](https://upstash.com/discord)\n\n## Additional Resources\n\n- [Getting Started Guide](/overview)\n- [Installation Instructions](https://github.com/upstash/context7#installation)\n- [API Documentation](/api-guide)\n- [Security & Privacy](/resources/security)\n"
  },
  {
    "path": "docs/sdks/ts/commands/get-context.mdx",
    "content": "---\ntitle: \"Get Context\"\ndescription: \"Retrieve documentation context for a library\"\n---\n\n# Get Context\n\nRetrieve documentation context for a specific library. Returns documentation as a JSON array of documentation snippets (default) or as plain text.\n\n## Arguments\n\n<ParamField path=\"query\" type=\"string\" required>\n  The user's question or task (used for relevance ranking)\n</ParamField>\n\n<ParamField path=\"libraryId\" type=\"string\" required>\n  The library identifier (e.g., `/facebook/react`)\n</ParamField>\n\n<ParamField path=\"options\" type=\"GetContextOptions\">\n  <Expandable title=\"properties\">\n    <ParamField path=\"type\" type=\"'json' | 'txt'\">\n      Format of the response\n      - `json`: Array of Documentation objects (default)\n      - `txt`: Plain text format\n\n      Default: `\"json\"`\n    </ParamField>\n  </Expandable>\n</ParamField>\n\n## Response\n\nThe response type depends on the `type` option.\n\n### JSON Format (`type: \"json\"` or default)\n\nReturns `Documentation[]` - an array of documentation objects.\n\n### Text Format (`type: \"txt\"`)\n\nReturns a `string` containing the documentation context ready to use in LLM prompts.\n\n<ResponseField name=\"Documentation\" type=\"object\">\n  <Expandable title=\"properties\">\n    <ResponseField name=\"title\" type=\"string\" required>\n      Title of the documentation snippet\n    </ResponseField>\n    <ResponseField name=\"content\" type=\"string\" required>\n      The documentation content (includes code blocks in markdown format)\n    </ResponseField>\n    <ResponseField name=\"source\" type=\"string\" required>\n      Source identifier for the snippet\n    </ResponseField>\n  </Expandable>\n</ResponseField>\n\n## Examples\n\n<RequestExample>\n```typescript JSON Format (Default)\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\nconst docs = await client.getContext(\n  \"How do I use hooks?\",\n  \"/facebook/react\"\n);\n\ndocs.forEach((doc) => {\n  console.log(doc.title);\n  console.log(doc.content);\n  console.log(doc.source);\n});\n```\n\n```typescript Text Format\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\nconst context = await client.getContext(\n  \"How do I use hooks?\",\n  \"/facebook/react\",\n  { type: \"txt\" }\n);\n\nconsole.log(context);\n```\n\n```typescript Error Handling\nimport { Context7, Context7Error } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\ntry {\n  const context = await client.getContext(\n    \"How to get started?\",\n    \"/invalid/library\"\n  );\n} catch (error) {\n  if (error instanceof Context7Error) {\n    console.error(\"API Error:\", error.message);\n  } else {\n    throw error;\n  }\n}\n```\n</RequestExample>\n\n## Use Cases\n\n### Providing Context to LLMs\n\n```typescript\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\nasync function getDocsForPrompt(library: string, question: string) {\n  const context = await client.getContext(question, library);\n\n  return `\nHere is the relevant documentation:\n\n${context}\n\nUser question: ${question}\n`;\n}\n\nconst prompt = await getDocsForPrompt(\"/facebook/react\", \"How do I use useEffect?\");\n```\n\n### Processing Individual Snippets\n\n```typescript\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\nconst docs = await client.getContext(\n  \"How to create components?\",\n  \"/facebook/react\",\n  { type: \"json\" }\n);\n\ndocs.forEach((doc) => {\n  console.log(`Title: ${doc.title}`);\n  console.log(`Source: ${doc.source}`);\n  console.log(`Content length: ${doc.content.length} chars`);\n});\n```\n"
  },
  {
    "path": "docs/sdks/ts/commands/search-library.mdx",
    "content": "---\ntitle: \"Search Library\"\ndescription: \"Search available libraries\"\n---\n\n# Search Library\n\nSearch across available libraries. Returns an array of matching libraries with metadata useful for selection.\n\n## Arguments\n\n<ParamField path=\"query\" type=\"string\" required>\n  The user's question or task (used for relevance ranking)\n</ParamField>\n\n<ParamField path=\"libraryName\" type=\"string\" required>\n  The library name to search for\n</ParamField>\n\n## Response\n\nReturns `Library[]` - an array of library objects.\n\n<ResponseField name=\"Library\" type=\"object\">\n  <Expandable title=\"properties\">\n    <ResponseField name=\"id\" type=\"string\" required>\n      Unique identifier for the library (e.g., `/facebook/react`)\n    </ResponseField>\n    <ResponseField name=\"name\" type=\"string\" required>\n      Display name of the library\n    </ResponseField>\n    <ResponseField name=\"description\" type=\"string\" required>\n      Brief description of the library\n    </ResponseField>\n    <ResponseField name=\"totalSnippets\" type=\"number\" required>\n      Total number of documentation snippets available\n    </ResponseField>\n    <ResponseField name=\"trustScore\" type=\"number\" required>\n      Trust score of the library\n    </ResponseField>\n    <ResponseField name=\"benchmarkScore\" type=\"number\" required>\n      Benchmark score indicating documentation quality\n    </ResponseField>\n    <ResponseField name=\"versions\" type=\"string[]\">\n      Available versions\n    </ResponseField>\n  </Expandable>\n</ResponseField>\n\n## Examples\n\n<RequestExample>\n```typescript Basic Search\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\nconst libraries = await client.searchLibrary(\n  \"I need to build a UI\",\n  \"react\"\n);\n\nconsole.log(`Found ${libraries.length} libraries`);\nlibraries.forEach((library) => {\n  console.log(`${library.name}: ${library.description}`);\n});\n```\n\n```typescript Selecting Best Library\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\nconst libraries = await client.searchLibrary(\n  \"I want to build a web app\",\n  \"next\"\n);\n\nconst sorted = libraries.sort((a, b) => b.benchmarkScore - a.benchmarkScore);\nconst best = sorted[0];\n\nconsole.log(`Best match: ${best.name} (score: ${best.benchmarkScore})`);\nconsole.log(`Available snippets: ${best.totalSnippets}`);\n```\n\n```typescript Error Handling\nimport { Context7, Context7Error } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\ntry {\n  const libraries = await client.searchLibrary(\"query\", \"express\");\n\n  if (libraries.length === 0) {\n    console.log(\"No libraries found\");\n  } else {\n    console.log(`Found ${libraries.length} libraries`);\n  }\n} catch (error) {\n  if (error instanceof Context7Error) {\n    console.error(\"API Error:\", error.message);\n  } else {\n    throw error;\n  }\n}\n```\n</RequestExample>\n\n## Use Cases\n\n### Finding Libraries by Score\n\n```typescript\nconst libraries = await client.searchLibrary(\"state management\", \"redux\");\n\nconst trusted = libraries.sort((a, b) => b.trustScore - a.trustScore);\nconsole.log(\"Most trusted:\", trusted[0].name);\n```\n\n### Checking Available Versions\n\n```typescript\nconst libraries = await client.searchLibrary(\"I want to use lodash\", \"lodash\");\n\nconst library = libraries[0];\nif (library.versions) {\n  console.log(`Available versions: ${library.versions.join(\", \")}`);\n}\n```\n\n### Full Workflow\n\n```typescript\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\nconst libraries = await client.searchLibrary(\n  \"I want to build a React app\",\n  \"react\"\n);\n\nconst library = libraries[0];\nconsole.log(`Using: ${library.name} (${library.id})`);\n\nconst context = await client.getContext(\n  \"How do I create a component?\",\n  library.id\n);\n\nconsole.log(context);\n```\n"
  },
  {
    "path": "docs/sdks/ts/getting-started.mdx",
    "content": "---\ntitle: \"Getting Started\"\ndescription: \"Get started with the Context7 TypeScript SDK\"\n---\n\n<Warning>\n  **Work in Progress**: This SDK is currently under active development. The API is subject to change and may introduce breaking changes in future releases.\n</Warning>\n\n# Getting Started\n\n`@upstash/context7-sdk` is a TypeScript SDK for Context7, enabling easier access to library documentation with full type coverage.\n\nUsing `@upstash/context7-sdk` you can:\n\n- Search across available libraries\n- Get documentation context for any library\n- Access library metadata including trust scores and versions\n\nYou can find the Github Repository [here](https://github.com/upstash/context7/tree/master/packages/sdk).\n\n## Install\n\n<CodeGroup>\n  ```shell npm\n  npm install @upstash/context7-sdk\n  ```\n\n```shell pnpm\npnpm add @upstash/context7-sdk\n```\n\n```shell yarn\nyarn add @upstash/context7-sdk\n```\n\n```shell bun\nbun add @upstash/context7-sdk\n```\n\n</CodeGroup>\n\n## Usage\n\n### Initializing the Client\n\nTo use the Context7 SDK, you need an API key. You can get your API key from the [Context7 Dashboard](https://context7.com/dashboard).\n\n#### Using environment variables\n\nThe SDK automatically reads from environment variables if no API key is provided in the config:\n\n```bash\nCONTEXT7_API_KEY=\"your_api_key_here\"\n```\n\nWhen an environment variable is set, you can initialize the client without any parameters:\n\n```typescript\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n```\n\n#### Using a configuration object\n\nIf you prefer to pass configuration in code, the constructor accepts a config object containing the apiKey value. This could be useful if your application needs to interact with multiple projects, each with a different configuration.\n\n```typescript\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7({\n  apiKey: <CONTEXT7_API_KEY>,\n});\n```\n\n<Note>\n  The SDK checks for API keys in this order: 1. `config.apiKey` (if provided) 2.\n  `process.env.CONTEXT7_API_KEY`\n</Note>\n\n## Quick Start Example\n\n```typescript\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\n// Search for libraries\nconst libraries = await client.searchLibrary(\n  \"I need to build a UI with components\",\n  \"react\"\n);\nconsole.log(`Found ${libraries.length} libraries`);\nconsole.log(libraries[0].id); // \"/facebook/react\"\n\n// Get documentation as JSON array (default)\nconst docs = await client.getContext(\n  \"How do I use hooks?\",\n  \"/facebook/react\"\n);\nconsole.log(docs[0].title, docs[0].content);\n\n// Get documentation context as plain text\nconst context = await client.getContext(\"How do I use hooks?\", \"/facebook/react\", {\n  type: \"txt\",\n});\nconsole.log(context);\n```\n\n## Error Handling\n\nThe SDK throws `Context7Error` for API errors:\n\n```typescript\nimport { Context7, Context7Error } from \"@upstash/context7-sdk\";\n\nconst client = new Context7();\n\ntry {\n  const context = await client.getContext(\"query\", \"/invalid/library\");\n} catch (error) {\n  if (error instanceof Context7Error) {\n    console.error(\"Context7 API Error:\", error.message);\n  } else {\n    console.error(\"Unexpected error:\", error);\n  }\n}\n```\n\n## Next Steps\n\nExplore the SDK commands:\n\n- [Search Library](/sdks/ts/commands/search-library) - Search for libraries\n- [Get Context](/sdks/ts/commands/get-context) - Retrieve library documentation context\n"
  },
  {
    "path": "docs/skills.mdx",
    "content": "---\ntitle: Skills\ndescription: Install, search, and manage AI coding assistant skills from the Context7 registry\n---\n\nSkills are reusable prompt templates that extend the capabilities of your AI coding assistants. They allow you to share and install common workflows like React best practices, web design guidelines, PDF processing, and more across projects and teams.\n\nContext7 maintains a registry of skills at [context7.com/skills](https://context7.com/skills) that can be installed directly into your AI coding assistant with a single command.\n\n## What Are Skills?\n\nSkills follow the [Agent Skills](https://agentskills.io) open standard — a specification that works across multiple AI coding tools. A skill is a directory containing a `SKILL.md` file with instructions that your AI assistant loads when relevant.\n\n**Why use skills?**\n\n- **Standardize workflows**: Ensure consistent code reviews, commit messages, or documentation across your team\n- **Share expertise**: Package domain knowledge (e.g., \"how we handle authentication\") as reusable prompts\n- **Save time**: Install pre-built skills instead of repeatedly explaining the same patterns to your AI assistant\n\n**Popular skills:**\n\n| Skill | What it does |\n|-------|--------------|\n| `vercel-react-best-practices` | Teaches Claude modern React patterns, Server Components, and performance optimization |\n| `web-design-guidelines` | Guides Claude on UI/UX principles, spacing, typography, and responsive layouts |\n| `pdf` / `docx` / `xlsx` | Enables Claude to read, create, and manipulate Office documents and PDFs |\n| `supabase-postgres-best-practices` | Helps Claude write optimized Postgres queries, RLS policies, and auth flows |\n| `seo-audit` | Lets Claude analyze pages for SEO issues and suggest improvements |\n| `browser-use` | Allows Claude to control browsers for testing and automation |\n\n## The Context7 Skills Registry\n\nThe [Context7 Skills Registry](https://context7.com/skills) is a searchable marketplace of skills indexed from GitHub repositories. Each skill is identified by its repository path (e.g., `/anthropics/skills`) and skill name.\n\nWhen browsing or searching skills, you'll see:\n\n| Field | Description |\n|-------|-------------|\n| **Name** | The skill identifier used for installation |\n| **Description** | What the skill does and when to use it |\n| **Install Count** | Number of times the skill has been installed |\n| **Trust Score** | Quality and safety indicator (0-10) |\n\n### CLI\n\nYou can interact with the registry directly from your terminal using the `ctx7` CLI. No configuration needed — most commands work without authentication.\n\n**Discover and install skills:**\n\n```bash\n# Search the registry by keyword\nctx7 skills search pdf\nctx7 skills search \"react testing\"\n\n# Browse all skills in a specific repository\nctx7 skills info /anthropics/skills\n\n# Install a skill interactively (prompts you to pick)\nctx7 skills install /anthropics/skills\n\n# Install a specific skill by name\nctx7 skills install /anthropics/skills pdf\n\n# Get suggestions based on your project's dependencies\nctx7 skills suggest\n```\n\n**Manage installed skills:**\n\n```bash\n# List skills installed in the current project\nctx7 skills list\n\n# List skills installed for a specific client\nctx7 skills list --claude\nctx7 skills list --cursor\n\n# Remove a skill\nctx7 skills remove pdf\n```\n\n**Generate a custom skill with AI:**\n\n```bash\n# Requires login — opens an interactive generation flow\nctx7 login\nctx7 skills generate\n```\n\nAll install commands accept `--claude`, `--cursor`, `--universal`, and `--global` flags to target a specific client or install location. \n\nSee the [CLI reference](/clients/cli#skills) for the full flag reference and examples.\n\n### Trust & Security\n\nContext7 vets every skill in the registry before it reaches you — both through automated scanning and community-driven quality signals.\n\n#### Trust Scores\n\nEvery skill has a **trust score** from 0 to 10 that reflects the reliability of its source.\n\n| Score | Level | Meaning |\n|-------|-------|---------|\n| 7.0 - 10.0 | High | Verified or well-established source |\n| 3.0 - 6.9 | Medium | Standard community contribution |\n| 0.0 - 2.9 | Low | New or unverified — review before using |\n\nHigher scores indicate skills from reputable sources with community validation. Trust scores are visible in search results and install prompts so you can make an informed decision before installing.\n\n#### Security Features\n\nContext7 automatically scans skills for potential security issues before they appear in the registry:\n\n- **Prompt injection detection**: Skills containing potentially malicious instructions are blocked from installation\n- **Blocked skill warnings**: When viewing a repository, you'll see how many skills were blocked due to security concerns\n- **Clear error messages**: If you try to install a blocked skill, you'll receive a specific warning explaining why\n\n## Skill File Structure\n\nEach skill is a directory containing at minimum a `SKILL.md` file:\n\n```\nmy-skill/\n├── SKILL.md           # Main instructions (required)\n├── templates/         # Optional templates\n├── examples/          # Optional example outputs\n└── scripts/           # Optional executable scripts\n```\n\n### SKILL.md Format\n\nSkills use YAML frontmatter followed by markdown instructions:\n\n```yaml\n---\nname: my-skill\ndescription: What this skill does and when to use it\n---\n\nInstructions for the AI assistant go here.\n\nUse markdown formatting, code examples, and clear steps.\n```\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `name` | Yes | Identifier for the skill (lowercase, hyphens allowed) |\n| `description` | Yes | Explains what the skill does — used for discovery and auto-triggering |\n\nThe markdown body contains the actual instructions your AI assistant follows when the skill is invoked.\n\n## Supported Clients\n\nThe CLI automatically detects installed AI coding assistants and offers to install skills for them.\n\n| Client | Project Directory | Global Directory |\n|--------|-------------------|------------------|\n| Universal (Amp, Codex, Gemini CLI, GitHub Copilot, OpenCode + more) | `.agents/skills/` | `~/.agents/skills/` |\n| Claude Code | `.claude/skills/` | `~/.claude/skills/` |\n| Cursor | `.cursor/skills/` | `~/.cursor/skills/` |\n| Antigravity | `.agent/skills/` | `~/.agent/skills/` |\n\n**Project vs Global:**\n- **Project skills** (default): Installed in your current project directory, available only in that project\n- **Global skills** (`--global`): Installed in your home directory, available across all projects\n\n## Managing Skills\n\nUse the `ctx7` CLI to install, search, generate, and remove skills. See the [CLI reference](/clients/cli#skills) for all commands.\n\n```bash\n# Quick start\nnpx ctx7 skills search pdf\nnpx ctx7 skills install /anthropics/skills pdf\n```\n\n## Troubleshooting\n\n### Permission Denied\n\nIf you see permission errors when installing or removing skills:\n\n```bash\n# Fix directory permissions\nsudo chown -R $(whoami) ~/.claude/skills\n```\n\n### Skill Blocked Due to Prompt Injection\n\nIf a skill is blocked, it contains content flagged as potentially malicious. This is a security feature — the skill cannot be installed.\n\n```\nError: This skill contains potentially malicious content and cannot be installed.\n```\n\nConsider using an alternative skill or contacting the skill author.\n\n### Client Not Detected\n\nIf your AI coding assistant isn't detected, ensure its configuration directory exists:\n\n```bash\n# For Claude Code\nmkdir -p .claude\n\n# For Cursor\nmkdir -p .cursor\n```\n\n### Authentication Issues\n\nIf login fails or tokens expire:\n\n```bash\nctx7 logout\nctx7 login\n```\n\n## Next Steps\n\n<CardGroup cols={2}>\n  <Card title=\"CLI Reference\" icon=\"terminal\" href=\"/clients/cli\">\n    All ctx7 commands for installing, searching, and generating skills\n  </Card>\n  <Card title=\"Browse Skills\" icon=\"magnifying-glass\" href=\"https://context7.com/skills\">\n    Explore the skills registry\n  </Card>\n  <Card title=\"Agent Skills Spec\" icon=\"code\" href=\"https://agentskills.io\">\n    Read the open standard specification\n  </Card>\n  <Card title=\"Claude Code Skills\" icon=\"book\" href=\"https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/skills\">\n    Learn more about how skills work in Claude Code\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/tips.mdx",
    "content": "---\ntitle: Best Practices\ndescription: Get the most out of Context7 with these best practices\n---\n\n## Add a Rule\n\nTo avoid typing `use context7` in every prompt, add a rule to your MCP client to automatically invoke Context7 for code-related questions:\n\n- **Cursor**: `Cursor Settings > Rules`\n- **Claude Code**: `CLAUDE.md`\n- Or the equivalent in your MCP client\n\n**Example rule:**\n\n```txt\nAlways use Context7 MCP when I need library/API documentation, code generation, setup or configuration steps without me having to explicitly ask.\n```\n\n## Use Library ID\n\nIf you already know exactly which library you want to use, add its Context7 ID to your prompt. That way, Context7 MCP server can skip the library-matching step and directly continue with retrieving docs.\n\n```txt\nImplement basic authentication with Supabase. use library /supabase/supabase for API and docs.\n```\n\nThe slash syntax tells the MCP tool exactly which library to load docs for.\n\n## Specify a Version\n\nTo get documentation for a specific library version, just mention the version in your prompt:\n\n```txt\nHow do I set up Next.js 14 middleware? use context7\n```\n\nContext7 will automatically match the appropriate version.\n"
  },
  {
    "path": "eslint.config.js",
    "content": "import tseslint from \"typescript-eslint\";\nimport eslintPluginPrettier from \"eslint-plugin-prettier\";\n\nexport default tseslint.config({\n  // Base ESLint configuration\n  ignores: [\"node_modules/**\", \"build/**\", \"dist/**\", \".git/**\", \".github/**\"],\n  languageOptions: {\n    ecmaVersion: 2020,\n    sourceType: \"module\",\n    parser: tseslint.parser,\n    parserOptions: {},\n    globals: {\n      // Add Node.js globals\n      process: \"readonly\",\n      require: \"readonly\",\n      module: \"writable\",\n      console: \"readonly\",\n    },\n  },\n  // Settings for all files\n  linterOptions: {\n    reportUnusedDisableDirectives: true,\n  },\n  // Apply ESLint recommended rules\n  extends: [tseslint.configs.recommended],\n  plugins: {\n    prettier: eslintPluginPrettier,\n  },\n  rules: {\n    // TypeScript rules\n    \"@typescript-eslint/explicit-module-boundary-types\": \"off\",\n    \"@typescript-eslint/no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\" }],\n    \"@typescript-eslint/no-explicit-any\": \"warn\",\n    // Prettier integration\n    \"prettier/prettier\": \"error\",\n  },\n});\n"
  },
  {
    "path": "gemini-extension.json",
    "content": "{\n  \"name\": \"context7\",\n  \"description\": \"Up-to-date code docs for any prompt\",\n  \"version\": \"1.0.0\",\n  \"settings\": [\n    {\n      \"name\": \"API Key\",\n      \"description\": \"Context7 API key. Create new key at https://context7.com/dashboard.\",\n      \"envVar\": \"CONTEXT7_API_KEY\"\n    }\n  ],\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"${CONTEXT7_API_KEY}\"]\n    }\n  }\n}\n"
  },
  {
    "path": "i18n/README.ar.md",
    "content": "# Context7 MCP - توثيق أكواد محدث لأي أمر برمجي\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n\n## ❌ بدون Context7\n\nتعتمد النماذج اللغوية الكبيرة على معلومات قديمة أو عامة حول المكتبات التي تستخدمها. مما يؤدي إلى:\n\n- ❌ أمثلة أكواد قديمة مبنية على بيانات تدريب مضى عليها وقت طويل\n- ❌ واجهات برمجة تطبيقات وهمية غير موجودة\n- ❌ إجابات عامة لنسخ قديمة من الحزم\n\n## ✅ مع Context7\n\nيستخرج Context7 MCP التوثيق والأمثلة البرمجية المحدثة مباشرة من المصدر — ويضعها في طلبك للنموذج.\nأضف `use context7` إلى طلبك في Cursor:\n\n```txt\nأنشئ مشروع Next.js بسيط باستخدام app router. use context7\n```\n\n```txt\nأنشئ سكربت لحذف الصفوف التي تكون فيها المدينة فارغة \"\" باستخدام بيانات اعتماد PostgreSQL. use context7\n```\n\nيقوم Context7 بجلب الأمثلة المحدثة والتوثيق المناسب مباشرة إلى السياق.\n\n- 1️⃣ اكتب طلبك بشكل طبيعي\n- 2️⃣ أخبر النموذج بـ `use context7`\n- 3️⃣ احصل على أكواد تعمل مباشرة\n  لا حاجة للتنقل بين التبويبات، لا واجهات برمجة تطبيقات وهمية، لا أكواد قديمة.\n\n## 🛠️ البدء\n\n### المتطلبات\n\n- Node.js إصدار 18.0.0 أو أعلى\n- Cursor، Windsurf، Claude Desktop أو أي عميل MCP آخر\n\n### التثبيت عبر Smithery\n\nلتثبيت Context7 MCP Server تلقائيًا لـ Claude Desktop:\n\n```bash\nnpx -y @smithery/cli install @upstash/context7-mcp --client claude\n```\n\n### التثبيت في Cursor\n\nاذهب إلى: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\nأو أضف هذا إلى ملف `~/.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### التثبيت باستخدام Bun\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### التثبيت باستخدام Deno\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-env\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n### التثبيت في Windsurf\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### التثبيت في VS Code\n\n```json\n{\n  \"servers\": {\n    \"Context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### التثبيت في Zed\n\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n### التثبيت في Claude Code\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp@latest\n```\n\n### التثبيت في Claude Desktop\n\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### التثبيت في BoltAI\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### التثبيت في Copilot Coding Agent\n\nأضف التكوين التالي إلى قسم `mcp` في ملف إعدادات Copilot Coding Agent الخاص بك Repository->Settings->Copilot->Coding agent->MCP configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\n\nلمزيد من المعلومات، راجع [التوثيق الرسمي على GitHub](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n\n### باستخدام Docker\n\n**Dockerfile:**\n\n```Dockerfile\nFROM node:18-alpine\nWORKDIR /app\nRUN npm install -g @upstash/context7-mcp@latest\nCMD [\"context7-mcp\"]\n```\n\n**بناء الصورة:**\n\n```bash\ndocker build -t context7-mcp .\n```\n\n**التهيئة داخل العميل:**\n\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n      \"transportType\": \"stdio\"\n    }\n  }\n}\n```\n\n### التثبيت في Windows\n\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp@latest\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n\n### الأدوات المتوفرة\n\n- `resolve-library-id`: يحول اسم مكتبة عام إلى معرف متوافق مع Context7.\n  - `query` (مطلوب): سؤال أو مهمة المستخدم (لترتيب الصلة)\n  - `libraryName` (مطلوب): اسم المكتبة للبحث عنها\n- `query-docs`: يستخرج التوثيق حسب المعرف.\n  - `libraryId` (مطلوب): معرف Context7 المتوافق الدقيق (مثل `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (مطلوب): السؤال أو المهمة للحصول على توثيق ذي صلة\n\n## التطوير\n\n```bash\npnpm i\npnpm run build\n```\n\n**التهيئة المحلية:**\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n\n**الاختبار باستخدام MCP Inspector:**\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp@latest\n```\n\n## استكشاف الأخطاء\n\n### ERR_MODULE_NOT_FOUND\n\nاستخدم `bunx` بدلاً من `npx`.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### مشاكل في ESM\n\nجرّب إضافة:\n\n```json\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n}\n```\n\n### أخطاء عميل MCP\n\n1. أزل `@latest`\n2. جرّب `bunx`\n3. جرّب `deno`\n4. تأكد أنك تستخدم Node v18 أو أحدث\n\n## إخلاء مسؤولية\n\nالمشاريع المدرجة في Context7 مساهم بها من المجتمع، ولا يمكن ضمان دقتها أو أمانها بشكل كامل. الرجاء الإبلاغ عن أي محتوى مريب باستخدام زر \"الإبلاغ\".\n\n## Context7 في الإعلام\n\n- [Better Stack: \"أداة مجانية تجعل Cursor أذكى 10x\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"أفضل MCP Server لمساعدين الذكاء الاصطناعي البرمجيين\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Context7 + SequentialThinking: هل هذا AGI؟](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [تحديث جديد من Context7 MCP](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [إعداد Context7 في VS Code](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Context7: MCP جديد سيغير البرمجة](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [Cline & RooCode + Context7: قوة مضاعفة](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [أفضل 5 MCP Servers لتجربة برمجة ساحرة](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## سجل النجوم\n\n[![Star History Chart](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## الترخيص\n\nMIT\n"
  },
  {
    "path": "i18n/README.de.md",
    "content": "# Context7 MCP - Aktuelle Dokumentation für jeden Prompt\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"In VS Code installieren (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n\n## ❌ Ohne Context7\n\nKI-Sprachmodelle (LLMs) greifen auf veraltete oder allgemeine Informationen über die von dir verwendeten Bibliotheken zurück. Das Ergebnis:\n\n- ❌ Codebeispiele sind veraltet und basieren auf Trainingsdaten, die Jahre alt sind\n- ❌ Halluzinierte APIs, die gar nicht existieren\n- ❌ Generische Antworten für alte Paketversionen\n\n## ✅ Mit Context7\n\nContext7 MCP holt aktuelle, versionsspezifische Dokumentationen und Codebeispiele direkt aus der Quelle und fügt sie in deinen Prompt ein.\nFüge `use context7` zu deinem Prompt in Cursor hinzu:\n\n```txt\nErstelle ein einfaches Next.js-Projekt mit dem App Router. use context7\n```\n\n```txt\nErstelle ein Skript zum Löschen der Zeilen, in denen die Stadt \"\" ist, mit PostgreSQL-Anmeldedaten. use context7\n```\n\nContext7 holt aktuelle Codebeispiele und Dokumentationen direkt in den Kontext deines LLMs.\n\n- 1️⃣ Schreibe deinen Prompt auf natürliche Weise\n- 2️⃣ Weise das LLM an, context7 zu verwenden, mit `use context7`\n- 3️⃣ Erhalte funktionierende Codeantworten\n  Kein Tab-Switching, keine halluzinierten APIs, die nicht existieren, keine veralteten Code-Generierungen.\n\n## 🛠️ Erste Schritte\n\n### Anforderungen\n\n- Node.js >= v18.0.0\n- Cursor, Windsurf, Claude Desktop oder ein anderer MCP-Client\n\n### Installation über Smithery\n\nUm den Context7 MCP Server für Claude Desktop automatisch über [Smithery](https://smithery.ai/server/@upstash/context7-mcp) zu installieren:\n\n```bash\nnpx -y @smithery/cli install @upstash/context7-mcp --client claude\n```\n\n### Installation in Cursor\n\nGehe zu: `Einstellungen` -> `Cursor-Einstellungen` -> `MCP` -> `Neuen globalen MCP-Server hinzufügen`\nDer empfohlene Ansatz ist die folgende Konfiguration in deine Cursor-Datei `~/.cursor/mcp.json` einzufügen. Siehe die [Cursor MCP Dokumentation](https://docs.cursor.com/context/model-context-protocol) für mehr Informationen.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n<details>\n<summary>Alternative: Bun verwenden</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Alternative: Deno verwenden</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n### Installation in Windsurf\nFüge dies zu deiner Windsurf MCP-Konfigurationsdatei hinzu. Siehe die [Windsurf MCP Dokumentation](https://docs.windsurf.com/windsurf/mcp) für mehr Informationen.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installation in VS Code\n[<img alt=\"In VS Code installieren (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"In VS Code Insiders installieren (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nFüge dies zu deiner VS Code MCP-Konfigurationsdatei hinzu. Siehe die [VS Code MCP Dokumentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) für mehr Informationen.\n```json\n{\n  \"servers\": {\n    \"Context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installation in Zed\nEs kann über [Zed Extensions](https://zed.dev/extensions?query=Context7) installiert werden oder du kannst dies zu deiner Zed `settings.json` hinzufügen. Siehe die [Zed Context Server Dokumentation](https://zed.dev/docs/assistant/context-servers) für mehr Informationen.\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n### Installation in Claude Code\nFühre diesen Befehl aus. Siehe die [Claude Code MCP Dokumentation](https://docs.anthropic.com/de/docs/claude-code/mcp) für mehr Informationen.\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp@latest\n```\n\n### Installation in Claude Desktop\nFüge dies zu deiner Claude Desktop `claude_desktop_config.json` Datei hinzu. Siehe die [Claude Desktop MCP Dokumentation](https://modelcontextprotocol.io/quickstart/user) für mehr Informationen.\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installation im Copilot Coding Agent\nFüge die folgende Konfiguration zum Abschnitt `mcp` deiner Copilot Coding Agent-Konfigurationsdatei hinzu (Repository->Settings->Copilot->Coding agent->MCP configuration):\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nWeitere Informationen findest du in der [offiziellen GitHub-Dokumentation](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n\n### Installation im Copilot CLI\n1.  Öffne die MCP-Konfigurationsdatei von Copilot CLI. Der Ort ist `~/.copilot/mcp-config.json` (wobei `~` dein Home-Verzeichnis ist).\n2.  Füge Folgendes zum `mcpServers`-Objekt in deiner `mcp-config.json`-Datei hinzu:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nOder für einen lokalen Server:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nFalls die `mcp-config.json`-Datei nicht existiert, erstelle sie.\n\n### Docker verwenden\nWenn du den MCP-Server lieber in einem Docker-Container ausführen möchtest:\n1.  **Docker-Image erstellen:**\n    Erstelle zunächst ein `Dockerfile` im Projekt-Root (oder an einem Ort deiner Wahl):\n    <details>\n    <summary>Klicke, um den Dockerfile-Inhalt zu sehen</summary>\n\n    ```Dockerfile\n    FROM node:18-alpine\n    WORKDIR /app\n    # Installiere die neueste Version global\n    RUN npm install -g @upstash/context7-mcp@latest\n    # Port freigeben, falls nötig (optional, abhängig von der MCP-Client-Interaktion)\n    # EXPOSE 3000\n    # Standardbefehl zum Ausführen des Servers\n    CMD [\"context7-mcp\"]\n    ```\n    </details>\n\n    Baue dann das Image mit einem Tag (z.B. `context7-mcp`). **Stelle sicher, dass Docker Desktop (oder der Docker-Daemon) läuft.** Führe den folgenden Befehl in dem Verzeichnis aus, in dem du das `Dockerfile` gespeichert hast:\n    ```bash\n    docker build -t context7-mcp .\n    ```\n2.  **Konfiguriere deinen MCP-Client:**\n    Aktualisiere die Konfiguration deines MCP-Clients, um den Docker-Befehl zu verwenden.\n    _Beispiel für eine cline_mcp_settings.json:_\n    ```json\n    {\n      \"mcpServers\": {\n        \"Сontext7\": {\n          \"autoApprove\": [],\n          \"disabled\": false,\n          \"timeout\": 60,\n          \"command\": \"docker\",\n          \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n          \"transportType\": \"stdio\"\n        }\n      }\n    }\n    ```\n    _Hinweis: Dies ist eine Beispielkonfiguration. Bitte beziehe dich auf die spezifischen Beispiele für deinen MCP-Client (wie Cursor, VS Code usw.), die weiter oben in dieser README beschrieben sind, um die Struktur anzupassen (z.B. `mcpServers` vs `servers`). Stelle außerdem sicher, dass der Bildname in `args` mit dem beim `docker build`-Befehl verwendeten Tag übereinstimmt._\n\n### Verfügbare Tools\n- `resolve-library-id`: Löst einen allgemeinen Bibliotheksnamen in eine Context7-kompatible Bibliotheks-ID auf.\n  - `query` (erforderlich): Die Frage oder Aufgabe des Benutzers (zur Relevanzranking)\n  - `libraryName` (erforderlich): Der Name der zu suchenden Bibliothek\n- `query-docs`: Ruft die Dokumentation für eine Bibliothek mit einer Context7-kompatiblen Bibliotheks-ID ab.\n  - `libraryId` (erforderlich): Exakte Context7-kompatible Bibliotheks-ID (z.B. `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (erforderlich): Die Frage oder Aufgabe, für die relevante Dokumentation abgerufen werden soll\n\n## Entwicklung\nKlone das Projekt und installiere die Abhängigkeiten:\n```bash\npnpm i\n```\nBauen:\n```bash\npnpm run build\n```\n\n### Lokales Konfigurationsbeispiel\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/pfad/zum/ordner/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n\n### Testen mit MCP Inspector\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp@latest\n```\n\n## Fehlerbehebung\n\n### ERR_MODULE_NOT_FOUND\nWenn du diesen Fehler siehst, versuche `bunx` anstelle von `npx` zu verwenden.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\nDies löst häufig Probleme bei der Modulauflösung, besonders in Umgebungen, in denen `npx` Pakete nicht ordnungsgemäß installiert oder auflöst.\n\n### ESM-Auflösungsprobleme\nWenn du einen Fehler wie `Error: Cannot find module 'uriTemplate.js'` bekommst, versuche mit dem Flag `--experimental-vm-modules` auszuführen:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n\n### MCP-Client-Fehler\n1. Versuche, `@latest` aus dem Paketnamen zu entfernen.\n2. Versuche, `bunx` als Alternative zu verwenden.\n3. Versuche, `deno` als Alternative zu verwenden.\n4. Stelle sicher, dass du Node v18 oder höher verwendest, um native Fetch-Unterstützung mit `npx` zu haben.\n\n## Haftungsausschluss\nContext7-Projekte werden von der Community beigetragen, und obwohl wir uns bemühen, eine hohe Qualität aufrechtzuerhalten, können wir die Genauigkeit, Vollständigkeit oder Sicherheit aller Bibliotheksdokumentationen nicht garantieren. Die in Context7 aufgeführten Projekte werden von ihren jeweiligen Eigentümern entwickelt und gepflegt, nicht von Context7. Wenn du auf verdächtige, unangemessene oder potenziell schädliche Inhalte stößt, verwende bitte die Schaltfläche \"Melden\" auf der Projektseite, um uns sofort zu benachrichtigen. Wir nehmen alle Berichte ernst und werden gemeldete Inhalte umgehend überprüfen, um die Integrität und Sicherheit unserer Plattform zu gewährleisten. Durch die Nutzung von Context7 erkennst du an, dass du dies nach eigenem Ermessen und auf eigenes Risiko tust.\n\n## Context7 in den Medien\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income stream surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income stream surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n\n## Verlauf der Sterne\n[![Stern-Historien-Diagramm](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## Lizenz\nMIT\n"
  },
  {
    "path": "i18n/README.es.md",
    "content": "# Context7 MCP - Documentación Actualizada Para Cualquier Prompt\n\n[![Sitio Web](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![insignia smithery](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Instalar en VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Instalar%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522context7%2522%252C%2522config%2522%253A%257B%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522%2540upstash%252Fcontext7-mcp%2540latest%2522%255D%257D%257D)\n\n## ❌ Sin Context7\n\nLos LLMs dependen de información desactualizada o genérica sobre las bibliotecas que utilizas. Obtienes:\n\n- ❌ Ejemplos de código desactualizados y basados en datos de entrenamiento de hace un año\n- ❌ APIs inventadas que ni siquiera existen\n- ❌ Respuestas genéricas para versiones antiguas de paquetes\n\n## ✅ Con Context7\n\nEl Context7 MCP obtiene documentación y ejemplos de código actualizados y específicos de la versión directamente desde la fuente, y los coloca directamente en tu prompt.\nAñade `use context7` a tu prompt en Cursor:\n\n```txt\nCrea un proyecto básico de Next.js con app router. use context7\n```\n\n```txt\nCrea un script para eliminar las filas donde la ciudad es \"\" dadas las credenciales de PostgreSQL. use context7\n```\n\nContext7 obtiene ejemplos de código y documentación actualizados directamente en el contexto de tu LLM.\n\n- 1️⃣ Escribe tu prompt de forma natural\n- 2️⃣ Dile al LLM que `use context7`\n- 3️⃣ Obtén respuestas de código que funcionan\n  Sin cambiar de pestaña, sin APIs inventadas que no existen, sin generaciones de código desactualizadas.\n\n## 🛠️ Empezando\n\n### Requisitos\n\n- Node.js >= v18.0.0\n- Cursor, Windsurf, Claude Desktop u otro Cliente MCP\n\n### Instalando vía Smithery\n\nPara instalar Context7 MCP Server para Claude Desktop automáticamente vía [Smithery](https://smithery.ai/server/@upstash/context7-mcp):\n\n```bash\nnpx -y @smithery/cli install @upstash/context7-mcp --client claude\n```\n\n### Instalar en Cursor\n\nVe a: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\nPegar la siguiente configuración en tu archivo `~/.cursor/mcp.json` de Cursor es el metodo recomendado. Consulta la [documentación de MCP de Cursor](https://docs.cursor.com/context/model-context-protocol) para más información.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n<details>\n<summary>Alternativa: Usar Bun</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Alternativa: Usar Deno</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n### Instalar en Windsurf\nAñade esto a tu archivo de configuración MCP de Windsurf. Consulta la [documentación de MCP de Windsurf](https://docs.windsurf.com/windsurf/mcp) para más información.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Instalar en VS Code\n[<img alt=\"Instalar en VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Instalar%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522context7%2522%252C%2522config%2522%253A%257B%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522%2540upstash%252Fcontext7-mcp%2540latest%2522%255D%257D%257D)\n[<img alt=\"Instalar en VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Instalar%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522context7%2522%252C%2522config%2522%253A%257B%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522%2540upstash%252Fcontext7-mcp%2540latest%2522%255D%257D%257D)\nAñade esto a tu archivo de configuración MCP de VS Code. Consulta la [documentación de VS Code MCP](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) para más información.\n```json\n{\n  \"servers\": {\n    \"Context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Instalar en Claude Code\nEjecuta este comando. Consulta la [documentación de MCP de Claude Code](https://docs.anthropic.com/es/docs/claude-code/mcp) para más información.\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp@latest\n```\n\n### Instalar en Claude Desktop\nAñade esto a tu archivo `claude_desktop_config.json` de Claude Desktop. Consulta la [documentación de MCP de Claude Desktop](https://modelcontextprotocol.io/quickstart/user) para más información.\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Instalar en Copilot Coding Agent\nAgrega la siguiente configuración a la sección `mcp` de tu archivo de configuración de Copilot Coding Agent (Repository->Settings->Copilot->Coding agent->MCP configuration):\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nPara más información, consulta la [documentación oficial de GitHub](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n\n### Instalar en Copilot CLI\n1.  Abre el archivo de configuración MCP de Copilot CLI. La ubicación es `~/.copilot/mcp-config.json` (donde `~` es tu directorio home).\n2.  Agrega lo siguiente al objeto `mcpServers` en tu archivo `mcp-config.json`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nO, para un servidor local:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nSi el archivo `mcp-config.json` no existe, créalo.\n\n### Herramientas Disponibles\n- `resolve-library-id`: Resuelve un nombre de una biblioteca general en un ID de biblioteca compatible con Context7.\n  - `query` (requerido): La pregunta o tarea del usuario (para ranking de relevancia)\n  - `libraryName` (requerido): El nombre de la biblioteca a buscar\n- `query-docs`: Obtiene documentación para una biblioteca utilizando un ID de biblioteca compatible con Context7.\n  - `libraryId` (requerido): ID exacto compatible con Context7 (por ejemplo, `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (requerido): La pregunta o tarea para obtener documentación relevante\n\n## Desarrollo\nClona el proyecto e instala las dependencias:\n```bash\npnpm i\n```\nCompila:\n```bash\npnpm run build\n```\n\n### Ejemplo de Configuración Local\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/ruta/a/la/carpeta/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n\n### Probando con MCP Inspector\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp@latest\n```\n\n## Solución de Problemas\n\n### ERR_MODULE_NOT_FOUND\nSi ves este error, intenta usar `bunx` en lugar de `npx`.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\nEsto a menudo resuelve problemas de resolución de módulos, especialmente en entornos donde `npx` no instala o resuelve paquetes correctamente.\n\n### Errores del Cliente MCP\n1. Intenta eliminar `@latest` del nombre del paquete.\n2. Intenta usar `bunx` como alternativa.\n3. Intenta usar `deno` como alternativa.\n\n## Context7 en los Medios\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income stream surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income stream surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n\n## Historial de Estrellas\n[![Gráfico de Historial de Estrellas](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## Licencia\nMIT\n"
  },
  {
    "path": "i18n/README.fr.md",
    "content": "# Context7 MCP - Documentation à jour pour vos prompts\n\n[![Site Web](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![badge smithery](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Installer dans VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Installer%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n\n## ❌ Sans Context7\n\nLes LLMs s’appuient sur des informations obsolètes ou génériques concernant les bibliothèques que vous utilisez. Vous obtenez :\n\n- ❌ Des exemples de code obsolètes, basés sur des données d’entraînement vieilles d’un an\n- ❌ Des APIs inventées qui n’existent même pas\n- ❌ Des réponses génériques pour d’anciennes versions de packages\n\n## ✅ Avec Context7\n\nContext7 MCP récupère la documentation et les exemples de code à jour, spécifiques à la version, directement à la source — et les place dans votre prompt.\nAjoutez `use context7` à votre prompt dans Cursor :\n\n```txt\nCrée un projet Next.js basique avec app router. use context7\n```\n\n```txt\nCrée un script pour supprimer les lignes où la ville est \"\" avec des identifiants PostgreSQL. use context7\n```\n\nContext7 apporte des exemples de code et de la documentation à jour directement dans le contexte de votre LLM.\n\n- 1️⃣ Rédigez votre prompt naturellement\n- 2️⃣ Dites au LLM `use context7`\n- 3️⃣ Obtenez des réponses de code qui fonctionnent\n  Plus besoin de changer d’onglet, plus d’APIs inventées, plus de code obsolète.\n\n## 🛠️ Démarrage\n\n### Prérequis\n\n- Node.js >= v18.0.0\n- Cursor, Windsurf, Claude Desktop ou un autre client MCP\n\n### Installation via Smithery\n\nPour installer Context7 MCP Server pour Claude Desktop automatiquement via [Smithery](https://smithery.ai/server/@upstash/context7-mcp) :\n\n```bash\nnpx -y @smithery/cli install @upstash/context7-mcp --client claude\n```\n\n### Installation dans Cursor\n\nAllez dans : `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\nLa méthode recommandée est de coller la configuration suivante dans votre fichier `~/.cursor/mcp.json`. Voir la [documentation Cursor MCP](https://docs.cursor.com/context/model-context-protocol) pour plus d’informations.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n<details>\n<summary>Alternative : Utiliser Bun</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Alternative : Utiliser Deno</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n### Installation dans Windsurf\nAjoutez ceci à votre fichier de configuration MCP Windsurf. Voir la [documentation Windsurf MCP](https://docs.windsurf.com/windsurf/mcp) pour plus d’informations.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installation dans VS Code\n[<img alt=\"Installer dans VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Installer%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Installer dans VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Installer%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nAjoutez ceci à votre fichier de configuration MCP VS Code. Voir la [documentation VS Code MCP](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) pour plus d'informations.\n```json\n{\n  \"servers\": {\n    \"Context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installation dans Zed\nPeut être installé via [Zed Extensions](https://zed.dev/extensions?query=Context7) ou en ajoutant ceci à votre `settings.json` Zed. Voir la [documentation Zed Context Server](https://zed.dev/docs/assistant/context-servers).\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n### Installation dans Claude Code\nExécutez cette commande. Voir la [documentation Claude Code MCP](https://docs.anthropic.com/fr/docs/claude-code/mcp).\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp@latest\n```\n\n### Installation dans Claude Desktop\nAjoutez ceci à votre fichier `claude_desktop_config.json`. Voir la [documentation Claude Desktop MCP](https://modelcontextprotocol.io/quickstart/user).\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installation dans BoltAI\nOuvrez la page \"Settings\" de l'application, naviguez jusqu'à \"Plugins\", et entrez le JSON suivant :\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\nUne fois enregistré, saisissez dans le chat `query-docs` suivi de votre ID de documentation Context7 (par exemple, `query-docs /nuxt/ui`). Plus d'informations sont disponibles sur le [site de documentation BoltAI](https://docs.boltai.com/docs/plugins/mcp-servers). Pour BoltAI sur iOS, [consultez ce guide](https://docs.boltai.com/docs/boltai-mobile/mcp-servers).\n\n### Installation dans Copilot Coding Agent\nAjoutez la configuration suivante à la section `mcp` de votre fichier de configuration Copilot Coding Agent (Repository->Settings->Copilot->Coding agent->MCP configuration) :\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nPour plus d'informations, consultez la [documentation officielle GitHub](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n\n### Installation dans Copilot CLI\n1.  Ouvrez le fichier de configuration MCP de Copilot CLI. L'emplacement est `~/.copilot/mcp-config.json` (où `~` est votre répertoire personnel).\n2.  Ajoutez ce qui suit à l'objet `mcpServers` dans votre fichier `mcp-config.json` :\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nOu, pour un serveur local :\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nSi le fichier `mcp-config.json` n'existe pas, créez-le.\n\n### Utilisation avec Docker\nSi vous préférez exécuter le serveur MCP dans un conteneur Docker :\n1.  **Construisez l’image Docker :**\n    Créez un `Dockerfile` à la racine du projet (ou ailleurs) :\n    <details>\n    <summary>Voir le contenu du Dockerfile</summary>\n\n    ```Dockerfile\n    FROM node:18-alpine\n    WORKDIR /app\n    # Installer la dernière version en global\n    RUN npm install -g @upstash/context7-mcp@latest\n    # Exposer le port par défaut si besoin (optionnel)\n    # EXPOSE 3000\n    # Commande par défaut\n    CMD [\"context7-mcp\"]\n    ```\n    </details>\n\n    Puis, construisez l’image :\n    ```bash\n    docker build -t context7-mcp .\n    ```\n2.  **Configurez votre client MCP :**\n    Mettez à jour la configuration de votre client MCP pour utiliser la commande Docker.\n    _Exemple pour un fichier cline_mcp_settings.json :_\n    ```json\n    {\n      \"mcpServers\": {\n        \"Сontext7\": {\n          \"autoApprove\": [],\n          \"disabled\": false,\n          \"timeout\": 60,\n          \"command\": \"docker\",\n          \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n          \"transportType\": \"stdio\"\n        }\n      }\n    }\n    ```\n    _Note : Ceci est un exemple. Adaptez la structure selon votre client MCP (voir plus haut dans ce README). Assurez-vous que le nom de l’image dans `args` correspond au tag utilisé lors du build._\n\n### Installation sous Windows\nLa configuration sous Windows est légèrement différente par rapport à Linux ou macOS (_`Cline` est utilisé dans l'exemple_). Le même principe s'applique à d'autres éditeurs; référez-vous à la configuration de `command` et `args`.\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp@latest\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n\n### Outils disponibles\n- `resolve-library-id` : Résout un nom de bibliothèque général en un ID compatible Context7.\n  - `libraryName` (obligatoire)\n- `query-docs` : Récupère la documentation d’une bibliothèque via un ID Context7.\n  - `libraryId` (obligatoire)\n\n## Développement\nClonez le projet et installez les dépendances :\n```bash\npnpm i\n```\nBuild :\n```bash\npnpm run build\n```\n\n### Exemple de configuration locale\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n\n### Tester avec MCP Inspector\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp@latest\n```\n\n## Dépannage\n\n### ERR_MODULE_NOT_FOUND\nSi vous voyez cette erreur, essayez d’utiliser `bunx` à la place de `npx`.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\nCela résout souvent les problèmes de résolution de modules, surtout si `npx` n’installe ou ne résout pas correctement les packages.\n\n### Problèmes de résolution ESM\nSi vous rencontrez une erreur comme : `Error: Cannot find module 'uriTemplate.js'` essayez d'exécuter avec le drapeau `--experimental-vm-modules` :\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n\n### Erreurs client MCP\n1. Essayez de retirer `@latest` du nom du package.\n2. Essayez d'utiliser `bunx` comme alternative.\n3. Essayez d'utiliser `deno` comme alternative.\n4. Assurez-vous d'utiliser Node v18 ou supérieur pour avoir le support natif de fetch avec `npx`.\n\n## Clause de non-responsabilité\nLes projets Context7 sont des contributions de la communauté, et bien que nous nous efforcions de maintenir une haute qualité, nous ne pouvons garantir l'exactitude, l'exhaustivité ou la sécurité de toute la documentation des bibliothèques. Les projets listés dans Context7 sont développés et maintenus par leurs propriétaires respectifs, et non par Context7. Si vous rencontrez un contenu suspect, inapproprié ou potentiellement nuisible, veuillez utiliser le bouton \"Signaler\" sur la page du projet pour nous le faire savoir immédiatement. Nous prenons tous les signalements au sérieux et examinerons rapidement les contenus signalés pour maintenir l'intégrité et la sécurité de notre plateforme. En utilisant Context7, vous reconnaissez que vous le faites à votre propre discrétion et à vos risques et périls.\n\n## Context7 dans les médias\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income stream surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income stream surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## Historique des stars\n[![Graphique d'historique des stars](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## Licence\nMIT\n"
  },
  {
    "path": "i18n/README.id-ID.md",
    "content": "# Context7 MCP - Dokumentasi Kode Terkini Untuk Setiap Permintaan\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[![English](https://img.shields.io/badge/docs-English-blue)](../README.md) [![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./README.zh-TW.md) [![简体中文](https://img.shields.io/badge/docs-简体中文-yellow)](./README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./README.uk.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./README.ar.md)\n\n## ❌ Tanpa Context7\n\nLLM bergantung pada informasi yang sudah usang atau generik tentang pustaka yang Anda gunakan. Anda mendapatkan:\n\n- ❌ Contoh kode yang sudah usang dan berdasarkan data pelatihan dari tahun lalu\n- ❌ API yang diimajinasikan tidak pernah ada\n- ❌ Jawaban generik untuk versi paket yang lama\n\n## ✅ Dengan Context7\n\nContext7 MCP mengambil dokumentasi dan contoh kode terkini yang spesifik versi langsung dari sumbernya — dan menempatkannya langsung ke dalam prompt Anda.\nTambahkan `use context7` ke prompt Anda di Cursor:\n\n```txt\nBuat middleware Next.js yang memeriksa JWT valid di cookie dan mengarahkan pengguna yang tidak terautentikasi ke `/login`. use context7\n```\n\n```txt\nKonfigurasikan skrip Cloudflare Worker untuk menyimpan respons API JSON selama lima menit. use context7\n```\n\nContext7 mengambil contoh kode dan dokumentasi terkini langsung ke konteks LLM.\n\n- 1️⃣ Tulis permintaan Anda secara alami\n- 2️⃣ Beri tahu LLM untuk `use context7`\n- 3️⃣ Dapatkan jawaban kode yang berfungsi\n  Tidak perlu berpindah tab, tidak ada API yang diimajinasikan yang tidak ada, tidak ada hasil kode usang.\n\n## 📚 Menambahkan Proyek\n\nKunjungi [panduan penambahan proyek](https://context7.com/docs/adding-libraries) untuk mempelajari cara menambahkan (atau memperbarui) pustaka favorit Anda ke Context7.\n\n## 🛠️ Instalasi\n\n### Persyaratan\n\n- Node.js >= v18.0.0\n- Cursor, Windsurf, Claude Desktop, atau klien MCP lainnya\n<details>\n<summary><b>Menginstal melalui Smithery</b></summary>\n\nUntuk menginstal Context7 MCP Server untuk klien apa pun secara otomatis melalui [Smithery](https://smithery.ai/server/@upstash/context7-mcp):\n\n```bash\nnpx -y @smithery/cli@latest install @upstash/context7-mcp --client <NAMA_KLIEN> --key <KUNCI_SMITHERY_ANDA>\n```\n\nAnda dapat menemukan kunci Smithery Anda di [halaman web Smithery.ai](https://smithery.ai/server/@upstash/context7-mcp).\n\n</details>\n\n<details>\n<summary><b>Instal di Cursor</b></summary>\n\nPergi ke: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\nMenyalin konfigurasi berikut ke file `~/.cursor/mcp.json` Anda adalah pendekatan yang direkomendasikan. Anda juga dapat menginstalnya di proyek tertentu dengan membuat `.cursor/mcp.json` di folder proyek Anda. Lihat [dokumentasi Cursor MCP](https://docs.cursor.com/context/model-context-protocol) untuk info lebih lanjut.\n> Sejak Cursor 1.0, Anda dapat mengklik tombol instal di bawah untuk instalasi satu klik instan.\n\n#### Koneksi Server Remote Cursor\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Koneksi Server Lokal Cursor\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n<details>\n<summary>Alternatif: Gunakan Bun</summary>\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoiYnVueCAteSBAdXBzdGFzaC9jb250ZXh0Ny1tY3AifQ%3D%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Alternatif: Gunakan Deno</summary>\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoiZGVubyBydW4gLS1hbGxvdy1lbnYgLS1hbGxvdy1uZXQgbnBtOkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-env=NO_DEPRECATION,TRACE_DEPRECATION\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n</details>\n\n<details>\n<summary><b>Instal di Windsurf</b></summary>\n\nTambahkan ini ke file konfigurasi MCP Windsurf Anda. Lihat [dokumentasi MCP Windsurf](https://docs.windsurf.com/windsurf/mcp) untuk info lebih lanjut.\n\n#### Koneksi Server Remote Windsurf\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Koneksi Server Lokal Windsurf\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di Trae</b></summary>\n\nGunakan fitur Tambah secara manual dan isi informasi konfigurasi JSON untuk server MCP tersebut.\nUntuk detail lebih lanjut, kunjungi [dokumentasi Trae](https://docs.trae.ai/ide/model-context-protocol?_lang=en).\n\n#### Koneksi Server Remote Trae\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Koneksi Server Lokal Trae\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di VS Code</b></summary>\n\n[<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Install in VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nTambahkan ini ke file konfigurasi MCP VS Code Anda. Lihat [dokumentasi MCP VS Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) untuk info lebih lanjut.\n\n#### Koneksi Server Remote VS Code\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Koneksi Server Lokal VS Code\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di Visual Studio 2022</b></summary>\n\nAnda dapat mengonfigurasi Context7 MCP di Visual Studio 2022 dengan mengikuti [dokumentasi Server MCP Visual Studio](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\nTambahkan ini ke file konfigurasi MCP Visual Studio Anda (lihat [dokumentasi Visual Studio](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022) untuk detailnya):\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"http\",\n        \"url\": \"https://mcp.context7.com/mcp\"\n      }\n    }\n  }\n}\n```\nAtau, untuk server lokal:\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"stdio\",\n        \"command\": \"npx\",\n        \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n      }\n    }\n  }\n}\n```\nUntuk informasi dan pemecahan masalah lebih lanjut, lihat [dokumentasi Server MCP Visual Studio](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\n</details>\n\n<details>\n<summary><b>Instal di Zed</b></summary>\n\nDapat diinstal melalui [Ekstensi Zed](https://zed.dev/extensions?query=Context7) atau Anda dapat menambahkan ini ke `settings.json` Zed Anda. Lihat [dokumentasi Server Konteks Zed](https://zed.dev/docs/assistant/context-servers) untuk info lebih lanjut.\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di Gemini CLI</b></summary>\n\nLihat [Konfigurasi Gemini CLI](https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/configuration.md) untuk detailnya.\n1.  Buka file pengaturan Gemini CLI. Lokasinya adalah `~/.gemini/settings.json` (di mana `~` adalah direktori home Anda).\n2.  Tambahkan berikut ini ke objek `mcpServers` di file `settings.json` Anda:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"httpUrl\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\nAtau, untuk server lokal:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nJika objek `mcpServers` tidak ada, buatlah.\n</details>\n\n<details>\n<summary><b>Instal di Claude Code</b></summary>\n\nJalankan perintah ini. Lihat [dokumentasi MCP Claude Code](https://docs.anthropic.com/id/docs/claude-code/mcp) untuk info lebih lanjut.\n\n#### Koneksi Server Lokal Claude Code\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp\n```\n\n#### Koneksi Server Remote Claude Code\n\n```sh\nclaude mcp add --scope user --transport http context7 https://mcp.context7.com/mcp\n```\n</details>\n\n<details>\n<summary><b>Instal di Claude Desktop</b></summary>\n\nTambahkan ini ke file `claude_desktop_config.json` Claude Desktop Anda. Lihat [dokumentasi MCP Claude Desktop](https://modelcontextprotocol.io/quickstart/user) untuk info lebih lanjut.\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>\n<b>Instal di Cline</b>\n</summary>\n\nAnda dapat dengan mudah menginstal Context7 melalui [Pasar Server MCP Cline](https://cline.bot/mcp-marketplace) dengan mengikuti petunjuk berikut:\n1. Buka **Cline**.\n2. Klik ikon menu hamburger (☰) untuk masuk ke bagian **Server MCP**.\n3. Gunakan bilah pencarian di tab **Marketplace** untuk menemukan *Context7*.\n4. Klik tombol **Instal**.\n</details>\n\n<details>\n<summary><b>Instal di BoltAI</b></summary>\n\nBuka halaman \"Pengaturan\" aplikasi, navigasikan ke \"Plugin,\" dan masukkan JSON berikut:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nSetelah disimpan, masukkan di obrolan `query-docs` diikuti oleh ID dokumentasi Context7 Anda (contoh: `query-docs /nuxt/ui`). Informasi lebih lanjut tersedia di [situs dokumentasi BoltAI](https://docs.boltai.com/docs/plugins/mcp-servers). Untuk BoltAI di iOS, [lihat panduan ini](https://docs.boltai.com/docs/boltai-mobile/mcp-servers).\n</details>\n\n<details>\n<summary><b>Menggunakan Docker</b></summary>\n\nJika Anda lebih suka menjalankan server MCP dalam wadah Docker:\n1. **Bangun Gambar Docker:**\n   Pertama, buat `Dockerfile` di direktori utama proyek (atau di mana pun Anda inginkan):\n   <details>\n   <summary>Klik untuk melihat isi Dockerfile</summary>\n\n   ```Dockerfile\n   FROM node:18-alpine\n   WORKDIR /app\n   # Instal versi terbaru secara global\n   RUN npm install -g @upstash/context7-mcp\n   # Ekspor port default jika diperlukan (opsional, tergantung pada interaksi klien MCP)\n   # EXPOSE 3000\n   # Perintah default untuk menjalankan server\n   CMD [\"context7-mcp\"]\n   ```\n   </details>\n\n   Kemudian, bangun gambar menggunakan tag (contoh: `context7-mcp`). **Pastikan Docker Desktop (atau daemon Docker) berjalan.** Jalankan perintah berikut di direktori yang sama tempat Anda menyimpan `Dockerfile`:\n   ```bash\n   docker build -t context7-mcp .\n   ```\n2. **Konfigurasikan Klien MCP Anda:**\n   Perbarui konfigurasi klien MCP Anda untuk menggunakan perintah Docker.\n   _Contoh untuk cline_mcp_settings.json:_\n   ```json\n   {\n     \"mcpServers\": {\n       \"Сontext7\": {\n         \"autoApprove\": [],\n         \"disabled\": false,\n         \"timeout\": 60,\n         \"command\": \"docker\",\n         \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n         \"transportType\": \"stdio\"\n       }\n     }\n   }\n   ```\n   _Catatan: Ini adalah contoh konfigurasi. Silakan merujuk ke contoh spesifik untuk klien MCP Anda (seperti Cursor, VS Code, dll.) sebelumnya di README ini untuk menyesuaikan struktur (misalnya, `mcpServers` vs `servers`). Juga, pastikan nama gambar di `args` sesuai dengan tag yang digunakan saat perintah `docker build`._\n</details>\n\n<details>\n<summary><b>Instal di Windows</b></summary>\n\nKonfigurasi di Windows sedikit berbeda dibandingkan Linux atau macOS (_`Cline` digunakan sebagai contoh_). Prinsip yang sama berlaku untuk editor lainnya; lihat konfigurasi `command` dan `args`.\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp@latest\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di Augment Code</b></summary>\n\nUntuk mengonfigurasi Context7 MCP di Augment Code, Anda dapat menggunakan antarmuka grafis atau konfigurasi manual.\n\n### **A. Menggunakan UI Augment Code**\n1. Klik menu hamburger.\n2. Pilih **Pengaturan**.\n3. Navigasikan ke bagian **Alat**.\n4. Klik tombol **+ Tambah MCP**.\n5. Masukkan perintah berikut:\n   ```\n   npx -y @upstash/context7-mcp@latest\n   ```\n6. Beri nama MCP: **Context7**.\n7. Klik tombol **Tambah**.\n   Setelah server MCP ditambahkan, Anda dapat mulai menggunakan fitur dokumentasi kode terkini Context7 langsung di Augment Code.\n---\n\n### **B. Konfigurasi Manual**\n1. Tekan Cmd/Ctrl Shift P atau pergi ke menu hamburger di panel Augment\n2. Pilih Edit Pengaturan\n3. Di bawah Lanjutan, klik Edit di settings.json\n4. Tambahkan konfigurasi server ke array `mcpServers` di objek `augment.advanced`\n```json\n\"augment.advanced\": {\n  \"mcpServers\": [\n    {\n      \"name\": \"context7\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  ]\n}\n```\nSetelah server MCP ditambahkan, restart editor Anda. Jika Anda menerima kesalahan, periksa sintaks untuk memastikan tanda kurung atau koma penutup tidak hilang.\n</details>\n\n<details>\n<summary><b>Instal di Roo Code</b></summary>\n\nTambahkan ini ke file konfigurasi MCP Roo Code Anda. Lihat [dokumentasi MCP Roo Code](https://docs.roocode.com/features/mcp/using-mcp-in-roo) untuk info lebih lanjut.\n\n#### Koneksi Server Remote Roo Code\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Koneksi Server Lokal Roo Code\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di Zencoder</b></summary>\n\nUntuk mengonfigurasi Context7 MCP di Zencoder, ikuti langkah-langkah berikut:\n1. Pergi ke menu Zencoder (...)\n2. Dari menu dropdown, pilih Alat Agen\n3. Klik Tambah MCP Kustom\n4. Tambahkan nama dan konfigurasi server dari bawah, dan pastikan untuk menekan tombol Instal\n```json\n{\n    \"command\": \"npx\",\n    \"args\": [\n        \"-y\",\n        \"@upstash/context7-mcp@latest\"\n    ]\n}\n```\nSetelah server MCP ditambahkan, Anda dapat dengan mudah terus menggunakannya.\n</details>\n\n<details>\n<summary><b>Instal di Amazon Q Developer CLI</b></summary>\n\nTambahkan ini ke file konfigurasi Amazon Q Developer CLI Anda. Lihat [dokumentasi Amazon Q Developer CLI](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html) untuk detail lebih lanjut.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di Qodo Gen</b></summary>\n\nLihat [dokumentasi Qodo Gen](https://docs.qodo.ai/qodo-documentation/qodo-gen/qodo-gen-chat/agentic-mode/agentic-tools-mcps) untuk detail lebih lanjut.\n1. Buka panel obrolan Qodo Gen di VSCode atau IntelliJ.\n2. Klik Hubungkan lebih banyak alat.\n3. Klik + Tambah MCP baru.\n4. Tambahkan konfigurasi berikut:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di JetBrains AI Assistant</b></summary>\n\nLihat [Dokumentasi JetBrains AI Assistant](https://www.jetbrains.com/help/ai-assistant/configure-an-mcp-server.html) untuk detail lebih lanjut.\n1. Di IDE JetBrains pergi ke `Pengaturan` -> `Alat` -> `Asisten AI` -> `Protokol Konteks Model (MCP)`\n2. Klik `+ Tambah`.\n3. Klik pada `Perintah` di pojok kiri atas dialog dan pilih opsi Sebagai JSON dari daftar\n4. Tambahkan konfigurasi ini dan klik `OK`\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n5. Klik `Terapkan` untuk menyimpan perubahan.\n6. Dengan cara yang sama context7 dapat ditambahkan untuk JetBrains Junie di `Pengaturan` -> `Alat` -> `Junie` -> `Pengaturan MCP`\n</details>\n\n<details>\n<summary><b>Instal di Warp</b></summary>\n\nLihat [Dokumentasi Protokol Konteks Model Warp](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server) untuk detail.\n1. Navigasikan `Pengaturan` > `AI` > `Kelola server MCP`.\n2. Tambahkan server MCP baru dengan mengklik tombol `+ Tambah`.\n3. Tempel konfigurasi yang diberikan di bawah:\n```json\n{\n  \"Context7\": {\n    \"command\": \"npx\",\n    \"args\": [\n      \"-y\",\n      \"@upstash/context7-mcp\"\n    ],\n    \"env\": {},\n    \"working_directory\": null,\n    \"start_on_launch\": true\n  }\n}\n```\n4. Klik `Simpan` untuk menerapkan perubahan.\n</details>\n\n<details>\n<summary><b>Instal di Opencode</b></summary>\n\nTambahkan ini ke file konfigurasi Opencode Anda. Lihat [dokumentasi MCP Opencode](https://opencode.ai/docs/mcp-servers) untuk info lebih lanjut.\n\n#### Koneksi Server Remote Opencode\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"enabled\": true\n  }\n}\n```\n\n#### Koneksi Server Lokal Opencode\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instal di Copilot Coding Agent</b></summary>\n\n## Menggunakan Context7 dengan Copilot Coding Agent\nTambahkan konfigurasi berikut ke bagian `mcp` file konfigurasi Copilot Coding Agent Anda Repositori->Pengaturan->Copilot->Coding agent->Konfigurasi MCP:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\n        \"query-docs\",\n        \"resolve-library-id\"\n      ]\n    }\n  }\n}\n```\nUntuk informasi lebih lanjut, lihat [dokumentasi resmi GitHub](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n</details>\n\n<details>\n<summary><b>Instal di Copilot CLI</b></summary>\n\n1.  Buka file konfigurasi MCP Copilot CLI. Lokasinya adalah `~/.copilot/mcp-config.json` (di mana `~` adalah direktori home Anda).\n2.  Tambahkan yang berikut ke objek `mcpServers` di file `mcp-config.json` Anda:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nAtau, untuk server lokal:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nJika file `mcp-config.json` tidak ada, buatlah.\n</details>\n\n<details>\n<summary><b>Instal di Kiro</b></summary>\n\nLihat [Dokumentasi Protokol Konteks Model Kiro](https://kiro.dev/docs/mcp/configuration/) untuk detail.\n1. Navigasikan `Kiro` > `Server MCP`\n2. Tambahkan server MCP baru dengan mengklik tombol `+ Tambah`.\n3. Tempel konfigurasi yang diberikan di bawah:\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n    \"command\": \"npx\",\n    \"args\": [\n      \"-y\",\n      \"@upstash/context7-mcp\"\n    ],\n    \"env\": {},\n    \"disabled\": false,\n    \"autoApprove\": []\n    }\n  }\n}\n```\n4. Klik `Simpan` untuk menerapkan perubahan.\n</details>\n\n<details>\n<summary><b>Instal di OpenAI Codex</b></summary>\n\nLihat [OpenAI Codex](https://github.com/openai/codex) untuk informasi lebih lanjut.\nTambahkan konfigurasi berikut ke pengaturan server MCP OpenAI Codex Anda:\n\n#### Koneksi Server Lokal\n\n```toml\n[mcp_servers.context7]\nargs = [\"-y\", \"@upstash/context7-mcp\"]\ncommand = \"npx\"\n```\n\n#### Koneksi Server Jarak Jauh\n\n```toml\n[mcp_servers.context7]\nurl = \"https://mcp.context7.com/mcp\"\nhttp_headers = { \"CONTEXT7_API_KEY\" = \"YOUR_API_KEY\" }\n```\n</details>\n\n<details>\n<summary><b>Instal di LM Studio</b></summary>\n\nLihat [Dukungan MCP LM Studio](https://lmstudio.ai/blog/lmstudio-v0.3.17) untuk informasi lebih lanjut.\n\n#### Instal satu klik:\n[![Add MCP Server context7 to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJdfQ%3D%3D)\n\n#### Pengaturan manual:\n1. Navigasikan ke `Program` (sisi kanan) > `Instal` > `Edit mcp.json`.\n2. Tempel konfigurasi yang diberikan di bawah:\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n3. Klik `Simpan` untuk menerapkan perubahan.\n4. Aktifkan/nonaktifkan server MCP dari sisi kanan, di bawah `Program`, atau dengan mengklik ikon colokan di bagian bawah kotak obrolan.\n</details>\n\n## 🔨 Alat yang Tersedia\nContext7 MCP menyediakan alat berikut yang dapat digunakan oleh LLM:\n- `resolve-library-id`: Mengubah nama pustaka umum menjadi ID pustaka yang kompatibel dengan Context7.\n  - `query` (wajib): Pertanyaan atau tugas pengguna (untuk peringkat relevansi)\n  - `libraryName` (wajib): Nama pustaka yang ingin dicari\n- `query-docs`: Mengambil dokumentasi untuk pustaka menggunakan ID pustaka yang kompatibel dengan Context7.\n  - `libraryId` (wajib): ID pustaka yang kompatibel dengan Context7 (contoh: `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (wajib): Pertanyaan atau tugas untuk mendapatkan dokumentasi yang relevan\n\n## 🛟 Tips\n\n### Tambahkan Aturan\n> Jika Anda tidak ingin menambahkan `use context7` ke setiap permintaan, Anda dapat menentukan aturan sederhana di file `.windsurfrules` Anda di Windsurf atau dari bagian `Cursor Settings > Rules` di Cursor (atau yang setara di klien MCP Anda) untuk memanggil Context7 secara otomatis pada setiap pertanyaan kode:\n>\n> ```toml\n> [[calls]]\n> match = \"when the user requests code examples, setup or configuration steps, or library/API documentation\"\n> tool  = \"context7\"\n> ```\n>\n> Mulai saat itu, Anda akan mendapatkan dokumen Context7 dalam setiap percakapan terkait tanpa mengetik sesuatu tambahan. Anda dapat menambahkan kasus penggunaan Anda ke bagian match.\n\n### Gunakan ID Pustaka\n> Jika Anda sudah tahu persis pustaka mana yang ingin digunakan, tambahkan ID Context7-nya ke permintaan Anda. Dengan begitu, server MCP Context7 dapat melewati langkah pencocokan pustaka dan langsung mengambil dokumen.\n>\n> ```txt\n> implementasikan otentikasi dasar dengan supabase. gunakan pustaka /supabase/supabase untuk api dan docs\n> ```\n>\n> Sintaks garis miring memberi tahu alat MCP pustaka mana yang harus dimuat dokumennya.\n\n## 💻 Pengembangan\nSalin proyek dan instal dependensi:\n```bash\npnpm i\n```\nBangun:\n```bash\npnpm run build\n```\nJalankan server:\n```bash\nnode packages/mcp/dist/index.js\n```\n\n### Argumen CLI\n`context7-mcp` menerima bendera CLI berikut:\n- `--transport <stdio|http>` – Transportasi yang digunakan (`stdio` secara default).\n- `--port <number>` – Port yang didengarkan saat menggunakan transport `http` (default `3000`).\n  Contoh dengan transport http dan port 8080:\n```bash\nnode packages/mcp/dist/index.js --transport http --port 8080\n```\n<details>\n<summary><b>Contoh Konfigurasi Lokal</b></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Pengujian dengan MCP Inspector</b></summary>\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n</details>\n\n## 🚨 Pemecahan Masalah\n<details>\n<summary><b>Kesalahan Modul Tidak Ditemukan</b></summary>\n\nJika Anda mengalami `ERR_MODULE_NOT_FOUND`, coba gunakan `bunx` alih-alih `npx`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nIni sering menyelesaikan masalah penyelesaian modul di lingkungan di mana `npx` tidak menginstal atau menyelesaikan paket dengan benar.\n</details>\n\n<details>\n<summary><b>Masalah Resolusi ESM</b></summary>\n\nUntuk kesalahan seperti `Error: Cannot find module 'uriTemplate.js'`, coba gunakan bendera `--experimental-vm-modules`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Masalah TLS/Sertifikat</b></summary>\n\nGunakan bendera `--experimental-fetch` untuk melewati masalah terkait TLS:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-fetch\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Kesalahan Umum Klien MCP</b></summary>\n\n1. Coba tambahkan `@latest` ke nama paket\n2. Gunakan `bunx` sebagai alternatif `npx`\n3. Pertimbangkan menggunakan `deno` sebagai alternatif lain\n4. Pastikan Anda menggunakan Node.js v18 atau lebih tinggi untuk dukungan fetch native\n</details>\n\n## ⚠️ Penafian\nProyek Context7 dikontribusikan oleh komunitas dan meskipun kami berusaha menjaga kualitas tinggi, kami tidak dapat menjamin keakuratan, kelengkapan, atau keamanan semua dokumentasi pustaka. Proyek yang terdaftar di Context7 dikembangkan dan dikelola oleh pemilik masing-masing, bukan oleh Context7. Jika Anda menemukan konten yang mencurigakan, tidak pantas, atau berpotensi membahayakan, gunakan tombol \"Laporkan\" di halaman proyek untuk segera memberi tahu kami. Kami memperlakukan semua laporan dengan serius dan akan segera meninjau konten yang dilaporkan untuk menjaga integritas dan keamanan platform kami. Dengan menggunakan Context7, Anda mengakui bahwa Anda melakukannya atas kebijaksanaan dan risiko Anda sendiri.\n\n## 🤝 Terhubung dengan Kami\nTetap terbaru dan bergabunglah dengan komunitas kami:\n- 📢 Ikuti kami di [X](https://x.com/context7ai) untuk berita dan pembaruan terbaru\n- 🌐 Kunjungi [Situs Web](https://context7.com) kami\n- 💬 Bergabunglah dengan [Komunitas Discord](https://upstash.com/discord) kami\n\n## 📺 Context7 Di Media\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Sejarah Bintang\n[![Star History Chart](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 Lisensi\nMIT\n"
  },
  {
    "path": "i18n/README.it.md",
    "content": "# Context7 MCP - Documentazione aggiornata per qualsiasi prompt\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Installa%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[![中文文档](https://img.shields.io/badge/docs-中文版-yellow)](./README.zh-CN.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md)\n\n## ❌ Senza Context7\n\nLLMs si affidano a informazioni obsolete o generiche sulle librerie che utilizzi. Ottieni:\n\n- ❌ Gli esempi di codice sono obsoleti e basati su dati di formazione vecchi di anni\n- ❌ Le API allucinate non esistono nemmeno\n- ❌ Risposte generiche per vecchie versioni del pacchetto\n\n## ✅ Con Context7\n\nContext7 MCP recupera documentazione aggiornata, specifica per versione e esempi di codice direttamente dalla fonte — e li inserisce direttamente nel tuo prompt.\nAggiungi `use context7` al prompt in Cursor:\n\n```txt\nCrea un progetto Next.js di base con app router. Usa context7\n```\n\n```txt\nCreare uno script per eliminare le righe in cui la città è \"\", date le credenziali di PostgreSQL. usare context7\n```\n\nContext7 recupera esempi di codice e documentazione aggiornati direttamente nel contesto del tuo LLM.\n\n- 1️⃣ Scrivi il tuo prompt in modo naturale\n- 2️⃣ Indica all'LLM di usare context7\n- 3️⃣ Ottieni risposte di codice funzionante\n  Nessun cambio di tab, nessuna API allucinata che non esiste, nessuna generazione di codice obsoleta.\n\n## 🛠️ Iniziare\n\n### Requisiti\n\n- Node.js >= v18.0.0\n- Cursor, Windsurf, Claude Desktop o un altro client MCP\n\n### Installazione tramite Smithery\n\nPer installare Context7 MCP Server per Claude Desktop automaticamente tramite [Smithery](https://smithery.ai/server/@upstash/context7-mcp):\n\n```bash\nnpx -y @smithery/cli install @upstash/context7-mcp --client claude\n```\n\n### Installare in Cursor\n\nVai a: `Impostazioni` -> `Impostazioni cursore` -> `MCP` -> `Aggiungi nuovo server MCP globale`\nIncollare la seguente configurazione nel file `~/.cursor/mcp.json` di Cursor è l'approccio consigliato. Vedi [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol) per ulteriori informazioni.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n<details>\n<summary>Alternativa: Usa Bun</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Alternativa: Usa Deno</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n### Installare in Windsurf\nAggiungi questo al tuo file di configurazione Windsurf MCP. Vedi [Windsurf MCP docs](https://docs.windsurf.com/windsurf/mcp) per ulteriori informazioni.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installare in VS Code\n[<img alt=\"Installa in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Installa%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Installa in VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Installa%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nAggiungi questo al tuo file di configurazione MCP di VS Code. Vedi [VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) per ulteriori informazioni.\n```json\n{\n  \"servers\": {\n    \"Context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installare in Zed\nPuò essere installato tramite [Zed Extensions](https://zed.dev/extensions?query=Context7) oppure puoi aggiungere questo al tuo `settings.json` di Zed. Vedi [Zed Context Server docs](https://zed.dev/docs/assistant/context-servers) per ulteriori informazioni.\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n### Installare in Claude Code\nEsegui questo comando. Vedi [Claude Code MCP docs](https://docs.anthropic.com/it/docs/claude-code/mcp) per ulteriori informazioni.\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp@latest\n```\n\n### Installare in Claude Desktop\nAggiungi questo al tuo file `claude_desktop_config.json` di Claude Desktop. Vedi [Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user) per ulteriori informazioni.\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Installazione in Copilot Coding Agent\nAggiungi la seguente configurazione alla sezione `mcp` del file di configurazione di Copilot Coding Agent (Repository->Settings->Copilot->Coding agent->MCP configuration):\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nPer maggiori informazioni, consulta la [documentazione ufficiale GitHub](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n\n### Installazione in Copilot CLI\n1.  Apri il file di configurazione MCP di Copilot CLI. La posizione è `~/.copilot/mcp-config.json` (dove `~` è la tua home directory).\n2.  Aggiungi quanto segue all'oggetto `mcpServers` nel tuo file `mcp-config.json`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nOppure, per un server locale:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nSe il file `mcp-config.json` non esiste, crealo.\n\n### Utilizzo di Docker\nSe preferisci eseguire il server MCP in un contenitore Docker:\n1.  **Costruisci l'immagine Docker:**\n    Prima, crea un `Dockerfile` nella radice del progetto (o ovunque tu preferisca):\n    <details>\n    <summary>Clicca per visualizzare il contenuto del Dockerfile</summary>\n\n    ```Dockerfile\n    FROM node:18-alpine\n    WORKDIR /app\n    # Installa l ultima versione globalmente\n    RUN npm install -g @upstash/context7-mcp@latest\n    # Esponi la porta predefinita se necessario (opzionale, dipende dall interazione del client MCP)\n    # EXPOSE 3000\n    # Comando predefinito per eseguire il server\n    CMD [\"context7-mcp\"]\n    ```\n    </details>\n\n    Poi, costruisci l'immagine utilizzando un tag (ad esempio, `context7-mcp`). **Assicurati che Docker Desktop (o il demone Docker) sia in esecuzione.** Esegui il seguente comando nella stessa directory in cui hai salvato il `Dockerfile`:\n    ```bash\n    docker build -t context7-mcp .\n    ```\n2.  **Configura il tuo client MCP:**\n    Aggiorna la configurazione del tuo client MCP per utilizzare il comando Docker.\n    _Esempio per un file cline_mcp_settings.json:_\n    ```json\n    {\n      \"mcpServers\": {\n        \"Сontext7\": {\n          \"autoApprove\": [],\n          \"disabled\": false,\n          \"timeout\": 60,\n          \"command\": \"docker\",\n          \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n          \"transportType\": \"stdio\"\n        }\n      }\n    }\n    ```\n    _Nota: Questa è una configurazione di esempio. Consulta gli esempi specifici per il tuo client MCP (come Cursor, VS Code, ecc.) precedentemente in questo README per adattare la struttura (ad es., `mcpServers` vs `servers`). Inoltre, assicurati che il nome dell'immagine in `args` corrisponda al tag utilizzato durante il comando `docker build`._\n\n### Strumenti Disponibili\n- `resolve-library-id`: Converte un nome generico di libreria in un ID di libreria compatibile con Context7.\n  - `query` (obbligatorio): La domanda o il compito dell'utente (per il ranking di rilevanza)\n  - `libraryName` (obbligatorio): Il nome della libreria da cercare\n- `query-docs`: Recupera la documentazione per una libreria utilizzando un ID di libreria compatibile con Context7.\n  - `libraryId` (obbligatorio): ID esatto compatibile con Context7 (ad esempio, `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (obbligatorio): La domanda o il compito per ottenere documentazione pertinente\n\n## Sviluppo\nClona il progetto e installa le dipendenze:\n```bash\npnpm i\n```\nCompila:\n```bash\npnpm run build\n```\n\n### Esempio di Configurazione Locale\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n\n### Test con MCP Inspector\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp@latest\n```\n\n## Risoluzione dei problemi\n\n### ERR_MODULE_NOT_FOUND\nSe vedi questo errore, prova a usare `bunx` invece di `npx`.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\nQuesto spesso risolve i problemi di risoluzione dei moduli, specialmente negli ambienti dove `npx` non installa o risolve correttamente i pacchetti.\n\n### Problemi di risoluzione ESM\nSe riscontri un errore come: `Error: Cannot find module 'uriTemplate.js'` prova a eseguire con il flag `--experimental-vm-modules`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n\n### Errori del Client MCP\n1. Prova a rimuovere `@latest` dal nome del pacchetto.\n2. Prova a usare `bunx` come alternativa.\n3. Prova a usare `deno` come alternativa.\n4. Assicurati di utilizzare Node v18 o superiore per avere il supporto nativo di fetch con `npx`.\n\n## Dichiarazione di non responsabilità\nI progetti Context7 sono contributi della comunità e, sebbene ci impegniamo a mantenere un'alta qualità, non possiamo garantire l'accuratezza, la completezza o la sicurezza di tutta la documentazione delle librerie. I progetti elencati in Context7 sono sviluppati e gestiti dai rispettivi proprietari, non da Context7. Se riscontri contenuti sospetti, inappropriati o potenzialmente dannosi, utilizza il pulsante \"Segnala\" sulla pagina del progetto per informarci immediatamente. Prendiamo sul serio tutte le segnalazioni e esamineremo prontamente i contenuti segnalati per mantenere l'integrità e la sicurezza della nostra piattaforma. Utilizzando Context7, riconosci di farlo a tua discrezione e a tuo rischio.\n\n## Context7 nei Media\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income stream surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income stream surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n\n## Storico delle Stelle\n[![Star History Chart](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## Licenza\nMIT\n"
  },
  {
    "path": "i18n/README.ja.md",
    "content": "# Context7 MCP - どんなプロンプトにも最新のコードドキュメントで応える\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./README.zh-TW.md) [![簡體中文](https://img.shields.io/badge/docs-簡體中文-yellow)](./README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./README.ar.md)\n\n## ❌ Context7 を使わないと\n\nLLM は使用しているライブラリに関する古い情報や一般的な情報に依存しています。その結果：\n\n- ❌ コード例が古く、1 年前のトレーニングデータに基づいている\n- ❌ 存在しない API をハルシネーションして生成する\n- ❌ 古いパッケージバージョンに対する一般的な回答しか得られない\n\n## ✅ Context7 を使うと\n\nContext7 MCP は最新のバージョン固有のドキュメントとコード例をソースから直接取得し、プロンプトに直接配置します。\nCursor のプロンプトに `use context7` を追加するだけ：\n\n```txt\nCreate a basic Next.js project with app router. use context7\n```\n\n```txt\nCreate a script to delete the rows where the city is \"\" given PostgreSQL credentials. use context7\n```\n\nContext7 は最新のコード例とドキュメントを直接 LLM のコンテキストに取得します。\n\n- 1️⃣ 普段通りにプロンプトを書く\n- 2️⃣ LLM に `use context7` と指示する\n- 3️⃣ 動作するコードの回答を得る\n  タブの切り替えも、存在しない API のハルシネーションも、古いコード生成もありません。\n\n## 📚 プロジェクトの追加\n\n[プロジェクト追加ガイド](https://context7.com/docs/adding-libraries) をチェックして、お気に入りのライブラリを Context7 に追加（または更新）する方法を学びましょう。\n\n## 🛠️ インストール\n\n### 必須要件\n\n- Node.js >= v18.0.0\n- Cursor、Windsurf、Claude Desktop またはその他の MCP クライアント\n<details>\n<summary><b>Smithery 経由でのインストール</b></summary>\n\n[Smithery](https://smithery.ai/server/@upstash/context7-mcp) 経由で任意のクライアントに Context7 MCP サーバーを自動的にインストールするには：\n\n```bash\nnpx -y @smithery/cli@latest install @upstash/context7-mcp --client <CLIENT_NAME> --key <YOUR_SMITHERY_KEY>\n```\n\nSmithery キーは [Smithery.ai Web ページ](https://smithery.ai/server/@upstash/context7-mcp) で確認できます。\n\n</details>\n\n<details>\n<summary><b>Cursor へのインストール</b></summary>\n\n`Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server` に移動します\n以下の設定を Cursor の `~/.cursor/mcp.json` ファイルに貼り付けることが推奨されます。プロジェクトフォルダに `.cursor/mcp.json` を作成することで、特定のプロジェクトにインストールすることもできます。詳細は [Cursor MCP ドキュメント](https://docs.cursor.com/context/model-context-protocol) を参照してください。\n> Cursor 1.0 以降、下のインストールボタンをクリックすることで、ワンクリックで即座にインストールできます。\n\n#### Cursor リモートサーバー接続\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Cursor ローカルサーバー接続\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n<details>\n<summary>代替方法：Bun を使用</summary>\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoiYnVueCAteSBAdXBzdGFzaC9jb250ZXh0Ny1tY3AifQ%3D%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>代替方法：Deno を使用</summary>\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoiZGVubyBydW4gLS1hbGxvdy1lbnYgLS1hbGxvdy1uZXQgbnBtOkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\n        \"run\",\n        \"--allow-env=NO_DEPRECATION,TRACE_DEPRECATION\",\n        \"--allow-net\",\n        \"npm:@upstash/context7-mcp\"\n      ]\n    }\n  }\n}\n```\n</details>\n\n</details>\n\n<details>\n<summary><b>Windsurf へのインストール</b></summary>\n\nこれを Windsurf MCP 設定ファイルに追加します。詳細は [Windsurf MCP ドキュメント](https://docs.windsurf.com/windsurf/mcp) を参照してください。\n\n#### Windsurf リモートサーバー接続\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Windsurf ローカルサーバー接続\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>VS Code へのインストール</b></summary>\n\n[<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Install in VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nこれを VS Code MCP 設定ファイルに追加します。詳細は [VS Code MCP ドキュメント](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) を参照してください。\n\n#### VS Code リモートサーバー接続\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### VS Code ローカルサーバー接続\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>\n<b>Cline でのインストール</b>\n</summary>\n\n1. **Cline** を開きます。\n2. メニューアイコン (☰) をクリックし、**MCP サーバー**セクションに移動します。\n3. **リモートサーバー** タブを選択します。\n4. **設定を編集** ボタンをクリックします。\n5. context7 に関連する設定を `mcpServers` に追加します：\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"type\": \"streamableHttp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Visual Studio 2022 へのインストール</b></summary>\n\n[Visual Studio MCP サーバードキュメント](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022) に従って、Visual Studio 2022 で Context7 MCP を設定できます。\nこれを Visual Studio MCP 設定ファイルに追加します（詳細は [Visual Studio ドキュメント](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022) を参照）：\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"http\",\n        \"url\": \"https://mcp.context7.com/mcp\"\n      }\n    }\n  }\n}\n```\nまたは、ローカルサーバーの場合：\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"stdio\",\n        \"command\": \"npx\",\n        \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n      }\n    }\n  }\n}\n```\n詳細情報とトラブルシューティングについては、[Visual Studio MCP サーバードキュメント](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022) を参照してください。\n</details>\n\n<details>\n<summary><b>Zed へのインストール</b></summary>\n\n[Zed Extensions](https://zed.dev/extensions?query=Context7) 経由でインストールできるか、Zed の `settings.json` にこれを追加できます。詳細は [Zed Context Server ドキュメント](https://zed.dev/docs/assistant/context-servers) を参照してください。\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Claude Code へのインストール</b></summary>\n\nこのコマンドを実行します。詳細は [Claude Code MCP ドキュメント](https://docs.anthropic.com/ja/docs/claude-code/mcp) を参照してください。\n\n#### Claude Code ローカルサーバー接続\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp\n```\n\n#### Claude Code リモートサーバー接続\n\n```sh\nclaude mcp add --scope user --transport http context7 https://mcp.context7.com/mcp\n```\n</details>\n\n<details>\n<summary><b>Claude Desktop へのインストール</b></summary>\n\nこれを Claude Desktop の `claude_desktop_config.json` ファイルに追加します。詳細は [Claude Desktop MCP ドキュメント](https://modelcontextprotocol.io/quickstart/user) を参照してください。\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>BoltAI へのインストール</b></summary>\n\nアプリの \"Settings\" ページを開き、\"Plugins\" に移動し、以下の JSON を入力します：\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n保存後、チャットで `query-docs` の後に Context7 ドキュメント ID を入力します（例：`query-docs /nuxt/ui`）。詳細情報は [BoltAI ドキュメンテーションサイト](https://docs.boltai.com/docs/plugins/mcp-servers) で利用可能です。iOS 版 BoltAI については、[このガイドを参照してください](https://docs.boltai.com/docs/boltai-mobile/mcp-servers)。\n</details>\n\n<details>\n<summary><b>Copilot Coding Agent へのインストール</b></summary>\n\n以下の設定を Copilot Coding Agent の `mcp` セクション（Repository->Settings->Copilot->Coding agent->MCP configuration）に追加してください：\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\n詳細は [公式 GitHub ドキュメント](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp) をご覧ください。\n</details>\n\n<details>\n<summary><b>Copilot CLI へのインストール</b></summary>\n\n1.  Copilot CLI MCP 設定ファイルを開きます。ファイルの場所は `~/.copilot/mcp-config.json`（`~` はホームディレクトリ）です。\n2.  `mcp-config.json` ファイルの `mcpServers` オブジェクトに以下を追加します：\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nまたは、ローカルサーバーの場合：\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n`mcp-config.json` ファイルが存在しない場合は、作成してください。\n</details>\n\n<details>\n<summary><b>Docker を使用</b></summary>\n\nMCP サーバーを Docker コンテナで実行したい場合：\n1. **Docker イメージのビルド：**\n   まず、プロジェクトルート（または希望の場所）に `Dockerfile` を作成します：\n   <details>\n   <summary>Dockerfile の内容を表示</summary>\n\n   ```Dockerfile\n   FROM node:18-alpine\n   WORKDIR /app\n   # 最新バージョンをグローバルにインストール\n   RUN npm install -g @upstash/context7-mcp\n   # 必要に応じてデフォルトポートを公開（任意、MCP クライアントの相互作用に依存）\n   # EXPOSE 3000\n   # サーバーを実行するデフォルトコマンド\n   CMD [\"context7-mcp\"]\n   ```\n   </details>\n\n   次に、タグ（例：`context7-mcp`）を使用してイメージをビルドします。**Docker Desktop（または Docker デーモン）が実行中であることを確認してください。** `Dockerfile` を保存した同じディレクトリで次のコマンドを実行します：\n   ```bash\n   docker build -t context7-mcp .\n   ```\n2. **MCP クライアントの設定：**\n   MCP クライアントの設定を更新して Docker コマンドを使用するようにします。\n   _cline_mcp_settings.json の例：_\n   ```json\n   {\n     \"mcpServers\": {\n       \"Сontext7\": {\n         \"autoApprove\": [],\n         \"disabled\": false,\n         \"timeout\": 60,\n         \"command\": \"docker\",\n         \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n         \"transportType\": \"stdio\"\n       }\n     }\n   }\n   ```\n   _注：これは設定例です。この README の前半で MCP クライアント（Cursor、VS Code など）の具体的な例を参照して、構造（例：`mcpServers` 対 `servers`）を適応させてください。また、`args` 内のイメージ名が `docker build` コマンドで使用したタグと一致していることを確認してください。_\n</details>\n\n<details>\n<summary><b>Windows へのインストール</b></summary>\n\nWindows での設定は Linux や macOS と比べて少し異なります（_例では `Cline` を使用_）。同じ原則が他のエディタにも適用されます。`command` と `args` の設定を参照してください。\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp@latest\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Augment Code へのインストール</b></summary>\n\nAugment Code で Context7 MCP を設定するには、グラフィカルインターフェースまたは手動設定のいずれかを使用できます。\n\n### **A. Augment Code UI を使用する場合**\n1. ハンバーガーメニューをクリックします。\n2. **Settings** を選択します。\n3. **Tools** セクションに移動します。\n4. **+ Add MCP** ボタンをクリックします。\n5. 以下のコマンドを入力します：\n   ```\n   npx -y @upstash/context7-mcp@latest\n   ```\n6. MCP に **Context7** と名前を付けます。\n7. **Add** ボタンをクリックします。\nMCP サーバーが追加されたら、Augment Code 内で Context7 の最新コードドキュメンテーション機能を直接使用できます。\n---\n\n### **B. 手動設定**\n1. Cmd/Ctrl Shift P を押すか、Augment パネルのハンバーガーメニューに移動します\n2. Edit Settings を選択します\n3. Advanced の下で、Edit in settings.json をクリックします\n4. `augment.advanced` オブジェクト内の `mcpServers` 配列にサーバー設定を追加します\n\"augment.advanced\": {\n\"mcpServers\": [\n{\n\"name\": \"context7\",\n\"command\": \"npx\",\n\"args\": [\"-y\", \"@upstash/context7-mcp\"]\n}\n]\n}\nMCP サーバーが追加されたら、エディタを再起動します。エラーが発生した場合は、構文をチェックして、閉じ括弧やカンマが欠けていないことを確認してください。\n</details>\n\n<details>\n<summary><b>Roo Code へのインストール</b></summary>\n\nこれを Roo Code MCP 設定ファイルに追加します。詳細は [Roo Code MCP ドキュメント](https://docs.roocode.com/features/mcp/using-mcp-in-roo) を参照してください。\n\n#### Roo Code リモートサーバー接続\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Roo Code ローカルサーバー接続\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Zencoder へのインストール</b></summary>\n\nZencoder で Context7 MCP を設定するには、以下の手順に従います：\n1. Zencoder メニュー (...) に移動します\n2. ドロップダウンメニューから Agent tools を選択します\n3. Add custom MCP をクリックします\n4. 以下から名前とサーバー設定を追加し、Install ボタンを必ず押してください\n```json\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n}\n```\nMCP サーバーが追加されたら、簡単に使用を続けることができます。\n</details>\n\n<details>\n<summary><b>Amazon Q Developer CLI へのインストール</b></summary>\n\nこれを Amazon Q Developer CLI 設定ファイルに追加します。詳細は [Amazon Q Developer CLI ドキュメント](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html) を参照してください。\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n## 🔨 利用可能なツール\nContext7 MCP は LLM が使用できる以下のツールを提供します：\n- `resolve-library-id`：一般的なライブラリ名を Context7 互換のライブラリ ID に変換します。\n  - `query`（必須）：ユーザーの質問またはタスク（関連性によるランキングに使用）\n  - `libraryName`（必須）：検索するライブラリの名前\n- `query-docs`：Context7 互換のライブラリ ID を使用してライブラリのドキュメントを取得します。\n  - `libraryId`（必須）：正確な Context7 互換のライブラリ ID（例：`/mongodb/docs`、`/vercel/next.js`）\n  - `query`（必須）：関連するドキュメントを取得するための質問またはタスク\n\n## 💻 開発\nプロジェクトをクローンして依存関係をインストールします：\n```bash\npnpm i\n```\nビルド：\n```bash\npnpm run build\n```\nサーバーを実行：\n```bash\nnode packages/mcp/dist/index.js\n```\n\n### CLI 引数\n`context7-mcp` は以下の CLI フラグを受け付けます：\n- `--transport <stdio|http>` – 使用するトランスポート（デフォルトは `stdio`）。\n- `--port <number>` – `http` トランスポート使用時にリッスンするポート（デフォルト `3000`）。\nhttp トランスポートとポート 8080 の例：\n```bash\nnode packages/mcp/dist/index.js --transport http --port 8080\n```\n<details>\n<summary><b>ローカル設定例</b></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>MCP Inspector でのテスト</b></summary>\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n</details>\n\n## 🚨 トラブルシューティング\n<details>\n<summary><b>モジュールが見つからないエラー</b></summary>\n\n`ERR_MODULE_NOT_FOUND` が発生した場合は、`npx` の代わりに `bunx` を使用してみてください：\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nこれにより、`npx` がパッケージを正しくインストールまたは解決できない環境でのモジュール解決の問題が解決されることがあります。\n</details>\n\n<details>\n<summary><b>ESM 解決の問題</b></summary>\n\n`Error: Cannot find module 'uriTemplate.js'` のようなエラーの場合は、`--experimental-vm-modules` フラグを試してください：\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>TLS/証明書の問題</b></summary>\n\nTLS 関連の問題を回避するには、`--experimental-fetch` フラグを使用します：\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-fetch\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>一般的な MCP クライアントエラー</b></summary>\n\n1. パッケージ名に `@latest` を追加してみる\n2. `npx` の代替として `bunx` を使用する\n3. 別の代替方法として `deno` の使用を検討する\n4. ネイティブ fetch サポートのために Node.js v18 以上を使用していることを確認する\n</details>\n\n## ⚠️ 免責事項\nContext7 プロジェクトはコミュニティが貢献しているもので、高品質を維持するよう努めていますが、すべてのライブラリドキュメントの正確性、完全性、セキュリティを保証することはできません。Context7 にリストされているプロジェクトは、Context7 ではなく、それぞれの所有者によって開発および保守されています。疑わしい、不適切な、または潜在的に有害なコンテンツを発見した場合は、プロジェクトページの「報告」ボタンを使用して、すぐにお知らせください。私たちはすべての報告を真剣に受け止め、プラットフォームの整合性と安全性を維持するために、フラグが付けられたコンテンツを迅速にレビューします。Context7 を使用することにより、あなたは自己の裁量とリスクで使用することを認めます。\n\n## 🤝 私たちとつながる\n最新情報を入手し、コミュニティに参加しましょう：\n- 📢 最新ニュースとアップデートのために [X](https://x.com/contextai) でフォローしてください\n- 🌐 [Web サイト](https://context7.com) を訪問してください\n- 💬 [Discord コミュニティ](https://upstash.com/discord) に参加してください\n\n## 📺 メディアでの Context7\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ スター履歴\n[![Star History Chart](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 ライセンス\nMIT\n"
  },
  {
    "path": "i18n/README.ko.md",
    "content": "![Cover](https://github.com/upstash/context7/blob/master/public/cover.png?raw=true)\n\n[![MCP 서버 설치](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n# Context7 MCP - 모든 프롬프트를 위한 최신 코드 문서\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [![NPM Version](https://img.shields.io/npm/v/%40upstash%2Fcontext7-mcp?color=red)](https://www.npmjs.com/package/@upstash/context7-mcp) [![MIT licensed](https://img.shields.io/npm/l/%40upstash%2Fcontext7-mcp)](../LICENSE)\n\n[![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./README.zh-TW.md) [![简体中文](https://img.shields.io/badge/docs-简体中文-yellow)](./README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./README.uk.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./README.ar.md) [![Tiếng Việt](https://img.shields.io/badge/docs-Tiếng%20Việt-red)](./README.vi.md)\n\n## ❌ Context7 미사용 시\n\nLLM은 사용하는 라이브러리에 대해 오래되거나 일반적인 정보에 의존하므로 다음과 같은 문제가 발생합니다:\n\n- ❌ 1년 전 학습 데이터를 기반으로 한 오래된 코드 예제\n- ❌ 실제로 존재하지 않는 API에 대한 환각(Hallucination)\n- ❌ 구 버전 패키지에 대한 일반적인 답변\n\n## ✅ Context7 사용 시\n\nContext7 MCP는 소스에서 직접 최신 버전별 문서와 코드 예제를 가져와 프롬프트에 바로 배치합니다.\n\n프롬프트에 `use context7`을 추가하세요(또는 자동으로 호출되도록 [규칙을 설정](#규칙-추가)하세요):\n\n```txt\n쿠키에서 유효한 JWT를 확인하고 인증되지 않은 사용자를 '/login'으로 리디렉션하는 Next.js 미들웨어를 만들어주세요. use context7\n```\n\n```txt\nJSON API 응답을 5분 동안 캐시하도록 Cloudflare Worker 스크립트를 구성해주세요. use context7\n```\n\nContext7은 최신 코드 예제와 문서를 LLM의 컨텍스트로 바로 가져옵니다. 탭 전환도, 존재하지 않는 API에 대한 환각도, 오래된 코드 생성도 없습니다.\n\n## 설치\n\n> [!NOTE]\n> **API 키 권장**: 더 높은 속도 제한을 위해 [context7.com/dashboard](https://context7.com/dashboard)에서 무료 API 키를 받으세요.\n\n<details>\n<summary><b>Cursor에 설치</b></summary>\n\n이동: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\n\nCursor의 `~/.cursor/mcp.json` 파일에 다음 설정을 붙여넣는 것이 권장되는 접근 방식입니다. 프로젝트 폴더에 `.cursor/mcp.json`을 생성하여 특정 프로젝트에 설치할 수도 있습니다. 자세한 내용은 [Cursor MCP 문서](https://docs.cursor.com/context/model-context-protocol)를 참조하세요.\n\n> Cursor 1.0부터는 아래 설치 버튼을 클릭하여 즉시 원클릭 설치가 가능합니다.\n\n#### Cursor 원격 서버 연결\n\n[![MCP 서버 설치](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Cursor 로컬 서버 연결\n\n[![MCP 서버 설치](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Claude Code에 설치</b></summary>\n\n이 명령어를 실행하세요. 자세한 내용은 [Claude Code MCP 문서](https://code.claude.com/docs/en/mcp)를 참조하세요.\n\n#### Claude Code 로컬 서버 연결\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY\n```\n\n#### Claude Code 원격 서버 연결\n\n```sh\nclaude mcp add --scope user --header \"CONTEXT7_API_KEY: YOUR_API_KEY\" --transport http context7 https://mcp.context7.com/mcp\n```\n\n</details>\n\n<details>\n<summary><b>Opencode에 설치</b></summary>\n\nOpencode 설정 파일에 이것을 추가하세요. 자세한 내용은 [Opencode MCP 문서](https://opencode.ai/docs/mcp-servers)를 참조하세요.\n\n#### Opencode 원격 서버 연결\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"headers\": {\n      \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n    },\n    \"enabled\": true\n  }\n}\n```\n\n#### Opencode 로컬 서버 연결\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n\n</details>\n\n**[기타 IDE 및 클라이언트 →](https://context7.com/docs/resources/all-clients)**\n\n## 중요 팁\n\n### 규칙 추가\n\n모든 프롬프트에 `use context7`을 입력하는 것을 피하려면, 코드 관련 질문에 대해 자동으로 Context7을 호출하도록 MCP 클라이언트에 규칙을 추가하세요:\n\n- **Cursor**: `Cursor Settings > Rules`\n- **Claude Code**: `CLAUDE.md`\n- 또는 사용 중인 MCP 클라이언트의 동등한 기능\n\n**규칙 예시:**\n\n```txt\n라이브러리/API 문서, 코드 생성, 설정 또는 구성 단계가 필요할 때 내가 명시적으로 요청하지 않아도 항상 Context7 MCP를 사용하세요.\n```\n\n### 라이브러리 ID 사용\n\n사용하려는 라이브러리를 이미 정확히 알고 있다면, 프롬프트에 해당 라이브러리의 Context7 ID를 추가하세요. 이렇게 하면 Context7 MCP 서버가 라이브러리 매칭 단계를 건너뛰고 바로 문서 검색을 계속할 수 있습니다.\n\n```txt\nSupabase로 기본 인증을 구현해줘. API와 문서는 use library /supabase/supabase를 사용해줘.\n```\n\n슬래시 구문은 MCP 도구에게 어떤 라이브러리의 문서를 로드할지 정확히 알려줍니다.\n\n### 버전 지정\n\n특정 라이브러리 버전에 대한 문서를 얻으려면 프롬프트에 버전을 언급하면 됩니다:\n\n```txt\nNext.js 14 미들웨어는 어떻게 설정하나요? use context7\n```\n\nContext7은 적절한 버전을 자동으로 매칭합니다.\n\n## 사용 가능한 도구\n\nContext7 MCP는 LLM이 사용할 수 있는 다음 도구들을 제공합니다:\n\n- `resolve-library-id`: 일반적인 라이브러리 이름을 Context7이 인식할 수 있는 라이브러리 ID로 변환합니다.\n  - `query` (필수): 사용자의 질문 또는 작업 (결과 순위 지정에 사용됨)\n  - `libraryName` (필수): 검색할 라이브러리의 이름\n\n- `query-docs`: Context7 호환 라이브러리 ID를 사용하여 라이브러리의 문서를 가져옵니다.\n  - `libraryId` (필수): 정확한 Context7 호환 라이브러리 ID (예: `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (필수): 관련 문서를 가져오기 위한 질문 또는 작업\n\n## 추가 문서\n\n- [더 많은 MCP 클라이언트](https://context7.com/docs/resources/all-clients) - 30개 이상의 클라이언트에 대한 설치 방법\n- [라이브러리 추가](https://context7.com/docs/adding-libraries) - Context7에 라이브러리 제출하기\n- [문제 해결](https://context7.com/docs/resources/troubleshooting) - 일반적인 문제 및 해결 방법\n- [API 참조](https://context7.com/docs/api-guide) - REST API 문서\n- [개발자 가이드](https://context7.com/docs/resources/developer) - 로컬에서 Context7 MCP 실행하기\n\n## 면책 조항\n\n1- Context7 프로젝트는 커뮤니티의 기여로 이루어지며 높은 품질을 유지하기 위해 노력하지만, 모든 라이브러리 문서의 정확성, 완전성 또는 보안을 보장할 수는 없습니다. Context7에 나열된 프로젝트는 Context7이 아닌 해당 소유자가 개발하고 유지 관리합니다. 의심스럽거나, 부적절하거나, 잠재적으로 유해한 콘텐츠를 발견하면 프로젝트 페이지의 \"Report\" 버튼을 사용하여 즉시 알려주시기 바랍니다. 저희는 모든 신고를 심각하게 받아들이며 플랫폼의 무결성과 안전을 유지하기 위해 신고된 콘텐츠를 신속하게 검토할 것입니다. Context7을 사용함으로써 귀하는 자신의 재량과 위험 감수 하에 사용함을 인정하는 것입니다.\n\n2- 이 저장소는 MCP 서버의 소스 코드를 호스팅합니다. API 백엔드, 파싱 엔진, 크롤링 엔진과 같은 지원 구성 요소는 비공개이며 이 저장소의 일부가 아닙니다.\n\n## 🤝 소통하기\n\n최신 소식을 받고 커뮤니티에 참여하세요:\n\n- 📢 [X](https://x.com/context7ai)에서 팔로우하여 최신 뉴스 및 업데이트 확인\n- 🌐 [웹사이트](https://context7.com) 방문\n- 💬 [Discord 커뮤니티](https://upstash.com/discord) 참여\n\n## 📺 미디어 속 Context7\n\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 라이선스\n\nMIT\n"
  },
  {
    "path": "i18n/README.pt-BR.md",
    "content": "# Context7 MCP - Documentação de Código Atualizada para Qualquer Prompt\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp)\n[<img alt=\"Instalar no Cursor\" src=\"https://img.shields.io/badge/Instalar%20no%20CURSOR-000000?style=for-the-badge&logo=cursor&logoColor=white\">](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D) [<img alt=\"Instalar no VS Code (npx)\" src=\"https://img.shields.io/badge/Instalar%20no%20VS%20Code-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[![Documentation in English](https://img.shields.io/badge/docs-English-purple)](../README.md) [![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./README.zh-TW.md) [![简体中文](https://img.shields.io/badge/docs-简体中文-yellow)](./README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./README.uk.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./README.ar.md) [![Tiếng Việt](https://img.shields.io/badge/docs-Tiếng%20Việt-red)](./README.vi.md)\n\n## ❌ Sem o Context7\n\nOs LLMs dependem de informações desatualizadas ou genéricas sobre as bibliotecas que você usa. Você obtém:\n\n- ❌ Exemplos de código desatualizados e baseados em dados de treinamento de anos atrás\n- ❌ APIs alucinadas que nem existem\n- ❌ Respostas genéricas para versões antigas de pacotes\n\n## ✅ Com o Context7\n\nO Context7 MCP extrai documentação e exemplos de código atualizados e específicos para cada versão diretamente da fonte — e os coloca diretamente em seu prompt.\nAdicione `use context7` ao seu prompt no Cursor:\n\n```txt\nCreate a basic Next.js project with app router. use context7\n```\n\n```txt\nCreate a script to delete the rows where the city is \"\" given PostgreSQL credentials. use context7\n```\n\nO Context7 busca exemplos de código e documentação atualizados diretamente para o contexto do seu LLM.\n\n- 1️⃣ Escreva seu prompt naturalmente\n- 2️⃣ Diga ao LLM `use context7`\n- 3️⃣ Obtenha respostas com código funcional\n  Sem alternar entre abas, sem APIs alucinadas que não existem, sem gerações de código desatualizadas.\n\n## 📚 Adicionando Projetos\n\nConfira nosso [guia de adição de projetos](https://context7.com/docs/adding-libraries) para aprender como adicionar (ou atualizar) suas bibliotecas favoritas ao Context7.\n\n## 🛠️ Instalação\n\n### Requisitos\n\n- Node.js >= v18.0.0\n- Cursor, Claude Code, VSCode, Windsurf ou outro Cliente MCP\n<details>\n<summary><b>Instalando via Smithery</b></summary>\n\nPara instalar o Context7 MCP Server automaticamente em qualquer cliente via [Smithery](https://smithery.ai/server/@upstash/context7-mcp):\n\n```bash\nnpx -y @smithery/cli@latest install @upstash/context7-mcp --client <CLIENT_NAME> --key <YOUR_SMITHERY_KEY>\n```\n\nVocê pode encontrar sua chave Smithery na [página do Smithery.ai](https://smithery.ai/server/@upstash/context7-mcp).\n\n</details>\n\n<details>\n<summary><b>Instalar no Cursor</b></summary>\n\nVá em: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\nColar a seguinte configuração no arquivo `~/.cursor/mcp.json` do Cursor é a abordagem recomendada. Você também pode instalar em um projeto específico criando `.cursor/mcp.json` na pasta do seu projeto. Veja mais em [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol).\n> Desde o Cursor 1.0, você pode clicar no botão de instalar abaixo para uma instalação instantânea com um clique.\n\n#### Conexão Remota do Servidor Cursor\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Conexão Local do Servidor Cursor\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no Claude Code</b></summary>\n\nExecute este comando. Veja mais em [Claude Code MCP docs](https://docs.anthropic.com/pt/docs/claude-code/mcp).\n\n#### Conexão Local do Servidor Claude Code\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp\n```\n\n#### Conexão Remota do Servidor Claude Code\n\n```sh\nclaude mcp add --scope user --transport http context7 https://mcp.context7.com/mcp\n```\n</details>\n\n<details>\n<summary><b>Instalar no Windsurf</b></summary>\n\nAdicione isto ao arquivo de configuração MCP do Windsurf. Veja mais em [Windsurf MCP docs](https://docs.windsurf.com/windsurf/cascade/mcp).\n\n#### Conexão Remota do Servidor Windsurf\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Conexão Local do Servidor Windsurf\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no VS Code</b></summary>\n\n[<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Install in VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nAdicione isto ao arquivo de configuração MCP do VS Code. Veja mais em [VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers).\n\n#### Conexão Remota do Servidor VS Code\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Conexão Local do Servidor VS Code\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>\n<b>Instalar no Cline</b>\n</summary>\n\nVocê pode instalar o Context7 facilmente pelo [Cline MCP Server Marketplace](https://cline.bot/mcp-marketplace) seguindo estas instruções:\n1. Abra o **Cline**.\n2. Clique no ícone de menu (☰) para entrar na seção **MCP Servers**.\n3. Use a barra de busca na aba **Marketplace** para encontrar _Context7_.\n4. Clique no botão **Install**.\n</details>\n\n<details>\n<summary><b>Instalar no Zed</b></summary>\n\nPode ser instalado via [Zed Extensions](https://zed.dev/extensions?query=Context7) ou você pode adicionar isto ao seu `settings.json` do Zed. Veja mais em [Zed Context Server docs](https://zed.dev/docs/assistant/context-servers).\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no Augment Code</b></summary>\n\nPara configurar o Context7 MCP no Augment Code, você pode usar a interface gráfica ou a configuração manual.\n\n### **A. Usando a UI do Augment Code**\n1. Clique no menu hambúrguer.\n2. Selecione **Settings**.\n3. Navegue até a seção **Tools**.\n4. Clique no botão **+ Add MCP**.\n5. Insira o seguinte comando:\n   ```\n   npx -y @upstash/context7-mcp@latest\n   ```\n6. Nomeie o MCP: **Context7**.\n7. Clique no botão **Add**.\nDepois que o servidor MCP for adicionado, você pode começar a usar os recursos de documentação de código atualizada do Context7 diretamente no Augment Code.\n---\n\n### **B. Configuração Manual**\n1. Pressione Cmd/Ctrl Shift P ou vá ao menu hambúrguer no painel do Augment\n2. Selecione Edit Settings\n3. Em Advanced, clique em Edit em settings.json\n4. Adicione a configuração do servidor ao array `mcpServers` no objeto `augment.advanced`\n```json\n\"augment.advanced\": {\n  \"mcpServers\": [\n    {\n      \"name\": \"context7\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  ]\n}\n```\nDepois de adicionar o servidor MCP, reinicie seu editor. Se você receber algum erro, verifique a sintaxe para garantir que colchetes ou vírgulas não estejam faltando.\n</details>\n\n<details>\n<summary><b>Instalar no Roo Code</b></summary>\n\nAdicione isto ao arquivo de configuração MCP do Roo Code. Veja mais em [Roo Code MCP docs](https://docs.roocode.com/features/mcp/using-mcp-in-roo).\n\n#### Conexão Remota do Servidor Roo Code\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Conexão Local do Servidor Roo Code\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no Gemini CLI</b></summary>\n\nVeja os detalhes em [Configuração do Gemini CLI](https://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html).\n1. Abra o arquivo de configurações do Gemini CLI. A localização é `~/.gemini/settings.json` (onde `~` é o seu diretório home).\n2. Adicione o seguinte ao objeto `mcpServers` no seu arquivo `settings.json`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"httpUrl\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\nOu, para um servidor local:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nSe o objeto `mcpServers` não existir, crie-o.\n</details>\n\n<details>\n<summary><b>Instalar no Claude Desktop</b></summary>\n\n#### Conexão Remota\nAbra o Claude Desktop e navegue até Settings > Connectors > Add Custom Connector. Insira o nome como `Context7` e a URL remota do MCP server como `https://mcp.context7.com/mcp`.\n\n#### Conexão Local\nAbra as configurações de desenvolvedor do Claude Desktop e edite seu arquivo `claude_desktop_config.json` para adicionar a seguinte configuração. Veja mais em [Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user).\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no Opencode</b></summary>\n\nAdicione isto ao arquivo de configuração do Opencode. Veja mais em [Opencode MCP docs](https://opencode.ai/docs/mcp-servers).\n\n#### Conexão Remota do Opencode\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"enabled\": true\n  }\n}\n```\n\n#### Conexão Local do Opencode\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no OpenAI Codex</b></summary>\n\nVeja mais em [OpenAI Codex](https://github.com/openai/codex).\nAdicione a seguinte configuração às definições do servidor MCP do OpenAI Codex:\n\n#### Conexão de Servidor Local\n\n```toml\n[mcp_servers.context7]\nargs = [\"-y\", \"@upstash/context7-mcp\"]\ncommand = \"npx\"\n```\n\n#### Conexão de Servidor Remoto\n\n```toml\n[mcp_servers.context7]\nurl = \"https://mcp.context7.com/mcp\"\nhttp_headers = { \"CONTEXT7_API_KEY\" = \"YOUR_API_KEY\" }\n```\n</details>\n\n<details>\n<summary><b>Instalar no JetBrains AI Assistant</b></summary>\n\nVeja mais detalhes na [Documentação do JetBrains AI Assistant](https://www.jetbrains.com/help/ai-assistant/configure-an-mcp-server.html).\n1. Nos IDEs da JetBrains vá em `Settings` -> `Tools` -> `AI Assistant` -> `Model Context Protocol (MCP)`\n2. Clique em `+ Add`.\n3. Clique em `Command` no canto superior esquerdo do diálogo e selecione a opção As JSON na lista\n4. Adicione esta configuração e clique em `OK`\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n5. Clique em `Apply` para salvar as alterações.\n6. Da mesma forma, o context7 pode ser adicionado ao JetBrains Junie em `Settings` -> `Tools` -> `Junie` -> `MCP Settings`\n</details>\n\n<details>\n<summary><b>Instalar no Kiro</b></summary>\n\nVeja a [Documentação do Kiro Model Context Protocol](https://kiro.dev/docs/mcp/configuration/) para detalhes.\n1. Navegue até `Kiro` > `MCP Servers`\n2. Adicione um novo servidor MCP clicando no botão `+ Add`.\n3. Cole a configuração abaixo:\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n      \"env\": {},\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n4. Clique em `Save` para aplicar as alterações.\n</details>\n\n<details>\n<summary><b>Instalar no Trae</b></summary>\n\nUse o recurso Add manually e preencha as informações de configuração JSON para esse servidor MCP.\nPara mais detalhes, visite a [documentação do Trae](https://docs.trae.ai/ide/model-context-protocol?_lang=en).\n\n#### Conexão Remota do Servidor Trae\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Conexão Local do Servidor Trae\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Usando Bun ou Deno</b></summary>\n\nUse estas alternativas para executar o servidor Context7 MCP local com outros runtimes. Esses exemplos funcionam para qualquer cliente que suporte iniciar um servidor MCP local via command + args.\n\n#### Bun\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n#### Deno\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\n        \"run\",\n        \"--allow-env=NO_DEPRECATION,TRACE_DEPRECATION\",\n        \"--allow-net\",\n        \"npm:@upstash/context7-mcp\"\n      ]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Usando Docker</b></summary>\n\nSe preferir executar o servidor MCP em um contêiner Docker:\n1. **Crie a Imagem Docker:**\n   Primeiro, crie um `Dockerfile` na raiz do projeto (ou onde preferir):\n   <details>\n   <summary>Clique para ver o conteúdo do Dockerfile</summary>\n\n   ```Dockerfile\n   FROM node:18-alpine\n   WORKDIR /app\n   # Instalar a versão mais recente globalmente\n   RUN npm install -g @upstash/context7-mcp\n   # Expor porta padrão se necessário (opcional, depende da interação do cliente MCP)\n   # EXPOSE 3000\n   # Comando padrão para rodar o servidor\n   CMD [\"context7-mcp\"]\n   ```\n   </details>\n\n   Em seguida, construa a imagem usando uma tag (por exemplo, `context7-mcp`). **Certifique-se de que o Docker Desktop (ou o daemon Docker) esteja em execução.** Execute o comando abaixo no mesmo diretório onde você salvou o `Dockerfile`:\n   ```bash\n   docker build -t context7-mcp .\n   ```\n2. **Configure seu Cliente MCP:**\n   Atualize a configuração do seu cliente MCP para usar o comando Docker.\n   _Exemplo para um cline_mcp_settings.json:_\n   ```json\n   {\n     \"mcpServers\": {\n       \"Сontext7\": {\n         \"autoApprove\": [],\n         \"disabled\": false,\n         \"timeout\": 60,\n         \"command\": \"docker\",\n         \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n         \"transportType\": \"stdio\"\n       }\n     }\n   }\n   ```\n   _Nota: Este é um exemplo de configuração. Consulte os exemplos específicos do seu cliente MCP (como Cursor, VS Code, etc.) anteriormente neste README para adaptar a estrutura (por exemplo, `mcpServers` vs `servers`). Além disso, garanta que o nome da imagem em `args` corresponda à tag usada durante o comando `docker build`._\n</details>\n\n<details>\n<summary><b>Instalar Usando a Extensão Desktop</b></summary>\n\nInstale o arquivo [context7.dxt](dxt/context7.dxt) na pasta dxt e adicione-o ao seu cliente. Para mais informações, confira a [documentação de desktop extensions](https://github.com/anthropics/dxt#desktop-extensions-dxt).\n</details>\n\n<details>\n<summary><b>Instalar no Windows</b></summary>\n\nA configuração no Windows é um pouco diferente em comparação ao Linux ou macOS (_`Cline` é usado no exemplo_). O mesmo princípio se aplica a outros editores; consulte a configuração de `command` e `args`.\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no Amazon Q Developer CLI</b></summary>\n\nAdicione isto ao arquivo de configuração do Amazon Q Developer CLI. Veja mais em [documentação do Amazon Q Developer CLI](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html).\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no Warp</b></summary>\n\nVeja mais em [Documentação do Warp Model Context Protocol](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server).\n1. Vá em `Settings` > `AI` > `Manage MCP servers`.\n2. Adicione um novo servidor MCP clicando no botão `+ Add`.\n3. Cole a configuração abaixo:\n```json\n{\n  \"Context7\": {\n    \"command\": \"npx\",\n    \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n    \"env\": {},\n    \"working_directory\": null,\n    \"start_on_launch\": true\n  }\n}\n```\n4. Clique em `Save` para aplicar as alterações.\n</details>\n\n<details>\n<summary><b>Instalar no Copilot Coding Agent</b></summary>\n\n## Usando o Context7 com o Copilot Coding Agent\nAdicione a seguinte configuração à seção `mcp` do arquivo de configuração do seu Copilot Coding Agent Repository->Settings->Copilot->Coding agent->MCP configuration:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nPara mais informações, veja a [documentação oficial do GitHub](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n</details>\n\n<details>\n<summary><b>Instalar no Copilot CLI</b></summary>\n\n1.  Abra o arquivo de configuração MCP do Copilot CLI. A localização é `~/.copilot/mcp-config.json` (onde `~` é o seu diretório home).\n2.  Adicione o seguinte ao objeto `mcpServers` no seu arquivo `mcp-config.json`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nOu, para um servidor local:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nSe o arquivo `mcp-config.json` não existir, crie-o.\n</details>\n\n<details>\n<summary><b>Instalar no LM Studio</b></summary>\n\nVeja mais em [Suporte a MCP no LM Studio](https://lmstudio.ai/blog/lmstudio-v0.3.17).\n\n#### Instalação com um clique:\n[![Add MCP Server context7 to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJdfQ%3D%3D)\n\n#### Configuração manual:\n1. Navegue até `Program` (lado direito) > `Install` > `Edit mcp.json`.\n2. Cole a configuração abaixo:\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n3. Clique em `Save` para aplicar as alterações.\n4. Ative/desative o servidor MCP no lado direito, em `Program`, ou clicando no ícone de plug na parte inferior da caixa de chat.\n</details>\n\n<details>\n<summary><b>Instalar no Visual Studio 2022</b></summary>\n\nVocê pode configurar o Context7 MCP no Visual Studio 2022 seguindo a [documentação de MCP Servers do Visual Studio](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\nAdicione isto ao arquivo de configuração MCP do Visual Studio (veja os [docs do Visual Studio](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022) para detalhes):\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"http\",\n        \"url\": \"https://mcp.context7.com/mcp\"\n      }\n    }\n  }\n}\n```\nOu, para um servidor local:\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"stdio\",\n        \"command\": \"npx\",\n        \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n      }\n    }\n  }\n}\n```\nPara mais informações e solução de problemas, consulte a [documentação de MCP Servers do Visual Studio](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\n</details>\n\n<details>\n<summary><b>Instalar no Crush</b></summary>\n\nAdicione isto ao arquivo de configuração do Crush. Veja mais em [Crush MCP docs](https://github.com/charmbracelet/crush#mcps).\n\n#### Conexão Remota do Crush\n\n```json\n{\n  \"$schema\": \"https://charm.land/crush.json\",\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Conexão Local do Crush\n\n```json\n{\n  \"$schema\": \"https://charm.land/crush.json\",\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no BoltAI</b></summary>\n\nAbra a página \"Settings\" do app, navegue até \"Plugins\" e insira o seguinte JSON:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nDepois de salvar, digite no chat `query-docs` seguido do seu Context7 documentation ID (por exemplo, `query-docs /nuxt/ui`). Mais informações em [BoltAI's Documentation site](https://docs.boltai.com/docs/plugins/mcp-servers). Para o BoltAI no iOS, [veja este guia](https://docs.boltai.com/docs/boltai-mobile/mcp-servers).\n</details>\n\n<details>\n<summary><b>Instalar no Rovo Dev CLI</b></summary>\n\nEdite sua configuração MCP do Rovo Dev CLI executando o comando abaixo -\n```bash\nacli rovodev mcp\n```\nConfiguração de exemplo -\n\n#### Conexão Remota\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Conexão Local\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no Zencoder</b></summary>\n\nPara configurar o Context7 MCP no Zencoder, siga estes passos:\n1. Vá ao menu do Zencoder (...)\n2. No menu suspenso, selecione Agent tools\n3. Clique em Add custom MCP\n4. Adicione o nome e a configuração do servidor abaixo e certifique-se de clicar no botão Install\n```json\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n}\n```\nDepois que o servidor MCP for adicionado, você pode continuar usando-o facilmente.\n</details>\n\n<details>\n<summary><b>Instalar no Qodo Gen</b></summary>\n\nVeja mais em [docs do Qodo Gen](https://docs.qodo.ai/qodo-documentation/qodo-gen/qodo-gen-chat/agentic-mode/agentic-tools-mcps).\n1. Abra o painel de chat do Qodo Gen no VSCode ou IntelliJ.\n2. Clique em Connect more tools.\n3. Clique em + Add new MCP.\n4. Adicione a seguinte configuração:\n\n#### Conexão Local do Qodo Gen\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n#### Conexão Remota do Qodo Gen\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Instalar no Perplexity Desktop</b></summary>\n\nVeja mais em [Local and Remote MCPs for Perplexity](https://www.perplexity.ai/help-center/en/articles/11502712-local-and-remote-mcps-for-perplexity).\n1. Vá em `Perplexity` > `Settings`\n2. Selecione `Connectors`.\n3. Clique em `Add Connector`.\n4. Selecione `Advanced`.\n5. Insira Server Name: `Context7`\n6. Cole o seguinte JSON na área de texto:\n```json\n{\n  \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n  \"command\": \"npx\",\n  \"env\": {}\n}\n```\n7. Clique em `Save`.\n</details>\n\n## 🔨 Ferramentas Disponíveis\nO Context7 MCP fornece as seguintes ferramentas que LLMs podem usar:\n- `resolve-library-id`: Resolve um nome geral de biblioteca em um ID compatível com o Context7.\n  - `query` (obrigatório): A pergunta ou tarefa do usuário (para ranking de relevância)\n  - `libraryName` (obrigatório): O nome da biblioteca a ser pesquisada\n- `query-docs`: Busca documentação para uma biblioteca usando um ID compatível com o Context7.\n  - `libraryId` (obrigatório): ID exato compatível com Context7 (por exemplo, `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (obrigatório): A pergunta ou tarefa para obter documentação relevante\n\n## 🛟 Dicas\n\n### Adicionar uma Regra\n> Se você não quiser adicionar `use context7` a todo prompt, você pode definir uma regra simples no seu arquivo `.windsurfrules` no Windsurf ou em `Cursor Settings > Rules` no Cursor (ou equivalente no seu cliente MCP) para invocar o Context7 automaticamente em qualquer questão de código:\n>\n> ```toml\n> [[calls]]\n> match = \"quando o usuário solicitar exemplos de código, passos de configuração ou documentação de biblioteca/API\"\n> tool  = \"context7\"\n> ```\n>\n> A partir daí você receberá os docs do Context7 em qualquer conversa relacionada sem digitar nada extra. Você pode adicionar seus casos de uso na parte match.\n\n### Usar o ID da Biblioteca\n> Se você já sabe exatamente qual biblioteca deseja usar, adicione o ID do Context7 ao seu prompt. Assim, o servidor MCP do Context7 pode pular a etapa de correspondência de biblioteca e ir direto para recuperar os docs.\n>\n> ```txt\n> implementar autenticação básica com supabase. use library /supabase/supabase para api e docs\n> ```\n>\n> A sintaxe com barra informa à ferramenta MCP exatamente qual biblioteca carregar.\n\n## 💻 Desenvolvimento\nClone o projeto e instale as dependências:\n```bash\npnpm i\n```\nBuild:\n```bash\npnpm run build\n```\nExecute o servidor:\n```bash\nnode packages/mcp/dist/index.js\n```\n\n### Argumentos de CLI\n`context7-mcp` aceita as seguintes flags de CLI:\n- `--transport <stdio|http>` – Transporte a ser usado (`stdio` por padrão). Use `http` para servidor HTTP remoto ou `stdio` para integração local.\n- `--port <number>` – Porta para escutar ao usar o transporte `http` (padrão `3000`).\nExemplo com transporte http e porta 8080:\n```bash\nnode packages/mcp/dist/index.js --transport http --port 8080\n```\nOutro exemplo com transporte stdio:\n```bash\nnode packages/mcp/dist/index.js --transport stdio\n```\n<details>\n<summary><b>Exemplo de Configuração Local</b></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Testando com o MCP Inspector</b></summary>\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n</details>\n\n## 🚨 Solução de Problemas\n<details>\n<summary><b>Erros de Módulo Não Encontrado</b></summary>\n\nSe você encontrar `ERR_MODULE_NOT_FOUND`, tente usar `bunx` em vez de `npx`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nIsso frequentemente resolve problemas de resolução de módulos em ambientes onde o `npx` não instala ou resolve os pacotes corretamente.\n</details>\n\n<details>\n<summary><b>Problemas de Resolução ESM</b></summary>\n\nPara erros como `Error: Cannot find module 'uriTemplate.js'`, tente a flag `--experimental-vm-modules`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Problemas de TLS/Certificados</b></summary>\n\nUse a flag `--experimental-fetch` para contornar problemas relacionados a TLS:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-fetch\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Erros Gerais do Cliente MCP</b></summary>\n\n1. Tente adicionar `@latest` ao nome do pacote\n2. Use `bunx` como alternativa ao `npx`\n3. Considere usar `deno` como outra alternativa\n4. Certifique-se de estar usando Node.js v18 ou superior para suporte nativo a fetch\n</details>\n\n## ⚠️ Aviso\nOs projetos do Context7 são contribuídos pela comunidade e, embora nos esforcemos para manter alta qualidade, não podemos garantir a precisão, integridade ou segurança de toda a documentação de bibliotecas. Os projetos listados no Context7 são desenvolvidos e mantidos por seus respectivos proprietários, não pelo Context7. Se você encontrar qualquer conteúdo suspeito, impróprio ou potencialmente prejudicial, use o botão \"Report\" na página do projeto para nos notificar imediatamente. Levamos todos os relatos a sério e revisaremos o conteúdo sinalizado prontamente para manter a integridade e a segurança de nossa plataforma. Ao usar o Context7, você reconhece que o faz por sua própria conta e risco.\n\n## 🤝 Conecte-se Conosco\nMantenha-se atualizado e junte-se à nossa comunidade:\n- 📢 Siga-nos no [X](https://x.com/context7ai) para as últimas notícias e atualizações\n- 🌐 Visite nosso [Website](https://context7.com)\n- 💬 Junte-se ao nosso [Discord Community](https://upstash.com/discord)\n\n## 📺 Context7 na Mídia\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Histórico de Stars\n[![Gráfico de Histórico de Stars](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 Licença\nMIT\n"
  },
  {
    "path": "i18n/README.ru.md",
    "content": "# Context7 MCP - Актуальная документация для любого промпта\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n\n## ❌ Без Context7\n\nLLMs полагаются на устаревшую или обобщённую информацию о библиотеках, с которыми вы работаете. В результате этого вы получаете:\n\n- ❌ Устаревшие примеры кода многолетней давности\n- ❌ Выдуманные API, которые даже не существуют\n- ❌ Обобщённые ответы для старых библиотек\n\n## ✅ С Context7\n\nContext7 MCP получает актуальную документацию и примеры кода, строго соответствующие нужной версии, прямо из исходных источников и вставляет их прямо в ваш промпт.\nДобавьте строку `use context7` в промпт для Cursor:\n\n```txt\nСоздай базовый Next.js проект с маршрутизатором приложений. Use context7\n```\n\n```txt\nСоздай скрипт, удаляющий строки, где город равен \"\", используя учётные данные PostgreSQL. Use context7\n```\n\nContext7 MCP подгружает свежие примеры кода и документацию из источников прямо в контекст вашей LLM.\n\n- 1️⃣ Напишите свой промпт так, как писали его всегда\n- 2️⃣ Добавьте к промпту `use context7`\n- 3️⃣ Получите работающий результат\n  Никакого переключения между вкладками, выдуманного API или устаревшего кода.\n\n## 🛠️ Начало работы\n\n### Требования\n\n- Node.js >= v18.0.0\n- Cursor, Windsurf, Claude Desktop или другой MCP клиент\n\n### Установка через Smithery\n\nВоспользуйтесь [Smithery](https://smithery.ai/server/@upstash/context7-mcp), чтобы автоматически установить MCP сервер Context7 для Claude Desktop:\n\n```bash\nnpx -y @smithery/cli install @upstash/context7-mcp --client claude\n```\n\n### Установка в Cursor\n\nПерейдите в вкладку: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\nРекомендуется вставить конфигурацию в файл `~/.cursor/mcp.json`. Также можно установить конфигурацию для конкретного проекта, создав файл `.cursor/mcp.json` в его директории. Смотрите [документацию Cursor MCP](https://docs.cursor.com/context/model-context-protocol) для получения дополнительной информации.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n<details>\n<summary>Альтернативный вариант - Bun</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Альтернативный вариант - Deno</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-env\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n### Установка в Windsurf\nДобавьте следующие строки в ваш конфигурационный файл Windsurf MCP. Смотрите [документацию Windsurf MCP](https://docs.windsurf.com/windsurf/mcp) для получения дополнительной информации.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n### Установка в VS Code\n[<img alt=\"Установка в VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Установить%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Установка в VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Установить%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nДобавьте следующие строки в ваш конфигурационный файл VS Code MCP. Смотрите [документацию VS Code MCP](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) для получения дополнительной информации.\n```json\n{\n  \"servers\": {\n    \"Context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n### Установка in Zed\nМожно установить через [Zed расширение](https://zed.dev/extensions?query=Context7) или добавить следующие строки в `settings.json`. Смотрите [документацию Zed Context Server](https://zed.dev/docs/assistant/context-servers) для получения дополнительной информации.\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n### Установка в Claude Code\nЗапустите следующую команду для установки. Смотрите [документацию Claude Code MCP](https://docs.anthropic.com/ru/docs/claude-code/mcp) для получения дополнительной информации.\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp\n```\n\n### Установка в Claude Desktop\nДобавьте следующие следующие строки в ваш конфигурационный файл `claude_desktop_config.json`. Смотрите [документацию Claude Desktop MCP](https://modelcontextprotocol.io/quickstart/user) для получения дополнительной информации.\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n### Установка в BoltAI\nОткройте страницу \"Settings\", перейдите в \"Plugins\" и добавьте следующие JSON-строки:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n      \"command\": \"npx\"\n    }\n  }\n}\n```\n\n### Установка в Copilot Coding Agent\nДобавьте следующую конфигурацию в секцию `mcp` вашего файла настроек Copilot Coding Agent (Repository->Settings->Copilot->Coding agent->MCP configuration):\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nПодробнее см. в [официальной документации GitHub](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n\n### Установка в Copilot CLI\n1.  Откройте файл конфигурации MCP Copilot CLI. Расположение: `~/.copilot/mcp-config.json` (где `~` — ваша домашняя папка).\n2.  Добавьте следующее к объекту `mcpServers` в вашем файле `mcp-config.json`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nИли для локального сервера:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nЕсли файл `mcp-config.json` не существует, создайте его.\n\n### Используя Docker\nЕсли вы предпочитаете запускать MCP сервер в Docker контейнере:\n1. **Создайте образ Docker:**\n   Во-первых, создайте `Dockerfile` в корне вашего проекта (или в любом другом месте):\n   <details>\n   <summary>Нажмите, чтобы просмотреть содержимое файла Dockerfile</summary>\n\n   ```Dockerfile\n   FROM node:18-alpine\n   WORKDIR /app\n   # Установите последнюю версию пакета глобально\n   RUN npm install -g @upstash/context7-mcp\n   # Откройте стандартный порт, если это необходимо (необязательно, это зависит от взаимодействия с MCP клиентом)\n   # EXPOSE 3000\n   # Стандартная команда для запуска сервера\n   CMD [\"context7-mcp\"]\n   ```\n   </details>\n\n   Затем, соберите образ, используя тег (например, `context7-mcp`). **Убедитесь, что Docker Desktop (или демон Docker) работает.** Запустите следующую команду в этой же директории, где сохранён `Dockerfile`:\n   ```bash\n   docker build -t context7-mcp .\n   ```\n2. **Настройте ваш MCP клиент:**\n   Обновите вашу конфигурацию MCP клиента, чтобы использовать Docker команду.\n   _Пример для cline_mcp_settings.json:_\n   ```json\n   {\n     \"mcpServers\": {\n       \"Сontext7\": {\n         \"autoApprove\": [],\n         \"disabled\": false,\n         \"timeout\": 60,\n         \"command\": \"docker\",\n         \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n         \"transportType\": \"stdio\"\n       }\n     }\n   }\n   ```\n   _Примечение: это пример конфигурации. Обратитесь к конкретным примерам для вашего MCP-клиента (например, Cursor, VS Code и т.д.), в предыдущих разделах этого README, чтобы адаптировать структуру (например, `mcpServers` вместо `servers`). Также убедитесь, что имя образа в `args` соответствует тегу, использованному при выполнении команды `docker build`._\n\n### Установка в Windows\nКонфигурация в Windows немного отличается от Linux или macOS (_в качестве примера используется `Cline`_). Однако, эти же же принципы применимы и к другим редакторам. В случае необходимости обратитесь к настройкам `command` и `args`.\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n\n### Доступные инструменты\n- `resolve-library-id`: преобразует общее название библиотеки в совместимый с Context7 идентификатор.\n  - `query` (обязательно): вопрос или задача пользователя (для ранжирования по релевантности)\n  - `libraryName` (обязательно): название библиотеки для поиска\n- `query-docs`: получает документацию по библиотеке по совместимому с Context7 идентификатору.\n  - `libraryId` (обязательно): точный совместимый с Context7 идентификатор (например, `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (обязательно): вопрос или задача для получения релевантной документации\n\n## Разработка\nСклонируйте проект и установите зависимости:\n```bash\npnpm i\n```\nСборка:\n```bash\npnpm run build\n```\n\n### Пример локальной конфигурации\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n\n### Тестирование с помощью инспектора MCP\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n\n## Решение проблем\n\n### ERR_MODULE_NOT_FOUND\nЕсли вы видите эту ошибку, используйте `bunx` вместо `npx`.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nЗачастую это решает проблему с недостающими модулями, особенно в окружении, где `npx` некорректно устанавливает или разрешает библиотеки.\n\n### Проблемы с разрешением ESM\nЕсли вы сталкиваетесь с проблемой по типу: `Error: Cannot find module 'uriTemplate.js'`, попробуйте запустить команду с флагом `--experimental-vm-modules`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n### Проблемы с TLS/сертификатами\nИспользуйте флаг `--experimental-fetch` c `npx`, чтобы избежать ошибки, связанные с TLS:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-fetch\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n### Ошибки MCP клиента\n1. Попробуйте добавить тег `@latest` в имя пакета.\n2. Попробуйте использовать `bunx` как альтернативу `npx`.\n3. Попробуйте использовать `deno` как замену `npx` или `bunx`.\n4. Убедитесь, что используете версию Node v18 или выше, чтобы `npx` поддерживал встроенный `fetch`.\n\n## Отказ от ответственности\nПроекты Context7 создаются сообществом. Мы стремимся поддерживать высокое качество, однако не можем гарантировать точность, полноту или безопасность всей документации по библиотекам. Проекты, представленные в Context7, разрабатываются и поддерживаются их авторами, а не командой Context7.\nЕсли вы столкнётесь с подозрительным, неуместным или потенциально вредоносным контентом, пожалуйста, воспользуйтесь кнопкой \"Report\" на странице проекта, чтобы немедленно сообщить нам. Мы внимательно относимся ко всем обращениям и оперативно проверяем помеченные материалы, чтобы обеспечить надёжность и безопасность платформы.\nИспользуя Context7, вы признаёте, что делаете это по собственному усмотрению и на свой страх и риск.\n\n## Оставайтесь с нами на связи\nБудьте в курсе последних новостей на наших платформах:\n- 📢 Следите за нашими новостями на [X](https://x.com/contextai), чтобы быть в курсе последних новостей\n- 🌐 Загляните на наш [сайт](https://context7.com)\n- 💬 При желании присоединяйтесь к нашему [сообществу в Discord](https://upstash.com/discord)\n\n## Context7 в СМИ\n- [Better Stack: \"Бесплатный инструмент делает Cursor в 10 раз умнее\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"Это, без сомнения, ЛУЧШИЙ MCP-сервер для AI-помощников в коде\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income stream surfers: \"Context7 + SequentialThinking MCPs: Это уже AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: обновление MCP-агента\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: мгновенный доступ к документации + настройка для VS Code\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income stream surfers: \"Context7: новый MCP-сервер, который изменит кодинг с ИИ\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: Этот MCP сервер делает CLINE в 100 раз ЭФФЕКТИВНЕЕ!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP серверов для стремительного вайб-программирования (Подключи и Работай)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## История звёзд на GitHub\n[![График истории звёзд на GitHub](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## Лицензия\nMIT\n"
  },
  {
    "path": "i18n/README.tr.md",
    "content": "# Context7 MCP - Herhangi Bir Prompt İçin Güncel Kod Belgeleri\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"VS Code'da Yükle (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Context7%20MCP%20Y%C3%BCkle&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[![中文文档](https://img.shields.io/badge/docs-中文版-yellow)](./README.zh-CN.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md)\n\n## ❌ Context7 Olmadan\n\nLLM'ler, kullandığınız kütüphaneler hakkında güncel olmayan veya genel bilgilere güvenir. Karşılaştığınız sorunlar:\n\n- ❌ Kod örnekleri eskidir ve bir yıllık eğitim verilerine dayanır\n- ❌ Halüsinasyon yapılan API'ler gerçekte mevcut değildir\n- ❌ Eski paket sürümleri için genel cevaplar alırsınız\n\n## ✅ Context7 İle\n\nContext7 MCP, güncel ve sürüme özel belgeleri ve kod örneklerini doğrudan kaynağından çeker ve doğrudan prompt'unuza yerleştirir.\nCursor'da prompt'unuza `use context7` ekleyin:\n\n```txt\nNext.js ile app router kullanan basit bir proje oluştur. use context7\n```\n\n```txt\nPostgreSQL kimlik bilgileriyle şehir değeri \"\" olan satırları silmek için bir betik oluştur. use context7\n```\n\nContext7, güncel kod örneklerini ve belgelerini doğrudan LLM'inizin içeriğine getirir.\n\n- 1️⃣ Prompt'unuzu doğal bir şekilde yazın\n- 2️⃣ LLM'e `use context7` kullanmasını söyleyin\n- 3️⃣ Çalışan kod cevapları alın\n  Sekme değiştirme, var olmayan halüsinasyon API'ler, güncel olmayan kod üretimleri yok.\n\n## 🛠️ Başlangıç\n\n### Gereksinimler\n\n- Node.js >= v18.0.0\n- Cursor, Windsurf, Claude Desktop veya başka bir MCP İstemcisi\n\n### Smithery aracılığıyla kurulum\n\nContext7 MCP Server'ı Claude Desktop için [Smithery](https://smithery.ai/server/@upstash/context7-mcp) aracılığıyla otomatik olarak kurmak için:\n\n```bash\nnpx -y @smithery/cli install @upstash/context7-mcp --client claude\n```\n\n### Cursor'da Kurulum\n\nŞu yolu izleyin: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\nAşağıdaki yapılandırmayı Cursor `~/.cursor/mcp.json` dosyanıza yapıştırmanız önerilen yaklaşımdır. Ayrıca, proje klasörünüzde `.cursor/mcp.json` oluşturarak belirli bir projeye de kurabilirsiniz. Daha fazla bilgi için [Cursor MCP belgelerine](https://docs.cursor.com/context/model-context-protocol) bakabilirsiniz.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n<details>\n<summary>Alternatif: Bun Kullanın</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Alternatif: Deno Kullanın</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\"run\", \"--allow-net\", \"npm:@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n### Windsurf'te Kurulum\nBunu Windsurf MCP yapılandırma dosyanıza ekleyin. Daha fazla bilgi için [Windsurf MCP belgelerine](https://docs.windsurf.com/windsurf/mcp) bakabilirsiniz.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### VS Code'da Kurulum\n[<img alt=\"VS Code'da Yükle (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Context7%20MCP%20Y%C3%BCkle&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"VS Code Insiders'da Yükle (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Context7%20MCP%20Y%C3%BCkle&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nBunu VS Code MCP yapılandırma dosyanıza ekleyin. Daha fazla bilgi için [VS Code MCP belgelerine](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) bakabilirsiniz.\n```json\n{\n  \"servers\": {\n    \"Context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Zed'de Kurulum\n[Zed Uzantıları](https://zed.dev/extensions?query=Context7) aracılığıyla kurulabilir veya Zed `settings.json` dosyanıza ekleyebilirsiniz. Daha fazla bilgi için [Zed Context Server belgelerine](https://zed.dev/docs/assistant/context-servers) bakabilirsiniz.\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n### Claude Code'da Kurulum\nBu komutu çalıştırın. Daha fazla bilgi için [Claude Code MCP belgelerine](https://docs.anthropic.com/en/docs/claude-code/mcp) bakabilirsiniz.\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp@latest\n```\n\n### Claude Desktop'ta Kurulum\nBunu Claude Desktop `claude_desktop_config.json` dosyanıza ekleyin. Daha fazla bilgi için [Claude Desktop MCP belgelerine](https://modelcontextprotocol.io/quickstart/user) bakabilirsiniz.\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n\n### Copilot Coding Agent Kurulumu\nAşağıdaki yapılandırmayı Copilot Coding Agent'ın `mcp` bölümüne ekleyin (Repository->Settings->Copilot->Coding agent->MCP configuration):\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nDaha fazla bilgi için [resmi GitHub dokümantasyonuna](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp) bakabilirsiniz.\n\n### Docker Kullanımı\nMCP sunucusunu bir Docker konteynerinde çalıştırmayı tercih ederseniz:\n1.  **Docker Görüntüsü Oluşturun:**\n    Önce, proje kökünde (veya tercih ettiğiniz herhangi bir yerde) bir `Dockerfile` oluşturun:\n    <details>\n    <summary>Dockerfile içeriğini görmek için tıklayın</summary>\n\n    ```Dockerfile\n    FROM node:18-alpine\n    WORKDIR /app\n    # En son sürümü global olarak yükleyin\n    RUN npm install -g @upstash/context7-mcp@latest\n    # Gerekirse varsayılan portu açın (isteğe bağlı, MCP istemci etkileşimine bağlıdır)\n    # EXPOSE 3000\n    # Sunucuyu çalıştırmak için varsayılan komut\n    CMD [\"context7-mcp\"]\n    ```\n    </details>\n\n    Ardından, bir etiket (örneğin, `context7-mcp`) kullanarak görüntüyü oluşturun. **Docker Desktop'un (veya Docker daemon'un) çalıştığından emin olun.** `Dockerfile`'ı kaydettiğiniz dizinde aşağıdaki komutu çalıştırın:\n    ```bash\n    docker build -t context7-mcp .\n    ```\n2.  **MCP İstemcinizi Yapılandırın:**\n    MCP istemcinizin yapılandırmasını Docker komutunu kullanacak şekilde güncelleyin.\n    _cline_mcp_settings.json için örnek:_\n    ```json\n    {\n      \"mcpServers\": {\n        \"Сontext7\": {\n          \"autoApprove\": [],\n          \"disabled\": false,\n          \"timeout\": 60,\n          \"command\": \"docker\",\n          \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n          \"transportType\": \"stdio\"\n        }\n      }\n    }\n    ```\n    _Not: Bu bir örnek yapılandırmadır. Yapıyı uyarlamak için MCP istemcinize (Cursor, VS Code vb.) özel örneklere bakın (örneğin, `mcpServers` ve `servers` farkı). Ayrıca, `args` içindeki görüntü adının `docker build` komutu sırasında kullanılan etiketle eşleştiğinden emin olun._\n\n### Kullanılabilir Araçlar\n- `resolve-library-id`: Genel bir kütüphane adını Context7 uyumlu bir kütüphane ID'sine dönüştürür.\n  - `query` (gerekli): Kullanıcının sorusu veya görevi (alaka sıralaması için)\n  - `libraryName` (gerekli): Aranacak kütüphane adı\n- `query-docs`: Context7 uyumlu bir kütüphane ID'si kullanarak bir kütüphane için belgeleri getirir.\n  - `libraryId` (gerekli): Context7 uyumlu tam kütüphane ID'si (örneğin, `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (gerekli): İlgili belgeleri almak için soru veya görev\n\n## Geliştirme\nProjeyi klonlayın ve bağımlılıkları yükleyin:\n```bash\npnpm i\n```\nDerleyin:\n```bash\npnpm run build\n```\n\n### Yerel Yapılandırma Örneği\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n\n### MCP Inspector ile Test Etme\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp@latest\n```\n\n## Sorun Giderme\n\n### ERR_MODULE_NOT_FOUND\nBu hatayı görürseniz, `npx` yerine `bunx` kullanmayı deneyin.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\nBu, özellikle `npx`'in paketleri düzgün şekilde yüklemediği veya çözemediği ortamlarda modül çözümleme sorunlarını genellikle çözer.\n\n### ESM Çözümleme Sorunları\n`Error: Cannot find module 'uriTemplate.js'` gibi bir hatayla karşılaşırsanız, `--experimental-vm-modules` bayrağıyla çalıştırmayı deneyin:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n\n### MCP İstemci Hataları\n1. Paket adından `@latest` ifadesini kaldırmayı deneyin.\n2. Alternatif olarak `bunx` kullanmayı deneyin.\n3. Alternatif olarak `deno` kullanmayı deneyin.\n4. `npx` ile yerel fetch desteğine sahip olmak için Node v18 veya daha yüksek bir sürüm kullandığınızdan emin olun.\n\n## Sorumluluk Reddi\nContext7 projeleri topluluk katkılıdır ve yüksek kaliteyi korumaya çalışsak da, tüm kütüphane belgelerinin doğruluğunu, eksiksizliğini veya güvenliğini garanti edemeyiz. Context7'de listelenen projeler, Context7 tarafından değil, ilgili sahipleri tarafından geliştirilmekte ve sürdürülmektedir. Şüpheli, uygunsuz veya potansiyel olarak zararlı içerikle karşılaşırsanız, lütfen bizi hemen bilgilendirmek için proje sayfasındaki \"Bildir\" düğmesini kullanın. Tüm bildirimleri ciddiye alıyoruz ve platformumuzun bütünlüğünü ve güvenliğini korumak için işaretlenen içeriği hızla inceleyeceğiz. Context7'yi kullanarak, bunu kendi takdirinizle ve riskinizle yaptığınızı kabul etmiş olursunuz.\n\n## Context7 Medyada\n- [Better Stack: \"Ücretsiz Araç Cursor'u 10 Kat Daha Akıllı Yapıyor\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"Bu, Tartışmasız AI Kodlama Asistanları İçin EN İYİ MCP Sunucusudur\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income stream surfers: \"Context7 + SequentialThinking MCP'leri: Bu AGI mi?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: Yeni MCP AI Aracı Güncellemesi\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Belgeleri Anında Alın + VS Code Kurulumu\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income stream surfers: \"Context7: AI Kodlamayı DEĞİŞTİRECEK Yeni MCP Sunucusu\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: Bu MCP Sunucusu CLINE'ı 100 KAT DAHA ETKİLİ YAPIYOR!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"Vibe Kodlama İhtişamı İçin 5 MCP Sunucusu (Tak ve Çalıştır)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## Yıldız Geçmişi\n[![Yıldız Geçmişi Grafiği](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## Lisans\nMIT\n"
  },
  {
    "path": "i18n/README.uk.md",
    "content": "# Context7 MCP — Актуальна документація з прикладами коду для будь-якого запиту\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./README.zh-TW.md) [![简体中文](https://img.shields.io/badge/docs-简体中文-yellow)](./README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./README.ar.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./README.uk.md)\n\n## ❌ Без Context7\n\nВеликі мовні моделі покладаються на застарілу або узагальнену інформацію про бібліотеки, які ви використовуєте. Внаслідок цього ви отримуєте:\n\n- ❌ Застарілі приклади коду, що базуються на даних навчання кількарічної давності\n- ❌ «Галюцинації» — API, які взагалі не існують\n- ❌ Узагальнені відповіді для старих версій пакунків\n\n## ✅ З Context7\n\nContext7 MCP отримує актуальну, специфічну для версії документацію та приклади коду безпосередньо з джерела — і вбудовує їх прямо у ваш промпт.\nДодайте `use context7` до вашого запиту в Cursor:\n\n```txt\nCreate a Next.js middleware that checks for a valid JWT in cookies and redirects unauthenticated users to `/login`. use context7\n```\n\n```txt\nConfigure a Cloudflare Worker script to cache JSON API responses for five minutes. use context7\n```\n\nContext7 завантажує свіжі приклади коду й документацію безпосередньо в контекст вашої великої мовної моделі.\n\n- 1️⃣ Написуйте ваш промпт природно\n- 2️⃣ Скажіть ШІ використати `use context7`\n- 3️⃣ Отримайте робочі відповіді з кодом\n  Без перемикання між вкладками, без неіснуючих API та без застарілого коду.\n\n## 📚 Додавання проєктів\n\nОзнайомтеся з нашим [посібником з додавання проєктів](https://context7.com/docs/adding-libraries), щоб дізнатися, як додати (або оновити) ваші улюблені бібліотеки в Context7.\n\n## 🛠️ Встановлення\n\n### Системні вимоги\n\n- Node.js ≥ v18.0.0\n- Cursor, Windsurf, Claude Desktop або інший MCP-клієнт\n<details>\n<summary><b>Встановлення через Smithery</b></summary>\n\nДля автоматичного встановлення Context7 MCP Server для будь-якого клієнта через [Smithery](https://smithery.ai/server/@upstash/context7-mcp):\n\n```bash\nnpx -y @smithery/cli@latest install @upstash/context7-mcp --client <CLIENT_NAME> --key <YOUR_SMITHERY_KEY>\n```\n\nВаш ключ Smithery можна знайти на [сторінці Smithery.ai](https://smithery.ai/server/@upstash/context7-mcp).\n\n</details>\n\n<details>\n<summary><b>Встановлення в Cursor</b></summary>\n\nПерейдіть до: `Settings` → `Cursor Settings` → `MCP` → `Add new global MCP server`\nРекомендується вставити наступну конфігурацію у файл `~/.cursor/mcp.json`. Також можна встановити для конкретного проєкту, створивши `.cursor/mcp.json` у теці проєкту. Детальніше див. у [документації Cursor MCP](https://docs.cursor.com/context/model-context-protocol).\n> Починаючи з Cursor 1.0, ви можете просто натиснути кнопку встановлення нижче для миттєвої інсталяції.\n\n#### Підключення до віддаленого сервера Cursor\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Підключення до локального сервера Cursor\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n<details>\n<summary>Альтернатива: використання Bun</summary>\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoiYnVueCAteSBAdXBzdGFzaC9jb250ZXh0Ny1tY3AifQ%3D%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Альтернатива: використання Deno</summary>\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoiZGVubyBydW4gLS1hbGxvdy1lbnYgLS1hbGxvdy1uZXQgbnBtOkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\n        \"run\",\n        \"--allow-env=NO_DEPRECATION,TRACE_DEPRECATION\",\n        \"--allow-net\",\n        \"npm:@upstash/context7-mcp\"\n      ]\n    }\n  }\n}\n```\n</details>\n\n</details>\n\n<details>\n<summary><b>Встановлення в Windsurf</b></summary>\n\nДодайте це до вашого конфігураційного файлу Windsurf MCP. Детальніше див. у [документації Windsurf MCP](https://docs.windsurf.com/windsurf/mcp).\n\n#### Підключення до віддаленого сервера Windsurf\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Підключення до локального сервера Windsurf\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Trae</b></summary>\n\nВикористовуйте функцію \"Add manually\" і заповніть конфігурацію JSON для цього MCP-сервера.\nДетальніше див. у [документації Trae](https://docs.trae.ai/ide/model-context-protocol?_lang=en).\n\n#### Підключення до віддаленого сервера Trae\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Підключення до локального сервера Trae\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в VS Code</b></summary>\n\n[<img alt=\"Встановити в VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Встановити%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Встановити в VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Встановити%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nДодайте це до вашого конфігураційного файлу VS Code MCP. Детальніше див. у [документації VS Code MCP](https://code.visualstudio.com/docs/copilot/chat/mcp-servers).\n\n#### Підключення до віддаленого сервера VS Code\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Підключення до локального сервера VS Code\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Visual Studio 2022</b></summary>\n\nВи можете налаштувати Context7 MCP у Visual Studio 2022, дотримуючись [документації Visual Studio MCP Servers](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\nДодайте це до вашого конфігураційного файлу Visual Studio MCP (детальніше в [документації Visual Studio](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022)):\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"http\",\n        \"url\": \"https://mcp.context7.com/mcp\"\n      }\n    }\n  }\n}\n```\nАбо для локального сервера:\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"stdio\",\n        \"command\": \"npx\",\n        \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n      }\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Zed</b></summary>\n\nМожна встановити через [розширення Zed](https://zed.dev/extensions?query=Context7) або додати це до вашого `settings.json`. Детальніше див. у [документації Zed Context Server](https://zed.dev/docs/assistant/context-servers).\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Copilot Coding Agent</b></summary>\n\n## Використання Context7 з Copilot Coding Agent\nДодайте наступну конфігурацію до розділу `mcp` вашого файла настроек Copilot Coding Agent Repository->Settings->Copilot->Coding agent->MCP configuration:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nДетальніше див. в [офіційній документації GitHub](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n</details>\n\n<details>\n<summary><b>Встановлення в Copilot CLI</b></summary>\n\n1.  Відкрийте файл конфігурації MCP Copilot CLI. Розташування: `~/.copilot/mcp-config.json` (де `~` — ваша домашня папка).\n2.  Додайте наступне до об'єкта `mcpServers` у вашому файлі `mcp-config.json`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nАбо для локального сервера:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nЯкщо файл `mcp-config.json` не існує, створіть його.\n</details>\n\n<details>\n<summary><b>Встановлення в Gemini CLI</b></summary>\n\nДетальніше див. у [конфігурації Gemini CLI](https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/configuration.md).\n1. Відкрийте файл налаштувань Gemini CLI. Розташування: `~/.gemini/settings.json` (де `~` — ваша домашня тека).\n2. Додайте наступне до об'єкта `mcpServers` у вашому `settings.json`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nЯкщо об'єкт `mcpServers` не існує, створіть його.\n</details>\n\n<details>\n<summary><b>Встановлення в Claude Code</b></summary>\n\nВиконайте цю команду. Детальніше див. у [документації Claude Code MCP](https://docs.anthropic.com/en/docs/claude-code/mcp).\n\n#### Підключення до локального сервера Claude Code\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp\n```\n\n#### Підключення до віддаленого сервера Claude Code\n\n```sh\nclaude mcp add --scope user --transport http context7 https://mcp.context7.com/mcp\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Claude Desktop</b></summary>\n\nДодайте це до вашого файлу `claude_desktop_config.json` у Claude Desktop. Детальніше див. у [документації Claude Desktop MCP](https://modelcontextprotocol.io/quickstart/user).\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Cline</b></summary>\n\nВи можете легко встановити Context7 через [торговий майданчик MCP-серверів Cline](https://cline.bot/mcp-marketplace), дотримуючись цих інструкцій:\n1. Відкрийте **Cline**.\n2. Натисніть значок меню гамбургер (☰), щоб увійти до розділу **MCP Servers**.\n3. Використовуйте панель пошуку у вкладці **Marketplace**, щоб знайти _Context7_.\n4. Натисніть кнопку **Install**.\n</details>\n\n<details>\n<summary><b>Встановлення в BoltAI</b></summary>\n\nВідкрийте сторінку \"Settings\" застосунку, перейдіть до \"Plugins\" і введіть наступний JSON:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nПісля збереження введіть у чаті `query-docs`, а потім ваш ідентифікатор документації Context7 (наприклад, `query-docs /nuxt/ui`). Додаткова інформація доступна на [сайті документації BoltAI](https://docs.boltai.com/docs/plugins/mcp-servers). Для BoltAI на iOS [див. цей посібник](https://docs.boltai.com/docs/boltai-mobile/mcp-servers).\n</details>\n\n<details>\n<summary><b>Використання Docker</b></summary>\n\nЯкщо ви віддаєте перевагу запуску MCP-сервера в Docker-контейнері:\n1. **Створіть Docker-образ:**\n   Спочатку створіть `Dockerfile` у корені проєкту (або де завгодно):\n   <details>\n   <summary>Натисніть, щоб побачити вміст Dockerfile</summary>\n\n   ```Dockerfile\n   FROM node:18-alpine\n   WORKDIR /app\n   # Встановіть найновішу версію глобально\n   RUN npm install -g @upstash/context7-mcp\n   # Відкрийте стандартний порт, якщо потрібно (необов'язково, залежить від взаємодії з MCP-клієнтом)\n   # EXPOSE 3000\n   # Стандартна команда для запуску сервера\n   CMD [\"context7-mcp\"]\n   ```\n   </details>\n\n   Потім створіть образ, використовуючи тег (наприклад, `context7-mcp`). **Переконайтеся, що Docker Desktop (або демон Docker) запущений.** Виконайте наступну команду в тій же теці, де ви зберегли `Dockerfile`:\n   ```bash\n   docker build -t context7-mcp .\n   ```\n2. **Налаштуйте ваш MCP-клієнт:**\n   Оновіть конфігурацію вашого MCP-клієнта для використання Docker-команди.\n   _Приклад для cline_mcp_settings.json:_\n   ```json\n   {\n     \"mcpServers\": {\n       \"Context7\": {\n         \"autoApprove\": [],\n         \"disabled\": false,\n         \"timeout\": 60,\n         \"command\": \"docker\",\n         \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n         \"transportType\": \"stdio\"\n       }\n     }\n   }\n   ```\n   _Примітка: Це приклад конфігурації. Будь ласка, зверніться до конкретних прикладів для вашого MCP-клієнта (наприклад, Cursor, VS Code тощо) раніше в цьому README, щоб адаптувати структуру (наприклад, `mcpServers` проти `servers`). Також переконайтеся, що назва образу в `args` збігається з тегом, використаним під час команди `docker build`._\n</details>\n\n<details>\n<summary><b>Встановлення в Windows</b></summary>\n\nКонфігурація в Windows дещо відрізняється від Linux або macOS (_у прикладі використовується `Cline`_). Той же принцип застосовується до інших редакторів; зверніться до конфігурації `command` та `args`.\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp@latest\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Augment Code</b></summary>\n\nДля налаштування Context7 MCP в Augment Code ви можете використовувати або графічний інтерфейс, або ручну конфігурацію.\n\n### **A. Використання інтерфейсу Augment Code**\n1. Натисніть меню гамбургер.\n2. Виберіть **Settings**.\n3. Перейдіть до розділу **Tools**.\n4. Натисніть кнопку **+ Add MCP**.\n5. Введіть наступну команду:\n   ```\n   npx -y @upstash/context7-mcp@latest\n   ```\n6. Назва MCP: **Context7**.\n7. Натисніть кнопку **Add**.\n\n### **B. Ручна конфігурація**\n1. Натисніть Cmd/Ctrl Shift P або перейдіть до меню гамбургер у панелі Augment\n2. Виберіть Edit Settings\n3. У розділі Advanced натисніть Edit in settings.json\n4. Додайте конфігурацію сервера до масиву `mcpServers` в об'єкті `augment.advanced`\n```json\n\"augment.advanced\": {\n  \"mcpServers\": [\n    {\n      \"name\": \"context7\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  ]\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Roo Code</b></summary>\n\nДодайте це до вашого конфігураційного файлу Roo Code MCP. Детальніше див. у [документації Roo Code MCP](https://docs.roocode.com/features/mcp/using-mcp-in-roo).\n\n#### Підключення до віддаленого сервера Roo Code\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Підключення до локального сервера Roo Code\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Zencoder</b></summary>\n\nДля налаштування Context7 MCP в Zencoder виконайте наступні кроки:\n1. Перейдіть до меню Zencoder (...)\n2. З випадного меню виберіть Agent tools\n3. Натисніть на Add custom MCP\n4. Додайте назву та конфігурацію сервера знизу і обов'язково натисніть кнопку Install\n```json\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Amazon Q Developer CLI</b></summary>\n\nДодайте це до вашого конфігураційного файлу Amazon Q Developer CLI. Детальніше див. у [документації Amazon Q Developer CLI](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html).\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в Qodo Gen</b></summary>\n\nДетальніше див. у [документації Qodo Gen](https://docs.qodo.ai/qodo-documentation/qodo-gen/qodo-gen-chat/agentic-mode/agentic-tools-mcps).\n1. Відкрийте панель чату Qodo Gen у VSCode або IntelliJ.\n2. Натисніть Connect more tools.\n3. Натисніть + Add new MCP.\n4. Додайте наступну конфігурацію:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Встановлення в JetBrains AI Assistant</b></summary>\n\nДетальніше див. у [документації JetBrains AI Assistant](https://www.jetbrains.com/help/ai-assistant/configure-an-mcp-server.html).\n1. У JetBrains IDE перейдіть до `Settings` → `Tools` → `AI Assistant` → `Model Context Protocol (MCP)`\n2. Натисніть `+ Add`.\n3. Натисніть на `Command` у верхньому лівому куті діалогу та виберіть опцію As JSON зі списку\n4. Додайте цю конфігурацію та натисніть `OK`\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n5. Натисніть `Apply`, щоб зберегти зміни.\n</details>\n\n<details>\n<summary><b>Встановлення в Warp</b></summary>\n\nДетальніше див. у [документації Warp Model Context Protocol](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server).\n1. Перейдіть до `Settings` > `AI` > `Manage MCP servers`.\n2. Додайте новий MCP-сервер, натиснувши кнопку `+ Add`.\n3. Вставте конфігурацію, наведену нижче:\n```json\n{\n  \"Context7\": {\n    \"command\": \"npx\",\n    \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n    \"env\": {},\n    \"working_directory\": null,\n    \"start_on_launch\": true\n  }\n}\n```\n4. Натисніть `Save`, щоб застосувати зміни.\n</details>\n\n<details>\n<summary><b>Встановлення в Opencode</b></summary>\n\nДодайте це до вашого конфігураційного файлу Opencode. Детальніше див. у [документації Opencode MCP](https://opencode.ai/docs/mcp-servers).\n\n#### Підключення до віддаленого сервера Opencode\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"enabled\": true\n  }\n}\n```\n\n#### Підключення до локального сервера Opencode\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n</details>\n\n## 🔨 Доступні інструменти\nContext7 MCP надає наступні інструменти, які можуть використовувати великі мовні моделі:\n- `resolve-library-id`: Перетворює загальну назву бібліотеки на сумісний з Context7 ідентифікатор бібліотеки.\n  - `query` (обов'язково): Питання або завдання користувача (для ранжування за релевантністю)\n  - `libraryName` (обов'язково): Назва бібліотеки для пошуку\n- `query-docs`: Отримує документацію для бібліотеки, використовуючи сумісний з Context7 ідентифікатор бібліотеки.\n  - `libraryId` (обов'язково): Точний сумісний з Context7 ідентифікатор бібліотеки (наприклад, `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (обов'язково): Питання або завдання для отримання релевантної документації\n\n## 🛟 Поради\n\n### Додайте правило\n> Якщо ви не хочете додавати `use context7` до кожного промпту, ви можете визначити просте правило у вашому файлі `.windsurfrules` в Windsurf або в розділі `Cursor Settings > Rules` в Cursor (або еквівалентному у вашому MCP-клієнті), щоб автоматично викликати Context7 для будь-яких запитань про код:\n>\n> ```toml\n> [[calls]]\n> match = \"when the user requests code examples, setup or configuration steps, or library/API documentation\"\n> tool  = \"context7\"\n> ```\n>\n> Відтоді ви отримуватимете документацію Context7 у будь-якій пов'язаній розмові без введення будь-чого додаткового. Ви можете додати свої випадки використання до частини match.\n\n### Використовуйте ідентифікатор бібліотеки\n> Якщо ви вже точно знаєте, яку бібліотеку хочете використовувати, додайте її ідентифікатор Context7 до вашого промпту. Таким чином Context7 MCP-сервер може пропустити крок пошуку бібліотеки та одразу перейти до отримання документації.\n>\n> ```txt\n> implement basic authentication with supabase. use library /supabase/supabase for api and docs\n> ```\n>\n> Синтаксис із слешем повідомляє MCP-інструменту точно, для якої бібліотеки завантажувати документацію.\n\n## 💻 Розробка\nСклонуйте проєкт і встановіть залежності:\n```bash\npnpm i\n```\nЗбирання:\n```bash\npnpm run build\n```\nЗапуск сервера:\n```bash\nnode packages/mcp/dist/index.js\n```\n\n### Аргументи командного рядка\n`context7-mcp` приймає наступні прапори CLI:\n- `--transport <stdio|http>` — Транспорт для використання (`stdio` за замовчуванням).\n- `--port <number>` — Порт для прослуховування при використанні транспорту `http` (за замовчуванням `3000`).\nПриклад з http-транспортом і портом 8080:\n```bash\nnode packages/mcp/dist/index.js --transport http --port 8080\n```\n<details>\n<summary><b>Приклад локальної конфігурації</b></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Тестування з MCP Inspector</b></summary>\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n</details>\n\n## 🚨 Усунення несправностей\n<details>\n<summary><b>Помилки \"Module Not Found\"</b></summary>\n\nЯкщо ви стикаєтеся з `ERR_MODULE_NOT_FOUND`, спробуйте використовувати `bunx` замість `npx`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nЦе часто вирішує проблеми розв'язання модулів у середовищах, де `npx` не встановлює або не розв'язує пакунки належним чином.\n</details>\n\n<details>\n<summary><b>Проблеми розв'язання ESM</b></summary>\n\nДля помилок типу `Error: Cannot find module 'uriTemplate.js'` спробуйте прапор `--experimental-vm-modules`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Проблеми TLS/сертифікатів</b></summary>\n\nВикористовуйте прапор `--experimental-fetch`, щоб обійти проблеми, пов'язані з TLS:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-fetch\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Загальні помилки MCP-клієнта</b></summary>\n\n1. Спробуйте додати `@latest` до назви пакунка\n2. Використовуйте `bunx` як альтернативу до `npx`\n3. Розгляньте використання `deno` як іншу альтернативу\n4. Переконайтеся, що ви використовуєте Node.js v18 або вище для підтримки нативного fetch\n</details>\n\n## ⚠️ Застереження\nПроєкти Context7 створюються спільнотою, і хоча ми прагнемо підтримувати високу якість, ми не можемо гарантувати точність, повноту або безпеку всієї документації бібліотек. Проєкти, перелічені в Context7, розробляються та підтримуються їхніми відповідними власниками, а не Context7. Якщо ви зіткнетеся з будь-яким підозрілим, неприйнятним або потенційно шкідливим контентом, будь ласка, використовуйте кнопку \"Report\" на сторінці проєкту, щоб негайно повідомити нас. Ми серйозно ставимося до всіх звітів і оперативно переглядаємо позначений контент для підтримання цілісності та безпеки нашої платформи. Використовуючи Context7, ви визнаєте, що робите це на власний розсуд і ризик.\n\n## 🤝 Зв'яжіться з нами\nЗалишайтеся в курсі подій та приєднуйтеся до нашої спільноти:\n- 📢 Слідкуйте за нами в [X](https://x.com/contextai) для отримання останніх новин та оновлень\n- 🌐 Відвідайте наш [веб-сайт](https://context7.com)\n- 💬 Приєднуйтеся до нашої [спільноти Discord](https://upstash.com/discord)\n\n## 📺 Context7 у медіа\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Історія зірок\n[![Діаграма історії зірок](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 Ліцензія\nMIT\n"
  },
  {
    "path": "i18n/README.vi.md",
    "content": "# Context7 MCP - Tài Liệu Code Cập Nhật Cho Mọi Prompt\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./README.zh-TW.md) [![简体中文](https://img.shields.io/badge/docs-简体中文-yellow)](./README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./README.uk.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./README.ar.md) [![Tiếng Việt](https://img.shields.io/badge/docs-Tiếng%20Việt-red)](./README.vi.md)\n\n## ❌ Không có Context7\n\nCác LLM dựa vào thông tin lỗi thời hoặc chung chung về các thư viện bạn sử dụng. Bạn sẽ gặp phải:\n\n- ❌ Các ví dụ code lỗi thời và dựa trên dữ liệu huấn luyện cũ\n- ❌ API được tạo ra không tồn tại thực sự\n- ❌ Câu trả lời chung chung cho các phiên bản package cũ\n\n## ✅ Với Context7\n\nContext7 MCP lấy tài liệu và ví dụ code cập nhật, dành cho phiên bản cụ thể trực tiếp từ nguồn gốc — và đặt chúng trực tiếp vào prompt của bạn.\nThêm `use context7` vào prompt của bạn trong Cursor:\n\n```txt\nTạo một Next.js middleware kiểm tra JWT hợp lệ trong cookies và chuyển hướng người dùng chưa xác thực đến `/login`. use context7\n```\n\n```txt\nCấu hình script Cloudflare Worker để cache JSON API responses trong năm phút. use context7\n```\n\nContext7 lấy các ví dụ code và tài liệu cập nhật ngay vào context của LLM.\n\n- 1️⃣ Viết prompt một cách tự nhiên\n- 2️⃣ Nói với LLM để `use context7`\n- 3️⃣ Nhận được câu trả lời code hoạt động\n  Không cần chuyển tab, không có API tự tạo không tồn tại, không có code generation lỗi thời.\n\n## 📚 Thêm Dự Án\n\nXem [hướng dẫn thêm dự án](https://context7.com/docs/adding-libraries) để học cách thêm (hoặc cập nhật) các thư viện yêu thích của bạn vào Context7.\n\n## 🛠️ Cài Đặt\n\n### Yêu Cầu\n\n- Node.js >= v18.0.0\n- Cursor, Windsurf, Claude Desktop hoặc MCP Client khác\n<details>\n<summary><b>Cài đặt qua Smithery</b></summary>\n\nĐể cài đặt Context7 MCP Server cho bất kỳ client nào tự động qua [Smithery](https://smithery.ai/server/@upstash/context7-mcp):\n\n```bash\nnpx -y @smithery/cli@latest install @upstash/context7-mcp --client <CLIENT_NAME> --key <YOUR_SMITHERY_KEY>\n```\n\nBạn có thể tìm Smithery key của mình tại [trang web Smithery.ai](https://smithery.ai/server/@upstash/context7-mcp).\n\n</details>\n\n<details>\n<summary><b>Cài đặt trong Cursor</b></summary>\n\nĐi đến: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\nPaste cấu hình sau vào file Cursor `~/.cursor/mcp.json` là cách được khuyến nghị. Bạn cũng có thể cài đặt trong một dự án cụ thể bằng cách tạo `.cursor/mcp.json` trong thư mục dự án. Xem [tài liệu Cursor MCP](https://docs.cursor.com/context/model-context-protocol) để biết thêm thông tin.\n> Từ Cursor 1.0, bạn có thể click nút cài đặt bên dưới để cài đặt một cú click ngay lập tức.\n\n#### Kết nối Cursor Remote Server\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Kết nối Cursor Local Server\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n<details>\n<summary>Thay thế: Sử dụng Bun</summary>\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoiYnVueCAteSBAdXBzdGFzaC9jb250ZXh0Ny1tY3AifQ%3D%3D)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Thay thế: Sử dụng Deno</summary>\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=context7&config=eyJjb21tYW5kIjoiZGVubyBydW4gLS1hbGxvdy1lbnYgLS1hbGxvdy1uZXQgbnBtOkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\n        \"run\",\n        \"--allow-env=NO_DEPRECATION,TRACE_DEPRECATION\",\n        \"--allow-net\",\n        \"npm:@upstash/context7-mcp\"\n      ]\n    }\n  }\n}\n```\n</details>\n\n</details>\n\n<details>\n<summary><b>Cài đặt trong Windsurf</b></summary>\n\nThêm cấu hình này vào file cấu hình Windsurf MCP của bạn. Xem [tài liệu Windsurf MCP](https://docs.windsurf.com/windsurf/mcp) để biết thêm thông tin.\n\n#### Kết nối Windsurf Remote Server\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Kết nối Windsurf Local Server\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong Trae</b></summary>\n\nSử dụng tính năng Add manually và điền thông tin cấu hình JSON cho MCP server đó.\nĐể biết thêm chi tiết, truy cập [tài liệu Trae](https://docs.trae.ai/ide/model-context-protocol?_lang=en).\n\n#### Kết nối Trae Remote Server\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Kết nối Trae Local Server\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong VS Code</b></summary>\n\n[<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Install in VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\nThêm cấu hình này vào file cấu hình VS Code MCP của bạn. Xem [tài liệu VS Code MCP](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) để biết thêm thông tin.\n\n#### Kết nối VS Code Remote Server\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Kết nối VS Code Local Server\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong Visual Studio 2022</b></summary>\n\nBạn có thể cấu hình Context7 MCP trong Visual Studio 2022 bằng cách làm theo [tài liệu Visual Studio MCP Servers](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\nThêm cấu hình này vào file cấu hình Visual Studio MCP của bạn (xem [tài liệu Visual Studio](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022) để biết chi tiết):\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"http\",\n        \"url\": \"https://mcp.context7.com/mcp\"\n      }\n    }\n  }\n}\n```\nHoặc, cho local server:\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"stdio\",\n        \"command\": \"npx\",\n        \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n      }\n    }\n  }\n}\n```\nĐể biết thêm thông tin và khắc phục sự cố, tham khảo [tài liệu Visual Studio MCP Servers](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\n</details>\n\n<details>\n<summary><b>Cài đặt trong Zed</b></summary>\n\nCó thể cài đặt thông qua [Zed Extensions](https://zed.dev/extensions?query=Context7) hoặc bạn có thể thêm cấu hình này vào `settings.json` của Zed. Xem [tài liệu Zed Context Server](https://zed.dev/docs/assistant/context-servers) để biết thêm thông tin.\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong Gemini CLI</b></summary>\n\nXem [Cấu hình Gemini CLI](https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/configuration.md) để biết chi tiết.\n1. Mở file cài đặt Gemini CLI. Vị trí là `~/.gemini/settings.json` (trong đó `~` là thư mục home của bạn).\n2. Thêm cấu hình sau vào object `mcpServers` trong file `settings.json` của bạn:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"httpUrl\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\nHoặc, cho local server:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nNếu object `mcpServers` không tồn tại, hãy tạo nó.\n</details>\n\n<details>\n<summary><b>Cài đặt trong Claude Code</b></summary>\n\nChạy lệnh này. Xem [tài liệu Claude Code MCP](https://docs.anthropic.com/en/docs/claude-code/mcp) để biết thêm thông tin.\n\n#### Kết nối Claude Code Local Server\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp\n```\n\n#### Kết nối Claude Code Remote Server\n\n```sh\nclaude mcp add --scope user --transport http context7 https://mcp.context7.com/mcp\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong Claude Desktop</b></summary>\n\nThêm cấu hình này vào file `claude_desktop_config.json` của Claude Desktop. Xem [tài liệu Claude Desktop MCP](https://modelcontextprotocol.io/quickstart/user) để biết thêm thông tin.\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>\n<b>Cài đặt trong Cline</b>\n</summary>\n\nBạn có thể dễ dàng cài đặt Context7 thông qua [Cline MCP Server Marketplace](https://cline.bot/mcp-marketplace) bằng cách làm theo các hướng dẫn này:\n1. Mở **Cline**.\n2. Click biểu tượng menu hamburger (☰) để vào phần **MCP Servers**.\n3. Sử dụng thanh tìm kiếm trong tab **Marketplace** để tìm _Context7_.\n4. Click nút **Install**.\n</details>\n\n<details>\n<summary><b>Cài đặt trong BoltAI</b></summary>\n\nMở trang \"Settings\" của ứng dụng, điều hướng đến \"Plugins,\" và nhập JSON sau:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nSau khi lưu, nhập trong chat `query-docs` theo sau bởi Context7 documentation ID của bạn (ví dụ: `query-docs /nuxt/ui`). Thêm thông tin có sẵn tại [trang Tài liệu BoltAI](https://docs.boltai.com/docs/plugins/mcp-servers). Cho BoltAI trên iOS, [xem hướng dẫn này](https://docs.boltai.com/docs/boltai-mobile/mcp-servers).\n</details>\n\n<details>\n<summary><b>Sử dụng Docker</b></summary>\n\nNếu bạn muốn chạy MCP server trong Docker container:\n1. **Build Docker Image:**\n   Đầu tiên, tạo `Dockerfile` trong thư mục gốc dự án (hoặc bất cứ đâu bạn thích):\n   <details>\n   <summary>Click để xem nội dung Dockerfile</summary>\n\n   ```Dockerfile\n   FROM node:18-alpine\n   WORKDIR /app\n   # Cài đặt phiên bản mới nhất globally\n   RUN npm install -g @upstash/context7-mcp\n   # Expose default port nếu cần (tùy chọn, phụ thuộc vào tương tác MCP client)\n   # EXPOSE 3000\n   # Lệnh mặc định để chạy server\n   CMD [\"context7-mcp\"]\n   ```\n   </details>\n\n   Sau đó, build image sử dụng tag (ví dụ: `context7-mcp`). **Đảm bảo Docker Desktop (hoặc Docker daemon) đang chạy.** Chạy lệnh sau trong cùng thư mục nơi bạn lưu `Dockerfile`:\n   ```bash\n   docker build -t context7-mcp .\n   ```\n2. **Cấu hình MCP Client của bạn:**\n   Cập nhật cấu hình MCP client của bạn để sử dụng lệnh Docker.\n   _Ví dụ cho cline_mcp_settings.json:_\n   ```json\n   {\n     \"mcpServers\": {\n       \"Сontext7\": {\n         \"autoApprove\": [],\n         \"disabled\": false,\n         \"timeout\": 60,\n         \"command\": \"docker\",\n         \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n         \"transportType\": \"stdio\"\n       }\n     }\n   }\n   ```\n   _Lưu ý: Đây là một ví dụ cấu hình. Vui lòng tham khảo các ví dụ cụ thể cho MCP client của bạn (như Cursor, VS Code, v.v.) ở phần trước trong README này để điều chỉnh cấu trúc (ví dụ: `mcpServers` vs `servers`). Ngoài ra, đảm bảo tên image trong `args` khớp với tag được sử dụng trong lệnh `docker build`._\n</details>\n\n<details>\n<summary><b>Cài đặt trong Windows</b></summary>\n\nCấu hình trên Windows hơi khác so với Linux hoặc macOS (_`Cline` được sử dụng trong ví dụ_). Nguyên tắc tương tự áp dụng cho các editor khác; tham khảo cấu hình của `command` và `args`.\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp@latest\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong Augment Code</b></summary>\n\nĐể cấu hình Context7 MCP trong Augment Code, bạn có thể sử dụng giao diện đồ họa hoặc cấu hình thủ công.\n\n### **A. Sử dụng Augment Code UI**\n1. Click menu hamburger.\n2. Chọn **Settings**.\n3. Điều hướng đến phần **Tools**.\n4. Click nút **+ Add MCP**.\n5. Nhập lệnh sau:\n   ```\n   npx -y @upstash/context7-mcp@latest\n   ```\n6. Đặt tên MCP: **Context7**.\n7. Click nút **Add**.\nSau khi MCP server được thêm, bạn có thể bắt đầu sử dụng các tính năng tài liệu code cập nhật của Context7 trực tiếp trong Augment Code.\n---\n\n### **B. Cấu hình Thủ công**\n1. Nhấn Cmd/Ctrl Shift P hoặc đi đến menu hamburger trong panel Augment\n2. Chọn Edit Settings\n3. Trong Advanced, click Edit in settings.json\n4. Thêm cấu hình server vào mảng `mcpServers` trong object `augment.advanced`\n\"augment.advanced\": {\n\"mcpServers\": [\n{\n\"name\": \"context7\",\n\"command\": \"npx\",\n\"args\": [\"-y\", \"@upstash/context7-mcp\"]\n}\n]\n}\nSau khi MCP server được thêm, khởi động lại editor của bạn. Nếu bạn nhận được bất kỳ lỗi nào, kiểm tra cú pháp để đảm bảo không thiếu dấu ngoặc đóng hoặc dấu phẩy.\n</details>\n\n<details>\n<summary><b>Cài đặt trong Roo Code</b></summary>\n\nThêm cấu hình này vào file cấu hình Roo Code MCP của bạn. Xem [tài liệu Roo Code MCP](https://docs.roocode.com/features/mcp/using-mcp-in-roo) để biết thêm thông tin.\n\n#### Kết nối Roo Code Remote Server\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Kết nối Roo Code Local Server\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong Zencoder</b></summary>\n\nĐể cấu hình Context7 MCP trong Zencoder, làm theo các bước sau:\n1. Đi đến menu Zencoder (...)\n2. Từ menu dropdown, chọn Agent tools\n3. Click vào Add custom MCP\n4. Thêm tên và cấu hình server từ bên dưới, và đảm bảo nhấn nút Install\n```json\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n}\n```\nSau khi MCP server được thêm, bạn có thể dễ dàng tiếp tục sử dụng nó.\n</details>\n\n<details>\n<summary><b>Cài đặt trong Amazon Q Developer CLI</b></summary>\n\nThêm cấu hình này vào file cấu hình Amazon Q Developer CLI của bạn. Xem [tài liệu Amazon Q Developer CLI](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html) để biết thêm chi tiết.\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp@latest\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong Qodo Gen</b></summary>\n\nXem [tài liệu Qodo Gen](https://docs.qodo.ai/qodo-documentation/qodo-gen/qodo-gen-chat/agentic-mode/agentic-tools-mcps) để biết thêm chi tiết.\n1. Mở panel chat Qodo Gen trong VSCode hoặc IntelliJ.\n2. Click Connect more tools.\n3. Click + Add new MCP.\n4. Thêm cấu hình sau:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong JetBrains AI Assistant</b></summary>\n\nXem [Tài liệu JetBrains AI Assistant](https://www.jetbrains.com/help/ai-assistant/configure-an-mcp-server.html) để biết thêm chi tiết.\n1. Trong JetBrains IDEs đi đến `Settings` -> `Tools` -> `AI Assistant` -> `Model Context Protocol (MCP)`\n2. Click `+ Add`.\n3. Click vào `Command` ở góc trên bên trái của dialog và chọn tùy chọn As JSON từ danh sách\n4. Thêm cấu hình này và click `OK`\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n5. Click `Apply` để lưu thay đổi.\n6. Theo cách tương tự, context7 có thể được thêm cho JetBrains Junie trong `Settings` -> `Tools` -> `Junie` -> `MCP Settings`\n</details>\n\n<details>\n<summary><b>Cài đặt trong Warp</b></summary>\n\nXem [Tài liệu Warp Model Context Protocol](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server) để biết chi tiết.\n1. Điều hướng `Settings` > `AI` > `Manage MCP servers`.\n2. Thêm MCP server mới bằng cách click nút `+ Add`.\n3. Paste cấu hình được cung cấp bên dưới:\n```json\n{\n  \"Context7\": {\n    \"command\": \"npx\",\n    \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n    \"env\": {},\n    \"working_directory\": null,\n    \"start_on_launch\": true\n  }\n}\n```\n4. Click `Save` để áp dụng thay đổi.\n</details>\n\n<details>\n<summary><b>Cài đặt trong Opencode</b></summary>\n\nThêm cấu hình này vào file cấu hình Opencode của bạn. Xem [tài liệu Opencode MCP](https://opencode.ai/docs/mcp-servers) để biết thêm thông tin.\n\n#### Kết nối Opencode Remote Server\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"enabled\": true\n  }\n}\n```\n\n#### Kết nối Opencode Local Server\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong Copilot Coding Agent</b></summary>\n\n## Sử dụng Context7 với Copilot Coding Agent\nThêm cấu hình sau vào phần `mcp` trong file cấu hình Copilot Coding Agent của bạn Repository->Settings->Copilot->Coding agent->MCP configuration:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nĐể biết thêm thông tin, xem [tài liệu GitHub chính thức](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n</details>\n\n<details>\n<summary><b>Cài đặt trong Copilot CLI</b></summary>\n\n1.  Mở file cấu hình MCP của Copilot CLI. Vị trí là `~/.copilot/mcp-config.json` (trong đó `~` là thư mục home của bạn).\n2.  Thêm nội dung sau vào đối tượng `mcpServers` trong file `mcp-config.json` của bạn:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"query-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\nHoặc, đối với server cục bộ:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"query-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\nNếu file `mcp-config.json` không tồn tại, hãy tạo nó.\n</details>\n\n<details>\n<summary><b>Cài đặt trong Kiro</b></summary>\n\nXem [Tài liệu Kiro Model Context Protocol](https://kiro.dev/docs/mcp/configuration/) để biết chi tiết.\n1. Điều hướng `Kiro` > `MCP Servers`\n2. Thêm MCP server mới bằng cách click nút `+ Add`.\n3. Paste cấu hình được cung cấp bên dưới:\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n      \"env\": {},\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n4. Click `Save` để áp dụng thay đổi.\n</details>\n\n<details>\n<summary><b>Cài đặt trong OpenAI Codex</b></summary>\n\nXem [OpenAI Codex](https://github.com/openai/codex) để biết thêm thông tin.\nThêm cấu hình sau vào cài đặt OpenAI Codex MCP server của bạn:\n\n#### Kết nối Server Cục bộ\n\n```toml\n[mcp_servers.context7]\nargs = [\"-y\", \"@upstash/context7-mcp\"]\ncommand = \"npx\"\n```\n\n#### Kết nối Server Từ xa\n\n```toml\n[mcp_servers.context7]\nurl = \"https://mcp.context7.com/mcp\"\nhttp_headers = { \"CONTEXT7_API_KEY\" = \"YOUR_API_KEY\" }\n```\n</details>\n\n<details>\n<summary><b>Cài đặt trong LM Studio</b></summary>\n\nXem [LM Studio MCP Support](https://lmstudio.ai/blog/lmstudio-v0.3.17) để biết thêm thông tin.\n\n#### Cài đặt một cú click:\n[![Add MCP Server context7 to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJdfQ%3D%3D)\n\n#### Thiết lập thủ công:\n1. Điều hướng đến `Program` (bên phải) > `Install` > `Edit mcp.json`.\n2. Paste cấu hình được cung cấp bên dưới:\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n3. Click `Save` để áp dụng thay đổi.\n4. Bật/tắt MCP server từ bên phải, dưới `Program`, hoặc bằng cách click biểu tượng plug ở cuối hộp chat.\n</details>\n\n## 🔨 Công Cụ Có Sẵn\nContext7 MCP cung cấp các công cụ sau mà LLM có thể sử dụng:\n- `resolve-library-id`: Chuyển đổi tên thư viện chung thành Context7-compatible library ID.\n  - `query` (bắt buộc): Câu hỏi hoặc nhiệm vụ của người dùng (để xếp hạng độ liên quan)\n  - `libraryName` (bắt buộc): Tên của thư viện cần tìm kiếm\n- `query-docs`: Lấy tài liệu cho thư viện sử dụng Context7-compatible library ID.\n  - `libraryId` (bắt buộc): Context7-compatible library ID chính xác (ví dụ: `/mongodb/docs`, `/vercel/next.js`)\n  - `query` (bắt buộc): Câu hỏi hoặc nhiệm vụ để lấy tài liệu liên quan\n\n## 🛟 Mẹo\n\n### Thêm Quy Tắc\n> Nếu bạn không muốn thêm `use context7` vào mỗi prompt, bạn có thể định nghĩa một quy tắc đơn giản trong file `.windsurfrules` của bạn trong Windsurf hoặc từ phần `Cursor Settings > Rules` trong Cursor (hoặc tương đương trong MCP client của bạn) để tự động gọi Context7 trên bất kỳ câu hỏi code nào:\n>\n> ```toml\n> [[calls]]\n> match = \"when the user requests code examples, setup or configuration steps, or library/API documentation\"\n> tool  = \"context7\"\n> ```\n>\n> Từ đó bạn sẽ nhận được tài liệu Context7 trong bất kỳ cuộc hội thoại liên quan nào mà không cần gõ thêm gì. Bạn có thể thêm các trường hợp sử dụng của mình vào phần match.\n\n### Sử dụng Library Id\n> Nếu bạn đã biết chính xác thư viện nào muốn sử dụng, hãy thêm Context7 ID của nó vào prompt của bạn. Cách đó, Context7 MCP server có thể bỏ qua bước matching thư viện và trực tiếp tiếp tục với việc lấy tài liệu.\n>\n> ```txt\n> implement basic authentication with supabase. use library /supabase/supabase for api and docs\n> ```\n>\n> Cú pháp dấu gạch chéo nói với MCP tool chính xác thư viện nào cần load tài liệu.\n\n## 💻 Phát Triển\nClone dự án và cài đặt dependencies:\n```bash\npnpm i\n```\nBuild:\n```bash\npnpm run build\n```\nChạy server:\n```bash\nnode packages/mcp/dist/index.js\n```\n\n### Tham Số CLI\n`context7-mcp` chấp nhận các CLI flags sau:\n- `--transport <stdio|http>` – Transport để sử dụng (`stdio` theo mặc định).\n- `--port <number>` – Port để lắng nghe khi sử dụng transport `http` (mặc định `3000`).\nVí dụ với http transport và port 8080:\n```bash\nnode packages/mcp/dist/index.js --transport http --port 8080\n```\n<details>\n<summary><b>Ví dụ Cấu hình Local</b></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7-mcp/src/index.ts\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Test với MCP Inspector</b></summary>\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n</details>\n\n## 🚨 Khắc Phục Sự Cố\n<details>\n<summary><b>Lỗi Module Not Found</b></summary>\n\nNếu bạn gặp `ERR_MODULE_NOT_FOUND`, thử sử dụng `bunx` thay vì `npx`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\nĐiều này thường giải quyết các vấn đề phân giải module trong môi trường mà `npx` không cài đặt hoặc phân giải packages đúng cách.\n</details>\n\n<details>\n<summary><b>Vấn đề ESM Resolution</b></summary>\n\nĐối với lỗi như `Error: Cannot find module 'uriTemplate.js'`, thử flag `--experimental-vm-modules`:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Vấn đề TLS/Certificate</b></summary>\n\nSử dụng flag `--experimental-fetch` để vượt qua các vấn đề liên quan đến TLS:\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-fetch\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary><b>Lỗi MCP Client Chung</b></summary>\n\n1. Thử thêm `@latest` vào tên package\n2. Sử dụng `bunx` như một thay thế cho `npx`\n3. Cân nhắc sử dụng `deno` như một thay thế khác\n4. Đảm bảo bạn đang sử dụng Node.js v18 trở lên để hỗ trợ native fetch\n</details>\n\n## ⚠️ Tuyên Bố Miễn Trừ Trách Nhiệm\nCác dự án Context7 được đóng góp bởi cộng đồng và mặc dù chúng tôi cố gắng duy trì chất lượng cao, chúng tôi không thể đảm bảo tính chính xác, đầy đủ hoặc bảo mật của tất cả tài liệu thư viện. Các dự án được liệt kê trong Context7 được phát triển và duy trì bởi các chủ sở hữu tương ứng của họ, không phải bởi Context7. Nếu bạn gặp bất kỳ nội dung đáng ngờ, không phù hợp hoặc có khả năng gây hại nào, vui lòng sử dụng nút \"Report\" trên trang dự án để thông báo cho chúng tôi ngay lập tức. Chúng tôi xem xét tất cả các báo cáo một cách nghiêm túc và sẽ xem xét nội dung được gắn cờ kịp thời để duy trì tính toàn vẹn và an toàn của nền tảng. Bằng cách sử dụng Context7, bạn thừa nhận rằng bạn làm như vậy theo quyết định và rủi ro của riêng mình.\n\n## 🤝 Kết Nối Với Chúng Tôi\nCập nhật và tham gia cộng đồng của chúng tôi:\n- 📢 Theo dõi chúng tôi trên [X](https://x.com/context7ai) để có tin tức và cập nhật mới nhất\n- 🌐 Truy cập [Website](https://context7.com) của chúng tôi\n- 💬 Tham gia [Discord Community](https://upstash.com/discord) của chúng tôi\n\n## 📺 Context7 Trên Truyền Thông\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Lịch Sử Star\n[![Star History Chart](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 Giấy Phép\nMIT\n"
  },
  {
    "path": "i18n/README.zh-CN.md",
    "content": "![Cover](https://github.com/upstash/context7/blob/master/public/cover.png?raw=true)\n\n[![安装 MCP 服务器](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n# Context7 MCP - 最新文档赋能每个提示词\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [![NPM Version](https://img.shields.io/npm/v/%40upstash%2Fcontext7-mcp?color=red)](https://www.npmjs.com/package/@upstash/context7-mcp) [![MIT licensed](https://img.shields.io/npm/l/%40upstash%2Fcontext7-mcp)](./LICENSE)\n\n[![English](https://img.shields.io/badge/docs-English-purple)](../README.md) [![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./README.zh-TW.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./README.uk.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./README.ar.md) [![Tiếng Việt](https://img.shields.io/badge/docs-Tiếng%20Việt-red)](./README.vi.md)\n\n## ❌ 不使用Context7\n\n大语言模型（LLM）依赖过时或通用的库信息。你会遇到：\n\n- ❌ 代码示例已过时，基于一年前的训练数据\n- ❌ 幻觉产生的API根本不存在\n- ❌ 针对旧版本包的通用回答\n\n## ✅ 使用Context7\n\nContext7 MCP直接从源头获取最新的、特定版本的文档和代码示例——并将它们直接放入你的提示词中。\n\n在你的提示词中附上`用context7`（或[设置规则](#添加规则)自动调用）：\n\n```txt\n创建一个Next.js中间件，检查cookies中的有效JWT，\n并将未认证用户重定向到 `/login`。用context7\n```\n\n```txt\n配置Cloudflare Worker脚本，将JSON API响应\n缓存五分钟。用context7\n```\n\nContext7将最新的代码示例和文档直接获取到你的LLM上下文中。无需切换标签页，不会因幻觉产生不存在的API，不会生成过时的代码。\n\n## 安装\n\n> [!NOTE]\n> **推荐使用API密钥**：在[context7.com/dashboard](https://context7.com/dashboard)s获取免费API密钥，使用秘钥后速率限制更高。\n\n<details>\n<summary><b>在Cursor中安装</b></summary>\n\n前往：`Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\n\n推荐将以下配置粘贴到你的Cursor `~/.cursor/mcp.json` 文件中。你也可以通过在项目文件夹中创建 `.cursor/mcp.json` 在特定项目中安装。更多信息请参阅 [Cursor MCP 文档](https://docs.cursor.com/context/model-context-protocol)。\n\n> 自Cursor 1.0起，你可以点击下面的安装按钮一键安装。\n\n#### Cursor远程服务器连接\n\n[![安装 MCP 服务器](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Cursor本地服务器连接\n\n[![安装MCP服务器](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>在Claude Code中安装</b></summary>\n\n运行以下命令。更多信息请参见[Claude Code MCP文档](https://code.claude.com/docs/zh-CN/mcp)。\n\n#### Claude Code本地服务器连接\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY\n```\n\n#### Claude Code远程服务器连接\n\n```sh\nclaude mcp add --scope user --header \"CONTEXT7_API_KEY: YOUR_API_KEY\" --transport http context7 https://mcp.context7.com/mcp\n```\n\n</details>\n\n<details>\n<summary><b>在Opencode中安装</b></summary>\n\n将此内容添加到你的Opencode配置文件中。更多信息请参见[Opencode MCP 文档](https://opencode.ai/docs/mcp-servers)。\n\n#### Opencode远程服务器连接\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"headers\": {\n      \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n    },\n    \"enabled\": true\n  }\n}\n```\n\n#### Opencode本地服务器连接\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n\n</details>\n\n**[其他IDE和客户端 →](https://context7.com/docs/resources/all-clients)**\n\n<details>\n<summary><b>OAuth认证</b></summary>\n\nContext7 MCP服务器支持OAuth 2.0认证，适用于实现了[MCP OAuth规范](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization)的MCP客户端。\n\n要使用OAuth，请在客户端配置中将端点从`/mcp`更改为`/mcp/oauth`：\n\n```diff\n- \"url\": \"https://mcp.context7.com/mcp\"\n+ \"url\": \"https://mcp.context7.com/mcp/oauth\"\n```\n\nOAuth仅适用于远程HTTP连接。对于使用stdio传输的本地MCP连接，请改用API密钥认证。\n\n</details>\n\n## 重点技巧\n\n### 添加规则\n\n为避免每次都在提示词中输入`用context7`，你可以在MCP客户端中添加规则，自动为代码相关问题调用 Context7：\n\n- **Cursor**：`Cursor Settings > Rules`\n- **Claude Code**：`CLAUDE.md`\n- 或你的 MCP 客户端中的等效设置\n\n**规则示例：**\n\n```txt\n无需我明确要求，当我需要库或API文档、生成代码、创建项目基架时或配置步骤时，始终使用Context7 MCP。\n```\n\n### 使用库 ID\n\n如果你已经确切知道要使用哪个库，请将其Context7 ID添加到你的提示词中。这样，Context7 MCP服务器可以跳过库匹配步骤，直接检索文档。\n\n```txt\n使用Supabase实现基本身份验证。用/supabase/supabase作为库ID获取API和文档。\n```\n\n斜杠语法明确告知MCP工具需加载文档的库。\n\n### 指定版本\n\n要获取特定库版本的文档，只需在提示词中提及版本：\n\n```txt\n如何设置Next.js 14中间件？用context7\n```\n\nContext7 将自动匹配适当的版本。\n\n## 可用工具\n\nContext7 MCP提供以下工具供LLM使用：\n\n- `resolve-library-id`：将通用库名称解析为Context7兼容的库ID。\n  - `query`（必需）：用户的问题或任务（用于按相关性排名结果）\n  - `libraryName`（必需）：要搜索的库名称\n\n- `query-docs`：使用Context7兼容的库ID获取库的文档。\n  - `libraryId`（必需）：精确的Context7兼容的库ID（例如 `/mongodb/docs`、`/vercel/next.js`）\n  - `query`（必需）：用于获取相关文档的问题或任务\n\n## 更多文档\n\n- [更多MCP客户端](https://context7.com/docs/resources/all-clients) - 30+客户端的安装说明\n- [添加库](https://context7.com/docs/adding-libraries) - 将你的库提交到Context7\n- [故障排除](https://context7.com/docs/resources/troubleshooting) - 常见问题和解决方案\n- [API参考](https://context7.com/docs/api-guide) - REST API 文档\n- [开发者指南](https://context7.com/docs/resources/developer) - 本地运行Context7 MCP\n\n## 免责声明\n\n1- Context7项目由社区贡献，虽然我们努力保持高质量，但我们不能保证所有库文档的准确性、完整性或安全性。Context7中列出的项目由其各自所有者开发和维护，而非由Context7开发和维护。如果你遇到任何可疑、不当或潜在有害的内容，请使用项目页面上的“Report”按钮立即通知我们。我们认真对待所有举报，并将及时审查被举报的内容，以维护我们平台的完整性和安全性。使用Context7即表示你承认自行承担风险。\n\n2- 本仓库托管MCP服务器的源代码。支持组件——API 后端、解析引擎和爬取引擎——是私有的，不包含在本仓库中。\n\n## 🤝 与我们联系\n\n保持更新并加入我们的社区：\n\n- 📢 在[X](https://x.com/context7ai)上关注我们获取最新新闻和更新\n- 🌐 访问我们的[网站](https://context7.com)\n- 💬 加入我们的[Discord社区](https://upstash.com/discord)\n\n## 📺 Context7媒体报道\n\n- [Better Stack：\"免费工具让Cursor智能10倍\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin：\"这绝对是AI编码助手的最佳MCP服务器\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers：\"Context7 + SequentialThinking MCP：这是AGI吗？\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO：\"Context7：新的MCP AI代理更新\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu：\"Context 7 MCP：即时获取文档 + VS Code配置方法\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers：\"Context7：将改变AI编码的新MCP服务器\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing：\"Context7 + Cline & RooCode：这个MCP服务器让CLINE效果提升100倍！\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel：\"5个让编码更爽的MCP服务器（即插即用）\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Star 历史\n\n[![Star历史图表](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 许可证\n\nMIT\n"
  },
  {
    "path": "i18n/README.zh-TW.md",
    "content": "![Cover](https://github.com/upstash/context7/blob/master/public/cover.png?raw=true)\n\n[![安裝 MCP 伺服器](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n# Context7 MCP - 即時更新的程式碼文件，適用於任何提示\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [![NPM Version](https://img.shields.io/npm/v/%40upstash%2Fcontext7-mcp?color=red)](https://www.npmjs.com/package/@upstash/context7-mcp) [![MIT licensed](https://img.shields.io/npm/l/%40upstash%2Fcontext7-mcp)](./LICENSE)\n\n[![English](https://img.shields.io/badge/docs-English-purple)](../README.md) [![简体中文](https://img.shields.io/badge/docs-简体中文-yellow)](./README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./README.ru.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./README.uk.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./README.ar.md) [![Tiếng Việt](https://img.shields.io/badge/docs-Tiếng%20Việt-red)](./README.vi.md)\n\n## ❌ 沒有 Context7\n\n大型語言模型（LLM）依賴過時或通用的函式庫資訊。你會遇到：\n\n- ❌ 程式碼範例已過時，基於一年前的訓練資料\n- ❌ 產生根本不存在的幻覺 API\n- ❌ 針對舊版本套件的通用回答\n\n## ✅ 有了 Context7\n\nContext7 MCP 直接從來源取得最新的、特定版本的文件與程式碼範例——並直接放入你的提示中。\n\n在你的提示中加入 `use context7`（或[設定規則](#新增規則)自動調用）：\n\n```txt\n建立一個 Next.js 中介軟體，檢查 cookies 中的有效 JWT，\n並將未認證使用者重新導向至 `/login`。use context7\n```\n\n```txt\n設定 Cloudflare Worker 腳本，將 JSON API 回應\n快取五分鐘。use context7\n```\n\nContext7 將最新的程式碼範例與文件直接取得到你的 LLM 上下文中。不需切換分頁、不會產生不存在的幻覺 API、不會產生過時的程式碼。\n\n## 安裝\n\n> [!NOTE]\n> **建議使用 API 金鑰**：在 [context7.com/dashboard](https://context7.com/dashboard) 取得免費 API 金鑰，可獲得更高的請求速率限制。\n\n<details>\n<summary><b>在 Cursor 中安裝</b></summary>\n\n前往：`Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\n\n建議將下列設定貼到你的 Cursor `~/.cursor/mcp.json` 檔案中。你也可以透過在專案資料夾中建立 `.cursor/mcp.json` 在特定專案中安裝。更多資訊請參閱 [Cursor MCP 文件](https://docs.cursor.com/context/model-context-protocol)。\n\n> 自 Cursor 1.0 起，你可以點擊下方的安裝按鈕進行即時一鍵安裝。\n\n#### Cursor 遠端伺服器連線\n\n[![安裝 MCP 伺服器](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Cursor 本地伺服器連線\n\n[![安裝 MCP 伺服器](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>在 Claude Code 中安裝</b></summary>\n\n執行下列指令。更多資訊請參見 [Claude Code MCP 文件](https://code.claude.com/docs/en/mcp)。\n\n#### Claude Code 本地伺服器連線\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY\n```\n\n#### Claude Code 遠端伺服器連線\n\n```sh\nclaude mcp add --scope user --header \"CONTEXT7_API_KEY: YOUR_API_KEY\" --transport http context7 https://mcp.context7.com/mcp\n```\n\n</details>\n\n<details>\n<summary><b>在 Opencode 中安裝</b></summary>\n\n將此內容加入你的 Opencode 設定檔。更多資訊請參見 [Opencode MCP 文件](https://opencode.ai/docs/mcp-servers)。\n\n#### Opencode 遠端伺服器連線\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"headers\": {\n      \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n    },\n    \"enabled\": true\n  }\n}\n```\n\n#### Opencode 本地伺服器連線\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n\n</details>\n\n**[其他 IDE 和客戶端 →](https://context7.com/docs/resources/all-clients)**\n\n<details>\n<summary><b>OAuth 認證</b></summary>\n\nContext7 MCP 伺服器支援 OAuth 2.0 認證，適用於實作了 [MCP OAuth 規範](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization)的 MCP 客戶端。\n\n要使用 OAuth，請在客戶端設定中將端點從 `/mcp` 更改為 `/mcp/oauth`：\n\n```diff\n- \"url\": \"https://mcp.context7.com/mcp\"\n+ \"url\": \"https://mcp.context7.com/mcp/oauth\"\n```\n\nOAuth 僅適用於遠端 HTTP 連線。對於使用 stdio 傳輸的本地 MCP 連線，請改用 API 金鑰認證。\n\n</details>\n\n## 重要提示\n\n### 新增規則\n\n為避免每次都在提示中輸入 `use context7`，你可以在 MCP 客戶端中新增規則，自動為程式碼相關問題調用 Context7：\n\n- **Cursor**：`Cursor Settings > Rules`\n- **Claude Code**：`CLAUDE.md`\n- 或你的 MCP 客戶端中的等效設定\n\n**規則範例：**\n\n```txt\n當我需要函式庫/API 文件、程式碼產生、設定或設定步驟時，始終使用 Context7 MCP，無需我明確要求。\n```\n\n### 使用函式庫 ID\n\n如果你已經確切知道要使用哪個函式庫，請將其 Context7 ID 加入你的提示中。這樣，Context7 MCP 伺服器可以跳過函式庫匹配步驟，直接取得文件。\n\n```txt\n使用 Supabase 實作基本身分驗證。use library /supabase/supabase 取得 API 和文件。\n```\n\n斜線語法告訴 MCP 工具確切要為哪個函式庫載入文件。\n\n### 指定版本\n\n要取得特定函式庫版本的文件，只需在提示中提及版本：\n\n```txt\n如何設定 Next.js 14 中介軟體？use context7\n```\n\nContext7 將自動匹配適當的版本。\n\n## 可用工具\n\nContext7 MCP 提供下列 LLM 可使用的工具：\n\n- `resolve-library-id`：將通用函式庫名稱解析為 Context7 相容的函式庫 ID。\n  - `query`（必填）：使用者的問題或任務（用於按相關性排名結果）\n  - `libraryName`（必填）：要搜尋的函式庫名稱\n\n- `query-docs`：使用 Context7 相容的函式庫 ID 取得函式庫的文件。\n  - `libraryId`（必填）：精確的 Context7 相容函式庫 ID（例如 `/mongodb/docs`、`/vercel/next.js`）\n  - `query`（必填）：用於取得相關文件的問題或任務\n\n## 更多文件\n\n- [更多 MCP 客戶端](https://context7.com/docs/resources/all-clients) - 30+ 客戶端的安裝說明\n- [新增函式庫](https://context7.com/docs/adding-libraries) - 將你的函式庫提交到 Context7\n- [疑難排解](https://context7.com/docs/resources/troubleshooting) - 常見問題與解決方案\n- [API 參考](https://context7.com/docs/api-guide) - REST API 文件\n- [開發者指南](https://context7.com/docs/resources/developer) - 本地執行 Context7 MCP\n\n## 免責聲明\n\n1- Context7 專案由社群貢獻，雖然我們致力於維持高品質，但我們無法保證所有函式庫文件的準確性、完整性或安全性。Context7 中列出的專案由其各自擁有者開發和維護，而非由 Context7 開發和維護。如果你遇到任何可疑、不當或潛在有害的內容，請使用專案頁面上的「檢舉」按鈕立即通知我們。我們認真對待所有檢舉，並將及時審查標記的內容，以維護我們平台的完整性和安全性。使用 Context7 即表示你承認自行承擔風險。\n\n2- 本儲存庫託管 MCP 伺服器的原始碼。支援元件——API 後端、解析引擎和爬取引擎——是私有的，不包含在本儲存庫中。\n\n## 🤝 與我們聯繫\n\n保持更新並加入我們的社群：\n\n- 📢 在 [X](https://x.com/context7ai) 上追蹤我們取得最新消息和更新\n- 🌐 造訪我們的[網站](https://context7.com)\n- 💬 加入我們的 [Discord 社群](https://upstash.com/discord)\n\n## 📺 Context7 媒體報導\n\n- [Better Stack：「免費工具讓 Cursor 智慧 10 倍」](https://youtu.be/52FC3qObp9E)\n- [Cole Medin：「這絕對是 AI 程式助理最強 MCP 伺服器」](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers：「Context7 + SequentialThinking MCPs：這是 AGI 嗎？」](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO：「Context7：全新 MCP AI 代理更新」](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu：「Context 7 MCP：即時取得文件 + VS Code 設定」](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers：「Context7：將改變 AI 程式開發的新 MCP 伺服器」](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing：「Context7 + Cline & RooCode：這個 MCP 伺服器讓 CLINE 效率提升 100 倍！」](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel：「5 個讓程式開發如虎添翼的 MCP 伺服器（即插即用）」](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Star 歷史\n\n[![Star 歷史圖表](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 授權\n\nMIT\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@upstash/context7\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"Context7 monorepo - Documentation tools and SDKs\",\n  \"workspaces\": [\n    \"packages/*\"\n  ],\n  \"scripts\": {\n    \"build\": \"pnpm -r run build\",\n    \"build:sdk\": \"pnpm --filter @upstash/context7-sdk build\",\n    \"build:mcp\": \"pnpm --filter @upstash/context7-mcp build\",\n    \"build:ai-sdk\": \"pnpm --filter @upstash/context7-tools-ai-sdk build\",\n    \"typecheck\": \"pnpm -r run typecheck\",\n    \"test\": \"pnpm -r run test\",\n    \"test:sdk\": \"pnpm --filter @upstash/context7-sdk test\",\n    \"test:tools-ai-sdk\": \"pnpm --filter @upstash/context7-tools-ai-sdk test\",\n    \"clean\": \"pnpm -r run clean && rm -rf node_modules\",\n    \"lint\": \"pnpm -r run lint\",\n    \"lint:check\": \"pnpm -r run lint:check\",\n    \"format\": \"pnpm -r run format\",\n    \"format:check\": \"pnpm -r run format:check\",\n    \"release\": \"pnpm build && changeset publish\",\n    \"release:snapshot\": \"changeset version --snapshot canary && pnpm build && changeset publish --tag canary --no-git-tag\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/upstash/context7.git\"\n  },\n  \"keywords\": [\n    \"modelcontextprotocol\",\n    \"mcp\",\n    \"context7\",\n    \"vibe-coding\",\n    \"developer tools\",\n    \"documentation\",\n    \"context\"\n  ],\n  \"author\": \"abdush\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/upstash/context7/issues\"\n  },\n  \"homepage\": \"https://github.com/upstash/context7#readme\",\n  \"devDependencies\": {\n    \"@changesets/cli\": \"^2.29.7\",\n    \"@types/node\": \"^25.0.3\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.28.0\",\n    \"@typescript-eslint/parser\": \"^8.28.0\",\n    \"eslint\": \"^9.34.0\",\n    \"eslint-config-prettier\": \"^10.1.1\",\n    \"eslint-plugin-prettier\": \"^5.2.5\",\n    \"prettier\": \"^3.6.2\",\n    \"typescript\": \"^5.8.2\",\n    \"typescript-eslint\": \"^8.28.0\"\n  },\n  \"dependencies\": {\n    \"@inquirer/core\": \"^11.1.1\",\n    \"@inquirer/type\": \"^4.0.3\"\n  }\n}\n"
  },
  {
    "path": "packages/cli/.gitignore",
    "content": "node_modules/\ndist/\n.env\n"
  },
  {
    "path": "packages/cli/CHANGELOG.md",
    "content": "# Changelog\n\n## 0.3.7\n\n### Patch Changes\n\n- 93eaf54: Remove shell:true from spawn call in generate command to prevent command injection via EDITOR env variable\n- 8c5cf7d: Prevent directory traversal in skill file installation by validating resolved paths stay within the target directory\n\n## 0.3.6\n\n### Patch Changes\n\n- fae6127: Add active teamspace name to whoami command output\n- 4b63117: Reorder setup mode choices to show MCP server first\n- 18b3292: Add token refresh support, centralize auth constants, switch whoami to internal API endpoint with teamspace display, and add unit tests for CLI auth utilities and commands\n\n## 0.3.5\n\n### Patch Changes\n\n- 7e60d05: - feat(cli): track install count events when skills are installed via `ctx7 setup`\n\n## 0.3.4\n\n### Patch Changes\n\n- 62dc278: - feat(cli): enumerate popularity with a 4-star scale in skill search, install, and suggest results\n  - feat(cli): show install count range and trust score in skill hover details\n  - fix(cli): rename \"docs\" skill to \"find-docs\" in setup output and prompts\n- 04130b5: Consolidate skills under /skills with canonical sources: rename docs→find-docs, ctx7-cli→context7-cli, add context7-mcp as canonical MCP skill. MCP setup now downloads skill from GitHub instead of using hardcoded content.\n- d418405: Add CLI mode to ctx7 setup for installing the docs skill without MCP configuration\n\n## 0.3.3\n\n### Patch Changes\n\n- 31b4fb8: Align CLI library output format with MCP: use labeled fields (Title, Context7-compatible library ID, Description, Code Snippets, Source Reputation, Benchmark Score, Versions) and categorical reputation labels (High/Medium/Low/Unknown) instead of numeric trust scores\n- 9de3f06: Display warning when public library access filter is being used to filter libraries.\n- 05a4406: Remove default selection of Universal agent target during skills install prompt\n- 9aae852: Show source repository next to skill name in search and suggest results for easier disambiguation\n\n## 0.3.2\n\n### Patch Changes\n\n- df60e3e: Add `library` and `docs` commands for querying library documentation from the terminal\n\n## 0.3.1\n\n### Patch Changes\n\n- c66950a: Install documentation-lookup skill during `ctx7 setup`\n\n## 0.3.0\n\n### Minor Changes\n\n- 3d66191: Add `ctx7 setup` command for configuring Context7 MCP and rules across Claude Code, Cursor, and OpenCode\n\n## 0.2.4\n\n### Patch Changes\n\n- 4663c15: - Adopt `.agents/skills` as universal install target, supporting multiple agents with a single installation\n  - Replace `--codex`, `--opencode`, and `--amp` flags with single `--universal` flag\n  - Improve checkbox UI with aligned column headers for better readability\n\n## 0.2.3\n\n### Patch Changes\n\n- 0981656: Add `skills suggest` command that scans your project's dependencies (package.json, requirements.txt, pyproject.toml) and recommends relevant skills. Results show install counts, trust scores, and which dependency each skill matches.\n\n## 0.2.2\n\n### Patch Changes\n\n- 6328ed1: Skill search & generate command improvements:\n  - Add \"Installs\" and \"Trust(0-10)\" columns to skill search results with aligned column headers\n  - Auto-login via OAuth when the generate command requires authentication instead of showing an error\n  - Reorder question options so the recommended choice always appears first with a \"✓ Recommended\" badge\n  - Add \"View skill\" action that opens generated content in the user's default editor (`$EDITOR`)\n  - Revamp generate wizard copy: do/don't examples for skill descriptions, rename \"libraries\" to \"sources\", and clarify follow-up question and generation spinner text\n\n## 0.2.1\n\n### Patch Changes\n\n- 2f7cc42: Show exact install counts instead of rounded values, sort skills by install count in the install command, and display \"installs\" column header inline with the prompt\n- 85b905e: Add CLI telemetry for usage metrics collection (commands, searches, installs, generation feedback) via fire-and-forget events to /api/v2/cli/events. Respects CTX7_TELEMETRY_DISABLED env var.\n\n## 0.2.0\n\n### Minor Changes\n\n- 8ba484c: Add AI-powered skill generation with `skills generate` command, including library search, clarifying questions, real-time query progress, feedback loop, and weekly quota management.\n- aacfd31: Add OAuth 2.0 authentication with login, logout, and whoami commands.\n\n### Patch Changes\n\n- 572c3ca: Simplify `skills list` command to show all detected IDE skill directories without prompts.\n\n## 0.1.5\n\n### Improvements\n\n- Improved skill selection UX with metadata panel showing Skill, Repo, and Description\n- Clickable links in metadata (Skill → context7.com, Repo → GitHub)\n- Display install counts next to skill names (e.g., `↓100+`, `↓50+`)\n- Numbered list items for easier reference\n- Select hovered item on Enter without needing to Space-select first\n- Green highlight for hovered row\n- Fix circular scrolling - navigation now stops at list boundaries\n\n## 0.1.4\n\n- Add prompt injection detection with warning messages for blocked skills\n\n## 0.1.3\n\n- Auto-detect installed IDE configurations in project/global directories\n- Add confirmation prompt before installing to detected locations\n\n## 0.1.0\n\n- Initial stable release\n- Commands: `install`, `search`, `list`, `remove`, `info`\n- Multi-IDE support: Claude, Cursor, Codex, OpenCode, Amp, Antigravity\n- Global and project-level skill installation\n- Symlink support (Claude gets original files, others get symlinks)\n- Short aliases: `si`, `ss`\n- Single skill installation via `ctx7 skills install /owner/repo skill-name`\n- Installation tracking metrics\n"
  },
  {
    "path": "packages/cli/README.md",
    "content": "# ctx7\n\nCLI for [Context7](https://context7.com) - query up-to-date library documentation and manage AI coding skills.\n\nSkills are reusable prompt instructions that enhance your AI coding assistant with specialized capabilities like working with specific frameworks, libraries, or coding patterns.\n\n## Installation\n\n```bash\n# Run directly with npx (no install needed)\nnpx ctx7\n\n# Or install globally\nnpm install -g ctx7\n```\n\n## Quick Start\n\n```bash\n# Set up Context7 MCP for your coding agents\nctx7 setup\n\n# Target a specific agent\nctx7 setup --cursor\nctx7 setup --claude\nctx7 setup --opencode\n```\n\n### Library Documentation\n\n```bash\n# Find a library\nctx7 library react\nctx7 library nextjs \"app router\"\n\n# Get documentation\nctx7 docs /facebook/react \"useEffect cleanup\"\nctx7 docs /vercel/next.js \"middleware\"\n```\n\n### Skills\n\n```bash\n# Search for skills\nctx7 skills search pdf\n\n# Install a skill\nctx7 skills install /anthropics/skills pdf\n\n# Generate a custom skill with AI\nctx7 skills generate\n\n# List installed skills\nctx7 skills list --claude\n```\n\n## Usage\n\n### Find a library\n\nResolve a library name to a Context7 library ID.\n\n```bash\nctx7 library react\nctx7 library nextjs \"app router setup\"\nctx7 library prisma \"database relations\"\n\n# Output as JSON\nctx7 library react --json\n```\n\n### Query documentation\n\nFetch documentation for a specific library using its Context7 ID.\n\n```bash\nctx7 docs /facebook/react \"useEffect cleanup\"\nctx7 docs /vercel/next.js \"middleware authentication\"\nctx7 docs /prisma/prisma \"one-to-many relations\"\n\n# Output as JSON\nctx7 docs /facebook/react \"hooks\" --json\n```\n\n### Setup\n\nConfigure Context7 MCP and a rule for your AI coding agents. Authenticates via OAuth, generates an API key, and writes the config.\n\n```bash\n# Interactive (prompts for agent selection)\nctx7 setup\n\n# Target specific agents\nctx7 setup --cursor\nctx7 setup --claude\nctx7 setup --opencode\n\n# Use an existing API key instead of OAuth\nctx7 setup --api-key YOUR_API_KEY\n\n# Use OAuth endpoint (IDE handles auth flow)\nctx7 setup --oauth\n\n# Configure for current project only (default is global)\nctx7 setup --project\n\n# Skip prompts\nctx7 setup --yes\n```\n\n### Generate skills\n\nGenerate custom skills tailored to your use case using AI. Requires authentication.\n\n```bash\n# Log in first\nctx7 login\n\n# Generate a skill (interactive)\nctx7 skills generate\n\n# Short aliases\nctx7 skills gen\nctx7 skills g\n\n# Generate and install to a specific client\nctx7 skills generate --cursor\nctx7 skills generate --claude\nctx7 skills generate --universal\n\n# Generate globally\nctx7 skills generate --global\n```\n\nThe generate flow:\n\n1. Describe the expertise you want (e.g., \"OAuth authentication with NextAuth.js\")\n2. Select relevant libraries from search results\n3. Answer 3 clarifying questions to focus the skill\n4. Review the generated skill, request changes if needed, then install\n\nWeekly generation limits apply: free accounts get 6 generations/week, Pro accounts get 10.\n\n### Authentication\n\nLog in to access skill generation and other authenticated features.\n\n```bash\n# Log in (opens browser for OAuth)\nctx7 login\n\n# Check login status\nctx7 whoami\n\n# Log out\nctx7 logout\n```\n\n### Install skills\n\nInstall skills from a project repository to your AI coding assistant's skills directory.\n\n```bash\n# Install all skills from a project (interactive selection)\nctx7 skills install /anthropics/skills\n\n# Install a specific skill\nctx7 skills install /anthropics/skills pdf\n\n# Install multiple skills at once\nctx7 skills install /anthropics/skills pdf commit\n\n# Install to a specific client\nctx7 skills install /anthropics/skills pdf --cursor\nctx7 skills install /anthropics/skills pdf --claude\nctx7 skills install /anthropics/skills pdf --universal\n\n# Install globally (home directory instead of current project)\nctx7 skills install /anthropics/skills pdf --global\n```\n\n### Search for skills\n\nFind skills across all indexed projects in the registry.\n\n```bash\nctx7 skills search pdf\nctx7 skills search typescript\nctx7 skills search react testing\n```\n\n### List installed skills\n\nView skills installed in your project or globally.\n\n```bash\nctx7 skills list\nctx7 skills list --claude\nctx7 skills list --cursor\nctx7 skills list --universal\nctx7 skills list --global\n```\n\n### Show skill information\n\nGet details about available skills in a project.\n\n```bash\nctx7 skills info /anthropics/skills\n```\n\n### Remove a skill\n\nUninstall a skill from your project.\n\n```bash\nctx7 skills remove pdf\nctx7 skills remove pdf --claude\nctx7 skills remove pdf --universal\nctx7 skills remove pdf --global\n```\n\n## Supported Clients\n\nThe CLI automatically detects which AI coding assistants you have installed and offers to install skills for them:\n\n| Client | Skills Directory |\n|--------|-----------------|\n| Universal (Amp, Codex, Gemini CLI, GitHub Copilot, OpenCode + more) | `.agents/skills/` |\n| Claude Code | `.claude/skills/` |\n| Cursor | `.cursor/skills/` |\n| Antigravity | `.agent/skills/` |\n\n## Shortcuts\n\nFor faster usage, the CLI provides short aliases:\n\n```bash\nctx7 si /anthropics/skills pdf   # skills install\nctx7 ss pdf                       # skills search\nctx7 skills gen                   # skills generate\nctx7 skills g                     # skills generate\n```\n\n## Disabling Telemetry\n\nThe CLI collects anonymous usage data to help improve the product. To disable telemetry, set the `CTX7_TELEMETRY_DISABLED` environment variable:\n\n```bash\n# For a single command\nCTX7_TELEMETRY_DISABLED=1 ctx7 skills search pdf\n\n# Or export in your shell profile (~/.bashrc, ~/.zshrc, etc.)\nexport CTX7_TELEMETRY_DISABLED=1\n```\n\n## Learn More\n\nVisit [context7.com](https://context7.com) to browse the skills registry and discover available skills.\n"
  },
  {
    "path": "packages/cli/eslint.config.js",
    "content": "import { defineConfig } from \"eslint/config\";\nimport tseslint from \"typescript-eslint\";\nimport eslintPluginPrettier from \"eslint-plugin-prettier\";\n\nexport default defineConfig(\n  {\n    // Base ESLint configuration\n    ignores: [\"node_modules/**\", \"build/**\", \"dist/**\", \".git/**\", \".github/**\", \"tsup.config.ts\", \"vitest.config.ts\"],\n  },\n  {\n    files: [\"**/*.ts\", \"**/*.tsx\"],\n    languageOptions: {\n      ecmaVersion: 2020,\n      sourceType: \"module\",\n      parser: tseslint.parser,\n      parserOptions: {\n        project: \"./tsconfig.json\",\n        tsconfigRootDir: import.meta.dirname,\n      },\n      globals: {\n        // Add Node.js globals\n        process: \"readonly\",\n        require: \"readonly\",\n        module: \"writable\",\n        console: \"readonly\",\n      },\n    },\n    // Settings for all files\n    linterOptions: {\n      reportUnusedDisableDirectives: true,\n    },\n    plugins: {\n      \"@typescript-eslint\": tseslint.plugin,\n      prettier: eslintPluginPrettier,\n    },\n    rules: {\n      // TypeScript recommended rules\n      ...tseslint.configs.recommended.rules,\n      // TypeScript rules\n      \"@typescript-eslint/explicit-module-boundary-types\": \"off\",\n      \"@typescript-eslint/no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\" }],\n      \"@typescript-eslint/no-explicit-any\": \"warn\",\n      // Prettier integration\n      \"prettier/prettier\": \"error\",\n    },\n  }\n);\n"
  },
  {
    "path": "packages/cli/package.json",
    "content": "{\n  \"name\": \"ctx7\",\n  \"version\": \"0.3.7\",\n  \"description\": \"Context7 CLI - Manage AI coding skills and documentation context\",\n  \"type\": \"module\",\n  \"bin\": {\n    \"ctx7\": \"./dist/index.js\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsup\",\n    \"dev\": \"tsup --watch\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"lint\": \"eslint src --fix\",\n    \"lint:check\": \"eslint src\",\n    \"format\": \"prettier --write src\",\n    \"format:check\": \"prettier --check src\",\n    \"clean\": \"rm -rf dist node_modules\",\n    \"test\": \"vitest run\",\n    \"test:watch\": \"vitest\"\n  },\n  \"dependencies\": {\n    \"@inquirer/prompts\": \"^8.2.0\",\n    \"commander\": \"^13.1.0\",\n    \"figlet\": \"^1.9.4\",\n    \"open\": \"^10.1.0\",\n    \"ora\": \"^9.0.0\",\n    \"picocolors\": \"^1.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/figlet\": \"^1.7.0\",\n    \"@types/node\": \"^22.19.1\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.28.0\",\n    \"@typescript-eslint/parser\": \"^8.28.0\",\n    \"eslint\": \"^9.34.0\",\n    \"eslint-plugin-prettier\": \"^5.2.5\",\n    \"prettier\": \"^3.6.2\",\n    \"tsup\": \"^8.5.0\",\n    \"typescript\": \"^5.8.2\",\n    \"typescript-eslint\": \"^8.28.0\",\n    \"vitest\": \"^4.0.13\"\n  },\n  \"keywords\": [\n    \"context7\",\n    \"cli\",\n    \"ai\",\n    \"skills\",\n    \"documentation\",\n    \"mcp\"\n  ],\n  \"author\": \"Upstash\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/upstash/context7.git\",\n    \"directory\": \"packages/cli\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/upstash/context7/issues\"\n  },\n  \"homepage\": \"https://context7.com\",\n  \"engines\": {\n    \"node\": \">=18\"\n  }\n}\n"
  },
  {
    "path": "packages/cli/src/__tests__/auth-commands.test.ts",
    "content": "import { describe, test, expect, vi, beforeEach, afterEach } from \"vitest\";\nimport { Command } from \"commander\";\n\nconst mockGetValidAccessToken = vi.fn();\nconst mockClearTokens = vi.fn();\nconst mockSaveTokens = vi.fn();\nconst mockGeneratePKCE = vi.fn();\nconst mockGenerateState = vi.fn();\nconst mockCreateCallbackServer = vi.fn();\nconst mockExchangeCodeForTokens = vi.fn();\nconst mockBuildAuthorizationUrl = vi.fn();\n\nvi.mock(\"../utils/auth.js\", () => ({\n  getValidAccessToken: (...args: unknown[]) => mockGetValidAccessToken(...args),\n  clearTokens: (...args: unknown[]) => mockClearTokens(...args),\n  saveTokens: (...args: unknown[]) => mockSaveTokens(...args),\n  generatePKCE: (...args: unknown[]) => mockGeneratePKCE(...args),\n  generateState: (...args: unknown[]) => mockGenerateState(...args),\n  createCallbackServer: (...args: unknown[]) => mockCreateCallbackServer(...args),\n  exchangeCodeForTokens: (...args: unknown[]) => mockExchangeCodeForTokens(...args),\n  buildAuthorizationUrl: (...args: unknown[]) => mockBuildAuthorizationUrl(...args),\n}));\n\nvi.mock(\"../utils/tracking.js\", () => ({\n  trackEvent: vi.fn(),\n}));\n\nconst mockSpinner = {\n  start: vi.fn().mockReturnThis(),\n  stop: vi.fn().mockReturnThis(),\n  succeed: vi.fn().mockReturnThis(),\n  fail: vi.fn().mockReturnThis(),\n  text: \"\",\n};\nvi.mock(\"ora\", () => ({ default: () => mockSpinner }));\n\nconst mockOpen = vi.fn().mockResolvedValue(undefined);\nvi.mock(\"open\", () => ({ default: (...args: unknown[]) => mockOpen(...args) }));\n\nvi.mock(\"../constants.js\", () => ({ CLI_CLIENT_ID: \"test-client-id\" }));\nvi.mock(\"../utils/api.js\", () => ({ getBaseUrl: () => \"https://test.context7.com\" }));\n\nimport { registerAuthCommands, performLogin } from \"../commands/auth.js\";\nimport { trackEvent } from \"../utils/tracking.js\";\n\nlet logOutput: string[];\nlet errorOutput: string[];\nlet originalExit: typeof process.exit;\n\nbeforeEach(() => {\n  vi.clearAllMocks();\n  logOutput = [];\n  errorOutput = [];\n  vi.spyOn(console, \"log\").mockImplementation((...args: unknown[]) => {\n    logOutput.push(args.join(\" \"));\n  });\n  vi.spyOn(console, \"error\").mockImplementation((...args: unknown[]) => {\n    errorOutput.push(args.join(\" \"));\n  });\n  originalExit = process.exit;\n  process.exit = vi.fn() as never;\n\n  vi.stubGlobal(\n    \"fetch\",\n    vi.fn(() => {\n      throw new Error(\"fetch not mocked\");\n    })\n  );\n});\n\nafterEach(() => {\n  process.exit = originalExit;\n  vi.unstubAllGlobals();\n  vi.restoreAllMocks();\n});\n\nasync function runCommand(...args: string[]): Promise<void> {\n  const program = new Command();\n  program.exitOverride(); // throw instead of process.exit on commander errors\n  registerAuthCommands(program);\n  await program.parseAsync([\"node\", \"test\", ...args]);\n}\n\ndescribe(\"login command\", () => {\n  test(\"skips login when valid token exists\", async () => {\n    mockGetValidAccessToken.mockResolvedValue(\"existing-token\");\n    await runCommand(\"login\");\n    expect(logOutput.some((l) => l.includes(\"already logged in\"))).toBe(true);\n  });\n\n  test(\"tracks login event\", async () => {\n    mockGetValidAccessToken.mockResolvedValue(\"existing-token\");\n    await runCommand(\"login\");\n    expect(trackEvent).toHaveBeenCalledWith(\"command\", { name: \"login\" });\n  });\n\n  test(\"calls process.exit(1) when login fails\", async () => {\n    mockGetValidAccessToken.mockResolvedValue(null);\n    mockClearTokens.mockReturnValue(false);\n    // Mock performLogin to fail by making createCallbackServer reject\n    mockGeneratePKCE.mockReturnValue({ codeVerifier: \"v\", codeChallenge: \"c\" });\n    mockGenerateState.mockReturnValue(\"state\");\n    mockCreateCallbackServer.mockReturnValue({\n      port: Promise.resolve(52417),\n      result: Promise.reject(new Error(\"timeout\")),\n      close: vi.fn(),\n    });\n    mockBuildAuthorizationUrl.mockReturnValue(\"https://example.com/auth\");\n\n    await runCommand(\"login\").catch(() => {});\n    expect(process.exit).toHaveBeenCalledWith(1);\n  });\n});\n\ndescribe(\"logout command\", () => {\n  test(\"logs success when tokens were cleared\", async () => {\n    mockClearTokens.mockReturnValue(true);\n    await runCommand(\"logout\");\n    expect(logOutput.some((l) => l.includes(\"Logged out successfully\"))).toBe(true);\n  });\n\n  test(\"logs 'not logged in' when no tokens existed\", async () => {\n    mockClearTokens.mockReturnValue(false);\n    await runCommand(\"logout\");\n    expect(logOutput.some((l) => l.includes(\"You are not logged in\"))).toBe(true);\n  });\n\n  test(\"tracks logout event\", async () => {\n    mockClearTokens.mockReturnValue(false);\n    await runCommand(\"logout\");\n    expect(trackEvent).toHaveBeenCalledWith(\"command\", { name: \"logout\" });\n  });\n});\n\ndescribe(\"whoami command\", () => {\n  test(\"shows 'Not logged in' when no valid token\", async () => {\n    mockGetValidAccessToken.mockResolvedValue(null);\n    await runCommand(\"whoami\");\n    expect(logOutput.some((l) => l.includes(\"Not logged in\"))).toBe(true);\n  });\n\n  test(\"fetches and displays user info when logged in\", async () => {\n    mockGetValidAccessToken.mockResolvedValue(\"valid-token\");\n    vi.stubGlobal(\n      \"fetch\",\n      vi.fn().mockResolvedValue({\n        ok: true,\n        json: () =>\n          Promise.resolve({\n            success: true,\n            name: \"Test User\",\n            email: \"test@example.com\",\n            teamspace: null,\n          }),\n      })\n    );\n\n    await runCommand(\"whoami\");\n    expect(logOutput.some((l) => l.includes(\"Logged in\"))).toBe(true);\n    expect(logOutput.some((l) => l.includes(\"Test User\"))).toBe(true);\n    expect(logOutput.some((l) => l.includes(\"test@example.com\"))).toBe(true);\n  });\n\n  test(\"shows session expired hint when fetch fails\", async () => {\n    mockGetValidAccessToken.mockResolvedValue(\"valid-token\");\n    vi.stubGlobal(\n      \"fetch\",\n      vi.fn().mockResolvedValue({\n        ok: false,\n        json: () => Promise.reject(new Error(\"fail\")),\n      })\n    );\n\n    await runCommand(\"whoami\");\n    expect(logOutput.some((l) => l.includes(\"Session may be expired\"))).toBe(true);\n  });\n\n  test(\"tracks whoami event\", async () => {\n    mockGetValidAccessToken.mockResolvedValue(null);\n    await runCommand(\"whoami\");\n    expect(trackEvent).toHaveBeenCalledWith(\"command\", { name: \"whoami\" });\n  });\n});\n\ndescribe(\"performLogin\", () => {\n  test(\"returns access_token on success\", async () => {\n    const mockClose = vi.fn();\n    mockGeneratePKCE.mockReturnValue({ codeVerifier: \"verifier\", codeChallenge: \"challenge\" });\n    mockGenerateState.mockReturnValue(\"state\");\n    mockCreateCallbackServer.mockReturnValue({\n      port: Promise.resolve(52417),\n      result: Promise.resolve({ code: \"auth-code\", state: \"state\" }),\n      close: mockClose,\n    });\n    mockBuildAuthorizationUrl.mockReturnValue(\"https://example.com/auth\");\n    mockExchangeCodeForTokens.mockResolvedValue({\n      access_token: \"new-token\",\n      token_type: \"bearer\",\n    });\n\n    const result = await performLogin();\n    expect(result).toBe(\"new-token\");\n    expect(mockSaveTokens).toHaveBeenCalled();\n    expect(mockClose).toHaveBeenCalled();\n  });\n\n  test(\"opens browser by default\", async () => {\n    mockGeneratePKCE.mockReturnValue({ codeVerifier: \"v\", codeChallenge: \"c\" });\n    mockGenerateState.mockReturnValue(\"s\");\n    mockCreateCallbackServer.mockReturnValue({\n      port: Promise.resolve(52417),\n      result: Promise.resolve({ code: \"code\", state: \"s\" }),\n      close: vi.fn(),\n    });\n    mockBuildAuthorizationUrl.mockReturnValue(\"https://example.com/auth\");\n    mockExchangeCodeForTokens.mockResolvedValue({\n      access_token: \"tok\",\n      token_type: \"bearer\",\n    });\n\n    await performLogin(true);\n    expect(mockOpen).toHaveBeenCalledWith(\"https://example.com/auth\");\n  });\n\n  test(\"skips browser open when openBrowser=false\", async () => {\n    mockGeneratePKCE.mockReturnValue({ codeVerifier: \"v\", codeChallenge: \"c\" });\n    mockGenerateState.mockReturnValue(\"s\");\n    mockCreateCallbackServer.mockReturnValue({\n      port: Promise.resolve(52417),\n      result: Promise.resolve({ code: \"code\", state: \"s\" }),\n      close: vi.fn(),\n    });\n    mockBuildAuthorizationUrl.mockReturnValue(\"https://example.com/auth\");\n    mockExchangeCodeForTokens.mockResolvedValue({\n      access_token: \"tok\",\n      token_type: \"bearer\",\n    });\n\n    await performLogin(false);\n    expect(mockOpen).not.toHaveBeenCalled();\n  });\n\n  test(\"returns null on callback failure\", async () => {\n    const mockClose = vi.fn();\n    mockGeneratePKCE.mockReturnValue({ codeVerifier: \"v\", codeChallenge: \"c\" });\n    mockGenerateState.mockReturnValue(\"s\");\n    mockCreateCallbackServer.mockReturnValue({\n      port: Promise.resolve(52417),\n      result: Promise.reject(new Error(\"User cancelled\")),\n      close: mockClose,\n    });\n    mockBuildAuthorizationUrl.mockReturnValue(\"https://example.com/auth\");\n\n    const result = await performLogin();\n    expect(result).toBeNull();\n    expect(mockClose).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/cli/src/__tests__/auth-utils.test.ts",
    "content": "import { describe, test, expect, vi, beforeEach, afterEach } from \"vitest\";\nimport * as crypto from \"crypto\";\n\nvi.mock(\"os\", () => ({ homedir: () => \"/fake-home\", default: { homedir: () => \"/fake-home\" } }));\n\nvi.mock(\"fs\", () => {\n  const fns = {\n    existsSync: vi.fn(),\n    mkdirSync: vi.fn(),\n    writeFileSync: vi.fn(),\n    readFileSync: vi.fn(),\n    unlinkSync: vi.fn(),\n  };\n  return { ...fns, default: fns };\n});\n\nvi.mock(\"../constants.js\", () => ({ CLI_CLIENT_ID: \"test-client-id\" }));\nvi.mock(\"../utils/api.js\", () => ({ getBaseUrl: () => \"https://test.context7.com\" }));\n\nimport * as fs from \"fs\";\nimport {\n  generatePKCE,\n  generateState,\n  saveTokens,\n  loadTokens,\n  clearTokens,\n  isTokenExpired,\n  getValidAccessToken,\n  exchangeCodeForTokens,\n  buildAuthorizationUrl,\n  createCallbackServer,\n  type TokenData,\n} from \"../utils/auth.js\";\n\nconst mfs = vi.mocked(fs);\nconst CREDENTIALS_PATH = \"/fake-home/.context7/credentials.json\";\nconst CONFIG_DIR_PATH = \"/fake-home/.context7\";\n\nbeforeEach(() => {\n  vi.clearAllMocks();\n  vi.stubGlobal(\n    \"fetch\",\n    vi.fn(() => {\n      throw new Error(\"fetch not mocked for this test\");\n    })\n  );\n});\n\nafterEach(() => {\n  vi.unstubAllGlobals();\n});\n\ndescribe(\"generatePKCE\", () => {\n  test(\"returns codeVerifier and codeChallenge with correct SHA-256 relationship\", () => {\n    const { codeVerifier, codeChallenge } = generatePKCE();\n    const expected = crypto.createHash(\"sha256\").update(codeVerifier).digest(\"base64url\");\n    expect(codeChallenge).toBe(expected);\n  });\n\n  test(\"generates unique values on each call\", () => {\n    const a = generatePKCE();\n    const b = generatePKCE();\n    expect(a.codeVerifier).not.toBe(b.codeVerifier);\n  });\n});\n\ndescribe(\"generateState\", () => {\n  test(\"returns a base64url string\", () => {\n    const state = generateState();\n    expect(state).toMatch(/^[A-Za-z0-9_-]+$/);\n  });\n\n  test(\"generates unique values on each call\", () => {\n    expect(generateState()).not.toBe(generateState());\n  });\n});\n\ndescribe(\"saveTokens\", () => {\n  test(\"creates config directory if it does not exist\", () => {\n    mfs.existsSync.mockReturnValue(false);\n    saveTokens({ access_token: \"tok\", token_type: \"bearer\" });\n    expect(mfs.mkdirSync).toHaveBeenCalledWith(CONFIG_DIR_PATH, { recursive: true, mode: 0o700 });\n  });\n\n  test(\"skips directory creation if it already exists\", () => {\n    mfs.existsSync.mockReturnValue(true);\n    saveTokens({ access_token: \"tok\", token_type: \"bearer\" });\n    expect(mfs.mkdirSync).not.toHaveBeenCalled();\n  });\n\n  test(\"writes credentials file with 0o600 permissions\", () => {\n    mfs.existsSync.mockReturnValue(true);\n    saveTokens({ access_token: \"tok\", token_type: \"bearer\" });\n    expect(mfs.writeFileSync).toHaveBeenCalledWith(CREDENTIALS_PATH, expect.any(String), {\n      mode: 0o600,\n    });\n  });\n\n  test(\"computes expires_at from expires_in when expires_at is absent\", () => {\n    mfs.existsSync.mockReturnValue(true);\n    const now = 1000000;\n    vi.spyOn(Date, \"now\").mockReturnValue(now);\n    saveTokens({ access_token: \"tok\", token_type: \"bearer\", expires_in: 3600 });\n    const written = JSON.parse(mfs.writeFileSync.mock.calls[0][1] as string);\n    expect(written.expires_at).toBe(now + 3600 * 1000);\n  });\n\n  test(\"preserves existing expires_at if already set\", () => {\n    mfs.existsSync.mockReturnValue(true);\n    saveTokens({ access_token: \"tok\", token_type: \"bearer\", expires_at: 999, expires_in: 3600 });\n    const written = JSON.parse(mfs.writeFileSync.mock.calls[0][1] as string);\n    expect(written.expires_at).toBe(999);\n  });\n});\n\ndescribe(\"loadTokens\", () => {\n  test(\"returns null when credentials file does not exist\", () => {\n    mfs.existsSync.mockReturnValue(false);\n    expect(loadTokens()).toBeNull();\n  });\n\n  test(\"returns parsed TokenData when file exists\", () => {\n    const tokens: TokenData = { access_token: \"tok\", token_type: \"bearer\" };\n    mfs.existsSync.mockReturnValue(true);\n    mfs.readFileSync.mockReturnValue(JSON.stringify(tokens));\n    expect(loadTokens()).toEqual(tokens);\n  });\n\n  test(\"returns null on malformed JSON\", () => {\n    mfs.existsSync.mockReturnValue(true);\n    mfs.readFileSync.mockReturnValue(\"not json\");\n    expect(loadTokens()).toBeNull();\n  });\n});\n\ndescribe(\"clearTokens\", () => {\n  test(\"deletes file and returns true when it exists\", () => {\n    mfs.existsSync.mockReturnValue(true);\n    expect(clearTokens()).toBe(true);\n    expect(mfs.unlinkSync).toHaveBeenCalledWith(CREDENTIALS_PATH);\n  });\n\n  test(\"returns false when file does not exist\", () => {\n    mfs.existsSync.mockReturnValue(false);\n    expect(clearTokens()).toBe(false);\n    expect(mfs.unlinkSync).not.toHaveBeenCalled();\n  });\n});\n\ndescribe(\"isTokenExpired\", () => {\n  test(\"returns false when no expires_at is set\", () => {\n    expect(isTokenExpired({ access_token: \"tok\", token_type: \"bearer\" })).toBe(false);\n  });\n\n  test(\"returns false when well before expiry\", () => {\n    expect(\n      isTokenExpired({\n        access_token: \"tok\",\n        token_type: \"bearer\",\n        expires_at: Date.now() + 120_000,\n      })\n    ).toBe(false);\n  });\n\n  test(\"returns true when past expiry\", () => {\n    expect(\n      isTokenExpired({ access_token: \"tok\", token_type: \"bearer\", expires_at: Date.now() - 1000 })\n    ).toBe(true);\n  });\n\n  test(\"returns true within 60s buffer window\", () => {\n    expect(\n      isTokenExpired({ access_token: \"tok\", token_type: \"bearer\", expires_at: Date.now() + 30_000 })\n    ).toBe(true);\n  });\n\n  test(\"returns false at exactly 60s before expiry\", () => {\n    const now = 1000000;\n    vi.spyOn(Date, \"now\").mockReturnValue(now);\n    expect(\n      isTokenExpired({ access_token: \"tok\", token_type: \"bearer\", expires_at: now + 60_000 })\n    ).toBe(false);\n  });\n});\n\ndescribe(\"getValidAccessToken\", () => {\n  test(\"returns null when no tokens stored\", async () => {\n    mfs.existsSync.mockReturnValue(false);\n    expect(await getValidAccessToken()).toBeNull();\n  });\n\n  test(\"returns access_token when not expired\", async () => {\n    const tokens: TokenData = {\n      access_token: \"valid-tok\",\n      token_type: \"bearer\",\n      expires_at: Date.now() + 120_000,\n    };\n    mfs.existsSync.mockReturnValue(true);\n    mfs.readFileSync.mockReturnValue(JSON.stringify(tokens));\n    expect(await getValidAccessToken()).toBe(\"valid-tok\");\n  });\n\n  test(\"returns null when expired and no refresh_token\", async () => {\n    const tokens: TokenData = {\n      access_token: \"expired-tok\",\n      token_type: \"bearer\",\n      expires_at: Date.now() - 1000,\n    };\n    mfs.existsSync.mockReturnValue(true);\n    mfs.readFileSync.mockReturnValue(JSON.stringify(tokens));\n    expect(await getValidAccessToken()).toBeNull();\n  });\n\n  test(\"refreshes token when expired and refresh_token exists\", async () => {\n    const tokens: TokenData = {\n      access_token: \"expired-tok\",\n      token_type: \"bearer\",\n      expires_at: Date.now() - 1000,\n      refresh_token: \"refresh-tok\",\n    };\n    const newTokens: TokenData = {\n      access_token: \"new-tok\",\n      token_type: \"bearer\",\n      expires_in: 3600,\n    };\n\n    mfs.existsSync.mockReturnValue(true);\n    mfs.readFileSync.mockReturnValue(JSON.stringify(tokens));\n    vi.stubGlobal(\n      \"fetch\",\n      vi.fn().mockResolvedValue({\n        ok: true,\n        json: () => Promise.resolve(newTokens),\n      })\n    );\n\n    const result = await getValidAccessToken();\n    expect(result).toBe(\"new-tok\");\n\n    expect(fetch).toHaveBeenCalledWith(\n      \"https://test.context7.com/api/oauth/token\",\n      expect.objectContaining({\n        method: \"POST\",\n        body: expect.stringContaining(\"grant_type=refresh_token\"),\n      })\n    );\n\n    expect(mfs.writeFileSync).toHaveBeenCalled();\n  });\n\n  test(\"returns null when refresh fails\", async () => {\n    const tokens: TokenData = {\n      access_token: \"expired-tok\",\n      token_type: \"bearer\",\n      expires_at: Date.now() - 1000,\n      refresh_token: \"refresh-tok\",\n    };\n\n    mfs.existsSync.mockReturnValue(true);\n    mfs.readFileSync.mockReturnValue(JSON.stringify(tokens));\n    vi.stubGlobal(\n      \"fetch\",\n      vi.fn().mockResolvedValue({\n        ok: false,\n        json: () => Promise.resolve({ error: \"invalid_grant\" }),\n      })\n    );\n\n    expect(await getValidAccessToken()).toBeNull();\n  });\n});\n\ndescribe(\"exchangeCodeForTokens\", () => {\n  test(\"POSTs correct parameters and returns TokenData on success\", async () => {\n    const tokenResponse: TokenData = { access_token: \"new-tok\", token_type: \"bearer\" };\n    vi.stubGlobal(\n      \"fetch\",\n      vi.fn().mockResolvedValue({\n        ok: true,\n        json: () => Promise.resolve(tokenResponse),\n      })\n    );\n\n    const result = await exchangeCodeForTokens(\n      \"https://example.com\",\n      \"auth-code\",\n      \"verifier\",\n      \"http://localhost:52417/callback\",\n      \"client-id\"\n    );\n\n    expect(result).toEqual(tokenResponse);\n    expect(fetch).toHaveBeenCalledWith(\n      \"https://example.com/api/oauth/token\",\n      expect.objectContaining({\n        method: \"POST\",\n        body: expect.stringContaining(\"grant_type=authorization_code\"),\n      })\n    );\n    const body = vi.mocked(fetch).mock.calls[0][1]!.body as string;\n    const params = new URLSearchParams(body);\n    expect(params.get(\"client_id\")).toBe(\"client-id\");\n    expect(params.get(\"code\")).toBe(\"auth-code\");\n    expect(params.get(\"code_verifier\")).toBe(\"verifier\");\n    expect(params.get(\"redirect_uri\")).toBe(\"http://localhost:52417/callback\");\n  });\n\n  test(\"throws with error_description on failure\", async () => {\n    vi.stubGlobal(\n      \"fetch\",\n      vi.fn().mockResolvedValue({\n        ok: false,\n        json: () => Promise.resolve({ error_description: \"bad code\" }),\n      })\n    );\n\n    await expect(\n      exchangeCodeForTokens(\"https://example.com\", \"code\", \"verifier\", \"redirect\", \"client\")\n    ).rejects.toThrow(\"bad code\");\n  });\n\n  test(\"throws generic message when response has no JSON\", async () => {\n    vi.stubGlobal(\n      \"fetch\",\n      vi.fn().mockResolvedValue({\n        ok: false,\n        json: () => Promise.reject(new Error(\"no json\")),\n      })\n    );\n\n    await expect(\n      exchangeCodeForTokens(\"https://example.com\", \"code\", \"verifier\", \"redirect\", \"client\")\n    ).rejects.toThrow(\"Failed to exchange code for tokens\");\n  });\n});\n\ndescribe(\"buildAuthorizationUrl\", () => {\n  test(\"constructs URL with all required parameters\", () => {\n    const result = buildAuthorizationUrl(\n      \"https://example.com\",\n      \"client-id\",\n      \"http://localhost:52417/callback\",\n      \"challenge\",\n      \"state-value\"\n    );\n\n    const url = new URL(result);\n    expect(url.origin).toBe(\"https://example.com\");\n    expect(url.pathname).toBe(\"/api/oauth/authorize\");\n    expect(url.searchParams.get(\"client_id\")).toBe(\"client-id\");\n    expect(url.searchParams.get(\"redirect_uri\")).toBe(\"http://localhost:52417/callback\");\n    expect(url.searchParams.get(\"code_challenge\")).toBe(\"challenge\");\n    expect(url.searchParams.get(\"code_challenge_method\")).toBe(\"S256\");\n    expect(url.searchParams.get(\"state\")).toBe(\"state-value\");\n    expect(url.searchParams.get(\"scope\")).toBe(\"profile email\");\n    expect(url.searchParams.get(\"response_type\")).toBe(\"code\");\n  });\n});\n\ndescribe(\"createCallbackServer\", () => {\n  async function httpGet(url: string): Promise<void> {\n    const http = await import(\"http\");\n    return new Promise((resolve, reject) => {\n      http\n        .get(url, (res) => {\n          res.resume();\n          res.on(\"end\", resolve);\n        })\n        .on(\"error\", reject);\n    });\n  }\n\n  function closeAndWait(closeFn: () => void): Promise<void> {\n    return new Promise((resolve) => {\n      closeFn();\n      setTimeout(resolve, 100);\n    });\n  }\n\n  test(\"resolves with code and state on valid callback\", async () => {\n    const server = createCallbackServer(\"expected-state\");\n    const port = await server.port;\n    await httpGet(`http://127.0.0.1:${port}/callback?code=auth-code&state=expected-state`);\n    const result = await server.result;\n    expect(result).toEqual({ code: \"auth-code\", state: \"expected-state\" });\n    await closeAndWait(server.close);\n  });\n\n  test(\"rejects on state mismatch\", async () => {\n    const server = createCallbackServer(\"expected-state\");\n    const resultPromise = server.result.catch((e: Error) => e);\n    const port = await server.port;\n    await httpGet(`http://127.0.0.1:${port}/callback?code=auth-code&state=wrong-state`);\n    const err = await resultPromise;\n    expect(err).toBeInstanceOf(Error);\n    expect((err as Error).message).toBe(\"State mismatch\");\n    await closeAndWait(server.close);\n  });\n\n  test(\"rejects on missing code\", async () => {\n    const server = createCallbackServer(\"expected-state\");\n    const resultPromise = server.result.catch((e: Error) => e);\n    const port = await server.port;\n    await httpGet(`http://127.0.0.1:${port}/callback?state=expected-state`);\n    const err = await resultPromise;\n    expect(err).toBeInstanceOf(Error);\n    expect((err as Error).message).toBe(\"Missing authorization code or state\");\n    await closeAndWait(server.close);\n  });\n\n  test(\"rejects on error parameter\", async () => {\n    const server = createCallbackServer(\"expected-state\");\n    const resultPromise = server.result.catch((e: Error) => e);\n    const port = await server.port;\n    await httpGet(\n      `http://127.0.0.1:${port}/callback?error=access_denied&error_description=User+cancelled`\n    );\n    const err = await resultPromise;\n    expect(err).toBeInstanceOf(Error);\n    expect((err as Error).message).toBe(\"User cancelled\");\n    await closeAndWait(server.close);\n  });\n});\n"
  },
  {
    "path": "packages/cli/src/commands/auth.ts",
    "content": "import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport ora from \"ora\";\nimport open from \"open\";\nimport {\n  generatePKCE,\n  generateState,\n  createCallbackServer,\n  exchangeCodeForTokens,\n  saveTokens,\n  clearTokens,\n  buildAuthorizationUrl,\n  getValidAccessToken,\n} from \"../utils/auth.js\";\n\nimport { trackEvent } from \"../utils/tracking.js\";\nimport { CLI_CLIENT_ID } from \"../constants.js\";\nimport { getBaseUrl } from \"../utils/api.js\";\n\nlet baseUrl = \"https://context7.com\";\n\nexport function setAuthBaseUrl(url: string): void {\n  baseUrl = url;\n}\n\nexport function registerAuthCommands(program: Command): void {\n  program\n    .command(\"login\")\n    .description(\"Log in to Context7\")\n    .option(\"--no-browser\", \"Don't open browser automatically\")\n    .action(async (options) => {\n      await loginCommand(options);\n    });\n\n  program\n    .command(\"logout\")\n    .description(\"Log out of Context7\")\n    .action(() => {\n      logoutCommand();\n    });\n\n  program\n    .command(\"whoami\")\n    .description(\"Show current login status\")\n    .action(async () => {\n      await whoamiCommand();\n    });\n}\n\nexport async function performLogin(openBrowser = true): Promise<string | null> {\n  const spinner = ora(\"Preparing login...\").start();\n\n  try {\n    const { codeVerifier, codeChallenge } = generatePKCE();\n    const state = generateState();\n    const callbackServer = createCallbackServer(state);\n    const port = await callbackServer.port;\n    const redirectUri = `http://localhost:${port}/callback`;\n    const authUrl = buildAuthorizationUrl(\n      baseUrl,\n      CLI_CLIENT_ID,\n      redirectUri,\n      codeChallenge,\n      state\n    );\n\n    spinner.stop();\n\n    console.log(\"\");\n    console.log(pc.bold(\"Opening browser to log in...\"));\n    console.log(\"\");\n\n    if (openBrowser) {\n      await open(authUrl);\n      console.log(pc.dim(\"If the browser didn't open, visit this URL:\"));\n    } else {\n      console.log(pc.dim(\"Open this URL in your browser:\"));\n    }\n    console.log(pc.cyan(authUrl));\n    console.log(\"\");\n\n    const waitingSpinner = ora(\"Waiting for login...\").start();\n\n    try {\n      const { code } = await callbackServer.result;\n      waitingSpinner.text = \"Exchanging code for tokens...\";\n\n      const tokens = await exchangeCodeForTokens(\n        baseUrl,\n        code,\n        codeVerifier,\n        redirectUri,\n        CLI_CLIENT_ID\n      );\n      saveTokens(tokens);\n      callbackServer.close();\n\n      waitingSpinner.succeed(pc.green(\"Login successful!\"));\n      return tokens.access_token;\n    } catch (error) {\n      callbackServer.close();\n      waitingSpinner.fail(pc.red(\"Login failed\"));\n      if (error instanceof Error) {\n        console.error(pc.red(error.message));\n      }\n      return null;\n    }\n  } catch (error) {\n    spinner.fail(pc.red(\"Login failed\"));\n    if (error instanceof Error) {\n      console.error(pc.red(error.message));\n    }\n    return null;\n  }\n}\n\nasync function loginCommand(options: { browser: boolean }): Promise<void> {\n  trackEvent(\"command\", { name: \"login\" });\n  const existingToken = await getValidAccessToken();\n  if (existingToken) {\n    console.log(pc.yellow(\"You are already logged in.\"));\n    console.log(pc.dim(\"Run 'ctx7 logout' first if you want to log in with a different account.\"));\n    return;\n  }\n  clearTokens();\n\n  const token = await performLogin(options.browser);\n  if (!token) {\n    process.exit(1);\n  }\n  console.log(\"\");\n  console.log(pc.dim(\"You can now use authenticated Context7 features.\"));\n}\n\nfunction logoutCommand(): void {\n  trackEvent(\"command\", { name: \"logout\" });\n  if (clearTokens()) {\n    console.log(pc.green(\"Logged out successfully.\"));\n  } else {\n    console.log(pc.yellow(\"You are not logged in.\"));\n  }\n}\n\nasync function whoamiCommand(): Promise<void> {\n  trackEvent(\"command\", { name: \"whoami\" });\n  const accessToken = await getValidAccessToken();\n\n  if (!accessToken) {\n    console.log(pc.yellow(\"Not logged in.\"));\n    console.log(pc.dim(\"Run 'ctx7 login' to authenticate.\"));\n    return;\n  }\n\n  console.log(pc.green(\"Logged in\"));\n\n  try {\n    const whoami = await fetchWhoami(accessToken);\n    if (whoami.name) {\n      console.log(`${pc.dim(\"Name:\".padEnd(13))}${whoami.name}`);\n    }\n    if (whoami.email) {\n      console.log(`${pc.dim(\"Email:\".padEnd(13))}${whoami.email}`);\n    }\n    if (whoami.teamspace) {\n      console.log(`${pc.dim(\"Teamspace:\".padEnd(13))}${whoami.teamspace.name}`);\n    }\n  } catch {\n    console.log(pc.dim(\"(Session may be expired - run 'ctx7 login' to refresh)\"));\n  }\n}\n\ninterface WhoamiResponse {\n  success: boolean;\n  name: string | null;\n  email: string | null;\n  teamspace: { id: string; name: string } | null;\n}\n\nasync function fetchWhoami(accessToken: string): Promise<WhoamiResponse> {\n  const response = await fetch(`${getBaseUrl()}/api/dashboard/whoami`, {\n    headers: {\n      Authorization: `Bearer ${accessToken}`,\n    },\n  });\n\n  if (!response.ok) {\n    throw new Error(\"Failed to fetch user info\");\n  }\n\n  return (await response.json()) as WhoamiResponse;\n}\n"
  },
  {
    "path": "packages/cli/src/commands/docs.ts",
    "content": "import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport ora from \"ora\";\n\nimport { resolveLibrary, getLibraryContext } from \"../utils/api.js\";\nimport { log } from \"../utils/logger.js\";\nimport { trackEvent } from \"../utils/tracking.js\";\nimport { loadTokens, isTokenExpired } from \"../utils/auth.js\";\nimport type { LibrarySearchResult, ContextResponse } from \"../types.js\";\n\nconst isTTY = process.stdout.isTTY;\n\nfunction getReputationLabel(score: number | undefined): \"High\" | \"Medium\" | \"Low\" | \"Unknown\" {\n  if (score === undefined || score < 0) return \"Unknown\";\n  if (score >= 7) return \"High\";\n  if (score >= 4) return \"Medium\";\n  return \"Low\";\n}\n\nfunction getAccessToken(): string | undefined {\n  const tokens = loadTokens();\n  if (!tokens || isTokenExpired(tokens)) return undefined;\n  return tokens.access_token;\n}\n\nfunction formatLibraryResult(lib: LibrarySearchResult, index: number): string {\n  const lines: string[] = [];\n  lines.push(`${pc.dim(`${index + 1}.`)} ${pc.bold(`Title: ${lib.title}`)}`);\n  lines.push(`   ${pc.cyan(`Context7-compatible library ID: ${lib.id}`)}`);\n\n  if (lib.description) {\n    lines.push(`   ${pc.dim(`Description: ${lib.description}`)}`);\n  }\n\n  if (lib.totalSnippets) {\n    lines.push(`   ${pc.dim(`Code Snippets: ${lib.totalSnippets}`)}`);\n  }\n  if (lib.trustScore !== undefined) {\n    lines.push(`   ${pc.dim(`Source Reputation: ${getReputationLabel(lib.trustScore)}`)}`);\n  }\n  if (lib.benchmarkScore !== undefined && lib.benchmarkScore > 0) {\n    lines.push(`   ${pc.dim(`Benchmark Score: ${lib.benchmarkScore}`)}`);\n  }\n  if (lib.versions && lib.versions.length > 0) {\n    lines.push(`   ${pc.dim(`Versions: ${lib.versions.join(\", \")}`)}`);\n  }\n\n  return lines.join(\"\\n\");\n}\n\nasync function resolveCommand(\n  library: string,\n  query: string | undefined,\n  options: { json?: boolean }\n): Promise<void> {\n  trackEvent(\"command\", { name: \"library\" });\n\n  const spinner = isTTY ? ora(`Searching for \"${library}\"...`).start() : null;\n  const accessToken = getAccessToken();\n\n  let data;\n  try {\n    data = await resolveLibrary(library, query, accessToken);\n  } catch (err) {\n    spinner?.fail(`Error: ${err instanceof Error ? err.message : String(err)}`);\n    if (!spinner) log.error(err instanceof Error ? err.message : String(err));\n    process.exitCode = 1;\n    return;\n  }\n\n  if (data.error) {\n    spinner?.fail(data.message || data.error);\n    if (!spinner) log.error(data.message || data.error);\n    process.exitCode = 1;\n    return;\n  }\n\n  if (!data.results || data.results.length === 0) {\n    spinner?.warn(`No libraries found matching \"${library}\"`);\n    if (!spinner) log.warn(`No libraries found matching \"${library}\"`);\n    return;\n  }\n\n  const results = data.results;\n\n  spinner?.stop();\n\n  if (options.json) {\n    console.log(JSON.stringify(results, null, 2));\n    return;\n  }\n\n  log.blank();\n\n  if (data.searchFilterApplied) {\n    log.warn(\n      \"Your results only include libraries matching your access settings. To search across all public libraries, update your settings at https://context7.com/dashboard?tab=libraries\"\n    );\n    log.blank();\n  }\n\n  for (let i = 0; i < results.length; i++) {\n    log.plain(formatLibraryResult(results[i], i));\n    log.blank();\n  }\n\n  if (isTTY && results.length > 0) {\n    const best = results[0];\n    log.plain(\n      `${pc.bold(\"Quick command:\")}\\n` + `  ${pc.cyan(`ctx7 docs \"${best.id}\" \"<your question>\"`)}`\n    );\n    log.blank();\n  }\n}\n\nasync function queryCommand(\n  libraryId: string,\n  query: string,\n  options: { json?: boolean }\n): Promise<void> {\n  trackEvent(\"command\", { name: \"docs\" });\n\n  if (!libraryId.startsWith(\"/\") || !/^\\/[^/]+\\/[^/]/.test(libraryId)) {\n    log.error(`Invalid library ID: \"${libraryId}\"`);\n    log.info(`Expected format: /owner/repo or /owner/repo/version (e.g., /facebook/react)`);\n    log.info(`Run \"ctx7 library <name>\" to find the correct ID`);\n    process.exitCode = 1;\n    return;\n  }\n\n  const spinner = isTTY ? ora(`Fetching docs for \"${libraryId}\"...`).start() : null;\n  const accessToken = getAccessToken();\n  const outputType = options.json ? \"json\" : \"txt\";\n\n  let result;\n  try {\n    result = await getLibraryContext(libraryId, query, { type: outputType }, accessToken);\n  } catch (err) {\n    spinner?.fail(`Error: ${err instanceof Error ? err.message : String(err)}`);\n    if (!spinner) log.error(err instanceof Error ? err.message : String(err));\n    process.exitCode = 1;\n    return;\n  }\n\n  if (typeof result === \"string\") {\n    spinner?.stop();\n    console.log(result);\n    return;\n  }\n\n  const ctx = result as ContextResponse;\n\n  if (ctx.error) {\n    if (ctx.redirectUrl) {\n      spinner?.warn(\"Library has been redirected\");\n      if (!spinner) log.warn(\"Library has been redirected\");\n      log.info(`New ID: ${pc.cyan(ctx.redirectUrl)}`);\n      log.info(`Run: ${pc.cyan(`ctx7 docs \"${ctx.redirectUrl}\" \"${query}\"`)}`);\n      process.exitCode = 1;\n      return;\n    }\n\n    spinner?.fail(ctx.message || ctx.error);\n    if (!spinner) log.error(ctx.message || ctx.error);\n    process.exitCode = 1;\n    return;\n  }\n\n  const total = (ctx.codeSnippets?.length || 0) + (ctx.infoSnippets?.length || 0);\n  if (total === 0) {\n    spinner?.warn(`No documentation found for: \"${query}\"`);\n    if (!spinner) log.warn(`No documentation found for: \"${query}\"`);\n    return;\n  }\n\n  spinner?.stop();\n\n  if (options.json) {\n    console.log(JSON.stringify(ctx, null, 2));\n    return;\n  }\n\n  log.blank();\n\n  if (ctx.codeSnippets) {\n    for (const snippet of ctx.codeSnippets) {\n      log.plain(pc.bold(snippet.codeTitle));\n      if (snippet.codeDescription) log.dim(snippet.codeDescription);\n      log.blank();\n      for (const code of snippet.codeList) {\n        log.plain(\"```\" + code.language);\n        log.plain(code.code);\n        log.plain(\"```\");\n        log.blank();\n      }\n    }\n  }\n\n  if (ctx.infoSnippets) {\n    for (const snippet of ctx.infoSnippets) {\n      if (snippet.breadcrumb) log.plain(pc.bold(snippet.breadcrumb));\n      log.plain(snippet.content);\n      log.blank();\n    }\n  }\n}\n\nexport function registerDocsCommands(program: Command): void {\n  program\n    .command(\"library\")\n    .argument(\"<name>\", \"Library name to search for\")\n    .argument(\"[query]\", \"Question or task for relevance ranking\")\n    .option(\"--json\", \"Output as JSON\")\n    .description(\"Resolve a library name to a Context7 library ID\")\n    .action(async (name: string, query: string | undefined, options: { json?: boolean }) => {\n      await resolveCommand(name, query, options);\n    });\n\n  program\n    .command(\"docs\")\n    .argument(\"<libraryId>\", \"Context7 library ID (e.g., /facebook/react)\")\n    .argument(\"<query>\", \"Question or task to get docs for\")\n    .option(\"--json\", \"Output as JSON\")\n    .description(\"Query documentation for a library\")\n    .action(async (libraryId: string, query: string, options: { json?: boolean }) => {\n      await queryCommand(libraryId, query, options);\n    });\n}\n"
  },
  {
    "path": "packages/cli/src/commands/generate.ts",
    "content": "import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport ora from \"ora\";\nimport { mkdir, writeFile, readFile, unlink } from \"fs/promises\";\nimport { join } from \"path\";\nimport { homedir } from \"os\";\nimport { spawn } from \"child_process\";\nimport { input, select } from \"@inquirer/prompts\";\n\nimport {\n  searchLibraries,\n  getSkillQuestions,\n  generateSkillStructured,\n  getSkillQuota,\n} from \"../utils/api.js\";\nimport { loadTokens, isTokenExpired } from \"../utils/auth.js\";\nimport { performLogin } from \"./auth.js\";\nimport { log } from \"../utils/logger.js\";\nimport { promptForInstallTargets, getTargetDirs } from \"../utils/ide.js\";\nimport selectOrInput from \"../utils/selectOrInput.js\";\nimport { checkboxWithHover, terminalLink } from \"../utils/prompts.js\";\nimport { trackEvent } from \"../utils/tracking.js\";\nimport type {\n  GenerateOptions,\n  LibrarySearchResult,\n  SkillAnswer,\n  StructuredGenerateInput,\n  GenerateStreamEvent,\n  ToolResultSnippet,\n} from \"../types.js\";\n\ninterface QueryLogEntry {\n  query: string;\n  libraryId?: string;\n  results: ToolResultSnippet[];\n}\n\nexport function registerGenerateCommand(skillCommand: Command): void {\n  skillCommand\n    .command(\"generate\")\n    .alias(\"gen\")\n    .alias(\"g\")\n    .option(\"-o, --output <dir>\", \"Output directory (default: current directory)\")\n    .option(\"--all\", \"Generate for all detected IDEs\")\n    .option(\"--global\", \"Generate in global skills directory\")\n    .option(\"--claude\", \"Claude Code (.claude/skills/)\")\n    .option(\"--cursor\", \"Cursor (.cursor/skills/)\")\n    .option(\"--universal\", \"Universal (.agents/skills/)\")\n    .option(\"--antigravity\", \"Antigravity (.agent/skills/)\")\n    .description(\"Generate a skill for a library using AI\")\n    .action(async (options: GenerateOptions) => {\n      await generateCommand(options);\n    });\n}\n\nasync function generateCommand(options: GenerateOptions): Promise<void> {\n  trackEvent(\"command\", { name: \"generate\" });\n  log.blank();\n\n  let accessToken: string | null = null;\n  const tokens = loadTokens();\n  if (tokens && !isTokenExpired(tokens)) {\n    accessToken = tokens.access_token;\n  } else {\n    log.info(\"Authentication required. Logging in...\");\n    log.blank();\n    accessToken = await performLogin();\n    if (!accessToken) {\n      log.error(\"Login failed. Please try again.\");\n      return;\n    }\n    log.blank();\n  }\n\n  const initSpinner = ora().start();\n  const quota = await getSkillQuota(accessToken);\n\n  if (quota.error) {\n    initSpinner.fail(pc.red(\"Failed to initialize\"));\n    return;\n  }\n\n  if (quota.tier !== \"unlimited\" && quota.remaining < 1) {\n    initSpinner.fail(pc.red(\"Weekly skill generation limit reached\"));\n    log.blank();\n    console.log(\n      `  You've used ${pc.bold(pc.white(quota.used.toString()))}/${pc.bold(pc.white(quota.limit.toString()))} skill generations this week.`\n    );\n    console.log(\n      `  Your quota resets on ${pc.yellow(new Date(quota.resetDate!).toLocaleDateString())}.`\n    );\n    log.blank();\n    if (quota.tier === \"free\") {\n      console.log(\n        `  ${pc.yellow(\"Tip:\")} Upgrade to Pro for ${pc.bold(\"10\")} generations per week.`\n      );\n      console.log(`  Visit ${pc.green(\"https://context7.com/dashboard\")} to upgrade.`);\n    }\n    return;\n  }\n\n  initSpinner.stop();\n  initSpinner.clear();\n\n  console.log(pc.bold(\"What should your agent become an expert at?\\n\"));\n  console.log(\n    pc.dim(\n      \"Skills should encode best practices, constraints, and decision-making —\\nnot step-by-step tutorials or one-off tasks.\\n\"\n    )\n  );\n  console.log(pc.yellow(\"Examples:\"));\n  // prettier-ignore\n  {\n    console.log(pc.red('  ✕ \"Deploy a Next.js app to Vercel\"'));\n    console.log(pc.green('  ✓ \"Best practices and constraints for deploying Next.js apps to Vercel\"'));\n    log.blank();\n    console.log(pc.red('  ✕ \"Use Tailwind for responsive design\"'));\n    console.log(pc.green('  ✓ \"Responsive layout decision-making with Tailwind CSS\"'));\n    log.blank();\n    console.log(pc.red('  ✕ \"Build OAuth with NextAuth\"'));\n    console.log(pc.green('  ✓ \"OAuth authentication patterns and pitfalls with NextAuth.js\"'));\n  }\n  log.blank();\n\n  let motivation: string;\n  try {\n    motivation = await input({\n      message: \"Describe the expertise:\",\n    });\n\n    if (!motivation.trim()) {\n      log.warn(\"Expertise description is required\");\n      return;\n    }\n    motivation = motivation.trim();\n  } catch {\n    log.warn(\"Generation cancelled\");\n    return;\n  }\n\n  log.blank();\n  console.log(\n    pc.dim(\n      \"To generate this skill, we will read relevant documentation and examples\\nfrom Context7.\\n\"\n    )\n  );\n  console.log(\n    pc.dim(\n      \"These sources are used to:\\n• extract best practices and constraints\\n• compare patterns across official docs and examples\\n• avoid outdated or incorrect guidance\\n\"\n    )\n  );\n  console.log(pc.dim(\"You can adjust which sources the skill is based on.\\n\"));\n\n  const searchSpinner = ora(\"Finding relevant sources...\").start();\n  const searchResult = await searchLibraries(motivation, accessToken);\n\n  if (searchResult.error || !searchResult.results?.length) {\n    searchSpinner.fail(pc.red(\"No sources found\"));\n    log.warn(searchResult.message || \"Try a different description\");\n    return;\n  }\n\n  searchSpinner.succeed(pc.green(`Found ${searchResult.results.length} relevant sources`));\n  log.blank();\n\n  if (searchResult.searchFilterApplied) {\n    log.warn(\n      \"Your results only include libraries matching your access settings. To search across all public libraries, update your settings at https://context7.com/dashboard?tab=libraries\"\n    );\n    log.blank();\n  }\n\n  let selectedLibraries: LibrarySearchResult[];\n  try {\n    const formatProjectId = (id: string) => {\n      return id.startsWith(\"/\") ? id.slice(1) : id;\n    };\n\n    const isGitHubRepo = (id: string): boolean => {\n      const cleanId = id.startsWith(\"/\") ? id.slice(1) : id;\n      const parts = cleanId.split(\"/\");\n      if (parts.length !== 2) return false;\n      const nonGitHubPrefixes = [\"websites\", \"packages\", \"npm\", \"docs\", \"libraries\", \"llmstxt\"];\n      return !nonGitHubPrefixes.includes(parts[0].toLowerCase());\n    };\n\n    const libraries = searchResult.results.slice(0, 5);\n    const indexWidth = libraries.length.toString().length;\n    const maxNameLen = Math.max(...libraries.map((lib) => lib.title.length));\n\n    const libraryChoices = libraries.map((lib, index) => {\n      const projectId = formatProjectId(lib.id);\n      const isGitHub = isGitHubRepo(lib.id);\n      const indexStr = pc.dim(`${(index + 1).toString().padStart(indexWidth)}.`);\n      const paddedName = lib.title.padEnd(maxNameLen);\n\n      const libUrl = `https://context7.com${lib.id}`;\n      const libLink = terminalLink(lib.title, libUrl, pc.white);\n      const sourceUrl = isGitHub\n        ? `https://github.com/${projectId}`\n        : `https://context7.com${lib.id}`;\n      const repoLink = terminalLink(projectId, sourceUrl, pc.white);\n\n      const starsLine =\n        lib.stars && isGitHub ? [`${pc.yellow(\"Stars:\")}       ${lib.stars.toLocaleString()}`] : [];\n\n      const metadataLines = [\n        pc.dim(\"─\".repeat(50)),\n        \"\",\n        `${pc.yellow(\"Library:\")}     ${libLink}`,\n        `${pc.yellow(\"Source:\")}      ${repoLink}`,\n        `${pc.yellow(\"Snippets:\")}    ${lib.totalSnippets.toLocaleString()}`,\n        ...starsLine,\n        `${pc.yellow(\"Description:\")}`,\n        pc.white(lib.description || \"No description\"),\n      ];\n\n      return {\n        name: `${indexStr} ${paddedName}  ${pc.dim(`(${projectId})`)}`,\n        value: lib,\n        description: metadataLines.join(\"\\n\"),\n      };\n    });\n\n    selectedLibraries = await checkboxWithHover(\n      {\n        message: \"Select sources:\",\n        choices: libraryChoices,\n        pageSize: 10,\n        loop: false,\n      },\n      { getName: (lib) => `${lib.title} (${formatProjectId(lib.id)})` }\n    );\n\n    if (!selectedLibraries || selectedLibraries.length === 0) {\n      log.info(\"No sources selected. Try running the command again.\");\n      return;\n    }\n  } catch {\n    log.warn(\"Generation cancelled\");\n    return;\n  }\n\n  log.blank();\n\n  const questionsSpinner = ora(\n    \"Preparing follow-up questions to clarify scope and constraints...\"\n  ).start();\n  const librariesInput = selectedLibraries.map((lib) => ({ id: lib.id, name: lib.title }));\n  const questionsResult = await getSkillQuestions(librariesInput, motivation, accessToken);\n\n  if (questionsResult.error || !questionsResult.questions?.length) {\n    questionsSpinner.fail(pc.red(\"Failed to generate questions\"));\n    log.warn(questionsResult.message || \"Please try again\");\n    return;\n  }\n\n  questionsSpinner.succeed(pc.green(\"Questions prepared\"));\n  log.blank();\n\n  const answers: SkillAnswer[] = [];\n  try {\n    for (let i = 0; i < questionsResult.questions.length; i++) {\n      const q = questionsResult.questions[i];\n      const questionNum = i + 1;\n      const totalQuestions = questionsResult.questions.length;\n\n      const answer = await selectOrInput({\n        message: `${pc.dim(`[${questionNum}/${totalQuestions}]`)} ${q.question}`,\n        options: q.options,\n        recommendedIndex: q.recommendedIndex,\n      });\n\n      answers.push({\n        question: q.question,\n        answer,\n      });\n\n      const linesToClear = 3 + q.options.length;\n      process.stdout.write(`\\x1b[${linesToClear}A\\x1b[J`);\n\n      const truncatedAnswer = answer.length > 50 ? answer.slice(0, 47) + \"...\" : answer;\n      console.log(`${pc.green(\"✓\")} ${pc.dim(`[${questionNum}/${totalQuestions}]`)} ${q.question}`);\n      console.log(`  ${pc.cyan(truncatedAnswer)}`);\n      log.blank();\n    }\n  } catch {\n    log.warn(\"Generation cancelled\");\n    return;\n  }\n\n  let generatedContent: string | null = null;\n  let skillName: string = \"\";\n  let feedback: string | undefined;\n  let previewFile: string | null = null;\n  let previewFileWritten = false;\n\n  const cleanupPreviewFile = async () => {\n    if (previewFile) {\n      await unlink(previewFile).catch(() => {});\n    }\n  };\n\n  const queryLog: QueryLogEntry[] = [];\n  let genSpinner: ReturnType<typeof ora> | null = null;\n\n  const formatQueryLogText = (): string => {\n    if (queryLog.length === 0) return \"\";\n\n    const lines: string[] = [];\n    const latestEntry = queryLog[queryLog.length - 1];\n\n    lines.push(\"\");\n\n    for (const result of latestEntry.results.slice(0, 3)) {\n      const cleanContent = result.content.replace(/Source:\\s*https?:\\/\\/[^\\s]+/gi, \"\").trim();\n      if (cleanContent) {\n        lines.push(`  ${pc.yellow(\"•\")} ${pc.white(result.title)}`);\n        const maxLen = 400;\n        const content =\n          cleanContent.length > maxLen ? cleanContent.slice(0, maxLen - 3) + \"...\" : cleanContent;\n        const words = content.split(\" \");\n        let currentLine = \"    \";\n        for (const word of words) {\n          if (currentLine.length + word.length > 84) {\n            lines.push(pc.dim(currentLine));\n            currentLine = \"    \" + word + \" \";\n          } else {\n            currentLine += word + \" \";\n          }\n        }\n        if (currentLine.trim()) {\n          lines.push(pc.dim(currentLine));\n        }\n        lines.push(\"\");\n      }\n    }\n\n    return \"\\n\" + lines.join(\"\\n\");\n  };\n\n  let isGeneratingContent = false;\n  let initialStatus = \"Reading selected Context7 sources to generate the skill...\";\n\n  const handleStreamEvent = (event: GenerateStreamEvent) => {\n    if (event.type === \"progress\") {\n      if (genSpinner) {\n        if (event.message.startsWith(\"Generating skill content...\") && !isGeneratingContent) {\n          isGeneratingContent = true;\n          if (queryLog.length > 0) {\n            genSpinner.succeed(pc.green(`Read Context7 sources`));\n          } else {\n            genSpinner.succeed(pc.green(`Ready to generate`));\n          }\n          genSpinner = ora(\"Generating skill content...\").start();\n        } else if (!isGeneratingContent) {\n          genSpinner.text = initialStatus + formatQueryLogText();\n        }\n      }\n    } else if (event.type === \"tool_result\") {\n      queryLog.push({\n        query: event.query,\n        libraryId: event.libraryId,\n        results: event.results,\n      });\n      if (genSpinner && !isGeneratingContent) {\n        genSpinner.text = genSpinner.text.split(\"\\n\")[0] + formatQueryLogText();\n      }\n    }\n  };\n\n  while (true) {\n    const generateInput: StructuredGenerateInput = {\n      motivation,\n      libraries: librariesInput,\n      answers,\n      feedback,\n      previousContent: feedback && generatedContent ? generatedContent : undefined,\n    };\n\n    queryLog.length = 0;\n    isGeneratingContent = false;\n    previewFileWritten = false;\n    initialStatus = feedback\n      ? \"Regenerating skill with your feedback...\"\n      : \"Reading selected Context7 sources to generate the skill...\";\n\n    genSpinner = ora(initialStatus).start();\n\n    const result = await generateSkillStructured(generateInput, handleStreamEvent, accessToken);\n\n    if (result.error) {\n      genSpinner.fail(pc.red(`Error: ${result.error}`));\n      return;\n    }\n\n    if (!result.content) {\n      genSpinner.fail(pc.red(\"No content generated\"));\n      return;\n    }\n\n    genSpinner.succeed(pc.green(`Generated skill for \"${result.libraryName}\"`));\n    generatedContent = result.content;\n    skillName = result.libraryName.toLowerCase().replace(/[^a-z0-9-]/g, \"-\");\n\n    const contentLines = generatedContent.split(\"\\n\");\n    const previewLineCount = 20;\n    const hasMoreLines = contentLines.length > previewLineCount;\n    const previewContent = contentLines.slice(0, previewLineCount).join(\"\\n\");\n    const remainingLines = contentLines.length - previewLineCount;\n\n    const showPreview = () => {\n      log.blank();\n      console.log(pc.dim(\"━\".repeat(70)));\n      console.log(pc.bold(`Generated Skill: `) + pc.green(pc.bold(skillName)));\n      console.log(pc.dim(\"━\".repeat(70)));\n      log.blank();\n      console.log(previewContent);\n      if (hasMoreLines) {\n        log.blank();\n        console.log(pc.dim(`... ${remainingLines} more lines`));\n      }\n      log.blank();\n      console.log(pc.dim(\"━\".repeat(70)));\n      log.blank();\n    };\n\n    const openInEditor = async () => {\n      const previewDir = join(homedir(), \".context7\", \"previews\");\n      await mkdir(previewDir, { recursive: true });\n      previewFile = join(previewDir, `${skillName}.md`);\n      if (!previewFileWritten) {\n        await writeFile(previewFile, generatedContent!, \"utf-8\");\n        previewFileWritten = true;\n      }\n      const editor = process.env.EDITOR || \"open\";\n      await new Promise<void>((resolve) => {\n        const child = spawn(editor, [previewFile!], {\n          stdio: \"inherit\",\n        });\n        child.on(\"close\", () => resolve());\n      });\n    };\n\n    const syncFromPreviewFile = async () => {\n      if (previewFile) {\n        generatedContent = await readFile(previewFile, \"utf-8\");\n      }\n    };\n\n    showPreview();\n\n    await new Promise((resolve) => setTimeout(resolve, 100));\n\n    try {\n      let action: string;\n      while (true) {\n        const choices = [\n          { name: `${pc.green(\"✓\")} Install skill (save locally)`, value: \"install\" },\n          { name: `${pc.blue(\"⤢\")} Edit skill in editor`, value: \"view\" },\n          { name: `${pc.yellow(\"✎\")} Request changes`, value: \"feedback\" },\n          { name: `${pc.red(\"✕\")} Cancel`, value: \"cancel\" },\n        ];\n\n        action = await select({\n          message: \"What would you like to do?\",\n          choices,\n        });\n\n        if (action === \"view\") {\n          await openInEditor();\n          continue;\n        }\n        await syncFromPreviewFile();\n        break;\n      }\n\n      if (action === \"install\") {\n        break;\n      } else if (action === \"cancel\") {\n        await cleanupPreviewFile();\n        log.warn(\"Generation cancelled\");\n        return;\n      } else if (action === \"feedback\") {\n        trackEvent(\"gen_feedback\");\n        feedback = await input({\n          message: \"What changes would you like? (press Enter to skip)\",\n        });\n\n        if (!feedback.trim()) {\n          feedback = undefined;\n        }\n        log.blank();\n      }\n    } catch {\n      await cleanupPreviewFile();\n      log.warn(\"Generation cancelled\");\n      return;\n    }\n  }\n\n  const targets = await promptForInstallTargets(options);\n  if (!targets) {\n    log.warn(\"Generation cancelled\");\n    return;\n  }\n\n  const targetDirs = getTargetDirs(targets);\n\n  const writeSpinner = ora(\"Writing skill files...\").start();\n\n  let permissionError = false;\n  const failedDirs: Set<string> = new Set();\n\n  for (const targetDir of targetDirs) {\n    let finalDir = targetDir;\n    if (options.output && !targetDir.includes(\"/.config/\") && !targetDir.startsWith(homedir())) {\n      finalDir = targetDir.replace(process.cwd(), options.output);\n    }\n    const skillDir = join(finalDir, skillName);\n    const skillPath = join(skillDir, \"SKILL.md\");\n\n    try {\n      await mkdir(skillDir, { recursive: true });\n      await writeFile(skillPath, generatedContent!, \"utf-8\");\n    } catch (err) {\n      const error = err as NodeJS.ErrnoException;\n      if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n        permissionError = true;\n        failedDirs.add(skillDir);\n      } else {\n        log.warn(`Failed to write to ${skillPath}: ${error.message}`);\n      }\n    }\n  }\n\n  if (permissionError) {\n    writeSpinner.fail(pc.red(\"Permission denied\"));\n    log.blank();\n    console.log(pc.yellow(\"Fix permissions with:\"));\n    for (const dir of failedDirs) {\n      const parentDir = join(dir, \"..\");\n      console.log(pc.dim(`  sudo chown -R $(whoami) \"${parentDir}\"`));\n    }\n    log.blank();\n    return;\n  }\n\n  writeSpinner.succeed(pc.green(`Created skill in ${targetDirs.length} location(s)`));\n  trackEvent(\"gen_install\");\n\n  log.blank();\n  console.log(pc.green(\"Skill saved successfully\"));\n  for (const targetDir of targetDirs) {\n    console.log(pc.dim(`  ${targetDir}/`) + pc.green(skillName));\n  }\n  log.blank();\n\n  await cleanupPreviewFile();\n}\n"
  },
  {
    "path": "packages/cli/src/commands/setup.ts",
    "content": "import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport ora from \"ora\";\nimport { select } from \"@inquirer/prompts\";\nimport { mkdir, writeFile } from \"fs/promises\";\nimport { dirname, join } from \"path\";\nimport { randomBytes } from \"crypto\";\n\nimport { log } from \"../utils/logger.js\";\nimport { checkboxWithHover } from \"../utils/prompts.js\";\nimport { trackEvent } from \"../utils/tracking.js\";\nimport { getBaseUrl, downloadSkill } from \"../utils/api.js\";\nimport { installSkillFiles } from \"../utils/installer.js\";\nimport { promptForInstallTargets, getTargetDirs } from \"../utils/ide.js\";\nimport { performLogin } from \"./auth.js\";\nimport { saveTokens, getValidAccessToken } from \"../utils/auth.js\";\nimport {\n  type SetupAgent,\n  type AuthOptions,\n  SETUP_AGENT_NAMES,\n  AUTH_MODE_LABELS,\n  ALL_AGENT_NAMES,\n  getAgent,\n  detectAgents,\n} from \"../setup/agents.js\";\nimport { RULE_CONTENT } from \"../setup/templates.js\";\nimport {\n  readJsonConfig,\n  mergeServerEntry,\n  mergeInstructions,\n  writeJsonConfig,\n} from \"../setup/mcp-writer.js\";\n\ntype Scope = \"global\" | \"project\";\ntype SetupMode = \"mcp\" | \"cli\";\n\ninterface SetupOptions {\n  claude?: boolean;\n  cursor?: boolean;\n  universal?: boolean;\n  antigravity?: boolean;\n  opencode?: boolean;\n  project?: boolean;\n  yes?: boolean;\n  apiKey?: string;\n  oauth?: boolean;\n  cli?: boolean;\n  mcp?: boolean;\n}\n\nconst CHECKBOX_THEME = {\n  style: {\n    highlight: (text: string) => pc.green(text),\n    disabledChoice: (text: string) => ` ${pc.dim(\"◯\")} ${pc.dim(text)}`,\n  },\n};\n\nfunction getSelectedAgents(options: SetupOptions): SetupAgent[] {\n  const agents: SetupAgent[] = [];\n  if (options.claude) agents.push(\"claude\");\n  if (options.cursor) agents.push(\"cursor\");\n  if (options.opencode) agents.push(\"opencode\");\n  return agents;\n}\n\nexport function registerSetupCommand(program: Command): void {\n  program\n    .command(\"setup\")\n    .description(\"Set up Context7 for your AI coding agent\")\n    .option(\"--claude\", \"Set up for Claude Code\")\n    .option(\"--cursor\", \"Set up for Cursor\")\n    .option(\"--universal\", \"Set up for Universal (.agents/skills)\")\n    .option(\"--antigravity\", \"Set up for Antigravity (.agent/skills)\")\n    .option(\"--opencode\", \"Set up for OpenCode\")\n    .option(\"--mcp\", \"Set up MCP server mode\")\n    .option(\"--cli\", \"Set up CLI + Skills mode (no MCP server)\")\n    .option(\"-p, --project\", \"Configure for current project instead of globally\")\n    .option(\"-y, --yes\", \"Skip confirmation prompts\")\n    .option(\"--api-key <key>\", \"Use API key authentication\")\n    .option(\"--oauth\", \"Use OAuth endpoint (IDE handles auth flow)\")\n    .action(async (options: SetupOptions) => {\n      await setupCommand(options);\n    });\n}\n\nasync function authenticateAndGenerateKey(): Promise<string | null> {\n  const accessToken = (await getValidAccessToken()) ?? (await performLogin());\n\n  if (!accessToken) return null;\n\n  const spinner = ora(\"Configuring authentication...\").start();\n\n  try {\n    const response = await fetch(`${getBaseUrl()}/api/dashboard/api-keys`, {\n      method: \"POST\",\n      headers: {\n        Authorization: `Bearer ${accessToken}`,\n        \"Content-Type\": \"application/json\",\n      },\n      body: JSON.stringify({ name: `ctx7-cli-${randomBytes(3).toString(\"hex\")}` }),\n    });\n\n    if (!response.ok) {\n      const err = (await response.json().catch(() => ({}))) as { message?: string; error?: string };\n      spinner.fail(\"Authentication failed\");\n      log.error(err.message || err.error || `HTTP ${response.status}`);\n      return null;\n    }\n\n    const result = (await response.json()) as { data: { apiKey: string } };\n    spinner.succeed(\"Authenticated\");\n    return result.data.apiKey;\n  } catch (err) {\n    spinner.fail(\"Authentication failed\");\n    log.error(err instanceof Error ? err.message : String(err));\n    return null;\n  }\n}\n\nasync function resolveAuth(options: SetupOptions): Promise<AuthOptions | null> {\n  if (options.apiKey) return { mode: \"api-key\", apiKey: options.apiKey };\n  if (options.oauth) return { mode: \"oauth\" };\n\n  const apiKey = await authenticateAndGenerateKey();\n  if (!apiKey) return null;\n  return { mode: \"api-key\", apiKey };\n}\n\nasync function resolveMode(options: SetupOptions): Promise<SetupMode> {\n  if (options.cli) return \"cli\";\n  if (options.mcp || options.yes || options.oauth || options.apiKey) return \"mcp\";\n\n  return select<SetupMode>({\n    message: \"How should your agent access Context7?\",\n    choices: [\n      {\n        name: `MCP server\\n    ${pc.dim(\"Agent calls Context7 tools via MCP protocol to retrieve up-to-date library docs\")}`,\n        value: \"mcp\" as SetupMode,\n      },\n      {\n        name: `CLI + Skills\\n    ${pc.dim(\"Installs a find-docs skill that guides your agent to fetch up-to-date library docs using \")}${pc.dim(pc.bold(\"ctx7\"))}${pc.dim(\" CLI commands\")}`,\n        value: \"cli\" as SetupMode,\n      },\n    ],\n    theme: {\n      style: {\n        highlight: (text: string) => pc.green(text),\n        answer: (text: string) => pc.green(text.split(\"\\n\")[0].trim()),\n      },\n    },\n  });\n}\n\nasync function resolveCliAuth(apiKey?: string): Promise<void> {\n  if (apiKey) {\n    saveTokens({ access_token: apiKey, token_type: \"bearer\" });\n    log.blank();\n    log.plain(`${pc.green(\"✔\")} Authenticated`);\n    return;\n  }\n\n  const validToken = await getValidAccessToken();\n  if (validToken) {\n    log.blank();\n    log.plain(`${pc.green(\"✔\")} Authenticated`);\n    return;\n  }\n\n  await performLogin();\n}\n\nasync function isAlreadyConfigured(agentName: SetupAgent, scope: Scope): Promise<boolean> {\n  const agent = getAgent(agentName);\n  const mcpPath =\n    scope === \"global\" ? agent.mcp.globalPath : join(process.cwd(), agent.mcp.projectPath);\n  try {\n    const existing = await readJsonConfig(mcpPath);\n    const section = (existing[agent.mcp.configKey] as Record<string, unknown> | undefined) ?? {};\n    return \"context7\" in section;\n  } catch {\n    return false;\n  }\n}\n\nasync function promptAgents(scope: Scope, mode: SetupMode): Promise<SetupAgent[] | null> {\n  const choices = await Promise.all(\n    ALL_AGENT_NAMES.map(async (name) => {\n      const configured = mode === \"mcp\" ? await isAlreadyConfigured(name, scope) : false;\n      return {\n        name: SETUP_AGENT_NAMES[name],\n        value: name,\n        disabled: configured ? \"(already configured)\" : false,\n      };\n    })\n  );\n\n  if (choices.every((c) => c.disabled)) {\n    log.info(\"Context7 is already configured for all detected agents.\");\n    return null;\n  }\n\n  const message =\n    mode === \"cli\"\n      ? \"Install find-docs skill for which agents?\"\n      : \"Which agents do you want to set up?\";\n\n  try {\n    return await checkboxWithHover(\n      {\n        message,\n        choices,\n        loop: false,\n        theme: CHECKBOX_THEME,\n      },\n      { getName: (a: SetupAgent) => SETUP_AGENT_NAMES[a] }\n    );\n  } catch {\n    return null;\n  }\n}\n\nasync function resolveAgents(\n  options: SetupOptions,\n  scope: Scope,\n  mode: SetupMode = \"mcp\"\n): Promise<SetupAgent[]> {\n  const explicit = getSelectedAgents(options);\n  if (explicit.length > 0) return explicit;\n\n  const detected = await detectAgents(scope);\n\n  if (detected.length > 0 && options.yes) return detected;\n\n  log.blank();\n  const selected = await promptAgents(scope, mode);\n  if (!selected) {\n    log.warn(\"Setup cancelled\");\n    return [];\n  }\n  return selected;\n}\n\nasync function setupAgent(\n  agentName: SetupAgent,\n  auth: AuthOptions,\n  scope: Scope\n): Promise<{\n  agent: string;\n  mcpStatus: string;\n  mcpPath: string;\n  ruleStatus: string;\n  rulePath: string;\n  skillStatus: string;\n  skillPath: string;\n}> {\n  const agent = getAgent(agentName);\n\n  const mcpPath =\n    scope === \"global\" ? agent.mcp.globalPath : join(process.cwd(), agent.mcp.projectPath);\n\n  let mcpStatus: string;\n  try {\n    const existing = await readJsonConfig(mcpPath);\n    const { config, alreadyExists } = mergeServerEntry(\n      existing,\n      agent.mcp.configKey,\n      \"context7\",\n      agent.mcp.buildEntry(auth)\n    );\n\n    if (alreadyExists) {\n      mcpStatus = \"already configured\";\n    } else {\n      mcpStatus = `configured with ${AUTH_MODE_LABELS[auth.mode]}`;\n    }\n\n    const finalConfig = agent.rule.instructionsGlob\n      ? mergeInstructions(config, agent.rule.instructionsGlob(scope))\n      : config;\n\n    if (finalConfig !== existing) {\n      await writeJsonConfig(mcpPath, finalConfig);\n    }\n  } catch (err) {\n    mcpStatus = `failed: ${err instanceof Error ? err.message : String(err)}`;\n  }\n\n  const rulePath =\n    scope === \"global\"\n      ? join(agent.rule.dir(\"global\"), agent.rule.filename)\n      : join(process.cwd(), agent.rule.dir(\"project\"), agent.rule.filename);\n\n  let ruleStatus: string;\n  try {\n    await mkdir(dirname(rulePath), { recursive: true });\n    await writeFile(rulePath, RULE_CONTENT, \"utf-8\");\n    ruleStatus = \"installed\";\n  } catch (err) {\n    ruleStatus = `failed: ${err instanceof Error ? err.message : String(err)}`;\n  }\n\n  const skillDir =\n    scope === \"global\"\n      ? agent.skill.dir(\"global\")\n      : join(process.cwd(), agent.skill.dir(\"project\"));\n  const skillPath = join(skillDir, agent.skill.name, \"SKILL.md\");\n\n  let skillStatus: string;\n  try {\n    const downloadData = await downloadSkill(\"/upstash/context7\", agent.skill.name);\n    if (downloadData.error || downloadData.files.length === 0) {\n      throw new Error(downloadData.error || \"no files\");\n    }\n    await installSkillFiles(agent.skill.name, downloadData.files, skillDir);\n    skillStatus = \"installed\";\n  } catch (err) {\n    skillStatus = `failed: ${err instanceof Error ? err.message : String(err)}`;\n  }\n\n  return {\n    agent: agent.displayName,\n    mcpStatus,\n    mcpPath,\n    ruleStatus,\n    rulePath,\n    skillStatus,\n    skillPath,\n  };\n}\n\nasync function setupMcp(agents: SetupAgent[], options: SetupOptions, scope: Scope): Promise<void> {\n  const auth = await resolveAuth(options);\n  if (!auth) {\n    log.warn(\"Setup cancelled\");\n    return;\n  }\n\n  log.blank();\n  const spinner = ora(\"Setting up Context7...\").start();\n\n  const results = [];\n  for (const agentName of agents) {\n    spinner.text = `Setting up ${getAgent(agentName).displayName}...`;\n    results.push(await setupAgent(agentName, auth, scope));\n  }\n\n  spinner.succeed(\"Context7 setup complete\");\n\n  log.blank();\n  for (const r of results) {\n    log.plain(`  ${pc.bold(r.agent)}`);\n    const mcpIcon = r.mcpStatus.startsWith(\"configured\") ? pc.green(\"+\") : pc.dim(\"~\");\n    log.plain(`    ${mcpIcon} MCP server ${r.mcpStatus}`);\n    log.plain(`      ${pc.dim(r.mcpPath)}`);\n    const ruleIcon = r.ruleStatus === \"installed\" ? pc.green(\"+\") : pc.dim(\"~\");\n    log.plain(`    ${ruleIcon} Rule ${r.ruleStatus}`);\n    log.plain(`      ${pc.dim(r.rulePath)}`);\n    const skillIcon = r.skillStatus === \"installed\" ? pc.green(\"+\") : pc.dim(\"~\");\n    log.plain(`    ${skillIcon} Skill ${r.skillStatus}`);\n    log.plain(`      ${pc.dim(r.skillPath)}`);\n  }\n  log.blank();\n\n  trackEvent(\"setup\", { agents, scope, authMode: auth.mode });\n  trackEvent(\"install\", { skills: [\"/upstash/context7/context7-mcp\"], ides: agents });\n}\n\nasync function setupCli(options: SetupOptions): Promise<void> {\n  await resolveCliAuth(options.apiKey);\n\n  const targets = await promptForInstallTargets({ ...options, global: !options.project }, false);\n  if (!targets) {\n    log.warn(\"Setup cancelled\");\n    return;\n  }\n\n  log.blank();\n  const spinner = ora(\"Downloading find-docs skill...\").start();\n\n  const downloadData = await downloadSkill(\"/upstash/context7\", \"find-docs\");\n  if (downloadData.error || downloadData.files.length === 0) {\n    spinner.fail(`Failed to download find-docs skill: ${downloadData.error || \"no files\"}`);\n    return;\n  }\n\n  spinner.succeed(\"Downloaded find-docs skill\");\n\n  const targetDirs = getTargetDirs(targets);\n  const installSpinner = ora(\"Installing find-docs skill...\").start();\n\n  for (const dir of targetDirs) {\n    installSpinner.text = `Installing to ${dir}...`;\n    await installSkillFiles(\"find-docs\", downloadData.files, dir);\n  }\n\n  installSpinner.stop();\n  log.blank();\n  log.plain(`${pc.green(\"✔\")} Context7 CLI setup complete`);\n\n  log.blank();\n  for (const dir of targetDirs) {\n    log.itemAdd(\n      `find-docs  ${pc.dim(\"Guides your agent to fetch up-to-date library docs on demand using ctx7 CLI commands\")}`\n    );\n    log.plain(`    ${pc.dim(dir)}`);\n  }\n  log.blank();\n  log.plain(`  ${pc.bold(\"Next steps\")}`);\n  log.plain(`    Ask your agent: ${pc.cyan(`\"Use ctx7 CLI to look up React hooks\"`)}`);\n  log.blank();\n\n  trackEvent(\"setup\", { mode: \"cli\" });\n  trackEvent(\"install\", { skills: [\"/upstash/context7/find-docs\"], ides: targets.ides });\n}\n\nasync function setupCommand(options: SetupOptions): Promise<void> {\n  trackEvent(\"command\", { name: \"setup\" });\n\n  try {\n    const mode = await resolveMode(options);\n    if (mode === \"mcp\") {\n      const scope: Scope = options.project ? \"project\" : \"global\";\n      const agents = await resolveAgents(options, scope, mode);\n      if (agents.length === 0) return;\n      await setupMcp(agents, options, scope);\n    } else {\n      await setupCli(options);\n    }\n  } catch (err) {\n    if (err instanceof Error && err.name === \"ExitPromptError\") process.exit(0);\n    throw err;\n  }\n}\n"
  },
  {
    "path": "packages/cli/src/commands/skill.ts",
    "content": "import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport ora from \"ora\";\nimport { readdir, rm } from \"fs/promises\";\nimport { join } from \"path\";\n\nimport { parseSkillInput } from \"../utils/parse-input.js\";\nimport {\n  listProjectSkills,\n  searchSkills,\n  suggestSkills,\n  downloadSkill,\n  getSkill,\n} from \"../utils/api.js\";\nimport { log } from \"../utils/logger.js\";\nimport {\n  promptForInstallTargets,\n  promptForSingleTarget,\n  getTargetDirs,\n  getTargetDirFromSelection,\n  getSelectedIdes,\n  hasExplicitIdeOption,\n} from \"../utils/ide.js\";\nimport {\n  checkboxWithHover,\n  terminalLink,\n  formatPopularity,\n  formatTrust,\n  formatInstallRange,\n  getTrustLabel,\n} from \"../utils/prompts.js\";\nimport { installSkillFiles, symlinkSkill } from \"../utils/installer.js\";\nimport { trackEvent } from \"../utils/tracking.js\";\nimport { registerGenerateCommand } from \"./generate.js\";\nimport type {\n  Skill,\n  SkillSearchResult,\n  AddOptions,\n  ListOptions,\n  RemoveOptions,\n  SuggestOptions,\n  InstallTargets,\n  Scope,\n} from \"../types.js\";\nimport {\n  IDE_NAMES,\n  IDE_PATHS,\n  IDE_GLOBAL_PATHS,\n  UNIVERSAL_SKILLS_PATH,\n  UNIVERSAL_SKILLS_GLOBAL_PATH,\n  UNIVERSAL_AGENTS_LABEL,\n  VENDOR_SPECIFIC_AGENTS,\n} from \"../types.js\";\nimport { homedir } from \"os\";\nimport { detectProjectDependencies } from \"../utils/deps.js\";\nimport { loadTokens, isTokenExpired } from \"../utils/auth.js\";\n\nfunction logInstallSummary(\n  targets: InstallTargets,\n  targetDirs: string[],\n  skillNames: string[]\n): void {\n  log.blank();\n  const hasUniversal = targets.ides.some((ide) => ide === \"universal\");\n  const vendorIdes = targets.ides.filter((ide) => ide !== \"universal\");\n\n  let dirIndex = 0;\n  if (hasUniversal && dirIndex < targetDirs.length) {\n    log.plain(`${pc.bold(\"Universal\")} ${pc.dim(targetDirs[dirIndex])}`);\n    for (const name of skillNames) {\n      log.itemAdd(name);\n    }\n    dirIndex++;\n  }\n\n  for (const ide of vendorIdes) {\n    if (dirIndex >= targetDirs.length) break;\n    log.plain(`${pc.bold(IDE_NAMES[ide])} ${pc.dim(targetDirs[dirIndex])}`);\n    for (const name of skillNames) {\n      log.itemAdd(name);\n    }\n    dirIndex++;\n  }\n\n  log.blank();\n}\n\nexport function registerSkillCommands(program: Command): void {\n  const skill = program.command(\"skills\").alias(\"skill\").description(\"Manage AI coding skills\");\n\n  // Register generate subcommand\n  registerGenerateCommand(skill);\n\n  skill\n    .command(\"install\")\n    .alias(\"i\")\n    .alias(\"add\")\n    .argument(\"<repository>\", \"GitHub repository (/owner/repo)\")\n    .argument(\"[skill]\", \"Specific skill name to install\")\n    .option(\"--all\", \"Install all skills without prompting\")\n    .option(\"--global\", \"Install globally instead of current directory\")\n    .option(\"--claude\", \"Claude Code (.claude/skills/)\")\n    .option(\"--cursor\", \"Cursor (.cursor/skills/)\")\n    .option(\"--universal\", \"Universal (.agents/skills/)\")\n    .option(\"--antigravity\", \"Antigravity (.agent/skills/)\")\n    .description(\"Install skills from a repository\")\n    .action(async (project: string, skillName: string | undefined, options: AddOptions) => {\n      await installCommand(project, skillName, options);\n    });\n\n  skill\n    .command(\"search\")\n    .alias(\"s\")\n    .argument(\"<keywords...>\", \"Search keywords\")\n    .description(\"Search for skills across all indexed repositories\")\n    .action(async (keywords: string[]) => {\n      await searchCommand(keywords.join(\" \"));\n    });\n\n  skill\n    .command(\"list\")\n    .alias(\"ls\")\n    .option(\"--global\", \"List global skills\")\n    .option(\"--claude\", \"Claude Code (.claude/skills/)\")\n    .option(\"--cursor\", \"Cursor (.cursor/skills/)\")\n    .option(\"--universal\", \"Universal (.agents/skills/)\")\n    .option(\"--antigravity\", \"Antigravity (.agent/skills/)\")\n    .description(\"List installed skills\")\n    .action(async (options: ListOptions) => {\n      await listCommand(options);\n    });\n\n  skill\n    .command(\"remove\")\n    .alias(\"rm\")\n    .alias(\"delete\")\n    .argument(\"<name>\", \"Skill name to remove\")\n    .option(\"--global\", \"Remove from global skills\")\n    .option(\"--claude\", \"Claude Code (.claude/skills/)\")\n    .option(\"--cursor\", \"Cursor (.cursor/skills/)\")\n    .option(\"--universal\", \"Universal (.agents/skills/)\")\n    .option(\"--antigravity\", \"Antigravity (.agent/skills/)\")\n    .description(\"Remove an installed skill\")\n    .action(async (name: string, options: RemoveOptions) => {\n      await removeCommand(name, options);\n    });\n\n  skill\n    .command(\"info\")\n    .argument(\"<repository>\", \"GitHub repository (/owner/repo)\")\n    .description(\"Show skills in a repository\")\n    .action(async (project: string) => {\n      await infoCommand(project);\n    });\n\n  skill\n    .command(\"suggest\")\n    .option(\"--global\", \"Install globally instead of current directory\")\n    .option(\"--claude\", \"Claude Code (.claude/skills/)\")\n    .option(\"--cursor\", \"Cursor (.cursor/skills/)\")\n    .option(\"--universal\", \"Universal (.agents/skills/)\")\n    .option(\"--antigravity\", \"Antigravity (.agent/skills/)\")\n    .description(\"Suggest skills based on your project dependencies\")\n    .action(async (options: SuggestOptions) => {\n      await suggestCommand(options);\n    });\n}\n\nexport function registerSkillAliases(program: Command): void {\n  program\n    .command(\"si\", { hidden: true })\n    .argument(\"<repository>\", \"GitHub repository (/owner/repo)\")\n    .argument(\"[skill]\", \"Specific skill name to install\")\n    .option(\"--all\", \"Install all skills without prompting\")\n    .option(\"--global\", \"Install globally instead of current directory\")\n    .option(\"--claude\", \"Claude Code (.claude/skills/)\")\n    .option(\"--cursor\", \"Cursor (.cursor/skills/)\")\n    .option(\"--universal\", \"Universal (.agents/skills/)\")\n    .option(\"--antigravity\", \"Antigravity (.agent/skills/)\")\n    .description(\"Install skills (alias for: skills install)\")\n    .action(async (project: string, skillName: string | undefined, options: AddOptions) => {\n      await installCommand(project, skillName, options);\n    });\n\n  program\n    .command(\"ss\", { hidden: true })\n    .argument(\"<keywords...>\", \"Search keywords\")\n    .description(\"Search for skills (alias for: skills search)\")\n    .action(async (keywords: string[]) => {\n      await searchCommand(keywords.join(\" \"));\n    });\n\n  program\n    .command(\"ssg\", { hidden: true })\n    .option(\"--global\", \"Install globally instead of current directory\")\n    .option(\"--claude\", \"Claude Code (.claude/skills/)\")\n    .option(\"--cursor\", \"Cursor (.cursor/skills/)\")\n    .option(\"--universal\", \"Universal (.agents/skills/)\")\n    .option(\"--antigravity\", \"Antigravity (.agent/skills/)\")\n    .description(\"Suggest skills (alias for: skills suggest)\")\n    .action(async (options: SuggestOptions) => {\n      await suggestCommand(options);\n    });\n}\n\nasync function installCommand(\n  input: string,\n  skillName: string | undefined,\n  options: AddOptions\n): Promise<void> {\n  trackEvent(\"command\", { name: \"install\" });\n  const parsed = parseSkillInput(input);\n  if (!parsed) {\n    log.error(`Invalid input format: ${input}`);\n    log.info(`Expected: /owner/repo or full GitHub URL`);\n    log.info(`Example: ctx7 skills install /anthropics/skills pdf`);\n    log.blank();\n    return;\n  }\n  const repo = `/${parsed.owner}/${parsed.repo}`;\n\n  log.blank();\n  const spinner = ora(`Fetching skills from ${repo}...`).start();\n\n  let selectedSkills: (Skill & { project: string })[];\n\n  // When a specific skill name is provided, fetch only that skill\n  if (skillName) {\n    spinner.text = `Fetching skill: ${skillName}...`;\n    const skillData = await getSkill(repo, skillName);\n\n    if (skillData.error || !skillData.name) {\n      if (skillData.error === \"prompt_injection_detected\") {\n        spinner.fail(pc.red(`Prompt injection detected in skill: ${skillName}`));\n        log.warn(\"This skill contains potentially malicious content and cannot be installed.\");\n      } else {\n        spinner.fail(pc.red(`Skill not found: ${skillName}`));\n      }\n      return;\n    }\n\n    spinner.succeed(`Found skill: ${skillName}`);\n    selectedSkills = [\n      {\n        name: skillData.name,\n        description: skillData.description,\n        url: skillData.url,\n        project: repo,\n      },\n    ];\n  } else {\n    // Fetch all skills when no specific names provided\n    const data = await listProjectSkills(repo);\n\n    if (data.error) {\n      spinner.fail(pc.red(`Error: ${data.message || data.error}`));\n      return;\n    }\n\n    if (!data.skills || data.skills.length === 0) {\n      spinner.warn(pc.yellow(`No skills found in ${repo}`));\n      return;\n    }\n\n    const skillsWithRepo = data.skills\n      .map((s) => ({ ...s, project: repo }))\n      .sort((a, b) => (b.installCount ?? 0) - (a.installCount ?? 0));\n\n    spinner.succeed(`Found ${data.skills.length} skill(s)`);\n\n    if (data.blockedSkillsCount && data.blockedSkillsCount > 0) {\n      log.blank();\n      log.error(\n        `${data.blockedSkillsCount} skill(s) blocked due to prompt injection and not shown.`\n      );\n      log.warn(\"Review other skills from this repository carefully before installing.\");\n    }\n\n    if (options.all || data.skills.length === 1) {\n      selectedSkills = skillsWithRepo;\n    } else {\n      const indexWidth = data.skills.length.toString().length;\n      const maxNameLen = Math.max(...data.skills.map((s) => s.name.length));\n      const popularityColWidth = 13;\n      const choices = skillsWithRepo.map((s, index) => {\n        const indexStr = pc.dim(`${(index + 1).toString().padStart(indexWidth)}.`);\n        const paddedName = s.name.padEnd(maxNameLen);\n        const popularity = formatPopularity(s.installCount) + \" \".repeat(popularityColWidth - 4);\n        const trust = formatTrust(s.trustScore);\n\n        const skillUrl = `https://context7.com/skills${s.project}/${s.name}`;\n        const skillLink = terminalLink(s.name, skillUrl, pc.white);\n        const repoLink = terminalLink(s.project, `https://github.com${s.project}`, pc.white);\n        const metadataLines = [\n          pc.dim(\"─\".repeat(50)),\n          \"\",\n          `${pc.yellow(\"Skill:\")}       ${skillLink}`,\n          `${pc.yellow(\"Repo:\")}        ${repoLink}`,\n          `${pc.yellow(\"Installs:\")}    ${pc.white(formatInstallRange(s.installCount))}`,\n          `${pc.yellow(\"Trust:\")}       ${s.trustScore !== undefined && s.trustScore >= 0 ? pc.white(s.trustScore.toFixed(1)) : pc.dim(\"-\")}`,\n          `${pc.yellow(\"Description:\")}`,\n          pc.white(s.description || \"No description\"),\n        ];\n\n        return {\n          name: `${indexStr} ${paddedName} ${popularity}${trust}`,\n          value: s,\n          description: metadataLines.join(\"\\n\"),\n        };\n      });\n\n      log.blank();\n\n      const checkboxPrefixWidth = 3;\n      const headerPad = \" \".repeat(checkboxPrefixWidth + indexWidth + 1 + 1 + maxNameLen + 1);\n      const headerLine =\n        headerPad + pc.dim(\"Popularity\".padEnd(popularityColWidth)) + pc.dim(\"Trust\");\n\n      try {\n        selectedSkills = await checkboxWithHover({\n          message: `Select skills to install:\\n${headerLine}`,\n          choices,\n          pageSize: 15,\n          loop: false,\n          theme: {\n            style: {\n              message: (text: string, status: string) => {\n                if (status === \"done\") return pc.dim(text.split(\"\\n\")[0]);\n                return pc.bold(text);\n              },\n            },\n          },\n        });\n      } catch {\n        log.warn(\"Installation cancelled\");\n        return;\n      }\n    }\n  }\n\n  if (selectedSkills.length === 0) {\n    log.warn(\"No skills selected\");\n    return;\n  }\n\n  const targets = await promptForInstallTargets(options);\n  if (!targets) {\n    log.warn(\"Installation cancelled\");\n    return;\n  }\n\n  const targetDirs = getTargetDirs(targets);\n\n  const installSpinner = ora(\"Installing skills...\").start();\n\n  let permissionError = false;\n  const failedDirs: Set<string> = new Set();\n  const installedSkills: string[] = [];\n\n  for (const skill of selectedSkills) {\n    try {\n      installSpinner.text = `Downloading ${skill.name}...`;\n      const downloadData = await downloadSkill(skill.project, skill.name);\n\n      if (downloadData.error) {\n        log.warn(`Failed to download ${skill.name}: ${downloadData.error}`);\n        continue;\n      }\n\n      installSpinner.text = `Installing ${skill.name}...`;\n\n      const [primaryDir, ...symlinkDirs] = targetDirs;\n\n      try {\n        await installSkillFiles(skill.name, downloadData.files, primaryDir);\n      } catch (dirErr) {\n        const error = dirErr as NodeJS.ErrnoException;\n        if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n          permissionError = true;\n          failedDirs.add(primaryDir);\n        }\n        throw dirErr;\n      }\n\n      const primarySkillDir = join(primaryDir, skill.name);\n      for (const targetDir of symlinkDirs) {\n        try {\n          await symlinkSkill(skill.name, primarySkillDir, targetDir);\n        } catch (dirErr) {\n          const error = dirErr as NodeJS.ErrnoException;\n          if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n            permissionError = true;\n            failedDirs.add(targetDir);\n          }\n          throw dirErr;\n        }\n      }\n\n      installedSkills.push(`${skill.project}/${skill.name}`);\n    } catch (err) {\n      const error = err as NodeJS.ErrnoException;\n      if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n        continue;\n      }\n      const errMsg = err instanceof Error ? err.message : String(err);\n      log.warn(`Failed to install ${skill.name}: ${errMsg}`);\n    }\n  }\n\n  if (permissionError) {\n    installSpinner.fail(\"Permission denied\");\n    log.blank();\n    log.warn(\"Fix permissions with:\");\n    for (const dir of failedDirs) {\n      const parentDir = join(dir, \"..\");\n      log.dim(`  sudo chown -R $(whoami) \"${parentDir}\"`);\n    }\n    log.blank();\n    return;\n  }\n\n  installSpinner.succeed(`Installed ${installedSkills.length} skill(s)`);\n  trackEvent(\"install\", { skills: installedSkills, ides: targets.ides });\n\n  const installedNames = selectedSkills.map((s) => s.name);\n  logInstallSummary(targets, targetDirs, installedNames);\n}\n\nasync function searchCommand(query: string): Promise<void> {\n  trackEvent(\"command\", { name: \"search\" });\n  log.blank();\n  const spinner = ora(`Searching for \"${query}\"...`).start();\n\n  let data;\n  try {\n    data = await searchSkills(query);\n  } catch (err) {\n    spinner.fail(pc.red(`Error: ${err instanceof Error ? err.message : String(err)}`));\n    return;\n  }\n\n  if (data.error) {\n    spinner.fail(pc.red(`Error: ${data.message || data.error}`));\n    return;\n  }\n\n  if (!data.results || data.results.length === 0) {\n    spinner.warn(pc.yellow(`No skills found matching \"${query}\"`));\n    return;\n  }\n\n  spinner.succeed(`Found ${data.results.length} skill(s)`);\n  trackEvent(\"search_query\", { query, resultCount: data.results.length });\n  log.blank();\n\n  const indexWidth = data.results.length.toString().length;\n  const nameWithRepo = (s: SkillSearchResult) => `${s.name} ${pc.dim(`(${s.project})`)}`;\n  const nameWithRepoLen = (s: SkillSearchResult) => `${s.name} (${s.project})`.length;\n  const maxNameLen = Math.max(...data.results.map(nameWithRepoLen));\n  const popularityColWidth = 13;\n  const choices = data.results.map((s, index) => {\n    const indexStr = pc.dim(`${(index + 1).toString().padStart(indexWidth)}.`);\n    const rawLen = nameWithRepoLen(s);\n    const displayName = nameWithRepo(s) + \" \".repeat(maxNameLen - rawLen);\n    const popularity = formatPopularity(s.installCount) + \" \".repeat(popularityColWidth - 4);\n    const trust = formatTrust(s.trustScore);\n\n    const skillLink = terminalLink(\n      s.name,\n      `https://context7.com/skills${s.project}/${s.name}`,\n      pc.white\n    );\n    const repoLink = terminalLink(s.project, `https://github.com${s.project}`, pc.white);\n    const metadataLines = [\n      pc.dim(\"─\".repeat(50)),\n      \"\",\n      `${pc.yellow(\"Skill:\")}       ${skillLink}`,\n      `${pc.yellow(\"Repo:\")}        ${repoLink}`,\n      `${pc.yellow(\"Installs:\")}    ${pc.white(formatInstallRange(s.installCount))}`,\n      `${pc.yellow(\"Trust:\")}       ${s.trustScore !== undefined && s.trustScore >= 0 ? pc.white(s.trustScore.toFixed(1)) : pc.dim(\"-\")}`,\n      `${pc.yellow(\"Description:\")}`,\n      pc.white(s.description || \"No description\"),\n    ];\n\n    return {\n      name: `${indexStr} ${displayName} ${popularity}${trust}`,\n      value: s,\n      description: metadataLines.join(\"\\n\"),\n    };\n  });\n\n  const checkboxPrefixWidth = 3; // \"❯◯ \" or \" ◯ \"\n  const headerPad = \" \".repeat(checkboxPrefixWidth + indexWidth + 1 + 1 + maxNameLen + 1);\n  const headerLine = headerPad + pc.dim(\"Popularity\".padEnd(popularityColWidth)) + pc.dim(\"Trust\");\n\n  let selectedSkills: SkillSearchResult[];\n  try {\n    selectedSkills = await checkboxWithHover({\n      message: `Select skills to install:\\n${headerLine}`,\n      choices,\n      pageSize: 15,\n      loop: false,\n      theme: {\n        style: {\n          message: (text: string, status: string) => {\n            if (status === \"done\") return pc.dim(text.split(\"\\n\")[0]);\n            return pc.bold(text);\n          },\n        },\n      },\n    });\n  } catch {\n    log.warn(\"Installation cancelled\");\n    return;\n  }\n\n  const uniqueSkills = selectedSkills;\n\n  if (uniqueSkills.length === 0) {\n    log.warn(\"No skills selected\");\n    return;\n  }\n\n  const targets = await promptForInstallTargets({});\n  if (!targets) {\n    log.warn(\"Installation cancelled\");\n    return;\n  }\n\n  const targetDirs = getTargetDirs(targets);\n\n  const installSpinner = ora(\"Installing skills...\").start();\n\n  let permissionError = false;\n  const failedDirs: Set<string> = new Set();\n  const installedSkills: string[] = [];\n\n  for (const skill of uniqueSkills) {\n    try {\n      installSpinner.text = `Downloading ${skill.name}...`;\n      const downloadData = await downloadSkill(skill.project, skill.name);\n\n      if (downloadData.error) {\n        log.warn(`Failed to download ${skill.name}: ${downloadData.error}`);\n        continue;\n      }\n\n      installSpinner.text = `Installing ${skill.name}...`;\n\n      const [primaryDir, ...symlinkDirs] = targetDirs;\n\n      try {\n        await installSkillFiles(skill.name, downloadData.files, primaryDir);\n      } catch (dirErr) {\n        const error = dirErr as NodeJS.ErrnoException;\n        if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n          permissionError = true;\n          failedDirs.add(primaryDir);\n        }\n        throw dirErr;\n      }\n\n      const primarySkillDir = join(primaryDir, skill.name);\n      for (const targetDir of symlinkDirs) {\n        try {\n          await symlinkSkill(skill.name, primarySkillDir, targetDir);\n        } catch (dirErr) {\n          const error = dirErr as NodeJS.ErrnoException;\n          if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n            permissionError = true;\n            failedDirs.add(targetDir);\n          }\n          throw dirErr;\n        }\n      }\n\n      installedSkills.push(`${skill.project}/${skill.name}`);\n    } catch (err) {\n      const error = err as NodeJS.ErrnoException;\n      if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n        continue;\n      }\n      const errMsg = err instanceof Error ? err.message : String(err);\n      log.warn(`Failed to install ${skill.name}: ${errMsg}`);\n    }\n  }\n\n  if (permissionError) {\n    installSpinner.fail(\"Permission denied\");\n    log.blank();\n    log.warn(\"Fix permissions with:\");\n    for (const dir of failedDirs) {\n      const parentDir = join(dir, \"..\");\n      log.dim(`  sudo chown -R $(whoami) \"${parentDir}\"`);\n    }\n    log.blank();\n    return;\n  }\n\n  installSpinner.succeed(`Installed ${installedSkills.length} skill(s)`);\n  trackEvent(\"install\", { skills: installedSkills, ides: targets.ides });\n\n  const installedNames = uniqueSkills.map((s) => s.name);\n  logInstallSummary(targets, targetDirs, installedNames);\n}\n\nasync function listCommand(options: ListOptions): Promise<void> {\n  trackEvent(\"command\", { name: \"list\" });\n  const scope: Scope = options.global ? \"global\" : \"project\";\n  const baseDir = scope === \"global\" ? homedir() : process.cwd();\n\n  const results: { label: string; path: string; skills: string[] }[] = [];\n\n  // Helper to scan a skills directory\n  async function scanDir(dir: string): Promise<string[]> {\n    try {\n      const entries = await readdir(dir, { withFileTypes: true });\n      return entries.filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => e.name);\n    } catch {\n      return [];\n    }\n  }\n\n  if (hasExplicitIdeOption(options)) {\n    // Explicit flag mode — check the specific IDE paths\n    const ides = getSelectedIdes(options);\n    for (const ide of ides) {\n      const dir =\n        ide === \"universal\"\n          ? join(baseDir, scope === \"global\" ? UNIVERSAL_SKILLS_GLOBAL_PATH : UNIVERSAL_SKILLS_PATH)\n          : join(baseDir, (scope === \"global\" ? IDE_GLOBAL_PATHS : IDE_PATHS)[ide]);\n      const label = ide === \"universal\" ? UNIVERSAL_AGENTS_LABEL : IDE_NAMES[ide];\n      const skills = await scanDir(dir);\n      if (skills.length > 0) {\n        results.push({ label, path: dir, skills });\n      }\n    }\n  } else {\n    // Default: check universal + vendor-specific\n    const universalPath = scope === \"global\" ? UNIVERSAL_SKILLS_GLOBAL_PATH : UNIVERSAL_SKILLS_PATH;\n    const universalDir = join(baseDir, universalPath);\n    const universalSkills = await scanDir(universalDir);\n    if (universalSkills.length > 0) {\n      results.push({ label: UNIVERSAL_AGENTS_LABEL, path: universalPath, skills: universalSkills });\n    }\n\n    for (const ide of VENDOR_SPECIFIC_AGENTS) {\n      const pathMap = scope === \"global\" ? IDE_GLOBAL_PATHS : IDE_PATHS;\n      const dir = join(baseDir, pathMap[ide]);\n      const skills = await scanDir(dir);\n      if (skills.length > 0) {\n        results.push({ label: IDE_NAMES[ide], path: pathMap[ide], skills });\n      }\n    }\n  }\n\n  if (results.length === 0) {\n    log.warn(\"No skills installed\");\n    return;\n  }\n\n  log.blank();\n\n  for (const { label, path, skills } of results) {\n    log.plain(`${pc.bold(label)} ${pc.dim(path)}`);\n    for (const skill of skills) {\n      log.plain(`  ${pc.green(skill)}`);\n    }\n    log.blank();\n  }\n}\n\nasync function removeCommand(name: string, options: RemoveOptions): Promise<void> {\n  trackEvent(\"command\", { name: \"remove\" });\n  const target = await promptForSingleTarget(options);\n  if (!target) {\n    log.warn(\"Cancelled\");\n    return;\n  }\n\n  const skillsDir = getTargetDirFromSelection(target.ide, target.scope);\n  const skillPath = join(skillsDir, name);\n\n  try {\n    await rm(skillPath, { recursive: true });\n    log.success(`Removed skill: ${name}`);\n  } catch (err) {\n    const error = err as NodeJS.ErrnoException;\n    if (error.code === \"ENOENT\") {\n      log.error(`Skill not found: ${name}`);\n    } else if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n      log.error(`Permission denied. Try: sudo rm -rf \"${skillPath}\"`);\n    } else {\n      log.error(`Failed to remove skill: ${error.message}`);\n    }\n  }\n}\n\nasync function infoCommand(input: string): Promise<void> {\n  trackEvent(\"command\", { name: \"info\" });\n  const parsed = parseSkillInput(input);\n  if (!parsed) {\n    log.blank();\n    log.error(`Invalid input format: ${input}`);\n    log.info(`Expected: /owner/repo or full GitHub URL`);\n    log.blank();\n    return;\n  }\n  const repo = `/${parsed.owner}/${parsed.repo}`;\n\n  log.blank();\n  const spinner = ora(`Fetching skills from ${repo}...`).start();\n\n  const data = await listProjectSkills(repo);\n\n  if (data.error) {\n    spinner.fail(pc.red(`Error: ${data.message || data.error}`));\n    return;\n  }\n\n  if (!data.skills || data.skills.length === 0) {\n    spinner.warn(pc.yellow(`No skills found in ${repo}`));\n    return;\n  }\n\n  spinner.succeed(`Found ${data.skills.length} skill(s)`);\n\n  log.blank();\n  for (const skill of data.skills) {\n    log.item(skill.name);\n    log.dim(`    ${skill.description || \"No description\"}`);\n    log.dim(`    URL: ${skill.url}`);\n    log.blank();\n  }\n\n  log.plain(\n    `${pc.bold(\"Quick commands:\")}\\n` +\n      `  Install all: ${pc.cyan(`ctx7 skills install ${repo} --all`)}\\n` +\n      `  Install one: ${pc.cyan(`ctx7 skills install ${repo} ${data.skills[0]?.name}`)}\\n`\n  );\n}\n\nasync function suggestCommand(options: SuggestOptions): Promise<void> {\n  trackEvent(\"command\", { name: \"suggest\" });\n  log.blank();\n\n  // Step 1: Detect dependencies\n  const scanSpinner = ora(\"Scanning project dependencies...\").start();\n  const deps = await detectProjectDependencies(process.cwd());\n\n  if (deps.length === 0) {\n    scanSpinner.warn(pc.yellow(\"No dependencies detected\"));\n    log.info(`Try ${pc.cyan(\"ctx7 skills search <keyword>\")} to search manually`);\n    return;\n  }\n\n  scanSpinner.succeed(`Found ${deps.length} dependencies`);\n\n  // Step 2: Single API call to backend\n  const searchSpinner = ora(\"Finding matching skills...\").start();\n\n  const tokens = loadTokens();\n  const accessToken = tokens && !isTokenExpired(tokens) ? tokens.access_token : undefined;\n\n  let data;\n  try {\n    data = await suggestSkills(deps, accessToken);\n  } catch {\n    searchSpinner.fail(pc.red(\"Failed to connect to Context7\"));\n    return;\n  }\n\n  if (data.error) {\n    searchSpinner.fail(pc.red(`Error: ${data.message || data.error}`));\n    return;\n  }\n\n  const skills = data.skills;\n\n  if (skills.length === 0) {\n    searchSpinner.warn(pc.yellow(\"No matching skills found for your dependencies\"));\n    return;\n  }\n\n  searchSpinner.succeed(`Found ${skills.length} relevant skill(s)`);\n  trackEvent(\"suggest_results\", { depCount: deps.length, skillCount: skills.length });\n  log.blank();\n\n  const nameWithRepo = (s: SkillSearchResult) => `${s.name} ${pc.dim(`(${s.project})`)}`;\n  const nameWithRepoLen = (s: SkillSearchResult) => `${s.name} (${s.project})`.length;\n  const maxNameLen = Math.max(...skills.map(nameWithRepoLen));\n  const popularityColWidth = 13;\n  const trustColWidth = 8;\n  const maxMatchedLen = Math.max(...skills.map((s) => s.matchedDep.length));\n  const indexWidth = skills.length.toString().length;\n\n  const choices = skills.map((s, index) => {\n    const indexStr = pc.dim(`${(index + 1).toString().padStart(indexWidth)}.`);\n    const rawLen = nameWithRepoLen(s);\n    const displayName = nameWithRepo(s) + \" \".repeat(maxNameLen - rawLen);\n    const popularity = formatPopularity(s.installCount) + \" \".repeat(popularityColWidth - 4);\n    const trustLabel = getTrustLabel(s.trustScore);\n    const trust = formatTrust(s.trustScore) + \" \".repeat(trustColWidth - trustLabel.length);\n    const matched = pc.yellow(s.matchedDep.padEnd(maxMatchedLen));\n\n    const skillLink = terminalLink(\n      s.name,\n      `https://context7.com/skills${s.project}/${s.name}`,\n      pc.white\n    );\n    const repoLink = terminalLink(s.project, `https://github.com${s.project}`, pc.white);\n    const metadataLines = [\n      pc.dim(\"─\".repeat(50)),\n      \"\",\n      `${pc.yellow(\"Skill:\")}       ${skillLink}`,\n      `${pc.yellow(\"Repo:\")}        ${repoLink}`,\n      `${pc.yellow(\"Installs:\")}    ${pc.white(formatInstallRange(s.installCount))}`,\n      `${pc.yellow(\"Trust:\")}       ${s.trustScore !== undefined && s.trustScore >= 0 ? pc.white(s.trustScore.toFixed(1)) : pc.dim(\"-\")}`,\n      `${pc.yellow(\"Relevant:\")}    ${pc.white(s.matchedDep)}`,\n      `${pc.yellow(\"Description:\")}`,\n      pc.white(s.description || \"No description\"),\n    ];\n\n    return {\n      name: `${indexStr} ${displayName} ${popularity}${trust}${matched}`,\n      value: s,\n      description: metadataLines.join(\"\\n\"),\n    };\n  });\n\n  const checkboxPrefixWidth = 3; // \"❯◯ \" or \" ◯ \"\n  const headerPad = \" \".repeat(checkboxPrefixWidth + indexWidth + 1 + 1 + maxNameLen + 1);\n  const headerLine =\n    headerPad +\n    pc.dim(\"Popularity\".padEnd(popularityColWidth)) +\n    pc.dim(\"Trust\".padEnd(trustColWidth)) +\n    pc.dim(\"Relevant\");\n\n  let selectedSkills: SkillSearchResult[];\n  try {\n    selectedSkills = await checkboxWithHover({\n      message: `Select skills to install:\\n${headerLine}`,\n      choices,\n      pageSize: 15,\n      loop: false,\n      theme: {\n        style: {\n          message: (text: string, status: string) => {\n            if (status === \"done\") return pc.dim(text.split(\"\\n\")[0]);\n            return pc.bold(text);\n          },\n        },\n      },\n    });\n  } catch {\n    log.warn(\"Installation cancelled\");\n    return;\n  }\n\n  if (selectedSkills.length === 0) {\n    log.warn(\"No skills selected\");\n    return;\n  }\n\n  // Step 4: Install (same pattern as searchCommand)\n  const targets = await promptForInstallTargets(options);\n  if (!targets) {\n    log.warn(\"Installation cancelled\");\n    return;\n  }\n\n  const targetDirs = getTargetDirs(targets);\n  const installSpinner = ora(\"Installing skills...\").start();\n\n  let permissionError = false;\n  const failedDirs: Set<string> = new Set();\n  const installedSkills: string[] = [];\n\n  for (const skill of selectedSkills) {\n    try {\n      installSpinner.text = `Downloading ${skill.name}...`;\n      const downloadData = await downloadSkill(skill.project, skill.name);\n\n      if (downloadData.error) {\n        log.warn(`Failed to download ${skill.name}: ${downloadData.error}`);\n        continue;\n      }\n\n      installSpinner.text = `Installing ${skill.name}...`;\n\n      const [primaryDir, ...symlinkDirs] = targetDirs;\n\n      try {\n        await installSkillFiles(skill.name, downloadData.files, primaryDir);\n      } catch (dirErr) {\n        const error = dirErr as NodeJS.ErrnoException;\n        if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n          permissionError = true;\n          failedDirs.add(primaryDir);\n        }\n        throw dirErr;\n      }\n\n      const primarySkillDir = join(primaryDir, skill.name);\n      for (const targetDir of symlinkDirs) {\n        try {\n          await symlinkSkill(skill.name, primarySkillDir, targetDir);\n        } catch (dirErr) {\n          const error = dirErr as NodeJS.ErrnoException;\n          if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n            permissionError = true;\n            failedDirs.add(targetDir);\n          }\n          throw dirErr;\n        }\n      }\n\n      installedSkills.push(`${skill.project}/${skill.name}`);\n    } catch (err) {\n      const error = err as NodeJS.ErrnoException;\n      if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n        continue;\n      }\n      const errMsg = err instanceof Error ? err.message : String(err);\n      log.warn(`Failed to install ${skill.name}: ${errMsg}`);\n    }\n  }\n\n  if (permissionError) {\n    installSpinner.fail(\"Permission denied\");\n    log.blank();\n    log.warn(\"Fix permissions with:\");\n    for (const dir of failedDirs) {\n      const parentDir = join(dir, \"..\");\n      log.dim(`  sudo chown -R $(whoami) \"${parentDir}\"`);\n    }\n    log.blank();\n    return;\n  }\n\n  installSpinner.succeed(`Installed ${installedSkills.length} skill(s)`);\n  trackEvent(\"suggest_install\", { skills: installedSkills, ides: targets.ides });\n\n  const installedNames = selectedSkills.map((s) => s.name);\n  logInstallSummary(targets, targetDirs, installedNames);\n}\n"
  },
  {
    "path": "packages/cli/src/constants.ts",
    "content": "import { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"../package.json\"), \"utf-8\"));\n\nexport const VERSION: string = pkg.version;\nexport const NAME: string = pkg.name;\nexport const CLI_CLIENT_ID = \"2veBSofhicRBguUT\";\n"
  },
  {
    "path": "packages/cli/src/index.ts",
    "content": "import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport figlet from \"figlet\";\nimport { registerSkillCommands, registerSkillAliases } from \"./commands/skill.js\";\nimport { registerAuthCommands, setAuthBaseUrl } from \"./commands/auth.js\";\nimport { registerSetupCommand } from \"./commands/setup.js\";\nimport { registerDocsCommands } from \"./commands/docs.js\";\nimport { setBaseUrl } from \"./utils/api.js\";\nimport { VERSION } from \"./constants.js\";\n\nconst brand = {\n  primary: pc.green,\n  dim: pc.dim,\n};\n\nconst program = new Command();\n\nprogram\n  .name(\"ctx7\")\n  .description(\"Context7 CLI - Manage AI coding skills and documentation context\")\n  .version(VERSION)\n  .option(\"--base-url <url>\")\n  .hook(\"preAction\", (thisCommand) => {\n    const opts = thisCommand.opts();\n    if (opts.baseUrl) {\n      setBaseUrl(opts.baseUrl);\n      setAuthBaseUrl(opts.baseUrl);\n    }\n  })\n  .addHelpText(\n    \"after\",\n    `\nExamples:\n  ${brand.dim(\"# Search for skills\")}\n  ${brand.primary(\"npx ctx7 skills search pdf\")}\n  ${brand.primary(\"npx ctx7 skills search react hooks\")}\n\n  ${brand.dim(\"# Install from a repository\")}\n  ${brand.primary(\"npx ctx7 skills install /anthropics/skills\")}\n  ${brand.primary(\"npx ctx7 skills install /anthropics/skills pdf\")}\n\n  ${brand.dim(\"# Install to specific client\")}\n  ${brand.primary(\"npx ctx7 skills install /anthropics/skills --cursor\")}\n  ${brand.primary(\"npx ctx7 skills install /anthropics/skills --global\")}\n\n  ${brand.dim(\"# List and manage installed skills\")}\n  ${brand.primary(\"npx ctx7 skills list --claude\")}\n  ${brand.primary(\"npx ctx7 skills remove pdf\")}\n\n  ${brand.dim(\"# Query library documentation\")}\n  ${brand.primary('npx ctx7 library react \"how to use hooks\"')}\n  ${brand.primary('npx ctx7 docs /facebook/react \"useEffect examples\"')}\n\nVisit ${brand.primary(\"https://context7.com\")} to browse skills\n`\n  );\n\nregisterSkillCommands(program);\nregisterSkillAliases(program);\nregisterAuthCommands(program);\nregisterSetupCommand(program);\nregisterDocsCommands(program);\n\nprogram.action(() => {\n  console.log(\"\");\n  const banner = figlet.textSync(\"Context7\", { font: \"ANSI Shadow\" });\n  console.log(brand.primary(banner));\n  console.log(brand.dim(\"  The open agent skills ecosystem\"));\n  console.log(\"\");\n\n  console.log(\"  Quick start:\");\n  console.log(`    ${brand.primary(\"npx ctx7 skills search pdf\")}`);\n  console.log(`    ${brand.primary(\"npx ctx7 skills install /anthropics/skills\")}`);\n  console.log(\"\");\n\n  console.log(`  Run ${brand.primary(\"npx ctx7 --help\")} for all commands and options`);\n  console.log(`  Visit ${brand.primary(\"https://context7.com\")} to browse skills`);\n  console.log(\"\");\n});\n\nprogram.parse();\n"
  },
  {
    "path": "packages/cli/src/setup/agents.ts",
    "content": "import { access } from \"fs/promises\";\nimport { join } from \"path\";\nimport { homedir } from \"os\";\n\nexport type SetupAgent = \"claude\" | \"cursor\" | \"opencode\";\nexport type AuthMode = \"oauth\" | \"api-key\";\n\nexport interface AuthOptions {\n  mode: AuthMode;\n  apiKey?: string;\n}\n\nexport const SETUP_AGENT_NAMES: Record<SetupAgent, string> = {\n  claude: \"Claude Code\",\n  cursor: \"Cursor\",\n  opencode: \"OpenCode\",\n};\n\nexport const AUTH_MODE_LABELS: Record<AuthMode, string> = {\n  oauth: \"OAuth\",\n  \"api-key\": \"API Key\",\n};\n\nconst MCP_BASE_URL = \"https://mcp.context7.com\";\n\nexport interface AgentConfig {\n  name: SetupAgent;\n  displayName: string;\n  mcp: {\n    projectPath: string;\n    globalPath: string;\n    configKey: string;\n    buildEntry: (auth: AuthOptions) => Record<string, unknown>;\n  };\n  rule: {\n    dir: (scope: \"project\" | \"global\") => string;\n    filename: string;\n    /** When set, the rule path is registered in the agent's config `instructions` array */\n    instructionsGlob?: (scope: \"project\" | \"global\") => string;\n  };\n  skill: {\n    name: string;\n    dir: (scope: \"project\" | \"global\") => string;\n  };\n  detect: {\n    projectPaths: string[];\n    globalPaths: string[];\n  };\n}\n\nfunction mcpUrl(auth: AuthOptions): string {\n  return auth.mode === \"oauth\" ? `${MCP_BASE_URL}/mcp/oauth` : `${MCP_BASE_URL}/mcp`;\n}\n\nfunction withHeaders(base: Record<string, unknown>, auth: AuthOptions): Record<string, unknown> {\n  if (auth.mode === \"api-key\" && auth.apiKey) {\n    return { ...base, headers: { CONTEXT7_API_KEY: auth.apiKey } };\n  }\n  return base;\n}\n\nconst agents: Record<SetupAgent, AgentConfig> = {\n  claude: {\n    name: \"claude\",\n    displayName: \"Claude Code\",\n    mcp: {\n      projectPath: \".mcp.json\",\n      globalPath: join(homedir(), \".claude.json\"),\n      configKey: \"mcpServers\",\n      buildEntry: (auth) => withHeaders({ type: \"http\", url: mcpUrl(auth) }, auth),\n    },\n    rule: {\n      dir: (scope) =>\n        scope === \"global\" ? join(homedir(), \".claude\", \"rules\") : join(\".claude\", \"rules\"),\n      filename: \"context7.md\",\n    },\n    skill: {\n      name: \"context7-mcp\",\n      dir: (scope) =>\n        scope === \"global\" ? join(homedir(), \".claude\", \"skills\") : join(\".claude\", \"skills\"),\n    },\n    detect: {\n      projectPaths: [\".mcp.json\", \".claude\"],\n      globalPaths: [join(homedir(), \".claude\")],\n    },\n  },\n\n  cursor: {\n    name: \"cursor\",\n    displayName: \"Cursor\",\n    mcp: {\n      projectPath: join(\".cursor\", \"mcp.json\"),\n      globalPath: join(homedir(), \".cursor\", \"mcp.json\"),\n      configKey: \"mcpServers\",\n      buildEntry: (auth) => withHeaders({ url: mcpUrl(auth) }, auth),\n    },\n    rule: {\n      dir: (scope) =>\n        scope === \"global\" ? join(homedir(), \".cursor\", \"rules\") : join(\".cursor\", \"rules\"),\n      filename: \"context7.mdc\",\n    },\n    skill: {\n      name: \"context7-mcp\",\n      dir: (scope) =>\n        scope === \"global\" ? join(homedir(), \".cursor\", \"skills\") : join(\".cursor\", \"skills\"),\n    },\n    detect: {\n      projectPaths: [\".cursor\"],\n      globalPaths: [join(homedir(), \".cursor\")],\n    },\n  },\n\n  opencode: {\n    name: \"opencode\",\n    displayName: \"OpenCode\",\n    mcp: {\n      projectPath: \".opencode.json\",\n      globalPath: join(homedir(), \".config\", \"opencode\", \"opencode.json\"),\n      configKey: \"mcp\",\n      buildEntry: (auth) => withHeaders({ type: \"remote\", url: mcpUrl(auth), enabled: true }, auth),\n    },\n    rule: {\n      dir: (scope) =>\n        scope === \"global\"\n          ? join(homedir(), \".config\", \"opencode\", \"rules\")\n          : join(\".opencode\", \"rules\"),\n      filename: \"context7.md\",\n      instructionsGlob: (scope) =>\n        scope === \"global\"\n          ? join(homedir(), \".config\", \"opencode\", \"rules\", \"*.md\")\n          : \".opencode/rules/*.md\",\n    },\n    skill: {\n      name: \"context7-mcp\",\n      dir: (scope) =>\n        scope === \"global\" ? join(homedir(), \".agents\", \"skills\") : join(\".agents\", \"skills\"),\n    },\n    detect: {\n      projectPaths: [\".opencode.json\"],\n      globalPaths: [join(homedir(), \".config\", \"opencode\")],\n    },\n  },\n};\n\nexport function getAgent(name: SetupAgent): AgentConfig {\n  return agents[name];\n}\n\nexport const ALL_AGENT_NAMES: SetupAgent[] = Object.keys(agents) as SetupAgent[];\n\nasync function pathExists(p: string): Promise<boolean> {\n  try {\n    await access(p);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nexport async function detectAgents(scope: \"project\" | \"global\"): Promise<SetupAgent[]> {\n  const detected: SetupAgent[] = [];\n\n  for (const agent of Object.values(agents)) {\n    const paths = scope === \"global\" ? agent.detect.globalPaths : agent.detect.projectPaths;\n    for (const p of paths) {\n      const fullPath = scope === \"global\" ? p : join(process.cwd(), p);\n      if (await pathExists(fullPath)) {\n        detected.push(agent.name);\n        break;\n      }\n    }\n  }\n\n  return detected;\n}\n"
  },
  {
    "path": "packages/cli/src/setup/mcp-writer.ts",
    "content": "import { readFile, writeFile, mkdir } from \"fs/promises\";\nimport { dirname } from \"path\";\n\nexport async function readJsonConfig(filePath: string): Promise<Record<string, unknown>> {\n  let raw: string;\n  try {\n    raw = await readFile(filePath, \"utf-8\");\n  } catch {\n    return {};\n  }\n\n  raw = raw.trim();\n  if (!raw) return {};\n\n  return JSON.parse(raw) as Record<string, unknown>;\n}\n\nexport function mergeServerEntry(\n  existing: Record<string, unknown>,\n  configKey: string,\n  serverName: string,\n  entry: Record<string, unknown>\n): { config: Record<string, unknown>; alreadyExists: boolean } {\n  const section = (existing[configKey] as Record<string, unknown> | undefined) ?? {};\n\n  if (serverName in section) {\n    return { config: existing, alreadyExists: true };\n  }\n\n  return {\n    config: {\n      ...existing,\n      [configKey]: {\n        ...section,\n        [serverName]: entry,\n      },\n    },\n    alreadyExists: false,\n  };\n}\n\nexport function mergeInstructions(\n  config: Record<string, unknown>,\n  glob: string\n): Record<string, unknown> {\n  const instructions = (config.instructions as string[] | undefined) ?? [];\n  if (instructions.includes(glob)) return config;\n  return { ...config, instructions: [...instructions, glob] };\n}\n\nexport async function writeJsonConfig(\n  filePath: string,\n  config: Record<string, unknown>\n): Promise<void> {\n  await mkdir(dirname(filePath), { recursive: true });\n  await writeFile(filePath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n}\n"
  },
  {
    "path": "packages/cli/src/setup/templates.ts",
    "content": "export const RULE_CONTENT = `---\nalwaysApply: true\n---\n\nWhen working with libraries, frameworks, or APIs — use Context7 MCP to fetch current documentation instead of relying on training data. This includes setup questions, code generation, API references, and anything involving specific packages.\n\n## Steps\n\n1. Call \\`resolve-library-id\\` with the library name and the user's question\n2. Pick the best match — prefer exact names and version-specific IDs when a version is mentioned\n3. Call \\`query-docs\\` with the selected library ID and the user's question\n4. Answer using the fetched docs — include code examples and cite the version\n`;\n"
  },
  {
    "path": "packages/cli/src/types.ts",
    "content": "export interface SkillFile {\n  path: string;\n  content: string;\n}\n\nexport interface Skill {\n  name: string;\n  description: string;\n  url: string;\n  installCount?: number;\n  trustScore?: number;\n}\n\nexport interface SkillSearchResult extends Skill {\n  project: string;\n}\n\nexport interface ListSkillsResponse {\n  project: string;\n  skills: Skill[];\n  blockedSkillsCount?: number;\n  error?: string;\n  message?: string;\n}\n\nexport interface SingleSkillResponse extends Skill {\n  project: string;\n  error?: string;\n  message?: string;\n}\n\nexport interface SearchResponse {\n  results: SkillSearchResult[];\n  error?: string;\n  message?: string;\n}\n\nexport interface DownloadResponse {\n  skill: Skill & { project: string };\n  files: SkillFile[];\n  error?: string;\n}\n\n// Library search types\nexport interface LibrarySearchResult {\n  id: string;\n  title: string;\n  description: string;\n  branch: string;\n  totalSnippets: number;\n  totalTokens?: number;\n  stars?: number;\n  trustScore?: number;\n  benchmarkScore?: number;\n  versions?: string[];\n}\n\nexport interface LibrarySearchResponse {\n  results: LibrarySearchResult[];\n  searchFilterApplied?: boolean;\n  error?: string;\n  message?: string;\n}\n\n// Skill generation types\nexport interface SkillQuestion {\n  question: string;\n  options: string[];\n  recommendedIndex: number;\n}\n\nexport interface SkillQuestionsResponse {\n  questions: SkillQuestion[];\n  error?: string;\n  message?: string;\n}\n\nexport interface SkillAnswer {\n  question: string;\n  answer: string;\n}\n\nexport interface LibraryInput {\n  id: string;\n  name: string;\n}\n\nexport interface StructuredGenerateInput {\n  motivation: string;\n  libraries: LibraryInput[];\n  answers: SkillAnswer[];\n  feedback?: string;\n  previousContent?: string;\n}\n\nexport interface ToolResultSnippet {\n  title: string;\n  content: string;\n}\n\nexport interface ProgressEvent {\n  type: \"progress\";\n  message: string;\n}\n\nexport interface ToolResultEvent {\n  type: \"tool_result\";\n  toolName: string;\n  query: string;\n  libraryId?: string;\n  results: ToolResultSnippet[];\n}\n\nexport interface CompleteEvent {\n  type: \"complete\";\n  content: string;\n  libraryName: string;\n}\n\nexport interface ErrorEvent {\n  type: \"error\";\n  message: string;\n}\n\nexport type GenerateStreamEvent = ProgressEvent | ToolResultEvent | CompleteEvent | ErrorEvent;\n\nexport type IDE = \"claude\" | \"cursor\" | \"antigravity\" | \"universal\";\n\nexport type Scope = \"project\" | \"global\";\n\nexport interface IDEOptions {\n  claude?: boolean;\n  cursor?: boolean;\n  universal?: boolean;\n  antigravity?: boolean;\n}\n\nexport interface ScopeOptions {\n  global?: boolean;\n}\n\nexport type AddOptions = IDEOptions & ScopeOptions & { all?: boolean; yes?: boolean };\nexport type SuggestOptions = IDEOptions & ScopeOptions;\nexport type ListOptions = IDEOptions & ScopeOptions;\nexport type RemoveOptions = IDEOptions & ScopeOptions;\nexport type GenerateOptions = IDEOptions &\n  ScopeOptions & {\n    output?: string;\n    all?: boolean;\n  };\n\nexport interface InstallTargets {\n  ides: IDE[];\n  scopes: Scope[];\n}\n\nexport const IDE_PATHS: Record<IDE, string> = {\n  claude: \".claude/skills\",\n  cursor: \".cursor/skills\",\n  antigravity: \".agent/skills\",\n  universal: \".agents/skills\",\n};\n\nexport const IDE_GLOBAL_PATHS: Record<IDE, string> = {\n  claude: \".claude/skills\",\n  cursor: \".cursor/skills\",\n  antigravity: \".agent/skills\",\n  universal: \".agents/skills\",\n};\n\nexport const IDE_NAMES: Record<IDE, string> = {\n  claude: \"Claude Code\",\n  cursor: \"Cursor\",\n  antigravity: \"Antigravity\",\n  universal: \"Universal\",\n};\n\n// Universal .agents/skills standard\n// These agents read from .agents/skills/ natively — one install covers all of them.\nexport const UNIVERSAL_SKILLS_PATH = \".agents/skills\";\nexport const UNIVERSAL_SKILLS_GLOBAL_PATH = \".agents/skills\";\n\n// Display label for agents that read .agents/skills/ (includes agents beyond our IDE type)\nexport const UNIVERSAL_AGENTS_LABEL = \"Amp, Codex, Gemini CLI, GitHub Copilot, OpenCode + more\";\n\n// Agents that still require their own vendor-specific skill directory.\nexport const VENDOR_SPECIFIC_AGENTS: IDE[] = [\"claude\", \"cursor\", \"antigravity\"];\n\nexport interface C7Config {\n  defaultIde: IDE;\n  defaultScope: \"project\" | \"global\";\n}\n\nexport const DEFAULT_CONFIG: C7Config = {\n  defaultIde: \"universal\",\n  defaultScope: \"project\",\n};\n\n// Suggest endpoint types\nexport interface SuggestSkill extends SkillSearchResult {\n  matchedDep: string;\n}\n\nexport interface SuggestResponse {\n  skills: SuggestSkill[];\n  error?: string;\n  message?: string;\n}\n\nexport interface SkillQuotaResponse {\n  used: number;\n  limit: number;\n  remaining: number;\n  tier: \"free\" | \"pro\" | \"unlimited\";\n  resetDate: string | null;\n  message?: string;\n  error?: string;\n}\n\nexport interface CodeExample {\n  language: string;\n  code: string;\n}\n\nexport interface CodeSnippet {\n  codeTitle: string;\n  codeDescription: string;\n  codeLanguage: string;\n  codeTokens: number;\n  codeId: string;\n  pageTitle: string;\n  codeList: CodeExample[];\n}\n\nexport interface InfoSnippet {\n  pageId?: string;\n  breadcrumb?: string;\n  content: string;\n  contentTokens: number;\n}\n\nexport interface ContextResponse {\n  codeSnippets: CodeSnippet[];\n  infoSnippets: InfoSnippet[];\n  error?: string;\n  message?: string;\n  redirectUrl?: string;\n}\n"
  },
  {
    "path": "packages/cli/src/utils/api.ts",
    "content": "import type {\n  ListSkillsResponse,\n  SingleSkillResponse,\n  SearchResponse,\n  SuggestResponse,\n  DownloadResponse,\n  LibrarySearchResponse,\n  SkillQuestionsResponse,\n  StructuredGenerateInput,\n  GenerateStreamEvent,\n  SkillQuotaResponse,\n  ContextResponse,\n} from \"../types.js\";\nimport { downloadSkillFromGitHub } from \"./github.js\";\nimport { VERSION } from \"../constants.js\";\n\nlet baseUrl = \"https://context7.com\";\n\nexport function getBaseUrl(): string {\n  return baseUrl;\n}\n\nexport function setBaseUrl(url: string): void {\n  baseUrl = url;\n}\n\nexport async function listProjectSkills(project: string): Promise<ListSkillsResponse> {\n  const params = new URLSearchParams({ project });\n  const response = await fetch(`${baseUrl}/api/v2/skills?${params}`);\n  return (await response.json()) as ListSkillsResponse;\n}\n\nexport async function getSkill(project: string, skillName: string): Promise<SingleSkillResponse> {\n  const params = new URLSearchParams({ project, skill: skillName });\n  const response = await fetch(`${baseUrl}/api/v2/skills?${params}`);\n  return (await response.json()) as SingleSkillResponse;\n}\n\nexport async function searchSkills(query: string): Promise<SearchResponse> {\n  const params = new URLSearchParams({ query });\n  const response = await fetch(`${baseUrl}/api/v2/skills?${params}`);\n  return (await response.json()) as SearchResponse;\n}\n\nexport async function suggestSkills(\n  dependencies: string[],\n  accessToken?: string\n): Promise<SuggestResponse> {\n  const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n  if (accessToken) {\n    headers[\"Authorization\"] = `Bearer ${accessToken}`;\n  }\n  const response = await fetch(`${baseUrl}/api/v2/skills/suggest`, {\n    method: \"POST\",\n    headers,\n    body: JSON.stringify({ dependencies }),\n  });\n  return (await response.json()) as SuggestResponse;\n}\n\nexport async function downloadSkill(project: string, skillName: string): Promise<DownloadResponse> {\n  const skillData = await getSkill(project, skillName);\n\n  if (skillData.error) {\n    return {\n      skill: { name: skillName, description: \"\", url: \"\", project },\n      files: [],\n      error: skillData.message || skillData.error,\n    };\n  }\n\n  const skill = {\n    name: skillData.name,\n    description: skillData.description,\n    url: skillData.url,\n    project: skillData.project,\n  };\n\n  const { files, error } = await downloadSkillFromGitHub(skill);\n\n  if (error) {\n    return { skill, files: [], error };\n  }\n\n  return { skill, files };\n}\n\nexport interface GenerateSkillResponse {\n  content: string;\n  libraryName: string;\n  error?: string;\n}\n\nexport async function searchLibraries(\n  query: string,\n  accessToken?: string\n): Promise<LibrarySearchResponse> {\n  const params = new URLSearchParams({ query });\n  const headers: Record<string, string> = {};\n  if (accessToken) {\n    headers[\"Authorization\"] = `Bearer ${accessToken}`;\n  }\n  const response = await fetch(`${baseUrl}/api/v2/libs/search?${params}`, { headers });\n  return (await response.json()) as LibrarySearchResponse;\n}\n\nexport async function getSkillQuota(accessToken: string): Promise<SkillQuotaResponse> {\n  const response = await fetch(`${baseUrl}/api/v2/skills/quota`, {\n    headers: { Authorization: `Bearer ${accessToken}` },\n  });\n\n  if (!response.ok) {\n    const errorData = await response.json().catch(() => ({}));\n    return {\n      used: 0,\n      limit: 0,\n      remaining: 0,\n      tier: \"free\",\n      resetDate: null,\n      error: (errorData as { message?: string }).message || `HTTP error ${response.status}`,\n    };\n  }\n\n  return (await response.json()) as SkillQuotaResponse;\n}\n\nexport async function getSkillQuestions(\n  libraries: Array<{ id: string; name: string }>,\n  motivation: string,\n  accessToken?: string\n): Promise<SkillQuestionsResponse> {\n  const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n  if (accessToken) {\n    headers[\"Authorization\"] = `Bearer ${accessToken}`;\n  }\n\n  const response = await fetch(`${baseUrl}/api/v2/skills/questions`, {\n    method: \"POST\",\n    headers,\n    body: JSON.stringify({ libraries, motivation }),\n  });\n\n  if (!response.ok) {\n    const errorData = await response.json().catch(() => ({}));\n    return {\n      questions: [],\n      error: (errorData as { message?: string }).message || `HTTP error ${response.status}`,\n    };\n  }\n\n  return (await response.json()) as SkillQuestionsResponse;\n}\n\nexport async function generateSkillStructured(\n  input: StructuredGenerateInput,\n  onEvent?: (event: GenerateStreamEvent) => void,\n  accessToken?: string\n): Promise<GenerateSkillResponse> {\n  const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n  if (accessToken) {\n    headers[\"Authorization\"] = `Bearer ${accessToken}`;\n  }\n\n  const response = await fetch(`${baseUrl}/api/v2/skills/generate`, {\n    method: \"POST\",\n    headers,\n    body: JSON.stringify(input),\n  });\n\n  const libraryName = input.libraries[0]?.name || \"skill\";\n  return handleGenerateResponse(response, libraryName, onEvent);\n}\n\nasync function handleGenerateResponse(\n  response: Response,\n  libraryName: string,\n  onEvent?: (event: GenerateStreamEvent) => void\n): Promise<GenerateSkillResponse> {\n  if (!response.ok) {\n    const errorData = await response.json().catch(() => ({}));\n    return {\n      content: \"\",\n      libraryName,\n      error: (errorData as { message?: string }).message || `HTTP error ${response.status}`,\n    };\n  }\n\n  const reader = response.body?.getReader();\n  if (!reader) {\n    return { content: \"\", libraryName, error: \"No response body\" };\n  }\n\n  const decoder = new TextDecoder();\n  let content = \"\";\n  let finalLibraryName = libraryName;\n  let error: string | undefined;\n  let buffer = \"\"; // Buffer for incomplete lines across chunks\n\n  while (true) {\n    const { done, value } = await reader.read();\n    if (done) break;\n\n    const chunk = decoder.decode(value, { stream: true });\n    buffer += chunk;\n\n    // Split by newline but keep track of incomplete lines\n    const lines = buffer.split(\"\\n\");\n    // Keep the last element (may be incomplete) in the buffer\n    buffer = lines.pop() || \"\";\n\n    for (const line of lines) {\n      const trimmedLine = line.trim();\n      if (!trimmedLine) continue;\n\n      try {\n        const data = JSON.parse(trimmedLine) as GenerateStreamEvent;\n\n        if (onEvent) {\n          onEvent(data);\n        }\n\n        if (data.type === \"complete\") {\n          content = data.content || \"\";\n          finalLibraryName = data.libraryName || libraryName;\n        } else if (data.type === \"error\") {\n          error = data.message;\n        }\n      } catch {\n        // Ignore malformed JSON lines\n      }\n    }\n  }\n\n  // Process any remaining data in the buffer\n  if (buffer.trim()) {\n    try {\n      const data = JSON.parse(buffer.trim()) as GenerateStreamEvent;\n      if (onEvent) {\n        onEvent(data);\n      }\n      if (data.type === \"complete\") {\n        content = data.content || \"\";\n        finalLibraryName = data.libraryName || libraryName;\n      } else if (data.type === \"error\") {\n        error = data.message;\n      }\n    } catch {\n      // Ignore malformed JSON\n    }\n  }\n\n  return { content, libraryName: finalLibraryName, error };\n}\n\nfunction getAuthHeaders(accessToken?: string): Record<string, string> {\n  const headers: Record<string, string> = {\n    \"X-Context7-Source\": \"cli\",\n    \"X-Context7-Client-IDE\": \"ctx7-cli\",\n    \"X-Context7-Client-Version\": VERSION,\n    \"X-Context7-Transport\": \"cli\",\n  };\n  const apiKey = process.env.CONTEXT7_API_KEY;\n  if (apiKey) {\n    headers[\"Authorization\"] = `Bearer ${apiKey}`;\n  } else if (accessToken) {\n    headers[\"Authorization\"] = `Bearer ${accessToken}`;\n  }\n  return headers;\n}\n\nexport async function resolveLibrary(\n  libraryName: string,\n  query?: string,\n  accessToken?: string\n): Promise<LibrarySearchResponse> {\n  const params = new URLSearchParams({ libraryName });\n  if (query) {\n    params.set(\"query\", query);\n  }\n\n  const response = await fetch(`${baseUrl}/api/v2/libs/search?${params}`, {\n    headers: getAuthHeaders(accessToken),\n  });\n\n  if (!response.ok) {\n    const errorData = (await response.json().catch(() => ({}))) as {\n      error?: string;\n      message?: string;\n    };\n    return {\n      results: [],\n      error: errorData.error || `HTTP error ${response.status}`,\n      message: errorData.message,\n    };\n  }\n\n  return (await response.json()) as LibrarySearchResponse;\n}\n\nexport interface GetContextOptions {\n  type?: \"json\" | \"txt\";\n}\n\nexport async function getLibraryContext(\n  libraryId: string,\n  query: string,\n  options?: GetContextOptions,\n  accessToken?: string\n): Promise<ContextResponse | string> {\n  const params = new URLSearchParams({ libraryId, query });\n  if (options?.type) {\n    params.set(\"type\", options.type);\n  }\n  const response = await fetch(`${baseUrl}/api/v2/context?${params}`, {\n    headers: getAuthHeaders(accessToken),\n  });\n\n  if (!response.ok) {\n    const errorData = (await response.json().catch(() => ({}))) as {\n      error?: string;\n      message?: string;\n      redirectUrl?: string;\n    };\n\n    if (response.status === 301 && errorData.redirectUrl) {\n      return {\n        codeSnippets: [],\n        infoSnippets: [],\n        error: errorData.error || \"library_redirected\",\n        message: errorData.message,\n        redirectUrl: errorData.redirectUrl,\n      };\n    }\n\n    return {\n      codeSnippets: [],\n      infoSnippets: [],\n      error: errorData.error || `HTTP error ${response.status}`,\n      message: errorData.message,\n    };\n  }\n\n  if (options?.type === \"txt\") {\n    return await response.text();\n  }\n\n  return (await response.json()) as ContextResponse;\n}\n"
  },
  {
    "path": "packages/cli/src/utils/auth.ts",
    "content": "import * as crypto from \"crypto\";\nimport * as http from \"http\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { CLI_CLIENT_ID } from \"../constants.js\";\nimport { getBaseUrl } from \"./api.js\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".context7\");\nconst CREDENTIALS_FILE = path.join(CONFIG_DIR, \"credentials.json\");\n\nexport interface TokenData {\n  access_token: string;\n  refresh_token?: string;\n  token_type: string;\n  expires_in?: number;\n  expires_at?: number;\n  scope?: string;\n}\n\nexport interface PKCEChallenge {\n  codeVerifier: string;\n  codeChallenge: string;\n}\n\nexport function generatePKCE(): PKCEChallenge {\n  const codeVerifier = crypto.randomBytes(32).toString(\"base64url\");\n  const codeChallenge = crypto.createHash(\"sha256\").update(codeVerifier).digest(\"base64url\");\n  return { codeVerifier, codeChallenge };\n}\n\nexport function generateState(): string {\n  return crypto.randomBytes(16).toString(\"base64url\");\n}\n\nfunction ensureConfigDir(): void {\n  if (!fs.existsSync(CONFIG_DIR)) {\n    fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n  }\n}\n\nexport function saveTokens(tokens: TokenData): void {\n  ensureConfigDir();\n  const data = {\n    ...tokens,\n    expires_at:\n      tokens.expires_at ?? (tokens.expires_in ? Date.now() + tokens.expires_in * 1000 : undefined),\n  };\n  fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });\n}\n\nexport function loadTokens(): TokenData | null {\n  if (!fs.existsSync(CREDENTIALS_FILE)) {\n    return null;\n  }\n  try {\n    const data = JSON.parse(fs.readFileSync(CREDENTIALS_FILE, \"utf-8\"));\n    return data as TokenData;\n  } catch {\n    return null;\n  }\n}\n\nexport function clearTokens(): boolean {\n  if (fs.existsSync(CREDENTIALS_FILE)) {\n    fs.unlinkSync(CREDENTIALS_FILE);\n    return true;\n  }\n  return false;\n}\n\nexport function isTokenExpired(tokens: TokenData): boolean {\n  if (!tokens.expires_at) {\n    return false;\n  }\n  return Date.now() > tokens.expires_at - 60000;\n}\n\nasync function refreshAccessToken(refreshToken: string): Promise<TokenData> {\n  const response = await fetch(`${getBaseUrl()}/api/oauth/token`, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n    body: new URLSearchParams({\n      grant_type: \"refresh_token\",\n      client_id: CLI_CLIENT_ID,\n      refresh_token: refreshToken,\n    }).toString(),\n  });\n\n  if (!response.ok) {\n    const err = (await response.json().catch(() => ({}))) as TokenErrorResponse;\n    throw new Error(err.error_description || err.error || \"Failed to refresh token\");\n  }\n\n  return (await response.json()) as TokenData;\n}\n\n/**\n * Returns a valid access token, refreshing if expired.\n * Returns null if no tokens exist or refresh fails.\n */\nexport async function getValidAccessToken(): Promise<string | null> {\n  const tokens = loadTokens();\n  if (!tokens) return null;\n\n  if (!isTokenExpired(tokens)) {\n    return tokens.access_token;\n  }\n\n  if (!tokens.refresh_token) {\n    return null;\n  }\n\n  try {\n    const newTokens = await refreshAccessToken(tokens.refresh_token);\n    saveTokens(newTokens);\n    return newTokens.access_token;\n  } catch {\n    return null;\n  }\n}\n\nexport interface CallbackResult {\n  code: string;\n  state: string;\n}\n\n// Port for OAuth callback server - must match registered redirect URI\nconst CALLBACK_PORT = 52417;\n\nexport function createCallbackServer(expectedState: string): {\n  port: Promise<number>;\n  result: Promise<CallbackResult>;\n  close: () => void;\n} {\n  let resolvePort: (port: number) => void;\n  let resolveResult: (result: CallbackResult) => void;\n  let rejectResult: (error: Error) => void;\n  let serverInstance: http.Server | null = null;\n\n  const portPromise = new Promise<number>((resolve) => {\n    resolvePort = resolve;\n  });\n\n  const resultPromise = new Promise<CallbackResult>((resolve, reject) => {\n    resolveResult = resolve;\n    rejectResult = reject;\n  });\n\n  const server = http.createServer((req, res) => {\n    const url = new URL(req.url || \"/\", `http://localhost`);\n\n    if (url.pathname === \"/callback\") {\n      const code = url.searchParams.get(\"code\");\n      const state = url.searchParams.get(\"state\");\n      const error = url.searchParams.get(\"error\");\n      const errorDescription = url.searchParams.get(\"error_description\");\n\n      res.writeHead(200, { \"Content-Type\": \"text/html\" });\n\n      if (error) {\n        res.end(errorPage(errorDescription || error));\n        serverInstance?.close();\n        rejectResult(new Error(errorDescription || error));\n        return;\n      }\n\n      if (!code || !state) {\n        res.end(errorPage(\"Missing authorization code or state\"));\n        serverInstance?.close();\n        rejectResult(new Error(\"Missing authorization code or state\"));\n        return;\n      }\n\n      if (state !== expectedState) {\n        res.end(errorPage(\"State mismatch - possible CSRF attack\"));\n        serverInstance?.close();\n        rejectResult(new Error(\"State mismatch\"));\n        return;\n      }\n\n      res.end(successPage());\n      serverInstance?.close();\n      resolveResult({ code, state });\n    } else {\n      res.writeHead(404);\n      res.end(\"Not found\");\n    }\n  });\n\n  serverInstance = server;\n\n  server.on(\"error\", (err) => {\n    rejectResult(err as Error);\n  });\n\n  server.listen(CALLBACK_PORT, \"127.0.0.1\", () => {\n    resolvePort(CALLBACK_PORT);\n  });\n\n  const timeout = setTimeout(\n    () => {\n      server.close();\n      rejectResult(new Error(\"Login timed out after 5 minutes\"));\n    },\n    5 * 60 * 1000\n  );\n\n  return {\n    port: portPromise,\n    result: resultPromise,\n    close: () => {\n      clearTimeout(timeout);\n      server.close();\n    },\n  };\n}\n\nfunction successPage(): string {\n  return `<!DOCTYPE html>\n<html>\n  <head><title>Login Successful</title></head>\n  <body style=\"font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #f9fafb;\">\n    <div style=\"text-align: center; padding: 2rem;\">\n      <div style=\"width: 64px; height: 64px; background: #16a34a; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 1rem;\">\n        <svg width=\"32\" height=\"32\" fill=\"none\" stroke=\"white\" stroke-width=\"3\" viewBox=\"0 0 24 24\">\n          <path d=\"M5 13l4 4L19 7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        </svg>\n      </div>\n      <h1 style=\"color: #16a34a; margin: 0 0 0.5rem;\">Login Successful!</h1>\n      <p style=\"color: #6b7280; margin: 0;\">You can close this window and return to the terminal.</p>\n    </div>\n  </body>\n</html>`;\n}\n\nfunction escapeHtml(text: string): string {\n  return text\n    .replace(/&/g, \"&amp;\")\n    .replace(/</g, \"&lt;\")\n    .replace(/>/g, \"&gt;\")\n    .replace(/\"/g, \"&quot;\")\n    .replace(/'/g, \"&#039;\");\n}\n\nfunction errorPage(message: string): string {\n  const safeMessage = escapeHtml(message);\n  return `<!DOCTYPE html>\n<html>\n  <head><title>Login Failed</title></head>\n  <body style=\"font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #f9fafb;\">\n    <div style=\"text-align: center; padding: 2rem;\">\n      <div style=\"width: 64px; height: 64px; background: #dc2626; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 1rem;\">\n        <svg width=\"32\" height=\"32\" fill=\"none\" stroke=\"white\" stroke-width=\"3\" viewBox=\"0 0 24 24\">\n          <path d=\"M6 18L18 6M6 6l12 12\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        </svg>\n      </div>\n      <h1 style=\"color: #dc2626; margin: 0 0 0.5rem;\">Login Failed</h1>\n      <p style=\"color: #6b7280; margin: 0;\">${safeMessage}</p>\n      <p style=\"color: #9ca3af; margin: 1rem 0 0; font-size: 0.875rem;\">You can close this window.</p>\n    </div>\n  </body>\n</html>`;\n}\n\ninterface TokenErrorResponse {\n  error?: string;\n  error_description?: string;\n}\n\nexport async function exchangeCodeForTokens(\n  baseUrl: string,\n  code: string,\n  codeVerifier: string,\n  redirectUri: string,\n  clientId: string\n): Promise<TokenData> {\n  const response = await fetch(`${baseUrl}/api/oauth/token`, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n    body: new URLSearchParams({\n      grant_type: \"authorization_code\",\n      client_id: clientId,\n      code,\n      code_verifier: codeVerifier,\n      redirect_uri: redirectUri,\n    }).toString(),\n  });\n\n  if (!response.ok) {\n    const err = (await response.json().catch(() => ({}))) as TokenErrorResponse;\n    throw new Error(err.error_description || err.error || \"Failed to exchange code for tokens\");\n  }\n\n  return (await response.json()) as TokenData;\n}\n\nexport function buildAuthorizationUrl(\n  baseUrl: string,\n  clientId: string,\n  redirectUri: string,\n  codeChallenge: string,\n  state: string\n): string {\n  const url = new URL(`${baseUrl}/api/oauth/authorize`);\n  url.searchParams.set(\"client_id\", clientId);\n  url.searchParams.set(\"redirect_uri\", redirectUri);\n  url.searchParams.set(\"code_challenge\", codeChallenge);\n  url.searchParams.set(\"code_challenge_method\", \"S256\");\n  url.searchParams.set(\"state\", state);\n  url.searchParams.set(\"scope\", \"profile email\");\n  url.searchParams.set(\"response_type\", \"code\");\n  return url.toString();\n}\n"
  },
  {
    "path": "packages/cli/src/utils/deps.ts",
    "content": "import { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\nasync function readFileOrNull(path: string): Promise<string | null> {\n  try {\n    return await readFile(path, \"utf-8\");\n  } catch {\n    return null;\n  }\n}\n\n/** Basic client-side filter. The real SKIP_SET lives on the backend. */\nfunction isSkippedLocally(name: string): boolean {\n  return name.startsWith(\"@types/\");\n}\n\nasync function parsePackageJson(cwd: string): Promise<string[]> {\n  const content = await readFileOrNull(join(cwd, \"package.json\"));\n  if (!content) return [];\n\n  try {\n    const pkg = JSON.parse(content);\n    const names = new Set<string>();\n\n    for (const key of Object.keys(pkg.dependencies || {})) {\n      if (!isSkippedLocally(key)) names.add(key);\n    }\n    for (const key of Object.keys(pkg.devDependencies || {})) {\n      if (!isSkippedLocally(key)) names.add(key);\n    }\n\n    return [...names];\n  } catch {\n    return [];\n  }\n}\n\nasync function parseRequirementsTxt(cwd: string): Promise<string[]> {\n  const content = await readFileOrNull(join(cwd, \"requirements.txt\"));\n  if (!content) return [];\n\n  const deps: string[] = [];\n  for (const line of content.split(\"\\n\")) {\n    const trimmed = line.trim();\n    if (!trimmed || trimmed.startsWith(\"#\") || trimmed.startsWith(\"-\")) continue;\n    const name = trimmed.split(/[=<>!~;@\\s\\[]/)[0].trim();\n    if (name && !isSkippedLocally(name)) {\n      deps.push(name);\n    }\n  }\n  return deps;\n}\n\nasync function parsePyprojectToml(cwd: string): Promise<string[]> {\n  const content = await readFileOrNull(join(cwd, \"pyproject.toml\"));\n  if (!content) return [];\n\n  const deps: string[] = [];\n  const seen = new Set<string>();\n\n  const projectDepsMatch = content.match(/\\[project\\]\\s[\\s\\S]*?dependencies\\s*=\\s*\\[([\\s\\S]*?)\\]/);\n  if (projectDepsMatch) {\n    const entries = projectDepsMatch[1].match(/\"([^\"]+)\"/g) || [];\n    for (const entry of entries) {\n      const name = entry\n        .replace(/\"/g, \"\")\n        .split(/[=<>!~;@\\s\\[]/)[0]\n        .trim();\n      if (name && !isSkippedLocally(name) && !seen.has(name)) {\n        seen.add(name);\n        deps.push(name);\n      }\n    }\n  }\n\n  const poetryMatch = content.match(/\\[tool\\.poetry\\.dependencies\\]([\\s\\S]*?)(?:\\n\\[|$)/);\n  if (poetryMatch) {\n    const lines = poetryMatch[1].split(\"\\n\");\n    for (const line of lines) {\n      const match = line.match(/^(\\S+)\\s*=/);\n      if (match) {\n        const name = match[1].trim();\n        if (name && !isSkippedLocally(name) && name !== \"python\" && !seen.has(name)) {\n          seen.add(name);\n          deps.push(name);\n        }\n      }\n    }\n  }\n\n  return deps;\n}\n\nexport async function detectProjectDependencies(cwd: string): Promise<string[]> {\n  const results = await Promise.all([\n    parsePackageJson(cwd),\n    parseRequirementsTxt(cwd),\n    parsePyprojectToml(cwd),\n  ]);\n\n  return [...new Set(results.flat())];\n}\n"
  },
  {
    "path": "packages/cli/src/utils/github.ts",
    "content": "import type { SkillFile, Skill } from \"../types.js\";\n\nconst GITHUB_API = \"https://api.github.com\";\nconst GITHUB_RAW = \"https://raw.githubusercontent.com\";\n\ninterface GitHubTreeItem {\n  path: string;\n  mode: string;\n  type: \"blob\" | \"tree\";\n  sha: string;\n  size?: number;\n  url: string;\n}\n\ninterface GitHubTreeResponse {\n  sha: string;\n  url: string;\n  tree: GitHubTreeItem[];\n  truncated: boolean;\n}\n\nfunction parseGitHubUrl(url: string): {\n  owner: string;\n  repo: string;\n  branch: string;\n  path: string;\n} | null {\n  try {\n    const urlObj = new URL(url);\n    const parts = urlObj.pathname.split(\"/\").filter(Boolean);\n\n    // Handle raw.githubusercontent.com URLs\n    // Format: https://raw.githubusercontent.com/owner/repo/refs/heads/branch/path/SKILL.md\n    if (urlObj.hostname === \"raw.githubusercontent.com\") {\n      if (parts.length < 5) return null;\n\n      const owner = parts[0];\n      const repo = parts[1];\n\n      // Handle refs/heads/branch format\n      if (parts[2] === \"refs\" && parts[3] === \"heads\") {\n        const branch = parts[4];\n        // Get directory path (exclude the filename like SKILL.md)\n        const pathParts = parts.slice(5);\n        // Remove the last part if it looks like a file (has extension)\n        if (pathParts.length > 0 && pathParts[pathParts.length - 1].includes(\".\")) {\n          pathParts.pop();\n        }\n        const path = pathParts.join(\"/\");\n        return { owner, repo, branch, path };\n      }\n\n      // Handle direct branch format: owner/repo/branch/path\n      const branch = parts[2];\n      const pathParts = parts.slice(3);\n      if (pathParts.length > 0 && pathParts[pathParts.length - 1].includes(\".\")) {\n        pathParts.pop();\n      }\n      const path = pathParts.join(\"/\");\n      return { owner, repo, branch, path };\n    }\n\n    // Handle github.com tree URLs\n    // Format: https://github.com/owner/repo/tree/branch/path\n    if (urlObj.hostname === \"github.com\") {\n      if (parts.length < 4 || parts[2] !== \"tree\") return null;\n\n      const owner = parts[0];\n      const repo = parts[1];\n      const branch = parts[3];\n      const path = parts.slice(4).join(\"/\");\n\n      return { owner, repo, branch, path };\n    }\n\n    return null;\n  } catch {\n    return null;\n  }\n}\n\nexport async function downloadSkillFromGitHub(\n  skill: Skill & { project: string }\n): Promise<{ files: SkillFile[]; error?: string }> {\n  try {\n    const parsed = parseGitHubUrl(skill.url);\n\n    if (!parsed) {\n      return { files: [], error: `Invalid GitHub URL: ${skill.url}` };\n    }\n\n    const { owner, repo, branch, path: skillPath } = parsed;\n\n    const treeUrl = `${GITHUB_API}/repos/${owner}/${repo}/git/trees/${branch}?recursive=1`;\n    const treeResponse = await fetch(treeUrl, {\n      headers: {\n        Accept: \"application/vnd.github.v3+json\",\n        \"User-Agent\": \"context7-cli\",\n      },\n    });\n\n    if (!treeResponse.ok) {\n      return { files: [], error: `GitHub API error: ${treeResponse.status}` };\n    }\n\n    const treeData = (await treeResponse.json()) as GitHubTreeResponse;\n\n    const skillFiles = treeData.tree.filter(\n      (item) => item.type === \"blob\" && item.path.startsWith(skillPath + \"/\")\n    );\n\n    if (skillFiles.length === 0) {\n      return { files: [], error: `No files found in ${skillPath}` };\n    }\n\n    const files: SkillFile[] = [];\n    for (const item of skillFiles) {\n      const rawUrl = `${GITHUB_RAW}/${owner}/${repo}/${branch}/${item.path}`;\n      const fileResponse = await fetch(rawUrl);\n\n      if (!fileResponse.ok) {\n        console.warn(`Failed to fetch ${item.path}: ${fileResponse.status}`);\n        continue;\n      }\n\n      const content = await fileResponse.text();\n      const relativePath = item.path.slice(skillPath.length + 1);\n\n      // Reject paths that attempt directory traversal\n      if (relativePath.includes(\"..\")) {\n        console.warn(`Skipping file with unsafe path: ${item.path}`);\n        continue;\n      }\n\n      files.push({\n        path: relativePath,\n        content,\n      });\n    }\n\n    return { files };\n  } catch (err) {\n    const message = err instanceof Error ? err.message : String(err);\n    return { files: [], error: message };\n  }\n}\n"
  },
  {
    "path": "packages/cli/src/utils/ide.ts",
    "content": "import pc from \"picocolors\";\nimport { select, confirm } from \"@inquirer/prompts\";\nimport { access } from \"fs/promises\";\nimport { join, dirname } from \"path\";\nimport { homedir } from \"os\";\n\nimport { log } from \"./logger.js\";\nimport { checkboxWithHover } from \"./prompts.js\";\nimport type {\n  IDE,\n  IDEOptions,\n  Scope,\n  AddOptions,\n  ListOptions,\n  RemoveOptions,\n  InstallTargets,\n} from \"../types.js\";\nimport {\n  IDE_PATHS,\n  IDE_GLOBAL_PATHS,\n  IDE_NAMES,\n  UNIVERSAL_SKILLS_PATH,\n  UNIVERSAL_SKILLS_GLOBAL_PATH,\n  UNIVERSAL_AGENTS_LABEL,\n  VENDOR_SPECIFIC_AGENTS,\n  DEFAULT_CONFIG,\n} from \"../types.js\";\n\nexport function getSelectedIdes(options: IDEOptions): IDE[] {\n  const ides: IDE[] = [];\n  if (options.claude) ides.push(\"claude\");\n  if (options.cursor) ides.push(\"cursor\");\n  if (options.universal) ides.push(\"universal\");\n  if (options.antigravity) ides.push(\"antigravity\");\n  return ides;\n}\n\nexport function hasExplicitIdeOption(options: IDEOptions): boolean {\n  return !!(options.claude || options.cursor || options.universal || options.antigravity);\n}\n\n/** Detect vendor-specific agents whose parent directory exists. */\nasync function detectVendorSpecificAgents(scope: Scope): Promise<IDE[]> {\n  const baseDir = scope === \"global\" ? homedir() : process.cwd();\n  const pathMap = scope === \"global\" ? IDE_GLOBAL_PATHS : IDE_PATHS;\n  const detected: IDE[] = [];\n\n  for (const ide of VENDOR_SPECIFIC_AGENTS) {\n    const parentDir = dirname(pathMap[ide]);\n    try {\n      await access(join(baseDir, parentDir));\n      detected.push(ide);\n    } catch {}\n  }\n\n  return detected;\n}\n\nexport function getUniversalDir(scope: Scope): string {\n  if (scope === \"global\") {\n    return join(homedir(), UNIVERSAL_SKILLS_GLOBAL_PATH);\n  }\n  return join(process.cwd(), UNIVERSAL_SKILLS_PATH);\n}\n\nexport async function promptForInstallTargets(\n  options: AddOptions,\n  forceUniversal = true\n): Promise<InstallTargets | null> {\n  if (hasExplicitIdeOption(options)) {\n    const ides = getSelectedIdes(options);\n    const scope: Scope = options.global ? \"global\" : \"project\";\n    return {\n      ides: ides.length > 0 ? ides : [DEFAULT_CONFIG.defaultIde],\n      scopes: [scope],\n    };\n  }\n\n  const scope: Scope = options.global ? \"global\" : \"project\";\n  const baseDir = scope === \"global\" ? homedir() : process.cwd();\n  const pathMap = scope === \"global\" ? IDE_GLOBAL_PATHS : IDE_PATHS;\n  const universalPath = scope === \"global\" ? UNIVERSAL_SKILLS_GLOBAL_PATH : UNIVERSAL_SKILLS_PATH;\n\n  // Detect universal (.agents/) and vendor-specific agent directories\n  const detectedVendor = await detectVendorSpecificAgents(scope);\n  let hasUniversalDir = false;\n  try {\n    await access(join(baseDir, dirname(universalPath)));\n    hasUniversalDir = true;\n  } catch {}\n\n  const detectedIdes: IDE[] = [\n    ...(hasUniversalDir ? ([\"universal\"] as IDE[]) : []),\n    ...detectedVendor,\n  ];\n\n  if (detectedIdes.length > 0) {\n    // Detected — just confirm\n    const pathLines: string[] = [];\n    if (hasUniversalDir) {\n      pathLines.push(join(baseDir, universalPath));\n    }\n    for (const ide of detectedVendor) {\n      pathLines.push(join(baseDir, pathMap[ide]));\n    }\n\n    log.blank();\n\n    let confirmed: boolean;\n    if (options.yes) {\n      confirmed = true;\n    } else {\n      try {\n        confirmed = await confirm({\n          message: `Install to detected location(s)?\\n${pc.dim(pathLines.join(\"\\n\"))}`,\n          default: true,\n        });\n      } catch {\n        return null;\n      }\n    }\n\n    if (!confirmed) {\n      log.warn(\"Installation cancelled\");\n      return null;\n    }\n\n    return { ides: detectedIdes, scopes: [scope] };\n  }\n\n  // Nothing detected — show checkbox to pick\n  const universalLabel = `Universal \\u2014 ${UNIVERSAL_AGENTS_LABEL} ${pc.dim(`(${universalPath})`)}`;\n  const choices: { name: string; value: IDE; checked: boolean }[] = [\n    {\n      name: `${IDE_NAMES[\"claude\"]} ${pc.dim(`(${pathMap[\"claude\"]})`)}`,\n      value: \"claude\" as IDE,\n      checked: false,\n    },\n    { name: universalLabel, value: \"universal\", checked: false },\n  ];\n\n  for (const ide of VENDOR_SPECIFIC_AGENTS.filter((ide) => ide !== \"claude\")) {\n    choices.push({\n      name: `${IDE_NAMES[ide]} ${pc.dim(`(${pathMap[ide]})`)}`,\n      value: ide,\n      checked: false,\n    });\n  }\n\n  log.blank();\n\n  let selectedIdes: IDE[];\n  try {\n    selectedIdes = await checkboxWithHover(\n      {\n        message: `Which agents do you want to install to?\\n${pc.dim(`  ${baseDir}`)}`,\n        choices,\n        loop: false,\n        theme: {\n          style: {\n            highlight: (text: string) => pc.green(text),\n            message: (text: string, status: string) => {\n              if (status === \"done\") return text.split(\"\\n\")[0];\n              return pc.bold(text);\n            },\n          },\n        },\n      },\n      { getName: (ide: IDE) => IDE_NAMES[ide] }\n    );\n  } catch {\n    return null;\n  }\n\n  const ides: IDE[] = forceUniversal\n    ? [\"universal\", ...selectedIdes.filter((ide) => ide !== \"universal\")]\n    : selectedIdes;\n\n  return { ides, scopes: [scope] };\n}\n\nexport async function promptForSingleTarget(\n  options: ListOptions | RemoveOptions\n): Promise<{ ide: IDE; scope: Scope } | null> {\n  if (hasExplicitIdeOption(options)) {\n    const ides = getSelectedIdes(options);\n    const ide = ides[0] || DEFAULT_CONFIG.defaultIde;\n    const scope: Scope = options.global ? \"global\" : \"project\";\n    return { ide, scope };\n  }\n\n  log.blank();\n\n  const universalLabel = `Universal ${pc.dim(`(${UNIVERSAL_SKILLS_PATH})`)}`;\n  const choices: { name: string; value: IDE }[] = [\n    { name: `${IDE_NAMES[\"claude\"]} ${pc.dim(`(${IDE_PATHS[\"claude\"]})`)}`, value: \"claude\" },\n    { name: universalLabel, value: \"universal\" },\n  ];\n\n  for (const ide of VENDOR_SPECIFIC_AGENTS.filter((ide) => ide !== \"claude\")) {\n    choices.push({\n      name: `${IDE_NAMES[ide]} ${pc.dim(`(${IDE_PATHS[ide]})`)}`,\n      value: ide,\n    });\n  }\n\n  let selectedIde: IDE;\n  try {\n    selectedIde = await select({\n      message: \"Which location?\",\n      choices,\n      default: DEFAULT_CONFIG.defaultIde,\n      loop: false,\n      theme: { style: { highlight: (text: string) => pc.green(text) } },\n    });\n  } catch {\n    return null;\n  }\n\n  let selectedScope: Scope;\n  if (options.global !== undefined) {\n    selectedScope = options.global ? \"global\" : \"project\";\n  } else {\n    try {\n      selectedScope = await select({\n        message: \"Which scope?\",\n        choices: [\n          {\n            name: `Project ${pc.dim(\"(current directory)\")}`,\n            value: \"project\" as Scope,\n          },\n          {\n            name: `Global ${pc.dim(\"(home directory)\")}`,\n            value: \"global\" as Scope,\n          },\n        ],\n        default: DEFAULT_CONFIG.defaultScope,\n        loop: false,\n        theme: { style: { highlight: (text: string) => pc.green(text) } },\n      });\n    } catch {\n      return null;\n    }\n  }\n\n  return { ide: selectedIde, scope: selectedScope };\n}\n\nexport function getTargetDirs(targets: InstallTargets): string[] {\n  const hasUniversal = targets.ides.some((ide) => ide === \"universal\");\n  const dirs: string[] = [];\n\n  for (const scope of targets.scopes) {\n    const baseDir = scope === \"global\" ? homedir() : process.cwd();\n\n    if (hasUniversal) {\n      const uniPath = scope === \"global\" ? UNIVERSAL_SKILLS_GLOBAL_PATH : UNIVERSAL_SKILLS_PATH;\n      dirs.push(join(baseDir, uniPath));\n    }\n\n    for (const ide of targets.ides) {\n      if (ide === \"universal\") continue;\n      const pathMap = scope === \"global\" ? IDE_GLOBAL_PATHS : IDE_PATHS;\n      dirs.push(join(baseDir, pathMap[ide]));\n    }\n  }\n\n  return dirs;\n}\n\nexport function getTargetDirFromSelection(ide: IDE, scope: Scope): string {\n  if (ide === \"universal\") {\n    return getUniversalDir(scope);\n  }\n  if (scope === \"global\") {\n    return join(homedir(), IDE_GLOBAL_PATHS[ide]);\n  }\n  return join(process.cwd(), IDE_PATHS[ide]);\n}\n"
  },
  {
    "path": "packages/cli/src/utils/installer.ts",
    "content": "import { mkdir, writeFile, rm, symlink, lstat } from \"fs/promises\";\nimport { join, resolve, dirname } from \"path\";\n\nimport type { SkillFile } from \"../types.js\";\n\nexport async function installSkillFiles(\n  skillName: string,\n  files: SkillFile[],\n  targetDir: string\n): Promise<void> {\n  const skillDir = resolve(targetDir, skillName);\n\n  for (const file of files) {\n    const filePath = resolve(skillDir, file.path);\n\n    // Prevent directory traversal — resolved path must stay within skillDir\n    if (!filePath.startsWith(skillDir + \"/\") && filePath !== skillDir) {\n      throw new Error(`Skill file path \"${file.path}\" resolves outside the target directory`);\n    }\n\n    const fileDir = dirname(filePath);\n\n    await mkdir(fileDir, { recursive: true });\n    await writeFile(filePath, file.content);\n  }\n}\n\nexport async function symlinkSkill(\n  skillName: string,\n  sourcePath: string,\n  targetDir: string\n): Promise<void> {\n  const targetPath = join(targetDir, skillName);\n\n  try {\n    const stats = await lstat(targetPath);\n    if (stats.isSymbolicLink() || stats.isDirectory()) {\n      await rm(targetPath, { recursive: true });\n    }\n  } catch {}\n\n  await mkdir(targetDir, { recursive: true });\n  await symlink(sourcePath, targetPath);\n}\n"
  },
  {
    "path": "packages/cli/src/utils/logger.ts",
    "content": "import pc from \"picocolors\";\n\nexport const log = {\n  info: (message: string) => console.log(pc.cyan(message)),\n  success: (message: string) => console.log(pc.green(`✔ ${message}`)),\n  warn: (message: string) => console.log(pc.yellow(`⚠ ${message}`)),\n  error: (message: string) => console.log(pc.red(`✖ ${message}`)),\n  dim: (message: string) => console.log(pc.dim(message)),\n  item: (message: string) => console.log(pc.green(`  ${message}`)),\n  itemAdd: (message: string) => console.log(`  ${pc.green(\"+\")} ${message}`),\n  plain: (message: string) => console.log(message),\n  blank: () => console.log(\"\"),\n};\n"
  },
  {
    "path": "packages/cli/src/utils/parse-input.ts",
    "content": "export interface ParsedSkillInput {\n  type: \"repo\" | \"url\";\n  owner: string;\n  repo: string;\n  branch?: string;\n  path?: string;\n}\n\nexport function parseSkillInput(input: string): ParsedSkillInput | null {\n  const urlMatch = input.match(\n    /(?:https?:\\/\\/)?github\\.com\\/([^\\/]+)\\/([^\\/]+)\\/tree\\/([^\\/]+)\\/(.+)/\n  );\n  if (urlMatch) {\n    const [, owner, repo, branch, path] = urlMatch;\n    return { type: \"url\", owner, repo, branch, path };\n  }\n\n  const shortMatch = input.match(/^\\/?([^\\/]+)\\/([^\\/]+)$/);\n  if (shortMatch) {\n    const [, owner, repo] = shortMatch;\n    return { type: \"repo\", owner, repo };\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "packages/cli/src/utils/prompts.ts",
    "content": "import pc from \"picocolors\";\nimport { checkbox, type Separator } from \"@inquirer/prompts\";\nimport readline from \"readline\";\n\ntype CheckboxConfig<T> = Parameters<typeof checkbox<T>>[0];\ntype CheckboxChoice<T> = Exclude<CheckboxConfig<T>[\"choices\"][number], Separator | string>;\n\n/**\n * Creates a clickable terminal hyperlink using OSC 8 escape sequence.\n */\nexport function terminalLink(text: string, url: string, color?: (s: string) => string): string {\n  const colorFn = color ?? ((s: string) => s);\n  return `\\x1b]8;;${url}\\x07${colorFn(text)}\\x1b]8;;\\x07 ${pc.white(\"↗\")}`;\n}\n\n/**\n * Formats install count into a popularity star rating (4 stars).\n * 0/unknown → ☆☆☆☆, <100 → ★☆☆☆, <500 → ★★☆☆, <1000 → ★★★☆, 1000+ → ★★★★\n */\nexport function formatPopularity(count: number | undefined): string {\n  const filled = \"★\";\n  const empty = \"☆\";\n  const max = 4;\n  let stars: number;\n  if (count === undefined || count === 0) stars = 0;\n  else if (count < 100) stars = 1;\n  else if (count < 500) stars = 2;\n  else if (count < 1000) stars = 3;\n  else stars = 4;\n\n  const filledPart = filled.repeat(stars);\n  const emptyPart = empty.repeat(max - stars);\n  if (stars === 0) return pc.dim(emptyPart);\n  return pc.yellow(filledPart) + pc.dim(emptyPart);\n}\n\n/**\n * Returns the install count as a human-readable range string.\n */\nexport function formatInstallRange(count: number | undefined): string {\n  if (count === undefined || count === 0) return \"Unknown\";\n  if (count < 100) return \"<100\";\n  if (count < 500) return \"<500\";\n  if (count < 1000) return \"<1,000\";\n  return \"1,000+\";\n}\n\n/**\n * Formats trust score as High / Medium / Low label.\n * Uses MCP reputation thresholds: >=7 High, >=4 Medium, <4 Low.\n */\nexport function formatTrust(score: number | undefined): string {\n  if (score === undefined || score < 0) return pc.dim(\"-\");\n  if (score >= 7) return pc.green(\"High\");\n  if (score >= 4) return pc.yellow(\"Medium\");\n  return pc.red(\"Low\");\n}\n\n/**\n * Returns the raw trust label string (uncolored) for width calculations.\n */\nexport function getTrustLabel(score: number | undefined): string {\n  if (score === undefined || score < 0) return \"-\";\n  if (score >= 7) return \"High\";\n  if (score >= 4) return \"Medium\";\n  return \"Low\";\n}\nexport interface CheckboxWithHoverOptions<T> {\n  /** Function to extract display name from value. Defaults to (v) => v.name */\n  getName?: (value: T) => string;\n}\n\nexport async function checkboxWithHover<T>(\n  config: CheckboxConfig<T>,\n  options?: CheckboxWithHoverOptions<T>\n): Promise<T[]> {\n  const choices = config.choices.filter(\n    (c): c is CheckboxChoice<T> =>\n      typeof c === \"object\" && c !== null && !(\"type\" in c && c.type === \"separator\")\n  );\n  const values = choices.map((c) => c.value);\n  const totalItems = values.length;\n  let cursorPosition = 0;\n\n  // Default getName assumes object has 'name' property\n  const getName = options?.getName ?? ((v: T) => (v as { name: string }).name);\n\n  const keypressHandler = (_str: string | undefined, key: readline.Key) => {\n    if (key.name === \"up\" && cursorPosition > 0) {\n      cursorPosition--;\n    } else if (key.name === \"down\" && cursorPosition < totalItems - 1) {\n      cursorPosition++;\n    }\n  };\n\n  readline.emitKeypressEvents(process.stdin);\n  process.stdin.on(\"keypress\", keypressHandler);\n\n  const customConfig = {\n    ...config,\n    theme: {\n      ...config.theme,\n      style: {\n        answer: (text: string) => pc.green(text),\n        ...config.theme?.style,\n        highlight: (text: string) => pc.green(text),\n        renderSelectedChoices: (\n          selected: CheckboxChoice<T>[],\n          _allChoices: CheckboxChoice<T>[]\n        ): string => {\n          if (selected.length === 0) {\n            return pc.dim(getName(values[cursorPosition]));\n          }\n          return selected.map((c) => getName(c.value)).join(\", \");\n        },\n      },\n    },\n  };\n\n  try {\n    const selected = await checkbox(customConfig);\n    if (selected.length === 0) {\n      return [values[cursorPosition]];\n    }\n    return selected;\n  } finally {\n    process.stdin.removeListener(\"keypress\", keypressHandler);\n  }\n}\n"
  },
  {
    "path": "packages/cli/src/utils/selectOrInput.ts",
    "content": "import {\n  createPrompt,\n  useState,\n  useKeypress,\n  usePrefix,\n  isEnterKey,\n  isUpKey,\n  isDownKey,\n} from \"@inquirer/core\";\nimport type { KeypressEvent } from \"@inquirer/core\";\nimport pc from \"picocolors\";\n\nexport interface SelectOrInputConfig {\n  message: string;\n  options: string[];\n  recommendedIndex?: number;\n}\n\nfunction reorderOptions(options: string[], recommendedIndex: number): string[] {\n  if (recommendedIndex === 0) return options;\n  const reordered = [options[recommendedIndex]];\n  for (let i = 0; i < options.length; i++) {\n    if (i !== recommendedIndex) reordered.push(options[i]);\n  }\n  return reordered;\n}\n\nconst selectOrInput: (config: SelectOrInputConfig) => Promise<string> = createPrompt<\n  string,\n  SelectOrInputConfig\n>((config, done): string => {\n  const { message, options: rawOptions, recommendedIndex = 0 } = config;\n  const options = reorderOptions(rawOptions, recommendedIndex);\n  const [cursor, setCursor] = useState(0);\n  const [inputValue, setInputValue] = useState(\"\");\n\n  const prefix = usePrefix({});\n\n  useKeypress((key: KeypressEvent, rl) => {\n    if (isUpKey(key)) {\n      setCursor(Math.max(0, cursor - 1));\n      return;\n    }\n\n    if (isDownKey(key)) {\n      setCursor(Math.min(options.length, cursor + 1));\n      return;\n    }\n\n    if (isEnterKey(key)) {\n      if (cursor === options.length) {\n        const finalValue = inputValue.trim();\n        done(finalValue || options[0]);\n      } else {\n        done(options[cursor]);\n      }\n      return;\n    }\n\n    // Text input handling (only when on custom input line)\n    if (cursor === options.length && key.name !== \"return\") {\n      if ((key.name === \"w\" && key.ctrl) || key.name === \"backspace\") {\n        if (key.name === \"w\" && key.ctrl) {\n          const words = inputValue.trimEnd().split(/\\s+/);\n          if (words.length > 0) {\n            words.pop();\n            setInputValue(\n              words.join(\" \") + (inputValue.endsWith(\" \") && words.length > 0 ? \" \" : \"\")\n            );\n          }\n        } else {\n          setInputValue(inputValue.slice(0, -1));\n        }\n      } else if (key.name === \"u\" && key.ctrl) {\n        setInputValue(\"\");\n      } else if (key.name === \"space\") {\n        setInputValue(inputValue + \" \");\n      } else if (key.name && key.name.length === 1 && !key.ctrl) {\n        setInputValue(inputValue + key.name);\n      }\n    } else if (rl.line) {\n      rl.line = \"\";\n    }\n  });\n\n  let output = `${prefix} ${pc.bold(message)}\\n\\n`;\n\n  options.forEach((opt: string, idx: number) => {\n    const isRecommended = idx === 0;\n    const isCursor = idx === cursor;\n    const number = pc.cyan(`${idx + 1}.`);\n    const text = isRecommended ? `${opt} ${pc.green(\"✓ Recommended\")}` : opt;\n\n    if (isCursor) {\n      output += pc.cyan(`❯ ${number} ${text}\\n`);\n    } else {\n      output += `  ${number} ${text}\\n`;\n    }\n  });\n\n  const isCustomCursor = cursor === options.length;\n  if (isCustomCursor) {\n    output += pc.cyan(`❯ ${pc.yellow(\"✎\")} ${inputValue || pc.dim(\"Type your own...\")}`);\n  } else {\n    output += `  ${pc.yellow(\"✎\")} ${pc.dim(\"Type your own...\")}`;\n  }\n\n  return output;\n});\n\nexport default selectOrInput;\n"
  },
  {
    "path": "packages/cli/src/utils/tracking.ts",
    "content": "import { getBaseUrl } from \"./api.js\";\n\nexport function trackEvent(event: string, data?: Record<string, unknown>): void {\n  if (process.env.CTX7_TELEMETRY_DISABLED) return;\n  fetch(`${getBaseUrl()}/api/v2/cli/events`, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify({ event, data }),\n  }).catch(() => {});\n}\n"
  },
  {
    "path": "packages/cli/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"./dist\",\n    \"rootDir\": \"./src\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"sourceMap\": true,\n    \"resolveJsonModule\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "packages/cli/tsup.config.ts",
    "content": "import { defineConfig } from \"tsup\";\n\nexport default defineConfig({\n  entry: [\"src/index.ts\"],\n  format: [\"esm\"],\n  dts: true,\n  clean: true,\n  sourcemap: true,\n  banner: {\n    js: \"#!/usr/bin/env node\",\n  },\n  noExternal: [],\n  external: [\n    \"@inquirer/core\",\n    \"@inquirer/type\",\n    \"@inquirer/prompts\",\n    \"mute-stream\",\n    \"stream\",\n  ],\n});\n"
  },
  {
    "path": "packages/cli/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n  test: {\n    globals: true,\n    environment: \"node\",\n    include: [\"src/**/*.test.ts\"],\n  },\n});\n"
  },
  {
    "path": "packages/mcp/.prettierignore",
    "content": "# Dependencies\nnode_modules\n\n# Build outputs\ndist\n\n# Logs\n*.log\n\n# Environment files\n.env\n.env.*\n"
  },
  {
    "path": "packages/mcp/CHANGELOG.md",
    "content": "# @upstash/context7-mcp\n\n## 2.1.5\n\n### Patch Changes\n\n- 2070cb1: Support NODE_EXTRA_CA_CERTS for enterprise MITM proxies by injecting custom CA certificates into undici's global dispatcher at runtime\n\n## 2.1.4\n\n### Patch Changes\n\n- 9de3f06: Display warning when public library access filter is being used to filter libraries.\n\n## 2.1.3\n\n### Patch Changes\n\n- 9523522: Reject GET requests on MCP endpoints with 405 to eliminate idle SSE connection timeouts\n- 59d0327: Include source field in search result response\n\n## 2.1.2\n\n### Patch Changes\n\n- 617d8ed: Remove unnecessary warning and update tool descriptions\n\n## 2.1.1\n\n### Patch Changes\n\n- 02148ff: Bump zod from 3.x to 4.x\n\n## 2.1.0\n\n### Minor Changes\n\n- ef82f30: Add OAuth 2.0 authentication support for MCP server\n  - Add new `/mcp/oauth` endpoint requiring JWT authentication\n  - Implement JWT validation against authorization server JWKS\n  - Add OAuth Protected Resource Metadata endpoint (RFC 9728) at `/.well-known/oauth-protected-resource`\n  - Include `WWW-Authenticate` header for OAuth discovery\n\n## 2.0.2\n\n### Patch Changes\n\n- 368b143: Collect client and server version metrics\n\n## 2.0.1\n\n### Patch Changes\n\n- 93a2d5b: Adds MCP tool annotations (readOnlyHint) to all tools to help MCP clients better understand tool behavior and make safer decisions about tool execution.\n\n## 2.0.0\n\n### Major Changes\n\n- 66ea0d6: Upgrade MCP server to v2.0.0 with intelligent query-based architecture\n\n  Breaking Changes\n  - Removed get-library-docs tool, replaced with new query-docs tool\n  - resolve-library-id now requires both query and libraryName parameters\n  - Removed mode, topic, page, and limit parameters from documentation fetching\n  - Renamed context7CompatibleLibraryID parameter to libraryId\n\n  New Features\n  - Intelligent reranked and deduplicated library selection based on user intent\n  - Smart snippet selection with relevance-based ranking for documentation retrieval\n  - Query-driven context fetching that understands what the user is trying to accomplish\n  - Added security warnings for sensitive data in query parameters\n  - Added tool call limits (max 3 calls per question) to prevent excessive context window usage\n\n  Improvements\n  - Simplified API key header extraction (removed redundant case variants)\n  - Removed unused actualPort variable and dead code\n  - Cleaner type definitions with new ContextRequest and ContextResponse types\n  - Better error messages for library search failures\n\n## 1.0.33\n\n### Patch Changes\n\n- a5228fd: Fix API key not being passed in resolve-library-id tool when using stdio transport\n\n## 1.0.32\n\n### Patch Changes\n\n- ad23996: Remove masked API key display from unauthorized error responses\n- aa12390: Improve error message handling by using the responses from the server.\n\n## 1.0.31\n\n### Patch Changes\n\n- 6255e26: Migrate to pnpm monorepo structure\n"
  },
  {
    "path": "packages/mcp/Dockerfile",
    "content": "# ----- Build Stage -----\nFROM node:lts-alpine AS builder\nRUN corepack enable pnpm\nWORKDIR /app\n\n# Copy monorepo config and install dependencies\nCOPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.json ./\nCOPY packages/mcp ./packages/mcp\nRUN pnpm install --frozen-lockfile\n\n# Build the mcp package\nRUN pnpm --filter @upstash/context7-mcp build\n\n# ----- Production Stage -----\nFROM node:lts-alpine\nRUN corepack enable pnpm\nWORKDIR /app\n\n# Install production dependencies only\nCOPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./\nCOPY packages/mcp/package.json ./packages/mcp/\nRUN pnpm install --frozen-lockfile --prod --filter @upstash/context7-mcp\n\n# Copy built files from builder\nCOPY --from=builder /app/packages/mcp/dist ./packages/mcp/dist\n\nWORKDIR /app/packages/mcp\nEXPOSE 8080\nCMD [\"node\", \"dist/index.js\", \"--transport\", \"http\", \"--port\", \"8080\"]\n"
  },
  {
    "path": "packages/mcp/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2021 Upstash, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/mcp/README.md",
    "content": "![Cover](https://github.com/upstash/context7/blob/master/public/cover.png?raw=true)\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D) [<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/Install%20in%20VS%20Code-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n\n# Context7 MCP - Up-to-date Code Docs For Any Prompt\n\n[![Website](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com) [![smithery badge](https://smithery.ai/badge/@upstash/context7-mcp)](https://smithery.ai/server/@upstash/context7-mcp) [![NPM Version](https://img.shields.io/npm/v/%40upstash%2Fcontext7-mcp?color=red)](https://www.npmjs.com/package/@upstash/context7-mcp) [![MIT licensed](https://img.shields.io/npm/l/%40upstash%2Fcontext7-mcp)](./LICENSE)\n\n[![繁體中文](https://img.shields.io/badge/docs-繁體中文-yellow)](./i18n/README.zh-TW.md) [![简体中文](https://img.shields.io/badge/docs-简体中文-yellow)](./i18n/README.zh-CN.md) [![日本語](https://img.shields.io/badge/docs-日本語-b7003a)](./i18n/README.ja.md) [![한국어 문서](https://img.shields.io/badge/docs-한국어-green)](./i18n/README.ko.md) [![Documentación en Español](https://img.shields.io/badge/docs-Español-orange)](./i18n/README.es.md) [![Documentation en Français](https://img.shields.io/badge/docs-Français-blue)](./i18n/README.fr.md) [![Documentação em Português (Brasil)](<https://img.shields.io/badge/docs-Português%20(Brasil)-purple>)](./i18n/README.pt-BR.md) [![Documentazione in italiano](https://img.shields.io/badge/docs-Italian-red)](./i18n/README.it.md) [![Dokumentasi Bahasa Indonesia](https://img.shields.io/badge/docs-Bahasa%20Indonesia-pink)](./i18n/README.id-ID.md) [![Dokumentation auf Deutsch](https://img.shields.io/badge/docs-Deutsch-darkgreen)](./i18n/README.de.md) [![Документация на русском языке](https://img.shields.io/badge/docs-Русский-darkblue)](./i18n/README.ru.md) [![Українська документація](https://img.shields.io/badge/docs-Українська-lightblue)](./i18n/README.uk.md) [![Türkçe Doküman](https://img.shields.io/badge/docs-Türkçe-blue)](./i18n/README.tr.md) [![Arabic Documentation](https://img.shields.io/badge/docs-Arabic-white)](./i18n/README.ar.md) [![Tiếng Việt](https://img.shields.io/badge/docs-Tiếng%20Việt-red)](./i18n/README.vi.md)\n\n## ❌ Without Context7\n\nLLMs rely on outdated or generic information about the libraries you use. You get:\n\n- ❌ Code examples are outdated and based on year-old training data\n- ❌ Hallucinated APIs that don't even exist\n- ❌ Generic answers for old package versions\n\n## ✅ With Context7\n\nContext7 MCP pulls up-to-date, version-specific documentation and code examples straight from the source — and places them directly into your prompt.\n\nAdd `use context7` to your prompt (or [set up a rule](#️-installation) to auto-invoke):\n\n```txt\nCreate a Next.js middleware that checks for a valid JWT in cookies\nand redirects unauthenticated users to `/login`. use context7\n```\n\n```txt\nConfigure a Cloudflare Worker script to cache\nJSON API responses for five minutes. use context7\n```\n\nContext7 fetches up-to-date code examples and documentation right into your LLM's context.\n\n- 1️⃣ Write your prompt naturally\n- 2️⃣ Tell the LLM to `use context7` (or [set up a rule](#️-installation) once)\n- 3️⃣ Get working code answers\n\nNo tab-switching, no hallucinated APIs that don't exist, no outdated code generation.\n\n> [!NOTE]\n> This repository hosts the source code of Context7 MCP server. The supporting components — API backend, parsing engine, and crawling engine — are private and not part of this release.\n\n## 📚 Adding Projects\n\nCheck out our [project addition guide](https://context7.com/docs/adding-libraries) to learn how to add (or update) your favorite libraries to Context7.\n\n## 🛠️ Installation\n\n### Requirements\n\n- Node.js >= v18.0.0\n- Cursor, Claude Code, VSCode, Windsurf or another MCP Client\n- Context7 API Key (Optional) for higher rate limits and private repositories (Get yours by creating an account at [context7.com/dashboard](https://context7.com/dashboard))\n\n> [!TIP]\n> **Recommended Post-Setup: Add a Rule to Auto-Invoke Context7**\n>\n> After installing Context7 (see instructions below), enhance your workflow by adding a rule so you don't have to type `use context7` in every prompt. Define a simple rule in your MCP client's rule section to automatically invoke Context7 on any code question:\n>\n> - For Windsurf, in `.windsurfrules` file\n> - For Cursor, from `Cursor Settings > Rules` section\n> - For Claude Code, in `CLAUDE.md` file\n> - Or the equivalent in your MCP client\n>\n> **Example Rule:**\n>\n> ```txt\n> Always use context7 when I need code generation, setup or configuration steps, or\n> library/API documentation. This means you should automatically use the Context7 MCP\n> tools to resolve library id and get library docs without me having to explicitly ask.\n> ```\n>\n> From then on, you'll get Context7's docs in any related conversation without typing anything extra. You can alter the rule to match your use cases.\n\n<details>\n<summary><b>Installing via Smithery</b></summary>\n\nTo install Context7 MCP Server for any client automatically via [Smithery](https://smithery.ai/server/@upstash/context7-mcp):\n\n```bash\nnpx -y @smithery/cli@latest install @upstash/context7-mcp --client <CLIENT_NAME> --key <YOUR_SMITHERY_KEY>\n```\n\nYou can find your Smithery key in the [Smithery.ai webpage](https://smithery.ai/server/@upstash/context7-mcp).\n\n</details>\n\n<details>\n<summary><b>Install in Cursor</b></summary>\n\nGo to: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`\n\nPasting the following configuration into your Cursor `~/.cursor/mcp.json` file is the recommended approach. You may also install in a specific project by creating `.cursor/mcp.json` in your project folder. See [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol) for more info.\n\n> Since Cursor 1.0, you can click the install button below for instant one-click installation.\n\n#### Cursor Remote Server Connection\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Cursor Local Server Connection\n\n[![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IC15IEB1cHN0YXNoL2NvbnRleHQ3LW1jcCJ9)\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Claude Code</b></summary>\n\nRun this command. See [Claude Code MCP docs](https://docs.anthropic.com/en/docs/claude-code/mcp) for more info.\n\n#### Claude Code Local Server Connection\n\n```sh\nclaude mcp add --scope user context7 -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY\n```\n\n#### Claude Code Remote Server Connection\n\n```sh\nclaude mcp add --scope user --header \"CONTEXT7_API_KEY: YOUR_API_KEY\" --transport http context7 https://mcp.context7.com/mcp\n```\n\n> Remove `--scope user` to install for the current project only.\n\n</details>\n\n<details>\n<summary><b>Install in Amp</b></summary>\n\nRun this command in your terminal. See [Amp MCP docs](https://ampcode.com/manual#mcp) for more info.\n\n#### Without API Key (Basic Usage)\n\n```sh\namp mcp add context7 https://mcp.context7.com/mcp\n```\n\n#### With API Key (Higher Rate Limits & Private Repos)\n\n```sh\namp mcp add context7 --header \"CONTEXT7_API_KEY=YOUR_API_KEY\" https://mcp.context7.com/mcp\n```\n\n</details>\n\n<details>\n<summary><b>Install in Windsurf</b></summary>\n\nAdd this to your Windsurf MCP config file. See [Windsurf MCP docs](https://docs.windsurf.com/windsurf/cascade/mcp) for more info.\n\n#### Windsurf Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Windsurf Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in VS Code</b></summary>\n\n[<img alt=\"Install in VS Code (npx)\" src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF\">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n[<img alt=\"Install in VS Code Insiders (npx)\" src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Context7%20MCP&color=24bfa5\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%7B%22name%22%3A%22context7%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40upstash%2Fcontext7-mcp%40latest%22%5D%7D)\n\nAdd this to your VS Code MCP config file. See [VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for more info.\n\n#### VS Code Remote Server Connection\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### VS Code Local Server Connection\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary>\n<b>Install in Cline</b>\n</summary>\n\nYou can easily install Context7 through the [Cline MCP Server Marketplace](https://cline.bot/mcp-marketplace) by following these instructions:\n\n1. Open **Cline**.\n2. Click the hamburger menu icon (☰) to enter the **MCP Servers** section.\n3. Use the search bar within the **Marketplace** tab to find _Context7_.\n4. Click the **Install** button.\n\nOr you can directly edit MCP servers configuration:\n\n1. Open **Cline**.\n2. Click the hamburger menu icon (☰) to enter the **MCP Servers** section.\n3. Choose **Remote Servers** tab.\n4. Click the **Edit Configuration** button.\n5. Add context7 to `mcpServers`:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"type\": \"streamableHttp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Zed</b></summary>\n\nIt can be installed via [Zed Extensions](https://zed.dev/extensions?query=Context7) or you can add this to your Zed `settings.json`. See [Zed Context Server docs](https://zed.dev/docs/assistant/context-servers) for more info.\n\n```json\n{\n  \"context_servers\": {\n    \"Context7\": {\n      \"source\": \"custom\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Augment Code</b></summary>\n\nTo configure Context7 MCP in Augment Code, you can use either the graphical interface or manual configuration.\n\n### **A. Using the Augment Code UI**\n\n1. Click the hamburger menu.\n2. Select **Settings**.\n3. Navigate to the **Tools** section.\n4. Click the **+ Add MCP** button.\n5. Enter the following command:\n\n   ```\n   npx -y @upstash/context7-mcp@latest\n   ```\n\n6. Name the MCP: **Context7**.\n7. Click the **Add** button.\n\nOnce the MCP server is added, you can start using Context7's up-to-date code documentation features directly within Augment Code.\n\n---\n\n### **B. Manual Configuration**\n\n1. Press Cmd/Ctrl Shift P or go to the hamburger menu in the Augment panel\n2. Select Edit Settings\n3. Under Advanced, click Edit in settings.json\n4. Add the server configuration to the `mcpServers` array in the `augment.advanced` object\n\n```json\n\"augment.advanced\": {\n  \"mcpServers\": [\n    {\n      \"name\": \"context7\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  ]\n}\n```\n\nOnce the MCP server is added, restart your editor. If you receive any errors, check the syntax to make sure closing brackets or commas are not missing.\n\n</details>\n\n<details>\n<summary><b>Install in Kilo Code</b></summary>\n\nYou can configure the Context7 MCP server in **Kilo Code** using either the UI or by editing your project's MCP configuration file.\n\nKilo Code supports two configuration levels:\n\n- **Global MCP Configuration** — stored in `mcp_settings.json`\n- **Project-level MCP Configuration** — stored in `.kilocode/mcp.json` (recommended)\n\nIf a server is defined in both places, the **project-level configuration overrides the global one**.\n\n---\n\n## Configure via Kilo Code UI\n\n1. Open **Kilo Code**.\n2. Click the **Settings** icon in the top-right corner.\n3. Navigate to **Settings → MCP Servers**.\n4. Click **Add Server**.\n5. Choose **HTTP Server** (Streamable HTTP Transport).\n6. Enter the details:\n\n**URL**\n`https://mcp.context7.com/mcp`\n\n**Headers → Add Header**\n\n- **Key:** `Authorization`\n- **Value:** `Bearer YOUR_API_KEY`\n\n7. Click **Save**.\n8. Ensure the server toggle is **enabled**.\n9. If needed, click **Refresh MCP Servers** to reload the configuration.\n\n---\n\n## Manual Configuration (`.kilocode/mcp.json`)\n\nTo configure the server at the project level (recommended for team environments), create the following file:\n\n**`.kilocode/mcp.json`:**\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer YOUR_API_KEY\"\n      },\n      \"alwaysAllow\": [],\n      \"disabled\": false\n    }\n  }\n}\n```\n\nReplace YOUR_API_KEY with your actual Context7 API key.\n\nAfter saving the file:\n\n- Open Settings → MCP Servers\n\n- Click Refresh MCP Servers\n\nKilo Code will automatically detect and load the configuration.\n\n</details>\n\n<details>\n<summary><b>Install in Google Antigravity</b></summary>\n\nAdd this to your Antigravity MCP config file. See [Antigravity MCP docs](https://antigravity.google/docs/mcp) for more info.\n\n#### Google Antigravity Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"serverUrl\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Google Antigravity Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Roo Code</b></summary>\n\nAdd this to your Roo Code MCP configuration file. See [Roo Code MCP docs](https://docs.roocode.com/features/mcp/using-mcp-in-roo) for more info.\n\n#### Roo Code Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Roo Code Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Gemini CLI</b></summary>\n\nSee [Gemini CLI Configuration](https://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html) for details.\n\n1.  Open the Gemini CLI settings file. The location is `~/.gemini/settings.json` (where `~` is your home directory).\n2.  Add the following to the `mcpServers` object in your `settings.json` file:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"httpUrl\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\",\n        \"Accept\": \"application/json, text/event-stream\"\n      }\n    }\n  }\n}\n```\n\nOr, for a local server:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\nIf the `mcpServers` object does not exist, create it.\n\n</details>\n\n<details>\n<summary><b>Install in Qwen Coder</b></summary>\n\nSee [Qwen Coder MCP Configuration](https://qwenlm.github.io/qwen-code-docs/en/tools/mcp-server/#how-to-set-up-your-mcp-server) for details.\n\n1.  Open the Qwen Coder settings file. The location is `~/.qwen/settings.json` (where `~` is your home directory).\n2.  Add the following to the `mcpServers` object in your `settings.json` file:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"httpUrl\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\",\n        \"Accept\": \"application/json, text/event-stream\"\n      }\n    }\n  }\n}\n```\n\nOr, for a local server:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\nIf the `mcpServers` object does not exist, create it.\n\n</details>\n\n<details>\n<summary><b>Install in Claude Desktop</b></summary>\n\n#### Remote Server Connection\n\nOpen Claude Desktop and navigate to Settings > Connectors > Add Custom Connector. Enter the name as `Context7` and the remote MCP server URL as `https://mcp.context7.com/mcp`.\n\n#### Local Server Connection\n\nOpen Claude Desktop developer settings and edit your `claude_desktop_config.json` file to add the following configuration. See [Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user) for more info.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Opencode</b></summary>\n\nAdd this to your Opencode configuration file. See [Opencode MCP docs](https://opencode.ai/docs/mcp-servers) for more info.\n\n#### Opencode Remote Server Connection\n\n```json\n\"mcp\": {\n  \"context7\": {\n    \"type\": \"remote\",\n    \"url\": \"https://mcp.context7.com/mcp\",\n    \"headers\": {\n      \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n    },\n    \"enabled\": true\n  }\n}\n```\n\n#### Opencode Local Server Connection\n\n```json\n{\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"enabled\": true\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in OpenAI Codex</b></summary>\n\nSee [OpenAI Codex](https://github.com/openai/codex) for more information.\n\nAdd the following configuration to your OpenAI Codex MCP server settings:\n\n#### Local Server Connection\n\n```toml\n[mcp_servers.context7]\nargs = [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\ncommand = \"npx\"\nstartup_timeout_ms = 20_000\n```\n\n#### Remote Server Connection\n\n```toml\n[mcp_servers.context7]\nurl = \"https://mcp.context7.com/mcp\"\nhttp_headers = { \"CONTEXT7_API_KEY\" = \"YOUR_API_KEY\" }\n```\n\n> Optional troubleshooting — only if you see startup \"request timed out\" or \"not found program\". Most users can ignore this.\n>\n> - First try: increase `startup_timeout_ms` to `40_000` and retry.\n> - Windows quick fix (absolute `npx` path + explicit env):\n>\n> ```toml\n> [mcp_servers.context7]\n> command = \"C:\\\\Users\\\\yourname\\\\AppData\\\\Roaming\\\\npm\\\\npx.cmd\"\n> args = [\n>   \"-y\",\n>   \"@upstash/context7-mcp\",\n>   \"--api-key\",\n>   \"YOUR_API_KEY\"\n> ]\n> env = { SystemRoot=\"C:\\\\Windows\", APPDATA=\"C:\\\\Users\\\\yourname\\\\AppData\\\\Roaming\" }\n> startup_timeout_ms = 40_000\n> ```\n>\n> - macOS quick fix (use Node + installed package entry point):\n>\n> ```toml\n> [mcp_servers.context7]\n> command = \"/Users/yourname/.nvm/versions/node/v22.14.0/bin/node\"\n> args = [\"/Users/yourname/.nvm/versions/node/v22.14.0/lib/node_modules/@upstash/context7-mcp/dist/index.js\",\n>   \"--transport\",\n>   \"stdio\",\n>   \"--api-key\",\n>   \"YOUR_API_KEY\"\n> ]\n> ```\n>\n> Notes: Replace `yourname` with your OS username. Explicitly setting `APPDATA` and `SystemRoot` is essential because these are required by `npx` on Windows but not set by certain versions of OpenAI Codex mcp clients by default.\n\n</details>\n\n<details>\n\n<summary><b>Install in JetBrains AI Assistant</b></summary>\n\nSee [JetBrains AI Assistant Documentation](https://www.jetbrains.com/help/ai-assistant/configure-an-mcp-server.html) for more details.\n\n1. In JetBrains IDEs, go to `Settings` -> `Tools` -> `AI Assistant` -> `Model Context Protocol (MCP)`\n2. Click `+ Add`.\n3. Click on `Command` in the top-left corner of the dialog and select the As JSON option from the list\n4. Add this configuration and click `OK`\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n5. Click `Apply` to save changes.\n6. The same way context7 could be added for JetBrains Junie in `Settings` -> `Tools` -> `Junie` -> `MCP Settings`\n\n</details>\n\n<details>\n  \n<summary><b>Install in Kiro</b></summary>\n\nSee [Kiro Model Context Protocol Documentation](https://kiro.dev/docs/mcp/configuration/) for details.\n\n1. Navigate `Kiro` > `MCP Servers`\n2. Add a new MCP server by clicking the `+ Add` button.\n3. Paste the configuration given below:\n\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"env\": {},\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n\n4. Click `Save` to apply the changes.\n\n</details>\n\n<details>\n<summary><b>Install in Trae</b></summary>\n\nUse the Add manually feature and fill in the JSON configuration information for that MCP server.\nFor more details, visit the [Trae documentation](https://docs.trae.ai/ide/model-context-protocol?_lang=en).\n\n#### Trae Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Trae Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Using Bun or Deno</b></summary>\n\nUse these alternatives to run the local Context7 MCP server with other runtimes. These examples work for any client that supports launching a local MCP server via command + args.\n\n#### Bun\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n#### Deno\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"deno\",\n      \"args\": [\n        \"run\",\n        \"--allow-env=NO_DEPRECATION,TRACE_DEPRECATION\",\n        \"--allow-net\",\n        \"npm:@upstash/context7-mcp\"\n      ]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Using Docker</b></summary>\n\nIf you prefer to run the MCP server in a Docker container:\n\n1. **Build the Docker Image:**\n\n   First, create a `Dockerfile` in the project root (or anywhere you prefer):\n\n   <details>\n   <summary>Click to see Dockerfile content</summary>\n\n   ```Dockerfile\n   FROM node:18-alpine\n\n   WORKDIR /app\n\n   # Install the latest version globally\n   RUN npm install -g @upstash/context7-mcp\n\n   # Expose default port if needed (optional, depends on MCP client interaction)\n   # EXPOSE 3000\n\n   # Default command to run the server\n   CMD [\"context7-mcp\"]\n   ```\n\n   </details>\n\n   Then, build the image using a tag (e.g., `context7-mcp`). **Make sure Docker Desktop (or the Docker daemon) is running.** Run the following command in the same directory where you saved the `Dockerfile`:\n\n   ```bash\n   docker build -t context7-mcp .\n   ```\n\n2. **Configure Your MCP Client:**\n\n   Update your MCP client's configuration to use the Docker command.\n\n   _Example for a cline_mcp_settings.json:_\n\n   ```json\n   {\n     \"mcpServers\": {\n       \"Сontext7\": {\n         \"autoApprove\": [],\n         \"disabled\": false,\n         \"timeout\": 60,\n         \"command\": \"docker\",\n         \"args\": [\"run\", \"-i\", \"--rm\", \"context7-mcp\"],\n         \"transportType\": \"stdio\"\n       }\n     }\n   }\n   ```\n\n   _Note: This is an example configuration. Please refer to the specific examples for your MCP client (like Cursor, VS Code, etc.) earlier in this README to adapt the structure (e.g., `mcpServers` vs `servers`). Also, ensure the image name in `args` matches the tag used during the `docker build` command._\n\n</details>\n\n<details>\n<summary><b>Install Using the Desktop Extension</b></summary>\n\nInstall the [context7.mcpb](mcpb/context7.mcpb) file under the mcpb folder and add it to your client. For more information, please check out [MCP bundles docs](https://github.com/anthropics/mcpb#mcp-bundles-mcpb).\n\n</details>\n\n<details>\n<summary><b>Install in Windows</b></summary>\n\nThe configuration on Windows is slightly different compared to Linux or macOS (_`Cline` is used in the example_). The same principle applies to other editors; refer to the configuration of `command` and `args`.\n\n```json\n{\n  \"mcpServers\": {\n    \"github.com/upstash/context7-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n      \"disabled\": false,\n      \"autoApprove\": []\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Amazon Q Developer CLI</b></summary>\n\nAdd this to your Amazon Q Developer CLI configuration file. See [Amazon Q Developer CLI docs](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html) for more details.\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Warp</b></summary>\n\nSee [Warp Model Context Protocol Documentation](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server) for details.\n\n1. Navigate `Settings` > `AI` > `Manage MCP servers`.\n2. Add a new MCP server by clicking the `+ Add` button.\n3. Paste the configuration given below:\n\n```json\n{\n  \"Context7\": {\n    \"command\": \"npx\",\n    \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n    \"env\": {},\n    \"working_directory\": null,\n    \"start_on_launch\": true\n  }\n}\n```\n\n4. Click `Save` to apply the changes.\n\n</details>\n\n<details>\n\n<summary><b>Install in Copilot Coding Agent</b></summary>\n\n## Using Context7 with Copilot Coding Agent\n\nAdd the following configuration to the `mcp` section of your Copilot Coding Agent configuration file Repository->Settings->Copilot->Coding agent->MCP configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"get-library-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\n\nFor more information, see the [official GitHub documentation](https://docs.github.com/en/enterprise-cloud@latest/copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp).\n\n</details>\n\n<details>\n<summary><b>Install in Copilot CLI</b></summary>\n\n1.  Open the Copilot CLI MCP config file. The location is `~/.copilot/mcp-config.json` (where `~` is your home directory).\n2.  Add the following to the `mcpServers` object in your `mcp-config.json` file:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      },\n      \"tools\": [\"get-library-docs\", \"resolve-library-id\"]\n    }\n  }\n}\n```\n\nOr, for a local server:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"type\": \"local\",\n      \"command\": \"npx\",\n      \"tools\": [\"get-library-docs\", \"resolve-library-id\"],\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\nIf the `mcp-config.json` file does not exist, create it.\n\n</details>\n\n<details>\n<summary><b>Install in LM Studio</b></summary>\n\nSee [LM Studio MCP Support](https://lmstudio.ai/blog/lmstudio-v0.3.17) for more information.\n\n#### One-click install:\n\n[![Add MCP Server context7 to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=context7&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB1cHN0YXNoL2NvbnRleHQ3LW1jcCJdfQ%3D%3D)\n\n#### Manual set-up:\n\n1. Navigate to `Program` (right side) > `Install` > `Edit mcp.json`.\n2. Paste the configuration given below:\n\n```json\n{\n  \"mcpServers\": {\n    \"Context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n3. Click `Save` to apply the changes.\n4. Toggle the MCP server on/off from the right hand side, under `Program`, or by clicking the plug icon at the bottom of the chat box.\n\n</details>\n\n<details>\n<summary><b>Install in Visual Studio 2022</b></summary>\n\nYou can configure Context7 MCP in Visual Studio 2022 by following the [Visual Studio MCP Servers documentation](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\n\nAdd this to your Visual Studio MCP config file (see the [Visual Studio docs](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022) for details):\n\n```json\n{\n  \"inputs\": [],\n  \"servers\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\nOr, for a local server:\n\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"context7\": {\n        \"type\": \"stdio\",\n        \"command\": \"npx\",\n        \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n      }\n    }\n  }\n}\n```\n\nFor more information and troubleshooting, refer to the [Visual Studio MCP Servers documentation](https://learn.microsoft.com/visualstudio/ide/mcp-servers?view=vs-2022).\n\n</details>\n\n<details>\n<summary><b>Install in Crush</b></summary>\n\nAdd this to your Crush configuration file. See [Crush MCP docs](https://github.com/charmbracelet/crush#mcps) for more info.\n\n#### Crush Remote Server Connection (HTTP)\n\n```json\n{\n  \"$schema\": \"https://charm.land/crush.json\",\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n#### Crush Local Server Connection\n\n```json\n{\n  \"$schema\": \"https://charm.land/crush.json\",\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in BoltAI</b></summary>\n\nOpen the \"Settings\" page of the app, navigate to \"Plugins,\" and enter the following JSON:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\nOnce saved, enter in the chat `get-library-docs` followed by your Context7 documentation ID (e.g., `get-library-docs /nuxt/ui`). More information is available on [BoltAI's Documentation site](https://docs.boltai.com/docs/plugins/mcp-servers). For BoltAI on iOS, [see this guide](https://docs.boltai.com/docs/boltai-mobile/mcp-servers).\n\n</details>\n\n<details>\n<summary><b>Install in Rovo Dev CLI</b></summary>\n\nEdit your Rovo Dev CLI MCP config by running the command below -\n\n```bash\nacli rovodev mcp\n```\n\nExample config -\n\n#### Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n#### Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Zencoder</b></summary>\n\nTo configure Context7 MCP in Zencoder, follow these steps:\n\n1. Go to the Zencoder menu (...)\n2. From the dropdown menu, select Agent tools\n3. Click on the Add custom MCP\n4. Add the name and server configuration from below, and make sure to hit the Install button\n\n```json\n{\n  \"command\": \"npx\",\n  \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n}\n```\n\nOnce the MCP server is added, you can easily continue using it.\n\n</details>\n\n<details>\n<summary><b>Install in Qodo Gen</b></summary>\n\nSee [Qodo Gen docs](https://docs.qodo.ai/qodo-documentation/qodo-gen/qodo-gen-chat/agentic-mode/agentic-tools-mcps) for more details.\n\n1. Open Qodo Gen chat panel in VSCode or IntelliJ.\n2. Click Connect more tools.\n3. Click + Add new MCP.\n4. Add the following configuration:\n\n#### Qodo Gen Local Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n#### Qodo Gen Remote Server Connection\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"url\": \"https://mcp.context7.com/mcp\"\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Install in Perplexity Desktop</b></summary>\n\nSee [Local and Remote MCPs for Perplexity](https://www.perplexity.ai/help-center/en/articles/11502712-local-and-remote-mcps-for-perplexity) for more information.\n\n1. Navigate `Perplexity` > `Settings`\n2. Select `Connectors`.\n3. Click `Add Connector`.\n4. Select `Advanced`.\n5. Enter Server Name: `Context7`\n6. Paste the following JSON in the text area:\n\n```json\n{\n  \"args\": [\"-y\", \"@upstash/context7-mcp\", \"--api-key\", \"YOUR_API_KEY\"],\n  \"command\": \"npx\",\n  \"env\": {}\n}\n```\n\n7. Click `Save`.\n</details>\n\n<details>\n<summary><b>Install in Factory</b></summary>\n\nFactory's droid supports MCP servers through its CLI. See [Factory MCP docs](https://docs.factory.ai/cli/configuration/mcp) for more info.\n\n#### Factory Remote Server Connection (HTTP)\n\nRun this command in your terminal:\n\n```sh\ndroid mcp add context7 https://mcp.context7.com/mcp --type http --header \"CONTEXT7_API_KEY: YOUR_API_KEY\"\n```\n\nOr without an API key (basic usage with rate limits):\n\n```sh\ndroid mcp add context7 https://mcp.context7.com/mcp --type http\n```\n\n#### Factory Local Server Connection (Stdio)\n\nRun this command in your terminal:\n\n```sh\ndroid mcp add context7 \"npx -y @upstash/context7-mcp\" --env CONTEXT7_API_KEY=YOUR_API_KEY\n```\n\nOnce configured, Context7 tools will be available in your droid sessions. Type `/mcp` within droid to manage servers, authenticate, and view available tools.\n\n</details>\n\n<details>\n<summary><b>Install in Emdash</b></summary>\n\n[Emdash](https://github.com/generalaction/emdash) is an orchestration layer for running multiple coding agents in parallel. Provider-agnostic, worktree-isolated, and local-first. Emdash supports Context7 MCP to enable Context7 for your agents.\n\n**What Emdash provides:**\n\n- Global toggle: Settings → MCP → \"Enable Context7 MCP\"\n- Per-workspace enable: The Context7 button in the ProviderBar (off by default). First click enables it for that workspace. Clicking again disables it.\n- ProviderBar: The Context7 button shows status, a short explanation, and a link to docs\n\n**What you still need to do:**\nConfigure your coding agent (Codex, Claude Code, Cursor, etc.) to connect to Context7 MCP. Emdash does not modify your agent's config. See the respective MCP configuration sections above for your agent (e.g., OpenAI Codex, Claude Code, Cursor).\n\nSee the [Emdash repository](https://github.com/generalaction/emdash) for more information.\n\n</details>\n\n## 🔨 Available Tools\n\nContext7 MCP provides the following tools that LLMs can use:\n\n- `resolve-library-id`: Resolves a general library name into a Context7-compatible library ID.\n  - `libraryName` (required): The name of the library to search for\n\n- `get-library-docs`: Fetches documentation for a library using a Context7-compatible library ID.\n  - `context7CompatibleLibraryID` (required): Exact Context7-compatible library ID (e.g., `/mongodb/docs`, `/vercel/next.js`)\n  - `topic` (optional): Focus the docs on a specific topic (e.g., \"routing\", \"hooks\")\n  - `page` (optional, default 1): Page number for pagination (1-10). If the context is not sufficient, try page=2, page=3, etc. with the same topic.\n\n## 🛟 Tips\n\n### Add a Rule\n\nTo avoid typing `use context7` in every prompt, you can add a rule to your MCP client that automatically invokes Context7 for code-related questions. See the [recommended setup in the Installation section](#️-installation) for detailed instructions and example rules.\n\n### Use Library Id\n\nIf you already know exactly which library you want to use, add its Context7 ID to your prompt. That way, Context7 MCP server can skip the library-matching step and directly continue with retrieving docs.\n\n```txt\nImplement basic authentication with Supabase. use library /supabase/supabase for API and docs.\n```\n\nThe slash syntax tells the MCP tool exactly which library to load docs for.\n\n### HTTPS Proxy\n\nIf you are behind an HTTP proxy, Context7 uses the standard `https_proxy` / `HTTPS_PROXY` environment variables.\n\n## 💻 Development\n\nClone the project and install dependencies:\n\n```bash\nbun i\n```\n\nBuild:\n\n```bash\nbun run build\n```\n\nRun the server:\n\n```bash\nbun run dist/index.js\n```\n\n### CLI Arguments\n\n`context7-mcp` accepts the following CLI flags:\n\n- `--transport <stdio|http>` – Transport to use (`stdio` by default). Use `http` for remote HTTP server or `stdio` for local integration.\n- `--port <number>` – Port to listen on when using `http` transport (default `3000`).\n- `--api-key <key>` – API key for authentication (or set `CONTEXT7_API_KEY` env var). You can get your API key by creating an account at [context7.com/dashboard](https://context7.com/dashboard).\n\nExample with HTTP transport and port 8080:\n\n```bash\nbun run dist/index.js --transport http --port 8080\n```\n\nAnother example with stdio transport:\n\n```bash\nbun run dist/index.js --transport stdio --api-key YOUR_API_KEY\n```\n\n### Environment Variables\n\nYou can use the `CONTEXT7_API_KEY` environment variable instead of passing the `--api-key` flag. This is useful for:\n\n- Storing API keys securely in `.env` files\n- Integration with MCP server setups that use dotenv\n- Tools that prefer environment variable configuration\n\n**Note:** The `--api-key` CLI flag takes precedence over the environment variable when both are provided.\n\n**Example with .env file:**\n\n```bash\n# .env\nCONTEXT7_API_KEY=your_api_key_here\n```\n\n**Example MCP configuration using environment variable:**\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"],\n      \"env\": {\n        \"CONTEXT7_API_KEY\": \"YOUR_API_KEY\"\n      }\n    }\n  }\n}\n```\n\n<details>\n<summary><b>Local Configuration Example</b></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"tsx\", \"/path/to/folder/context7/src/index.ts\", \"--api-key\", \"YOUR_API_KEY\"]\n    }\n  }\n}\n```\n\n</details>\n\n### OAuth Authentication\n\nContext7 MCP server supports OAuth 2.0 authentication for MCP clients that implement the [MCP OAuth specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization).\n\nTo use OAuth, change the endpoint from `/mcp` to `/mcp/oauth` in your client configuration:\n\n```diff\n- \"url\": \"https://mcp.context7.com/mcp\"\n+ \"url\": \"https://mcp.context7.com/mcp/oauth\"\n```\n\n> **Note:** OAuth is not supported with stdio transport. For local MCP connections, use API key authentication instead.\n\n<details>\n<summary><b>Testing with MCP Inspector</b></summary>\n\n```bash\nnpx -y @modelcontextprotocol/inspector npx @upstash/context7-mcp\n```\n\n</details>\n\n## 🚨 Troubleshooting\n\n<details>\n<summary><b>Module Not Found Errors</b></summary>\n\nIf you encounter `ERR_MODULE_NOT_FOUND`, try using `bunx` instead of `npx`:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"bunx\",\n      \"args\": [\"-y\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\nThis often resolves module resolution issues in environments where `npx` doesn't properly install or resolve packages.\n\n</details>\n\n<details>\n<summary><b>ESM Resolution Issues</b></summary>\n\nFor errors like `Error: Cannot find module 'uriTemplate.js'`, try the `--experimental-vm-modules` flag:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-vm-modules\", \"@upstash/context7-mcp@1.0.6\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>TLS/Certificate Issues</b></summary>\n\nUse the `--experimental-fetch` flag to bypass TLS-related problems:\n\n```json\n{\n  \"mcpServers\": {\n    \"context7\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"--node-options=--experimental-fetch\", \"@upstash/context7-mcp\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>General MCP Client Errors</b></summary>\n\n1. Try adding `@latest` to the package name\n2. Use `bunx` as an alternative to `npx`\n3. Consider using `deno` as another alternative\n4. Ensure you're using Node.js v18 or higher for native fetch support\n\n</details>\n\n## ⚠️ Disclaimer\n\n1- Context7 projects are community-contributed and while we strive to maintain high quality, we cannot guarantee the accuracy, completeness, or security of all library documentation. Projects listed in Context7 are developed and maintained by their respective owners, not by Context7. If you encounter any suspicious, inappropriate, or potentially harmful content, please use the \"Report\" button on the project page to notify us immediately. We take all reports seriously and will review flagged content promptly to maintain the integrity and safety of our platform. By using Context7, you acknowledge that you do so at your own discretion and risk.\n\n2- This repository hosts the MCP server’s source code. The supporting components — API backend, parsing engine, and crawling engine — are private and not part of this release.\n\n## 🤝 Connect with Us\n\nStay updated and join our community:\n\n- 📢 Follow us on [X](https://x.com/context7ai) for the latest news and updates\n- 🌐 Visit our [Website](https://context7.com)\n- 💬 Join our [Discord Community](https://upstash.com/discord)\n\n## 📺 Context7 In Media\n\n- [Better Stack: \"Free Tool Makes Cursor 10x Smarter\"](https://youtu.be/52FC3qObp9E)\n- [Cole Medin: \"This is Hands Down the BEST MCP Server for AI Coding Assistants\"](https://www.youtube.com/watch?v=G7gK8H6u7Rs)\n- [Income Stream Surfers: \"Context7 + SequentialThinking MCPs: Is This AGI?\"](https://www.youtube.com/watch?v=-ggvzyLpK6o)\n- [Julian Goldie SEO: \"Context7: New MCP AI Agent Update\"](https://www.youtube.com/watch?v=CTZm6fBYisc)\n- [JeredBlu: \"Context 7 MCP: Get Documentation Instantly + VS Code Setup\"](https://www.youtube.com/watch?v=-ls0D-rtET4)\n- [Income Stream Surfers: \"Context7: The New MCP Server That Will CHANGE AI Coding\"](https://www.youtube.com/watch?v=PS-2Azb-C3M)\n- [AICodeKing: \"Context7 + Cline & RooCode: This MCP Server Makes CLINE 100X MORE EFFECTIVE!\"](https://www.youtube.com/watch?v=qZfENAPMnyo)\n- [Sean Kochel: \"5 MCP Servers For Vibe Coding Glory (Just Plug-In & Go)\"](https://www.youtube.com/watch?v=LqTQi8qexJM)\n\n## ⭐ Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=upstash/context7&type=Date)](https://www.star-history.com/#upstash/context7&Date)\n\n## 📄 License\n\nMIT\n"
  },
  {
    "path": "packages/mcp/eslint.config.js",
    "content": "import { defineConfig } from \"eslint/config\";\nimport tseslint from \"typescript-eslint\";\nimport eslintPluginPrettier from \"eslint-plugin-prettier\";\n\nexport default defineConfig(\n  {\n    // Base ESLint configuration\n    ignores: [\"node_modules/**\", \"build/**\", \"dist/**\", \".git/**\", \".github/**\"],\n  },\n  {\n    files: [\"**/*.ts\", \"**/*.tsx\"],\n    languageOptions: {\n      ecmaVersion: 2020,\n      sourceType: \"module\",\n      parser: tseslint.parser,\n      parserOptions: {\n        project: \"./tsconfig.json\",\n        tsconfigRootDir: import.meta.dirname,\n      },\n      globals: {\n        // Add Node.js globals\n        process: \"readonly\",\n        require: \"readonly\",\n        module: \"writable\",\n        console: \"readonly\",\n      },\n    },\n    // Settings for all files\n    linterOptions: {\n      reportUnusedDisableDirectives: true,\n    },\n    plugins: {\n      \"@typescript-eslint\": tseslint.plugin,\n      prettier: eslintPluginPrettier,\n    },\n    rules: {\n      // TypeScript recommended rules\n      ...tseslint.configs.recommended.rules,\n      // TypeScript rules\n      \"@typescript-eslint/explicit-module-boundary-types\": \"off\",\n      \"@typescript-eslint/no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\" }],\n      \"@typescript-eslint/no-explicit-any\": \"warn\",\n      // Prettier integration\n      \"prettier/prettier\": \"error\",\n    },\n  }\n);\n"
  },
  {
    "path": "packages/mcp/mcpb/.mcpbignore",
    "content": "# Source (dist/ is sufficient)\nsrc/\n*.ts\n\n# Config files\neslint.config.js\nprettier.config.mjs\nsmithery.yaml\ntsconfig.json\n\n# Documentation\n*.md\nLICENSE\n\n# Docker\nDockerfile\n\n# Schema\nschema/\n\n# Assets (icon is copied to root)\npublic/*\n\n# MCPB meta (avoid nesting)\nmcpb/\n"
  },
  {
    "path": "packages/mcp/mcpb/manifest.json",
    "content": "{\n  \"manifest_version\": \"0.3\",\n  \"name\": \"context7\",\n  \"display_name\": \"Context7\",\n  \"version\": \"2.1.0\",\n  \"description\": \"Up-to-date Code Docs For Any Prompt\",\n  \"long_description\": \"Context7 MCP pulls up-to-date, version-specific documentation and code examples straight from the source — and places them directly into your prompt.\",\n  \"author\": {\n    \"name\": \"Upstash\",\n    \"email\": \"context7@upstash.com\",\n    \"url\": \"https://upstash.com\"\n  },\n  \"homepage\": \"https://context7.com\",\n  \"documentation\": \"https://github.com/upstash/context7\",\n  \"support\": \"https://github.com/upstash/context7/issues\",\n  \"privacy_policies\": [\"https://upstash.com/privacy\"],\n  \"icon\": \"icon.png\",\n  \"server\": {\n    \"type\": \"node\",\n    \"entry_point\": \"dist/index.js\",\n    \"mcp_config\": {\n      \"command\": \"node\",\n      \"args\": [\"${__dirname}/dist/index.js\"],\n      \"env\": {}\n    }\n  },\n  \"tools\": [\n    {\n      \"name\": \"Resolve Context7 Library ID\",\n      \"description\": \"Resolves a package/product name to a Context7-compatible library ID and returns matching libraries.\"\n    },\n    {\n      \"name\": \"Query Documentation\",\n      \"description\": \"Retrieves and queries up-to-date documentation and code examples from Context7.\"\n    }\n  ],\n  \"compatibility\": {\n    \"platforms\": [\"darwin\", \"win32\", \"linux\"],\n    \"runtimes\": {\n      \"node\": \">=v18.0.0\"\n    }\n  },\n  \"keywords\": [\"vibe-coding\", \"developer tools\", \"documentation\", \"context\"],\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/upstash/context7.git\"\n  }\n}\n"
  },
  {
    "path": "packages/mcp/package.json",
    "content": "{\n  \"name\": \"@upstash/context7-mcp\",\n  \"version\": \"2.1.5\",\n  \"mcpName\": \"io.github.upstash/context7\",\n  \"description\": \"MCP server for Context7\",\n  \"scripts\": {\n    \"build\": \"tsc && chmod 755 dist/index.js\",\n    \"test\": \"echo \\\"No tests yet\\\"\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"lint\": \"eslint .\",\n    \"lint:check\": \"eslint .\",\n    \"format\": \"prettier --write .\",\n    \"format:check\": \"prettier --check .\",\n    \"dev\": \"tsc --watch\",\n    \"start\": \"node dist/index.js --transport http\",\n    \"pack-mcpb\": \"pnpm install && pnpm run build && rm -rf node_modules && pnpm install --prod && cp mcpb/manifest.json manifest.json && cp mcpb/.mcpbignore .mcpbignore && cp ../../public/icon.png icon.png && mcpb validate manifest.json && mcpb pack . mcpb/context7.mcpb && rm manifest.json .mcpbignore icon.png && pnpm install\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/upstash/context7.git\",\n    \"directory\": \"packages/mcp\"\n  },\n  \"keywords\": [\n    \"modelcontextprotocol\",\n    \"mcp\",\n    \"context7\",\n    \"vibe-coding\",\n    \"developer tools\",\n    \"documentation\",\n    \"context\"\n  ],\n  \"author\": \"abdush\",\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"bin\": {\n    \"context7-mcp\": \"dist/index.js\"\n  },\n  \"files\": [\n    \"dist\",\n    \"LICENSE\",\n    \"README.md\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/upstash/context7/issues\"\n  },\n  \"homepage\": \"https://github.com/upstash/context7#readme\",\n  \"dependencies\": {\n    \"@modelcontextprotocol/sdk\": \"^1.25.1\",\n    \"@types/express\": \"^5.0.4\",\n    \"commander\": \"^14.0.0\",\n    \"express\": \"^5.1.0\",\n    \"jose\": \"^6.1.3\",\n    \"undici\": \"^6.6.3\",\n    \"zod\": \"^4.3.4\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^25.0.3\",\n    \"typescript\": \"^5.8.2\"\n  }\n}\n"
  },
  {
    "path": "packages/mcp/prettier.config.mjs",
    "content": "/**\n * @type {import('prettier').Config}\n */\nconst config = {\n  endOfLine: \"lf\",\n  singleQuote: false,\n  tabWidth: 2,\n  trailingComma: \"es5\",\n  printWidth: 100,\n  arrowParens: \"always\",\n};\n\nexport default config;\n"
  },
  {
    "path": "packages/mcp/schema/context7.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://context7.com/schema/context7.json\",\n  \"title\": \"Context7 Configuration Schema\",\n  \"description\": \"Configuration file for Context7 project parsing and documentation generation\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"projectTitle\": {\n      \"type\": \"string\",\n      \"description\": \"The display name for your project in Context7. This overrides the default repository name.\",\n      \"minLength\": 1,\n      \"maxLength\": 100,\n      \"examples\": [\"Upstash Ratelimit\", \"Next.js\", \"React Query\"]\n    },\n    \"description\": {\n      \"type\": \"string\",\n      \"description\": \"A brief description of what your library does. This helps coding agents understand the purpose of your project.\",\n      \"minLength\": 10,\n      \"maxLength\": 200,\n      \"examples\": [\n        \"Ratelimiting library based on Upstash Redis\",\n        \"The React Framework for Production\",\n        \"Powerful data synchronization for React\"\n      ]\n    },\n    \"folders\": {\n      \"type\": \"array\",\n      \"description\": \"Specific folder paths to include when parsing documentation. If empty, Context7 will scan the entire repository. Supports regex patterns and requires full paths.\",\n      \"items\": {\n        \"type\": \"string\",\n        \"minLength\": 1\n      },\n      \"uniqueItems\": true,\n      \"default\": [],\n      \"examples\": [\n        [\"docs\", \"guides\", \"examples\"],\n        [\"documentation/**\"],\n        [\"api-reference\", \"tutorials/*\"]\n      ]\n    },\n    \"excludeFolders\": {\n      \"type\": \"array\",\n      \"description\": \"Folder paths to exclude from documentation parsing. Supports regex patterns and requires full paths.\",\n      \"items\": {\n        \"type\": \"string\",\n        \"minLength\": 1\n      },\n      \"uniqueItems\": true,\n      \"default\": [],\n      \"examples\": [\n        [\"src\", \"build\", \"node_modules\"],\n        [\"**/test/**\", \"**/tests/**\"],\n        [\"legacy/*\", \"archive\"]\n      ]\n    },\n    \"excludeFiles\": {\n      \"type\": \"array\",\n      \"description\": \"Specific file names to exclude from documentation parsing. Only include the filename (not the path). Regex patterns are not supported.\",\n      \"items\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"pattern\": \"^[^/\\\\\\\\]+$\"\n      },\n      \"uniqueItems\": true,\n      \"default\": [],\n      \"examples\": [\n        [\"CHANGELOG.md\", \"LICENSE\"],\n        [\"README-dev.md\", \"CONTRIBUTING.md\"],\n        [\"package.json\", \"tsconfig.json\"]\n      ]\n    },\n    \"rules\": {\n      \"type\": \"array\",\n      \"description\": \"Best practices or important guidelines that coding agents should follow when using your library. These appear as recommendations in the documentation context.\",\n      \"items\": {\n        \"type\": \"string\",\n        \"minLength\": 5,\n        \"maxLength\": 200\n      },\n      \"default\": [],\n      \"examples\": [\n        [\"Always use TypeScript for better type safety\"],\n        [\"Use Upstash Redis as a database\", \"Use single region set up\"],\n        [\"Import components from the main package\", \"Follow the naming conventions\"]\n      ]\n    },\n    \"previousVersions\": {\n      \"type\": \"array\",\n      \"description\": \"Information about previous versions of your library that should also be available in Context7.\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"tag\": {\n            \"type\": \"string\",\n            \"description\": \"The Git tag or version identifier\",\n            \"pattern\": \"^v?\\\\d+\\\\.\\\\d+\\\\.\\\\d+\",\n            \"examples\": [\"v1.2.1\", \"2.0.0\", \"v3.1.0-beta.1\"]\n          },\n          \"title\": {\n            \"type\": \"string\",\n            \"description\": \"Human-readable version name\",\n            \"minLength\": 1,\n            \"maxLength\": 50,\n            \"examples\": [\"version 1.2.1\", \"Legacy Version\", \"Beta Release\"]\n          }\n        },\n        \"required\": [\"tag\", \"title\"],\n        \"additionalProperties\": false\n      },\n      \"default\": []\n    }\n  },\n  \"additionalProperties\": false,\n  \"examples\": [\n    {\n      \"projectTitle\": \"Upstash Ratelimit\",\n      \"description\": \"Ratelimiting library based on Upstash Redis\",\n      \"folders\": [],\n      \"excludeFolders\": [\"src\"],\n      \"excludeFiles\": [],\n      \"rules\": [\"Use Upstash Redis as a database\", \"Use single region set up\"],\n      \"previousVersions\": [\n        {\n          \"tag\": \"v1.2.1\",\n          \"title\": \"version 1.2.1\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "packages/mcp/smithery.yaml",
    "content": "# Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml\n\nstartCommand:\n  type: http\n  configSchema:\n    # JSON Schema defining the configuration options for the MCP.\n    type: object\n    description: No configuration required\n  exampleConfig: {}\n"
  },
  {
    "path": "packages/mcp/src/index.ts",
    "content": "#!/usr/bin/env node\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { searchLibraries, fetchLibraryContext } from \"./lib/api.js\";\nimport { ClientContext } from \"./lib/encryption.js\";\nimport { formatSearchResults, extractClientInfoFromUserAgent } from \"./lib/utils.js\";\nimport { isJWT, validateJWT } from \"./lib/jwt.js\";\nimport express from \"express\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { Command } from \"commander\";\nimport { AsyncLocalStorage } from \"async_hooks\";\nimport { SERVER_VERSION, RESOURCE_URL, AUTH_SERVER_URL } from \"./lib/constants.js\";\n\n/** Default HTTP server port */\nconst DEFAULT_PORT = 3000;\n\n// Parse CLI arguments using commander\nconst program = new Command()\n  .option(\"--transport <stdio|http>\", \"transport type\", \"stdio\")\n  .option(\"--port <number>\", \"port for HTTP transport\", DEFAULT_PORT.toString())\n  .option(\"--api-key <key>\", \"API key for authentication (or set CONTEXT7_API_KEY env var)\")\n  .allowUnknownOption() // let MCP Inspector / other wrappers pass through extra flags\n  .parse(process.argv);\n\nconst cliOptions = program.opts<{\n  transport: string;\n  port: string;\n  apiKey?: string;\n}>();\n\n// Validate transport option\nconst allowedTransports = [\"stdio\", \"http\"];\nif (!allowedTransports.includes(cliOptions.transport)) {\n  console.error(\n    `Invalid --transport value: '${cliOptions.transport}'. Must be one of: stdio, http.`\n  );\n  process.exit(1);\n}\n\n// Transport configuration\nconst TRANSPORT_TYPE = (cliOptions.transport || \"stdio\") as \"stdio\" | \"http\";\n\n// Disallow incompatible flags based on transport\nconst passedPortFlag = process.argv.includes(\"--port\");\nconst passedApiKeyFlag = process.argv.includes(\"--api-key\");\n\nif (TRANSPORT_TYPE === \"http\" && passedApiKeyFlag) {\n  console.error(\n    \"The --api-key flag is not allowed when using --transport http. Use header-based auth at the HTTP layer instead.\"\n  );\n  process.exit(1);\n}\n\nif (TRANSPORT_TYPE === \"stdio\" && passedPortFlag) {\n  console.error(\"The --port flag is not allowed when using --transport stdio.\");\n  process.exit(1);\n}\n\n// HTTP port configuration\nconst CLI_PORT = (() => {\n  const parsed = parseInt(cliOptions.port, 10);\n  return isNaN(parsed) ? undefined : parsed;\n})();\n\nconst requestContext = new AsyncLocalStorage<ClientContext>();\n\n// Global state for stdio mode only\nlet stdioApiKey: string | undefined;\nlet stdioClientInfo: { ide?: string; version?: string } | undefined;\n\n/**\n * Get the effective client context\n */\nfunction getClientContext(): ClientContext {\n  const ctx = requestContext.getStore();\n\n  // HTTP mode: context is fully populated from request\n  if (ctx) {\n    return ctx;\n  }\n\n  // stdio mode: use globals\n  return {\n    apiKey: stdioApiKey,\n    clientInfo: stdioClientInfo,\n    transport: \"stdio\",\n  };\n}\n\n/**\n * Extract client IP address from request headers.\n * Handles X-Forwarded-For header for proxied requests.\n */\nfunction getClientIp(req: express.Request): string | undefined {\n  const forwardedFor = req.headers[\"x-forwarded-for\"] || req.headers[\"X-Forwarded-For\"];\n\n  if (forwardedFor) {\n    const ips = Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor;\n    const ipList = ips.split(\",\").map((ip) => ip.trim());\n\n    for (const ip of ipList) {\n      const plainIp = ip.replace(/^::ffff:/, \"\");\n      if (\n        !plainIp.startsWith(\"10.\") &&\n        !plainIp.startsWith(\"192.168.\") &&\n        !/^172\\.(1[6-9]|2[0-9]|3[0-1])\\./.test(plainIp)\n      ) {\n        return plainIp;\n      }\n    }\n    return ipList[0].replace(/^::ffff:/, \"\");\n  }\n\n  if (req.socket?.remoteAddress) {\n    return req.socket.remoteAddress.replace(/^::ffff:/, \"\");\n  }\n  return undefined;\n}\n\nconst server = new McpServer(\n  {\n    name: \"Context7\",\n    version: SERVER_VERSION,\n  },\n  {\n    instructions:\n      \"Use this server to retrieve up-to-date documentation and code examples for any library.\",\n  }\n);\n\n// Capture client info from MCP initialize handshake\nserver.server.oninitialized = () => {\n  const clientVersion = server.server.getClientVersion();\n  if (clientVersion) {\n    stdioClientInfo = {\n      ide: clientVersion.name,\n      version: clientVersion.version,\n    };\n  }\n};\n\nserver.registerTool(\n  \"resolve-library-id\",\n  {\n    title: \"Resolve Context7 Library ID\",\n    description: `Resolves a package/product name to a Context7-compatible library ID and returns matching libraries.\n\nYou MUST call this function before 'Query Documentation' tool to obtain a valid Context7-compatible library ID UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query.\n\nEach result includes:\n- Library ID: Context7-compatible identifier (format: /org/project)\n- Name: Library or package name\n- Description: Short summary\n- Code Snippets: Number of available code examples\n- Source Reputation: Authority indicator (High, Medium, Low, or Unknown)\n- Benchmark Score: Quality indicator (100 is the highest score)\n- Versions: List of versions if available. Use one of those versions if the user provides a version in their query. The format of the version is /org/project/version.\n\nFor best results, select libraries based on name match, source reputation, snippet coverage, benchmark score, and relevance to your use case.\n\nSelection Process:\n1. Analyze the query to understand what library/package the user is looking for\n2. Return the most relevant match based on:\n- Name similarity to the query (exact matches prioritized)\n- Description relevance to the query's intent\n- Documentation coverage (prioritize libraries with higher Code Snippet counts)\n- Source reputation (consider libraries with High or Medium reputation more authoritative)\n- Benchmark Score: Quality indicator (100 is the highest score)\n\nResponse Format:\n- Return the selected library ID in a clearly marked section\n- Provide a brief explanation for why this library was chosen\n- If multiple good matches exist, acknowledge this but proceed with the most relevant one\n- If no good matches exist, clearly state this and suggest query refinements\n\nFor ambiguous queries, request clarification before proceeding with a best-guess match.\n\nIMPORTANT: Do not call this tool more than 3 times per question. If you cannot find what you need after 3 calls, use the best result you have.`,\n    inputSchema: {\n      query: z\n        .string()\n        .describe(\n          \"The question or task you need help with. This is used to rank library results by relevance to what the user is trying to accomplish. The query is sent to the Context7 API for processing. Do not include any sensitive or confidential information such as API keys, passwords, credentials, personal data, or proprietary code in your query.\"\n        ),\n      libraryName: z\n        .string()\n        .describe(\"Library name to search for and retrieve a Context7-compatible library ID.\"),\n    },\n    annotations: {\n      readOnlyHint: true,\n    },\n  },\n  async ({ query, libraryName }) => {\n    const searchResponse = await searchLibraries(query, libraryName, getClientContext());\n\n    if (!searchResponse.results || searchResponse.results.length === 0) {\n      return {\n        content: [\n          {\n            type: \"text\",\n            text: searchResponse.error\n              ? searchResponse.error\n              : \"No libraries found matching the provided name.\",\n          },\n        ],\n      };\n    }\n\n    const resultsText = formatSearchResults(searchResponse);\n\n    const responseText = `Available Libraries:\n\n${resultsText}`;\n\n    return {\n      content: [\n        {\n          type: \"text\",\n          text: responseText,\n        },\n      ],\n    };\n  }\n);\n\nserver.registerTool(\n  \"query-docs\",\n  {\n    title: \"Query Documentation\",\n    description: `Retrieves and queries up-to-date documentation and code examples from Context7 for any programming library or framework.\n\nYou must call 'Resolve Context7 Library ID' tool first to obtain the exact Context7-compatible library ID required to use this tool, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query.\n\nIMPORTANT: Do not call this tool more than 3 times per question. If you cannot find what you need after 3 calls, use the best information you have.`,\n    inputSchema: {\n      libraryId: z\n        .string()\n        .describe(\n          \"Exact Context7-compatible library ID (e.g., '/mongodb/docs', '/vercel/next.js', '/supabase/supabase', '/vercel/next.js/v14.3.0-canary.87') retrieved from 'resolve-library-id' or directly from user query in the format '/org/project' or '/org/project/version'.\"\n        ),\n      query: z\n        .string()\n        .describe(\n          \"The question or task you need help with. Be specific and include relevant details. Good: 'How to set up authentication with JWT in Express.js' or 'React useEffect cleanup function examples'. Bad: 'auth' or 'hooks'. The query is sent to the Context7 API for processing. Do not include any sensitive or confidential information such as API keys, passwords, credentials, personal data, or proprietary code in your query.\"\n        ),\n    },\n    annotations: {\n      readOnlyHint: true,\n    },\n  },\n  async ({ query, libraryId }) => {\n    const response = await fetchLibraryContext({ query, libraryId }, getClientContext());\n\n    return {\n      content: [\n        {\n          type: \"text\",\n          text: response.data,\n        },\n      ],\n    };\n  }\n);\n\nasync function main() {\n  const transportType = TRANSPORT_TYPE;\n\n  if (transportType === \"http\") {\n    const initialPort = CLI_PORT ?? DEFAULT_PORT;\n\n    const app = express();\n    app.use(express.json());\n\n    app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {\n      res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n      res.setHeader(\"Access-Control-Allow-Methods\", \"GET,POST,OPTIONS,DELETE\");\n      res.setHeader(\n        \"Access-Control-Allow-Headers\",\n        \"Content-Type, MCP-Session-Id, MCP-Protocol-Version, X-Context7-API-Key, Context7-API-Key, X-API-Key, Authorization\"\n      );\n      res.setHeader(\"Access-Control-Expose-Headers\", \"MCP-Session-Id\");\n\n      if (req.method === \"OPTIONS\") {\n        res.sendStatus(200);\n        return;\n      }\n      next();\n    });\n\n    const extractHeaderValue = (value: string | string[] | undefined): string | undefined => {\n      if (!value) return undefined;\n      return typeof value === \"string\" ? value : value[0];\n    };\n\n    const extractBearerToken = (authHeader: string | string[] | undefined): string | undefined => {\n      const header = extractHeaderValue(authHeader);\n      if (!header) return undefined;\n\n      if (header.startsWith(\"Bearer \")) {\n        return header.substring(7).trim();\n      }\n\n      return header;\n    };\n\n    const extractApiKey = (req: express.Request): string | undefined => {\n      return (\n        extractBearerToken(req.headers.authorization) ||\n        extractHeaderValue(req.headers[\"context7-api-key\"]) ||\n        extractHeaderValue(req.headers[\"x-api-key\"]) ||\n        extractHeaderValue(req.headers[\"context7_api_key\"]) ||\n        extractHeaderValue(req.headers[\"x_api_key\"])\n      );\n    };\n\n    const handleMcpRequest = async (\n      req: express.Request,\n      res: express.Response,\n      requireAuth: boolean\n    ) => {\n      // Reject GET requests — this server is stateless and does not send server-initiated\n      // notifications, so SSE streams serve no purpose and cause mass NGINX timeouts.\n      // Returning 405 is spec-compliant per MCP StreamableHTTP (2025-03-26).\n      if (req.method === \"GET\") {\n        return res.status(405).json({\n          jsonrpc: \"2.0\",\n          error: { code: -32000, message: \"Server does not support GET requests\" },\n          id: null,\n        });\n      }\n\n      try {\n        const apiKey = extractApiKey(req);\n        const resourceUrl = RESOURCE_URL;\n        const baseUrl = new URL(resourceUrl).origin;\n\n        // OAuth discovery info header, used by MCP clients to discover the authorization server\n        res.set(\n          \"WWW-Authenticate\",\n          `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`\n        );\n\n        if (requireAuth) {\n          if (!apiKey) {\n            return res.status(401).json({\n              jsonrpc: \"2.0\",\n              error: {\n                code: -32001,\n                message: \"Authentication required. Please authenticate to use this MCP server.\",\n              },\n              id: null,\n            });\n          }\n\n          if (isJWT(apiKey)) {\n            const validationResult = await validateJWT(apiKey);\n            if (!validationResult.valid) {\n              return res.status(401).json({\n                jsonrpc: \"2.0\",\n                error: {\n                  code: -32001,\n                  message: validationResult.error || \"Invalid token. Please re-authenticate.\",\n                },\n                id: null,\n              });\n            }\n          }\n        }\n\n        const context: ClientContext = {\n          clientIp: getClientIp(req),\n          apiKey: apiKey,\n          clientInfo: extractClientInfoFromUserAgent(req.headers[\"user-agent\"]),\n          transport: \"http\",\n        };\n\n        const transport = new StreamableHTTPServerTransport({\n          sessionIdGenerator: undefined,\n          enableJsonResponse: true,\n        });\n\n        res.on(\"close\", () => {\n          transport.close();\n        });\n\n        await requestContext.run(context, async () => {\n          await server.connect(transport);\n          await transport.handleRequest(req, res, req.body);\n        });\n      } catch (error) {\n        console.error(\"Error handling MCP request:\", error);\n        if (!res.headersSent) {\n          res.status(500).json({\n            jsonrpc: \"2.0\",\n            error: { code: -32603, message: \"Internal server error\" },\n            id: null,\n          });\n        }\n      }\n    };\n\n    // Anonymous access endpoint - no authentication required\n    app.all(\"/mcp\", async (req, res) => {\n      await handleMcpRequest(req, res, false);\n    });\n\n    // OAuth-protected endpoint - requires authentication\n    app.all(\"/mcp/oauth\", async (req, res) => {\n      await handleMcpRequest(req, res, true);\n    });\n\n    app.get(\"/ping\", (_req: express.Request, res: express.Response) => {\n      res.json({ status: \"ok\", message: \"pong\" });\n    });\n\n    // OAuth 2.0 Protected Resource Metadata (RFC 9728)\n    // Used by MCP clients to discover the authorization server\n    app.get(\n      \"/.well-known/oauth-protected-resource\",\n      (_req: express.Request, res: express.Response) => {\n        res.json({\n          resource: RESOURCE_URL,\n          authorization_servers: [AUTH_SERVER_URL],\n          scopes_supported: [\"profile\", \"email\"],\n          bearer_methods_supported: [\"header\"],\n        });\n      }\n    );\n\n    app.get(\n      \"/.well-known/oauth-authorization-server\",\n      async (_req: express.Request, res: express.Response) => {\n        const authServerUrl = AUTH_SERVER_URL;\n\n        try {\n          const response = await fetch(`${authServerUrl}/.well-known/oauth-authorization-server`);\n          if (!response.ok) {\n            console.error(\"[OAuth] Upstream error:\", response.status);\n            return res.status(response.status).json({\n              error: \"upstream_error\",\n              message: \"Failed to fetch authorization server metadata\",\n            });\n          }\n          const metadata = await response.json();\n          res.json(metadata);\n        } catch (error) {\n          console.error(\"[OAuth] Error fetching OAuth metadata:\", error);\n          res.status(502).json({\n            error: \"proxy_error\",\n            message: \"Failed to proxy authorization server metadata\",\n          });\n        }\n      }\n    );\n\n    // Catch-all 404 handler - must be after all other routes\n    app.use((_req: express.Request, res: express.Response) => {\n      res.status(404).json({\n        error: \"not_found\",\n        message: \"Endpoint not found. Use /mcp for MCP protocol communication.\",\n      });\n    });\n\n    const startServer = (port: number, maxAttempts = 10) => {\n      const httpServer = app.listen(port);\n\n      httpServer.once(\"error\", (err: NodeJS.ErrnoException) => {\n        if (err.code === \"EADDRINUSE\" && port < initialPort + maxAttempts) {\n          console.warn(`Port ${port} is in use, trying port ${port + 1}...`);\n          startServer(port + 1, maxAttempts);\n        } else {\n          console.error(`Failed to start server: ${err.message}`);\n          process.exit(1);\n        }\n      });\n\n      httpServer.once(\"listening\", () => {\n        console.error(\n          `Context7 Documentation MCP Server v${SERVER_VERSION} running on HTTP at http://localhost:${port}/mcp`\n        );\n      });\n    };\n\n    startServer(initialPort);\n  } else {\n    stdioApiKey = cliOptions.apiKey || process.env.CONTEXT7_API_KEY;\n    const transport = new StdioServerTransport();\n\n    await server.connect(transport);\n\n    console.error(`Context7 Documentation MCP Server v${SERVER_VERSION} running on stdio`);\n  }\n}\n\nmain().catch((error) => {\n  console.error(\"Fatal error in main():\", error);\n  process.exit(1);\n});\n"
  },
  {
    "path": "packages/mcp/src/lib/api.ts",
    "content": "import { SearchResponse, ContextRequest, ContextResponse } from \"./types.js\";\nimport { ClientContext, generateHeaders } from \"./encryption.js\";\nimport { Agent, ProxyAgent, setGlobalDispatcher } from \"undici\";\nimport { CONTEXT7_API_BASE_URL } from \"./constants.js\";\nimport { readFileSync } from \"fs\";\n\n/**\n * Parses error response from the Context7 API\n * Extracts the server's error message, falling back to status-based messages if parsing fails\n * @param response The fetch Response object\n * @param apiKey Optional API key (used for fallback messages)\n * @returns Error message string\n */\nasync function parseErrorResponse(response: Response, apiKey?: string): Promise<string> {\n  try {\n    const json = (await response.json()) as { message?: string };\n    if (json.message) {\n      return json.message;\n    }\n  } catch {\n    // JSON parsing failed, fall through to default\n  }\n\n  const status = response.status;\n  if (status === 429) {\n    return apiKey\n      ? \"Rate limited or quota exceeded. Upgrade your plan at https://context7.com/plans for higher limits.\"\n      : \"Rate limited or quota exceeded. Create a free API key at https://context7.com/dashboard for higher limits.\";\n  }\n  if (status === 404) {\n    return \"The library you are trying to access does not exist. Please try with a different library ID.\";\n  }\n  if (status === 401) {\n    return \"Invalid API key. Please check your API key. API keys should start with 'ctx7sk' prefix.\";\n  }\n  return `Request failed with status ${status}. Please try again later.`;\n}\n\nconst PROXY_URL: string | null =\n  process.env.HTTPS_PROXY ??\n  process.env.https_proxy ??\n  process.env.HTTP_PROXY ??\n  process.env.http_proxy ??\n  null;\n\nconst CUSTOM_CA_CERTS: string | undefined = process.env.NODE_EXTRA_CA_CERTS;\n\nfunction loadCustomCACerts(): Buffer | undefined {\n  if (!CUSTOM_CA_CERTS) return undefined;\n  try {\n    return readFileSync(CUSTOM_CA_CERTS);\n  } catch (error) {\n    console.error(\n      `[Context7] Failed to load custom CA certificates from ${CUSTOM_CA_CERTS}:`,\n      error\n    );\n    return undefined;\n  }\n}\n\nif (PROXY_URL && !PROXY_URL.startsWith(\"$\") && /^(http|https):\\/\\//i.test(PROXY_URL)) {\n  try {\n    const ca = loadCustomCACerts();\n    setGlobalDispatcher(new ProxyAgent({ uri: PROXY_URL, ...(ca ? { connect: { ca } } : {}) }));\n  } catch (error) {\n    console.error(\n      `[Context7] Failed to configure proxy agent for provided proxy URL: ${PROXY_URL}:`,\n      error\n    );\n  }\n} else if (CUSTOM_CA_CERTS) {\n  const ca = loadCustomCACerts();\n  if (ca) {\n    try {\n      setGlobalDispatcher(new Agent({ connect: { ca } }));\n    } catch (error) {\n      console.error(`[Context7] Failed to configure custom CA certificates:`, error);\n    }\n  }\n}\n\n/**\n * Searches for libraries matching the given query\n * @param query The user's question or task (used for LLM relevance ranking)\n * @param libraryName The library name to search for in the database\n * @param context Client context including IP, API key, and client info\n * @returns Search results or error\n */\nexport async function searchLibraries(\n  query: string,\n  libraryName: string,\n  context: ClientContext = {}\n): Promise<SearchResponse> {\n  try {\n    const url = new URL(`${CONTEXT7_API_BASE_URL}/v2/libs/search`);\n    url.searchParams.set(\"query\", query);\n    url.searchParams.set(\"libraryName\", libraryName);\n\n    const headers = generateHeaders(context);\n\n    const response = await fetch(url, { headers });\n    if (!response.ok) {\n      const errorMessage = await parseErrorResponse(response, context.apiKey);\n      console.error(errorMessage);\n      return { results: [], error: errorMessage };\n    }\n    const searchData = await response.json();\n    return searchData as SearchResponse;\n  } catch (error) {\n    const errorMessage = `Error searching libraries: ${error}`;\n    console.error(errorMessage);\n    return { results: [], error: errorMessage };\n  }\n}\n\n/**\n * Fetches intelligent, reranked context for a natural language query\n * @param request The context request parameters (query, libraryId)\n * @param context Client context including IP, API key, and client info\n * @returns Context response with data\n */\nexport async function fetchLibraryContext(\n  request: ContextRequest,\n  context: ClientContext = {}\n): Promise<ContextResponse> {\n  try {\n    const url = new URL(`${CONTEXT7_API_BASE_URL}/v2/context`);\n    url.searchParams.set(\"query\", request.query);\n    url.searchParams.set(\"libraryId\", request.libraryId);\n\n    const headers = generateHeaders(context);\n\n    const response = await fetch(url, { headers });\n    if (!response.ok) {\n      const errorMessage = await parseErrorResponse(response, context.apiKey);\n      console.error(errorMessage);\n      return { data: errorMessage };\n    }\n\n    const text = await response.text();\n    if (!text) {\n      return {\n        data: \"Documentation not found or not finalized for this library. This might have happened because you used an invalid Context7-compatible library ID. To get a valid Context7-compatible library ID, use the 'resolve-library-id' with the package name you wish to retrieve documentation for.\",\n      };\n    }\n    return { data: text };\n  } catch (error) {\n    const errorMessage = `Error fetching library context. Please try again later. ${error}`;\n    console.error(errorMessage);\n    return { data: errorMessage };\n  }\n}\n"
  },
  {
    "path": "packages/mcp/src/lib/constants.ts",
    "content": "import { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"../../package.json\"), \"utf-8\"));\n\nexport const SERVER_VERSION: string = pkg.version;\n\nconst CONTEXT7_BASE_URL = \"https://context7.com\";\nconst MCP_RESOURCE_URL = \"https://mcp.context7.com\";\n\nexport const CLERK_DOMAIN = \"clerk.context7.com\";\nexport const CONTEXT7_API_BASE_URL = process.env.CONTEXT7_API_URL || `${CONTEXT7_BASE_URL}/api`;\nexport const RESOURCE_URL = process.env.RESOURCE_URL || MCP_RESOURCE_URL;\nexport const AUTH_SERVER_URL = process.env.AUTH_SERVER_URL || CONTEXT7_BASE_URL;\n"
  },
  {
    "path": "packages/mcp/src/lib/encryption.ts",
    "content": "import { createCipheriv, randomBytes } from \"crypto\";\nimport { SERVER_VERSION } from \"./constants.js\";\n\nconst DEFAULT_ENCRYPTION_KEY = \"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\";\nconst ENCRYPTION_KEY = process.env.CLIENT_IP_ENCRYPTION_KEY || DEFAULT_ENCRYPTION_KEY;\nconst ALGORITHM = \"aes-256-cbc\";\n\nfunction validateEncryptionKey(key: string): boolean {\n  // Must be exactly 64 hex characters (32 bytes)\n  return /^[0-9a-fA-F]{64}$/.test(key);\n}\n\nfunction encryptClientIp(clientIp: string): string {\n  if (!validateEncryptionKey(ENCRYPTION_KEY)) {\n    console.error(\"Invalid encryption key format. Must be 64 hex characters.\");\n    return clientIp; // Fallback to unencrypted\n  }\n\n  try {\n    const iv = randomBytes(16);\n    const cipher = createCipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY, \"hex\"), iv);\n    let encrypted = cipher.update(clientIp, \"utf8\", \"hex\");\n    encrypted += cipher.final(\"hex\");\n    return iv.toString(\"hex\") + \":\" + encrypted;\n  } catch (error) {\n    console.error(\"Error encrypting client IP:\", error);\n    return clientIp; // Fallback to unencrypted\n  }\n}\n\nexport interface ClientContext {\n  clientIp?: string;\n  apiKey?: string;\n  clientInfo?: {\n    ide?: string;\n    version?: string;\n  };\n  transport?: \"stdio\" | \"http\";\n}\n\n/**\n * Generate headers for Context7 API requests.\n * Handles client IP encryption, authentication, and telemetry headers.\n */\nexport function generateHeaders(context: ClientContext): Record<string, string> {\n  const headers: Record<string, string> = {\n    \"X-Context7-Source\": \"mcp-server\",\n    \"X-Context7-Server-Version\": SERVER_VERSION,\n  };\n\n  if (context.clientIp) {\n    headers[\"mcp-client-ip\"] = encryptClientIp(context.clientIp);\n  }\n  if (context.apiKey) {\n    headers[\"Authorization\"] = `Bearer ${context.apiKey}`;\n  }\n  if (context.clientInfo?.ide) {\n    headers[\"X-Context7-Client-IDE\"] = context.clientInfo.ide;\n  }\n  if (context.clientInfo?.version) {\n    headers[\"X-Context7-Client-Version\"] = context.clientInfo.version;\n  }\n  if (context.transport) {\n    headers[\"X-Context7-Transport\"] = context.transport;\n  }\n\n  return headers;\n}\n"
  },
  {
    "path": "packages/mcp/src/lib/jwt.ts",
    "content": "import * as jose from \"jose\";\nimport { CLERK_DOMAIN } from \"./constants.js\";\n\nconst JWKS_URL = `https://${CLERK_DOMAIN}/.well-known/jwks.json`;\nconst ISSUER = `https://${CLERK_DOMAIN}`;\n\nconst jwks = jose.createRemoteJWKSet(new URL(JWKS_URL));\n\nexport interface JWTValidationResult {\n  valid: boolean;\n  error?: string;\n}\n\nexport function isJWT(token: string): boolean {\n  const parts = token.split(\".\");\n  return parts.length === 3;\n}\n\nexport async function validateJWT(token: string): Promise<JWTValidationResult> {\n  try {\n    await jose.jwtVerify(token, jwks, {\n      issuer: ISSUER,\n    });\n\n    return { valid: true };\n  } catch (error) {\n    if (error instanceof jose.errors.JWTExpired) {\n      return { valid: false, error: \"Token expired\" };\n    }\n    if (error instanceof jose.errors.JWTClaimValidationFailed) {\n      return { valid: false, error: \"Invalid token claims\" };\n    }\n    if (error instanceof jose.errors.JWSSignatureVerificationFailed) {\n      return { valid: false, error: \"Invalid signature\" };\n    }\n    return { valid: false, error: \"Invalid token\" };\n  }\n}\n"
  },
  {
    "path": "packages/mcp/src/lib/types.ts",
    "content": "export interface SearchResult {\n  id: string;\n  title: string;\n  description: string;\n  branch: string;\n  lastUpdateDate: string;\n  state: DocumentState;\n  totalTokens: number;\n  totalSnippets: number;\n  stars?: number;\n  trustScore?: number;\n  benchmarkScore?: number;\n  versions?: string[];\n  source?: string;\n}\n\nexport interface SearchResponse {\n  error?: string;\n  results: SearchResult[];\n  searchFilterApplied?: boolean;\n}\n\n// Version state is still needed for validating search results\nexport type DocumentState = \"initial\" | \"finalized\" | \"error\" | \"delete\";\n\nexport type ContextRequest = {\n  query: string;\n  libraryId: string;\n};\n\nexport type ContextResponse = {\n  data: string;\n};\n"
  },
  {
    "path": "packages/mcp/src/lib/utils.ts",
    "content": "import { SearchResponse, SearchResult } from \"./types.js\";\n\n/**\n * Maps numeric source reputation score to an interpretable label for LLM consumption.\n *\n * @returns One of: \"High\", \"Medium\", \"Low\", or \"Unknown\"\n */\nfunction getSourceReputationLabel(\n  sourceReputation?: number\n): \"High\" | \"Medium\" | \"Low\" | \"Unknown\" {\n  if (sourceReputation === undefined || sourceReputation < 0) return \"Unknown\";\n  if (sourceReputation >= 7) return \"High\";\n  if (sourceReputation >= 4) return \"Medium\";\n  return \"Low\";\n}\n\n/**\n * Formats a search result into a human-readable string representation.\n * Only shows code snippet count and GitHub stars when available (not equal to -1).\n *\n * @param result The SearchResult object to format\n * @returns A formatted string with library information\n */\nexport function formatSearchResult(result: SearchResult): string {\n  // Always include these basic details\n  const formattedResult = [\n    `- Title: ${result.title}`,\n    `- Context7-compatible library ID: ${result.id}`,\n    `- Description: ${result.description}`,\n  ];\n\n  // Only add code snippets count if it's a valid value\n  if (result.totalSnippets !== -1 && result.totalSnippets !== undefined) {\n    formattedResult.push(`- Code Snippets: ${result.totalSnippets}`);\n  }\n\n  // Always add categorized source reputation\n  const reputationLabel = getSourceReputationLabel(result.trustScore);\n  formattedResult.push(`- Source Reputation: ${reputationLabel}`);\n\n  // Only add benchmark score if it's a valid value\n  if (result.benchmarkScore !== undefined && result.benchmarkScore > 0) {\n    formattedResult.push(`- Benchmark Score: ${result.benchmarkScore}`);\n  }\n\n  // Only add versions if it's a valid value\n  if (result.versions !== undefined && result.versions.length > 0) {\n    formattedResult.push(`- Versions: ${result.versions.join(\", \")}`);\n  }\n\n  if (result.source) {\n    formattedResult.push(`- Source: ${result.source}`);\n  }\n\n  // Join all parts with newlines\n  return formattedResult.join(\"\\n\");\n}\n\n/**\n * Formats a search response into a human-readable string representation.\n * Each result is formatted using formatSearchResult.\n *\n * @param searchResponse The SearchResponse object to format\n * @returns A formatted string with search results\n */\nexport function formatSearchResults(searchResponse: SearchResponse): string {\n  if (!searchResponse.results || searchResponse.results.length === 0) {\n    return \"No documentation libraries found matching your query.\";\n  }\n\n  const parts: string[] = [];\n\n  if (searchResponse.searchFilterApplied) {\n    parts.push(\n      \"**Note:** Your results only include libraries matching your access settings. To search across all public libraries, update your settings at https://context7.com/dashboard?tab=libraries\"\n    );\n  }\n\n  const formattedResults = searchResponse.results.map(formatSearchResult);\n  parts.push(formattedResults.join(\"\\n----------\\n\"));\n\n  return parts.join(\"\\n\\n\");\n}\n\n/**\n * Extract client info from User-Agent header.\n * Parses formats like \"Cursor/2.2.44 (darwin arm64)\" or \"claude-code/2.0.71\"\n */\nexport function extractClientInfoFromUserAgent(\n  userAgent: string | undefined\n): { ide?: string; version?: string } | undefined {\n  if (!userAgent) return undefined;\n  const match = userAgent.match(/^([^\\/\\s]+)\\/([^\\s(]+)/);\n  if (match) {\n    return { ide: match[1], version: match[2] };\n  }\n  return undefined;\n}\n"
  },
  {
    "path": "packages/mcp/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"resolveJsonModule\": true,\n    \"outDir\": \"./dist\",\n    \"rootDir\": \"./src\"\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "packages/sdk/CHANGELOG.md",
    "content": "# @upstash/context7-sdk\n\n## 0.3.0\n\n### Minor Changes\n\n- 9412e62: feat: Change SDK default response type from \"txt\" to \"json\" for both searchLibrary and getContext methods. AI SDK tools now explicitly use type: \"txt\" for LLM-friendly text responses.\n\n## 0.2.0\n\n### Minor Changes\n\n- b3cd38a: feat: Simplify SDK API\n  - Replace `getDocs()` with `getContext(query, libraryId, options)` - now takes a query parameter for relevance-based retrieval\n  - Update `searchLibrary(query, libraryName)` to take both query and libraryName parameters\n  - Replace response types: `Library` and `Documentation` instead of `SearchResult`, `CodeDocsResponse`, `InfoDocsResponse`, etc.\n  - Remove pagination, mode, topic, and limit options from context retrieval\n  - Simplify `GetContextOptions` to only include `type: \"json\" | \"txt\"`\n\n## 0.1.0\n\n### Minor Changes\n\n- 5e11d35: Initial release of the Context7 TypeScript SDK\n  - HTTP/REST client for the Context7 API\n  - `searchLibrary()` - Search for libraries in the Context7 database\n  - `getDocs()` - Retrieve documentation with filtering options\n  - Environment variable support for API key configuration\n"
  },
  {
    "path": "packages/sdk/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2021 Upstash, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "packages/sdk/README.md",
    "content": "# Upstash Context7 SDK\n\n> ⚠️ **Work in Progress**: This SDK is currently under active development. The API is subject to change and may introduce breaking changes in future releases.\n\n`@upstash/context7-sdk` is an HTTP/REST based client for TypeScript, built on top of the [Context7 API](https://context7.com).\n\n## Why Context7?\n\nLLMs rely on outdated or generic training data about the libraries you use. This leads to:\n\n- Code examples based on year-old training data\n- Hallucinated APIs that don't exist\n- Generic answers for old package versions\n\nContext7 solves this by providing up-to-date, version-specific documentation and code examples directly from the source. Use this SDK to:\n\n- Build AI agents with accurate, current documentation context\n- Create RAG pipelines with reliable library documentation\n- Power code generation tools with real API references\n\n## Quick Start\n\n### Install\n\n```bash\nnpm install @upstash/context7-sdk\n```\n\n### Get API Key\n\nGet your API key from [Context7](https://context7.com)\n\n## Basic Usage\n\n```ts\nimport { Context7 } from \"@upstash/context7-sdk\";\n\nconst client = new Context7({\n  apiKey: \"<CONTEXT7_API_KEY>\",\n});\n\n// Search for libraries\nconst libraries = await client.searchLibrary(\n  \"I need to build a UI with components\",\n  \"react\"\n);\nconsole.log(libraries[0].id); // \"/facebook/react\"\n\n// Get documentation as JSON array (default)\nconst docs = await client.getContext(\"How do I use hooks?\", \"/facebook/react\");\nconsole.log(docs[0].title, docs[0].content);\n\n// Get documentation context as plain text\nconst context = await client.getContext(\n  \"How do I use hooks?\",\n  \"/facebook/react\",\n  { type: \"txt\" }\n);\nconsole.log(context);\n```\n\n## Configuration\n\n### Environment Variables\n\nYou can set your API key via environment variable:\n\n```sh\nCONTEXT7_API_KEY=ctx7sk-...\n```\n\nThen initialize without options:\n\n```ts\nconst client = new Context7();\n```\n\n## Docs\n\nSee the [documentation](https://context7.com/docs/sdks/ts/getting-started) for details.\n\n## Contributing\n\n### Running tests\n\n```sh\npnpm test\n```\n\n### Building\n\n```sh\npnpm build\n```\n"
  },
  {
    "path": "packages/sdk/eslint.config.js",
    "content": "import { defineConfig } from \"eslint/config\";\nimport tseslint from \"typescript-eslint\";\nimport eslintPluginPrettier from \"eslint-plugin-prettier\";\n\nexport default defineConfig(\n  {\n    // Base ESLint configuration\n    ignores: [\"node_modules/**\", \"build/**\", \"dist/**\", \".git/**\", \".github/**\"],\n  },\n  {\n    files: [\"**/*.ts\", \"**/*.tsx\"],\n    languageOptions: {\n      ecmaVersion: 2020,\n      sourceType: \"module\",\n      parser: tseslint.parser,\n      parserOptions: {\n        project: \"./tsconfig.json\",\n        tsconfigRootDir: import.meta.dirname,\n      },\n      globals: {\n        // Add Node.js globals\n        process: \"readonly\",\n        require: \"readonly\",\n        module: \"writable\",\n        console: \"readonly\",\n      },\n    },\n    // Settings for all files\n    linterOptions: {\n      reportUnusedDisableDirectives: true,\n    },\n    plugins: {\n      \"@typescript-eslint\": tseslint.plugin,\n      prettier: eslintPluginPrettier,\n    },\n    rules: {\n      // TypeScript recommended rules\n      ...tseslint.configs.recommended.rules,\n      // TypeScript rules\n      \"@typescript-eslint/explicit-module-boundary-types\": \"off\",\n      \"@typescript-eslint/no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\" }],\n      \"@typescript-eslint/no-explicit-any\": \"warn\",\n      // Prettier integration\n      \"prettier/prettier\": \"error\",\n    },\n  }\n);\n"
  },
  {
    "path": "packages/sdk/package.json",
    "content": "{\n  \"name\": \"@upstash/context7-sdk\",\n  \"version\": \"0.3.0\",\n  \"description\": \"JavaScript/TypeScript SDK for Context7\",\n  \"scripts\": {\n    \"build\": \"tsup\",\n    \"test\": \"vitest run\",\n    \"test:watch\": \"vitest\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"dev\": \"tsup --watch\",\n    \"clean\": \"rm -rf dist\",\n    \"lint\": \"eslint .\",\n    \"lint:check\": \"eslint .\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/upstash/context7.git\",\n    \"directory\": \"packages/sdk\"\n  },\n  \"keywords\": [\n    \"context7\",\n    \"sdk\",\n    \"documentation\",\n    \"ai\",\n    \"upstash\"\n  ],\n  \"author\": \"Upstash\",\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/client.js\",\n      \"require\": \"./dist/client.cjs\"\n    }\n  },\n  \"main\": \"./dist/client.cjs\",\n  \"module\": \"./dist/client.js\",\n  \"types\": \"./dist/client.d.ts\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/upstash/context7/issues\"\n  },\n  \"homepage\": \"https://github.com/upstash/context7#readme\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^25.0.3\",\n    \"dotenv\": \"^17.2.3\",\n    \"tsup\": \"^8.5.1\",\n    \"typescript\": \"^5.8.2\",\n    \"vitest\": \"^4.0.13\"\n  }\n}\n"
  },
  {
    "path": "packages/sdk/prettier.config.mjs",
    "content": "/**\n * @type {import('prettier').Config}\n */\nconst config = {\n  endOfLine: \"lf\",\n  singleQuote: false,\n  tabWidth: 2,\n  trailingComma: \"es5\",\n  printWidth: 100,\n  arrowParens: \"always\",\n};\n\nexport default config;\n"
  },
  {
    "path": "packages/sdk/src/client.test.ts",
    "content": "import { describe, test, expect } from \"vitest\";\nimport { Context7 } from \"./client\";\nimport { Context7Error } from \"@error\";\n\ndescribe(\"Context7 Client\", () => {\n  const apiKey = process.env.CONTEXT7_API_KEY || process.env.API_KEY!;\n\n  describe(\"constructor\", () => {\n    test(\"should create client with API key\", () => {\n      const client = new Context7({ apiKey });\n      expect(client).toBeDefined();\n    });\n\n    test(\"should create client from environment variables\", () => {\n      const client = new Context7();\n      expect(client).toBeDefined();\n    });\n\n    test(\"should throw error when API key is missing\", () => {\n      const originalEnv = process.env.CONTEXT7_API_KEY;\n      const originalApiKey = process.env.API_KEY;\n\n      delete process.env.CONTEXT7_API_KEY;\n      delete process.env.API_KEY;\n\n      expect(() => new Context7({ apiKey: \"\" })).toThrow(Context7Error);\n      expect(() => new Context7({})).toThrow(Context7Error);\n      expect(() => new Context7()).toThrow(\"API key is required\");\n\n      if (originalEnv) process.env.CONTEXT7_API_KEY = originalEnv;\n      if (originalApiKey) process.env.API_KEY = originalApiKey;\n    });\n\n    test(\"should prefer config API key over environment variable\", () => {\n      const customApiKey = \"ctx7sk-custom-key\";\n      const client = new Context7({ apiKey: customApiKey });\n      expect(client).toBeDefined();\n    });\n  });\n\n  describe(\"searchLibrary\", () => {\n    const client = new Context7({ apiKey });\n\n    test(\"should search for libraries and return array directly\", async () => {\n      const result = await client.searchLibrary(\"I need to build a UI\", \"react\");\n\n      expect(result).toBeDefined();\n      expect(Array.isArray(result)).toBe(true);\n      expect(result.length).toBeGreaterThan(0);\n    });\n\n    test(\"should return Library objects with all fields\", async () => {\n      const result = await client.searchLibrary(\"I want to use TypeScript\", \"typescript\");\n\n      expect(result.length).toBeGreaterThan(0);\n      const library = result[0];\n\n      expect(library).toHaveProperty(\"id\");\n      expect(library).toHaveProperty(\"name\");\n      expect(library).toHaveProperty(\"description\");\n      expect(library).toHaveProperty(\"totalSnippets\");\n      expect(library).toHaveProperty(\"trustScore\");\n      expect(library).toHaveProperty(\"benchmarkScore\");\n    });\n\n    test(\"should search with different queries\", async () => {\n      const queries = [\"vue\", \"express\", \"next\"];\n\n      for (const query of queries) {\n        const result = await client.searchLibrary(`I want to use ${query}`, query);\n        expect(result.length).toBeGreaterThan(0);\n      }\n    }, 15000);\n  });\n\n  describe(\"getContext - JSON format (default)\", () => {\n    const client = new Context7({ apiKey });\n\n    test(\"should get context as Documentation array (default)\", async () => {\n      const result = await client.getContext(\"How to use hooks\", \"/facebook/react\");\n\n      expect(result).toBeDefined();\n      expect(Array.isArray(result)).toBe(true);\n      expect(result.length).toBeGreaterThan(0);\n    });\n\n    test(\"should get context with explicit json type\", async () => {\n      const result = await client.getContext(\"How to use hooks\", \"/facebook/react\", {\n        type: \"json\",\n      });\n\n      expect(result).toBeDefined();\n      expect(Array.isArray(result)).toBe(true);\n      expect(result.length).toBeGreaterThan(0);\n    });\n\n    test(\"should have correct Documentation structure\", async () => {\n      const result = await client.getContext(\"How to use hooks\", \"/facebook/react\", {\n        type: \"json\",\n      });\n\n      expect(result.length).toBeGreaterThan(0);\n      const doc = result[0];\n      expect(doc).toHaveProperty(\"title\");\n      expect(doc).toHaveProperty(\"content\");\n      expect(doc).toHaveProperty(\"source\");\n      expect(typeof doc.title).toBe(\"string\");\n      expect(typeof doc.content).toBe(\"string\");\n      expect(typeof doc.source).toBe(\"string\");\n    });\n  });\n\n  describe(\"getContext - text format\", () => {\n    const client = new Context7({ apiKey });\n\n    test(\"should get context as text string with type: txt\", async () => {\n      const result = await client.getContext(\"How to use hooks\", \"/facebook/react\", {\n        type: \"txt\",\n      });\n\n      expect(result).toBeDefined();\n      expect(typeof result).toBe(\"string\");\n      expect(result.length).toBeGreaterThan(0);\n    });\n  });\n\n  describe(\"getContext - different libraries\", () => {\n    const client = new Context7({ apiKey });\n\n    test(\"should get context for Vue\", async () => {\n      const result = await client.getContext(\"How to create components\", \"/vuejs/core\");\n\n      expect(result).toBeDefined();\n      expect(Array.isArray(result)).toBe(true);\n      expect(result.length).toBeGreaterThan(0);\n    });\n\n    test(\"should get context for Express\", async () => {\n      const result = await client.getContext(\"How to create routes\", \"/expressjs/express\");\n\n      expect(result).toBeDefined();\n      expect(Array.isArray(result)).toBe(true);\n      expect(result.length).toBeGreaterThan(0);\n    });\n  });\n\n  describe(\"error handling\", () => {\n    const client = new Context7({ apiKey });\n\n    test(\"should handle invalid library ID gracefully\", async () => {\n      await expect(client.getContext(\"test query\", \"/nonexistent/library\")).rejects.toThrow();\n    });\n\n    test(\"should handle invalid search query\", async () => {\n      await expect(client.searchLibrary(\"\", \"\")).rejects.toThrow(Context7Error);\n    });\n  });\n\n  describe(\"type inference\", () => {\n    const client = new Context7({ apiKey });\n\n    test(\"should infer Documentation[] for default (json) format\", async () => {\n      const result = await client.getContext(\"How to use hooks\", \"/facebook/react\");\n\n      expect(Array.isArray(result)).toBe(true);\n      expect(result[0]).toHaveProperty(\"title\");\n      expect(result[0]).toHaveProperty(\"content\");\n      expect(result[0]).toHaveProperty(\"source\");\n    });\n\n    test(\"should infer string type for txt format\", async () => {\n      const result = await client.getContext(\"How to use hooks\", \"/facebook/react\", {\n        type: \"txt\",\n      });\n\n      expect(typeof result).toBe(\"string\");\n    });\n  });\n});\n"
  },
  {
    "path": "packages/sdk/src/client.ts",
    "content": "import type {\n  Context7Config,\n  GetContextOptions,\n  SearchLibraryOptions,\n  Library,\n  Documentation,\n} from \"@commands/types\";\nimport { Context7Error } from \"@error\";\nimport { HttpClient } from \"@http\";\nimport { SearchLibraryCommand, GetContextCommand } from \"@commands/index\";\n\nconst DEFAULT_BASE_URL = \"https://context7.com/api\";\nconst API_KEY_PREFIX = \"ctx7sk\";\n\nexport type * from \"@commands/types\";\nexport * from \"@error\";\n\nexport class Context7 {\n  private httpClient: HttpClient;\n\n  constructor(config: Context7Config = {}) {\n    const apiKey = config.apiKey || process.env.CONTEXT7_API_KEY;\n\n    if (!apiKey) {\n      throw new Context7Error(\n        \"API key is required. Pass it in the config or set CONTEXT7_API_KEY environment variable.\"\n      );\n    }\n\n    if (!apiKey.startsWith(API_KEY_PREFIX)) {\n      console.warn(`API key should start with '${API_KEY_PREFIX}'`);\n    }\n\n    this.httpClient = new HttpClient({\n      baseUrl: DEFAULT_BASE_URL,\n      headers: {\n        Authorization: `Bearer ${apiKey}`,\n      },\n      retry: {\n        retries: 5,\n        backoff: (retryCount) => Math.exp(retryCount) * 50,\n      },\n      cache: \"no-store\",\n    });\n  }\n\n  /**\n   * Search for libraries matching the given query as JSON (array of Library objects)\n   */\n  async searchLibrary(\n    query: string,\n    libraryName: string,\n    options: SearchLibraryOptions & { type: \"json\" }\n  ): Promise<Library[]>;\n\n  /**\n   * Search for libraries matching the given query as plain text\n   */\n  async searchLibrary(\n    query: string,\n    libraryName: string,\n    options: SearchLibraryOptions & { type: \"txt\" }\n  ): Promise<string>;\n\n  /**\n   * Search for libraries matching the given query (defaults to JSON)\n   */\n  async searchLibrary(\n    query: string,\n    libraryName: string,\n    options?: SearchLibraryOptions\n  ): Promise<Library[]>;\n\n  /**\n   * Search for libraries matching the given query\n   * @param query The user's question or task (used for relevance ranking)\n   * @param libraryName The library name to search for\n   * @param options Response format options\n   * @returns Array of matching libraries (json) or formatted text (txt)\n   */\n  async searchLibrary(\n    query: string,\n    libraryName: string,\n    options?: SearchLibraryOptions\n  ): Promise<Library[] | string> {\n    const command = new SearchLibraryCommand(query, libraryName, options);\n    return await command.exec(this.httpClient);\n  }\n\n  /**\n   * Get documentation context for a library as JSON (array of documentation snippets)\n   */\n  async getContext(\n    query: string,\n    libraryId: string,\n    options: GetContextOptions & { type: \"json\" }\n  ): Promise<Documentation[]>;\n\n  /**\n   * Get documentation context for a library as plain text\n   */\n  async getContext(\n    query: string,\n    libraryId: string,\n    options: GetContextOptions & { type: \"txt\" }\n  ): Promise<string>;\n\n  /**\n   * Get documentation context for a library (defaults to JSON)\n   */\n  async getContext(\n    query: string,\n    libraryId: string,\n    options?: GetContextOptions\n  ): Promise<Documentation[]>;\n\n  /**\n   * Get documentation context for a library\n   * @param query The user's question or task\n   * @param libraryId Context7 library ID (e.g., \"/facebook/react\")\n   * @param options Response format options\n   * @returns Documentation as Documentation[] (json, default) or string (txt)\n   */\n  async getContext(\n    query: string,\n    libraryId: string,\n    options?: GetContextOptions\n  ): Promise<Documentation[] | string> {\n    const command = new GetContextCommand(query, libraryId, options);\n    return await command.exec(this.httpClient);\n  }\n}\n"
  },
  {
    "path": "packages/sdk/src/commands/command.ts",
    "content": "import type { Requester } from \"@http\";\n\nexport const _ENDPOINTS = [\"v2/libs/search\", \"v2/context\"];\n\nexport type EndpointVariants = (typeof _ENDPOINTS)[number];\n\nexport interface CommandRequest {\n  method?: \"GET\" | \"POST\";\n  body?: unknown;\n  query?: Record<string, string | number | boolean | undefined>;\n}\n\nexport class Command<TResult> {\n  public readonly request: CommandRequest;\n  public readonly endpoint: EndpointVariants;\n\n  constructor(request: CommandRequest, endpoint: EndpointVariants | string) {\n    this.request = request;\n    this.endpoint = endpoint;\n  }\n\n  /**\n   * Execute the command using a client.\n   */\n  public async exec(client: Requester): Promise<TResult> {\n    const { result } = await client.request<TResult>({\n      method: this.request.method || \"POST\",\n      path: [this.endpoint],\n      query: this.request.query,\n      body: this.request.body,\n    });\n\n    if (result === undefined) {\n      throw new TypeError(\"Request did not return a result\");\n    }\n\n    return result;\n  }\n}\n"
  },
  {
    "path": "packages/sdk/src/commands/get-context/index.test.ts",
    "content": "import { describe, test, expect } from \"vitest\";\nimport { GetContextCommand } from \"./index\";\nimport { newHttpClient } from \"../../utils/test-utils\";\nimport { Context7 } from \"../../client\";\nimport type { Documentation } from \"@commands/types\";\n\nconst httpClient = newHttpClient();\n\ndescribe(\"GetContextCommand\", () => {\n  test(\"should get library context as JSON (default)\", async () => {\n    const command = new GetContextCommand(\"How to use hooks\", \"/facebook/react\");\n    const result = await command.exec(httpClient);\n\n    expect(result).toBeDefined();\n    expect(Array.isArray(result)).toBe(true);\n\n    const docs = result as Documentation[];\n    expect(docs.length).toBeGreaterThan(0);\n\n    const doc = docs[0];\n    expect(doc).toHaveProperty(\"title\");\n    expect(doc).toHaveProperty(\"content\");\n    expect(doc).toHaveProperty(\"source\");\n  });\n\n  test(\"should get library context as text with type: txt\", async () => {\n    const command = new GetContextCommand(\"How to use hooks\", \"/facebook/react\", {\n      type: \"txt\",\n    });\n    const result = await command.exec(httpClient);\n\n    expect(result).toBeDefined();\n    expect(typeof result).toBe(\"string\");\n    expect((result as string).length).toBeGreaterThan(0);\n  });\n\n  test(\"should get library context as JSON using client (default)\", async () => {\n    const client = new Context7({\n      apiKey: process.env.CONTEXT7_API_KEY || process.env.API_KEY!,\n    });\n\n    const result = await client.getContext(\"How to use hooks\", \"/facebook/react\");\n\n    expect(result).toBeDefined();\n    expect(Array.isArray(result)).toBe(true);\n    expect(result.length).toBeGreaterThan(0);\n\n    const doc = result[0];\n    expect(doc).toHaveProperty(\"title\");\n    expect(doc).toHaveProperty(\"content\");\n    expect(doc).toHaveProperty(\"source\");\n  });\n\n  test(\"should get library context as text using client with type: txt\", async () => {\n    const client = new Context7({\n      apiKey: process.env.CONTEXT7_API_KEY || process.env.API_KEY!,\n    });\n\n    const result = await client.getContext(\"How to use hooks\", \"/facebook/react\", {\n      type: \"txt\",\n    });\n\n    expect(result).toBeDefined();\n    expect(typeof result).toBe(\"string\");\n    expect(result.length).toBeGreaterThan(0);\n  });\n});\n"
  },
  {
    "path": "packages/sdk/src/commands/get-context/index.ts",
    "content": "import { Command } from \"@commands/command\";\nimport type { GetContextOptions, Documentation } from \"@commands/types\";\nimport type { ApiContextJsonResponse } from \"./types\";\nimport type { Requester } from \"@http\";\nimport { Context7Error } from \"@error\";\nimport { formatCodeSnippet, formatInfoSnippet } from \"@utils/format\";\n\nconst DEFAULT_TYPE = \"json\";\n\nexport class GetContextCommand extends Command<Documentation[] | string> {\n  private readonly responseType: \"json\" | \"txt\";\n\n  constructor(query: string, libraryId: string, options?: GetContextOptions) {\n    const queryParams: Record<string, string | number | undefined> = {};\n\n    queryParams.query = query;\n    queryParams.libraryId = libraryId;\n\n    const responseType = options?.type ?? DEFAULT_TYPE;\n    queryParams.type = responseType;\n\n    super({ method: \"GET\", query: queryParams }, \"v2/context\");\n\n    this.responseType = responseType;\n  }\n\n  public override async exec(client: Requester): Promise<Documentation[] | string> {\n    const { result } = await client.request<string | ApiContextJsonResponse>({\n      method: this.request.method || \"GET\",\n      path: [this.endpoint],\n      query: this.request.query,\n      body: this.request.body,\n    });\n\n    if (result === undefined) {\n      throw new Context7Error(\"Request did not return a result\");\n    }\n\n    if (this.responseType === \"txt\" && typeof result === \"string\") {\n      return result;\n    }\n\n    const apiResult = result as ApiContextJsonResponse;\n    const codeDocs = apiResult.codeSnippets.map(formatCodeSnippet);\n    const infoDocs = apiResult.infoSnippets.map(formatInfoSnippet);\n\n    return [...codeDocs, ...infoDocs];\n  }\n}\n"
  },
  {
    "path": "packages/sdk/src/commands/get-context/types.ts",
    "content": "export interface ApiCodeSnippet {\n  codeTitle: string;\n  codeDescription: string;\n  codeLanguage: string;\n  codeList: { language: string; code: string }[];\n  codeId: string;\n  codeTokens?: number;\n  pageTitle?: string;\n}\n\nexport interface ApiInfoSnippet {\n  content: string;\n  breadcrumb?: string;\n  pageId: string;\n  contentTokens?: number;\n}\n\nexport interface ApiContextJsonResponse {\n  codeSnippets: ApiCodeSnippet[];\n  infoSnippets: ApiInfoSnippet[];\n}\n"
  },
  {
    "path": "packages/sdk/src/commands/index.ts",
    "content": "export * from \"./get-context\";\nexport * from \"./search-library\";\n"
  },
  {
    "path": "packages/sdk/src/commands/search-library/index.test.ts",
    "content": "import { describe, test, expect } from \"vitest\";\nimport { SearchLibraryCommand } from \"./index\";\nimport { newHttpClient } from \"../../utils/test-utils\";\nimport { Context7 } from \"../../client\";\n\nconst httpClient = newHttpClient();\n\ndescribe(\"SearchLibraryCommand\", () => {\n  test(\"should search for a library\", async () => {\n    const command = new SearchLibraryCommand(\"I need to build a UI\", \"react\");\n    const result = await command.exec(httpClient);\n\n    expect(result).toBeDefined();\n    expect(Array.isArray(result)).toBe(true);\n    expect(result.length).toBeGreaterThan(0);\n\n    const library = result[0];\n    expect(library).toHaveProperty(\"id\");\n    expect(library).toHaveProperty(\"name\");\n    expect(library).toHaveProperty(\"description\");\n    expect(library).toHaveProperty(\"totalSnippets\");\n    expect(library).toHaveProperty(\"trustScore\");\n    expect(library).toHaveProperty(\"benchmarkScore\");\n  });\n\n  test(\"should search for a library using client\", async () => {\n    const client = new Context7({\n      apiKey: process.env.CONTEXT7_API_KEY || process.env.API_KEY!,\n    });\n\n    const result = await client.searchLibrary(\"I need to build a UI\", \"react\");\n\n    expect(result).toBeDefined();\n    expect(Array.isArray(result)).toBe(true);\n    expect(result.length).toBeGreaterThan(0);\n\n    const library = result[0];\n    expect(library).toHaveProperty(\"id\");\n    expect(library).toHaveProperty(\"name\");\n    expect(library).toHaveProperty(\"description\");\n    expect(library).toHaveProperty(\"totalSnippets\");\n    expect(library).toHaveProperty(\"trustScore\");\n    expect(library).toHaveProperty(\"benchmarkScore\");\n  });\n});\n"
  },
  {
    "path": "packages/sdk/src/commands/search-library/index.ts",
    "content": "import { Command } from \"@commands/command\";\nimport type { Library, SearchLibraryOptions } from \"@commands/types\";\nimport type { ApiSearchResponse } from \"./types\";\nimport type { Requester } from \"@http\";\nimport { Context7Error } from \"@error\";\nimport { formatLibrary, formatLibrariesAsText } from \"@utils/format\";\n\nconst DEFAULT_TYPE = \"json\";\n\nexport class SearchLibraryCommand extends Command<Library[] | string> {\n  private readonly responseType: \"json\" | \"txt\";\n\n  constructor(query: string, libraryName: string, options?: SearchLibraryOptions) {\n    if (!query || !libraryName) {\n      throw new Context7Error(\"query and libraryName are required\");\n    }\n\n    const queryParams: Record<string, string | number | undefined> = {};\n\n    queryParams.query = query;\n    queryParams.libraryName = libraryName;\n\n    super({ method: \"GET\", query: queryParams }, \"v2/libs/search\");\n\n    this.responseType = options?.type ?? DEFAULT_TYPE;\n  }\n\n  public override async exec(client: Requester): Promise<Library[] | string> {\n    const { result } = await client.request<ApiSearchResponse>({\n      method: this.request.method || \"GET\",\n      path: [this.endpoint],\n      query: this.request.query,\n    });\n\n    if (result === undefined) {\n      throw new Context7Error(\"Request did not return a result\");\n    }\n\n    const libraries = result.results.map(formatLibrary);\n\n    if (this.responseType === \"txt\") {\n      return formatLibrariesAsText(libraries);\n    }\n\n    return libraries;\n  }\n}\n"
  },
  {
    "path": "packages/sdk/src/commands/search-library/types.ts",
    "content": "export interface ApiSearchResult {\n  id: string;\n  title: string;\n  description: string;\n  versions?: string[];\n  totalSnippets?: number;\n  trustScore?: number;\n  benchmarkScore?: number;\n}\n\nexport interface ApiSearchResponse {\n  results: ApiSearchResult[];\n}\n"
  },
  {
    "path": "packages/sdk/src/commands/types.ts",
    "content": "export interface Context7Config {\n  apiKey?: string;\n}\n\n/**\n * A library available in Context7\n */\nexport interface Library {\n  /** Context7 library ID (e.g., \"/facebook/react\") */\n  id: string;\n  /** Library display name */\n  name: string;\n  /** Library description */\n  description: string;\n  /** Number of documentation snippets available */\n  totalSnippets: number;\n  /** Source reputation score (0-10) */\n  trustScore: number;\n  /** Quality indicator score (0-100) */\n  benchmarkScore: number;\n  /** Available versions/tags */\n  versions?: string[];\n}\n\n/**\n * A piece of documentation content\n */\nexport interface Documentation {\n  /** Title of the documentation snippet */\n  title: string;\n  /** The documentation content (may include code blocks in markdown format) */\n  content: string;\n  /** Source URL or identifier for the snippet */\n  source: string;\n}\n\nexport interface GetContextOptions {\n  /**\n   * Response format.\n   * - \"json\": Returns Documentation[] array (default)\n   * - \"txt\": Returns formatted text string\n   * @default \"json\"\n   */\n  type?: \"json\" | \"txt\";\n}\n\nexport interface SearchLibraryOptions {\n  /**\n   * Response format.\n   * - \"json\": Returns Library[] array (default)\n   * - \"txt\": Returns formatted text string\n   * @default \"json\"\n   */\n  type?: \"json\" | \"txt\";\n}\n\nexport type QueryParams = Record<string, string | number | boolean | undefined>;\n"
  },
  {
    "path": "packages/sdk/src/error/index.ts",
    "content": "export class Context7Error extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = \"Context7Error\";\n  }\n}\n"
  },
  {
    "path": "packages/sdk/src/http/index.ts",
    "content": "import { Context7Error } from \"@error\";\n\ntype CacheSetting =\n  | \"default\"\n  | \"force-cache\"\n  | \"no-cache\"\n  | \"no-store\"\n  | \"only-if-cached\"\n  | \"reload\"\n  | false;\n\nexport type Context7Request = {\n  path?: string[];\n  /**\n   * Request body will be serialized to json\n   */\n  body?: unknown;\n  /**\n   * HTTP method to use\n   * @default \"POST\"\n   */\n  method?: \"GET\" | \"POST\";\n  /**\n   * Query parameters for GET requests\n   */\n  query?: Record<string, string | number | boolean | undefined>;\n};\nexport type TxtResponseHeaders = {\n  page: number;\n  limit: number;\n  totalPages: number;\n  hasNext: boolean;\n  hasPrev: boolean;\n  totalTokens: number;\n};\n\nexport type Context7Response<TResult> = {\n  result?: TResult;\n  headers?: TxtResponseHeaders;\n};\n\nexport type Requester = {\n  request: <TResult = unknown>(req: Context7Request) => Promise<Context7Response<TResult>>;\n};\n\nexport type RetryConfig =\n  | false\n  | {\n      /**\n       * The number of retries to attempt before giving up.\n       *\n       * @default 5\n       */\n      retries?: number;\n      /**\n       * A backoff function receives the current retry count and returns a number in milliseconds to wait before retrying.\n       *\n       * @default\n       * ```ts\n       * Math.exp(retryCount) * 50\n       * ```\n       */\n      backoff?: (retryCount: number) => number;\n    };\n\nexport type RequesterConfig = {\n  /**\n   * Configure the retry behaviour in case of network errors\n   */\n  retry?: RetryConfig;\n\n  /**\n   * Configure the cache behaviour\n   * @default \"no-store\"\n   */\n  cache?: CacheSetting;\n};\n\nexport type HttpClientConfig = {\n  headers?: Record<string, string>;\n  baseUrl: string;\n  retry?: RetryConfig;\n  signal?: () => AbortSignal;\n} & RequesterConfig;\n\nexport class HttpClient implements Requester {\n  public baseUrl: string;\n  public headers: Record<string, string>;\n  public readonly options: {\n    signal?: HttpClientConfig[\"signal\"];\n    cache?: CacheSetting;\n  };\n\n  public readonly retry: {\n    attempts: number;\n    backoff: (retryCount: number) => number;\n  };\n\n  public constructor(config: HttpClientConfig) {\n    this.options = {\n      cache: config.cache,\n      signal: config.signal,\n    };\n\n    this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n\n    this.headers = {\n      \"Content-Type\": \"application/json\",\n      ...config.headers,\n    };\n\n    this.retry =\n      typeof config?.retry === \"boolean\" && config?.retry === false\n        ? {\n            attempts: 1,\n            backoff: () => 0,\n          }\n        : {\n            attempts: config?.retry?.retries ?? 5,\n            backoff: config?.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50),\n          };\n  }\n\n  public async request<TResult>(req: Context7Request): Promise<Context7Response<TResult>> {\n    const method = req.method || \"POST\";\n\n    let url = [this.baseUrl, ...(req.path ?? [])].join(\"/\");\n    if (method === \"GET\" && req.query) {\n      const queryParams = new URLSearchParams();\n      Object.entries(req.query).forEach(([key, value]) => {\n        if (value !== undefined) {\n          queryParams.append(key, String(value));\n        }\n      });\n      const queryString = queryParams.toString();\n      if (queryString) {\n        url += `?${queryString}`;\n      }\n    }\n\n    const requestOptions = {\n      cache: this.options.cache,\n      method,\n      headers: this.headers,\n      body: req.body ? JSON.stringify(req.body) : undefined,\n      keepalive: true,\n      signal: this.options.signal?.(),\n    };\n\n    let res: Response | null = null;\n    let error: Error | null = null;\n\n    for (let i = 0; i <= this.retry.attempts; i++) {\n      try {\n        res = await fetch(url, requestOptions as RequestInit);\n        break;\n      } catch (error_) {\n        if (requestOptions.signal?.aborted) {\n          throw error_;\n        }\n        error = error_ as Error;\n        if (i < this.retry.attempts) {\n          await new Promise((r) => setTimeout(r, this.retry.backoff(i)));\n        }\n      }\n    }\n    if (!res) {\n      throw error ?? new Error(\"Exhausted all retries\");\n    }\n\n    if (!res.ok) {\n      const errorBody = (await res.json()) as { error?: string; message?: string };\n      throw new Context7Error(errorBody.error || errorBody.message || res.statusText);\n    }\n\n    const contentType = res.headers.get(\"content-type\");\n\n    if (contentType?.includes(\"application/json\")) {\n      const body = await res.json();\n      return { result: body as TResult };\n    } else {\n      const text = await res.text();\n      const headers = this.extractTxtResponseHeaders(res.headers);\n      return { result: text as TResult, headers };\n    }\n  }\n\n  private extractTxtResponseHeaders(headers: Headers): TxtResponseHeaders | undefined {\n    const page = headers.get(\"x-context7-page\");\n    const limit = headers.get(\"x-context7-limit\");\n    const totalPages = headers.get(\"x-context7-total-pages\");\n    const hasNext = headers.get(\"x-context7-has-next\");\n    const hasPrev = headers.get(\"x-context7-has-prev\");\n    const totalTokens = headers.get(\"x-context7-total-tokens\");\n\n    if (!page || !limit || !totalPages || !hasNext || !hasPrev || !totalTokens) {\n      return undefined;\n    }\n\n    return {\n      page: parseInt(page, 10),\n      limit: parseInt(limit, 10),\n      totalPages: parseInt(totalPages, 10),\n      hasNext: hasNext === \"true\",\n      hasPrev: hasPrev === \"true\",\n      totalTokens: parseInt(totalTokens, 10),\n    };\n  }\n}\n"
  },
  {
    "path": "packages/sdk/src/utils/format.ts",
    "content": "import type { Documentation, Library } from \"@commands/types\";\nimport type { ApiCodeSnippet, ApiInfoSnippet } from \"@commands/get-context/types\";\n\nexport function formatCodeSnippet(snippet: ApiCodeSnippet): Documentation {\n  const codeBlocks = snippet.codeList\n    .map((c) => `\\`\\`\\`${c.language}\\n${c.code}\\n\\`\\`\\``)\n    .join(\"\\n\\n\");\n\n  const content = snippet.codeDescription\n    ? `${snippet.codeDescription}\\n\\n${codeBlocks}`\n    : codeBlocks;\n\n  return {\n    title: snippet.codeTitle,\n    content,\n    source: snippet.codeId,\n  };\n}\n\nexport function formatInfoSnippet(snippet: ApiInfoSnippet): Documentation {\n  return {\n    title: snippet.breadcrumb || \"Documentation\",\n    content: snippet.content,\n    source: snippet.pageId,\n  };\n}\n\nexport function formatLibrary(r: {\n  id: string;\n  title: string;\n  description: string;\n  versions?: string[];\n  totalSnippets?: number;\n  trustScore?: number;\n  benchmarkScore?: number;\n}): Library {\n  return {\n    id: r.id,\n    name: r.title,\n    description: r.description,\n    totalSnippets: r.totalSnippets ?? 0,\n    trustScore: r.trustScore ?? 0,\n    benchmarkScore: r.benchmarkScore ?? 0,\n    versions: r.versions,\n  };\n}\n\n/**\n * Maps numeric trust score to an interpretable label.\n */\nfunction getTrustScoreLabel(trustScore?: number): \"High\" | \"Medium\" | \"Low\" | \"Unknown\" {\n  if (trustScore === undefined || trustScore < 0) return \"Unknown\";\n  if (trustScore >= 7) return \"High\";\n  if (trustScore >= 4) return \"Medium\";\n  return \"Low\";\n}\n\n/**\n * Formats a single library as a human-readable text block.\n */\nexport function formatLibraryAsText(library: Library): string {\n  const lines = [\n    `- Title: ${library.name}`,\n    `- Context7-compatible library ID: ${library.id}`,\n    `- Description: ${library.description}`,\n  ];\n\n  if (library.totalSnippets > 0) {\n    lines.push(`- Code Snippets: ${library.totalSnippets}`);\n  }\n\n  lines.push(`- Trust Score: ${getTrustScoreLabel(library.trustScore)}`);\n\n  if (library.benchmarkScore > 0) {\n    lines.push(`- Benchmark Score: ${library.benchmarkScore}`);\n  }\n\n  if (library.versions && library.versions.length > 0) {\n    lines.push(`- Versions: ${library.versions.join(\", \")}`);\n  }\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Formats an array of libraries as human-readable text.\n */\nexport function formatLibrariesAsText(libraries: Library[]): string {\n  if (libraries.length === 0) {\n    return \"No documentation libraries found matching your query.\";\n  }\n\n  return libraries.map(formatLibraryAsText).join(\"\\n----------\\n\");\n}\n"
  },
  {
    "path": "packages/sdk/src/utils/test-utils.ts",
    "content": "import { HttpClient } from \"@http\";\n\nexport function newHttpClient(): HttpClient {\n  const apiKey = process.env.CONTEXT7_API_KEY || process.env.API_KEY;\n\n  if (!apiKey) {\n    throw new Error(\"CONTEXT7_API_KEY or API_KEY environment variable is required for tests\");\n  }\n\n  return new HttpClient({\n    baseUrl: process.env.CONTEXT7_BASE_URL || \"https://context7.com/api\",\n    headers: {\n      Authorization: `Bearer ${apiKey}`,\n    },\n    retry: {\n      retries: 3,\n      backoff: (retryCount) => Math.exp(retryCount) * 50,\n    },\n    cache: \"no-store\",\n  });\n}\n"
  },
  {
    "path": "packages/sdk/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\"ESNext\"],\n    \"module\": \"esnext\",\n    \"target\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"moduleDetection\": \"force\",\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"allowJs\": true,\n    \"paths\": {\n      \"@error\": [\"./src/error/index.ts\"],\n      \"@http\": [\"./src/http/index.ts\"],\n      \"@commands/*\": [\"./src/commands/*\"],\n      \"@utils/*\": [\"./src/utils/*\"]\n    }\n  },\n  \"include\": [\"src/**/*\", \"tsup.config.ts\", \"vitest.config.ts\", \"eslint.config.js\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "packages/sdk/tsup.config.ts",
    "content": "import { defineConfig } from \"tsup\";\n\nexport default defineConfig({\n  entry: [\"./src/client.ts\"],\n  format: [\"cjs\", \"esm\"],\n  clean: true,\n  dts: true,\n});\n"
  },
  {
    "path": "packages/sdk/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\nimport path from \"path\";\nimport dotenv from \"dotenv\";\n\ndotenv.config({ path: path.resolve(__dirname, \"../../.env\") });\n\nexport default defineConfig({\n  test: {\n    globals: true,\n    environment: \"node\",\n    include: [\"src/**/*.test.ts\"],\n    env: process.env,\n  },\n  resolve: {\n    alias: {\n      \"@commands\": path.resolve(__dirname, \"./src/commands\"),\n      \"@http\": path.resolve(__dirname, \"./src/http\"),\n      \"@error\": path.resolve(__dirname, \"./src/error/index.ts\"),\n      \"@utils\": path.resolve(__dirname, \"./src/utils\"),\n    },\n  },\n});\n"
  },
  {
    "path": "packages/tools-ai-sdk/CHANGELOG.md",
    "content": "# @upstash/context7-tools-ai-sdk\n\n## 0.2.2\n\n### Patch Changes\n\n- 02148ff: Bump zod from 3.x to 4.x\n\n## 0.2.1\n\n### Patch Changes\n\n- 07a53dc: Upgrade ai peer dependency to >=6.0.0 for AI SDK v6 compatibility\n\n## 0.2.0\n\n### Minor Changes\n\n- 9412e62: feat: Change SDK default response type from \"txt\" to \"json\" for both searchLibrary and getContext methods. AI SDK tools now explicitly use type: \"txt\" for LLM-friendly text responses.\n\n### Patch Changes\n\n- Updated dependencies [9412e62]\n  - @upstash/context7-sdk@0.3.0\n\n## 0.1.0\n\n### Minor Changes\n\n- b3cd38a: feat: Rename tools to match MCP naming conventions\n  - Rename `resolveLibrary` to `resolveLibraryId` with new `query` parameter\n  - Rename `getLibraryDocs` to `queryDocs` with new `query` parameter (replaces `topic`)\n  - Rename `RESOLVE_LIBRARY_DESCRIPTION` to `RESOLVE_LIBRARY_ID_DESCRIPTION`\n  - Rename `GET_LIBRARY_DOCS_DESCRIPTION` to `QUERY_DOCS_DESCRIPTION`\n  - Update type re-exports to match new SDK types (Library, Documentation, GetContextOptions)\n  - Remove deprecated `defaultMaxResults` option from Context7ToolsConfig and Context7AgentConfig\n  - Add rate limiting guidance to tool descriptions\n\n### Patch Changes\n\n- Updated dependencies [b3cd38a]\n  - @upstash/context7-sdk@0.2.0\n"
  },
  {
    "path": "packages/tools-ai-sdk/README.md",
    "content": "# Upstash Context7 AI SDK\n\n`@upstash/context7-tools-ai-sdk` provides [Vercel AI SDK](https://ai-sdk.dev/) compatible tools and agents that give your AI applications access to up to date library documentation through Context7.\n\nUse this package to:\n\n- Add documentation lookup tools to your AI SDK workflows with `generateText` or `streamText`\n- Create documentation aware agents using the pre-configured `Context7Agent`\n- Build RAG pipelines that retrieve accurate, version specific code examples\n\nThe package provides two main tools:\n\n- `resolveLibrary` - Searches Context7's database to find the correct library ID\n- `getLibraryDocs` - Fetches documentation for a specific library with optional topic filtering\n\n## Quick Start\n\n### Install\n\n```bash\nnpm install @upstash/context7-tools-ai-sdk @upstash/context7-sdk ai zod\n```\n\n### Get API Key\n\nGet your API key from [Context7](https://context7.com)\n\n## Usage\n\n### Using Tools with `generateText`\n\n```typescript\nimport { resolveLibrary, getLibraryDocs } from \"@upstash/context7-tools-ai-sdk\";\nimport { generateText, stepCountIs } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\nconst { text } = await generateText({\n  model: openai(\"gpt-4o\"),\n  prompt: \"How do I use React Server Components?\",\n  tools: {\n    resolveLibrary: resolveLibrary(),\n    getLibraryDocs: getLibraryDocs(),\n  },\n  stopWhen: stepCountIs(5),\n});\n\nconsole.log(text);\n```\n\n### Using the Context7 Agent\n\nThe package provides a pre-configured agent that handles the multi-step workflow automatically:\n\n```typescript\nimport { Context7Agent } from \"@upstash/context7-tools-ai-sdk\";\nimport { anthropic } from \"@ai-sdk/anthropic\";\n\nconst agent = new Context7Agent({\n  model: anthropic(\"claude-sonnet-4-20250514\"),\n});\n\nconst { text } = await agent.generate({\n  prompt: \"How do I set up routing in Next.js?\",\n});\n\nconsole.log(text);\n```\n\n## Configuration\n\n### Environment Variables\n\nSet your API key via environment variable:\n\n```sh\nCONTEXT7_API_KEY=ctx7sk-...\n```\n\nThen use tools and agents without explicit configuration:\n\n```typescript\nconst tool = resolveLibrary(); // Uses CONTEXT7_API_KEY automatically\n```\n\n## Docs\n\nSee the [documentation](https://context7.com/docs/agentic-tools/ai-sdk/getting-started) for details.\n\n## Contributing\n\n### Running tests\n\n```sh\npnpm test\n```\n\n### Building\n\n```sh\npnpm build\n```\n"
  },
  {
    "path": "packages/tools-ai-sdk/eslint.config.js",
    "content": "import { defineConfig } from \"eslint/config\";\nimport tseslint from \"typescript-eslint\";\nimport eslintPluginPrettier from \"eslint-plugin-prettier\";\n\nexport default defineConfig(\n  {\n    // Base ESLint configuration\n    ignores: [\"node_modules/**\", \"build/**\", \"dist/**\", \".git/**\", \".github/**\"],\n  },\n  {\n    files: [\"**/*.ts\", \"**/*.tsx\"],\n    languageOptions: {\n      ecmaVersion: 2020,\n      sourceType: \"module\",\n      parser: tseslint.parser,\n      parserOptions: {\n        project: \"./tsconfig.json\",\n        tsconfigRootDir: import.meta.dirname,\n      },\n      globals: {\n        // Add Node.js globals\n        process: \"readonly\",\n        require: \"readonly\",\n        module: \"writable\",\n        console: \"readonly\",\n      },\n    },\n    // Settings for all files\n    linterOptions: {\n      reportUnusedDisableDirectives: true,\n    },\n    plugins: {\n      \"@typescript-eslint\": tseslint.plugin,\n      prettier: eslintPluginPrettier,\n    },\n    rules: {\n      // TypeScript recommended rules\n      ...tseslint.configs.recommended.rules,\n      // TypeScript rules\n      \"@typescript-eslint/explicit-module-boundary-types\": \"off\",\n      \"@typescript-eslint/no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\" }],\n      \"@typescript-eslint/no-explicit-any\": \"warn\",\n      // Prettier integration\n      \"prettier/prettier\": \"error\",\n    },\n  }\n);\n"
  },
  {
    "path": "packages/tools-ai-sdk/package.json",
    "content": "{\n  \"name\": \"@upstash/context7-tools-ai-sdk\",\n  \"version\": \"0.2.2\",\n  \"description\": \"Context7 tools for Vercel AI SDK\",\n  \"type\": \"module\",\n  \"main\": \"./dist/index.cjs\",\n  \"module\": \"./dist/index.js\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.js\",\n      \"require\": \"./dist/index.cjs\"\n    },\n    \"./agent\": {\n      \"types\": \"./dist/agent.d.ts\",\n      \"import\": \"./dist/agent.js\",\n      \"require\": \"./dist/agent.cjs\"\n    }\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsup\",\n    \"dev\": \"tsup --watch\",\n    \"test\": \"vitest run\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"clean\": \"rm -rf dist\"\n  },\n  \"peerDependencies\": {\n    \"@upstash/context7-sdk\": \">=0.3.0\",\n    \"ai\": \">=6.0.0\",\n    \"zod\": \">=4.0.0\"\n  },\n  \"devDependencies\": {\n    \"@upstash/context7-sdk\": \"workspace:*\",\n    \"ai\": \"^6.0.5\",\n    \"zod\": \"^4.3.4\",\n    \"@ai-sdk/amazon-bedrock\": \"^4.0.9\",\n    \"@types/node\": \"^25.0.3\",\n    \"dotenv\": \"^17.2.3\",\n    \"tsup\": \"^8.5.1\",\n    \"typescript\": \"^5.8.2\",\n    \"vitest\": \"^4.0.13\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/upstash/context7.git\",\n    \"directory\": \"packages/tools-ai-sdk\"\n  },\n  \"keywords\": [\n    \"context7\",\n    \"ai-sdk\",\n    \"vercel\",\n    \"documentation\",\n    \"agent\",\n    \"upstash\"\n  ],\n  \"author\": \"Upstash\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/upstash/context7/issues\"\n  },\n  \"homepage\": \"https://github.com/upstash/context7#readme\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/agents/context7.ts",
    "content": "import { ToolLoopAgent, type ToolLoopAgentSettings, type ToolSet, stepCountIs } from \"ai\";\nimport { resolveLibraryId, queryDocs } from \"@tools\";\nimport { AGENT_PROMPT } from \"@prompts\";\n\n/**\n * Configuration for Context7 agent.\n */\nexport interface Context7AgentConfig extends ToolLoopAgentSettings<never, ToolSet> {\n  /**\n   * Context7 API key. If not provided, uses the CONTEXT7_API_KEY environment variable.\n   */\n  apiKey?: string;\n}\n\n/**\n * Context7 documentation search agent\n *\n * The agent follows a multi-step workflow:\n * 1. Resolves library names to Context7 library IDs\n * 2. Fetches documentation for the resolved library\n * 3. Provides answers with code examples\n *\n * @example\n * ```typescript\n * import { Context7Agent } from '@upstash/context7-tools-ai-sdk';\n * import { anthropic } from '@ai-sdk/anthropic';\n *\n * const agent = new Context7Agent({\n *   model: anthropic('claude-sonnet-4-20250514'),\n *   apiKey: 'your-context7-api-key',\n * });\n *\n * const result = await agent.generate({\n *   prompt: 'How do I use React Server Components?',\n * });\n * ```\n */\nexport class Context7Agent extends ToolLoopAgent<never, ToolSet> {\n  constructor(config: Context7AgentConfig) {\n    const {\n      model,\n      stopWhen = stepCountIs(5),\n      instructions,\n      apiKey,\n\n      tools,\n      ...agentSettings\n    } = config;\n\n    const context7Config = { apiKey };\n\n    super({\n      ...agentSettings,\n      model,\n      instructions: instructions || AGENT_PROMPT,\n      tools: {\n        ...tools,\n        resolveLibraryId: resolveLibraryId(context7Config),\n        queryDocs: queryDocs(context7Config),\n      },\n      stopWhen,\n    });\n  }\n}\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/agents/index.ts",
    "content": "export { Context7Agent, type Context7AgentConfig } from \"./context7\";\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/index.test.ts",
    "content": "import { describe, test, expect } from \"vitest\";\nimport { generateText, stepCountIs, tool } from \"ai\";\nimport { createAmazonBedrock } from \"@ai-sdk/amazon-bedrock\";\nimport { z } from \"zod\";\nimport {\n  resolveLibraryId,\n  queryDocs,\n  Context7Agent,\n  SYSTEM_PROMPT,\n  AGENT_PROMPT,\n  RESOLVE_LIBRARY_ID_DESCRIPTION,\n} from \"./index\";\n\nconst bedrock = createAmazonBedrock({\n  region: process.env.AWS_REGION,\n  apiKey: process.env.AWS_BEARER_TOKEN_BEDROCK,\n});\n\ndescribe(\"@upstash/context7-tools-ai-sdk\", () => {\n  describe(\"Tool structure\", () => {\n    test(\"resolveLibraryId() should return a tool object with correct structure\", () => {\n      const tool = resolveLibraryId();\n\n      expect(tool).toBeDefined();\n      expect(tool).toHaveProperty(\"execute\");\n      expect(tool).toHaveProperty(\"inputSchema\");\n      expect(tool).toHaveProperty(\"description\");\n      expect(tool.description).toContain(\"library\");\n    });\n\n    test(\"queryDocs() should return a tool object with correct structure\", () => {\n      const tool = queryDocs();\n\n      expect(tool).toBeDefined();\n      expect(tool).toHaveProperty(\"execute\");\n      expect(tool).toHaveProperty(\"inputSchema\");\n      expect(tool).toHaveProperty(\"description\");\n      expect(tool.description).toContain(\"documentation\");\n    });\n\n    test(\"tools should accept custom config\", () => {\n      const resolveTool = resolveLibraryId({\n        apiKey: \"ctx7sk-test-key\",\n      });\n\n      const docsTool = queryDocs({\n        apiKey: \"ctx7sk-test-key\",\n      });\n\n      expect(resolveTool).toHaveProperty(\"execute\");\n      expect(docsTool).toHaveProperty(\"execute\");\n    });\n  });\n\n  describe(\"Tool usage with generateText\", () => {\n    test(\"resolveLibraryId tool should be called when searching for a library\", async () => {\n      const result = await generateText({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        tools: {\n          resolveLibraryId: resolveLibraryId(),\n        },\n        toolChoice: { type: \"tool\", toolName: \"resolveLibraryId\" },\n        stopWhen: stepCountIs(2),\n        prompt: \"Search for 'react' library\",\n      });\n\n      expect(result.toolCalls.length).toBeGreaterThan(0);\n      expect(result.toolCalls[0].toolName).toBe(\"resolveLibraryId\");\n      expect(result.toolResults.length).toBeGreaterThan(0);\n      const toolResult = result.toolResults[0] as unknown as { output: string };\n      expect(typeof toolResult.output).toBe(\"string\");\n      expect(toolResult.output).toContain(\"Context7-compatible library ID\");\n    }, 30000);\n\n    test(\"queryDocs tool should fetch documentation\", async () => {\n      const result = await generateText({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        tools: {\n          queryDocs: queryDocs(),\n        },\n        toolChoice: { type: \"tool\", toolName: \"queryDocs\" },\n        stopWhen: stepCountIs(2),\n        prompt: \"Fetch documentation for library ID '/facebook/react' about hooks\",\n      });\n\n      expect(result.toolCalls.length).toBeGreaterThan(0);\n      expect(result.toolCalls[0].toolName).toBe(\"queryDocs\");\n      expect(result.toolResults.length).toBeGreaterThan(0);\n      const toolResult = result.toolResults[0] as unknown as { output: string };\n      expect(typeof toolResult.output).toBe(\"string\");\n      expect(toolResult.output.length).toBeGreaterThan(0);\n    }, 30000);\n\n    test(\"both tools can work together in a multi-step flow\", async () => {\n      const result = await generateText({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        tools: {\n          resolveLibraryId: resolveLibraryId(),\n          queryDocs: queryDocs(),\n        },\n        stopWhen: stepCountIs(5),\n        prompt:\n          \"First use resolveLibraryId to find the Next.js library, then use queryDocs to get documentation about routing\",\n      });\n\n      const allToolCalls = result.steps.flatMap((step) => step.toolCalls);\n      const toolNames = allToolCalls.map((call) => call.toolName);\n      expect(toolNames).toContain(\"resolveLibraryId\");\n      expect(toolNames).toContain(\"queryDocs\");\n    }, 60000);\n  });\n\n  describe(\"Context7Agent class\", () => {\n    test(\"should create an agent instance with model\", () => {\n      const agent = new Context7Agent({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n      });\n\n      expect(agent).toBeDefined();\n      expect(agent).toHaveProperty(\"generate\");\n      expect(agent).toHaveProperty(\"stream\");\n    });\n\n    test(\"should accept custom stopWhen condition\", () => {\n      const agent = new Context7Agent({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        stopWhen: stepCountIs(3),\n      });\n\n      expect(agent).toBeDefined();\n    });\n\n    test(\"should accept custom instructions\", () => {\n      const agent = new Context7Agent({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        instructions: \"Custom instructions for testing\",\n      });\n\n      expect(agent).toBeDefined();\n    });\n\n    test(\"should accept Context7 config options\", () => {\n      const agent = new Context7Agent({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        apiKey: \"ctx7sk-test-key\",\n      });\n\n      expect(agent).toBeDefined();\n    });\n\n    test(\"should accept additional tools alongside Context7 tools\", () => {\n      const customTool = tool({\n        description: \"A custom test tool\",\n        inputSchema: z.object({\n          input: z.string().describe(\"Test input\"),\n        }),\n        execute: async ({ input }) => ({ result: `processed: ${input}` }),\n      });\n\n      const agent = new Context7Agent({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        tools: {\n          customTool,\n        },\n      });\n\n      expect(agent).toBeDefined();\n    });\n\n    test(\"should generate response using agent workflow\", async () => {\n      const agent = new Context7Agent({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        stopWhen: stepCountIs(5),\n      });\n\n      const result = await agent.generate({\n        prompt: \"Find the React library and get documentation about hooks\",\n      });\n\n      expect(result).toBeDefined();\n      expect(result.steps.length).toBeGreaterThan(0);\n\n      const allToolCalls = result.steps.flatMap((step) => step.toolCalls);\n      const toolNames = allToolCalls.map((call) => call.toolName);\n      expect(toolNames).toContain(\"resolveLibraryId\");\n    }, 60000);\n\n    test(\"should include Context7 tools in generate result\", async () => {\n      const agent = new Context7Agent({\n        model: bedrock(\"anthropic.claude-3-haiku-20240307-v1:0\"),\n        stopWhen: stepCountIs(5),\n      });\n\n      const result = await agent.generate({\n        prompt:\n          \"Use resolveLibraryId to search for Next.js, then use queryDocs to get routing documentation\",\n      });\n\n      expect(result).toBeDefined();\n\n      const allToolCalls = result.steps.flatMap((step) => step.toolCalls);\n      const toolNames = allToolCalls.map((call) => call.toolName);\n\n      expect(toolNames).toContain(\"resolveLibraryId\");\n      expect(toolNames).toContain(\"queryDocs\");\n    }, 60000);\n  });\n\n  describe(\"Prompt exports\", () => {\n    test(\"should export SYSTEM_PROMPT\", () => {\n      expect(SYSTEM_PROMPT).toBeDefined();\n      expect(typeof SYSTEM_PROMPT).toBe(\"string\");\n      expect(SYSTEM_PROMPT.length).toBeGreaterThan(0);\n    });\n\n    test(\"should export AGENT_PROMPT\", () => {\n      expect(AGENT_PROMPT).toBeDefined();\n      expect(typeof AGENT_PROMPT).toBe(\"string\");\n      expect(AGENT_PROMPT).toContain(\"Context7\");\n    });\n\n    test(\"should export RESOLVE_LIBRARY_ID_DESCRIPTION\", () => {\n      expect(RESOLVE_LIBRARY_ID_DESCRIPTION).toBeDefined();\n      expect(typeof RESOLVE_LIBRARY_ID_DESCRIPTION).toBe(\"string\");\n      expect(RESOLVE_LIBRARY_ID_DESCRIPTION).toContain(\"library\");\n    });\n  });\n});\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/index.ts",
    "content": "// Agents\nexport { Context7Agent, type Context7AgentConfig } from \"@agents\";\n\n// Tools\nexport { resolveLibraryId, queryDocs, type Context7ToolsConfig } from \"@tools\";\n\n// Prompts\nexport {\n  SYSTEM_PROMPT,\n  AGENT_PROMPT,\n  RESOLVE_LIBRARY_ID_DESCRIPTION,\n  QUERY_DOCS_DESCRIPTION,\n} from \"@prompts\";\n\n// Re-export useful types from SDK\nexport type {\n  Context7Config,\n  Library,\n  Documentation,\n  GetContextOptions,\n} from \"@upstash/context7-sdk\";\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/prompts/index.ts",
    "content": "export {\n  SYSTEM_PROMPT,\n  AGENT_PROMPT,\n  RESOLVE_LIBRARY_ID_DESCRIPTION,\n  QUERY_DOCS_DESCRIPTION,\n} from \"./system\";\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/prompts/system.ts",
    "content": "/**\n * System prompts for Context7 AI SDK agents\n */\n\n/**\n * Basic documentation assistant prompt\n */\nexport const SYSTEM_PROMPT = `You are a documentation search assistant powered by Context7.\n\nYour role is to help users find accurate, up-to-date documentation for libraries and frameworks.\n\nWhen answering questions:\n1. Search for the relevant library documentation\n2. Provide code examples when available\n3. Cite your sources by mentioning the library ID used`;\n\n/**\n * Detailed multi-step workflow prompt for comprehensive documentation retrieval\n */\nexport const AGENT_PROMPT = `You are a documentation search assistant powered by Context7.\n\nCRITICAL WORKFLOW - YOU MUST FOLLOW THESE STEPS:\n\nStep 1: ALWAYS start by calling 'resolveLibraryId' with the library name from the user's query\n   - Extract the main library/framework name (e.g., \"React\", \"Next.js\", \"Vue\")\n   - Call resolveLibraryId with just the library name\n   - Review ALL the search results returned\n\nStep 2: Analyze the results from resolveLibraryId and select the BEST library ID based on:\n   - Official sources (e.g., /reactjs/react.dev for React, /vercel/next.js for Next.js)\n   - Name similarity to what the user is looking for\n   - Description relevance\n   - Source reputation (High/Medium is better)\n   - Code snippet coverage (higher is better)\n   - Benchmark score (higher is better)\n\nStep 3: Call 'queryDocs' with the selected library ID and the user's query\n   - Use the exact library ID from the resolveLibraryId results\n   - Include the user's original question as the query parameter\n\nStep 4: Provide a clear answer with code examples from the documentation\n\nIMPORTANT:\n- You MUST call resolveLibraryId first before calling queryDocs\n- Do NOT skip resolveLibraryId - it helps you find the correct official documentation\n- Do not call either tool more than 3 times per question\n- Always cite which library ID you used`;\n\n/**\n * Library resolution tool description\n */\nexport const RESOLVE_LIBRARY_ID_DESCRIPTION = `Resolves a package/product name to a Context7-compatible library ID and returns matching libraries.\n\nYou MUST call this function before 'queryDocs' to obtain a valid Context7-compatible library ID UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query.\n\nSelection Process:\n1. Analyze the query to understand what library/package the user is looking for\n2. Return the most relevant match based on:\n- Name similarity to the query (exact matches prioritized)\n- Description relevance to the query's intent\n- Documentation coverage (prioritize libraries with higher Code Snippet counts)\n- Source reputation (consider libraries with High or Medium reputation more authoritative)\n- Benchmark Score: Quality indicator (100 is the highest score)\n\nResponse Format:\n- Return the selected library ID in a clearly marked section\n- Provide a brief explanation for why this library was chosen\n- If multiple good matches exist, acknowledge this but proceed with the most relevant one\n- If no good matches exist, clearly state this and suggest query refinements\n\nFor ambiguous queries, request clarification before proceeding with a best-guess match.\n\nIMPORTANT: Do not call this tool more than 3 times per question. If you cannot find what you need after 3 calls, use the best result you have.`;\n\n/**\n * Query docs tool description\n */\nexport const QUERY_DOCS_DESCRIPTION = `Retrieves and queries up-to-date documentation and code examples from Context7 for any programming library or framework.\n\nYou must call 'resolveLibraryId' first to obtain the exact Context7-compatible library ID required to use this tool, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query.\n\nIMPORTANT: Do not call this tool more than 3 times per question. If you cannot find what you need after 3 calls, use the best information you have.`;\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/tools/index.ts",
    "content": "export { resolveLibraryId } from \"./resolve-library-id\";\nexport { queryDocs } from \"./query-docs\";\nexport type { Context7ToolsConfig } from \"./types\";\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/tools/query-docs.ts",
    "content": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport { Context7 } from \"@upstash/context7-sdk\";\nimport type { Context7ToolsConfig } from \"./types\";\nimport { QUERY_DOCS_DESCRIPTION } from \"@prompts\";\n\n/**\n * Tool to fetch documentation for a library using its Context7 library ID.\n *\n * Can be called with or without configuration. Uses CONTEXT7_API_KEY environment\n * variable for authentication when no API key is provided.\n *\n * @param config Optional configuration options\n * @returns AI SDK tool for fetching library documentation\n *\n * @example\n * ```typescript\n * import { resolveLibraryId, queryDocs } from '@upstash/context7-tools-ai-sdk';\n * import { generateText, stepCountIs } from 'ai';\n * import { openai } from '@ai-sdk/openai';\n *\n * const { text } = await generateText({\n *   model: openai('gpt-4o'),\n *   prompt: 'Find React documentation about hooks',\n *   tools: {\n *     resolveLibraryId: resolveLibraryId(),\n *     queryDocs: queryDocs(),\n *   },\n *   stopWhen: stepCountIs(5),\n * });\n * ```\n */\nexport function queryDocs(config: Context7ToolsConfig = {}) {\n  const { apiKey } = config;\n  const getClient = () => new Context7({ apiKey });\n\n  return tool({\n    description: QUERY_DOCS_DESCRIPTION,\n    inputSchema: z.object({\n      libraryId: z\n        .string()\n        .describe(\n          \"Exact Context7-compatible library ID (e.g., '/mongodb/docs', '/vercel/next.js', '/supabase/supabase', '/vercel/next.js/v14.3.0-canary.87') retrieved from 'resolveLibraryId' or directly from user query in the format '/org/project' or '/org/project/version'.\"\n        ),\n      query: z\n        .string()\n        .describe(\n          \"The question or task you need help with. Be specific and include relevant details. Good: 'How to set up authentication with JWT in Express.js' or 'React useEffect cleanup function examples'. Bad: 'auth' or 'hooks'. IMPORTANT: Do not include any sensitive or confidential information such as API keys, passwords, credentials, or personal data in your query.\"\n        ),\n    }),\n    execute: async ({ libraryId, query }: { libraryId: string; query: string }) => {\n      try {\n        const client = getClient();\n        const documentation = await client.getContext(query, libraryId, { type: \"txt\" });\n\n        if (!documentation || documentation.length === 0) {\n          return `No documentation found for library \"${libraryId}\". This might have happened because you used an invalid Context7-compatible library ID. Use 'resolveLibraryId' to get a valid ID.`;\n        }\n\n        return documentation;\n      } catch (error) {\n        const errorMessage =\n          error instanceof Error ? error.message : \"Failed to fetch documentation\";\n        return `Error fetching documentation for \"${libraryId}\": ${errorMessage}`;\n      }\n    },\n  });\n}\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/tools/resolve-library-id.ts",
    "content": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport { Context7 } from \"@upstash/context7-sdk\";\nimport { RESOLVE_LIBRARY_ID_DESCRIPTION } from \"@prompts\";\nimport type { Context7ToolsConfig } from \"./types\";\n\n/**\n * Tool to resolve a library name to a Context7-compatible library ID.\n *\n * Can be called with or without configuration. Uses CONTEXT7_API_KEY environment\n * variable for authentication when no API key is provided.\n *\n * @param config Optional configuration options\n * @returns AI SDK tool for library resolution\n *\n * @example\n * ```typescript\n * import { resolveLibraryId, queryDocs } from '@upstash/context7-tools-ai-sdk';\n * import { generateText, stepCountIs } from 'ai';\n * import { openai } from '@ai-sdk/openai';\n *\n * const { text } = await generateText({\n *   model: openai('gpt-4o'),\n *   prompt: 'Find React documentation about hooks',\n *   tools: {\n *     resolveLibraryId: resolveLibraryId(),\n *     queryDocs: queryDocs(),\n *   },\n *   stopWhen: stepCountIs(5),\n * });\n * ```\n */\nexport function resolveLibraryId(config: Context7ToolsConfig = {}) {\n  const { apiKey } = config;\n  const getClient = () => new Context7({ apiKey });\n\n  return tool({\n    description: RESOLVE_LIBRARY_ID_DESCRIPTION,\n    inputSchema: z.object({\n      query: z\n        .string()\n        .describe(\n          \"The user's original question or task. This is used to rank library results by relevance to what the user is trying to accomplish. IMPORTANT: Do not include any sensitive or confidential information such as API keys, passwords, credentials, or personal data in your query.\"\n        ),\n      libraryName: z\n        .string()\n        .describe(\"Library name to search for and retrieve a Context7-compatible library ID.\"),\n    }),\n    execute: async ({ query, libraryName }: { query: string; libraryName: string }) => {\n      try {\n        const client = getClient();\n        const results = await client.searchLibrary(query, libraryName, { type: \"txt\" });\n\n        if (!results || results.length === 0) {\n          return `No libraries found matching \"${libraryName}\". Try a different search term or check the library name.`;\n        }\n\n        return results;\n      } catch (error) {\n        const errorMessage = error instanceof Error ? error.message : \"Failed to search libraries\";\n        return `Error searching for libraries: ${errorMessage}. Check your API key and try again.`;\n      }\n    },\n  });\n}\n"
  },
  {
    "path": "packages/tools-ai-sdk/src/tools/types.ts",
    "content": "/**\n * Configuration for Context7 tools\n */\nexport interface Context7ToolsConfig {\n  /**\n   * Context7 API key. If not provided, will use CONTEXT7_API_KEY environment variable.\n   */\n  apiKey?: string;\n}\n"
  },
  {
    "path": "packages/tools-ai-sdk/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\"ESNext\"],\n    \"module\": \"esnext\",\n    \"target\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"moduleDetection\": \"force\",\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"strict\": true,\n    \"downlevelIteration\": true,\n    \"skipLibCheck\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"allowJs\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@tools\": [\"./src/tools/index.ts\"],\n      \"@agents\": [\"./src/agents/index.ts\"],\n      \"@prompts\": [\"./src/prompts/index.ts\"]\n    }\n  },\n  \"include\": [\"src/**/*\", \"tsup.config.ts\", \"vitest.config.ts\", \"eslint.config.js\"],\n  \"exclude\": [\"node_modules\", \"dist\", \"examples\"]\n}\n"
  },
  {
    "path": "packages/tools-ai-sdk/tsup.config.ts",
    "content": "import { defineConfig } from \"tsup\";\n\nexport default defineConfig({\n  entry: {\n    index: \"./src/index.ts\",\n    agent: \"./src/agents/index.ts\",\n  },\n  format: [\"cjs\", \"esm\"],\n  clean: true,\n  dts: true,\n  esbuildOptions(options) {\n    options.alias = {\n      \"@tools\": \"./src/tools/index.ts\",\n      \"@agents\": \"./src/agents/index.ts\",\n      \"@prompts\": \"./src/prompts/index.ts\",\n    };\n  },\n});\n"
  },
  {
    "path": "packages/tools-ai-sdk/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\nimport path from \"path\";\nimport { config } from \"dotenv\";\n\nconfig({ path: path.resolve(__dirname, \"../../.env\") });\n\nexport default defineConfig({\n  test: {\n    globals: true,\n    environment: \"node\",\n    include: [\"src/**/*.test.ts\"],\n  },\n  resolve: {\n    alias: {\n      \"@tools\": path.resolve(__dirname, \"./src/tools/index.ts\"),\n      \"@agents\": path.resolve(__dirname, \"./src/agents/index.ts\"),\n      \"@prompts\": path.resolve(__dirname, \"./src/prompts/index.ts\"),\n    },\n  },\n});\n"
  },
  {
    "path": "plugins/claude/context7/.claude-plugin/plugin.json",
    "content": "{\n  \"name\": \"context7-plugin\",\n  \"description\": \"Upstash Context7 MCP server for up-to-date documentation lookup. Pull version-specific documentation and code examples directly from source repositories into your LLM context.\",\n  \"author\": {\n    \"name\": \"Upstash\"\n  }\n}\n"
  },
  {
    "path": "plugins/claude/context7/README.md",
    "content": "# Context7 Plugin for Claude Code\n\nContext7 solves a common problem with AI coding assistants: outdated training data and hallucinated APIs. Instead of relying on stale knowledge, Context7 fetches current documentation directly from source repositories.\n\n## What's Included\n\nThis plugin provides:\n\n- **MCP Server** - Connects Claude Code to Context7's documentation service\n- **Skills** - Auto-triggers documentation lookups when you ask about libraries\n- **Agents** - A dedicated `docs-researcher` agent for focused lookups\n- **Commands** - `/context7:docs` for manual documentation queries\n\n## Installation\n\nAdd the marketplace and install the plugin:\n\n```bash\nclaude plugin marketplace add upstash/context7\nclaude plugin install context7-plugin@context7-marketplace\n```\n\n## Available Tools\n\n### resolve-library-id\n\nSearches for libraries and returns Context7-compatible identifiers.\n\n```\nInput: \"next.js\"\nOutput: { id: \"/vercel/next.js\", name: \"Next.js\", versions: [\"v15.1.8\", \"v14.2.0\", ...] }\n```\n\n### query-docs\n\nFetches documentation for a specific library, ranked by relevance to your question.\n\n```\nInput: { libraryId: \"/vercel/next.js\", query: \"app router middleware\" }\nOutput: Relevant documentation snippets with code examples\n```\n\n## Usage Examples\n\nThe plugin works automatically when you ask about libraries:\n\n- \"How do I set up authentication in Next.js 15?\"\n- \"Show me React Server Components examples\"\n- \"What's the Prisma syntax for relations?\"\n\nFor manual lookups, use the command:\n\n```\n/context7:docs next.js app router\n/context7:docs /vercel/next.js/v15.1.8 middleware\n```\n\nOr spawn the docs-researcher agent when you want to keep your main context clean:\n\n```\nspawn docs-researcher to look up Supabase auth methods\n```\n\n## Version Pinning\n\nTo get documentation for a specific version, include the version in the library ID:\n\n```\n/vercel/next.js/v15.1.8\n/supabase/supabase/v2.45.0\n```\n\nThe `resolve-library-id` tool returns available versions, so you can pick the one that matches your project.\n"
  },
  {
    "path": "plugins/claude/context7/agents/docs-researcher.md",
    "content": "---\nname: docs-researcher\ndescription: Lightweight agent for fetching library documentation without cluttering your main conversation context.\nmodel: sonnet\n---\n\nYou are a documentation researcher specializing in fetching up-to-date library and framework documentation from Context7.\n\n## Your Task\n\nWhen given a question about a library or framework, fetch the relevant documentation and return a concise, actionable answer with code examples.\n\n## Process\n\n1. **Identify the library**: Extract the library/framework name from the user's question.\n\n2. **Resolve the library ID**: Call `resolve-library-id` with:\n   - `libraryName`: The library name (e.g., \"react\", \"next.js\", \"prisma\")\n   - `query`: The user's full question for relevance ranking\n\n3. **Select the best match**: From the results, pick the library with:\n   - Exact or closest name match\n   - Highest benchmark score\n   - Appropriate version if the user specified one (e.g., \"React 19\" → look for v19.x)\n\n4. **Fetch documentation**: Call `query-docs` with:\n   - `libraryId`: The selected Context7 library ID (e.g., `/vercel/next.js`)\n   - `query`: The user's specific question for targeted results\n\n5. **Return a focused answer**: Summarize the relevant documentation with:\n   - Direct answer to the question\n   - Code examples from the docs\n   - Links or references if available\n\n## Guidelines\n\n- Pass the user's full question as the query parameter for better relevance\n- When the user mentions a version (e.g., \"Next.js 15\"), use version-specific library IDs if available\n- If `resolve-library-id` returns multiple matches, prefer official/primary packages over community forks\n- Keep responses concise - the goal is to answer the question, not dump entire documentation\n"
  },
  {
    "path": "plugins/claude/context7/commands/docs.md",
    "content": "---\ndescription: Look up documentation for any library\nargument-hint: <library> [query]\n---\n\n# /context7:docs\n\nFetches up-to-date documentation and code examples for a library.\n\n## Usage\n\n```\n/context7:docs <library> [query]\n```\n\n- **library**: The library name, or a Context7 ID starting with `/`\n- **query**: What you're looking for (optional but recommended)\n\n## Examples\n\n```\n/context7:docs react hooks\n/context7:docs next.js authentication\n/context7:docs prisma relations\n/context7:docs /vercel/next.js/v15.1.8 app router\n/context7:docs /supabase/supabase row level security\n```\n\n## How It Works\n\n1. If the library starts with `/`, it's used directly as the Context7 ID\n2. Otherwise, `resolve-library-id` finds the best matching library\n3. `query-docs` fetches documentation relevant to your query\n4. Results include code examples and explanations\n\n## Version-Specific Lookups\n\nInclude the version in the library ID for pinned documentation:\n\n```\n/context7:docs /vercel/next.js/v15.1.8 middleware\n/context7:docs /facebook/react/v19.0.0 use hook\n```\n\nThis is useful when you're working with a specific version and want docs that match exactly.\n"
  },
  {
    "path": "plugins/claude/context7/skills/context7-mcp/SKILL.md",
    "content": "---\nname: context7-mcp\ndescription: This skill should be used when the user asks about libraries, frameworks, API references, or needs code examples. Activates for setup questions, code generation involving libraries, or mentions of specific frameworks like React, Vue, Next.js, Prisma, Supabase, etc.\n---\n\nWhen the user asks about libraries, frameworks, or needs code examples, use Context7 to fetch current documentation instead of relying on training data.\n\n## When to Use This Skill\n\nActivate this skill when the user:\n\n- Asks setup or configuration questions (\"How do I configure Next.js middleware?\")\n- Requests code involving libraries (\"Write a Prisma query for...\")\n- Needs API references (\"What are the Supabase auth methods?\")\n- Mentions specific frameworks (React, Vue, Svelte, Express, Tailwind, etc.)\n\n## How to Fetch Documentation\n\n### Step 1: Resolve the Library ID\n\nCall `resolve-library-id` with:\n\n- `libraryName`: The library name extracted from the user's question\n- `query`: The user's full question (improves relevance ranking)\n\n### Step 2: Select the Best Match\n\nFrom the resolution results, choose based on:\n\n- Exact or closest name match to what the user asked for\n- Higher benchmark scores indicate better documentation quality\n- If the user mentioned a version (e.g., \"React 19\"), prefer version-specific IDs\n\n### Step 3: Fetch the Documentation\n\nCall `query-docs` with:\n\n- `libraryId`: The selected Context7 library ID (e.g., `/vercel/next.js`)\n- `query`: The user's specific question\n\n### Step 4: Use the Documentation\n\nIncorporate the fetched documentation into your response:\n\n- Answer the user's question using current, accurate information\n- Include relevant code examples from the docs\n- Cite the library version when relevant\n\n## Guidelines\n\n- **Be specific**: Pass the user's full question as the query for better results\n- **Version awareness**: When users mention versions (\"Next.js 15\", \"React 19\"), use version-specific library IDs if available from the resolution step\n- **Prefer official sources**: When multiple matches exist, prefer official/primary packages over community forks\n"
  },
  {
    "path": "plugins/cursor/context7/.cursor/plugin.json",
    "content": "{\n  \"name\": \"context7\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Upstash Context7 MCP server for up-to-date documentation lookup. Pull version-specific documentation and code examples directly from source repositories into your LLM context.\",\n  \"author\": {\n    \"name\": \"Context7\",\n    \"email\": \"context7@upstash.com\",\n    \"url\": \"https://context7.com\"\n  },\n  \"keywords\": [\"documentation\", \"mcp\", \"context7\", \"libraries\", \"frameworks\"],\n  \"logo\": \"https://context7.com/brand/context7-icon-green.svg\",\n  \"primaryColor\": \"#059669\"\n}\n"
  },
  {
    "path": "plugins/cursor/context7/README.md",
    "content": "# Context7 Plugin for Cursor\n\nContext7 solves a common problem with AI coding assistants: outdated training data and hallucinated APIs. Instead of relying on stale knowledge, Context7 fetches current documentation directly from source repositories.\n\n## What's Included\n\nThis plugin provides:\n\n- **MCP Server** — Connects Cursor to Context7's documentation service\n- **Rules** — An always-on `use-context7` rule that nudges the agent to fetch docs when unsure about library APIs\n- **Skills** — A `context7-docs-lookup` skill with detailed instructions on resolving libraries and fetching documentation\n- **Agents** — A dedicated `docs-researcher` agent for focused lookups\n\n## Available Tools\n\n### resolve-library-id\n\nSearches for libraries and returns Context7-compatible identifiers.\n\n```\nInput: \"next.js\"\nOutput: { id: \"/vercel/next.js\", name: \"Next.js\", versions: [\"v15.1.8\", \"v14.2.0\", ...] }\n```\n\n### query-docs\n\nFetches documentation for a specific library, ranked by relevance to your question.\n\n```\nInput: { libraryId: \"/vercel/next.js\", query: \"app router middleware\" }\nOutput: Relevant documentation snippets with code examples\n```\n\n## Usage Examples\n\nThe plugin works automatically when you ask about libraries:\n\n- \"How do I set up authentication in Next.js 15?\"\n- \"Show me React Server Components examples\"\n- \"What's the Prisma syntax for relations?\"\n\nOr use the docs-researcher agent when you want to keep your main context clean.\n\n## Version Pinning\n\nTo get documentation for a specific version, include the version in the library ID:\n\n```\n/vercel/next.js/v15.1.8\n/supabase/supabase/v2.45.0\n```\n\nThe `resolve-library-id` tool returns available versions, so you can pick the one that matches your project.\n"
  },
  {
    "path": "plugins/cursor/context7/agents/docs-researcher.md",
    "content": "---\nname: docs-researcher\ndescription: Lightweight agent for fetching library documentation without cluttering your main conversation context.\n---\n\nYou are a documentation researcher specializing in fetching up-to-date library and framework documentation from Context7.\n\n## Your Task\n\nWhen given a question about a library or framework, fetch the relevant documentation and return a concise, actionable answer with code examples.\n\n## Process\n\n1. **Identify the library**: Extract the library/framework name from the user's question.\n\n2. **Resolve the library ID**: Call `resolve-library-id` with:\n   - `libraryName`: The library name (e.g., \"react\", \"next.js\", \"prisma\")\n   - `query`: The user's full question for relevance ranking\n\n3. **Select the best match**: From the results, pick the library with:\n   - Exact or closest name match\n   - Highest benchmark score\n   - Appropriate version if the user specified one (e.g., \"React 19\" → look for v19.x)\n\n4. **Fetch documentation**: Call `query-docs` with:\n   - `libraryId`: The selected Context7 library ID (e.g., `/vercel/next.js`)\n   - `query`: The user's specific question for targeted results\n\n5. **Return a focused answer**: Summarize the relevant documentation with:\n   - Direct answer to the question\n   - Code examples from the docs\n   - Links or references if available\n\n## Guidelines\n\n- Pass the user's full question as the query parameter for better relevance\n- When the user mentions a version (e.g., \"Next.js 15\"), use version-specific library IDs if available\n- If `resolve-library-id` returns multiple matches, prefer official/primary packages over community forks\n- Keep responses concise - the goal is to answer the question, not dump entire documentation\n"
  },
  {
    "path": "plugins/cursor/context7/mcp.json",
    "content": "{\n  \"context7\": {\n    \"url\": \"https://mcp.context7.com/mcp/oauth\"\n  }\n}\n"
  },
  {
    "path": "plugins/cursor/context7/rules/use-context7.mdc",
    "content": "---\ndescription: Use Context7 MCP to fetch up-to-date documentation when unsure about library APIs, syntax, or behavior instead of guessing from training data.\nalwaysApply: true\n---\n\nWhen you're unsure about a library's API, syntax, configuration, or behavior, use Context7 to fetch current documentation rather than guessing from training data that may be outdated.\n\nUse Context7 when:\n- You're not confident about the exact API or syntax for a library\n- The user asks about a specific version (e.g., \"Next.js 15\", \"React 19\")\n- The library or framework has had recent major changes\n- You need accurate code examples for a specific use case\n\nYou don't need to use Context7 for:\n- Well-established language features (e.g., JavaScript array methods, Python builtins)\n- Conversations where the user has already provided the relevant code or docs\n\nSee the `context7-docs-lookup` skill for detailed instructions on how to resolve libraries and fetch documentation.\n"
  },
  {
    "path": "plugins/cursor/context7/skills/context7-mcp/SKILL.md",
    "content": "---\nname: context7-mcp\ndescription: This skill should be used when the user asks about libraries, frameworks, API references, or needs code examples. Activates for setup questions, code generation involving libraries, or mentions of specific frameworks like React, Vue, Next.js, Prisma, Supabase, etc.\n---\n\nWhen the user asks about libraries, frameworks, or needs code examples, use Context7 to fetch current documentation instead of relying on training data.\n\n## When to Use This Skill\n\nActivate this skill when the user:\n\n- Asks setup or configuration questions (\"How do I configure Next.js middleware?\")\n- Requests code involving libraries (\"Write a Prisma query for...\")\n- Needs API references (\"What are the Supabase auth methods?\")\n- Mentions specific frameworks (React, Vue, Svelte, Express, Tailwind, etc.)\n\n## How to Fetch Documentation\n\n### Step 1: Resolve the Library ID\n\nCall `resolve-library-id` with:\n\n- `libraryName`: The library name extracted from the user's question\n- `query`: The user's full question (improves relevance ranking)\n\n### Step 2: Select the Best Match\n\nFrom the resolution results, choose based on:\n\n- Exact or closest name match to what the user asked for\n- Higher benchmark scores indicate better documentation quality\n- If the user mentioned a version (e.g., \"React 19\"), prefer version-specific IDs\n\n### Step 3: Fetch the Documentation\n\nCall `query-docs` with:\n\n- `libraryId`: The selected Context7 library ID (e.g., `/vercel/next.js`)\n- `query`: The user's specific question\n\n### Step 4: Use the Documentation\n\nIncorporate the fetched documentation into your response:\n\n- Answer the user's question using current, accurate information\n- Include relevant code examples from the docs\n- Cite the library version when relevant\n\n## Guidelines\n\n- **Be specific**: Pass the user's full question as the query for better results\n- **Version awareness**: When users mention versions (\"Next.js 15\", \"React 19\"), use version-specific library IDs if available from the resolution step\n- **Prefer official sources**: When multiple matches exist, prefer official/primary packages over community forks\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - \"packages/*\"\n"
  },
  {
    "path": "prettier.config.mjs",
    "content": "/**\n * @type {import('prettier').Config}\n */\nconst config = {\n  endOfLine: \"lf\",\n  singleQuote: false,\n  tabWidth: 2,\n  trailingComma: \"es5\",\n  printWidth: 100,\n  arrowParens: \"always\",\n};\n\nexport default config;\n"
  },
  {
    "path": "server.json",
    "content": "{\n  \"$schema\": \"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json\",\n  \"name\": \"io.github.upstash/context7\",\n  \"title\": \"Context7\",\n  \"description\": \"Up-to-date code docs for any prompt\",\n  \"repository\": {\n    \"url\": \"https://github.com/upstash/context7\",\n    \"source\": \"github\"\n  },\n  \"websiteUrl\": \"https://context7.com\",\n  \"icons\": [\n    {\n      \"src\": \"https://raw.githubusercontent.com/upstash/context7/master/public/icon.png\",\n      \"mimeType\": \"image/png\"\n    }\n  ],\n  \"version\": \"2.0.0\",\n  \"packages\": [\n    {\n      \"registryType\": \"npm\",\n      \"identifier\": \"@upstash/context7-mcp\",\n      \"version\": \"2.0.2\",\n      \"transport\": {\n        \"type\": \"stdio\"\n      },\n      \"environmentVariables\": [\n        {\n          \"name\": \"CONTEXT7_API_KEY\",\n          \"description\": \"API key for authentication\",\n          \"isRequired\": false,\n          \"isSecret\": true\n        }\n      ]\n    },\n    {\n      \"registryType\": \"mcpb\",\n      \"identifier\": \"https://github.com/upstash/context7/releases/download/@upstash/context7-mcp@2.0.2/context7.mcpb\",\n      \"version\": \"2.0.2\",\n      \"fileSha256\": \"aea76f179ceb92d22c289147c9d8343fb558d6dec93b144c9794e99239bb8194\",\n      \"transport\": {\n        \"type\": \"stdio\"\n      },\n      \"environmentVariables\": [\n        {\n          \"name\": \"CONTEXT7_API_KEY\",\n          \"description\": \"API key for authentication\",\n          \"isRequired\": false,\n          \"isSecret\": true\n        }\n      ]\n    }\n  ],\n  \"remotes\": [\n    {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.context7.com/mcp\",\n      \"headers\": [\n        {\n          \"name\": \"CONTEXT7_API_KEY\",\n          \"description\": \"API key for authentication\",\n          \"isRequired\": false,\n          \"isSecret\": true\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "skills/context7-cli/SKILL.md",
    "content": "---\nname: context7-cli\ndescription: Use the ctx7 CLI to fetch library documentation, manage AI coding skills, and configure Context7 MCP. Activate when the user mentions \"ctx7\" or \"context7\", needs current docs for any library, wants to install/search/generate skills, or needs to set up Context7 for their AI coding agent.\n---\n\n# ctx7 CLI\n\nThe Context7 CLI does three things: fetches up-to-date library documentation, manages AI coding skills, and sets up Context7 MCP for your editor.\n\nMake sure the CLI is up to date before running commands:\n\n```bash\nnpm install -g ctx7@latest\n```\n\nOr run directly without installing:\n\n```bash\nnpx ctx7@latest <command>\n```\n\n## What this skill covers\n\n- **[Documentation](references/docs.md)** — Fetch current docs for any library. Use when writing code, verifying API signatures, or when training data may be outdated.\n- **[Skills management](references/skills.md)** — Install, search, suggest, list, remove, and generate AI coding skills.\n- **[Setup](references/setup.md)** — Configure Context7 MCP for Claude Code / Cursor / OpenCode.\n\n## Quick Reference\n\n```bash\n# Documentation\nctx7 library <name> <query>           # Step 1: resolve library ID\nctx7 docs <libraryId> <query>         # Step 2: fetch docs\n\n# Skills\nctx7 skills install /owner/repo       # Install from a repo (interactive)\nctx7 skills install /owner/repo name  # Install a specific skill\nctx7 skills search <keywords>         # Search the registry\nctx7 skills suggest                   # Auto-suggest based on project deps\nctx7 skills list                      # List installed skills\nctx7 skills remove <name>             # Uninstall a skill\nctx7 skills generate                  # Generate a custom skill with AI (requires login)\n\n# Setup\nctx7 setup                            # Configure Context7 MCP (interactive)\nctx7 login                            # Log in for higher rate limits + skill generation\nctx7 whoami                           # Check current login status\n```\n\n## Authentication\n\n```bash\nctx7 login               # Opens browser for OAuth\nctx7 login --no-browser  # Prints URL instead of opening browser\nctx7 logout              # Clear stored tokens\nctx7 whoami              # Show current login status (name + email)\n```\n\nMost commands work without login. Exceptions: `skills generate` always requires it; `ctx7 setup` requires it unless `--api-key` or `--oauth` is passed. Login also unlocks higher rate limits on docs commands.\n\nSet an API key via environment variable to skip interactive login entirely:\n\n```bash\nexport CONTEXT7_API_KEY=your_key\n```\n\n## Common Mistakes\n\n- Library IDs require a `/` prefix — `/facebook/react` not `facebook/react`\n- Always run `ctx7 library` first — `ctx7 docs react \"hooks\"` will fail without a valid ID\n- Repository format for skills is `/owner/repo` — e.g., `ctx7 skills install /anthropics/skills`\n- `skills generate` requires login — run `ctx7 login` first\n"
  },
  {
    "path": "skills/context7-cli/references/docs.md",
    "content": "# Documentation Commands\n\nRetrieves and queries up-to-date documentation and code examples from Context7 for any programming library or framework. Two-step workflow: resolve the library name to get its ID, then query docs using that ID.\n\nIf the user already provided a library ID in `/org/project` or `/org/project/version` format, pass it directly to `ctx7 docs`.\n\n## Step 1: Resolve a Library\n\nResolves a package/product name to a Context7-compatible library ID and returns matching libraries.\n\n```bash\nctx7 library react \"How to clean up useEffect with async operations\"\nctx7 library nextjs \"How to set up app router with middleware\"\nctx7 library prisma \"How to define one-to-many relations with cascade delete\"\n```\n\nAlways pass a `query` argument — it is required and directly affects result ranking. Use the user's intent to form the query, which helps disambiguate when multiple libraries share a similar name. Do not include any sensitive or confidential information such as API keys, passwords, credentials, personal data, or proprietary code in your query.\n\n### Result fields\n\nEach result includes:\n\n- **Library ID** — Context7-compatible identifier (format: `/org/project`)\n- **Name** — Library or package name\n- **Description** — Short summary\n- **Code Snippets** — Number of available code examples\n- **Source Reputation** — Authority indicator (High, Medium, Low, or Unknown)\n- **Benchmark Score** — Quality indicator (100 is the highest score)\n- **Versions** — List of versions if available. Use one of those versions if the user provides a version in their query. The format is `/org/project/version`.\n\n### Selection process\n\n1. Analyze the query to understand what library/package the user is looking for\n2. Select the most relevant match based on:\n   - Name similarity to the query (exact matches prioritized)\n   - Description relevance to the query's intent\n   - Documentation coverage (prioritize libraries with higher Code Snippet counts)\n   - Source reputation (consider libraries with High or Medium reputation more authoritative)\n   - Benchmark score (higher is better, 100 is the maximum)\n3. If multiple good matches exist, acknowledge this but proceed with the most relevant one\n4. If no good matches exist, clearly state this and suggest query refinements\n5. For ambiguous queries, request clarification before proceeding with a best-guess match\n\nIMPORTANT: Do not call `ctx7 library` more than 3 times per question. If you cannot find what you need after 3 calls, use the best result you have.\n\n### Version-specific IDs\n\nIf the user mentions a specific version, use a version-specific library ID:\n\n```bash\n# General (latest indexed)\nctx7 docs /vercel/next.js \"How to set up app router\"\n\n# Version-specific\nctx7 docs /vercel/next.js/v14.3.0-canary.87 \"How to set up app router\"\n```\n\nThe available versions are listed in the `ctx7 library` output. Use the closest match to what the user specified.\n\n```bash\n# Output as JSON for scripting\nctx7 library react \"How to use hooks for state management\" --json | jq '.[0].id'\n```\n\n## Step 2: Query Documentation\n\nRetrieves up-to-date documentation and code examples for the resolved library.\n\nYou must call `ctx7 library` first to obtain the exact Context7-compatible library ID required to use this command, UNLESS the user explicitly provides a library ID in the format `/org/project` or `/org/project/version`.\n\n```bash\nctx7 docs /facebook/react \"How to clean up useEffect with async operations\"\nctx7 docs /vercel/next.js \"How to add authentication middleware to app router\"\nctx7 docs /prisma/prisma \"How to define one-to-many relations with cascade delete\"\n```\n\nIMPORTANT: Do not call `ctx7 docs` more than 3 times per question. If you cannot find what you need after 3 calls, use the best information you have.\n\n### Writing good queries\n\nThe query directly affects the quality of results. Be specific and include relevant details. Do not include any sensitive or confidential information such as API keys, passwords, credentials, personal data, or proprietary code in your query.\n\n| Quality | Example |\n|---------|---------|\n| Good | `\"How to set up authentication with JWT in Express.js\"` |\n| Good | `\"React useEffect cleanup function with async operations\"` |\n| Bad | `\"auth\"` |\n| Bad | `\"hooks\"` |\n\nUse the user's full question as the query when possible — vague one-word queries return generic results.\n\nThe output contains two types of content: **code snippets** (titled, with language-tagged blocks) and **info snippets** (prose explanations with breadcrumb context).\n\n```bash\n# Output as structured JSON\nctx7 docs /facebook/react \"How to use hooks for state management\" --json\n\n# Pipe to other tools — output is clean when not in a TTY (no spinners or colors)\nctx7 docs /facebook/react \"How to use hooks for state management\" | head -50\nctx7 docs /vercel/next.js \"How to add middleware for route protection\" | grep -A5 \"middleware\"\n```\n\n## Authentication\n\nWorks without authentication. For higher rate limits:\n\n```bash\n# Option A: environment variable\nexport CONTEXT7_API_KEY=your_key\n\n# Option B: OAuth login\nctx7 login\n```\n"
  },
  {
    "path": "skills/context7-cli/references/setup.md",
    "content": "# Setup\n\n## ctx7 setup\n\nOne-time command to configure Context7 for your AI coding agent. Prompts for mode on first run:\n- **MCP server** — registers the Context7 MCP server so the agent can call tools natively\n- **CLI + Skills** — installs a `find-docs` skill that guides the agent to use `ctx7` CLI commands (no MCP required)\n\n```bash\nctx7 setup                     # Interactive — prompts for mode, then agent/install target\nctx7 setup --mcp               # Skip prompt, use MCP server mode\nctx7 setup --cli               # Skip prompt, use CLI + Skills mode\n\n# MCP mode — target a specific agent\nctx7 setup --claude            # Claude Code only\nctx7 setup --cursor            # Cursor only\nctx7 setup --opencode          # OpenCode only\n\n# CLI + Skills mode — target a specific install location\nctx7 setup --cli --claude      # Claude Code (~/.claude/skills)\nctx7 setup --cli --cursor      # Cursor (~/.cursor/skills)\nctx7 setup --cli --universal   # Universal (~/.agents/skills)\nctx7 setup --cli --antigravity # Antigravity (~/.config/agent/skills)\n\nctx7 setup --project           # Configure current project instead of globally\nctx7 setup --yes               # Skip confirmation prompts\n```\n\n**Authentication options:**\n```bash\nctx7 setup --api-key YOUR_KEY  # Use an existing API key (both MCP and CLI + Skills mode)\nctx7 setup --oauth             # OAuth endpoint — MCP mode only (IDE handles the auth flow)\n```\n\nWithout `--api-key` or `--oauth`, setup opens a browser for OAuth login. MCP mode additionally generates a new API key after login. `--oauth` is MCP-only.\n\n**What gets written — MCP mode:**\n- MCP server entry in the agent's config file (`.mcp.json` for Claude, `.cursor/mcp.json` for Cursor, `.opencode.json` for OpenCode)\n- A Context7 rule file instructing the agent to use Context7 for library docs\n- A `context7-mcp` skill in the agent's skills directory\n\n**What gets written — CLI + Skills mode:**\n- A `find-docs` skill in the chosen agent's skills directory, guiding the agent to use `ctx7 library` and `ctx7 docs` commands\n"
  },
  {
    "path": "skills/context7-cli/references/skills.md",
    "content": "# Skills Commands\n\nManage AI coding skills from the Context7 registry. Skills are Markdown files that teach AI coding agents best practices, patterns, and workflows for specific libraries or tasks.\n\n## Install\n\nInstall skills from any GitHub repository. Repository format is always `/owner/repo`.\n\n```bash\nctx7 skills install /anthropics/skills           # Interactive — pick from a list\nctx7 skills install /anthropics/skills pdf        # Install a specific skill by name\nctx7 skills install /anthropics/skills --all      # Install everything without prompting\n```\n\nTarget a specific IDE with a flag:\n```bash\nctx7 skills install /anthropics/skills pdf --claude     # Claude Code only\nctx7 skills install /anthropics/skills pdf --cursor     # Cursor only\nctx7 skills install /anthropics/skills pdf --universal  # Universal (.agents/skills/)\nctx7 skills install /anthropics/skills --all --global   # All skills, global install\n```\n\nAlias: `ctx7 si /anthropics/skills pdf`\n\n## Search\n\nFind skills across the entire registry by keyword. Shows an interactive list with install counts and trust scores. Select to install.\n\n```bash\nctx7 skills search pdf\nctx7 skills search typescript testing\nctx7 skills search react nextjs\n```\n\nAlias: `ctx7 ss pdf`\n\n## Suggest\n\nAuto-detects your project dependencies and recommends relevant skills from the registry.\n\n```bash\nctx7 skills suggest           # Scan current project, install to project\nctx7 skills suggest --global  # Install suggestions globally\nctx7 skills suggest --claude  # Target Claude Code only\n```\n\nReads `package.json`, `requirements.txt`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `Gemfile`. Falls back to suggesting `ctx7 skills search` if no dependencies are detected.\n\nAlias: `ctx7 ssg`\n\n## Generate (AI-powered)\n\nGenerate a custom skill tailored to your stack using AI. **Requires login.**\n\n```bash\nctx7 skills generate\nctx7 skills generate --claude   # Install directly to Claude Code\nctx7 skills generate --global   # Install to global skills\n```\n\nInteractive flow:\n1. Describe the expertise you want (e.g., \"OAuth authentication with NextAuth.js\")\n2. Select relevant libraries from search results\n3. Answer 3 clarifying questions to focus the skill\n4. Review the generated skill, request changes if needed\n5. Choose where to install it\n\n**Limits:** Free accounts get 6 generations/week, Pro accounts get 10.\n\nAliases: `ctx7 skills gen`, `ctx7 skills g`\n\n## List\n\nShow all installed skills for the current project or globally.\n\n```bash\nctx7 skills list                  # Current project (all detected IDEs)\nctx7 skills list --claude         # Claude Code only\nctx7 skills list --global         # Global skills\nctx7 skills list --global --claude # Global Claude Code skills\n```\n\n## Remove\n\nUninstall a skill by name.\n\n```bash\nctx7 skills remove pdf\nctx7 skills remove pdf --claude   # From Claude Code only\nctx7 skills remove pdf --global   # From global skills\n```\n\nAliases: `ctx7 skills rm`, `ctx7 skills delete`\n\n## Info\n\nBrowse all skills in a repository without installing — useful for previewing what's available.\n\n```bash\nctx7 skills info /anthropics/skills\n```\n\nOutput shows each skill name, description, and URL, plus quick install commands.\n\n## IDE Flags\n\nAll skills commands accept these flags to target a specific AI coding assistant:\n\n| Flag | Directory | Used by |\n|------|-----------|---------|\n| `--universal` | `.agents/skills/` | Amp, Codex, Gemini CLI, OpenCode, GitHub Copilot |\n| `--claude` | `.claude/skills/` | Claude Code |\n| `--cursor` | `.cursor/skills/` | Cursor |\n| `--antigravity` | `.agent/skills/` | Antigravity |\n\nWithout a flag, the CLI prompts you to select one or more targets interactively.\n\nAdd `--global` to any flag to install in your home directory instead of the current project.\n"
  },
  {
    "path": "skills/context7-mcp/SKILL.md",
    "content": "---\nname: context7-mcp\ndescription: This skill should be used when the user asks about libraries, frameworks, API references, or needs code examples. Activates for setup questions, code generation involving libraries, or mentions of specific frameworks like React, Vue, Next.js, Prisma, Supabase, etc.\n---\n\nWhen the user asks about libraries, frameworks, or needs code examples, use Context7 to fetch current documentation instead of relying on training data.\n\n## When to Use This Skill\n\nActivate this skill when the user:\n\n- Asks setup or configuration questions (\"How do I configure Next.js middleware?\")\n- Requests code involving libraries (\"Write a Prisma query for...\")\n- Needs API references (\"What are the Supabase auth methods?\")\n- Mentions specific frameworks (React, Vue, Svelte, Express, Tailwind, etc.)\n\n## How to Fetch Documentation\n\n### Step 1: Resolve the Library ID\n\nCall `resolve-library-id` with:\n\n- `libraryName`: The library name extracted from the user's question\n- `query`: The user's full question (improves relevance ranking)\n\n### Step 2: Select the Best Match\n\nFrom the resolution results, choose based on:\n\n- Exact or closest name match to what the user asked for\n- Higher benchmark scores indicate better documentation quality\n- If the user mentioned a version (e.g., \"React 19\"), prefer version-specific IDs\n\n### Step 3: Fetch the Documentation\n\nCall `query-docs` with:\n\n- `libraryId`: The selected Context7 library ID (e.g., `/vercel/next.js`)\n- `query`: The user's specific question\n\n### Step 4: Use the Documentation\n\nIncorporate the fetched documentation into your response:\n\n- Answer the user's question using current, accurate information\n- Include relevant code examples from the docs\n- Cite the library version when relevant\n\n## Guidelines\n\n- **Be specific**: Pass the user's full question as the query for better results\n- **Version awareness**: When users mention versions (\"Next.js 15\", \"React 19\"), use version-specific library IDs if available from the resolution step\n- **Prefer official sources**: When multiple matches exist, prefer official/primary packages over community forks\n"
  },
  {
    "path": "skills/find-docs/SKILL.md",
    "content": "---\nname: find-docs\ndescription: >-\n  Retrieves authoritative, up-to-date technical documentation, API references,\n  configuration details, and code examples for any developer technology.\n\n  Use this skill whenever answering technical questions or writing code that\n  interacts with external technologies. This includes libraries, frameworks,\n  programming languages, SDKs, APIs, CLI tools, cloud services, infrastructure\n  tools, and developer platforms.\n\n  Common scenarios:\n  - looking up API endpoints, classes, functions, or method parameters\n  - checking configuration options or CLI commands\n  - answering \"how do I\" technical questions\n  - generating code that uses a specific library or service\n  - debugging issues related to frameworks, SDKs, or APIs\n  - retrieving setup instructions, examples, or migration guides\n  - verifying version-specific behavior or breaking changes\n\n  Prefer this skill whenever documentation accuracy matters or when model\n  knowledge may be outdated.\n---\n\n# Documentation Lookup\n\nRetrieve current documentation and code examples for any library using the Context7 CLI.\n\nMake sure the CLI is up to date before running commands:\n\n```bash\nnpm install -g ctx7@latest\n```\n\nOr run directly without installing:\n\n```bash\nnpx ctx7@latest <command>\n```\n\n## Workflow\n\nTwo-step process: resolve the library name to an ID, then query docs with that ID.\n\n```bash\n# Step 1: Resolve library ID\nctx7 library <name> <query>\n\n# Step 2: Query documentation\nctx7 docs <libraryId> <query>\n```\n\nYou MUST call `ctx7 library` first to obtain a valid library ID UNLESS the user explicitly provides a library ID in the format `/org/project` or `/org/project/version`.\n\nIMPORTANT: Do not run these commands more than 3 times per question. If you cannot find what you need after 3 attempts, use the best result you have.\n\n## Step 1: Resolve a Library\n\nResolves a package/product name to a Context7-compatible library ID and returns matching libraries.\n\n```bash\nctx7 library react \"How to clean up useEffect with async operations\"\nctx7 library nextjs \"How to set up app router with middleware\"\nctx7 library prisma \"How to define one-to-many relations with cascade delete\"\n```\n\nAlways pass a `query` argument — it is required and directly affects result ranking. Use the user's intent to form the query, which helps disambiguate when multiple libraries share a similar name. Do not include any sensitive or confidential information such as API keys, passwords, credentials, personal data, or proprietary code in your query.\n\n### Result fields\n\nEach result includes:\n\n- **Library ID** — Context7-compatible identifier (format: `/org/project`)\n- **Name** — Library or package name\n- **Description** — Short summary\n- **Code Snippets** — Number of available code examples\n- **Source Reputation** — Authority indicator (High, Medium, Low, or Unknown)\n- **Benchmark Score** — Quality indicator (100 is the highest score)\n- **Versions** — List of versions if available. Use one of those versions if the user provides a version in their query. The format is `/org/project/version`.\n\n### Selection process\n\n1. Analyze the query to understand what library/package the user is looking for\n2. Select the most relevant match based on:\n   - Name similarity to the query (exact matches prioritized)\n   - Description relevance to the query's intent\n   - Documentation coverage (prioritize libraries with higher Code Snippet counts)\n   - Source reputation (consider libraries with High or Medium reputation more authoritative)\n   - Benchmark score (higher is better, 100 is the maximum)\n3. If multiple good matches exist, acknowledge this but proceed with the most relevant one\n4. If no good matches exist, clearly state this and suggest query refinements\n5. For ambiguous queries, request clarification before proceeding with a best-guess match\n\n### Version-specific IDs\n\nIf the user mentions a specific version, use a version-specific library ID:\n\n```bash\n# General (latest indexed)\nctx7 docs /vercel/next.js \"How to set up app router\"\n\n# Version-specific\nctx7 docs /vercel/next.js/v14.3.0-canary.87 \"How to set up app router\"\n```\n\nThe available versions are listed in the `ctx7 library` output. Use the closest match to what the user specified.\n\n## Step 2: Query Documentation\n\nRetrieves up-to-date documentation and code examples for the resolved library.\n\n```bash\nctx7 docs /facebook/react \"How to clean up useEffect with async operations\"\nctx7 docs /vercel/next.js \"How to add authentication middleware to app router\"\nctx7 docs /prisma/prisma \"How to define one-to-many relations with cascade delete\"\n```\n\n### Writing good queries\n\nThe query directly affects the quality of results. Be specific and include relevant details. Do not include any sensitive or confidential information such as API keys, passwords, credentials, personal data, or proprietary code in your query.\n\n| Quality | Example |\n|---------|---------|\n| Good | `\"How to set up authentication with JWT in Express.js\"` |\n| Good | `\"React useEffect cleanup function with async operations\"` |\n| Bad | `\"auth\"` |\n| Bad | `\"hooks\"` |\n\nUse the user's full question as the query when possible, vague one-word queries return generic results.\n\nThe output contains two types of content: **code snippets** (titled, with language-tagged blocks) and **info snippets** (prose explanations with breadcrumb context).\n\n## Authentication\n\nWorks without authentication. For higher rate limits:\n\n```bash\n# Option A: environment variable\nexport CONTEXT7_API_KEY=your_key\n\n# Option B: OAuth login\nctx7 login\n```\n\n## Error Handling\n\nIf a command fails with a quota error (\"Monthly quota reached\" or \"quota exceeded\"):\n1. Inform the user their Context7 quota is exhausted\n2. Suggest they authenticate for higher limits: `ctx7 login`\n3. If they cannot or choose not to authenticate, answer from training knowledge and clearly note it may be outdated\n\nDo not silently fall back to training data — always tell the user why Context7 was not used.\n\n## Common Mistakes\n\n- Library IDs require a `/` prefix — `/facebook/react` not `facebook/react`\n- Always run `ctx7 library` first — `ctx7 docs react \"hooks\"` will fail without a valid ID\n- Use descriptive queries, not single words — `\"React useEffect cleanup function\"` not `\"hooks\"`\n- Do not include sensitive information (API keys, passwords, credentials) in queries\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"lib\": [\"ES2022\"],\n    \"moduleResolution\": \"Node16\",\n    \"module\": \"Node16\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true\n  },\n  \"exclude\": [\"node_modules\", \"dist\", \"build\"]\n}\n"
  }
]