Skip to main content
Glama

WhaTap MXQL CLI

by devload
ANALYSIS.md17.6 kB
# WhaTap MXQL MCP Server - 분석 및 설계 문서 ## 📋 분석 요약 ### 1. 기존 MXQL for Claude Code - **Repository**: https://github.com/kyupid/mxql-for-claude-code - **Type**: Claude Code Skill (Python 기반) - **기능**: - MXQL 쿼리 생성 (자연어 → MXQL) - 문법 검증 및 최적화 분석 - 테스트 쿼리 생성 - 카테고리 검색 (631개 메트릭) - **한계**: 실제 WhaTap 서비스 API 연동 없음 (오프라인 도구) ### 2. WhaTap Mobile App 인증 메커니즘 #### 2.1 인증 흐름 (Multi-Step Authentication) ``` Step 1: CSRF 토큰 획득 GET /account/login?lang=en Response: HTML에서 CSRF 토큰 추출 Step 2: 웹 로그인 POST /account/login Body: email, password, _csrf, rememberMe=on Headers: Content-Type: application/x-www-form-urlencoded Response: Cookies (wa, JSESSIONID) Step 3: 모바일 API 토큰 획득 POST /mobile/api/login Body: { email, password, appVersion, deviceInfo, deviceModel, deviceType, fcmToken, osVersion } Headers: Content-Type: application/json Cookies: wa, JSESSIONID (from Step 2) Response: { accountId, apiToken } Step 4 (Optional): OTP 검증 POST /account/api/checkOtpToken Body: { accountId, otpToken } Response: { result: true/false } ``` **코드 위치**: - Login Provider: `/src/lib/provider/login_provider.dart:196-231` - Web Login API: `/src/lib/api/web/login_api.dart:22-146` - Mobile Login API: `/src/lib/api/mobile/login_api.dart:19-44` #### 2.2 인증 상태 관리 - **쿠키 기반**: `wa`, `JSESSIONID` (CookieJar로 자동 관리) - **API 토큰**: Open API 호출 시 `x-whatap-token` 헤더 사용 - **저장**: SharedPreferences에 UserStatus 저장 (email, apiToken, accountId) ### 3. MXQL API 호출 메커니즘 #### 3.1 MXQL 데이터 구조 ```dart // /src/lib/model/api/mxql.dart class MXQL { String? type; // "mxql" int? pcode; // Project Code Params? params; String? path; // "text" or "path" } class Params { String? mql; // MXQL 쿼리 문자열 Inject? inject; // 변수 주입 (optional) int? stime; // Start time (milliseconds) int? etime; // End time (milliseconds) int? limit; // 결과 제한 (default: 10000) } ``` **실제 사용 예시** (`/src/lib/api/web/panel_api.dart:118-158`): ```dart final mxql = MXQL( type: 'mxql', pcode: pCode, params: Params( mql: ''' TIME-RANGE {duration:1m, etime:\$etime} CATEGORY container TAGLOAD { backward: true } SELECT ["Deployment","containerId","microOid","podName"] ''', stime: DateTime.now().subtract(Duration(minutes: 1)).millisecondsSinceEpoch, etime: DateTime.now().millisecondsSinceEpoch, limit: 1000, inject: null ), path: 'text', ); ``` #### 3.2 MXQL API 엔드포인트 **URL**: `POST /yard/api/flush` **요청**: ```json { "type": "mxql", "pcode": 12345, "params": { "mql": "CATEGORY app_counter\nOID [\$oid]\nTAGLOAD", "stime": 1699900000000, "etime": 1699900060000, "limit": 10000 }, "path": "text" } ``` **Headers**: ``` Content-Type: application/json Cookie: wa={cookie_value}; JSESSIONID={session_id} ``` **응답**: ```json [ { "oid": 123456789, "oname": "app-server-1", "value": 42.5, ... } ] ``` **코드 위치**: - MXQL 실행: `/src/lib/api/web/product/product_base_api.dart:44-65` - APM 예시: `/src/lib/api/web/product/apm_api.dart:20-43` - Container 예시: `/src/lib/api/web/panel_api.dart:111-199` #### 3.3 API 서비스 구조 **ApiService** (`/src/lib/service/api_service.dart`): - **Singleton 패턴**: 단일 Dio 인스턴스 - **CookieJar**: 자동 쿠키 관리 - **Interceptors**: Rate limiting, Logging, Curl 변환 - **Headers**: `json()` 메서드로 Content-Type 설정 ```dart Dio dio = ApiService().json(); // Content-Type: application/json final response = await dio.post('/yard/api/flush', data: mxql.toJson()); ``` ### 4. Open API 사용 (대안) **프로젝트 목록 조회**: ```dart // /src/lib/api/open/project_api.dart:13-32 GET /open/api/json/projects Headers: x-whatap-token: {apiToken} ``` **특징**: - API 토큰만으로 인증 가능 (쿠키 불필요) - 간단한 REST API - 공식 문서: https://docs.whatap.io/openapi-spec/ --- ## 🏗️ MCP 서버 아키텍처 설계 ### 1. 기술 스택 선택 **Option A: Node.js + TypeScript (추천)** - MCP SDK 공식 지원 - WhaTap API와 동일한 환경 (JavaScript/TypeScript) - 풍부한 HTTP 클라이언트 라이브러리 **Option B: Python** - 기존 mxql-for-claude-code와 통합 용이 - MCP SDK Python 버전 사용 **선택: Node.js + TypeScript** - 이유: MCP 생태계 성숙도, 비동기 처리 우수, WhaTap 팀과 기술 스택 유사 ### 2. MCP 서버 구조 ``` mxql-mcp-server/ ├── src/ │ ├── index.ts # MCP 서버 진입점 │ ├── auth/ │ │ ├── AuthManager.ts # 인증 관리자 │ │ └── SessionStore.ts # 세션 저장소 │ ├── api/ │ │ ├── WhatapClient.ts # WhaTap API 클라이언트 │ │ └── MxqlExecutor.ts # MXQL 실행기 │ ├── tools/ │ │ ├── login.ts # Tool: whatap_login │ │ ├── execute_mxql.ts # Tool: execute_mxql │ │ ├── list_projects.ts # Tool: list_projects │ │ └── validate_mxql.ts # Tool: validate_mxql (기존 validator 활용) │ ├── resources/ │ │ └── mxql_categories.ts # Resource: MXQL 카테고리 정보 │ └── types/ │ └── index.ts # 타입 정의 ├── package.json ├── tsconfig.json └── README.md ``` ### 3. MCP Tools 정의 #### Tool 1: `whatap_login` **목적**: WhaTap 계정으로 로그인하여 세션 생성 ```typescript { name: "whatap_login", description: "Login to WhaTap service and create an authenticated session", inputSchema: { type: "object", properties: { email: { type: "string", description: "WhaTap account email" }, password: { type: "string", description: "WhaTap account password" }, serviceUrl: { type: "string", description: "WhaTap service URL (e.g., https://service.whatap.io)", default: "https://service.whatap.io" } }, required: ["email", "password"] } } ``` **응답**: ```json { "success": true, "accountId": 12345, "email": "user@example.com", "sessionExpiry": "2025-11-12T00:00:00Z" } ``` #### Tool 2: `execute_mxql` **목적**: MXQL 쿼리 실행 및 데이터 조회 ```typescript { name: "execute_mxql", description: "Execute MXQL query against WhaTap monitoring data", inputSchema: { type: "object", properties: { pcode: { type: "number", description: "Project code (pcode)" }, mql: { type: "string", description: "MXQL query string" }, stime: { type: "number", description: "Start time in milliseconds (optional, defaults to 5 minutes ago)" }, etime: { type: "number", description: "End time in milliseconds (optional, defaults to now)" }, limit: { type: "number", description: "Result limit (default: 10000)", default: 10000 } }, required: ["pcode", "mql"] } } ``` **응답**: ```json { "success": true, "data": [ { "oid": 123, "oname": "server-1", "cpu": 45.2 }, { "oid": 124, "oname": "server-2", "cpu": 38.7 } ], "rowCount": 2, "executionTimeMs": 234 } ``` #### Tool 3: `list_projects` **목적**: 계정이 접근 가능한 프로젝트 목록 조회 ```typescript { name: "list_projects", description: "List all accessible WhaTap projects", inputSchema: { type: "object", properties: {} } } ``` **응답**: ```json { "success": true, "projects": [ { "pcode": 12345, "name": "Production APM", "type": "APM", "status": "active" }, { "pcode": 67890, "name": "DB Monitoring", "type": "DBX", "status": "active" } ] } ``` #### Tool 4: `validate_mxql` **목적**: MXQL 쿼리 문법 검증 (기존 validator 활용) ```typescript { name: "validate_mxql", description: "Validate MXQL query syntax and suggest improvements", inputSchema: { type: "object", properties: { mql: { type: "string", description: "MXQL query to validate" } }, required: ["mql"] } } ``` ### 4. 인증 처리 전략 #### Option A: 세션 기반 인증 (추천) **장점**: - 웹 앱과 동일한 인증 흐름 - 모든 API 엔드포인트 접근 가능 - 쿠키 자동 관리 **구현**: ```typescript class AuthManager { private cookies: Map<string, string> = new Map(); private accountId?: number; async login(email: string, password: string, serviceUrl: string) { // Step 1: CSRF 토큰 획득 const csrf = await this.getCsrfToken(serviceUrl); // Step 2: 웹 로그인 const { wa, jsessionid } = await this.webLogin(email, password, csrf); this.cookies.set('wa', wa); this.cookies.set('JSESSIONID', jsessionid); // Step 3: 모바일 API 토큰 획득 (선택적) const { accountId, apiToken } = await this.getMobileToken(email, password); this.accountId = accountId; // 세션 저장 await this.saveSession(); } getCookieHeader(): string { return Array.from(this.cookies.entries()) .map(([k, v]) => `${k}=${v}`) .join('; '); } } ``` #### Option B: API 토큰 기반 인증 **장점**: - 간단한 구조 - 토큰 재사용 가능 **단점**: - Open API만 사용 가능 (MXQL flush 엔드포인트 사용 불가) - 제한된 기능 **구현**: ```typescript class AuthManager { private apiToken?: string; async login(email: string, password: string) { // 웹 로그인 후 API 토큰만 획득 const { apiToken } = await this.getApiToken(email, password); this.apiToken = apiToken; } getAuthHeader(): Record<string, string> { return { 'x-whatap-token': this.apiToken! }; } } ``` **선택: Option A (세션 기반)** - 이유: MXQL flush 엔드포인트 사용 필요, 모든 기능 접근 가능 ### 5. 세션 저장소 설계 **보안 고려사항**: - 쿠키 및 토큰 암호화 저장 - 환경 변수로 비밀키 관리 - 세션 만료 시간 설정 (24시간) ```typescript interface Session { email: string; cookies: Record<string, string>; apiToken?: string; accountId: number; createdAt: Date; expiresAt: Date; } class SessionStore { private configDir = path.join(os.homedir(), '.whatap-mcp'); private sessionFile = path.join(this.configDir, 'session.enc'); async save(session: Session) { const encrypted = this.encrypt(JSON.stringify(session)); await fs.writeFile(this.sessionFile, encrypted); } async load(): Promise<Session | null> { if (!await fs.exists(this.sessionFile)) return null; const encrypted = await fs.readFile(this.sessionFile, 'utf-8'); const decrypted = this.decrypt(encrypted); const session = JSON.parse(decrypted); // 만료 확인 if (new Date(session.expiresAt) < new Date()) { return null; } return session; } } ``` ### 6. WhatapClient 구현 ```typescript import axios, { AxiosInstance } from 'axios'; class WhatapClient { private axios: AxiosInstance; private authManager: AuthManager; constructor(serviceUrl: string, authManager: AuthManager) { this.authManager = authManager; this.axios = axios.create({ baseURL: serviceUrl, timeout: 45000, headers: { 'User-Agent': 'WhatapMCP/1.0', }, }); // 쿠키 인터셉터 this.axios.interceptors.request.use((config) => { const cookieHeader = this.authManager.getCookieHeader(); if (cookieHeader) { config.headers['Cookie'] = cookieHeader; } return config; }); } async executeMxql(mxql: MxqlRequest): Promise<any> { const response = await this.axios.post('/yard/api/flush', mxql); return response.data; } async getProjects(): Promise<Project[]> { // 웹 API 사용 (쿠키 기반) const response = await this.axios.get('/v2/project/list'); return response.data; } } ``` ### 7. MCP 서버 메인 코드 ```typescript import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; const server = new Server({ name: 'whatap-mxql-server', version: '1.0.0', }, { capabilities: { tools: {}, }, }); // AuthManager 및 Client 초기화 const authManager = new AuthManager(); const sessionStore = new SessionStore(); let whatapClient: WhatapClient | null = null; // Tool: whatap_login server.setRequestHandler('tools/call', async (request) => { if (request.params.name === 'whatap_login') { const { email, password, serviceUrl } = request.params.arguments; await authManager.login(email, password, serviceUrl || 'https://service.whatap.io'); whatapClient = new WhatapClient(serviceUrl, authManager); return { content: [{ type: 'text', text: JSON.stringify({ success: true, accountId: authManager.accountId, email: email, }), }], }; } // Tool: execute_mxql if (request.params.name === 'execute_mxql') { if (!whatapClient) { throw new Error('Not authenticated. Please call whatap_login first.'); } const { pcode, mql, stime, etime, limit } = request.params.arguments; const mxqlRequest = { type: 'mxql', pcode: pcode, params: { mql: mql, stime: stime || Date.now() - 5 * 60 * 1000, etime: etime || Date.now(), limit: limit || 10000, }, path: 'text', }; const startTime = Date.now(); const data = await whatapClient.executeMxql(mxqlRequest); const executionTimeMs = Date.now() - startTime; return { content: [{ type: 'text', text: JSON.stringify({ success: true, data: data, rowCount: Array.isArray(data) ? data.length : 0, executionTimeMs, }), }], }; } // Tool: list_projects if (request.params.name === 'list_projects') { if (!whatapClient) { throw new Error('Not authenticated. Please call whatap_login first.'); } const projects = await whatapClient.getProjects(); return { content: [{ type: 'text', text: JSON.stringify({ success: true, projects: projects, }), }], }; } }); // 서버 시작 const transport = new StdioServerTransport(); await server.connect(transport); ``` ### 8. 보안 고려사항 1. **비밀번호 저장 금지** - 세션 파일에 비밀번호 저장 안 함 - 매번 로그인 시 입력 받기 2. **쿠키 암호화** - AES-256-GCM으로 세션 파일 암호화 - 환경 변수로 마스터 키 관리 3. **HTTPS 강제** - serviceUrl이 https가 아니면 거부 4. **Rate Limiting** - API 호출 제한 (모바일 앱과 동일) 5. **세션 만료** - 24시간 후 자동 만료 - 재로그인 요구 ### 9. 설치 및 사용 방법 #### 9.1 설치 ```bash # 레포지토리 클론 git clone https://github.com/yourusername/mxql-mcp-server.git cd mxql-mcp-server # 의존성 설치 npm install # 빌드 npm run build # Claude Code MCP 설정에 추가 # ~/.config/claude-code/mcp.json ``` #### 9.2 MCP 설정 파일 ```json { "mcpServers": { "whatap-mxql": { "command": "node", "args": ["/path/to/mxql-mcp-server/dist/index.js"], "env": { "WHATAP_SESSION_KEY": "your-secure-key-here" } } } } ``` #### 9.3 사용 예시 (Claude Code에서) ``` User: WhaTap에 로그인해줘 Claude: [whatap_login tool 호출] User: pcode 12345의 최근 5분간 CPU 사용률을 조회해줘 Claude: [execute_mxql tool 호출] Query: CATEGORY app_counter TAGLOAD SELECT [cpu] User: 내가 접근 가능한 프로젝트 목록을 보여줘 Claude: [list_projects tool 호출] ``` ### 10. 개발 로드맵 **Phase 1: MVP (1-2주)** - [ ] AuthManager 구현 (세션 기반) - [ ] WhatapClient 구현 (MXQL 실행) - [ ] MCP 서버 기본 구조 - [ ] Tools: login, execute_mxql, list_projects **Phase 2: 통합 (1주)** - [ ] 기존 mxql-for-claude-code validator 통합 - [ ] validate_mxql tool 구현 - [ ] 카테고리 검색 기능 **Phase 3: 고도화 (1-2주)** - [ ] 세션 저장소 암호화 - [ ] 에러 핸들링 강화 - [ ] 로깅 및 디버깅 - [ ] 테스트 코드 작성 **Phase 4: 문서화 및 배포** - [ ] README 작성 - [ ] 사용 예시 문서 - [ ] npm 패키지 배포 - [ ] GitHub Actions CI/CD --- ## 🔍 주요 결정 사항 1. **인증 방식**: 세션 기반 (쿠키) → MXQL flush API 접근 가능 2. **기술 스택**: Node.js + TypeScript → MCP 생태계 성숙도 3. **저장소**: 암호화된 로컬 파일 → 보안 강화 4. **Tool 구조**: 4개 핵심 tool (login, execute, list, validate) ## 📚 참고 자료 - WhaTap Mobile App: `/tmp/mobile-app/src/lib/` - MXQL Validator: https://github.com/kyupid/mxql-for-claude-code - MCP SDK: https://github.com/modelcontextprotocol/typescript-sdk - WhaTap Docs: https://docs.whatap.io/ ## 다음 단계 1. Node.js 프로젝트 초기화 2. AuthManager 구현 시작 3. WhatapClient 기본 구조 구현 4. MCP 서버 뼈대 구축

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/devload/whatap-mxql-cli'

If you have feedback or need assistance with the MCP directory API, please join our Discord server