0Pricing
AI Agents · 강의

에이전트 플러그인 마켓플레이스 구축

도구를 중앙에서 제공하는 저장소를 만들어 에이전트 플러그인을 게시하고 평가하며 배포합니다.

에이전트 플러그인 마켓플레이스 구축은(는) CoddyKit의 무료 AI Agents 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Agents 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.

에이전트 플러그인 마켓플레이스란 무엇입니까?

플러그인 마켓플레이스는 개발자가 공유 가능한 도구를 게시하고, 다른 개발자가 검색하여 도구를 찾으며, 에이전트 시스템이 도구를 자동으로 설치하는 중앙 레지스트리입니다. 에이전트 도구를 위한 npm이라고 생각하시면 됩니다. 한 번 게시하고 어디서나 사용합니다.

마켓플레이스 아키텍처

마켓플레이스에는 네 가지 주요 서비스가 있습니다. 레지스트리는 데이터베이스에 플러그인 메타데이터를 저장하고, 저장소는 객체 저장소에 플러그인 아카이브를 저장하며, 검색은 전문 검색 색인을 제공하고, 보안은 패키지에 서명하고 서명을 확인합니다. 모든 기능은 REST API를 통해 제공됩니다.

# Marketplace REST API endpoints:
API_ROUTES = {
    'POST /plugins': 'Publish a new plugin version',
    'GET /plugins': 'List all plugins (paginated)',
    'GET /plugins/search?q=weather': 'Search by keyword',
    'GET /plugins/{name}': 'Get plugin metadata',
    'GET /plugins/{name}/{version}': 'Get specific version metadata',
    'GET /plugins/{name}/{version}/download': 'Download plugin archive',
    'POST /plugins/{name}/{version}/reviews': 'Submit a rating/review',
    'GET /plugins/{name}/reviews': 'Get all reviews',
    'DELETE /plugins/{name}/{version}': 'Yank (hide) a version',
}

for route, description in API_ROUTES.items():
    print(f'{route}: {description}')

플러그인 게시

게시 엔드포인트는 플러그인 아카이브를 검증하고, 매니페스트를 확인하며, API 키를 통해 게시자의 신원을 검증하고, 알려진 악성 패턴을 검사하고, 패키지에 서명한 후 저장합니다. 게시 작업은 원자적으로 수행되므로 전체 업로드가 성공하거나 아무것도 저장되지 않습니다.

import hashlib
import hmac
import os

def publish_plugin(
    archive_path: str,
    api_key: str,
    registry_url: str = 'https://registry.agenttools.io'
) -> dict:
    import requests

    # Compute checksum for integrity
    with open(archive_path, 'rb') as f:
        data = f.read()
    sha256 = hashlib.sha256(data).hexdigest()

    # Sign the archive with the developer's API key
    signature = hmac.new(
        api_key.encode(), data, hashlib.sha256
    ).hexdigest()

    response = requests.post(
        f'{registry_url}/plugins',
        files={'archive': (os.path.basename(archive_path), data, 'application/zip')},
        headers={
            'X-API-Key': api_key,
            'X-Signature': signature,
            'X-Checksum-SHA256': sha256
        },
        timeout=60
    )
    response.raise_for_status()
    return response.json()

게시 시 서버 측 검증

레지스트리 서버는 각 제출물을 검증합니다. 매니페스트를 해석할 수 있고 완전한지, 해당 버전이 이미 존재하지 않는지, 아카이브가 크기 제한을 초과하지 않는지, 기본 보안 검사를 통과하는지를 확인합니다. 모든 검사가 완료된 후에만 서버가 업로드를 수락합니다.

import zipfile
import io
import json

MAX_ARCHIVE_SIZE_MB = 50

def validate_plugin_archive(archive_bytes: bytes) -> dict:
    errors = []

    # Size check
    size_mb = len(archive_bytes) / 1024 / 1024
    if size_mb > MAX_ARCHIVE_SIZE_MB:
        errors.append(f'Archive too large: {size_mb:.1f}MB (max {MAX_ARCHIVE_SIZE_MB}MB)')
        return {'valid': False, 'errors': errors}

    # Must be a valid zip
    try:
        zf = zipfile.ZipFile(io.BytesIO(archive_bytes))
    except zipfile.BadZipFile:
        errors.append('Not a valid zip archive')
        return {'valid': False, 'errors': errors}

    file_list = zf.namelist()

    # Must contain plugin.json
    if 'plugin.json' not in file_list:
        errors.append('Missing plugin.json in archive root')

    # Basic security scan: no .pyc files, no hidden dirs
    suspicious = [f for f in file_list if f.startswith('.') or '__pycache__' in f]
    if suspicious:
        errors.append(f'Suspicious files: {suspicious[:3]}')

    return {'valid': len(errors) == 0, 'errors': errors, 'files': len(file_list)}

if __name__ == '__main__':
    buf = io.BytesIO()
    with zipfile.ZipFile(buf, 'w') as zf:
        zf.writestr('plugin.json', '{"name": "demo-plugin"}')
    archive_bytes = buf.getvalue()
    print('Validation result:', validate_plugin_archive(archive_bytes))

패키지 서명 및 검증

게시되는 모든 패키지에 게시자의 키로 서명합니다. 클라이언트는 설치하기 전에 서명을 확인하여 전송 중이나 저장 중에 패키지가 변조되지 않았는지 확인합니다.

import hashlib
import hmac

def sign_package(archive_bytes: bytes, secret_key: str) -> str:
    return hmac.new(
        secret_key.encode(), archive_bytes, hashlib.sha256
    ).hexdigest()

def verify_package(
    archive_bytes: bytes,
    signature: str,
    secret_key: str
) -> bool:
    expected = sign_package(archive_bytes, secret_key)
    return hmac.compare_digest(expected, signature)

# Example:
package_data = b'fake plugin archive bytes'
developer_key = 'developer_secret_key_abc123'

sig = sign_package(package_data, developer_key)
print(f'Signature: {sig[:20]}...')

# Verify (registry or installer):
valid = verify_package(package_data, sig, developer_key)
print(f'Signature valid: {valid}')

# Tampered data:
tampered = b'tampered bytes'
print(f'Tampered valid: {verify_package(tampered, sig, developer_key)}')

검색을 통한 플러그인 찾기

검색 API는 자유 형식의 검색어와 태그 필터를 받습니다. 가중치가 적용된 점수를 사용하여 결과를 순위별로 반환합니다. 정확한 이름 일치가 가장 높은 순위를 차지하고, 그다음은 태그 일치, 설명의 키워드 일치 순입니다.

import requests

def search_marketplace(
    query: str,
    tags: list = None,
    page: int = 0,
    per_page: int = 20,
    registry_url: str = 'https://registry.agenttools.io'
) -> dict:
    params = {
        'q': query,
        'page': page,
        'per_page': per_page
    }
    if tags:
        params['tags'] = ','.join(tags)

    response = requests.get(
        f'{registry_url}/plugins/search',
        params=params,
        timeout=10
    )
    response.raise_for_status()
    return response.json()

# Usage:
results = search_marketplace('weather forecast', tags=['iot', 'weather'])
# {
#   'total': 12,
#   'results': [
#     {'name': 'weather-tools', 'version': '2.1.0', 'score': 0.98, ...},
#     ...
#   ]
# }
print(f'Total results: {results.get("total", 0)}')

플러그인 설치

설치 과정은 다음과 같습니다. 아카이브를 다운로드하고, 서명을 확인하고, 플러그인 디렉터리에 압축을 풀고, 매니페스트를 검증하고, 종속성을 확인한 후, 로컬 도구 레지스트리에 등록합니다. 모든 단계가 성공해야 하며, 그렇지 않으면 설치가 롤백됩니다.

import requests
import zipfile
import io
import shutil
import os

def install_plugin(
    plugin_name: str,
    version: str = 'latest',
    plugins_dir: str = 'plugins',
    registry_url: str = 'https://registry.agenttools.io'
) -> bool:
    # Step 1: Get metadata including expected signature
    meta = requests.get(
        f'{registry_url}/plugins/{plugin_name}/{version}',
        timeout=10
    ).json()

    # Step 2: Download archive
    archive_resp = requests.get(
        meta['download_url'], timeout=60
    )
    archive_bytes = archive_resp.content

    # Step 3: Verify signature
    if not verify_package(archive_bytes, meta['signature'], meta['public_key']):
        print('Signature verification FAILED — aborting install')
        return False

    # Step 4: Extract
    install_path = os.path.join(plugins_dir, plugin_name)
    if os.path.exists(install_path):
        shutil.rmtree(install_path)  # remove old version
    with zipfile.ZipFile(io.BytesIO(archive_bytes)) as zf:
        zf.extractall(install_path)

    print(f'Installed {plugin_name} v{version} to {install_path}')
    return True

평가 및 리뷰 시스템

평가 시스템은 개발자가 품질이 높은 플러그인을 선택하는 데 도움을 줍니다. 1~5개의 별점과 선택적 텍스트 리뷰를 구현합니다. 집계된 평가 데이터(평균, 개수)는 레지스트리에 저장되고 검색 결과에 반환됩니다.

import requests

def submit_review(
    plugin_name: str,
    stars: int,
    review_text: str = '',
    api_key: str = '',
    registry_url: str = 'https://registry.agenttools.io'
) -> dict:
    if not 1 <= stars <= 5:
        raise ValueError('Stars must be 1-5')
    payload = {
        'stars': stars,
        'review': review_text[:500]  # truncate to max length
    }
    response = requests.post(
        f'{registry_url}/plugins/{plugin_name}/reviews',
        json=payload,
        headers={'X-API-Key': api_key},
        timeout=10
    )
    response.raise_for_status()
    return response.json()

def get_reviews(plugin_name: str, registry_url: str = 'https://registry.agenttools.io') -> dict:
    response = requests.get(
        f'{registry_url}/plugins/{plugin_name}/reviews',
        timeout=10
    )
    return response.json()

# Example response structure:
# {'average_stars': 4.3, 'total_reviews': 47,
#  'reviews': [{'stars': 5, 'review': 'Works great!', 'date': '...'}]}
print('Review system ready')

버전 얀크(사용 중단)

게시된 버전에 치명적인 버그나 보안 취약성이 있는 경우 해당 버전을 얀크합니다. 즉, 레지스트리에서 숨김 상태로 표시하여 새 설치에서 사용할 수 없게 하지만 기존 설치는 계속 작동하도록 합니다. 이렇게 하는 것이 기존 에이전트를 중단시킬 수 있는 삭제보다 안전합니다.

import requests

def yank_version(
    plugin_name: str,
    version: str,
    reason: str,
    api_key: str,
    registry_url: str = 'https://registry.agenttools.io'
) -> dict:
    response = requests.delete(
        f'{registry_url}/plugins/{plugin_name}/{version}',
        json={'reason': reason},
        headers={'X-API-Key': api_key},
        timeout=10
    )
    response.raise_for_status()
    return response.json()

# Yanked versions:
# - Still downloadable by users who have them pinned
# - Not returned in 'latest' queries
# - Search results show a 'yanked' badge with reason
# - Install of yanked version requires explicit --allow-yanked flag

print('Yanking removes a version from new installs without breaking existing ones.')
print('Always provide a reason: "Security vulnerability in API key handling"')

마켓플레이스 명령줄 도구

명령줄 인터페이스를 사용하면 터미널이나 CI 파이프라인에서 마켓플레이스를 쉽게 이용할 수 있습니다. marketplace install, marketplace search, marketplace publish, marketplace list 명령을 구현합니다.

import argparse
import sys

def main():
    parser = argparse.ArgumentParser(description='Agent Tool Marketplace CLI')
    subparsers = parser.add_subparsers(dest='command')

    # Search
    search_parser = subparsers.add_parser('search', help='Search plugins')
    search_parser.add_argument('query', help='Search query')
    search_parser.add_argument('--tag', action='append', dest='tags')

    # Install
    install_parser = subparsers.add_parser('install', help='Install a plugin')
    install_parser.add_argument('plugin', help='Plugin name')
    install_parser.add_argument('--version', default='latest')
    install_parser.add_argument('--plugins-dir', default='plugins')

    # Publish
    publish_parser = subparsers.add_parser('publish', help='Publish plugin')
    publish_parser.add_argument('archive', help='Path to .zip archive')
    publish_parser.add_argument('--api-key', required=True)

    args = parser.parse_args()
    if args.command == 'search':
        results = search_marketplace(args.query, tags=args.tags or [])
        for r in results.get('results', []):
            print(f'{r["name"]} v{r["version"]} ({r.get("average_stars", "?")} stars)')
    elif args.command == 'install':
        install_plugin(args.plugin, args.version, args.plugins_dir)
    elif args.command == 'publish':
        result = publish_plugin(args.archive, args.api_key)
        print('Published:', result)

마켓플레이스 거버넌스

공개 마켓플레이스에는 이름 공간 지정(이름 선점을 방지하기 위한 규칙), 콘텐츠 조정(악성 코드 금지), 보안 검사(업로드 시 정적 분석), 게시 중단 절차(법적 사건이나 보안 사고에 대응하기 위한 절차)와 같은 거버넌스 규칙이 필요합니다. 이러한 문제는 기술적인 문제인 동시에 조직적인 문제이기도 합니다.

MARKETPLACE_POLICIES = {
    'namespace_policy': (
        'Plugin names must be unique across the registry. '
        'Names are claimed on first publish. '
        'Transfers require proof of original authorship.'
    ),
    'security_scanning': (
        'All uploads are scanned with bandit (Python security linter). '
        'Critical vulnerabilities block publish. '
        'High vulnerabilities generate a warning visible to installers.'
    ),
    'rate_limits': {
        'publish_per_hour': 10,
        'search_per_minute': 60,
        'install_per_minute': 30
    },
    'takedown_process': (
        'Maintainers can yank versions at any time. '
        'Legal/security takedowns processed within 48 hours. '
        'Appeals via security@agenttools.io'
    )
}

for policy, detail in MARKETPLACE_POLICIES.items():
    if isinstance(detail, str):
        print(f'{policy}: {detail[:80]}...')
    else:
        print(f'{policy}: {detail}')

지식 확인

플러그인 버전을 얀크하는 것과 삭제하는 것의 차이는 무엇입니까?

복습: 에이전트 플러그인 마켓플레이스 구축

이번 단원을 완료하신 것을 축하합니다! 핵심 내용은 다음과 같습니다.

  • 게시 파이프라인: 아카이브 검증 → 서명 확인 → 검사 → 저장 및 색인
  • 패키지 서명: HMAC 서명이 무결성을 보장하며, 클라이언트는 설치 전에 이를 확인합니다
  • 검색: 태그 필터링과 관련성 순위를 지원하는 전문 검색
  • 설치: 다운로드 → 확인 → 압축 해제 → 검증 → 등록(실패 시 롤백)
  • 평가: 1~5개의 별점과 텍스트 리뷰를 레지스트리에서 집계합니다
  • 얀크: 기존 설치를 중단하지 않고 새 설치에서 숨깁니다

마지막 과정은 자율 시스템으로 가는 길입니다.

자주 묻는 질문

“에이전트 플러그인 마켓플레이스 구축” 강의는 무료인가요?

네 — “에이전트 플러그인 마켓플레이스 구축” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Agents 강의 전체를 잠금 해제할 수 있습니다. AI Agents 강의에는 총 4개의 강의가 포함되어 있습니다.

“에이전트 플러그인 마켓플레이스 구축”에서 뭘 배우나요?

도구를 중앙에서 제공하는 저장소를 만들어 에이전트 플러그인을 게시하고 평가하며 배포합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Agents을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Agents을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Agents은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“에이전트 플러그인 마켓플레이스 구축” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Agents 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Agents 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 공유 가능한 에이전트 도구 설계
  2. 플러그인 검색 및 등록
  3. 도구 버전 관리 및 호환성
  4. 에이전트 플러그인 마켓플레이스 구축
← AI Agents(으)로 돌아가기