ltcai 3.5.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -35
- package/docs/CARRYOVER_AUDIT_v3.6.0.md +61 -0
- package/docs/CHANGELOG.md +32 -0
- package/docs/HANDOVER_v3.6.0.md +46 -0
- package/docs/RUNTIME_HOOK_COVERAGE_v3.6.0.md +49 -0
- package/docs/V4_BRAIN_ARCHITECTURE.md +322 -0
- package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +509 -0
- package/docs/V4_IMPLEMENTATION_PLAN.md +470 -0
- package/docs/architecture.md +13 -12
- package/docs/kg-schema.md +102 -53
- package/docs/privacy.md +18 -2
- package/docs/security-model.md +17 -0
- package/kg_schema.py +139 -10
- package/knowledge_graph.py +874 -26
- package/knowledge_graph_api.py +11 -127
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/admin.py +1 -1
- package/latticeai/api/agents.py +7 -1
- package/latticeai/api/auth.py +27 -4
- package/latticeai/api/browser.py +217 -0
- package/latticeai/api/chat.py +112 -76
- package/latticeai/api/health.py +1 -1
- package/latticeai/api/hooks.py +1 -1
- package/latticeai/api/knowledge_graph.py +146 -0
- package/latticeai/api/local_files.py +1 -1
- package/latticeai/api/mcp.py +23 -11
- package/latticeai/api/memory.py +1 -1
- package/latticeai/api/models.py +1 -1
- package/latticeai/api/network.py +81 -0
- package/latticeai/api/portability.py +93 -0
- package/latticeai/api/realtime.py +1 -1
- package/latticeai/api/search.py +26 -2
- package/latticeai/api/security_dashboard.py +2 -3
- package/latticeai/api/setup.py +2 -2
- package/latticeai/api/static_routes.py +2 -4
- package/latticeai/api/tools.py +3 -0
- package/latticeai/api/workflow_designer.py +46 -0
- package/latticeai/api/workspace.py +71 -49
- package/latticeai/app_factory.py +1710 -0
- package/latticeai/brain/__init__.py +18 -0
- package/latticeai/brain/context.py +213 -0
- package/latticeai/brain/conversations.py +236 -0
- package/latticeai/brain/identity.py +175 -0
- package/latticeai/brain/memory.py +102 -0
- package/latticeai/brain/network.py +205 -0
- package/latticeai/core/agent.py +31 -7
- package/latticeai/core/audit.py +0 -7
- package/latticeai/core/config.py +1 -1
- package/latticeai/core/context_builder.py +1 -2
- package/latticeai/core/enterprise.py +1 -1
- package/latticeai/core/graph_curator.py +2 -2
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/mcp_registry.py +791 -0
- package/latticeai/core/model_compat.py +1 -1
- package/latticeai/core/model_resolution.py +0 -1
- package/latticeai/core/multi_agent.py +238 -4
- package/latticeai/core/security.py +1 -1
- package/latticeai/core/sessions.py +37 -7
- package/latticeai/core/workflow_engine.py +114 -2
- package/latticeai/core/workspace_os.py +58 -10
- package/latticeai/models/__init__.py +7 -0
- package/latticeai/models/router.py +779 -0
- package/latticeai/server_app.py +29 -1504
- package/latticeai/services/agent_runtime.py +1 -0
- package/latticeai/services/app_context.py +75 -14
- package/latticeai/services/ingestion.py +318 -0
- package/latticeai/services/kg_portability.py +207 -0
- package/latticeai/services/memory_service.py +39 -11
- package/latticeai/services/model_runtime.py +2 -5
- package/latticeai/services/platform_runtime.py +100 -23
- package/latticeai/services/search_service.py +17 -8
- package/latticeai/services/tool_dispatch.py +12 -2
- package/latticeai/services/triggers.py +241 -0
- package/latticeai/services/upload_service.py +37 -12
- package/latticeai/services/workspace_service.py +31 -0
- package/llm_router.py +29 -772
- package/ltcai_cli.py +1 -2
- package/mcp_registry.py +25 -788
- package/p_reinforce.py +124 -14
- package/package.json +11 -8
- package/scripts/build_vsix.mjs +72 -0
- package/scripts/bump_version.py +99 -0
- package/scripts/generate_diagrams.py +0 -1
- package/scripts/lint_v3.mjs +82 -18
- package/scripts/validate_release_artifacts.py +0 -1
- package/scripts/wheel_smoke.py +142 -0
- package/server.py +11 -7
- package/setup_wizard.py +1142 -0
- package/static/account.html +2 -4
- package/static/admin.html +3 -5
- package/static/chat.html +3 -6
- package/static/graph.html +2 -4
- package/static/sw.js +81 -52
- package/static/v3/asset-manifest.json +20 -19
- package/static/v3/css/{lattice.base.e4cdd05d.css → lattice.base.49deefb5.css} +1 -1
- package/static/v3/css/lattice.base.css +1 -1
- package/static/v3/css/{lattice.components.9b49d614.css → lattice.components.cde18231.css} +1 -1
- package/static/v3/css/lattice.components.css +1 -1
- package/static/v3/css/{lattice.shell.8fcc9d33.css → lattice.shell.29d36d85.css} +1 -1
- package/static/v3/css/lattice.shell.css +1 -1
- package/static/v3/css/{lattice.tokens.e7018963.css → lattice.tokens.304cbc40.css} +3 -0
- package/static/v3/css/lattice.tokens.css +3 -0
- package/static/v3/css/{lattice.views.22f69117.css → lattice.views.0a18b6c5.css} +2 -2
- package/static/v3/css/lattice.views.css +2 -2
- package/static/v3/index.html +3 -4
- package/static/v3/js/{app.d086489d.js → app.356e6452.js} +1 -1
- package/static/v3/js/core/{api.12b568ad.js → api.7a308b89.js} +39 -1
- package/static/v3/js/core/api.js +38 -0
- package/static/v3/js/core/{routes.d214b399.js → routes.7222343d.js} +22 -22
- package/static/v3/js/core/routes.js +22 -22
- package/static/v3/js/core/{shell.d05266f5.js → shell.a1657f20.js} +4 -4
- package/static/v3/js/core/shell.js +1 -1
- package/static/v3/js/core/{store.34ebd5e6.js → store.204a08b2.js} +1 -1
- package/static/v3/js/core/store.js +1 -1
- package/static/v3/js/views/graph-canvas.17c15d65.js +509 -0
- package/static/v3/js/views/graph-canvas.js +509 -0
- package/static/v3/js/views/{hybrid-search.b22b97e0.js → hybrid-search.2fb63ed9.js} +1 -2
- package/static/v3/js/views/hybrid-search.js +1 -2
- package/static/v3/js/views/knowledge-graph.5e40cbeb.js +509 -0
- package/static/v3/js/views/knowledge-graph.js +326 -54
- package/static/vendor/chart.umd.min.js +20 -0
- package/static/vendor/fonts/inter-latin-300-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-400-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-500-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-600-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-700-normal.woff2 +0 -0
- package/static/vendor/fonts/inter-latin-800-normal.woff2 +0 -0
- package/static/vendor/fonts/inter.css +44 -0
- package/static/vendor/icons/tabler-icons.min.css +4 -0
- package/static/vendor/icons/tabler-icons.woff2 +0 -0
- package/static/vendor/marked.min.js +69 -0
- package/static/workspace.html +2 -2
- package/telegram_bot.py +1 -2
- package/tools/commands.py +4 -2
- package/tools/computer.py +1 -1
- package/tools/documents.py +1 -3
- package/tools/filesystem.py +0 -4
- package/tools/knowledge.py +1 -3
- package/tools/network.py +1 -3
- package/codex_telegram_bot.py +0 -195
- package/docs/assets/v3.4.0/agent-run.png +0 -0
- package/docs/assets/v3.4.0/agents.png +0 -0
- package/docs/assets/v3.4.0/before/chat-before.png +0 -0
- package/docs/assets/v3.4.0/before/files-before.png +0 -0
- package/docs/assets/v3.4.0/chat.png +0 -0
- package/docs/assets/v3.4.0/connect-folder.png +0 -0
- package/docs/assets/v3.4.0/files.png +0 -0
- package/docs/assets/v3.4.0/home.png +0 -0
- package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
- package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
- package/docs/assets/v3.4.0/local-agent.png +0 -0
- package/docs/assets/v3.4.0/memory.png +0 -0
- package/docs/assets/v3.4.0/settings.png +0 -0
- package/docs/assets/v3.4.0/vision-input.png +0 -0
- package/docs/assets/v3.4.0/workflows.png +0 -0
- package/docs/assets/v3.4.1/e2e_runtime_log.txt +0 -42
- package/docs/assets/v3.4.1/hooks-dispatch.png +0 -0
- package/docs/assets/v3.4.1/local-agent.png +0 -0
- package/docs/images/admin-dashboard.png +0 -0
- package/docs/images/architecture.png +0 -0
- package/docs/images/enterprise.png +0 -0
- package/docs/images/graph.png +0 -0
- package/docs/images/hero.gif +0 -0
- package/docs/images/knowledge-graph.png +0 -0
- package/docs/images/lattice-ai-demo.gif +0 -0
- package/docs/images/lattice-ai-hero.png +0 -0
- package/docs/images/logo.svg +0 -33
- package/docs/images/mobile-responsive.png +0 -0
- package/docs/images/model-recommendation.png +0 -0
- package/docs/images/onboarding.png +0 -0
- package/docs/images/organization.png +0 -0
- package/docs/images/pipeline.png +0 -0
- package/docs/images/screenshot-admin.png +0 -0
- package/docs/images/screenshot-chat.png +0 -0
- package/docs/images/screenshot-graph.png +0 -0
- package/docs/images/skills.png +0 -0
- package/docs/images/workspace-dark.png +0 -0
- package/docs/images/workspace-light.png +0 -0
- package/docs/images/workspace.png +0 -0
- package/requirements.txt +0 -16
- package/static/v3/js/views/knowledge-graph.a14ea7e7.js +0 -237
package/mcp_registry.py
CHANGED
|
@@ -1,791 +1,28 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Lattice AI — MCP Registry data & pure helper functions.
|
|
3
|
-
|
|
4
|
-
Extracted from server.py to reduce module size.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import json
|
|
8
|
-
import logging
|
|
9
|
-
from datetime import datetime, timedelta
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from typing import Dict, List, Optional
|
|
12
|
-
|
|
13
|
-
import httpx
|
|
14
|
-
from fastapi import HTTPException
|
|
15
|
-
|
|
16
|
-
# ── MCP Registry (built-in tool definitions) ─────────────────────────────────
|
|
17
|
-
|
|
18
|
-
MCP_REGISTRY = [
|
|
19
|
-
{
|
|
20
|
-
"id": "presentations",
|
|
21
|
-
"name": "Presentations MCP",
|
|
22
|
-
"category": "PPT / slides",
|
|
23
|
-
"install_mode": "bundled",
|
|
24
|
-
"description": "PowerPoint, Google Slides용 발표자료를 만들고 렌더링 검수까지 이어갑니다.",
|
|
25
|
-
"keywords": ["ppt", "powerpoint", "slides", "slide", "deck", "presentation", "발표", "피피티", "프레젠테이션", "슬라이드", "제안서"],
|
|
26
|
-
"capabilities": ["PPTX 생성", "슬라이드 구조화", "차트 중심 스토리", "렌더링 검수"],
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"id": "documents",
|
|
30
|
-
"name": "Documents MCP",
|
|
31
|
-
"category": "Docs / reports",
|
|
32
|
-
"install_mode": "bundled",
|
|
33
|
-
"description": "Word 문서, 보고서, 계약서 초안, 문서 redline 및 시각 검수를 처리합니다.",
|
|
34
|
-
"keywords": ["docx", "word", "docs", "document", "report", "문서", "보고서", "계약서", "기획서", "레포트"],
|
|
35
|
-
"capabilities": ["DOCX 생성", "문서 편집", "코멘트/수정", "PDF 렌더 확인"],
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"id": "spreadsheets",
|
|
39
|
-
"name": "Spreadsheets MCP",
|
|
40
|
-
"category": "Sheets / data",
|
|
41
|
-
"install_mode": "bundled",
|
|
42
|
-
"description": "Excel/CSV/Google Sheets형 데이터 분석, 수식, 표, 차트를 만듭니다.",
|
|
43
|
-
"keywords": ["xlsx", "excel", "spreadsheet", "sheet", "csv", "data", "엑셀", "스프레드시트", "표", "데이터", "차트"],
|
|
44
|
-
"capabilities": ["XLSX 생성", "수식/서식", "데이터 분석", "차트"],
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"id": "browser",
|
|
48
|
-
"name": "Browser MCP",
|
|
49
|
-
"category": "Web / dashboard QA",
|
|
50
|
-
"install_mode": "bundled",
|
|
51
|
-
"description": "로컬 웹앱, 대시보드, 폼, 페이지 렌더링을 브라우저에서 확인합니다.",
|
|
52
|
-
"keywords": ["dashboard", "web", "website", "frontend", "ui", "browser", "localhost", "대시보드", "웹", "사이트", "프론트", "화면", "검수"],
|
|
53
|
-
"capabilities": ["로컬 페이지 열기", "스크린샷", "DOM 검사", "UI 회귀 확인"],
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
"id": "chrome",
|
|
57
|
-
"name": "Chrome MCP",
|
|
58
|
-
"category": "Browser / authenticated web",
|
|
59
|
-
"install_mode": "connector",
|
|
60
|
-
"connector_url": "/mcp/connectors/chrome",
|
|
61
|
-
"external_url": "codex://plugins/chrome",
|
|
62
|
-
"description": "사용자 Chrome 프로필, 로그인 세션, 기존 탭을 활용하는 브라우저 자동화 브리지입니다.",
|
|
63
|
-
"keywords": ["chrome", "browser", "cookie", "session", "login", "크롬", "브라우저", "로그인", "세션", "탭"],
|
|
64
|
-
"capabilities": ["Chrome 탭 확인", "로그인 세션 활용", "프로필 기반 웹 자동화"],
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"id": "computer-use",
|
|
68
|
-
"name": "내 컴퓨터 MCP",
|
|
69
|
-
"category": "Desktop / Mac UI",
|
|
70
|
-
"install_mode": "connector",
|
|
71
|
-
"connector_url": "/mcp/connectors/computer-use",
|
|
72
|
-
"external_url": "codex://plugins/computer-use",
|
|
73
|
-
"description": "사용자의 허용을 받아 이 컴퓨터의 파일, 화면, 앱 작업을 돕는 브리지입니다.",
|
|
74
|
-
"keywords": ["computer use", "desktop", "mac", "click", "type", "scroll", "내 컴퓨터", "컴퓨터", "맥", "앱", "클릭", "타이핑"],
|
|
75
|
-
"capabilities": ["Mac 앱 UI 조작", "스크린샷 기반 상태 확인", "클릭/입력/스크롤"],
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
"id": "filesystem",
|
|
79
|
-
"name": "Workspace Files MCP",
|
|
80
|
-
"category": "Files / coding",
|
|
81
|
-
"install_mode": "builtin",
|
|
82
|
-
"description": "프로젝트 파일 읽기/쓰기, 검색, 코드 생성, 로컬 preview URL 생성을 수행합니다.",
|
|
83
|
-
"keywords": ["code", "coding", "file", "folder", "project", "build", "deploy", "구현", "코드", "파일", "폴더", "프로젝트", "빌드", "배포"],
|
|
84
|
-
"capabilities": ["파일 생성", "코드 검색", "빌드 스크립트", "배포 스크립트"],
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
"id": "google-drive",
|
|
88
|
-
"name": "Google Drive Connector",
|
|
89
|
-
"category": "File sharing",
|
|
90
|
-
"install_mode": "connector",
|
|
91
|
-
"connector_url": "/mcp/connectors/google-drive",
|
|
92
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
93
|
-
"description": "Drive/Docs/Sheets/Slides 파일 공유, 검색, 협업 워크플로에 사용합니다.",
|
|
94
|
-
"keywords": ["share", "sharing", "drive", "google drive", "file share", "공유", "파일공유", "드라이브", "구글드라이브", "협업"],
|
|
95
|
-
"capabilities": ["파일 공유", "Drive 검색", "Google Docs/Sheets/Slides 연결"],
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"id": "github",
|
|
99
|
-
"name": "GitHub Connector",
|
|
100
|
-
"category": "Code hosting",
|
|
101
|
-
"install_mode": "connector",
|
|
102
|
-
"connector_url": "/mcp/connectors/github",
|
|
103
|
-
"external_url": "https://github.com/apps",
|
|
104
|
-
"description": "저장소, 이슈, PR, CI 확인과 코드 배포 워크플로를 연결합니다.",
|
|
105
|
-
"keywords": ["github", "repo", "repository", "pr", "pull request", "issue", "ci", "깃허브", "저장소", "이슈", "배포"],
|
|
106
|
-
"capabilities": ["PR 확인", "이슈 탐색", "CI 확인", "릴리즈 준비"],
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"id": "slack",
|
|
110
|
-
"name": "Slack Connector",
|
|
111
|
-
"category": "Team sharing",
|
|
112
|
-
"install_mode": "connector",
|
|
113
|
-
"connector_url": "/mcp/connectors/slack",
|
|
114
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
115
|
-
"description": "팀 채널에 결과 공유, 논의 요약, 알림 워크플로를 연결합니다.",
|
|
116
|
-
"keywords": ["slack", "message", "team", "notify", "공유", "알림", "메시지", "슬랙", "팀"],
|
|
117
|
-
"capabilities": ["채널 공유", "메시지 작성", "협업 알림"],
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
"id": "obsidian-memory",
|
|
121
|
-
"name": "Obsidian Memory Vault",
|
|
122
|
-
"category": "Memory / knowledge",
|
|
123
|
-
"install_mode": "builtin",
|
|
124
|
-
"description": "Lattice AI의 장기 기억을 Obsidian 호환 Markdown vault에 저장하고 검색합니다.",
|
|
125
|
-
"keywords": ["memory", "remember", "obsidian", "vault", "knowledge", "기억", "메모리", "옵시디언", "지식", "노트"],
|
|
126
|
-
"capabilities": ["Markdown vault 저장", "장기 기억 검색", "Obsidian URI 힌트", "프로젝트 로그"],
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
"id": "voice-whisper",
|
|
130
|
-
"name": "Voice STT (Whisper Local)",
|
|
131
|
-
"category": "Voice / speech-to-text",
|
|
132
|
-
"install_mode": "pip",
|
|
133
|
-
"pip_packages": ["openai-whisper"],
|
|
134
|
-
"description": "로컬 음성 인식(STT) 파이프라인용 Whisper 런타임을 설치합니다.",
|
|
135
|
-
"keywords": ["voice", "speech", "stt", "whisper", "audio", "음성", "인식", "자막", "전사"],
|
|
136
|
-
"capabilities": ["로컬 STT 런타임", "오디오 전사 워크플로 준비"],
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
"id": "voice-speechrecognition",
|
|
140
|
-
"name": "Voice STT (SpeechRecognition)",
|
|
141
|
-
"category": "Voice / speech-to-text",
|
|
142
|
-
"install_mode": "pip",
|
|
143
|
-
"pip_packages": ["SpeechRecognition"],
|
|
144
|
-
"description": "가벼운 음성 인식 실험용 SpeechRecognition 패키지를 설치합니다.",
|
|
145
|
-
"keywords": ["voice", "speech", "recognition", "stt", "microphone", "음성", "마이크", "받아쓰기"],
|
|
146
|
-
"capabilities": ["STT 파이썬 패키지", "마이크 입력 인식 실험"],
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
"id": "audio-pydub",
|
|
150
|
-
"name": "Audio Processing (PyDub)",
|
|
151
|
-
"category": "Voice / audio processing",
|
|
152
|
-
"install_mode": "pip",
|
|
153
|
-
"pip_packages": ["pydub"],
|
|
154
|
-
"description": "오디오 파일 분할/정규화/포맷 변환 워크플로용 패키지를 설치합니다.",
|
|
155
|
-
"keywords": ["audio", "pydub", "wav", "mp3", "전처리", "오디오", "변환"],
|
|
156
|
-
"capabilities": ["오디오 전처리", "세그먼트 분할", "포맷 변환"],
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
"id": "threejs-workflow",
|
|
160
|
-
"name": "3D Workflow (Three.js)",
|
|
161
|
-
"category": "3D / interactive web",
|
|
162
|
-
"install_mode": "bundled",
|
|
163
|
-
"description": "브라우저 검수 + 코드 생성 흐름으로 Three.js 기반 3D 화면을 구현/검증합니다.",
|
|
164
|
-
"keywords": ["3d", "three", "threejs", "webgl", "scene", "3차원", "쓰리제이에스", "렌더링"],
|
|
165
|
-
"capabilities": ["Three.js 코드 생성", "3D 씬 검수", "브라우저 상호작용 테스트"],
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
"id": "figma",
|
|
169
|
-
"name": "Figma Connector",
|
|
170
|
-
"category": "Design / handoff",
|
|
171
|
-
"install_mode": "connector",
|
|
172
|
-
"connector_url": "/mcp/connectors/figma",
|
|
173
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
174
|
-
"description": "디자인 파일 참조, 컴포넌트 규칙 확인, 구현 핸드오프를 연결합니다.",
|
|
175
|
-
"keywords": ["figma", "design", "handoff", "컴포넌트", "디자인", "피그마"],
|
|
176
|
-
"capabilities": ["디자인 참조", "핸드오프 워크플로", "컴포넌트 맵핑"],
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
"id": "notion",
|
|
180
|
-
"name": "Notion Connector",
|
|
181
|
-
"category": "Knowledge / docs",
|
|
182
|
-
"install_mode": "connector",
|
|
183
|
-
"connector_url": "/mcp/connectors/notion",
|
|
184
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
185
|
-
"description": "노션 문서/DB와 연동해 구현 노트, 회의 요약, 지식 관리 워크플로를 만듭니다.",
|
|
186
|
-
"keywords": ["notion", "wiki", "docs", "database", "노션", "위키", "문서", "지식관리"],
|
|
187
|
-
"capabilities": ["페이지 검색", "문서 작성 보조", "지식 동기화"],
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
"id": "linear",
|
|
191
|
-
"name": "Linear Connector",
|
|
192
|
-
"category": "Project / issue tracking",
|
|
193
|
-
"install_mode": "connector",
|
|
194
|
-
"connector_url": "/mcp/connectors/linear",
|
|
195
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
196
|
-
"description": "이슈 상태 확인, 우선순위 정리, 릴리즈 태스크 연결에 사용합니다.",
|
|
197
|
-
"keywords": ["linear", "issue", "project", "sprint", "이슈", "태스크", "프로젝트"],
|
|
198
|
-
"capabilities": ["이슈 조회", "작업 우선순위", "릴리즈 트래킹"],
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
"id": "gmail",
|
|
202
|
-
"name": "Gmail Connector",
|
|
203
|
-
"category": "Communication / email",
|
|
204
|
-
"install_mode": "connector",
|
|
205
|
-
"connector_url": "/mcp/connectors/gmail",
|
|
206
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
207
|
-
"description": "이메일 요약, 답장 초안, 업무 메일 정리에 사용합니다.",
|
|
208
|
-
"keywords": ["gmail", "email", "mail", "inbox", "메일", "지메일", "이메일"],
|
|
209
|
-
"capabilities": ["메일 검색", "요약", "답장 초안"],
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
"id": "google-calendar",
|
|
213
|
-
"name": "Google Calendar Connector",
|
|
214
|
-
"category": "Scheduling / calendar",
|
|
215
|
-
"install_mode": "connector",
|
|
216
|
-
"connector_url": "/mcp/connectors/google-calendar",
|
|
217
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
218
|
-
"description": "일정 확인, 미팅 슬롯 탐색, 일정 생성 워크플로를 연결합니다.",
|
|
219
|
-
"keywords": ["calendar", "schedule", "meeting", "구글캘린더", "일정", "미팅"],
|
|
220
|
-
"capabilities": ["일정 조회", "빈 시간 탐색", "이벤트 생성"],
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
"id": "outlook-email",
|
|
224
|
-
"name": "Outlook Email Connector",
|
|
225
|
-
"category": "Communication / email",
|
|
226
|
-
"install_mode": "connector",
|
|
227
|
-
"connector_url": "/mcp/connectors/outlook-email",
|
|
228
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
229
|
-
"description": "Outlook 메일함 연동, 메일 검색/초안/요약 워크플로를 제공합니다.",
|
|
230
|
-
"keywords": ["outlook", "email", "mail", "아웃룩", "메일"],
|
|
231
|
-
"capabilities": ["메일 검색", "요약", "초안 작성"],
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
"id": "outlook-calendar",
|
|
235
|
-
"name": "Outlook Calendar Connector",
|
|
236
|
-
"category": "Scheduling / calendar",
|
|
237
|
-
"install_mode": "connector",
|
|
238
|
-
"connector_url": "/mcp/connectors/outlook-calendar",
|
|
239
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
240
|
-
"description": "Outlook 일정 연동으로 회의 준비/시간 조율 작업을 진행합니다.",
|
|
241
|
-
"keywords": ["outlook calendar", "calendar", "schedule", "아웃룩 캘린더", "일정"],
|
|
242
|
-
"capabilities": ["일정 조회", "회의 준비", "시간 조율"],
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
"id": "teams",
|
|
246
|
-
"name": "Microsoft Teams Connector",
|
|
247
|
-
"category": "Team collaboration",
|
|
248
|
-
"install_mode": "connector",
|
|
249
|
-
"connector_url": "/mcp/connectors/teams",
|
|
250
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
251
|
-
"description": "팀 대화 컨텍스트 기반 업무 자동화와 협업 공유를 지원합니다.",
|
|
252
|
-
"keywords": ["teams", "microsoft teams", "chat", "협업", "팀즈"],
|
|
253
|
-
"capabilities": ["팀 대화 공유", "협업 흐름 연결"],
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
"id": "sharepoint",
|
|
257
|
-
"name": "SharePoint Connector",
|
|
258
|
-
"category": "Enterprise files",
|
|
259
|
-
"install_mode": "connector",
|
|
260
|
-
"connector_url": "/mcp/connectors/sharepoint",
|
|
261
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
262
|
-
"description": "SharePoint 문서 저장소를 검색/참조하는 엔터프라이즈 워크플로를 지원합니다.",
|
|
263
|
-
"keywords": ["sharepoint", "document", "enterprise", "문서", "셰어포인트"],
|
|
264
|
-
"capabilities": ["문서 검색", "사내 파일 참조"],
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
"id": "canva",
|
|
268
|
-
"name": "Canva Connector",
|
|
269
|
-
"category": "Design / visuals",
|
|
270
|
-
"install_mode": "connector",
|
|
271
|
-
"connector_url": "/mcp/connectors/canva",
|
|
272
|
-
"external_url": "https://chatgpt.com/connectors",
|
|
273
|
-
"description": "디자인 템플릿 기반 이미지/슬라이드 작업을 연동합니다.",
|
|
274
|
-
"keywords": ["canva", "design", "poster", "card", "캔바", "디자인"],
|
|
275
|
-
"capabilities": ["디자인 템플릿", "이미지 제작 워크플로"],
|
|
276
|
-
},
|
|
277
|
-
# ── 데이터베이스 ─────────────────────────────────────────────────────────
|
|
278
|
-
{
|
|
279
|
-
"id": "mcp-postgres",
|
|
280
|
-
"name": "PostgreSQL MCP",
|
|
281
|
-
"category": "Database",
|
|
282
|
-
"install_mode": "npm",
|
|
283
|
-
"package": "@modelcontextprotocol/server-postgres",
|
|
284
|
-
"description": "PostgreSQL 데이터베이스에 연결해 쿼리 실행, 스키마 탐색, 데이터 분석을 수행합니다.",
|
|
285
|
-
"keywords": ["postgres", "postgresql", "database", "sql", "db", "데이터베이스", "쿼리"],
|
|
286
|
-
"capabilities": ["SQL 쿼리 실행", "스키마 탐색", "테이블 분석"],
|
|
287
|
-
"env_vars": [{"name": "POSTGRES_CONNECTION_STRING", "description": "postgresql://user:pass@host:5432/db"}],
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
"id": "mcp-sqlite",
|
|
291
|
-
"name": "SQLite MCP",
|
|
292
|
-
"category": "Database",
|
|
293
|
-
"install_mode": "npm",
|
|
294
|
-
"package": "@modelcontextprotocol/server-sqlite",
|
|
295
|
-
"description": "로컬 SQLite 파일에 쿼리를 실행하고 데이터를 탐색합니다.",
|
|
296
|
-
"keywords": ["sqlite", "database", "sql", "local", "로컬", "데이터베이스"],
|
|
297
|
-
"capabilities": ["SQLite 쿼리", "테이블 탐색", "데이터 집계"],
|
|
298
|
-
"env_vars": [{"name": "SQLITE_DB_PATH", "description": "/path/to/database.db"}],
|
|
299
|
-
},
|
|
300
|
-
# ── 검색 / 웹 ────────────────────────────────────────────────────────────
|
|
301
|
-
{
|
|
302
|
-
"id": "mcp-brave-search",
|
|
303
|
-
"name": "Brave Search MCP",
|
|
304
|
-
"category": "Search / web",
|
|
305
|
-
"install_mode": "npm",
|
|
306
|
-
"package": "@modelcontextprotocol/server-brave-search",
|
|
307
|
-
"description": "Brave Search API로 실시간 웹 검색 결과를 가져옵니다.",
|
|
308
|
-
"keywords": ["search", "web", "brave", "websearch", "검색", "웹검색"],
|
|
309
|
-
"capabilities": ["실시간 웹 검색", "뉴스 검색", "이미지 검색"],
|
|
310
|
-
"env_vars": [{"name": "BRAVE_API_KEY", "description": "Brave Search API 키 (search.brave.com)"}],
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
"id": "mcp-tavily",
|
|
314
|
-
"name": "Tavily Search MCP",
|
|
315
|
-
"category": "Search / web",
|
|
316
|
-
"install_mode": "npm",
|
|
317
|
-
"package": "tavily-mcp",
|
|
318
|
-
"description": "AI 최적화 웹 검색 엔진 Tavily로 고품질 검색 결과를 가져옵니다.",
|
|
319
|
-
"keywords": ["search", "tavily", "ai search", "검색", "AI검색"],
|
|
320
|
-
"capabilities": ["AI 최적화 검색", "요약 검색 결과"],
|
|
321
|
-
"env_vars": [{"name": "TAVILY_API_KEY", "description": "app.tavily.com에서 발급"}],
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
"id": "mcp-puppeteer",
|
|
325
|
-
"name": "Puppeteer MCP",
|
|
326
|
-
"category": "Browser automation",
|
|
327
|
-
"install_mode": "npm",
|
|
328
|
-
"package": "@modelcontextprotocol/server-puppeteer",
|
|
329
|
-
"description": "Puppeteer로 브라우저를 제어하고 웹 스크래핑, 스크린샷, 자동화를 수행합니다.",
|
|
330
|
-
"keywords": ["puppeteer", "browser", "scraping", "screenshot", "automation", "스크래핑", "자동화"],
|
|
331
|
-
"capabilities": ["웹 스크래핑", "스크린샷", "폼 자동화", "클릭/입력"],
|
|
332
|
-
},
|
|
333
|
-
# ── 배포 / 인프라 ─────────────────────────────────────────────────────────
|
|
334
|
-
{
|
|
335
|
-
"id": "mcp-vercel",
|
|
336
|
-
"name": "Vercel MCP",
|
|
337
|
-
"category": "Deployment",
|
|
338
|
-
"install_mode": "npm",
|
|
339
|
-
"package": "@vercel/mcp-adapter",
|
|
340
|
-
"description": "Vercel 프로젝트 배포 상태 확인, 로그 조회, 환경 변수 관리를 수행합니다.",
|
|
341
|
-
"keywords": ["vercel", "deploy", "deployment", "serverless", "배포", "버셀"],
|
|
342
|
-
"capabilities": ["배포 상태 확인", "로그 조회", "환경 변수 관리"],
|
|
343
|
-
"env_vars": [{"name": "VERCEL_API_TOKEN", "description": "Vercel 계정 토큰"}],
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
"id": "mcp-cloudflare",
|
|
347
|
-
"name": "Cloudflare MCP",
|
|
348
|
-
"category": "Deployment / CDN",
|
|
349
|
-
"install_mode": "npm",
|
|
350
|
-
"package": "@cloudflare/mcp-server-cloudflare",
|
|
351
|
-
"description": "Cloudflare Workers, KV, R2, D1 등 Cloudflare 서비스를 관리합니다.",
|
|
352
|
-
"keywords": ["cloudflare", "workers", "cdn", "kv", "r2", "클라우드플레어"],
|
|
353
|
-
"capabilities": ["Workers 배포", "KV/R2 관리", "DNS 조회", "D1 쿼리"],
|
|
354
|
-
"env_vars": [{"name": "CLOUDFLARE_API_TOKEN", "description": "Cloudflare API 토큰"}],
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
"id": "mcp-docker",
|
|
358
|
-
"name": "Docker MCP",
|
|
359
|
-
"category": "Infrastructure",
|
|
360
|
-
"install_mode": "npm",
|
|
361
|
-
"package": "docker-mcp",
|
|
362
|
-
"description": "Docker 컨테이너 목록 조회, 실행/중지, 로그 확인을 수행합니다.",
|
|
363
|
-
"keywords": ["docker", "container", "devops", "도커", "컨테이너", "인프라"],
|
|
364
|
-
"capabilities": ["컨테이너 관리", "이미지 조회", "로그 확인", "실행/중지"],
|
|
365
|
-
},
|
|
366
|
-
# ── SaaS / 결제 ───────────────────────────────────────────────────────────
|
|
367
|
-
{
|
|
368
|
-
"id": "mcp-stripe",
|
|
369
|
-
"name": "Stripe MCP",
|
|
370
|
-
"category": "Payments",
|
|
371
|
-
"install_mode": "npm",
|
|
372
|
-
"package": "@stripe/agent-toolkit",
|
|
373
|
-
"description": "Stripe 결제, 고객, 구독, 인보이스를 조회하고 관리합니다.",
|
|
374
|
-
"keywords": ["stripe", "payment", "billing", "subscription", "결제", "스트라이프"],
|
|
375
|
-
"capabilities": ["결제 조회", "고객 관리", "구독 확인", "인보이스"],
|
|
376
|
-
"env_vars": [{"name": "STRIPE_SECRET_KEY", "description": "Stripe Secret Key (sk_...)"}],
|
|
377
|
-
},
|
|
378
|
-
{
|
|
379
|
-
"id": "mcp-supabase",
|
|
380
|
-
"name": "Supabase MCP",
|
|
381
|
-
"category": "Database / BaaS",
|
|
382
|
-
"install_mode": "npm",
|
|
383
|
-
"package": "@supabase/mcp-server-supabase",
|
|
384
|
-
"description": "Supabase 프로젝트의 DB 쿼리, Auth 관리, Storage 파일 접근을 수행합니다.",
|
|
385
|
-
"keywords": ["supabase", "database", "auth", "storage", "supabase", "슈퍼베이스"],
|
|
386
|
-
"capabilities": ["DB 쿼리", "Auth 사용자 조회", "Storage 파일 관리"],
|
|
387
|
-
"env_vars": [
|
|
388
|
-
{"name": "SUPABASE_URL", "description": "https://xxx.supabase.co"},
|
|
389
|
-
{"name": "SUPABASE_SERVICE_ROLE_KEY", "description": "service_role 키"},
|
|
390
|
-
],
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
"id": "mcp-hubspot",
|
|
394
|
-
"name": "HubSpot MCP",
|
|
395
|
-
"category": "CRM / marketing",
|
|
396
|
-
"install_mode": "npm",
|
|
397
|
-
"package": "@hubspot/mcp-server",
|
|
398
|
-
"description": "HubSpot CRM의 연락처, 딜, 캠페인 데이터를 조회하고 분석합니다.",
|
|
399
|
-
"keywords": ["hubspot", "crm", "marketing", "sales", "허브스팟", "CRM"],
|
|
400
|
-
"capabilities": ["연락처 조회", "딜 파이프라인", "캠페인 분석"],
|
|
401
|
-
"env_vars": [{"name": "HUBSPOT_ACCESS_TOKEN", "description": "HubSpot Private App 토큰"}],
|
|
402
|
-
},
|
|
403
|
-
# ── AI / 메모리 ───────────────────────────────────────────────────────────
|
|
404
|
-
{
|
|
405
|
-
"id": "mcp-memory",
|
|
406
|
-
"name": "Memory MCP (공식)",
|
|
407
|
-
"category": "Memory / knowledge",
|
|
408
|
-
"install_mode": "npm",
|
|
409
|
-
"package": "@modelcontextprotocol/server-memory",
|
|
410
|
-
"description": "대화 간 지속 메모리를 저장하고 검색하는 공식 MCP 서버입니다.",
|
|
411
|
-
"keywords": ["memory", "remember", "knowledge", "기억", "메모리", "지식"],
|
|
412
|
-
"capabilities": ["장기 기억 저장", "메모리 검색", "엔티티 추적"],
|
|
413
|
-
},
|
|
414
|
-
{
|
|
415
|
-
"id": "mcp-sequential-thinking",
|
|
416
|
-
"name": "Sequential Thinking MCP",
|
|
417
|
-
"category": "AI / reasoning",
|
|
418
|
-
"install_mode": "npm",
|
|
419
|
-
"package": "@modelcontextprotocol/server-sequential-thinking",
|
|
420
|
-
"description": "복잡한 문제를 단계별로 분해해 추론하는 사고 흐름 도구입니다.",
|
|
421
|
-
"keywords": ["reasoning", "thinking", "chain of thought", "추론", "사고"],
|
|
422
|
-
"capabilities": ["단계별 추론", "문제 분해", "사고 흐름 추적"],
|
|
423
|
-
},
|
|
424
|
-
# ── 커뮤니케이션 ──────────────────────────────────────────────────────────
|
|
425
|
-
{
|
|
426
|
-
"id": "mcp-discord",
|
|
427
|
-
"name": "Discord MCP",
|
|
428
|
-
"category": "Communication",
|
|
429
|
-
"install_mode": "npm",
|
|
430
|
-
"package": "discord-mcp",
|
|
431
|
-
"description": "Discord 서버 채널 메시지 전송, 읽기, 관리 자동화를 수행합니다.",
|
|
432
|
-
"keywords": ["discord", "message", "channel", "디스코드", "메시지", "알림"],
|
|
433
|
-
"capabilities": ["메시지 전송", "채널 읽기", "알림 자동화"],
|
|
434
|
-
"env_vars": [{"name": "DISCORD_BOT_TOKEN", "description": "Discord Bot 토큰"}],
|
|
435
|
-
},
|
|
436
|
-
{
|
|
437
|
-
"id": "mcp-telegram",
|
|
438
|
-
"name": "Telegram MCP",
|
|
439
|
-
"category": "Communication",
|
|
440
|
-
"install_mode": "npm",
|
|
441
|
-
"package": "telegram-mcp",
|
|
442
|
-
"description": "Telegram 봇을 통한 메시지 전송, 수신, 알림 자동화를 수행합니다.",
|
|
443
|
-
"keywords": ["telegram", "bot", "message", "텔레그램", "봇", "메시지"],
|
|
444
|
-
"capabilities": ["메시지 전송/수신", "알림 자동화", "그룹 관리"],
|
|
445
|
-
"env_vars": [{"name": "TELEGRAM_BOT_TOKEN", "description": "BotFather에서 발급한 토큰"}],
|
|
446
|
-
},
|
|
447
|
-
# ── 개발 도구 ─────────────────────────────────────────────────────────────
|
|
448
|
-
{
|
|
449
|
-
"id": "mcp-everything",
|
|
450
|
-
"name": "Everything MCP (테스트)",
|
|
451
|
-
"category": "Developer tools",
|
|
452
|
-
"install_mode": "npm",
|
|
453
|
-
"package": "@modelcontextprotocol/server-everything",
|
|
454
|
-
"description": "MCP 연결 테스트용 모든 기능이 포함된 데모 서버입니다.",
|
|
455
|
-
"keywords": ["test", "demo", "everything", "테스트", "개발"],
|
|
456
|
-
"capabilities": ["MCP 기능 테스트", "프로토타입"],
|
|
457
|
-
},
|
|
458
|
-
]
|
|
459
|
-
|
|
460
|
-
# ── Remote MCP Registry (registry.modelcontextprotocol.io) ───────────────────
|
|
461
|
-
_REMOTE_REGISTRY_CACHE: List[Dict] = []
|
|
462
|
-
_REMOTE_REGISTRY_FETCHED_AT: Optional[datetime] = None
|
|
463
|
-
_REMOTE_REGISTRY_TTL = timedelta(hours=1)
|
|
464
|
-
_REMOTE_REGISTRY_URL = "https://registry.modelcontextprotocol.io/v0/servers"
|
|
465
|
-
_LOCAL_IDS = {e["id"] for e in MCP_REGISTRY}
|
|
466
|
-
|
|
467
|
-
async def _fetch_remote_mcp_registry() -> List[Dict]:
|
|
468
|
-
global _REMOTE_REGISTRY_CACHE, _REMOTE_REGISTRY_FETCHED_AT
|
|
469
|
-
now = datetime.now()
|
|
470
|
-
if _REMOTE_REGISTRY_FETCHED_AT and (now - _REMOTE_REGISTRY_FETCHED_AT) < _REMOTE_REGISTRY_TTL:
|
|
471
|
-
return _REMOTE_REGISTRY_CACHE
|
|
472
|
-
try:
|
|
473
|
-
result: List[Dict] = []
|
|
474
|
-
cursor = None
|
|
475
|
-
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
476
|
-
while True:
|
|
477
|
-
params: Dict = {"limit": 100}
|
|
478
|
-
if cursor:
|
|
479
|
-
params["cursor"] = cursor
|
|
480
|
-
resp = await client.get(_REMOTE_REGISTRY_URL, params=params)
|
|
481
|
-
resp.raise_for_status()
|
|
482
|
-
data = resp.json()
|
|
483
|
-
for s in data.get("servers", []):
|
|
484
|
-
srv = s["server"]
|
|
485
|
-
meta = s.get("_meta", {}).get("io.modelcontextprotocol.registry/official", {})
|
|
486
|
-
if not meta.get("isLatest", True):
|
|
487
|
-
continue
|
|
488
|
-
pkg = next(
|
|
489
|
-
(p for p in srv.get("packages", [])
|
|
490
|
-
if p.get("transport", {}).get("type") == "stdio"
|
|
491
|
-
and p.get("registryType") in ("npm", "pypi")),
|
|
492
|
-
None,
|
|
493
|
-
)
|
|
494
|
-
if not pkg:
|
|
495
|
-
continue
|
|
496
|
-
entry_id = srv["name"].replace("/", "-").replace(".", "-")
|
|
497
|
-
if entry_id in _LOCAL_IDS:
|
|
498
|
-
continue
|
|
499
|
-
result.append({
|
|
500
|
-
"id": entry_id,
|
|
501
|
-
"name": srv.get("title") or srv["name"],
|
|
502
|
-
"category": "MCP Registry",
|
|
503
|
-
"install_mode": pkg["registryType"],
|
|
504
|
-
"package": pkg["identifier"],
|
|
505
|
-
"package_version": pkg.get("version"),
|
|
506
|
-
"description": srv.get("description", ""),
|
|
507
|
-
"keywords": [],
|
|
508
|
-
"capabilities": [],
|
|
509
|
-
"source": "registry",
|
|
510
|
-
"homepage": (srv.get("repository") or {}).get("url"),
|
|
511
|
-
})
|
|
512
|
-
cursor = data.get("nextCursor")
|
|
513
|
-
if not cursor:
|
|
514
|
-
break
|
|
515
|
-
_REMOTE_REGISTRY_CACHE = result
|
|
516
|
-
_REMOTE_REGISTRY_FETCHED_AT = now
|
|
517
|
-
logging.info("Fetched %d stdio MCP servers from remote registry", len(result))
|
|
518
|
-
except Exception as e:
|
|
519
|
-
logging.warning("Failed to fetch remote MCP registry: %s", e)
|
|
520
|
-
return _REMOTE_REGISTRY_CACHE
|
|
521
|
-
|
|
522
|
-
async def _get_combined_registry() -> List[Dict]:
|
|
523
|
-
remote = await _fetch_remote_mcp_registry()
|
|
524
|
-
return MCP_REGISTRY + remote
|
|
525
|
-
|
|
526
|
-
# ── Anthropic Skills Marketplace (Apache 2.0) ─────────────────────────────────
|
|
527
|
-
_MARKETPLACE_RAW = "https://raw.githubusercontent.com/anthropics/claude-plugins-official/main"
|
|
528
|
-
_MARKETPLACE_API = "https://api.github.com/repos/anthropics/claude-plugins-official/contents"
|
|
529
|
-
|
|
530
|
-
# 검증된 서드파티 skills 소스 (Apache-2.0 / MIT)
|
|
531
|
-
_THIRD_PARTY_SKILL_SOURCES: List[Dict] = [
|
|
532
|
-
{
|
|
533
|
-
"plugin": "adobe-for-creativity", "author": "Adobe", "license": "Apache-2.0",
|
|
534
|
-
"repo": "adobe/skills", "branch": "main",
|
|
535
|
-
"plugin_path": "plugins/creative-cloud/adobe-for-creativity",
|
|
536
|
-
"category": "design",
|
|
537
|
-
},
|
|
538
|
-
{
|
|
539
|
-
"plugin": "airtable", "author": "Airtable", "license": "MIT",
|
|
540
|
-
"repo": "Airtable/skills", "branch": "main",
|
|
541
|
-
"plugin_path": "plugins/airtable",
|
|
542
|
-
"category": "productivity",
|
|
543
|
-
},
|
|
544
|
-
{
|
|
545
|
-
"plugin": "auth0", "author": "Auth0", "license": "Apache-2.0",
|
|
546
|
-
"repo": "auth0/agent-skills", "branch": "main",
|
|
547
|
-
"plugin_path": "plugins/auth0",
|
|
548
|
-
"category": "security",
|
|
549
|
-
},
|
|
550
|
-
{
|
|
551
|
-
"plugin": "expo", "author": "Expo", "license": "MIT",
|
|
552
|
-
"repo": "expo/skills", "branch": "main",
|
|
553
|
-
"plugin_path": "plugins/expo",
|
|
554
|
-
"category": "development",
|
|
555
|
-
},
|
|
556
|
-
{
|
|
557
|
-
"plugin": "logfire", "author": "Pydantic", "license": "MIT",
|
|
558
|
-
"repo": "pydantic/skills", "branch": "main",
|
|
559
|
-
"plugin_path": "plugins/logfire",
|
|
560
|
-
"category": "monitoring",
|
|
561
|
-
},
|
|
562
|
-
]
|
|
563
|
-
|
|
564
|
-
# 검증된 레포 라이선스 맵 (GitHub API 없이 빠르게 조회)
|
|
565
|
-
_KNOWN_REPO_LICENSES: Dict[str, str] = {
|
|
566
|
-
# Apache-2.0
|
|
567
|
-
"adobe/skills": "Apache-2.0", "awslabs/agent-plugins": "Apache-2.0",
|
|
568
|
-
"auth0/agent-skills": "Apache-2.0", "aws/agent-toolkit-for-aws": "Apache-2.0",
|
|
569
|
-
"carta/plugins": "Apache-2.0", "circlefin/skills": "Apache-2.0",
|
|
570
|
-
"clickhouse/clickhouse-docs": "Apache-2.0", "cloudflare/agents": "Apache-2.0",
|
|
571
|
-
"cockroachdb/claude-code": "Apache-2.0", "codspeed-hq/codspeed-claude": "Apache-2.0",
|
|
572
|
-
"DataDog/datadog-claude-code": "Apache-2.0", "datahub-project/datahub-skills": "Apache-2.0",
|
|
573
|
-
"neondatabase/agent-skills": "Apache-2.0", "PagerDuty/pd-ai-agents-plugins": "Apache-2.0",
|
|
574
|
-
"getpostman/postman-mcp-server": "Apache-2.0", "qdrant/qdrant-skills": "Apache-2.0",
|
|
575
|
-
"rootlyhq/rootly-plugins": "Apache-2.0", "snowflake-labs/snowflake-claude": "Apache-2.0",
|
|
576
|
-
"sumup/sumup-claude": "Apache-2.0", "zilliz-labs/zilliz-skills": "Apache-2.0",
|
|
577
|
-
"mercadopago/mercadopago-claude-marketplace": "Apache-2.0",
|
|
578
|
-
# MIT
|
|
579
|
-
"Airtable/skills": "MIT", "endorlabs/ai-plugins": "MIT",
|
|
580
|
-
"apollographql/apollo-claude-skills": "MIT", "appwrite/skills": "MIT",
|
|
581
|
-
"atlan-inc/claude-code-skills": "MIT", "boxer/boxerbox": "MIT",
|
|
582
|
-
"buildkite/claude-code": "MIT", "coderabbitai/coderabbit-skills": "MIT",
|
|
583
|
-
"CrowdStrike/crowdstrike-skills": "MIT", "microsoft/Dataverse-skills": "MIT",
|
|
584
|
-
"duckdb/duckdb-skills": "MIT", "expo/skills": "MIT",
|
|
585
|
-
"intercom/intercom-skills": "MIT", "pydantic/skills": "MIT",
|
|
586
|
-
"mapbox/mapbox-skills": "MIT", "mintlify/mintlify-skills": "MIT",
|
|
587
|
-
"miroapp/miro-ai": "MIT", "netlify/netlify-skills": "MIT",
|
|
588
|
-
"pinecone-io/pinecone-skills": "MIT", "railwayapp/railway-skills": "MIT",
|
|
589
|
-
"resend/resend-skills": "MIT", "sanity-io/sanity-skills": "MIT",
|
|
590
|
-
"getsentry/sentry-ai-skills": "MIT", "Shopify/liquid-skills": "MIT",
|
|
591
|
-
"slackapi/slack-skills": "MIT", "stripe/stripe-skills": "MIT",
|
|
592
|
-
"twilio-labs/twilio-skills": "MIT", "workos/workos-skills": "MIT",
|
|
593
|
-
"zoom/zoom-skills": "MIT", "aws-samples/sample-claude-code-plugins-for-startups": "MIT-0",
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
_SKILLS_MARKETPLACE_CACHE: List[Dict] = []
|
|
597
|
-
_SKILLS_MARKETPLACE_FETCHED_AT: Optional[datetime] = None
|
|
598
|
-
_SKILLS_MARKETPLACE_TTL = timedelta(hours=1)
|
|
1
|
+
"""Deprecation shim — the MCP registry moved to ``latticeai.core.mcp_registry`` in v4.
|
|
599
2
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
if line.startswith("description:"):
|
|
603
|
-
return line.split(":", 1)[1].strip()
|
|
604
|
-
return fallback
|
|
3
|
+
This root module remains importable for the deprecation window and will be
|
|
4
|
+
removed in a future major release. Import from ``latticeai.core.mcp_registry``.
|
|
605
5
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
api_base = f"https://api.github.com/repos/{repo}/contents"
|
|
611
|
-
homepage_base = f"https://github.com/{repo}/tree/{branch}"
|
|
612
|
-
|
|
613
|
-
dir_resp = await client.get(f"{api_base}/{plugin_path}/skills")
|
|
614
|
-
if dir_resp.status_code != 200:
|
|
615
|
-
return []
|
|
616
|
-
skill_dirs = [f["name"] for f in dir_resp.json() if f["type"] == "dir"]
|
|
617
|
-
|
|
618
|
-
skills: List[Dict] = []
|
|
619
|
-
for skill_name in skill_dirs:
|
|
620
|
-
skill_md_url = f"{raw_base}/{plugin_path}/skills/{skill_name}/SKILL.md"
|
|
621
|
-
sm_resp = await client.get(skill_md_url)
|
|
622
|
-
if sm_resp.status_code != 200:
|
|
623
|
-
continue
|
|
624
|
-
skills.append({
|
|
625
|
-
"plugin": source["plugin"],
|
|
626
|
-
"skill": skill_name,
|
|
627
|
-
"category": source.get("category", "development"),
|
|
628
|
-
"description": _extract_skill_desc(sm_resp.text, source.get("description", "")),
|
|
629
|
-
"skill_md_url": skill_md_url,
|
|
630
|
-
"homepage": f"{homepage_base}/{plugin_path}/skills/{skill_name}",
|
|
631
|
-
"license": source["license"],
|
|
632
|
-
"author": source["author"],
|
|
633
|
-
})
|
|
634
|
-
return skills
|
|
635
|
-
|
|
636
|
-
async def _fetch_skills_marketplace() -> List[Dict]:
|
|
637
|
-
global _SKILLS_MARKETPLACE_CACHE, _SKILLS_MARKETPLACE_FETCHED_AT
|
|
638
|
-
now = datetime.now()
|
|
639
|
-
if _SKILLS_MARKETPLACE_FETCHED_AT and (now - _SKILLS_MARKETPLACE_FETCHED_AT) < _SKILLS_MARKETPLACE_TTL:
|
|
640
|
-
return _SKILLS_MARKETPLACE_CACHE
|
|
641
|
-
try:
|
|
642
|
-
result: List[Dict] = []
|
|
643
|
-
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
644
|
-
# ── Anthropic 공식 skills (Apache-2.0) ──────────────────────────
|
|
645
|
-
mp_resp = await client.get(f"{_MARKETPLACE_RAW}/.claude-plugin/marketplace.json")
|
|
646
|
-
mp_resp.raise_for_status()
|
|
647
|
-
marketplace_json = mp_resp.json()
|
|
648
|
-
anthropic_plugins = [
|
|
649
|
-
p for p in marketplace_json.get("plugins", [])
|
|
650
|
-
if (p.get("author") or {}).get("name") == "Anthropic"
|
|
651
|
-
and isinstance(p.get("source"), str)
|
|
652
|
-
and p["source"].startswith("./")
|
|
653
|
-
]
|
|
654
|
-
for plugin in anthropic_plugins:
|
|
655
|
-
plugin_path = plugin["source"].lstrip("./")
|
|
656
|
-
result.extend(await _fetch_plugin_skills(client, {
|
|
657
|
-
"plugin": plugin["name"],
|
|
658
|
-
"author": "Anthropic",
|
|
659
|
-
"license": "Apache-2.0",
|
|
660
|
-
"repo": "anthropics/claude-plugins-official",
|
|
661
|
-
"branch": "main",
|
|
662
|
-
"plugin_path": plugin_path,
|
|
663
|
-
"category": plugin.get("category", "development"),
|
|
664
|
-
"description": plugin.get("description", ""),
|
|
665
|
-
}))
|
|
666
|
-
# ── 검증된 서드파티 skills ────────────────────────────────────────
|
|
667
|
-
for source in _THIRD_PARTY_SKILL_SOURCES:
|
|
668
|
-
result.extend(await _fetch_plugin_skills(client, source))
|
|
669
|
-
|
|
670
|
-
_SKILLS_MARKETPLACE_CACHE = result
|
|
671
|
-
_SKILLS_MARKETPLACE_FETCHED_AT = now
|
|
672
|
-
logging.info("Fetched %d skills from marketplace (%d sources)",
|
|
673
|
-
len(result), len(anthropic_plugins) + len(_THIRD_PARTY_SKILL_SOURCES))
|
|
674
|
-
except Exception as e:
|
|
675
|
-
logging.warning("Failed to fetch skills marketplace: %s", e)
|
|
676
|
-
return _SKILLS_MARKETPLACE_CACHE
|
|
677
|
-
|
|
678
|
-
# ── Plugin Directory ──────────────────────────────────────────────────────────
|
|
679
|
-
_PLUGIN_DIRECTORY_CACHE: List[Dict] = []
|
|
680
|
-
_PLUGIN_DIRECTORY_FETCHED_AT: Optional[datetime] = None
|
|
681
|
-
_PLUGIN_DIRECTORY_TTL = timedelta(hours=1)
|
|
682
|
-
_OPEN_LICENSES = {"Apache-2.0", "MIT", "MIT-0", "CC-BY-4.0"}
|
|
683
|
-
_REPO_LICENSE_CACHE: Dict[str, str] = {}
|
|
684
|
-
|
|
685
|
-
async def _get_repo_license(client: httpx.AsyncClient, repo: str) -> str:
|
|
686
|
-
if repo in _REPO_LICENSE_CACHE:
|
|
687
|
-
return _REPO_LICENSE_CACHE[repo]
|
|
688
|
-
if repo in _KNOWN_REPO_LICENSES:
|
|
689
|
-
_REPO_LICENSE_CACHE[repo] = _KNOWN_REPO_LICENSES[repo]
|
|
690
|
-
return _KNOWN_REPO_LICENSES[repo]
|
|
691
|
-
try:
|
|
692
|
-
r = await client.get(f"https://api.github.com/repos/{repo}", timeout=5.0)
|
|
693
|
-
lic = (r.json().get("license") or {}).get("spdx_id", "") if r.status_code == 200 else ""
|
|
694
|
-
except Exception:
|
|
695
|
-
lic = ""
|
|
696
|
-
_REPO_LICENSE_CACHE[repo] = lic
|
|
697
|
-
return lic
|
|
698
|
-
|
|
699
|
-
async def _fetch_plugin_directory() -> List[Dict]:
|
|
700
|
-
global _PLUGIN_DIRECTORY_CACHE, _PLUGIN_DIRECTORY_FETCHED_AT
|
|
701
|
-
now = datetime.now()
|
|
702
|
-
if _PLUGIN_DIRECTORY_FETCHED_AT and (now - _PLUGIN_DIRECTORY_FETCHED_AT) < _PLUGIN_DIRECTORY_TTL:
|
|
703
|
-
return _PLUGIN_DIRECTORY_CACHE
|
|
704
|
-
try:
|
|
705
|
-
result: List[Dict] = []
|
|
706
|
-
async with httpx.AsyncClient(timeout=15.0) as client:
|
|
707
|
-
mp_resp = await client.get(f"{_MARKETPLACE_RAW}/.claude-plugin/marketplace.json")
|
|
708
|
-
mp_resp.raise_for_status()
|
|
709
|
-
plugins = mp_resp.json().get("plugins", [])
|
|
710
|
-
|
|
711
|
-
for p in plugins:
|
|
712
|
-
author = (p.get("author") or {}).get("name", "")
|
|
713
|
-
src = p.get("source", {})
|
|
714
|
-
|
|
715
|
-
# Anthropic 같은 레포 플러그인 → Apache-2.0 확인됨
|
|
716
|
-
if isinstance(src, str) and src.startswith("./") and author == "Anthropic":
|
|
717
|
-
plugin_path = src.lstrip("./")
|
|
718
|
-
result.append({
|
|
719
|
-
"name": p["name"],
|
|
720
|
-
"description": p.get("description", ""),
|
|
721
|
-
"category": p.get("category", ""),
|
|
722
|
-
"author": author,
|
|
723
|
-
"license": "Apache-2.0",
|
|
724
|
-
"homepage": p.get("homepage") or f"https://github.com/anthropics/claude-plugins-official/tree/main/{plugin_path}",
|
|
725
|
-
"source_type": "anthropic",
|
|
726
|
-
})
|
|
727
|
-
continue
|
|
728
|
-
|
|
729
|
-
# 외부 레포 플러그인 → 라이선스 확인
|
|
730
|
-
if not isinstance(src, dict):
|
|
731
|
-
continue
|
|
732
|
-
repo_url = src.get("url", "").replace("https://github.com/", "").replace(".git", "").split("/tree/")[0]
|
|
733
|
-
if not repo_url:
|
|
734
|
-
continue
|
|
735
|
-
license_id = await _get_repo_license(client, repo_url)
|
|
736
|
-
if license_id not in _OPEN_LICENSES:
|
|
737
|
-
continue
|
|
738
|
-
result.append({
|
|
739
|
-
"name": p["name"],
|
|
740
|
-
"description": p.get("description", ""),
|
|
741
|
-
"category": p.get("category", ""),
|
|
742
|
-
"author": author or repo_url.split("/")[0],
|
|
743
|
-
"license": license_id,
|
|
744
|
-
"homepage": p.get("homepage") or f"https://github.com/{repo_url}",
|
|
745
|
-
"source_type": "third-party",
|
|
746
|
-
})
|
|
747
|
-
|
|
748
|
-
_PLUGIN_DIRECTORY_CACHE = result
|
|
749
|
-
_PLUGIN_DIRECTORY_FETCHED_AT = now
|
|
750
|
-
logging.info("Fetched plugin directory: %d open-source plugins", len(result))
|
|
751
|
-
except Exception as e:
|
|
752
|
-
logging.warning("Failed to fetch plugin directory: %s", e)
|
|
753
|
-
return _PLUGIN_DIRECTORY_CACHE
|
|
754
|
-
|
|
755
|
-
# ─────────────────────────────────────────────────────────────────────────────
|
|
756
|
-
|
|
757
|
-
SKILLS_DIR = Path(__file__).resolve().parent / "skills"
|
|
6
|
+
Note: the remote-registry cache lives in ``latticeai.core.mcp_registry``
|
|
7
|
+
module globals — code that *assigns* cache attributes (e.g.
|
|
8
|
+
``_REMOTE_REGISTRY_FETCHED_AT``) must import the real module, not this shim.
|
|
9
|
+
"""
|
|
758
10
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
risk_path = skill_dir / "risk.json"
|
|
778
|
-
if not risk_path.exists():
|
|
779
|
-
risk_path.write_text(json.dumps({
|
|
780
|
-
"risk": "read", "destructive": False,
|
|
781
|
-
"shell": False, "network": False,
|
|
782
|
-
"auto_approve": True, "sandbox": "workspace", "rollback": "none"
|
|
783
|
-
}, indent=2), encoding="utf-8")
|
|
784
|
-
return {
|
|
785
|
-
"status": "installed",
|
|
786
|
-
"plugin": plugin,
|
|
787
|
-
"skill": skill,
|
|
788
|
-
"path": str(skill_dir),
|
|
789
|
-
"license": entry["license"],
|
|
790
|
-
"author": entry["author"],
|
|
791
|
-
}
|
|
11
|
+
from latticeai.core.mcp_registry import * # noqa: F401,F403
|
|
12
|
+
from latticeai.core.mcp_registry import ( # noqa: F401 — explicit key surface
|
|
13
|
+
MCP_REGISTRY,
|
|
14
|
+
SKILLS_DIR,
|
|
15
|
+
_KNOWN_REPO_LICENSES,
|
|
16
|
+
_MARKETPLACE_API,
|
|
17
|
+
_MARKETPLACE_RAW,
|
|
18
|
+
_THIRD_PARTY_SKILL_SOURCES,
|
|
19
|
+
_extract_skill_desc,
|
|
20
|
+
_fetch_plugin_directory,
|
|
21
|
+
_fetch_plugin_skills,
|
|
22
|
+
_fetch_remote_mcp_registry,
|
|
23
|
+
_fetch_skills_marketplace,
|
|
24
|
+
_get_combined_registry,
|
|
25
|
+
install_skill,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = ["MCP_REGISTRY", "SKILLS_DIR", "install_skill"]
|