CrownyAI Mac App Store 등록 컴플라이언스 갭 분석
개요
사장님 지시(2026-07-22): CrownyAI를 "MCP 연결 가능 웹브라우저"로 애플 앱스토어에 등록 준비. 현재 /Users/ef/CrownyBrowser/native/ 구현(신셸 crowny-ai-*.m 8파일, CrownyAI.app)을 실측해 App Store 샌드박스 요건 대비 갭을 정리한다. 본 문서는 조사·분석 전용이며 코드는 수정하지 않았다.
결론 선요약: 현재 아키텍처(그대로)로는 App Sandbox 진입 불가. NSTask로 로컬 CLI/VM/컴파일러를 기동하는 구조 자체가 샌드박스와 근본 충돌한다. 앱스토어용은 별도 타깃(샌드박스판)이 필요하며, 로컬 VM 실행 기능을 제거하거나 XPC/헬퍼-외부 서비스(HTTP)로 대체해야 한다.
1. 현재 앱의 앱스토어 차단 요소 실측
1-1. entitlements.plist 현재값과 샌드박스 충돌
/Users/ef/CrownyBrowser/native/entitlements.plist (실제 서명본, codesign -d --entitlements :- CrownyAI.app로 재확인 — plist 파일과 임베딩 값 일치):
xmlcom.apple.security.cs.allow-jit true ← 샌드박스와 공존 가능(허용 O), 단 심사 시 사유 설명 요구될 수 있음
com.apple.security.cs.allow-unsigned-executable-memory true ← ⚠ App Sandbox에서도 이론상 허용되나, 자체 VM(crownyc) JIT/미서명 코드 실행 목적이면 App Review가 "왜 필요한가" 강하게 캐물음 — 근거 못 대면 리젝 확실
com.apple.security.cs.disable-library-validation true ← ⚠ 라이브러리 검증 비활성 = 서명 안 된 외부 dylib 로드 허용. App Store 심사에서 강한 리젝 사유(비검증 코드 로딩 경로 자체가 정책 위반 소지)
com.apple.security.network.client true ← 샌드박스 호환 O
com.apple.security.network.server true ← 샌드박스 호환 O (로컬 리슨 — 이유 설명 필요)
com.apple.security.files.user-selected.read-write true ← 샌드박스 호환 O(표준 항목)
com.apple.security.app-sandbox 키 자체가 없다 — 즉 현재 앱은 샌드박스 밖에서 서명(Apple Development, Team LQ83M5TL9S, codesign -dvvv 실측: Authority=Apple Development: sunkyung kim (Y447DT68BP))되어 있다. App Store Connect 제출은 com.apple.security.app-sandbox = true가 강제이며, 이 키를 켜는 순간 위 disable-library-validation/allow-unsigned-executable-memory 조합이 실질적으로 "자기 자신의 VM을 서명 없이 돌리는 구조"와 충돌한다 — VM 바이너리(crownyc, hanseonc_high)가 앱 번들 밖(/Users/ef/CrownyOS/crownyc/)에 있고 NSTask로 별도 프로세스 실행하는 구조라 disable-library-validation은 자체 바이너리 실행에는 직접 안 쓰이지만, NSTask로 번들 밖 실행파일을 띄우는 것 자체가 샌드박스에서 기본 차단(아래 1-2).
1-2. NSTask(로컬 프로세스 실행) — 샌드박스 최대 충돌점
grep -n NSTask crowny-ai-*.m 전수 결과, 8개 파일 전부에서 사용. 확인된 실행 대상:
| 파일:라인 | 실행 대상(추정 커맨드) | 용도 | 샌드박스 판정 |
|---|---|---|---|
crowny-ai-engine.m:279,304,354,924,1030,1233 | hanseonc_high, crownyc(/Users/ef/CrownyOS/crownyc/...) | 오피스/뷰어용 한선씨 소스 → toau 컴파일 + VM 실행 | ❌ 금지 — 번들 밖 임의경로 실행파일 spawn |
crowny-ai-engine.m:1006,1198,1996 (gAppSrvTask) | 상주 appSrv 서버 프로세스(포트 9821~9840 bind) | 콜드스폰 대체용 상주 서버 | ❌ 금지 — 자식 프로세스가 자체 소켓 리슨, 샌드박스는 자식 프로세스 자체를 원천 차단(com.apple.security.inherit류 예외 없이는 spawn 불가) |
crowny-ai-butler.m:92,127,171,1065,1178 | /Users/ef/CrownyBrowser/tools/집사CLI브릿지.sh | 집사(butler) CLI 브릿지 호출 | ❌ 금지 — 임의 쉘스크립트 spawn |
crowny-ai-main.m:770 | open -n <bundle> (openNewInstance) | "새 창" = 새 프로세스 기동 | ❌ 금지 — 샌드박스는 자기자신 재실행(open -n)도 기본 차단(사용자 상호작용 없는 self-relaunch) |
crowny-ai-content.m:407,423,474,497,2615,2634,2677,2695,2738,2756,3790,3809,4444,4462 | crownyc/hanseonc_high (오피스·ERP 저장/열기 VM 스테이지, caOfficeRunVMStage) | 문서 저장/열기 시 한선씨 VM 스테이지 실행 | ❌ 금지 |
crowny-ai-settings.m:826,947 | 집사CLI브릿지.sh | 설정 패널 → CLI 브릿지 | ❌ 금지 |
- 제거가 정답인 것: 새 창 = NSTask(open -n) → 샌드박스에서는
NSWorkspace openApplicationAtURL:configuration:completionHandler:(정상 다중 인스턴스 launch API, 샌드박스 허용)로 교체하거나, 애초에 macOS 표준 "새 윈도우" 패턴(같은 프로세스 내NSWindowController추가)으로 재설계. - XPC로 대체: 한선씨 VM 실행(
crownyc/hanseonc_high)은 앱 번들에 내장된 XPC 서비스(com.apple.security.temporary-exception.*없이, 정식 XPC Service 타깃)로 재구성 — VM 바이너리를Contents/XPCServices/에 넣고NSXPCConnection으로 통신. 단 XPC 서비스도 자체 샌드박스 적용받으므로, "임의 쉘스크립트 실행"(집사CLI브릿지.sh) 성격은 XPC로도 못 살림 — 근본 재작성 필요. - HTTP로 대체(권장, MVP에 가장 적합): appSrv 상주 서버·집사 CLI 브릿지 기능은 로컬 프로세스 스폰 대신 외부 상시 서버(사용자의 다른 Mac/서버에서 이미 상주 중인 crowny 서비스, 예: 9821~9840 포트 서비스를 localhost가 아닌 원격 호스트로)에 HTTP/MCP 호출로 전환.
com.apple.security.network.client만으로 충분, 샌드박스 완전 호환. - 오피스/ERP 저장 VM 스테이지: 이미 문서에 있는 "로컬+클라우드 동기"(저장동기.한선,
/api/office/save:9938) 패턴처럼, 로컬 컴파일 스테이지를 제거하고 클라우드 API 경유로 완전 전환하거나, 애초에 이 기능(오피스/ERP/집사/한선씨 VM 실행)을 앱스토어판에서는 완전히 뺀다(별도 비앱스토어 "Pro/개발자판"으로 분리).
1-3. CGWindowListCopyWindowInfo / 탭-창 간 이동 / 창이동 훅
crowny-ai-main.m:916—CGWindowListCopyWindowInfo(...): 다른 CrownyAI 창의 탭바 히트테스트(같은 앱 다중 창 간 탭 드래그용). CGWindowList API는 퍼블릭 API(비공개 아님)이나, macOS는 Screen Recording 권한류 프라이버시 게이트에 걸릴 수 있고, App Review는 "왜 다른 창 정보를 열거하는가"를 물을 수 있음. 리스크 등급: 의심(공식 API라 리젝 확실은 아니나, 스크린 캡처 관련 TCC 권한이 얽히면 사유서 필요).crowny-ai-main.m:372-379—isMovable게터 오버라이드 +mouseLocationOutsideOfEventStream:NSWindow의 공개 메서드를 오버라이드하는 정상적인 Cocoa 패턴(비공개 API 아님).mouseLocationOutsideOfEventStream도 AppKit 공개 API. 리스크 등급: 허용(공식 API 정상 사용).crowny-ai-content.msetValue:forKey:(fullScreenEnabled,drawsBackground) +NSSelectorFromString(@"setContinuousSpellCheckingEnabled:")/setGrammarCheckingEnabled:+NSInvocation(1102~1117행): WKWebView/NSTextView의 비공개 프로퍼티에 KVC로 접근하는 전형적 패턴.drawsBackground/fullScreenEnabled는 WKWebView 진영에서 오래 쓰인 사실상 관용구지만 공식 문서화 API가 아니다 — 앱스토어 심사에서 자동화 스캐너(비공개 셀렉터/문자열 조합 탐지)가 걸어낼 위험이 실질적으로 있다. 리스크 등급: 의심~리젝 가능(과거 사례상setValue:forKey:@"drawsBackground"류는 심사 통과 사례도 있으나 100% 보장 안 됨 — "확인 필요").
1-4. 분산 알림(NSDistributedNotificationCenter)
crowny-ai-main.m:441,507,963, crowny-ai-engine.m:1840,1860 — 프로세스 간(다중 CrownyAI 창) 탭 이관 통신에 사용. App Sandbox는 NSDistributedNotificationCenter를 기본 차단한다(entitlement로도 살릴 수 없는 항목 중 하나 — Apple 문서상 샌드박스 앱은 distributed notification 송수신이 사실상 불가/제한적). 리스크 등급: 리젝 확실(샌드박스 활성화 시 이 통신 경로 자체가 죽는다) → 이 기능(다중 창 탭 드래그 이관)은 앱스토어판에서 재설계 필요(같은 프로세스 내 다중 윈도우로 통합하거나 기능 제거).
1-5. 파일 임의경로 접근 / 하드코딩 절대경로
grep '"/Users/ef' crowny-ai-*.m 전수 30건 (butler 3, chrome 1, main 3, engine 9, content 8, settings 3 등). 대표:
crowny-ai-butler.m:60 @"/Users/ef/CrownyBrowser"
crowny-ai-engine.m:87 @"/Users/ef/CrownyBrowser"
crowny-ai-engine.m:92 @"/Users/ef/CrownyOS/crownyc"
crowny-ai-engine.m:97 @"/Users/ef/crowny-fonts"
crowny-ai-engine.m:103 @"/Users/ef/crowny-butler"
crowny-ai-content.m:346 kCACrownycPath = @"/Users/ef/CrownyOS/crownyc/crownyc"
crowny-ai-content.m:347 kCAHanseoncHighPath = @"/Users/ef/CrownyOS/crownyc/hanseonc_high"
crowny-ai-settings.m:603 placeholder:@"/Users/ef/.local/bin/claude"
대부분 getenv("CROWNY_BROWSER_ROOT") 등 env 폴백 실패 시의 "개발기 절대경로"이며, 코드 주석도 이를 "개발 폴백"으로 명시(crowny-ai-engine.m:656). App Sandbox 컨테이너에서는 /Users/ef/... 절대경로가 애초에 접근 불가(컨테이너 밖 파일 시스템은 user-selected 경로 외 전면 차단) — env 미설정 시 이 폴백 경로로 떨어지면 100% 실패. 샌드박스판은 이 폴백 자체를 제거하고 "해당 기능 없음"으로 처리하거나, 기능을 아예 안 가져가야 한다./tmp/ 하드코딩도 전수(예: crowny-ai-engine.m 45건, crowny-ai-butler.m 12건, crowny-ai-content.m 7건) — 샌드박스에서 /tmp는 앱 전용 컨테이너 tmp(NSTemporaryDirectory())로 리다이렉트되긴 하나(커널이 자동 치환), 하드코딩된 절대경로 /tmp/...가 그대로 open()되면 컨테이너 밖 시스템 /tmp를 가리켜 권한 거부될 수 있다(경로에 따라 다름 — 실제로는 대부분 자동 리다이렉트되지만 readlink/심볼릭 링크 우회 경로는 실패 가능). 안전하게는 전부 NSTemporaryDirectory() API 경유로 교체 필요.
1-6. 요약 — 최대 차단 요소 Top 3
- NSTask 기반 로컬 프로세스 실행(한선씨 VM 컴파일/실행, 집사 CLI 브릿지, appSrv 상주서버,
open -n자기재실행) — 8개 소스파일 전체에 걸쳐 40+ 호출 지점. 샌드박스 활성화 시 전부 죽는다. 가장 크고 구조적인 갭. com.apple.security.app-sandbox자체가 미선언 +disable-library-validation/allow-unsigned-executable-memory조합 — 현재 서명 체계가 애초에 App Store 배포 형태가 아님(Developer ID/Development 서명, 샌드박스 없음).- NSDistributedNotificationCenter 기반 다중 창 통신 + 하드코딩 절대경로 폴백(
/Users/ef/...) — 샌드박스에서 원천 차단/무효화되는 기능들이 핵심 UX(창 간 탭 이관, 자산·CLI 경로 해석)에 얽혀 있다.
2. WKWebView 브라우저의 앱스토어 가능성
crowny-browser.m/신셸 crowny-ai-*.m)는 WKWebView를 사용하는 구조이므로 엔진 자체는 원칙적으로 문제 없음(OK).LSSetDefaultHandlerForURLScheme(이미 set-default-browser.m에 구현됨, 시스템 확인 대화상자 필요 — 이 자체는 App Store 앱도 사용 가능한 공개 API)로 사용자가 "기본 브라우저로 설정"할 수 있어야 브라우저 카테고리 요건을 충족하는 경우가 많음. 현재 CLAUDE.md에 이미 "http/https는 macOS 시스템 확인 대화상자 승인 필요(우회 불가)"로 기록 — 이 부분은 그대로 사용 가능.history.json, bookmarks.json)는 로컬 저장이라도 Privacy Nutrition Label(App Privacy 질문지)에 "브라우징 히스토리 수집"으로 신고 필요할 가능성 — 확인 필요.3. 필요한 것 목록
3-1. App Sandbox 엔타이틀먼트 세트(최소 권한, 앱스토어 타깃 신규 entitlements 예시)
xml<key>com.apple.security.app-sandbox</key><true/>
<key>com.apple.security.network.client</key><true/> <!-- MCP/원격 API 호출 -->
<key>com.apple.security.files.user-selected.read-write</key><true/> <!-- 파일 열기/저장 다이얼로그 -->
<key>com.apple.security.files.downloads.read-write</key><true/> <!-- 다운로드 폴더 -->
<key>com.apple.security.personal-information.location</key><false/> <!-- 불필요 항목은 아예 제외 -->
제거 대상: allow-jit(VM 미포함 시 불필요), allow-unsigned-executable-memory(동일), disable-library-validation(동일), network.server(로컬 리슨 기능 제거 시 불필요).
allow-jit은 WKWebView의 JavaScriptCore 자체 JIT에는 보통 불필요(WebKit 프로세스가 자체 entitlement로 처리) — 확인 필요(WKWebView만 쓰는 다른 앱스토어 앱들의 entitlements 사례 확인 권장).3-2. 서명 요건
- 현재:
Apple Development: sunkyung kim (Y447DT68BP), TeamLQ83M5TL9S(개발 서명, 로컬 실행/테스트용). - 필요: "Apple Distribution" 인증서(App Store Connect 배포용, Development와 별개 발급) + Provisioning Profile(App Store 배포용, sandbox entitlement 포함). Apple Developer Program 계정에서 Certificates, Identifiers & Profiles → App Store 배포 프로파일 생성 필요. Team ID
LQ83M5TL9S가 유료 Developer Program 멤버십(연 $99)인지 확인 필요 — Bundle IDorg.crowny.browser를 App Store Connect에 앱으로 등록해야 함(신규 App ID 등록·앱 레코드 생성).
3-3. 공증/제출 파이프라인
- App Store 제출은 공증(notarization)이 별도로 필요 없다(App Store Connect가 자체 심사) — Developer ID 배포판(현재처럼 ad-hoc/개발서명 배포)만 notarize 필요. 즉 앱스토어 경로와 현재
install-ai-app.sh의 ad-hoc 재서명 경로는 완전히 다른 파이프라인. - 필요 파이프라인: Xcode Archive(또는
xcodebuild archive+xcodebuild -exportArchivewithapp-storeexport method) →.ipa/.pkg생성 →xcrun altool/notarytool(App Store Connect API 업로드는 notarize와 별개 경로,xcrun altool --upload-app또는 Transporter.app) → App Store Connect에서 심사 제출. - 현재 빌드는 순수
make(cc 직접 호출) + 수동 codesign — Xcode 프로젝트(.xcodeproj)가 없다(Makefile만 존재,find . -iname Info.plist결과 native/ 루트엔 없고/Users/ef/CrownyBrowser/CrownyAI.app/Contents/Info.plist에만 존재). App Store Connect 업로드는 사실상 Xcode 프로젝트 구조(또는 최소한 Xcode가 인식하는 export 절차)가 필요 — Makefile 산출물을 그대로 App Store Connect에 올리는 표준 경로는 없음(Transporter로 .pkg 업로드는 가능하나 서명·프로파일 요건은 동일하게 따라야 함). 확인 필요: Makefile 기반 빌드에서 App Store 배포용 아카이브를 직접 만드는 것이 가능한지, 혹은 최소 Xcode 래퍼 프로젝트를 새로 만들어야 하는지.
3-4. Info.plist 요건
현재 /Users/ef/CrownyBrowser/CrownyAI.app/Contents/Info.plist 실측:
CFBundleShortVersionString = 0.9.0-beta— App Store는 정식 버전 형식 권장(1.0.0), "beta" 문자열은 심사에서 지적될 수 있음.LSApplicationCategoryType키 없음 — App Store는 카테고리 필수(예:public.app-category.productivity또는 웹브라우저는 보통public.app-category.utilities; 명시적 "Browser" 카테고리는 App Store Connect 메타데이터에서 설정, Info.plist엔 일반 카테고리 키만).NSAppTransportSecurity: NSAllowsArbitraryLoads = true— ⚠ 임의 HTTP(비HTTPS) 로드 전면 허용. App Review가 사유 요구 가능(브라우저 특성상 임의 사이트 방문이 정당 사유가 될 수 있으나, "확인 필요").- 개인정보 사용문자열(Usage Description) 전무:
NSCameraUsageDescription/NSMicrophoneUsageDescription/NSLocationUsageDescription등이 plist에 없음 — 현재 기능이 카메라/마이크/위치를 안 쓰면 문제 없으나, WKWebView가 웹사이트의 getUserMedia 요청을 프록시할 경우 Info.plist에 해당 usage description이 없으면 크래시/거부됨 — 확인 필요(브라우저가 웹캠/마이크 권한이 필요한 사이트를 지원할지 여부에 따라 추가 필요). CFBundleDocumentTypes에public.html뷰어 선언 있음 — 유지 가능.- App Privacy(Nutrition Label)는 Info.plist가 아니라 App Store Connect 메타데이터에서 별도 작성 — 브라우징 데이터 수집 여부 신고 필요.
4. 현실 판정
현재 아키텍처 그대로는 App Sandbox 진입 불가. 근거:
- NSTask 40+ 호출 지점이 로컬 CLI(집사 브릿지)·한선씨 VM 컴파일/실행·상주 서버·자기 프로세스 재실행에 구조적으로 얽혀 있다(오피스/ERP 저장, 뷰어, 집사, 새 창 전부). 샌드박스는 자식 프로세스 spawn 자체를 기본 차단하며, 이 기능들은 "권한 추가 신청"으로 해결되는 수준이 아니라 아키텍처 재설계가 필요한 수준이다.
NSDistributedNotificationCenter(다중 창 탭 이관)도 샌드박스에서 무효화된다.- 하드코딩된
/Users/ef/...절대경로 폴백은 샌드박스 컨테이너 밖이라 애초에 도달 불가능하다.
open -n 자기재실행) 전부 제거 또는 원격 HTTP 대체.NSWindowController로 재설계.NSTemporaryDirectory()/앱 컨테이너 경로만 사용.MVP로 낼 수 있는 최소 기능 셸:
- 순수 WKWebView 브라우저(멀티탭, 히스토리, 북마크, 시작페이지) — CLAUDE.md "Path A v0.2" 수준 기능은 대부분 샌드박스 호환(로컬 JSON 파일 저장은 앱 컨테이너 내부라 문제 없음).
- MCP over HTTP: 로컬 프로세스 스폰(NSTask) 없이, 사용자가 설정한 MCP 서버 엔드포인트(원격 HTTP/WebSocket)에
network.cliententitlement만으로 연결하는 클라이언트 기능. crowny 생태계의 MCP 관련 로컬 실행(예: 한선씨 VM을 MCP 툴로 직접 실행)은 앱스토어판에서 배제하고, 이미 상시 구동 중인 원격 crowny 서비스(9821~9840류 포트를 로컬이 아닌 서버 호스트로 이전한 것)를 호출하는 형태로 한정. - 기본 브라우저 설정 기능(
set-default-browser.m로직, 공개 API라 유지 가능). - crowny:// 커스텀 앱 카드(erp/hall/cad/ev/factory/fab 등, 전부 "라이브 서버형" —
loadRequest로 원격 HTTPS를 여는 방식)는 로컬 프로세스 실행이 없으므로 그대로 유지 가능(CLAUDE.md 기록상 이들은 이미 서버가 직접 서빙하는 구조라 NSTask 의존이 없음 — 단 crowny-ai-content.m 각 지점의 하드코딩 절대경로 폴백만 제거하면 됨). - 제외할 것: 오피스/ERP의 로컬 cdf 저장 시 VM 스테이지 실행(
caOfficeRunVMStage), 집사(butler) CLI 브릿지, appSrv 상주서버, 새 창=open -n.
5. 단계적 로드맵 (우선순위)
- P0 — 변종 스캐폴딩:
make-app.sh/package-variants.sh관례를 따라-DCROWNY_PRODUCT_STORE매크로 신설,crowny-ai-*.m전체에서 이 매크로로 NSTask 블록·NSDistributedNotificationCenter 블록·하드코딩 절대경로 폴백을#ifndef CROWNY_PRODUCT_STORE로 컴파일 제외. (CLAUDE.md 3변종 정책과 동일 패턴이라 도구화 난이도 낮음.) - P0 — entitlements-store.plist 신규 작성:
com.apple.security.app-sandbox=true+ 최소 세트(3-1 참조), Xcode 프로젝트 골격 하나 신설(Makefile과 병행, App Store Connect 업로드 경로 확보). - P1 — MCP-over-HTTP 클라이언트 설계: 로컬 NSTask 대신 원격 crowny 서비스 호출로 붙일 MCP 연동 스펙 확정(어떤 기능을 "MCP 도구"로 노출할지 — 사장님 의사결정 필요 항목).
- P1 — Apple Developer Program / Distribution 인증서 확인: Team
LQ83M5TL9S가 유료 멤버십인지, App Store Connect에org.crowny.browserApp ID 등록 여부 확인(계정 작업, 개발 범위 밖 — 사장님 액션 필요할 가능성). - P2 — Info.plist 정비: 버전 문자열 정식화(
beta제거),LSApplicationCategoryType추가, ATSNSAllowsArbitraryLoads사유 정리, Privacy Usage Description 필요 여부 점검(웹캠/마이크 지원 범위 확정에 따라). - P2 — 심사 리스크 항목 사전 정리:
setValue:forKey:/NSInvocation기반 비공개 프로퍼티 접근(§1-3) 제거 또는 공식 API 대체 검토, CGWindowListCopyWindowInfo 사용처 리뷰 노트 작성. - P3 — 실제 제출: Xcode Archive → App Store Connect 업로드 → 심사 제출(Privacy Nutrition Label 작성 포함).
관련 파일
/Users/ef/CrownyBrowser/native/entitlements.plist/Users/ef/CrownyBrowser/native/Makefile/Users/ef/CrownyBrowser/native/crowny-ai-main.m,crowny-ai-chrome.m,crowny-ai-content.m,crowny-ai-engine.m,crowny-ai-butler.m,crowny-ai-panels.m,crowny-ai-overlays.m,crowny-ai-settings.m/Users/ef/CrownyBrowser/CrownyAI.app/Contents/Info.plist/Users/ef/CrownyBrowser/native/install-ai-app.sh/Users/ef/CrownyBrowser/CLAUDE.md
잔여 이슈 / 확인 필요 목록
- Team
LQ83M5TL9S가 유료 Apple Developer Program 멤버십인지,org.crowny.browserBundle ID를 App Store Connect에 등록 가능한지(계정 레벨, 코드로 확인 불가). - WKWebView-only 앱의
allow-jitentitlement 필요 여부(다른 App Store WKWebView 앱 사례 확인 권장). - Makefile 기반 빌드에서 App Store Connect 업로드용 아카이브를 직접 만들 수 있는지, Xcode 프로젝트 골격이 반드시 필요한지.
- 브라우저 카테고리 App Review 요건 최신본(콘텐츠 필터링/성인물 정책 등) — Apple 공식 가이드라인 재확인 필요.
- MCP 연동을 App Review가 "비공개 API/미승인 기능"으로 보지 않도록 어떻게 설명·스코프할지 — 정책 문구 최신본과 대조 필요.
- WebRTC(getUserMedia) 지원 여부에 따른 Privacy Usage Description 추가 필요성.