feat: Add Multi-Agent Orchestrator MCP Server using Cursor Agent CLI
This commit is contained in:
parent
43541a12c9
commit
04565eb480
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"mcpServers": {
|
||||
"agent-orchestrator": {
|
||||
"command": "node",
|
||||
"args": ["C:/Users/defaultuser0/ERP-node/mcp-agent-orchestrator/build/index.js"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,989 @@
|
|||
# Multi-Agent 협업 시스템 설계서
|
||||
|
||||
> Cursor 에이전트 간 협업을 통한 효율적인 개발 시스템
|
||||
|
||||
## 목차
|
||||
|
||||
1. [개요](#개요)
|
||||
2. [아키텍처](#아키텍처)
|
||||
3. [에이전트 역할 정의](#에이전트-역할-정의)
|
||||
4. [통신 프로토콜](#통신-프로토콜)
|
||||
5. [워크플로우](#워크플로우)
|
||||
6. [프롬프트 템플릿](#프롬프트-템플릿)
|
||||
7. [MCP 서버 구현](#mcp-서버-구현)
|
||||
8. [비용 분석](#비용-분석)
|
||||
9. [한계점 및 해결방안](#한계점-및-해결방안)
|
||||
|
||||
---
|
||||
|
||||
## 개요
|
||||
|
||||
### 문제점: 단일 에이전트의 한계
|
||||
|
||||
```
|
||||
단일 에이전트 문제:
|
||||
┌─────────────────────────────────────────┐
|
||||
│ • 컨텍스트 폭발 (50k+ 토큰 → 까먹음) │
|
||||
│ • 전문성 분산 (모든 영역 얕게 앎) │
|
||||
│ • 재작업 빈번 (실수, 누락) │
|
||||
│ • 검증 부재 (크로스체크 없음) │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 해결책: Multi-Agent 협업
|
||||
|
||||
```
|
||||
멀티 에이전트 장점:
|
||||
┌─────────────────────────────────────────┐
|
||||
│ • 컨텍스트 분리 (각자 작은 컨텍스트) │
|
||||
│ • 전문성 집중 (영역별 깊은 이해) │
|
||||
│ • 크로스체크 (서로 검증) │
|
||||
│ • 병렬 처리 (동시 작업) │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 모델 티어링 전략
|
||||
|
||||
| 에이전트 | 모델 | 역할 | 비용 |
|
||||
|----------|------|------|------|
|
||||
| Agent A (PM) | Claude Opus 4.5 | 분석, 계획, 조율 | 높음 |
|
||||
| Agent B (Backend) | Claude Sonnet | 백엔드 구현 | 낮음 |
|
||||
| Agent C (DB) | Claude Sonnet | DB/쿼리 담당 | 낮음 |
|
||||
| Agent D (Frontend) | Claude Sonnet | 프론트 구현 | 낮음 |
|
||||
|
||||
**예상 비용 절감: 50-60%**
|
||||
|
||||
---
|
||||
|
||||
## 아키텍처
|
||||
|
||||
### 전체 구조
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ USER │
|
||||
└──────┬──────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────┐
|
||||
│ Agent A (PM) │
|
||||
│ Claude Opus 4.5 │
|
||||
│ │
|
||||
│ • 사용자 의도 파악 │
|
||||
│ • 작업 분배 │
|
||||
│ • 결과 통합 │
|
||||
│ • 품질 검증 │
|
||||
└───────────┬───────────┘
|
||||
│
|
||||
┌─────────────────┼─────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Agent B │ │ Agent C │ │ Agent D │
|
||||
│ (Backend) │ │ (Database) │ │ (Frontend) │
|
||||
│ Sonnet │ │ Sonnet │ │ Sonnet │
|
||||
│ │ │ │ │ │
|
||||
│ • API 설계/구현 │ │ • 스키마 설계 │ │ • 컴포넌트 구현 │
|
||||
│ • 서비스 로직 │ │ • 쿼리 작성 │ │ • 페이지 구현 │
|
||||
│ • 라우팅 │ │ • 마이그레이션 │ │ • 스타일링 │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└─────────────────┴─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────┐
|
||||
│ MCP Orchestrator │
|
||||
│ │
|
||||
│ • 메시지 라우팅 │
|
||||
│ • 병렬 실행 │
|
||||
│ • 결과 수집 │
|
||||
└───────────────────────┘
|
||||
```
|
||||
|
||||
### 폴더별 담당 영역
|
||||
|
||||
| 에이전트 | 담당 폴더 | 파일 유형 |
|
||||
|----------|-----------|-----------|
|
||||
| Agent B (Backend) | `backend-node/src/` | `.ts`, `.js` |
|
||||
| Agent C (DB) | `src/com/pms/mapper/`, `db/` | `.xml`, `.sql` |
|
||||
| Agent D (Frontend) | `frontend/` | `.tsx`, `.ts`, `.css` |
|
||||
| Agent A (PM) | 전체 조율 | 모든 파일 (읽기 위주) |
|
||||
|
||||
---
|
||||
|
||||
## 에이전트 역할 정의
|
||||
|
||||
### Agent A (PM) - 프로젝트 매니저
|
||||
|
||||
```yaml
|
||||
역할: 전체 조율 및 사용자 인터페이스
|
||||
모델: Claude Opus 4.5
|
||||
|
||||
핵심 책임:
|
||||
의도 파악:
|
||||
- 사용자 요청 분석
|
||||
- 모호한 요청 명확화
|
||||
- 숨겨진 요구사항 발굴
|
||||
|
||||
작업 분배:
|
||||
- 작업을 세부 태스크로 분해
|
||||
- 적절한 에이전트에게 할당
|
||||
- 우선순위 및 의존성 결정
|
||||
|
||||
품질 관리:
|
||||
- 결과물 검증
|
||||
- 일관성 체크
|
||||
- 충돌 해결
|
||||
|
||||
통합:
|
||||
- 개별 결과물 취합
|
||||
- 최종 결과 생성
|
||||
- 사용자에게 보고
|
||||
|
||||
하지 않는 것:
|
||||
- 직접 코드 구현 (전문가에게 위임)
|
||||
- 특정 영역 깊이 분석 (전문가에게 요청)
|
||||
```
|
||||
|
||||
### Agent B (Backend) - 백엔드 전문가
|
||||
|
||||
```yaml
|
||||
역할: API 및 서버 로직 담당
|
||||
모델: Claude Sonnet
|
||||
|
||||
담당 영역:
|
||||
폴더:
|
||||
- backend-node/src/controllers/
|
||||
- backend-node/src/services/
|
||||
- backend-node/src/routes/
|
||||
- backend-node/src/middleware/
|
||||
- backend-node/src/utils/
|
||||
|
||||
작업:
|
||||
- REST API 엔드포인트 설계/구현
|
||||
- 비즈니스 로직 구현
|
||||
- 미들웨어 작성
|
||||
- 에러 핸들링
|
||||
- 인증/인가 로직
|
||||
|
||||
담당 아닌 것:
|
||||
- frontend/ 폴더 (Agent D 담당)
|
||||
- SQL 쿼리 직접 작성 (Agent C에게 요청)
|
||||
- DB 스키마 변경 (Agent C 담당)
|
||||
|
||||
협업 필요 시:
|
||||
- DB 쿼리 필요 → Agent C에게 요청
|
||||
- 프론트 연동 문제 → Agent D와 협의
|
||||
```
|
||||
|
||||
### Agent C (Database) - DB 전문가
|
||||
|
||||
```yaml
|
||||
역할: 데이터베이스 및 쿼리 담당
|
||||
모델: Claude Sonnet
|
||||
|
||||
담당 영역:
|
||||
폴더:
|
||||
- src/com/pms/mapper/
|
||||
- db/
|
||||
- backend-node/src/database/
|
||||
|
||||
작업:
|
||||
- 테이블 스키마 설계
|
||||
- MyBatis 매퍼 XML 작성
|
||||
- SQL 쿼리 최적화
|
||||
- 인덱스 설계
|
||||
- 마이그레이션 스크립트
|
||||
|
||||
담당 아닌 것:
|
||||
- API 로직 (Agent B 담당)
|
||||
- 프론트엔드 (Agent D 담당)
|
||||
- 비즈니스 로직 판단 (Agent A에게 확인)
|
||||
|
||||
협업 필요 시:
|
||||
- API에서 필요한 데이터 구조 → Agent B와 협의
|
||||
- 쿼리 결과 사용법 → Agent B에게 전달
|
||||
```
|
||||
|
||||
### Agent D (Frontend) - 프론트엔드 전문가
|
||||
|
||||
```yaml
|
||||
역할: UI/UX 및 클라이언트 로직 담당
|
||||
모델: Claude Sonnet
|
||||
|
||||
담당 영역:
|
||||
폴더:
|
||||
- frontend/components/
|
||||
- frontend/pages/
|
||||
- frontend/lib/
|
||||
- frontend/hooks/
|
||||
- frontend/styles/
|
||||
|
||||
작업:
|
||||
- React 컴포넌트 구현
|
||||
- 페이지 레이아웃
|
||||
- 상태 관리
|
||||
- API 연동 (호출)
|
||||
- 스타일링
|
||||
|
||||
담당 아닌 것:
|
||||
- API 구현 (Agent B 담당)
|
||||
- DB 쿼리 (Agent C 담당)
|
||||
- API 스펙 결정 (Agent A/B와 협의)
|
||||
|
||||
협업 필요 시:
|
||||
- API 엔드포인트 필요 → Agent B에게 요청
|
||||
- 데이터 구조 확인 → Agent C에게 문의
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 통신 프로토콜
|
||||
|
||||
### 메시지 포맷
|
||||
|
||||
```typescript
|
||||
// 요청 메시지
|
||||
interface TaskRequest {
|
||||
id: string; // 고유 ID (예: "task-001")
|
||||
from: 'A' | 'B' | 'C' | 'D'; // 발신자
|
||||
to: 'A' | 'B' | 'C' | 'D'; // 수신자
|
||||
type: 'info_request' | 'work_request' | 'question';
|
||||
priority: 'high' | 'medium' | 'low';
|
||||
content: {
|
||||
task: string; // 작업 내용
|
||||
context?: string; // 배경 정보
|
||||
expected_output?: string; // 기대 결과
|
||||
depends_on?: string[]; // 선행 작업 ID
|
||||
};
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
// 응답 메시지
|
||||
interface TaskResponse {
|
||||
id: string; // 요청 ID와 매칭
|
||||
from: 'A' | 'B' | 'C' | 'D';
|
||||
to: 'A' | 'B' | 'C' | 'D';
|
||||
status: 'success' | 'partial' | 'failed' | 'need_clarification';
|
||||
confidence: 'high' | 'medium' | 'low';
|
||||
|
||||
result?: {
|
||||
summary: string; // 한 줄 요약
|
||||
details: string; // 상세 내용
|
||||
files_affected?: string[]; // 영향받는 파일
|
||||
code_changes?: CodeChange[]; // 코드 변경사항
|
||||
};
|
||||
|
||||
// 메타 정보
|
||||
scope_violations?: string[]; // 스코프 벗어난 요청
|
||||
dependencies?: string[]; // 필요한 선행 작업
|
||||
side_effects?: string[]; // 부작용
|
||||
alternatives?: string[]; // 대안
|
||||
|
||||
// 추가 요청
|
||||
questions?: string[]; // 명확화 필요
|
||||
needs_from_others?: {
|
||||
agent: 'A' | 'B' | 'C' | 'D';
|
||||
request: string;
|
||||
}[];
|
||||
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
// 코드 변경
|
||||
interface CodeChange {
|
||||
file: string;
|
||||
action: 'create' | 'modify' | 'delete';
|
||||
content?: string; // 전체 코드 또는 diff
|
||||
line_start?: number;
|
||||
line_end?: number;
|
||||
}
|
||||
```
|
||||
|
||||
### 상태 코드 정의
|
||||
|
||||
| 상태 | 의미 | 후속 조치 |
|
||||
|------|------|-----------|
|
||||
| `success` | 완전히 완료 | 결과 사용 가능 |
|
||||
| `partial` | 부분 완료 | 추가 작업 필요 |
|
||||
| `failed` | 실패 | 에러 확인 후 재시도 |
|
||||
| `need_clarification` | 명확화 필요 | 질문에 답변 후 재요청 |
|
||||
|
||||
### 확신도 정의
|
||||
|
||||
| 확신도 | 의미 | 권장 조치 |
|
||||
|--------|------|-----------|
|
||||
| `high` | 확실함 | 바로 적용 가능 |
|
||||
| `medium` | 대체로 맞음 | 검토 후 적용 |
|
||||
| `low` | 추측임 | 반드시 검증 필요 |
|
||||
|
||||
---
|
||||
|
||||
## 워크플로우
|
||||
|
||||
### Phase 1: 정보 수집
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Phase 1: 정보 수집 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. User → Agent A: "주문 관리 기능 만들어줘" │
|
||||
│ │
|
||||
│ 2. Agent A 분석: │
|
||||
│ - 기능 범위 파악 │
|
||||
│ - 필요한 정보 식별 │
|
||||
│ - 정보 수집 요청 생성 │
|
||||
│ │
|
||||
│ 3. Agent A → B, C, D (병렬): │
|
||||
│ - B에게: "현재 order 관련 API 구조 분석해줘" │
|
||||
│ - C에게: "orders 테이블 스키마 알려줘" │
|
||||
│ - D에게: "주문 관련 컴포넌트 현황 알려줘" │
|
||||
│ │
|
||||
│ 4. B, C, D → Agent A (응답): │
|
||||
│ - B: API 현황 보고 │
|
||||
│ - C: 스키마 정보 보고 │
|
||||
│ - D: 컴포넌트 현황 보고 │
|
||||
│ │
|
||||
│ 5. Agent A: 정보 취합 및 계획 수립 │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Phase 2: 작업 분배
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Phase 2: 작업 분배 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. Agent A: 종합 계획 수립 │
|
||||
│ ┌─────────────────────────────────────────┐ │
|
||||
│ │ 분석 결과: │ │
|
||||
│ │ - API에 pagination 추가 필요 │ │
|
||||
│ │ - DB는 현재 구조 유지 │ │
|
||||
│ │ - 프론트 무한스크롤 → 페이지네이션 │ │
|
||||
│ │ │ │
|
||||
│ │ 작업 순서: │ │
|
||||
│ │ 1. C: 페이징 쿼리 준비 │ │
|
||||
│ │ 2. B: API 수정 (C 결과 의존) │ │
|
||||
│ │ 3. D: 프론트 수정 (B 결과 의존) │ │
|
||||
│ └─────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 2. Agent A → B, C, D: 작업 할당 │
|
||||
│ - C에게: "cursor 기반 페이징 쿼리 작성" │
|
||||
│ - B에게: "GET /api/orders에 pagination 추가" (C 대기) │
|
||||
│ - D에게: "Pagination 컴포넌트 적용" (B 대기) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Phase 3: 실행 및 통합
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Phase 3: 실행 및 통합 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. 순차/병렬 실행: │
|
||||
│ - C: 쿼리 작성 → 완료 보고 │
|
||||
│ - B: API 수정 (C 완료 후) → 완료 보고 │
|
||||
│ - D: 프론트 수정 (B 완료 후) → 완료 보고 │
|
||||
│ │
|
||||
│ 2. Agent A: 결과 검증 │
|
||||
│ - 일관성 체크 │
|
||||
│ - 누락 확인 │
|
||||
│ - 충돌 해결 │
|
||||
│ │
|
||||
│ 3. Agent A → User: 최종 보고 │
|
||||
│ ┌─────────────────────────────────────────┐ │
|
||||
│ │ 완료된 작업: │ │
|
||||
│ │ ✅ orders.xml - 페이징 쿼리 추가 │ │
|
||||
│ │ ✅ OrderController.ts - pagination 적용 │ │
|
||||
│ │ ✅ OrderListPage.tsx - UI 수정 │ │
|
||||
│ │ │ │
|
||||
│ │ 테스트 필요: │ │
|
||||
│ │ - GET /api/orders?page=1&limit=10 │ │
|
||||
│ └─────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 프롬프트 템플릿
|
||||
|
||||
### Agent A (PM) 시스템 프롬프트
|
||||
|
||||
```markdown
|
||||
# 역할
|
||||
너는 PM(Project Manager) 에이전트야.
|
||||
사용자 요청을 분석하고, 전문가 에이전트들(Backend, DB, Frontend)에게
|
||||
작업을 분배하고, 결과를 통합해서 최종 결과물을 만들어.
|
||||
|
||||
# 사용 가능한 도구
|
||||
- ask_backend_agent: 백엔드 전문가에게 질문/작업 요청
|
||||
- ask_db_agent: DB 전문가에게 질문/작업 요청
|
||||
- ask_frontend_agent: 프론트 전문가에게 질문/작업 요청
|
||||
- parallel_ask: 여러 전문가에게 동시에 요청
|
||||
|
||||
# 작업 프로세스
|
||||
|
||||
## Phase 1: 분석
|
||||
1. 사용자 요청 분석
|
||||
2. 필요한 정보 식별
|
||||
3. 정보 수집 요청 (parallel_ask 활용)
|
||||
|
||||
## Phase 2: 계획
|
||||
1. 수집된 정보 분석
|
||||
2. 작업 분해 및 의존성 파악
|
||||
3. 우선순위 결정
|
||||
4. 작업 분배 계획 수립
|
||||
|
||||
## Phase 3: 실행
|
||||
1. 의존성 순서대로 작업 요청
|
||||
2. 결과 검증
|
||||
3. 필요시 재요청
|
||||
|
||||
## Phase 4: 통합
|
||||
1. 모든 결과 취합
|
||||
2. 일관성 검증
|
||||
3. 사용자에게 보고
|
||||
|
||||
# 작업 분배 기준
|
||||
- Backend Agent: API, 서비스 로직, 라우팅 (backend-node/)
|
||||
- DB Agent: 스키마, 쿼리, 마이그레이션 (mapper/, db/)
|
||||
- Frontend Agent: 컴포넌트, 페이지, 스타일 (frontend/)
|
||||
|
||||
# 판단 기준
|
||||
- 불확실하면 사용자에게 물어봐
|
||||
- 에이전트 결과가 이상하면 재요청
|
||||
- 영향 범위 크면 사용자 확인
|
||||
- 충돌 시 더 안전한 방향 선택
|
||||
|
||||
# 응답 형식
|
||||
작업 분배 시:
|
||||
```json
|
||||
{
|
||||
"phase": "info_gathering | work_distribution | integration",
|
||||
"reasoning": "왜 이렇게 분배하는지",
|
||||
"tasks": [
|
||||
{
|
||||
"agent": "backend | db | frontend",
|
||||
"priority": 1,
|
||||
"task": "구체적인 작업 내용",
|
||||
"depends_on": [],
|
||||
"expected_output": "기대 결과"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
최종 보고 시:
|
||||
```json
|
||||
{
|
||||
"summary": "한 줄 요약",
|
||||
"completed_tasks": ["완료된 작업들"],
|
||||
"files_changed": ["변경된 파일들"],
|
||||
"next_steps": ["다음 단계 (있다면)"],
|
||||
"test_instructions": ["테스트 방법"]
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
### Agent B (Backend) 시스템 프롬프트
|
||||
|
||||
```markdown
|
||||
# 역할
|
||||
너는 Backend 전문가 에이전트야.
|
||||
backend-node/ 폴더의 API, 서비스, 라우팅을 담당해.
|
||||
|
||||
# 담당 영역 (이것만!)
|
||||
- backend-node/src/controllers/
|
||||
- backend-node/src/services/
|
||||
- backend-node/src/routes/
|
||||
- backend-node/src/middleware/
|
||||
- backend-node/src/utils/
|
||||
|
||||
# 담당 아닌 것 (절대 건들지 마)
|
||||
- frontend/ → Frontend Agent 담당
|
||||
- src/com/pms/mapper/ → DB Agent 담당
|
||||
- SQL 쿼리 직접 작성 → DB Agent에게 요청
|
||||
|
||||
# 코드 작성 규칙
|
||||
1. TypeScript 사용
|
||||
2. 에러 핸들링 필수
|
||||
3. 주석은 한글로
|
||||
4. 기존 코드 스타일 따르기
|
||||
5. ... 생략 없이 완전한 코드
|
||||
|
||||
# 응답 형식
|
||||
```json
|
||||
{
|
||||
"status": "success | partial | failed | need_clarification",
|
||||
"confidence": "high | medium | low",
|
||||
"result": {
|
||||
"summary": "한 줄 요약",
|
||||
"details": "상세 설명",
|
||||
"files_affected": ["파일 경로들"],
|
||||
"code_changes": [
|
||||
{
|
||||
"file": "경로",
|
||||
"action": "create | modify | delete",
|
||||
"content": "전체 코드"
|
||||
}
|
||||
]
|
||||
},
|
||||
"needs_from_others": [
|
||||
{"agent": "db", "request": "필요한 것"}
|
||||
],
|
||||
"side_effects": ["영향받는 것들"],
|
||||
"questions": ["명확하지 않은 것들"]
|
||||
}
|
||||
```
|
||||
|
||||
# 협업 규칙
|
||||
1. 내 영역 아니면 즉시 보고 (scope_violation)
|
||||
2. 확실하지 않으면 confidence: "low"
|
||||
3. 다른 에이전트 필요하면 needs_from_others에 명시
|
||||
4. 부작용 있으면 반드시 보고
|
||||
```
|
||||
|
||||
### Agent C (Database) 시스템 프롬프트
|
||||
|
||||
```markdown
|
||||
# 역할
|
||||
너는 Database 전문가 에이전트야.
|
||||
DB 스키마, 쿼리, 마이그레이션을 담당해.
|
||||
|
||||
# 담당 영역 (이것만!)
|
||||
- src/com/pms/mapper/ (MyBatis XML)
|
||||
- db/ (스키마, 마이그레이션)
|
||||
- backend-node/src/database/
|
||||
|
||||
# 담당 아닌 것 (절대 건들지 마)
|
||||
- API 로직 → Backend Agent 담당
|
||||
- 프론트엔드 → Frontend Agent 담당
|
||||
- 비즈니스 로직 판단 → PM에게 확인
|
||||
|
||||
# 코드 작성 규칙
|
||||
1. PostgreSQL 문법 사용
|
||||
2. 파라미터 바인딩 (#{}) 필수 - SQL 인젝션 방지
|
||||
3. 인덱스 고려
|
||||
4. 성능 최적화 (EXPLAIN 결과 고려)
|
||||
|
||||
# MyBatis 매퍼 규칙
|
||||
```xml
|
||||
<!-- 파라미터 바인딩 (안전) -->
|
||||
WHERE id = #{id}
|
||||
|
||||
<!-- 동적 쿼리 -->
|
||||
<if test="name != null and name != ''">
|
||||
AND name LIKE '%' || #{name} || '%'
|
||||
</if>
|
||||
|
||||
<!-- 페이징 -->
|
||||
LIMIT #{limit} OFFSET #{offset}
|
||||
```
|
||||
|
||||
# 응답 형식
|
||||
```json
|
||||
{
|
||||
"status": "success | partial | failed | need_clarification",
|
||||
"confidence": "high | medium | low",
|
||||
"result": {
|
||||
"summary": "한 줄 요약",
|
||||
"details": "상세 설명",
|
||||
"schema_info": {
|
||||
"tables": ["관련 테이블"],
|
||||
"columns": ["주요 컬럼"],
|
||||
"indexes": ["인덱스"]
|
||||
},
|
||||
"code_changes": [
|
||||
{
|
||||
"file": "경로",
|
||||
"action": "create | modify",
|
||||
"content": "쿼리/스키마"
|
||||
}
|
||||
]
|
||||
},
|
||||
"performance_notes": ["성능 관련 참고사항"],
|
||||
"questions": ["명확하지 않은 것들"]
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
### Agent D (Frontend) 시스템 프롬프트
|
||||
|
||||
```markdown
|
||||
# 역할
|
||||
너는 Frontend 전문가 에이전트야.
|
||||
React/Next.js 기반 UI 구현을 담당해.
|
||||
|
||||
# 담당 영역 (이것만!)
|
||||
- frontend/components/
|
||||
- frontend/pages/ (또는 app/)
|
||||
- frontend/lib/
|
||||
- frontend/hooks/
|
||||
- frontend/styles/
|
||||
|
||||
# 담당 아닌 것 (절대 건들지 마)
|
||||
- backend-node/ → Backend Agent 담당
|
||||
- DB 관련 → DB Agent 담당
|
||||
- API 스펙 결정 → PM/Backend와 협의
|
||||
|
||||
# 코드 작성 규칙
|
||||
1. TypeScript 사용
|
||||
2. React 함수형 컴포넌트
|
||||
3. 커스텀 훅 활용
|
||||
4. 주석은 한글로
|
||||
5. Tailwind CSS 또는 기존 스타일 시스템 따르기
|
||||
|
||||
# API 호출 규칙
|
||||
- 절대 fetch 직접 사용 금지
|
||||
- lib/api/ 클라이언트 사용
|
||||
- 에러 핸들링 필수
|
||||
|
||||
# 응답 형식
|
||||
```json
|
||||
{
|
||||
"status": "success | partial | failed | need_clarification",
|
||||
"confidence": "high | medium | low",
|
||||
"result": {
|
||||
"summary": "한 줄 요약",
|
||||
"details": "상세 설명",
|
||||
"components_affected": ["컴포넌트 목록"],
|
||||
"code_changes": [
|
||||
{
|
||||
"file": "경로",
|
||||
"action": "create | modify",
|
||||
"content": "전체 코드"
|
||||
}
|
||||
]
|
||||
},
|
||||
"needs_from_others": [
|
||||
{"agent": "backend", "request": "필요한 API"}
|
||||
],
|
||||
"ui_notes": ["UX 관련 참고사항"],
|
||||
"questions": ["명확하지 않은 것들"]
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## MCP 서버 구현
|
||||
|
||||
### 프로젝트 구조
|
||||
|
||||
```
|
||||
mcp-agent-orchestrator/
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
├── src/
|
||||
│ ├── index.ts # 메인 서버
|
||||
│ ├── agents/
|
||||
│ │ ├── types.ts # 타입 정의
|
||||
│ │ ├── pm.ts # PM 에이전트 프롬프트
|
||||
│ │ ├── backend.ts # Backend 에이전트 프롬프트
|
||||
│ │ ├── database.ts # DB 에이전트 프롬프트
|
||||
│ │ └── frontend.ts # Frontend 에이전트 프롬프트
|
||||
│ └── utils/
|
||||
│ └── logger.ts # 로깅
|
||||
└── build/
|
||||
└── index.js # 컴파일된 파일
|
||||
```
|
||||
|
||||
### 핵심 코드
|
||||
|
||||
```typescript
|
||||
// src/index.ts
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import Anthropic from "@anthropic-ai/sdk";
|
||||
import { PM_PROMPT, BACKEND_PROMPT, DB_PROMPT, FRONTEND_PROMPT } from "./agents";
|
||||
|
||||
const server = new Server({
|
||||
name: "agent-orchestrator",
|
||||
version: "1.0.0",
|
||||
});
|
||||
|
||||
const anthropic = new Anthropic();
|
||||
|
||||
// 에이전트별 설정
|
||||
const AGENT_CONFIG = {
|
||||
pm: { model: "claude-opus-4-5-20250214", prompt: PM_PROMPT },
|
||||
backend: { model: "claude-sonnet-4-20250514", prompt: BACKEND_PROMPT },
|
||||
db: { model: "claude-sonnet-4-20250514", prompt: DB_PROMPT },
|
||||
frontend: { model: "claude-sonnet-4-20250514", prompt: FRONTEND_PROMPT },
|
||||
};
|
||||
|
||||
// 도구 목록
|
||||
server.setRequestHandler("tools/list", async () => ({
|
||||
tools: [
|
||||
{
|
||||
name: "ask_backend_agent",
|
||||
description: "백엔드 전문가에게 질문하거나 작업 요청",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
task: { type: "string", description: "작업 내용" },
|
||||
context: { type: "string", description: "배경 정보 (선택)" },
|
||||
},
|
||||
required: ["task"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ask_db_agent",
|
||||
description: "DB 전문가에게 질문하거나 작업 요청",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
task: { type: "string", description: "작업 내용" },
|
||||
context: { type: "string", description: "배경 정보 (선택)" },
|
||||
},
|
||||
required: ["task"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ask_frontend_agent",
|
||||
description: "프론트엔드 전문가에게 질문하거나 작업 요청",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
task: { type: "string", description: "작업 내용" },
|
||||
context: { type: "string", description: "배경 정보 (선택)" },
|
||||
},
|
||||
required: ["task"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "parallel_ask",
|
||||
description: "여러 전문가에게 동시에 질문 (병렬 실행)",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
requests: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
agent: {
|
||||
type: "string",
|
||||
enum: ["backend", "db", "frontend"]
|
||||
},
|
||||
task: { type: "string" },
|
||||
context: { type: "string" },
|
||||
},
|
||||
required: ["agent", "task"],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["requests"],
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
// 도구 실행
|
||||
server.setRequestHandler("tools/call", async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
const callAgent = async (agentType: string, task: string, context?: string) => {
|
||||
const config = AGENT_CONFIG[agentType];
|
||||
const response = await anthropic.messages.create({
|
||||
model: config.model,
|
||||
max_tokens: 8192,
|
||||
system: config.prompt,
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: context ? `${task}\n\n배경 정보:\n${context}` : task,
|
||||
},
|
||||
],
|
||||
});
|
||||
return response.content[0].text;
|
||||
};
|
||||
|
||||
switch (name) {
|
||||
case "ask_backend_agent":
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: await callAgent("backend", args.task, args.context) },
|
||||
],
|
||||
};
|
||||
|
||||
case "ask_db_agent":
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: await callAgent("db", args.task, args.context) },
|
||||
],
|
||||
};
|
||||
|
||||
case "ask_frontend_agent":
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: await callAgent("frontend", args.task, args.context) },
|
||||
],
|
||||
};
|
||||
|
||||
case "parallel_ask":
|
||||
const results = await Promise.all(
|
||||
args.requests.map(async (req) => ({
|
||||
agent: req.agent,
|
||||
result: await callAgent(req.agent, req.task, req.context),
|
||||
}))
|
||||
);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: JSON.stringify(results, null, 2) },
|
||||
],
|
||||
};
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${name}`);
|
||||
}
|
||||
});
|
||||
|
||||
// 서버 시작
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
```
|
||||
|
||||
### Cursor 설정
|
||||
|
||||
```json
|
||||
// .cursor/mcp.json
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-orchestrator": {
|
||||
"command": "node",
|
||||
"args": ["C:/Users/defaultuser0/mcp-agent-orchestrator/build/index.js"],
|
||||
"env": {
|
||||
"ANTHROPIC_API_KEY": "your-api-key-here"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 비용 분석
|
||||
|
||||
### 토큰 사용량 비교
|
||||
|
||||
| 시나리오 | 단일 에이전트 | 멀티 에이전트 | 절감 |
|
||||
|----------|--------------|--------------|------|
|
||||
| 기능 1개 추가 | 100,000 토큰 | 60,000 토큰 | 40% |
|
||||
| 시스템 리팩토링 | 300,000 토큰 | 150,000 토큰 | 50% |
|
||||
| 새 모듈 개발 | 500,000 토큰 | 200,000 토큰 | 60% |
|
||||
|
||||
### 비용 계산 (예시)
|
||||
|
||||
```
|
||||
단일 에이전트 (전부 Opus):
|
||||
- 300,000 토큰 × $15/M = $4.50
|
||||
|
||||
멀티 에이전트 (Opus PM + Sonnet Workers):
|
||||
- PM (Opus): 50,000 토큰 × $15/M = $0.75
|
||||
- Workers (Sonnet): 100,000 토큰 × $3/M = $0.30
|
||||
- 총: $1.05
|
||||
|
||||
절감: $4.50 - $1.05 = $3.45 (76% 절감!)
|
||||
```
|
||||
|
||||
### ROI 분석
|
||||
|
||||
```
|
||||
초기 투자:
|
||||
- MCP 서버 개발: 4-6시간
|
||||
- 프롬프트 튜닝: 2-4시간
|
||||
- 테스트: 2시간
|
||||
- 총: 8-12시간
|
||||
|
||||
회수:
|
||||
- 대규모 작업당 $3-5 절감
|
||||
- 재작업 시간 70% 감소
|
||||
- 품질 30% 향상
|
||||
|
||||
손익분기점: 대규모 작업 3-5회
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 한계점 및 해결방안
|
||||
|
||||
### 현재 한계
|
||||
|
||||
| 한계 | 설명 | 해결방안 |
|
||||
|------|------|----------|
|
||||
| 완전 자동화 불가 | Cursor 에이전트 간 직접 통신 없음 | MCP 서버로 우회 |
|
||||
| 파일 읽기 제한 | 각 에이전트가 모든 파일 접근 어려움 | 컨텍스트에 필요한 정보 전달 |
|
||||
| 실시간 동기화 | 변경사항 즉시 반영 어려움 | 명시적 갱신 요청 |
|
||||
| 에러 복구 | 자동 롤백 메커니즘 없음 | 수동 복구 또는 git 활용 |
|
||||
|
||||
### 향후 개선 방향
|
||||
|
||||
1. **파일 시스템 연동**
|
||||
- MCP 서버에 파일 읽기/쓰기 도구 추가
|
||||
- 에이전트가 직접 코드 확인 가능
|
||||
|
||||
2. **결과 자동 적용**
|
||||
- 코드 변경사항 자동 적용
|
||||
- git 커밋 자동화
|
||||
|
||||
3. **피드백 루프**
|
||||
- 테스트 자동 실행
|
||||
- 실패 시 자동 재시도
|
||||
|
||||
4. **히스토리 관리**
|
||||
- 대화 이력 저장
|
||||
- 컨텍스트 캐싱
|
||||
|
||||
---
|
||||
|
||||
## 체크리스트
|
||||
|
||||
### 구현 전 준비
|
||||
|
||||
- [ ] Node.js 18+ 설치
|
||||
- [ ] Anthropic API 키 발급
|
||||
- [ ] 프로젝트 폴더 생성
|
||||
|
||||
### MCP 서버 구현
|
||||
|
||||
- [ ] package.json 설정
|
||||
- [ ] TypeScript 설정
|
||||
- [ ] 기본 서버 구조
|
||||
- [ ] 도구 정의 (4개)
|
||||
- [ ] 에이전트 프롬프트 작성
|
||||
- [ ] 빌드 및 테스트
|
||||
|
||||
### Cursor 연동
|
||||
|
||||
- [ ] mcp.json 설정
|
||||
- [ ] Cursor 재시작
|
||||
- [ ] 도구 호출 테스트
|
||||
- [ ] 실제 작업 테스트
|
||||
|
||||
### 튜닝
|
||||
|
||||
- [ ] 프롬프트 개선
|
||||
- [ ] 에러 핸들링 강화
|
||||
- [ ] 로깅 추가
|
||||
- [ ] 성능 최적화
|
||||
|
||||
---
|
||||
|
||||
## 참고 자료
|
||||
|
||||
- [MCP SDK 문서](https://modelcontextprotocol.io/)
|
||||
- [Anthropic API 문서](https://docs.anthropic.com/)
|
||||
- [CrewAI](https://github.com/joaomdmoura/crewAI) - 멀티에이전트 프레임워크 참고
|
||||
- [AutoGen](https://github.com/microsoft/autogen) - Microsoft 멀티에이전트 참고
|
||||
|
||||
---
|
||||
|
||||
*작성일: 2026-02-05*
|
||||
*버전: 1.0*
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
# Multi-Agent Orchestrator MCP Server v2.0
|
||||
|
||||
Cursor Agent CLI를 활용한 멀티에이전트 시스템입니다.
|
||||
**Cursor Team Plan만으로 동작** - 외부 API 키 불필요!
|
||||
|
||||
## 아키텍처
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Cursor IDE (PM Agent) │
|
||||
│ Claude Opus 4.5 │
|
||||
└────────────────────┬────────────────────┘
|
||||
│ MCP Tools
|
||||
┌────────────────┼────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌────────┐ ┌────────┐ ┌────────┐
|
||||
│Backend │ │ DB │ │Frontend│
|
||||
│ Agent │ │ Agent │ │ Agent │
|
||||
│ via CLI│ │ via CLI│ │ via CLI│
|
||||
│Sonnet │ │Sonnet │ │Sonnet │
|
||||
└────────┘ └────────┘ └────────┘
|
||||
↑ ↑ ↑
|
||||
└──────────────┴───────────────┘
|
||||
Cursor Agent CLI
|
||||
(Team Plan 크레딧 사용)
|
||||
```
|
||||
|
||||
## 특징
|
||||
|
||||
- **API 키 불필요**: Cursor Team Plan 크레딧만 사용
|
||||
- **크로스 플랫폼**: Windows, Mac, Linux 지원
|
||||
- **진짜 병렬 실행**: `parallel_ask`로 동시 작업
|
||||
- **모델 티어링**: PM=Opus, Sub-agents=Sonnet
|
||||
|
||||
## 사전 요구사항
|
||||
|
||||
1. **Cursor Team/Pro Plan** 구독
|
||||
2. **Cursor Agent CLI** 설치 및 로그인
|
||||
```bash
|
||||
# 설치 후 로그인 확인
|
||||
agent status
|
||||
```
|
||||
|
||||
## 설치
|
||||
|
||||
```bash
|
||||
cd mcp-agent-orchestrator
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Cursor 설정
|
||||
|
||||
### Windows
|
||||
|
||||
`.cursor/mcp.json`:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-orchestrator": {
|
||||
"command": "node",
|
||||
"args": ["C:/Users/YOUR_USERNAME/ERP-node/mcp-agent-orchestrator/build/index.js"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Mac
|
||||
|
||||
`.cursor/mcp.json`:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-orchestrator": {
|
||||
"command": "node",
|
||||
"args": ["/Users/YOUR_USERNAME/ERP-node/mcp-agent-orchestrator/build/index.js"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**주의**: Mac에서 agent CLI가 PATH에 있어야 합니다.
|
||||
```bash
|
||||
# agent CLI 위치 확인
|
||||
which agent
|
||||
# 보통: ~/.cursor-agent/bin/agent 또는 /usr/local/bin/agent
|
||||
|
||||
# PATH에 없으면 추가 (.zshrc 또는 .bashrc)
|
||||
export PATH="$HOME/.cursor-agent/bin:$PATH"
|
||||
```
|
||||
|
||||
## 사용 가능한 도구
|
||||
|
||||
### ask_backend_agent
|
||||
백엔드 전문가에게 질문/작업 요청
|
||||
- API 설계, 서비스 로직, 라우팅
|
||||
- 담당 폴더: `backend-node/src/`
|
||||
|
||||
### ask_db_agent
|
||||
DB 전문가에게 질문/작업 요청
|
||||
- 스키마, 쿼리, MyBatis 매퍼
|
||||
- 담당 폴더: `src/com/pms/mapper/`, `db/`
|
||||
|
||||
### ask_frontend_agent
|
||||
프론트엔드 전문가에게 질문/작업 요청
|
||||
- React 컴포넌트, 페이지, 스타일
|
||||
- 담당 폴더: `frontend/`
|
||||
|
||||
### parallel_ask
|
||||
여러 전문가에게 동시에 질문 (진짜 병렬 실행!)
|
||||
- 정보 수집 단계에서 유용
|
||||
|
||||
### get_agent_info
|
||||
에이전트 시스템 정보 확인
|
||||
|
||||
## 워크플로우 예시
|
||||
|
||||
### 1단계: 정보 수집 (병렬)
|
||||
```
|
||||
parallel_ask([
|
||||
{ agent: "backend", task: "현재 order 관련 API 구조 분석" },
|
||||
{ agent: "db", task: "orders 테이블 스키마 분석" },
|
||||
{ agent: "frontend", task: "주문 관련 컴포넌트 현황 분석" }
|
||||
])
|
||||
```
|
||||
|
||||
### 2단계: 개별 작업 (순차)
|
||||
```
|
||||
ask_db_agent("cursor 기반 페이징 쿼리 작성")
|
||||
ask_backend_agent("GET /api/orders에 pagination 추가")
|
||||
ask_frontend_agent("Pagination 컴포넌트 적용")
|
||||
```
|
||||
|
||||
## 모델 설정
|
||||
|
||||
| Agent | Model | 역할 |
|
||||
|-------|-------|------|
|
||||
| PM (Cursor IDE) | Opus 4.5 | 전체 조율, 사용자 대화 |
|
||||
| Backend | Sonnet 4.5 | API, 서비스 로직 |
|
||||
| DB | Sonnet 4.5 | 스키마, 쿼리 |
|
||||
| Frontend | Sonnet 4.5 | 컴포넌트, UI |
|
||||
|
||||
**비용 최적화**: PM만 Opus, 나머지는 Sonnet 사용
|
||||
|
||||
## 환경 변수
|
||||
|
||||
- `LOG_LEVEL`: 로그 레벨 (debug, info, warn, error)
|
||||
|
||||
## 트러블슈팅
|
||||
|
||||
### Windows: agent 명령어가 안 됨
|
||||
```powershell
|
||||
# PowerShell 실행 정책 확인
|
||||
Get-ExecutionPolicy -List
|
||||
|
||||
# 필요시 변경
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
```
|
||||
|
||||
### Mac: agent 명령어를 찾을 수 없음
|
||||
```bash
|
||||
# agent CLI 위치 확인
|
||||
ls -la ~/.cursor-agent/bin/
|
||||
|
||||
# PATH 추가
|
||||
echo 'export PATH="$HOME/.cursor-agent/bin:$PATH"' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
### 응답이 오래 걸림
|
||||
- 정상입니다! 각 에이전트 호출에 15-30초 소요
|
||||
- `parallel_ask`로 병렬 처리하면 시간 절약
|
||||
|
||||
## 개발
|
||||
|
||||
```bash
|
||||
# 개발 모드 (watch)
|
||||
npm run dev
|
||||
|
||||
# 빌드
|
||||
npm run build
|
||||
|
||||
# 테스트 실행
|
||||
npm start
|
||||
```
|
||||
|
||||
## 라이선스
|
||||
|
||||
MIT
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "mcp-agent-orchestrator",
|
||||
"version": "2.0.0",
|
||||
"description": "Multi-Agent Orchestrator MCP Server using Cursor Agent CLI (Team Plan)",
|
||||
"type": "module",
|
||||
"main": "build/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node build/index.js",
|
||||
"dev": "tsc --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"cursor",
|
||||
"mcp",
|
||||
"multi-agent",
|
||||
"ai",
|
||||
"orchestrator"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* 에이전트 모듈 내보내기
|
||||
*/
|
||||
|
||||
export * from "./types.js";
|
||||
export * from "./prompts.js";
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
/**
|
||||
* Agent System Prompts (English to avoid CMD encoding issues)
|
||||
* Agents will still respond in Korean based on user preferences
|
||||
*/
|
||||
|
||||
export const PM_PROMPT = `# Role
|
||||
You are a PM (Project Manager) agent.
|
||||
Analyze user requests, distribute tasks to specialist agents (Backend, DB, Frontend),
|
||||
and integrate results to create the final deliverable.
|
||||
|
||||
# Available Tools
|
||||
- ask_backend_agent: Ask/request tasks from backend expert
|
||||
- ask_db_agent: Ask/request tasks from DB expert
|
||||
- ask_frontend_agent: Ask/request tasks from frontend expert
|
||||
- parallel_ask: Request from multiple experts simultaneously
|
||||
|
||||
# Work Process
|
||||
|
||||
## Phase 1: Analysis
|
||||
1. Analyze user request
|
||||
2. Identify required information
|
||||
3. Request info gathering (use parallel_ask)
|
||||
|
||||
## Phase 2: Planning
|
||||
1. Analyze gathered information
|
||||
2. Break down tasks and identify dependencies
|
||||
3. Determine priorities
|
||||
4. Create work distribution plan
|
||||
|
||||
## Phase 3: Execution
|
||||
1. Request tasks in dependency order
|
||||
2. Verify results
|
||||
3. Re-request if needed
|
||||
|
||||
## Phase 4: Integration
|
||||
1. Collect all results
|
||||
2. Verify consistency
|
||||
3. Report to user
|
||||
|
||||
# Task Distribution Criteria
|
||||
- Backend Agent: API, service logic, routing (backend-node/)
|
||||
- DB Agent: Schema, queries, migrations (mapper/, db/)
|
||||
- Frontend Agent: Components, pages, styles (frontend/)
|
||||
|
||||
# Decision Criteria
|
||||
- Ask user if uncertain
|
||||
- Re-request if agent result seems wrong
|
||||
- Confirm with user if impact is large
|
||||
- Choose safer direction when conflicts arise
|
||||
|
||||
# Response Format
|
||||
Use JSON format when distributing tasks:
|
||||
{
|
||||
"phase": "info_gathering | work_distribution | integration",
|
||||
"reasoning": "why distributing this way",
|
||||
"tasks": [
|
||||
{
|
||||
"agent": "backend | db | frontend",
|
||||
"priority": 1,
|
||||
"task": "specific task content",
|
||||
"depends_on": [],
|
||||
"expected_output": "expected result"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Final report:
|
||||
{
|
||||
"summary": "one line summary",
|
||||
"completed_tasks": ["completed tasks"],
|
||||
"files_changed": ["changed files"],
|
||||
"next_steps": ["next steps"],
|
||||
"test_instructions": ["how to test"]
|
||||
}`;
|
||||
|
||||
export const BACKEND_PROMPT = `# Role
|
||||
You are a Backend specialist agent.
|
||||
You handle API, services, and routing in the backend-node/ folder.
|
||||
|
||||
# Your Domain (ONLY these!)
|
||||
- backend-node/src/controllers/
|
||||
- backend-node/src/services/
|
||||
- backend-node/src/routes/
|
||||
- backend-node/src/middleware/
|
||||
- backend-node/src/utils/
|
||||
|
||||
# NOT Your Domain (NEVER touch)
|
||||
- frontend/ -> Frontend Agent handles this
|
||||
- src/com/pms/mapper/ -> DB Agent handles this
|
||||
- Direct SQL queries -> Request from DB Agent
|
||||
|
||||
# Code Rules
|
||||
1. Use TypeScript
|
||||
2. Error handling required
|
||||
3. Comments in Korean
|
||||
4. Follow existing code style
|
||||
5. Complete code, no ... ellipsis
|
||||
|
||||
# Response Format (JSON)
|
||||
{
|
||||
"status": "success | partial | failed | need_clarification",
|
||||
"confidence": "high | medium | low",
|
||||
"result": {
|
||||
"summary": "one line summary",
|
||||
"details": "detailed explanation",
|
||||
"files_affected": ["file paths"],
|
||||
"code_changes": [
|
||||
{
|
||||
"file": "path",
|
||||
"action": "create | modify | delete",
|
||||
"content": "complete code"
|
||||
}
|
||||
]
|
||||
},
|
||||
"needs_from_others": [
|
||||
{"agent": "db", "request": "what you need"}
|
||||
],
|
||||
"side_effects": ["affected areas"],
|
||||
"questions": ["unclear points"]
|
||||
}
|
||||
|
||||
# Collaboration Rules
|
||||
1. Report immediately if out of scope (scope_violation)
|
||||
2. Set confidence: "low" if uncertain
|
||||
3. Specify in needs_from_others if other agents needed
|
||||
4. Always report side effects`;
|
||||
|
||||
export const DB_PROMPT = `# Role
|
||||
You are a Database specialist agent.
|
||||
You handle DB schema, queries, and migrations.
|
||||
|
||||
# Your Domain (ONLY these!)
|
||||
- src/com/pms/mapper/ (MyBatis XML)
|
||||
- db/ (schema, migrations)
|
||||
- backend-node/src/database/
|
||||
|
||||
# NOT Your Domain (NEVER touch)
|
||||
- API logic -> Backend Agent handles this
|
||||
- Frontend -> Frontend Agent handles this
|
||||
- Business logic decisions -> Confirm with PM
|
||||
|
||||
# Code Rules
|
||||
1. Use PostgreSQL syntax
|
||||
2. Parameter binding (#{}) required - prevent SQL injection
|
||||
3. Consider indexes
|
||||
4. Consider performance optimization
|
||||
|
||||
# MyBatis Mapper Rules
|
||||
- Parameter binding: WHERE id = #{id}
|
||||
- Dynamic queries: <if test="name != null">...</if>
|
||||
- Pagination: LIMIT #{limit} OFFSET #{offset}
|
||||
|
||||
# Response Format (JSON)
|
||||
{
|
||||
"status": "success | partial | failed | need_clarification",
|
||||
"confidence": "high | medium | low",
|
||||
"result": {
|
||||
"summary": "one line summary",
|
||||
"details": "detailed explanation",
|
||||
"schema_info": {
|
||||
"tables": ["related tables"],
|
||||
"columns": ["main columns"],
|
||||
"indexes": ["indexes"]
|
||||
},
|
||||
"code_changes": [
|
||||
{
|
||||
"file": "path",
|
||||
"action": "create | modify",
|
||||
"content": "query/schema"
|
||||
}
|
||||
]
|
||||
},
|
||||
"performance_notes": ["performance considerations"],
|
||||
"questions": ["unclear points"]
|
||||
}
|
||||
|
||||
# Collaboration Rules
|
||||
1. Report immediately if out of scope
|
||||
2. Set confidence: "low" if uncertain
|
||||
3. Always mention performance issues`;
|
||||
|
||||
export const FRONTEND_PROMPT = `# Role
|
||||
You are a Frontend specialist agent.
|
||||
You handle React/Next.js UI implementation.
|
||||
|
||||
# Your Domain (ONLY these!)
|
||||
- frontend/components/
|
||||
- frontend/pages/ or frontend/app/
|
||||
- frontend/lib/
|
||||
- frontend/hooks/
|
||||
- frontend/styles/
|
||||
|
||||
# NOT Your Domain (NEVER touch)
|
||||
- backend-node/ -> Backend Agent handles this
|
||||
- DB related -> DB Agent handles this
|
||||
- API spec decisions -> Discuss with PM/Backend
|
||||
|
||||
# Code Rules
|
||||
1. Use TypeScript
|
||||
2. React functional components
|
||||
3. Use custom hooks
|
||||
4. Comments in Korean
|
||||
5. Follow Tailwind CSS or existing style system
|
||||
|
||||
# API Call Rules
|
||||
- NEVER use fetch directly!
|
||||
- Use lib/api/ client
|
||||
- Error handling required
|
||||
|
||||
# Response Format (JSON)
|
||||
{
|
||||
"status": "success | partial | failed | need_clarification",
|
||||
"confidence": "high | medium | low",
|
||||
"result": {
|
||||
"summary": "one line summary",
|
||||
"details": "detailed explanation",
|
||||
"components_affected": ["component list"],
|
||||
"code_changes": [
|
||||
{
|
||||
"file": "path",
|
||||
"action": "create | modify",
|
||||
"content": "complete code"
|
||||
}
|
||||
]
|
||||
},
|
||||
"needs_from_others": [
|
||||
{"agent": "backend", "request": "needed API"}
|
||||
],
|
||||
"ui_notes": ["UX considerations"],
|
||||
"questions": ["unclear points"]
|
||||
}
|
||||
|
||||
# Collaboration Rules
|
||||
1. Report immediately if out of scope
|
||||
2. Set confidence: "low" if uncertain
|
||||
3. Specify in needs_from_others if API needed
|
||||
4. Suggest UX improvements if any`;
|
||||
|
||||
// 에이전트 설정 맵
|
||||
export const AGENT_CONFIGS = {
|
||||
pm: {
|
||||
model: 'claude-opus-4-5-20250214',
|
||||
systemPrompt: PM_PROMPT,
|
||||
maxTokens: 8192,
|
||||
},
|
||||
backend: {
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
systemPrompt: BACKEND_PROMPT,
|
||||
maxTokens: 8192,
|
||||
},
|
||||
db: {
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
systemPrompt: DB_PROMPT,
|
||||
maxTokens: 8192,
|
||||
},
|
||||
frontend: {
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
systemPrompt: FRONTEND_PROMPT,
|
||||
maxTokens: 8192,
|
||||
},
|
||||
} as const;
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* Multi-Agent System 타입 정의
|
||||
*/
|
||||
|
||||
// 에이전트 타입
|
||||
export type AgentType = 'pm' | 'backend' | 'db' | 'frontend';
|
||||
|
||||
// 에이전트 설정
|
||||
export interface AgentConfig {
|
||||
model: string;
|
||||
systemPrompt: string;
|
||||
maxTokens: number;
|
||||
}
|
||||
|
||||
// 작업 요청
|
||||
export interface TaskRequest {
|
||||
agent: AgentType;
|
||||
task: string;
|
||||
context?: string;
|
||||
}
|
||||
|
||||
// 작업 응답 상태
|
||||
export type ResponseStatus = 'success' | 'partial' | 'failed' | 'need_clarification';
|
||||
|
||||
// 확신도
|
||||
export type ConfidenceLevel = 'high' | 'medium' | 'low';
|
||||
|
||||
// 코드 변경
|
||||
export interface CodeChange {
|
||||
file: string;
|
||||
action: 'create' | 'modify' | 'delete';
|
||||
content?: string;
|
||||
lineStart?: number;
|
||||
lineEnd?: number;
|
||||
}
|
||||
|
||||
// 에이전트 응답
|
||||
export interface AgentResponse {
|
||||
status: ResponseStatus;
|
||||
confidence: ConfidenceLevel;
|
||||
result?: {
|
||||
summary: string;
|
||||
details: string;
|
||||
filesAffected?: string[];
|
||||
codeChanges?: CodeChange[];
|
||||
};
|
||||
scopeViolations?: string[];
|
||||
dependencies?: string[];
|
||||
sideEffects?: string[];
|
||||
alternatives?: string[];
|
||||
questions?: string[];
|
||||
needsFromOthers?: {
|
||||
agent: AgentType;
|
||||
request: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
// 병렬 요청 결과
|
||||
export interface ParallelResult {
|
||||
agent: AgentType;
|
||||
result: string;
|
||||
error?: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,401 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* Multi-Agent Orchestrator MCP Server
|
||||
*
|
||||
* Cursor Agent CLI를 활용한 멀티에이전트 시스템
|
||||
* - PM (Cursor IDE): 전체 조율
|
||||
* - Sub-agents (agent CLI): 전문가별 작업 수행
|
||||
*
|
||||
* 모든 AI 호출이 Cursor Team Plan으로 처리됨!
|
||||
* API 키 불필요!
|
||||
*/
|
||||
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
import { platform } from "os";
|
||||
import { AGENT_CONFIGS } from "./agents/prompts.js";
|
||||
import { AgentType, ParallelResult } from "./agents/types.js";
|
||||
import { logger } from "./utils/logger.js";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
// OS 감지
|
||||
const isWindows = platform() === "win32";
|
||||
logger.info(`Platform detected: ${platform()} (isWindows: ${isWindows})`);
|
||||
|
||||
// MCP 서버 생성
|
||||
const server = new Server(
|
||||
{
|
||||
name: "agent-orchestrator",
|
||||
version: "2.0.0",
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Cursor Agent CLI를 통해 에이전트 호출
|
||||
* Cursor Team Plan 사용 - API 키 불필요!
|
||||
*
|
||||
* 크로스 플랫폼 지원:
|
||||
* - Windows: cmd /c "echo. | agent ..." (stdin 닫기 위해)
|
||||
* - Mac/Linux: echo "" | agent ... (bash 사용)
|
||||
*/
|
||||
async function callAgentCLI(
|
||||
agentType: AgentType,
|
||||
task: string,
|
||||
context?: string
|
||||
): Promise<string> {
|
||||
const config = AGENT_CONFIGS[agentType];
|
||||
|
||||
// 모델 선택: PM은 opus, 나머지는 sonnet
|
||||
const model = agentType === 'pm' ? 'opus-4.5' : 'sonnet-4.5';
|
||||
|
||||
logger.info(`Calling ${agentType} agent via CLI`, { model, task: task.substring(0, 100) });
|
||||
|
||||
try {
|
||||
// 프롬프트 구성
|
||||
const systemPrompt = config.systemPrompt
|
||||
.replace(/\r?\n/g, ' ') // 줄바꿈을 공백으로
|
||||
.replace(/"/g, '\\"'); // 쌍따옴표 이스케이프
|
||||
|
||||
const userMessage = context
|
||||
? `${task} (Background info: ${context})`
|
||||
: task;
|
||||
|
||||
// 전체 프롬프트 (시스템 + 유저)
|
||||
const fullPrompt = `SYSTEM INSTRUCTIONS: ${systemPrompt} --- TASK REQUEST: ${userMessage}`
|
||||
.replace(/\[/g, '(') // 대괄호를 괄호로 변환 (쉘 호환)
|
||||
.replace(/\]/g, ')')
|
||||
.replace(/"/g, '\\"'); // 쌍따옴표 이스케이프
|
||||
|
||||
let cmd: string;
|
||||
let shell: string;
|
||||
|
||||
if (isWindows) {
|
||||
// Windows: CMD를 통해 echo로 빈 입력 파이프
|
||||
cmd = `cmd /c "echo. | agent -p \\"${fullPrompt}\\" --model ${model} --output-format text"`;
|
||||
shell = 'cmd.exe';
|
||||
} else {
|
||||
// Mac/Linux: Bash를 통해 빈 문자열 파이프
|
||||
// 참고: Mac에서는 agent CLI가 ~/.cursor-agent/bin/agent 경로에 있을 수 있음
|
||||
cmd = `echo "" | agent -p "${fullPrompt}" --model ${model} --output-format text`;
|
||||
shell = '/bin/bash';
|
||||
}
|
||||
|
||||
logger.debug(`Executing on ${isWindows ? 'Windows' : 'Mac/Linux'}: agent -p "..." --model ${model}`);
|
||||
|
||||
const { stdout, stderr } = await execAsync(cmd, {
|
||||
cwd: process.cwd(),
|
||||
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
||||
timeout: 300000, // 5분 타임아웃
|
||||
shell,
|
||||
});
|
||||
|
||||
if (stderr && !stderr.includes('warning')) {
|
||||
logger.warn(`${agentType} agent stderr`, { stderr });
|
||||
}
|
||||
|
||||
logger.info(`${agentType} agent completed via CLI`);
|
||||
return stdout.trim();
|
||||
} catch (error) {
|
||||
logger.error(`${agentType} agent CLI error`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 도구 목록 핸들러
|
||||
*/
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
return {
|
||||
tools: [
|
||||
{
|
||||
name: "ask_backend_agent",
|
||||
description:
|
||||
"백엔드 전문가에게 질문하거나 작업을 요청합니다. " +
|
||||
"API 설계, 서비스 로직, 라우팅, 미들웨어 관련 작업에 사용하세요. " +
|
||||
"담당 폴더: backend-node/src/ (Cursor Team Plan 사용, sonnet-4.5 모델)",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
task: {
|
||||
type: "string",
|
||||
description: "백엔드 에이전트에게 요청할 작업 내용",
|
||||
},
|
||||
context: {
|
||||
type: "string",
|
||||
description: "작업에 필요한 배경 정보 (선택사항)",
|
||||
},
|
||||
},
|
||||
required: ["task"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ask_db_agent",
|
||||
description:
|
||||
"DB 전문가에게 질문하거나 작업을 요청합니다. " +
|
||||
"스키마 설계, SQL 쿼리, MyBatis 매퍼, 마이그레이션 관련 작업에 사용하세요. " +
|
||||
"담당 폴더: src/com/pms/mapper/, db/ (Cursor Team Plan 사용, sonnet-4.5 모델)",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
task: {
|
||||
type: "string",
|
||||
description: "DB 에이전트에게 요청할 작업 내용",
|
||||
},
|
||||
context: {
|
||||
type: "string",
|
||||
description: "작업에 필요한 배경 정보 (선택사항)",
|
||||
},
|
||||
},
|
||||
required: ["task"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ask_frontend_agent",
|
||||
description:
|
||||
"프론트엔드 전문가에게 질문하거나 작업을 요청합니다. " +
|
||||
"React 컴포넌트, 페이지, 스타일링, 상태관리 관련 작업에 사용하세요. " +
|
||||
"담당 폴더: frontend/ (Cursor Team Plan 사용, sonnet-4.5 모델)",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
task: {
|
||||
type: "string",
|
||||
description: "프론트엔드 에이전트에게 요청할 작업 내용",
|
||||
},
|
||||
context: {
|
||||
type: "string",
|
||||
description: "작업에 필요한 배경 정보 (선택사항)",
|
||||
},
|
||||
},
|
||||
required: ["task"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "parallel_ask",
|
||||
description:
|
||||
"여러 전문가에게 동시에 질문합니다 (진짜 병렬 실행!). " +
|
||||
"정보 수집 단계에서 모든 영역의 현황을 빠르게 파악할 때 유용합니다. " +
|
||||
"모든 에이전트가 동시에 실행되어 시간 절약! (Cursor Team Plan 사용)",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
requests: {
|
||||
type: "array",
|
||||
description: "각 에이전트에게 보낼 요청 목록",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
agent: {
|
||||
type: "string",
|
||||
enum: ["backend", "db", "frontend"],
|
||||
description: "요청할 에이전트 타입",
|
||||
},
|
||||
task: {
|
||||
type: "string",
|
||||
description: "해당 에이전트에게 요청할 작업",
|
||||
},
|
||||
context: {
|
||||
type: "string",
|
||||
description: "배경 정보 (선택사항)",
|
||||
},
|
||||
},
|
||||
required: ["agent", "task"],
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["requests"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get_agent_info",
|
||||
description:
|
||||
"에이전트 시스템의 현재 상태와 사용 가능한 에이전트 정보를 확인합니다.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* 도구 호출 핸들러
|
||||
*/
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
logger.info(`Tool called: ${name}`);
|
||||
|
||||
try {
|
||||
switch (name) {
|
||||
case "ask_backend_agent": {
|
||||
const { task, context } = args as { task: string; context?: string };
|
||||
const result = await callAgentCLI("backend", task, context);
|
||||
return {
|
||||
content: [{ type: "text" as const, text: result }],
|
||||
};
|
||||
}
|
||||
|
||||
case "ask_db_agent": {
|
||||
const { task, context } = args as { task: string; context?: string };
|
||||
const result = await callAgentCLI("db", task, context);
|
||||
return {
|
||||
content: [{ type: "text" as const, text: result }],
|
||||
};
|
||||
}
|
||||
|
||||
case "ask_frontend_agent": {
|
||||
const { task, context } = args as { task: string; context?: string };
|
||||
const result = await callAgentCLI("frontend", task, context);
|
||||
return {
|
||||
content: [{ type: "text" as const, text: result }],
|
||||
};
|
||||
}
|
||||
|
||||
case "parallel_ask": {
|
||||
const { requests } = args as {
|
||||
requests: Array<{
|
||||
agent: "backend" | "db" | "frontend";
|
||||
task: string;
|
||||
context?: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
logger.info(`Parallel ask to ${requests.length} agents (TRUE PARALLEL!)`);
|
||||
|
||||
// 진짜 병렬 실행! 모든 에이전트가 동시에 작업
|
||||
const results: ParallelResult[] = await Promise.all(
|
||||
requests.map(async (req) => {
|
||||
try {
|
||||
const result = await callAgentCLI(req.agent, req.task, req.context);
|
||||
return { agent: req.agent, result };
|
||||
} catch (error) {
|
||||
return {
|
||||
agent: req.agent,
|
||||
result: "",
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// 결과를 보기 좋게 포맷팅
|
||||
const formattedResults = results.map((r) => {
|
||||
const header = `\n${"=".repeat(60)}\n## ${r.agent.toUpperCase()} Agent 응답\n${"=".repeat(60)}\n`;
|
||||
if (r.error) {
|
||||
return `${header}❌ 에러: ${r.error}`;
|
||||
}
|
||||
return `${header}${r.result}`;
|
||||
});
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: formattedResults.join("\n"),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case "get_agent_info": {
|
||||
const info = {
|
||||
system: "Multi-Agent Orchestrator v2.0",
|
||||
version: "2.0.0",
|
||||
backend: "Cursor Agent CLI (Team Plan)",
|
||||
apiKey: "NOT REQUIRED! Using Cursor subscription",
|
||||
agents: {
|
||||
pm: {
|
||||
role: "Project Manager",
|
||||
model: "opus-4.5 (Cursor IDE에서 직접)",
|
||||
description: "전체 조율, 사용자 의도 파악, 작업 분배",
|
||||
},
|
||||
backend: {
|
||||
role: "Backend Specialist",
|
||||
model: "sonnet-4.5 (via agent CLI)",
|
||||
description: "API, 서비스 로직, 라우팅 담당",
|
||||
folder: "backend-node/src/",
|
||||
},
|
||||
db: {
|
||||
role: "Database Specialist",
|
||||
model: "sonnet-4.5 (via agent CLI)",
|
||||
description: "스키마, 쿼리, 마이그레이션 담당",
|
||||
folder: "src/com/pms/mapper/, db/",
|
||||
},
|
||||
frontend: {
|
||||
role: "Frontend Specialist",
|
||||
model: "sonnet-4.5 (via agent CLI)",
|
||||
description: "컴포넌트, 페이지, 스타일링 담당",
|
||||
folder: "frontend/",
|
||||
},
|
||||
},
|
||||
features: {
|
||||
parallel_execution: true,
|
||||
cursor_team_plan: true,
|
||||
separate_api_key: false,
|
||||
real_multi_session: true,
|
||||
},
|
||||
usage: {
|
||||
single_agent: "ask_backend_agent, ask_db_agent, ask_frontend_agent",
|
||||
parallel: "parallel_ask로 여러 에이전트 동시 호출",
|
||||
workflow: "1. parallel_ask로 정보 수집 → 2. 개별 에이전트로 작업 분배",
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: JSON.stringify(info, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Tool error: ${name}`, error);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: `❌ 에러 발생: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 서버 시작
|
||||
*/
|
||||
async function main() {
|
||||
logger.info("Starting Multi-Agent Orchestrator MCP Server v2.0...");
|
||||
logger.info("Backend: Cursor Agent CLI (Team Plan - No API Key Required!)");
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
|
||||
logger.info("MCP Server connected and ready!");
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
logger.error("Server failed to start", error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* 간단한 로깅 유틸리티
|
||||
*/
|
||||
|
||||
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
||||
|
||||
const LOG_LEVELS: Record<LogLevel, number> = {
|
||||
debug: 0,
|
||||
info: 1,
|
||||
warn: 2,
|
||||
error: 3,
|
||||
};
|
||||
|
||||
// 환경변수로 로그 레벨 설정 (기본: info)
|
||||
const currentLevel = (process.env.LOG_LEVEL as LogLevel) || 'info';
|
||||
|
||||
function shouldLog(level: LogLevel): boolean {
|
||||
return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
|
||||
}
|
||||
|
||||
function formatMessage(level: LogLevel, message: string, data?: unknown): string {
|
||||
const timestamp = new Date().toISOString();
|
||||
const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
|
||||
|
||||
if (data) {
|
||||
return `${prefix} ${message} ${JSON.stringify(data, null, 2)}`;
|
||||
}
|
||||
return `${prefix} ${message}`;
|
||||
}
|
||||
|
||||
export const logger = {
|
||||
debug(message: string, data?: unknown): void {
|
||||
if (shouldLog('debug')) {
|
||||
console.error(formatMessage('debug', message, data));
|
||||
}
|
||||
},
|
||||
|
||||
info(message: string, data?: unknown): void {
|
||||
if (shouldLog('info')) {
|
||||
console.error(formatMessage('info', message, data));
|
||||
}
|
||||
},
|
||||
|
||||
warn(message: string, data?: unknown): void {
|
||||
if (shouldLog('warn')) {
|
||||
console.error(formatMessage('warn', message, data));
|
||||
}
|
||||
},
|
||||
|
||||
error(message: string, data?: unknown): void {
|
||||
if (shouldLog('error')) {
|
||||
console.error(formatMessage('error', message, data));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"outDir": "./build",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "build"]
|
||||
}
|
||||
Loading…
Reference in New Issue