Skip to content
ioob.dev
Go back

Claude Code 플러그인과 마켓플레이스 — 직접 만들고 배포하기

· 9분 읽기
Table of contents

Table of contents

왜 패키지인가

Claude Code에 자기 작업 환경을 박아 넣는 방법은 처음엔 단순했다. ~/.claude/ 밑에 스킬과 훅을 흩뿌리거나, 프로젝트 루트의 .claude/에 챙겨두는 식이다. 혼자 쓰는 동안엔 충분하다. 그런데 팀에 공유하려고 하면 갑자기 일이 된다. “그 폴더 복사해서 깔아라”가 안내의 전부고, 버전이 다르면 누구 환경에서는 동작하고 누구는 안 된다.

플러그인은 이 문제를 정면으로 푼다. 스킬, 에이전트, 훅, MCP 서버, LSP 서버를 한 묶음의 디렉토리로 패키징하고, 매니페스트 한 장으로 식별한다. 마켓플레이스는 그 묶음들을 모아 두는 카탈로그다. 사용자는 /plugin install 한 줄로 받아 가고, 작성자가 새 버전을 푸시하면 자동 업데이트가 흐른다.

flowchart LR
    classDef src fill:#5ca45c,color:#fff,stroke:#3d7740
    classDef mkt fill:#4a90d9,color:#fff,stroke:#2c5d8f
    classDef user fill:#d4943a,color:#fff,stroke:#9c6a26

    Dev[작성자]:::src
    Plugin[플러그인 디렉토리<br/>.claude-plugin/plugin.json]:::src
    MP[마켓플레이스<br/>.claude-plugin/marketplace.json]:::mkt
    GH[GitHub 리포]:::mkt
    User[사용자]:::user

    Dev --> Plugin
    Plugin --> MP
    MP --> GH
    GH -->|/plugin marketplace add| User
    User -->|/plugin install| Plugin

이 글은 플러그인 한 개 만들기부터 마켓플레이스에 올려 배포까지를 한 흐름으로 따라간다. 공식 문서는 분리돼 있지만, 실제로는 한 번에 익히는 게 자연스럽다.

디렉토리 한 장 — 플러그인의 정체

플러그인은 디렉토리다. 그 안에 .claude-plugin/plugin.json 한 파일이 있으면 Claude Code가 그걸 플러그인으로 인식한다. 나머지는 컴포넌트다.

my-plugin/
├── .claude-plugin/
│   └── plugin.json          ← 매니페스트 (필수)
├── skills/
│   └── hello/
│       └── SKILL.md         ← 슬래시 커맨드형 스킬
├── agents/                  ← 서브에이전트 정의
├── hooks/
│   └── hooks.json           ← 이벤트 훅
├── .mcp.json                ← MCP 서버
├── .lsp.json                ← LSP 서버
├── monitors/
│   └── monitors.json        ← 백그라운드 모니터
├── bin/                     ← 활성화 시 PATH에 붙는 실행 파일
└── settings.json            ← 기본 설정

쉽게 말해, 플러그인은 Claude Code 확장의 표준 박스 규격이다. USB-C에 어댑터·케이블·도크가 다 꽂히듯, 한 박스 안에 스킬·에이전트·훅·MCP가 같은 규약으로 들어간다.

자주 하는 실수 하나. commands/, agents/, skills/, hooks/.claude-plugin/ 안에 두지 않는다. .claude-plugin/에는 plugin.json만 들어가고, 나머지 디렉토리는 모두 플러그인 루트에 둔다.

가장 작은 플러그인 만들기

스킬 하나가 들어있는 플러그인을 처음부터 만들어 본다. 디렉토리부터 시작한다.

mkdir -p my-first-plugin/.claude-plugin
mkdir -p my-first-plugin/skills/hello

매니페스트 한 장을 적는다.

// my-first-plugin/.claude-plugin/plugin.json
{
  "name": "my-first-plugin",
  "description": "인사 스킬 — 플러그인 구조를 익히는 최소 예제",
  "version": "1.0.0",
  "author": { "name": "Your Name" }
}
필드의미
name식별자이자 스킬 네임스페이스. 스킬은 /my-first-plugin:hello처럼 노출된다
description플러그인 매니저에서 보이는 한 줄 설명
version명시하면 이 값이 바뀔 때만 업데이트가 흐른다. 생략 시 git commit SHA가 버전 역할
author선택. 표시용

스킬을 추가한다. 폴더 이름이 곧 스킬 이름이다.

<!-- my-first-plugin/skills/hello/SKILL.md -->
---
description: 사용자를 따뜻하게 인사하고 도울 일이 있는지 물어본다
---

"$ARGUMENTS"라는 이름의 사용자를 따뜻하게 인사하고, 오늘 어떻게 도와줄 수 있는지 물어봐.

여기서 $ARGUMENTS가 슬래시 커맨드 뒤에 붙는 인자를 받아 준다.

로컬에서 바로 테스트한다. 설치 없이 디렉토리만 가리키면 된다.

claude --plugin-dir ./my-first-plugin

Claude Code가 켜지면 스킬이 네임스페이스 붙은 이름으로 잡힌다.

/my-first-plugin:hello Alex

스킬을 고쳤다면 /reload-plugins로 새로고침할 수 있다. 재시작이 필요 없다.

다른 컴포넌트 얹기

스킬만 들어있는 플러그인은 시작점이고, 실제 쓸 만한 묶음은 보통 에이전트까지 같이 들어간다. 두 가지를 짧게 본다.

훅 — 이벤트에 자동 반응

hooks/hooks.json에 이벤트 핸들러를 적는다. 형식은 .claude/settings.jsonhooks 객체와 동일하다.

// my-first-plugin/hooks/hooks.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs prettier --write"
          }
        ]
      }
    ]
  }
}

Edit이나 Write 호출 직후, 수정된 파일에 prettier가 돌아간다. 명령은 stdin으로 훅 입력 JSON을 받으므로 jq로 파일 경로를 뽑아 쓴다.

에이전트 — 컨텍스트 격리된 서브 인스턴스

agents/ 밑에 마크다운 파일을 두면, 그 정의가 서브에이전트로 잡힌다.

<!-- my-first-plugin/agents/security-reviewer.md -->
---
name: security-reviewer
description: PR diff를 OWASP 체크리스트 기준으로 본다
tools: [Read, Grep, Bash]
---

당신은 보안 리뷰어다. 입력으로 받은 diff에서
1. 인증·인가 우회
2. 입력 검증 부재
3. 민감 데이터 노출
4. 안전하지 않은 의존성 호출
네 가지만 본다. 다른 영역은 다른 리뷰어가 본다.

/agents에서 이 에이전트가 잡히는지 확인할 수 있다.

MCP 서버 — 외부 서비스 연결

플러그인 루트의 .mcp.json에 MCP 서버를 적어 두면, 플러그인이 활성화될 때 같이 붙는다.

// my-first-plugin/.mcp.json
{
  "mcpServers": {
    "issue-tracker": {
      "command": "npx",
      "args": ["-y", "@my-org/issue-tracker-mcp"]
    }
  }
}

스킬·훅·MCP가 한 박스 안에서 같이 움직이는 게 플러그인의 본질이다. 배포 플러그인이라면 /deploy 스킬, 스테이징 상태를 보는 MCP, 배포 전 테스트 돌리는 훅이 한 번에 들어가 있다.

마켓플레이스 — 플러그인의 카탈로그

플러그인 하나만 쓸 거면 --plugin-dir로 끝이다. 하지만 팀에 뿌리거나 커뮤니티에 공유하려면 카탈로그가 필요하다. 카탈로그는 marketplace.json 한 파일이다.

리포 구조는 보통 이렇게 잡는다.

my-marketplace/
├── .claude-plugin/
│   └── marketplace.json           ← 카탈로그 (필수)
└── plugins/
    ├── quality-review-plugin/
    │   ├── .claude-plugin/
    │   │   └── plugin.json
    │   └── skills/
    │       └── quality-review/
    │           └── SKILL.md
    └── deploy-plugin/
        └── ...

마켓플레이스 매니페스트는 어떤 플러그인이 들어있고, 각각을 어디서 가져오는지를 기록한다.

// my-marketplace/.claude-plugin/marketplace.json
{
  "name": "my-plugins",
  "owner": {
    "name": "Your Name",
    "email": "you@example.com"
  },
  "plugins": [
    {
      "name": "quality-review-plugin",
      "source": "./plugins/quality-review-plugin",
      "description": "코드 품질 리뷰 스킬"
    },
    {
      "name": "deployment-tools",
      "source": {
        "source": "github",
        "repo": "your-org/deploy-plugin",
        "ref": "v1.2.0"
      },
      "description": "배포 자동화 도구"
    }
  ]
}

이름이 살짝 헷갈리는 두 개념을 정리해 둔다.

둘은 다른 리포를 가리킬 수 있다. 카탈로그는 acme-corp/plugin-catalog에 있고, 그 안에 적힌 플러그인은 acme-corp/code-formatter에서 가져오는 식이다.

플러그인 소스로 쓸 수 있는 타입은 다섯 가지다.

소스형식비고
상대 경로"./plugins/foo"마켓플레이스 리포 안의 디렉토리. ../로 바깥 참조 불가
github{ source: "github", repo, ref?, sha? }가장 흔한 형태
url{ source: "url", url, ref?, sha? }GitLab/Bitbucket 등 임의 git URL
git-subdir{ source: "git-subdir", url, path }모노레포의 한 디렉토리만 sparse clone
npm{ source: "npm", package, version? }npm 패키지로 받기

배포 — GitHub에 푸시하고 끝

마켓플레이스 리포를 GitHub에 푸시한다. 그게 끝이다. 사용자는 한 줄로 카탈로그를 등록하고, 또 한 줄로 플러그인을 설치한다.

# 사용자 입장
/plugin marketplace add your-org/my-marketplace
/plugin install quality-review-plugin@my-plugins

your-org/my-marketplace는 GitHub owner/repo 표기. 자체 호스팅 GitLab이면 풀 URL을 쓴다.

/plugin marketplace add https://gitlab.com/company/plugins.git
/plugin marketplace add https://gitlab.com/company/plugins.git#v1.0.0  # 특정 ref

로컬 개발 중에는 마켓플레이스도 디렉토리로 바로 붙일 수 있다.

/plugin marketplace add ./my-marketplace

설치 후 /plugin을 실행하면 탭형 매니저가 뜬다. Tab으로 Discover · Installed · Marketplaces · Errors 네 탭을 오간다. 설치한 플러그인을 끄고 켜고, 즐겨찾기를 표시하고, 로드 에러를 확인하는 곳이다.

Claude Code의 /plugin Manage Plugins 화면 출처: Plugins for Claude Code and Cowork — Anthropic 공식 블로그

위 스크린샷은 claude-code-marketplace에서 code-review · typescript-lsp · security-guidance 세 플러그인을 받아 둔 상태다. Space로 활성/비활성을 토글하고, u로 업데이트 표시, Delete로 제거 표시를 해 둔 뒤 한 번에 처리한다.

운영에서 알아둘 것 — 스코프·버전·strict

배포까지 끝났으면 어떻게 굴릴지가 남는다. 세 가지만 알면 된다.

설치 스코프. 사용자가 플러그인을 받을 때 세 가지 중 하나를 고른다.

스코프의미
User내 모든 프로젝트에서 활성 (기본값)
Project이 리포의 모든 협업자에게 배포 (.claude/settings.json에 기록되어 PR로 공유)
Local이 리포에서 나만 활성

팀 공통 도구라면 프로젝트 스코프가 자연스럽다. 협업자가 리포를 신뢰하는 순간 설치가 자동 제안된다.

// .claude/settings.json
{
  "extraKnownMarketplaces": {
    "my-team-tools": {
      "source": { "source": "github", "repo": "your-org/claude-plugins" }
    }
  }
}

버전 관리. plugin.jsonversion 필드를 적느냐 안 적느냐로 동작이 갈린다. 명시하면 그 값이 바뀔 때만 업데이트가 흐르고, 생략하면 git 호스팅 환경에서 모든 커밋이 새 버전이 된다. 릴리스 노트를 따로 관리할 거면 명시하는 쪽이 깔끔하다.

strict 모드. marketplace.json의 플러그인 엔트리에 strict: false를 두면 플러그인 리포에 plugin.json이 없어도 동작한다. 외부 리포를 자기 마켓플레이스에서 얇게 감싸 노출할 때 쓴다. 기본값은 true이고, 자기가 작성하는 플러그인은 그대로 두는 게 안전하다.

{
  "name": "external-tool",
  "source": { "source": "github", "repo": "third-party/tool" },
  "description": "외부 도구를 우리 마켓플레이스에서 감싸 노출",
  "strict": false,
  "skills": "./skills",
  "version": "1.0.0"
}

공식 마켓플레이스 — Anthropic이 직접 관리하는 곳

claude-plugins-official은 Claude Code가 시작될 때 자동으로 따라붙는 공식 카탈로그다. /plugin의 Discover 탭에서 바로 보인다.

여기엔 Anthropic이 직접 또는 파트너십으로 검수한 플러그인들이 들어 있다. 자주 쓰이는 묶음은 대체로 이 다섯 갈래다.

분류예시
Code Intelligencetypescript-lsp, pyright-lsp, gopls-lsp 등 LSP 통합
External Integrationgithub, gitlab, linear, figma, sentry
Development Workflowcommit-commands, pr-review-toolkit, plugin-dev
Output Styleexplanatory-output-style, learning-output-style
사내 통합용 MCP조직 단위 배포 도구

자기 플러그인을 공식 마켓플레이스에 올리고 싶다면 두 가지 경로가 있다. 직접 자기 마켓플레이스를 운영하면서 사용자가 add 하게 두거나, 공식 디렉토리에 제출하거나. 후자는 claude.ai/settings/plugins/submit 또는 platform.claude.com/plugins/submit에서 폼으로 제출한다.

디버깅이 안 될 때

--plugin-dir로 띄운 로컬 플러그인은 같은 이름의 설치된 플러그인보다 우선한다. 마켓플레이스에 올린 플러그인을 수정 중일 때 uninstall 없이 그 위에 덮어 테스트할 수 있다.

마무리

플러그인은 결국 디렉토리 하나고, 마켓플레이스는 그 디렉토리들의 목록이다. 구조만 익히면 만드는 데 한 시간이 안 걸리고, 한 번 만들면 팀 전체가 같은 환경 위에서 움직인다.

처음 시작할 만한 자리는 보통 이렇다. 내가 같은 SKILL.md 설정을 두 번째 프로젝트에서 또 꺼냈을 때. 거기서부터 .claude/my-plugin/으로 옮기고, plugin.json을 한 장 적고, 다음번엔 그 옆의 동료가 한 줄로 받아 간다. 그렇게 도구가 내 환경에서 팀의 환경으로 옮겨간다.

참고 자료


Related Posts

Share this post on:

Comments

Loading comments...


Previous Post
Context Rot — 1M 토큰 컨텍스트 윈도우의 진짜 한계 (2026)
Next Post
Karpathy의 LLM Wiki — RAG 다음의 지식 베이스 패턴