<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Plugins on ICE-ICE-BEAR-BLOG</title><link>https://ice-ice-bear.github.io/ko/tags/plugins/</link><description>Recent content in Plugins on ICE-ICE-BEAR-BLOG</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Mon, 06 Apr 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://ice-ice-bear.github.io/ko/tags/plugins/index.xml" rel="self" type="application/rss+xml"/><item><title>Claude Code 하네스 해부학 #5 — MCP 서비스와 플러그인 스킬 확장 생태계</title><link>https://ice-ice-bear.github.io/ko/posts/2026-04-06-harness-anatomy-5/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0900</pubDate><guid>https://ice-ice-bear.github.io/ko/posts/2026-04-06-harness-anatomy-5/</guid><description>&lt;img src="https://ice-ice-bear.github.io/" alt="Featured image of post Claude Code 하네스 해부학 #5 — MCP 서비스와 플러그인 스킬 확장 생태계" /&gt;&lt;h2 id="개요"&gt;개요
&lt;/h2&gt;&lt;p&gt;Claude Code는 42개의 내장 도구 외에 MCP(Model Context Protocol)를 통해 외부 도구를 무제한으로 확장할 수 있다. 이 포스트에서는 &lt;code&gt;client.ts&lt;/code&gt;(3,348줄)의 연결 관리 아키텍처, &lt;code&gt;auth.ts&lt;/code&gt;(2,465줄)의 OAuth 인증 체계, 4계층 보안 모델, 설정 중복 제거를 분석한다. 이어서 플러그인과 스킬의 구조적 차이, 5계층 스킬 디스커버리 엔진, &lt;code&gt;mcpSkillBuilders.ts&lt;/code&gt;의 순환 참조 해결 패턴까지 해부한다.&lt;/p&gt;
&lt;h2 id="1-mcp-클라이언트--연결-관리가-프로토콜보다-어렵다"&gt;1. MCP 클라이언트 &amp;ndash; 연결 관리가 프로토콜보다 어렵다
&lt;/h2&gt;&lt;h3 id="메모이제이션-기반-커넥션-풀"&gt;메모이제이션 기반 커넥션 풀
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;connectToServer&lt;/code&gt;는 &lt;code&gt;lodash.memoize&lt;/code&gt;로 래핑되어 있다. 캐시 키는 &lt;code&gt;name + JSON(config)&lt;/code&gt;. MCP 서버는 stateful(stdio 프로세스, WebSocket 연결)이므로 매 도구 호출마다 새 연결을 만들면 성능이 치명적으로 나빠진다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;onclose&lt;/code&gt; 핸들러가 캐시를 무효화 -&amp;gt; 다음 호출이 자동으로 재연결&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetchToolsForClient&lt;/code&gt;, &lt;code&gt;fetchResourcesForClient&lt;/code&gt;도 각각 LRU 캐시(20개)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="도구-프록시-패턴"&gt;도구 프록시 패턴
&lt;/h3&gt;&lt;p&gt;MCP 도구는 네이티브 &lt;code&gt;Tool&lt;/code&gt; 인터페이스로 변환된다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;: &lt;code&gt;mcp__&amp;lt;normalized_server&amp;gt;__&amp;lt;normalized_tool&amp;gt;&lt;/code&gt; 형식&lt;/li&gt;
&lt;li&gt;&lt;code&gt;call()&lt;/code&gt;: &lt;code&gt;ensureConnectedClient&lt;/code&gt; -&amp;gt; &lt;code&gt;callMCPToolWithUrlElicitationRetry&lt;/code&gt; -&amp;gt; &lt;code&gt;callMCPTool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;checkPermissions()&lt;/code&gt;: 항상 &lt;code&gt;passthrough&lt;/code&gt; &amp;ndash; MCP 도구는 별도 권한 시스템&lt;/li&gt;
&lt;li&gt;&lt;code&gt;annotations&lt;/code&gt;: &lt;code&gt;readOnlyHint&lt;/code&gt;, &lt;code&gt;destructiveHint&lt;/code&gt; 등 MCP 어노테이션 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;URL Elicitation Retry&lt;/strong&gt;: OAuth 기반 MCP 서버는 도구 호출 중간에 인증을 요구할 수 있다(에러 코드 -32042). retry 루프가 사용자에게 URL을 보여주고 인증 완료 후 재시도한다.&lt;/p&gt;
&lt;h3 id="연결-상태-머신과-3-strike-터미널-에러"&gt;연결 상태 머신과 3-strike 터미널 에러
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;stateDiagram-v2
 [*] --&gt; Pending: 설정 로드됨
 Pending --&gt; Connected: connectToServer 성공
 Pending --&gt; Failed: 연결 타임아웃
 Pending --&gt; NeedsAuth: 401 UnauthorizedError
 Pending --&gt; Disabled: isMcpServerDisabled()

 Connected --&gt; Connected: 도구 호출 성공
 Connected --&gt; Failed: 터미널 에러 3회 연속
 Connected --&gt; NeedsAuth: 401 during callMCPTool
 Connected --&gt; Pending: onclose 캐시 무효화

 NeedsAuth --&gt; Pending: 인증 완료
 NeedsAuth --&gt; NeedsAuth: 15분 TTL 캐시

 Failed --&gt; Pending: reconnectMcpServer()
 Disabled --&gt; Pending: toggleMcpServer()

 note right of Connected
 memoize 캐시에 존재
 fetchTools/Resources도 캐시
 end note&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;3-strike 규칙&lt;/strong&gt;: 터미널 에러가 3회 연속 발생하면 &lt;code&gt;Failed&lt;/code&gt; 상태로 강제 전환. 이는 죽은 서버에 계속 재시도하는 것을 방지한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;15분 needs-auth 캐시&lt;/strong&gt;: 401을 받은 서버를 매번 재시도하면 30개 이상의 커넥터가 동시에 네트워크 요청을 만든다. TTL 캐시로 불필요한 재시도를 방지한다.&lt;/p&gt;
&lt;h2 id="2-oauth--2465줄의-현실"&gt;2. OAuth &amp;ndash; 2,465줄의 현실
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;auth.ts&lt;/code&gt;가 2,465줄인 이유는 &lt;strong&gt;현실의 OAuth 서버들이 RFC를 일관성 있게 구현하지 않기 때문&lt;/strong&gt;이다:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;구성 요소&lt;/th&gt;
 &lt;th&gt;설명&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;RFC 9728 + 8414 디스커버리&lt;/td&gt;
 &lt;td&gt;서버가 별도 호스트에서 AS 운영 가능 -&amp;gt; PRM으로 AS URL 탐색&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;PKCE&lt;/td&gt;
 &lt;td&gt;공개 클라이언트 &amp;ndash; code_verifier/code_challenge 필수&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;XAA (Cross-App Access)&lt;/td&gt;
 &lt;td&gt;IdP의 id_token으로 MCP 서버 AS에서 access_token 교환&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;비표준 에러 정규화&lt;/td&gt;
 &lt;td&gt;Slack은 HTTP 200에 &lt;code&gt;{&amp;quot;error&amp;quot;:&amp;quot;invalid_grant&amp;quot;}&lt;/code&gt; 반환&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Keychain 저장&lt;/td&gt;
 &lt;td&gt;macOS Keychain 연동 (&lt;code&gt;getSecureStorage()&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Rust 포팅 시사점: OAuth는 SDK 의존이 아니라 &lt;strong&gt;복잡한 비동기 상태 머신&lt;/strong&gt;이다. 디스커버리(2단계) -&amp;gt; PKCE -&amp;gt; 콜백 서버 -&amp;gt; 토큰 저장 -&amp;gt; 갱신 -&amp;gt; 폐기 -&amp;gt; XAA. 이 전체를 이식하는 것은 비현실적이므로, stdio MCP + API 키 인증으로 시작하는 것이 현실적이다.&lt;/p&gt;
&lt;h2 id="3-4계층-보안-모델"&gt;3. 4계층 보안 모델
&lt;/h2&gt;&lt;p&gt;MCP 보안은 단일 게이트가 아니라 &lt;strong&gt;트러스트 레벨의 합성&lt;/strong&gt;이다:&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 subgraph L1["1. Enterprise"]
 E1["managed-mcp.json&amp;lt;br/&amp;gt;존재하면 다른 모든 소스 차단"]
 E2["denylist / allowlist&amp;lt;br/&amp;gt;이름, 명령어, URL 패턴"]
 end

 subgraph L2["2. Project"]
 P1[".mcp.json 로드"]
 P2["pending -&gt; 사용자 승인 -&gt; approved"]
 end

 subgraph L3["3. Server"]
 S1["OAuth 서버별 독립 토큰"]
 S2["Keychain 저장"]
 end

 subgraph L4["4. Channel"]
 C1["GrowthBook allowlist&amp;lt;br/&amp;gt;tengu_harbor_ledger"]
 C2["구조화된 이벤트&amp;lt;br/&amp;gt;일반 텍스트 매칭 아님"]
 end

 L1 --&gt; L2 --&gt; L3 --&gt; L4

 style L1 fill:#ffcdd2
 style L2 fill:#fff9c4
 style L3 fill:#c8e6c9
 style L4 fill:#e1f5fe&lt;/pre&gt;&lt;p&gt;각 레이어가 독립적으로 동작하며, &lt;strong&gt;Enterprise가 최우선&lt;/strong&gt;이다. &lt;code&gt;.mcp.json&lt;/code&gt;이 프로젝트에 있어도 enterprise denylist에 걸리면 차단된다.&lt;/p&gt;
&lt;h3 id="설정-소스와-중복-제거-configts-1578줄"&gt;설정 소스와 중복 제거 (config.ts 1,578줄)
&lt;/h3&gt;&lt;p&gt;설정 소스 우선순위 (높은 것이 이긴다):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enterprise managed (&lt;code&gt;managed-mcp.json&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Local (사용자별 프로젝트 설정)&lt;/li&gt;
&lt;li&gt;User (글로벌 &lt;code&gt;~/.claude.json&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Project (&lt;code&gt;.mcp.json&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Plugin (동적)&lt;/li&gt;
&lt;li&gt;claude.ai connectors (최저)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;왜 중복 제거가 필요한가?&lt;/strong&gt; 같은 MCP 서버가 &lt;code&gt;.mcp.json&lt;/code&gt;과 claude.ai 커넥터 모두에 존재할 수 있다. &lt;code&gt;getMcpServerSignature&lt;/code&gt;가 &lt;code&gt;stdio:[command|args]&lt;/code&gt; 또는 &lt;code&gt;url:&amp;lt;base&amp;gt;&lt;/code&gt; 시그니처를 만들어, CCR 프록시 URL도 원본 벤더 URL로 언래핑한 뒤 비교한다.&lt;/p&gt;
&lt;p&gt;환경 변수 확장: &lt;code&gt;${VAR}&lt;/code&gt; 및 &lt;code&gt;${VAR:-default}&lt;/code&gt; 문법 지원. 누락 변수는 에러 대신 경고로 보고하여 부분적 연결 실패를 방지한다.&lt;/p&gt;
&lt;h2 id="4-플러그인-vs-스킬--구조적-차이"&gt;4. 플러그인 vs 스킬 &amp;ndash; 구조적 차이
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;차원&lt;/th&gt;
 &lt;th&gt;스킬&lt;/th&gt;
 &lt;th&gt;플러그인&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;본질&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;프롬프트 확장 (SKILL.md = 텍스트)&lt;/td&gt;
 &lt;td&gt;시스템 확장 (스킬 + 훅 + MCP)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;설치&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;파일 하나 배치&lt;/td&gt;
 &lt;td&gt;마켓플레이스 git 클론&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;런타임 코드&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;없음 (순수 텍스트)&lt;/td&gt;
 &lt;td&gt;있음 (MCP 서버, 훅 스크립트)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;토글&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;암묵적 (파일 존재 여부)&lt;/td&gt;
 &lt;td&gt;명시적 (&lt;code&gt;/plugin&lt;/code&gt; UI)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;ID 체계&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;파일 경로&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;{name}@builtin&lt;/code&gt; 또는 &lt;code&gt;{name}@marketplace&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;스킬은 &amp;ldquo;파일 = 확장&amp;quot;이라는 원칙의 구현이다. &lt;code&gt;SKILL.md&lt;/code&gt; 하나가 설치/빌드 없이 즉시 확장으로 작동한다.&lt;/p&gt;
&lt;h3 id="플러그인-서비스의-관심사-분리"&gt;플러그인 서비스의 관심사 분리
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;파일&lt;/th&gt;
 &lt;th&gt;역할&lt;/th&gt;
 &lt;th&gt;부작용&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;pluginOperations.ts&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;순수 라이브러리 함수&lt;/td&gt;
 &lt;td&gt;없음&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;pluginCliCommands.ts&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;CLI 래퍼&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;process.exit&lt;/code&gt;, console 출력&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;PluginInstallationManager.ts&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;백그라운드 조정기&lt;/td&gt;
 &lt;td&gt;AppState 업데이트&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;pluginOperations&lt;/code&gt;의 순수 함수는 CLI와 대화형 UI 양쪽에서 재사용된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;마켓플레이스 조정&lt;/strong&gt;: &lt;code&gt;diffMarketplaces()&lt;/code&gt;로 선언된 마켓플레이스와 실재 설치를 비교. 신규 설치면 자동 새로고침, 기존 업데이트면 &lt;code&gt;needsRefresh&lt;/code&gt; 플래그만 설정. 신규는 &amp;ldquo;플러그인 못 찾음&amp;rdquo; 오류 방지가 필요하지만, 업데이트는 사용자가 적용 시점을 선택해야 한다.&lt;/p&gt;
&lt;h2 id="5-5계층-스킬-디스커버리-엔진"&gt;5. 5계층 스킬 디스커버리 엔진
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;loadSkillsDir.ts&lt;/code&gt;(1,086줄)의 로딩 소스 우선순위:&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 subgraph Discovery["스킬 디스커버리"]
 A["1. policySettings&amp;lt;br/&amp;gt;managed-settings.json"]
 B["2. userSettings&amp;lt;br/&amp;gt;~/.claude/skills/"]
 C["3. projectSettings&amp;lt;br/&amp;gt;.claude/skills/&amp;lt;br/&amp;gt;프로젝트 루트~홈까지"]
 D["4. --add-dir&amp;lt;br/&amp;gt;추가 디렉토리"]
 E["5. 레거시&amp;lt;br/&amp;gt;/commands/ 디렉토리"]
 end

 subgraph Dedup["중복 제거"]
 F["realpath() 심링크 해소"]
 G["파일 ID 기반 first-wins"]
 end

 subgraph Parse["프론트매터 파싱"]
 H["description, when_to_use"]
 I["allowed-tools"]
 J["model, context, hooks"]
 K["paths, shell"]
 end

 A --&gt; B --&gt; C --&gt; D --&gt; E
 E --&gt; F --&gt; G
 G --&gt; H &amp; I &amp; J &amp; K

 style Discovery fill:#e1f5fe
 style Parse fill:#fff3e0&lt;/pre&gt;&lt;h3 id="프론트매터-시스템"&gt;프론트매터 시스템
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;SKILL.md&lt;/code&gt;의 YAML 프론트매터에서 15개+ 필드를 추출한다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt;, &lt;code&gt;when_to_use&lt;/code&gt;: 모델이 스킬 선택에 사용&lt;/li&gt;
&lt;li&gt;&lt;code&gt;allowed-tools&lt;/code&gt;: 스킬 실행 시 허용 도구 목록&lt;/li&gt;
&lt;li&gt;&lt;code&gt;model&lt;/code&gt;: 특정 모델 강제 지정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;context: fork&lt;/code&gt;: 별도 컨텍스트에서 실행&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hooks&lt;/code&gt;: 스킬 전용 훅 설정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;paths&lt;/code&gt;: 경로 기반 활성화 필터&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shell&lt;/code&gt;: 인라인 셸 명령 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="번들-스킬의-지연-디스크-추출"&gt;번들 스킬의 지연 디스크 추출
&lt;/h3&gt;&lt;p&gt;CLI 바이너리에 컴파일되는 17개 번들 스킬(&lt;code&gt;skills/bundled/&lt;/code&gt;)은 &lt;code&gt;files&lt;/code&gt; 필드가 있으면 &lt;strong&gt;첫 호출 시 디스크에 추출&lt;/strong&gt;한다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;O_NOFOLLOW | O_EXCL&lt;/code&gt; 플래그로 심링크 공격 차단&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0o600&lt;/code&gt; 퍼미션으로 접근 제한&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resolveSkillFilePath()&lt;/code&gt;가 &lt;code&gt;..&lt;/code&gt; 경로를 거부하여 디렉토리 탈출 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;왜 디스크에 추출하는가?&lt;/strong&gt; 모델이 &lt;code&gt;Read&lt;/code&gt;/&lt;code&gt;Grep&lt;/code&gt; 도구로 참조 파일을 읽을 수 있게 하기 위해서다. 메모리에만 두면 모델이 접근할 수 없다.&lt;/p&gt;
&lt;h3 id="mcpskillbuilders--44줄짜리-순환-참조-해결"&gt;mcpSkillBuilders &amp;ndash; 44줄짜리 순환 참조 해결
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;mcpSkillBuilders.ts&lt;/code&gt;(44줄)는 작지만 아키텍처적으로 중요하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;문제&lt;/strong&gt;: &lt;code&gt;mcpSkills.ts&lt;/code&gt;가 &lt;code&gt;loadSkillsDir.ts&lt;/code&gt;의 함수를 필요로 하지만, 직접 임포트하면 순환 참조가 발생한다 (&lt;code&gt;client.ts -&amp;gt; mcpSkills.ts -&amp;gt; loadSkillsDir.ts -&amp;gt; ... -&amp;gt; client.ts&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;해법&lt;/strong&gt;: write-once 레지스트리. &lt;code&gt;loadSkillsDir.ts&lt;/code&gt;가 모듈 초기화 시 함수를 등록하고, &lt;code&gt;mcpSkills.ts&lt;/code&gt;가 필요할 때 가져간다. 동적 임포트는 Bun 번들러에서 실패하고, 리터럴 동적 임포트는 dependency-cruiser 순환 검사를 트리거하기 때문에 &lt;strong&gt;이 방식이 유일한 해결책&lt;/strong&gt;이다.&lt;/p&gt;
&lt;p&gt;의존성 그래프의 리프 모듈이 타입만 임포트하고, 런타임 등록은 시작 시 한 번만 수행한다.&lt;/p&gt;
&lt;h2 id="rust-대조"&gt;Rust 대조
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;영역&lt;/th&gt;
 &lt;th&gt;TS (완성)&lt;/th&gt;
 &lt;th&gt;Rust (현재)&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;이름 정규화&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;normalization.ts&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;mcp.rs&lt;/code&gt; &amp;ndash; 동일 로직&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;서버 시그니처&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;getMcpServerSignature&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;mcp_server_signature&lt;/code&gt; &amp;ndash; CCR 프록시 언래핑 포함&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;stdio JSON-RPC&lt;/td&gt;
 &lt;td&gt;SDK 의존&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;mcp_stdio.rs&lt;/code&gt; &amp;ndash; 직접 구현 (initialize, tools/list, tools/call)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;OAuth&lt;/td&gt;
 &lt;td&gt;2,465줄 완전 구현&lt;/td&gt;
 &lt;td&gt;없음 &amp;ndash; 타입만 정의&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;연결 관리&lt;/td&gt;
 &lt;td&gt;memoize + onclose 재연결&lt;/td&gt;
 &lt;td&gt;없음&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;스킬 로딩&lt;/td&gt;
 &lt;td&gt;5계층 + 프론트매터 15필드&lt;/td&gt;
 &lt;td&gt;2 디렉토리, SKILL.md만&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;번들 스킬&lt;/td&gt;
 &lt;td&gt;17개 내장&lt;/td&gt;
 &lt;td&gt;없음&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;플러그인&lt;/td&gt;
 &lt;td&gt;빌트인 + 마켓플레이스&lt;/td&gt;
 &lt;td&gt;없음&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;보안&lt;/td&gt;
 &lt;td&gt;4계층 (Enterprise-&amp;gt;Channel)&lt;/td&gt;
 &lt;td&gt;없음&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;핵심 격차&lt;/strong&gt;: Rust는 부트스트랩(설정 -&amp;gt; 트랜스포트)과 stdio JSON-RPC까지 구현했다. &lt;code&gt;mcp_stdio.rs&lt;/code&gt;의 SDK 없는 JSON-RPC 구현은 의미 있는 진전이다. 그러나 OAuth, 연결 생명주기, 채널 보안, 스킬 디스커버리 전체가 부재한다.&lt;/p&gt;
&lt;h2 id="인사이트"&gt;인사이트
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MCP는 &amp;ldquo;프로토콜&amp;quot;이 아니라 &amp;ldquo;통합 프레임워크&amp;quot;다&lt;/strong&gt; &amp;ndash; 3,348줄의 &lt;code&gt;client.ts&lt;/code&gt;가 말해주는 것은, 어려운 부분이 JSON-RPC가 아니라 &lt;strong&gt;연결 생명주기 관리&lt;/strong&gt;라는 점이다. 메모이제이션, 자동 재연결, 세션 만료 감지, 401 retry, 3-strike 터미널 에러, needs-auth 캐시. 외부 프로세스(stdio)와 원격 서비스(HTTP/SSE)는 예측 불가능하게 죽고, OAuth 토큰은 만료되고, 네트워크는 끊긴다. &amp;ldquo;한번 연결하면 끝&amp;quot;이 아닌 현실을 반영하는 코드다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;스킬은 &amp;ldquo;파일 = 확장&amp;quot;이라는 원칙의 구현이다&lt;/strong&gt; &amp;ndash; SKILL.md 하나가 설치/빌드 없이 즉시 확장으로 작동한다. 이 단순성이 프론트매터를 통한 점진적 복잡성 추가(모델 지정, 훅, 경로 필터)와 결합되어 초보자와 파워 유저를 모두 수용한다. 플러그인은 스킬의 상위 조직 단위로, &amp;ldquo;스킬 + 훅 + MCP 서버&amp;quot;를 묶는 패키지다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;mcpSkillBuilders.ts&lt;/code&gt;는 44줄짜리 아키텍처 교훈이다&lt;/strong&gt; &amp;ndash; Bun 번들러의 동적 임포트 제약과 dependency-cruiser의 순환 검사를 동시에 만족시키는 유일한 해법이 &amp;ldquo;write-once 레지스트리&amp;quot;였다. 의존성 그래프의 리프 모듈이 타입만 임포트하고 런타임 등록은 시작 시 한 번만 수행하는 패턴은, 복잡한 모듈 시스템에서 순환 참조를 해결하는 범용적인 접근법으로 기억할 가치가 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;다음 포스트: &lt;a class="link" href="https://ice-ice-bear.github.io/posts/2026-04-06-harness-anatomy-6/" &gt;#6 &amp;ndash; Claude Code를 넘어서, 7크레이트 독자 하네스 구축 회고&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description></item></channel></rss>