What is Hackers' Pub?

Hackers' Pub is a place for software engineers to share their knowledge and experience with each other. It's also an ActivityPub-enabled social network, so you can follow your favorite hackers in the fediverse and get their latest posts in your feed.

クリスマスイブの夜に特に予定がいので雑談配信します!​:rv_blobcat_xmas:
12月24日(水)22時開始~0時ぐらいまで!
ジュースでも飲み
がらみんでお話しましょ~

サムネイルは有名
ネットミームのパロディです
一度描いてみたかったので…

配信枠はここです

3
0
0
0
0
0
0
1
2
3
0
0
0
0
1
0

J'ai acheté un 1e papasan en rotin en ligne. Il était infesté de vers à bois. J'ai été remboursée.
J'en ai commandé un autre au même endroit, me disant que ça peut pas re-arriver : même souci.
Là ça fait beaucoup. On peut contacter qui pour dénoncer la vente de produits insalubres en Europe ?

0

MCP도 Tool Use를 사용합니다.

자손킴 @jasonkim@hackers.pub

지난 글에서는 Subagent가 Tool Use 위에서 어떻게 동작하는지 알아보았다. 이번 글에서는 MCP(Model Context Protocol)가 Tool Use와 어떻게 연결되는지 내장 도구인 Subagent를 예시로 비교하며 설명할 것이다. 또한 내장 도구가 있음에도 불구하고 MCP가 필요한 이유에 대해서도 알아본다.

내장 도구 vs MCP 도구

Subagent 글에서 살펴본 Task 도구는 에이전트에 내장된 도구였다. MCP 도구는 어떻게 다를까? 결론부터 말하면 LLM 입장에서는 둘 다 그냥 도구다. 차이는 실행이 어디서 일어나는가뿐이다.

내장 도구든 MCP 도구든 API 요청의 tools 배열에 동일한 형태로 들어간다:

{
  "tools": [
    {
      "name": "Read",
      "description": "Reads a file from the local filesystem...",
      "input_schema": { ... }
    },
    {
      "name": "Task",
      "description": "Launch a new agent to handle complex tasks...",
      "input_schema": { ... }
    },
    {
      "name": "mcp__claude-in-chrome__navigate",
      "description": "Navigate to a URL in the browser...",
      "input_schema": { ... }
    }
  ]
}

LLM은 도구 이름과 description, input_schema만 보고 어떤 도구를 호출할지 결정한다. 이 도구가 내장인지 MCP인지는 알 수 없고 알 필요도 없다.

핵심 차이는 도구가 어디서 실행되는가다.

내장 도구 (예: Task) MCP 도구
실행 위치 Host 내부 Host 외부 (별도 프로세스)
통신 방식 함수 호출 프로토콜 (STDIO/HTTP)
실행 주체 Host (또는 LLM) 외부 시스템
결과 Host가 생성한 데이터 외부 시스템이 반환한 데이터

다이어그램으로 보면 더 명확하다:

                        Host 프로세스
    ─────────────────────────────────────────────────
    
                         Agent

              ┌────────────┴────────────┐
              ▼                         ▼
            Task                   mcp__xxx 도구
          (내장 도구)                     │
              │                         │
              ▼                         │ STDIO / HTTP
         새 메시지 루프                    │
           (LLM)                       │

    ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─

                        외부 프로세스     ▼
                                   MCP Server
                               (Chrome, DB...)
  • 내장 도구 흐름: Agent → Task → 새 메시지 루프 (모두 Host 프로세스 내부)
  • MCP 도구 흐름: Agent → mcp__xxx 도구 → [프로세스 경계] → MCP Server (Host 외부)

실제 예시로 보는 차이

지난 글에서 본 Explorer subagent 호출과 MCP 도구 호출을 비교해보자.

내장 도구 (Task) 호출:

{
  "type": "tool_use",
  "id": "toolu_01ABC123",
  "name": "Task",
  "input": {
    "subagent_type": "Explore",
    "prompt": "entity 구조를 탐색해주세요",
    "description": "Entity 구조 탐색"
  }
}

Task 도구가 호출되면 Host 내부에서 새로운 메시지 루프가 생성되고, Haiku 모델이 Glob, Read 등 다른 내장 도구로 탐색을 수행한다. 결과는 LLM이 생성한 분석 텍스트다.

MCP 도구 호출:

{
  "type": "tool_use",
  "id": "toolu_01DEF456",
  "name": "mcp__claude-in-chrome__navigate",
  "input": {
    "tabId": 12345,
    "url": "http://localhost:3000"
  }
}

MCP 도구가 호출되면 Host는 외부의 MCP Server(Chrome 브라우저 프로세스)에 명령을 전달한다. 결과는 브라우저가 반환한 데이터(스크린샷, 콘솔 로그 등)다.

Agent 입장에서는 둘 다 tool_use 요청을 받아 실행하고 tool_result를 반환하는 동일한 패턴이다.

MCP 도구가 tools 배열에 포함되는 방식

MCP 서버가 제공하는 도구들은 어떻게 tools 배열에 들어갈까? MCP 도구는 mcp__server-name__tool-name 형태의 이름을 가진다.

{
  "name": "mcp__claude-in-chrome__navigate",
  "description": "Navigate to a URL, or go forward/back in browser history...",
  "input_schema": {
    "type": "object",
    "properties": {
      "tabId": {
        "description": "Tab ID to navigate",
        "type": "number"
      },
      "url": {
        "description": "The URL to navigate to",
        "type": "string"
      }
    },
    "required": ["tabId", "url"]
  }
}

이 네이밍 규칙이 필요한 이유는 여러 MCP 서버가 동시에 연결될 수 있기 때문이다. 예를 들어 filesystem 서버와 github 서버가 둘 다 read라는 도구를 제공한다면 충돌이 발생한다. mcp__filesystem__readmcp__github__read로 구분하면 이 문제가 해결된다.

Claude Code에서 /mcp를 입력하면 연결된 MCP 서버 목록을 볼 수 있다. Claude in Chrome이 제공하는 도구들을 살펴보자:

도구 이름 설명
mcp__claude-in-chrome__navigate URL로 이동하거나 브라우저 히스토리 앞/뒤로 이동
mcp__claude-in-chrome__computer 마우스/키보드로 브라우저와 상호작용, 스크린샷 촬영
mcp__claude-in-chrome__read_page 페이지의 접근성 트리 표현을 가져옴
mcp__claude-in-chrome__find 자연어로 페이지 요소 찾기
mcp__claude-in-chrome__form_input 폼 요소에 값 입력
mcp__claude-in-chrome__javascript_tool 페이지 컨텍스트에서 JavaScript 실행

이 도구들은 에이전트가 MCP 서버에 연결할 때 서버로부터 목록을 받아와 tools 배열에 추가된다. 에이전트가 시작될 때 대략 다음과 같은 과정이 일어난다:

  1. 에이전트가 설정된 MCP 서버들에 연결
  2. 각 서버에 tools/list 요청을 보내 제공하는 도구 목록 수신
  3. 받은 도구들에 mcp__server-name__ prefix를 붙여 tools 배열에 추가
  4. API 요청 시 내장 도구와 함께 전송

MCP 도구 호출 흐름

Claude가 MCP 도구를 호출하면 에이전트는 다음 단계를 수행한다:

Claude                    Agent                    MCP Server
   │                        │                          │
   │  tool_use              │                          │
   │  (mcp__claude-in-      │                          │
   │   chrome__navigate)    │                          │
   │ ─────────────────────► │                          │
   │                        │                          │
   │                      prefix 파싱                   │
   │                      server: claude-in-chrome     │
   │                      tool: navigate               │
   │                        │                          │
   │                        │  tools/call              │
   │                        │ ───────────────────────► │
   │                        │                          │
   │                        │  실행 결과                 │
   │                        │ ◄─────────────────────── │
   │                        │                          │
   │  tool_result           │                          │
   │ ◄───────────────────── │                          │
   │                        │                          │

결국 MCP 도구 호출도 일반 Tool Use와 동일한 패턴을 따른다. 차이점은 에이전트가 도구를 직접 실행하는 대신 외부 MCP 서버에 위임한다는 것뿐이다.

MCP는 왜 도구를 외부로 분리하는가

지금까지 MCP 도구가 어떻게 동작하는지 살펴보았다. 그런데 왜 이런 구조가 필요할까?

모든 도구를 내장할 수 없다

에이전트에 도구를 추가하는 가장 단순한 방법은 에이전트 내부에 직접 구현하는 것이다. 하지만 이 방식에는 한계가 있다:

  • 모든 도구를 미리 구현할 수 없다: 파일 시스템, 데이터베이스, 브라우저, Slack, GitHub, Jira... 세상에는 수많은 시스템이 있고 에이전트 개발자가 이 모든 연동을 직접 구현하기는 불가능하다.
  • 사용자마다 필요한 도구가 다르다: 어떤 사용자는 PostgreSQL을, 다른 사용자는 MongoDB를 사용한다. 모든 조합을 에이전트에 내장할 수 없다.
  • 도구 업데이트가 어렵다: 외부 API가 변경되면 에이전트 전체를 다시 배포해야 한다.

MCP는 이 문제를 도구 제공자와 도구 사용자의 분리로 해결한다.

MCP의 핵심 구조

MCP는 클라이언트-서버 아키텍처를 따른다.

참여자 (Participants):

  • MCP Host: MCP 클라이언트를 관리하는 AI 애플리케이션 (예: Claude Desktop, VS Code, Claude Code)
  • MCP Client: MCP 서버와 연결을 유지하고 컨텍스트를 얻어오는 컴포넌트
  • MCP Server: MCP 클라이언트에게 컨텍스트를 제공하는 프로그램 (도구 제공자)

Host와 Client의 관계:

  • Host는 MCP 서버 연결마다 별도의 MCP Client를 생성한다
  • 예를 들어 Claude Code(Host)가 Chrome 서버와 filesystem 서버에 연결하면 두 개의 MCP Client 객체가 생성된다
  • 각 MCP Client는 하나의 MCP Server와 전용 연결을 유지한다

이 분리 덕분에:

  • 도구 제공자는 MCP 서버만 만들면 됨 (에이전트 코드 수정 불필요)
  • 에이전트 개발자는 MCP 클라이언트만 구현하면 모든 MCP 서버의 도구 사용 가능
  • 사용자는 필요한 MCP 서버만 설치하여 에이전트 기능 확장 가능

MCP와 인증

원격 MCP 서버를 사용할 때는 인증이 필요한 상황이 발생한다. MCP 서버가 사용자의 GitHub 저장소에 접근하거나 Slack 워크스페이스에 메시지를 보내야 할 때, "이 요청이 정말 이 사용자로부터 온 것인가?"를 확인해야 한다.

MCP는 프로토콜 수준에서 OAuth 2.1 인증 체계를 표준화했다. 덕분에 어떤 MCP 클라이언트든 동일한 방식으로 MCP 서버에 인증할 수 있고, MCP 서버 개발자는 인증 로직을 한 번만 구현하면 모든 클라이언트와 호환된다.

Tool Use를 넘어서

지금까지 MCP를 Tool Use의 확장으로 설명했다. 실제로 MCP 도구는 가장 많이 사용되는 기능이고, LLM이 외부 시스템과 상호작용하는 핵심 방식이다.

하지만 MCP가 제공하는 것이 도구만은 아니다. MCP 명세를 보면 Tool Use와 무관하게 동작하는 기능들이 있다. 이 기능들은 tool_use -> tool_result 사이클을 거치지 않고 다른 방식으로 LLM에게 컨텍스트를 제공하거나 LLM의 능력을 활용한다.

MCP의 확장 기능

MCP는 도구(Tools) 외에도 몇가지 핵심 기능들이 있다. Resources, Prompts, 그리고 Sampling이다.

Resources

Resources는 Tool Use를 거치지 않는 데이터 제공 기능이다. 도구는 LLM이 "행동"을 요청할 때 호출되지만 Resource는 LLM이 응답을 생성하기 전에 컨텍스트로 미리 주입된다.

예를 들어 PostgreSQL MCP 서버가 데이터베이스 스키마를 Resource로 노출한다고 하자. 사용자가 "users 테이블에 email 컬럼 추가해줘"라고 요청하면 LLM은 별도의 도구 호출 없이도 현재 스키마 구조를 이미 알고 있다. SELECT * FROM information_schema.columns를 먼저 실행할 필요가 없는 것이다. Resource가 컨텍스트에 미리 주입되어 있기 때문이다.

Prompts

Prompts도 Tool Use와 무관하다. MCP 서버가 미리 정의한 재사용 가능한 프롬프트 템플릿으로 클라이언트가 직접 요청해서 가져온다.

예를 들어 코드 리뷰 MCP 서버가 "보안 취약점 분석" 프롬프트 템플릿을 제공하면 클라이언트는 이 템플릿을 불러와 LLM에게 전달할 수 있다. LLM이 도구를 호출하는 것이 아니라 클라이언트가 MCP 서버로부터 프롬프트를 받아오는 것이다.

Sampling (역방향 LLM 호출)

Sampling은 가장 독특한 기능이다. 일반적인 MCP 흐름은 LLM → Agent → MCP Server지만 Sampling은 이 방향을 뒤집는다:

일반 흐름:     LLM → Agent → MCP Server
Sampling:     MCP Server → Agent → LLM

MCP 서버가 복잡한 판단이 필요할 때 역으로 LLM에게 질문할 수 있다. 예를 들어 코드 분석 MCP 서버가 특정 패턴을 발견했을 때 "이 코드가 보안 취약점인지 판단해달라"고 LLM에게 요청하는 식이다. MCP 서버는 LLM의 답변을 기반으로 최종 결과를 만들거나 다른 도구나 함수를 사용하는 등의 판단을 할 수 있게 된다.

Sampling은 Tool Use의 tool_use -> tool_result 패턴이 아니라 MCP 프로토콜 자체의 sampling/createMessage 요청을 통해 동작한다.

마무리

지금까지 MCP가 Tool Use 위에서 어떻게 동작하고 또 Tool Use를 넘어 어떤 기능들을 제공하는지 살펴보았다.

MCP 도구는 Tool Use다. 내장 도구와 동일하게 tools 배열에 포함되고 tool_use로 호출되며 tool_result로 결과가 반환된다. LLM 입장에서는 구분이 없다. 차이점은 실행 위치뿐이다. 내장 도구는 Host 프로세스 내부에서, MCP 도구는 외부 MCP Server에서 실행된다.

하지만 MCP는 도구만 제공하지 않는다. Resources와 Prompts는 Tool Use 없이 컨텍스트를 제공하고 Sampling은 MCP 서버가 역으로 LLM을 활용할 수 있게 한다. MCP는 Tool Use를 확장하면서도 Tool Use만으로는 해결할 수 없는 영역까지 커버하는 프로토콜이다.

모든 도구를 에이전트에 내장할 수 없기 때문에 에이전트와 도구를 분리할 필요가 생겼고 MCP는 도구 제공자와 사용자를 분리하여 생태계 확장을 가능하게 한다.

이 글에서는 Tool Use의 기본 구조를, 이어지는 글에서는 Subagent가 Tool Use 위에서 동작함을 살펴보았고 이번 글에서 MCP가 Tool Use를 확장하면서도 그 이상의 기능을 제공함을 살펴보았다. Claude Code의 핵심 확장 기능들은 Tool Use라는 메커니즘 위에서 동작하지만 MCP 생태계는 그보다 더 넓은 가능성을 열어두고 있다.

Read more →
4
0
1
1
1
0
0
1
2
0
1
0
1
0
1

関西で有名な元アナウンサーのコモさん(子守泰範さん)が「ひょうごデモ行進」の様子を見やすく動画編集して下さっています。
もし良ければ :_mastodon_2022: :aozo: の皆様もご覧下さい。
:mastogrin:
動画に使われているかっこいい楽曲は、ひょうごデモ行進公式ソング「STAND UP HYOGO」で、主催者のREBELさんの思いを作詞なさったものです🔥


プロテスト✊🪧📣
youtu.be/Eq34kF0dNpY

0
1
0
1
1
0
0
0
0
2
1
1

집에 통신망 이중화를 하려고 했는데, 이미 한 통신사의 유선 인터넷이 들어와있는 상태에서 타사 회선을 하나 더 신청하는건 민폐가 될 수 있다 그래서...

유선 1회선에, LTE 3회선(통신 3사) 가입해서 4중 이중화로 구성함.

솔직히 LTE 망이 유선에 비해 훨씬 느린건 어쩔 수 없는 것 같음. ㅠㅠ

그래도 쓰는 이유가 장애 상황에선 대역폭이 큰 것보다 연결이 유지되는게 중요하니까

랜 케이블 뽑아가면서 테스트해보니 Failover 잘 되는거 보니까 뿌듯함.

얼마전에 실제로 유선 망에 이상이 생겨서 Failover 된 적이 있었는데 끊어진지도 모르고 썼을 정도 ㅋㅋ

0

【ブログ書いたやで】 CSS で独自のチェックボックスやラジオボタンをデザインする時に label や span の擬似要素を使うより input 要素そのものの擬似要素を使った方が何かと便利で簡単だよ、という話を書きました。ギリギリですが何とかリリース日前に記事を公開できて良かったなと思います(ポイントはそこじゃないです。涙)
👇
えっ先輩まだチェックボックスやラジオボタンのカスタマイズに label とかの擬似要素使ってんすか? それもう古いっすよ… jeffreyfrancesco.org/weblog/20

0
1

從2019年去過德國以後,我好像沒再出國過,睽違六年再次坐飛機,有好多新奇(?)的心得。

- 好驚訝在飛機上有免費wifi。
- 我現在在一萬公尺的高空上發嘟!
- 第一次出國帶那麼大又重的行李箱,推起來真是吃力。
- 還好不需要等到起飛前3小時就能在機場托運了。
- 今天出境的人好多!幸好也通關得很快。
- 我覺得自己很棒,重新以飛行新手的身份自己打包行李、走登機程序,都沒有問題。我感慨的點是,如果是我的媽媽,她一定不願意花心力搞懂這一切,所以她也一直不懂,必須要有人「帶」她出國。我對她這點特別看不順眼,這可能是我的陰影。
- 有些人顯然是飛行老手,背包上吊著一雙球鞋、腳上穿著一雙拖鞋登機。我只有腳上穿著的短靴,一上機就座就馬上脫掉,但上廁所要再套回腳上有點麻煩。
- 非常幸運的,我坐在靠窗的位置且旁邊是空座!所以我可以往左靠也可以往右靠著睡。
- 但上廁所還是要把靠走道的乘客叫醒,還好我抓到他醒來的空檔。
- 我帶了六年前的長途飛機上發的眼罩,感謝自己。
-很順利一口氣睡了6小時,醒來後,飛行旅程只剩下6小時,還可以上網發廢嘟。

在我降落前4hrs,情況突然急轉直下,弟妹竟然破水了!雖然早就知道生辰是小孩揀的,半分勉強不得,但是這也太巧了吧!我一度做好下機後衝去醫院向我弟拿他家鑰匙、再在他家廚房自己搜食材做飯的心理準備,結果德國的醫生又叫他們「開始宮縮再來」把他們打發回家了。

這麼一來,我只要自行前往他家就行,只要我能趕在姪女之前抵達他們家!

0
0
0
1
1
1
1