# 하나의 질문, 세 가지 접근 경로: MCP, A2A, REST

접근 경로와 봉투

*레슨 2/5 · 12분 · 고급 · 개발자*

## 이번 레슨에서는

레슨을 마치면 다음을 할 수 있습니다.

- get-sanctions-status를 스킬 메서드, A2A 핵심 메시지, REST 읽기로 각각 호출하기
- MCP 세션을 직접 초기화하고 도구 나열하기
- 유형이 정해진 거부 알아보기: -32600, -32602, 세션 오류, 코드가 붙은 400

## 질문

`get-sanctions-status`는 매개변수를 받지 않으며 [OFAC](https://achivx.kr/academy/how-it-works/what-is-the-ofac-sdn-list/) 데이터 세트의 상태에 답합니다. 호스트에서 가장 저렴한 읽기이며, 모든 접근 경로에서 같은 객체입니다. 2026-10-13에는 다음과 같았습니다.

```
{"source": "ofac_sdn", "evm_count": 120, "solana_count": 4, "tron_count": 261, "total": 385,
 "updated_at": "2026-10-13T04:00:02Z",
 "note": "OFAC SDN digital-currency addresses (public, 0xB10C list). Heuristic exposure only — not legal advice; verify against the official SDN list."}
```

## 접근 경로 1: REST

`GET /v1/sanctions` — 위의 객체가 `ETag`, `Cache-Control: public, max-age=300`과 함께 반환됩니다. 그날 `If-None-Match`를 붙인 두 번째 요청은 `304`로 응답했습니다.

## 접근 경로 2: A2A, 두 가지 방식

자체 메서드로 호출 — 버전 헤더는 필요 없고, 봉투는 필수입니다.

```
POST /a2a
{"jsonrpc": "2.0", "id": 1, "method": "get-sanctions-status", "params": {}}
```

답은 `{"jsonrpc": "2.0", "result": {…the object…}, "id": 1}`이며, 응답 헤더 `A2A-Extensions: https://stablescan.achivx.com/a2a-ext/skill-methods/v1`이 붙습니다. A2A 1.0 핵심 방식으로는 `A2A-Version: 1.0` 헤더와 데이터 파트를 붙인 `SendMessage`를 보냅니다.

```
{"jsonrpc": "2.0", "id": 2, "method": "SendMessage",
 "params": {"message": {"messageId": "any-unique-string", "role": "ROLE_USER",
                        "parts": [{"data": {"skill": "get-sanctions-status", "params": {}}}]}}}
```

답은 맨 `result`가 아니라 Message입니다. 2026-10-19에는 `role: "ROLE_AGENT"`인 `result.message`로 돌아왔고, 데이터 파트 하나의 `data`가 제재 객체였습니다. 위와 같은 형태이며 `updated_at`만 그날의 값입니다. 그러므로 `result`가 아니라 `result.message.parts[0].data`를 비교하십시오. 한 줄씩 보면, `messageId`는 직접 정하며 고유해야 합니다. `role`은 `ROLE_USER`여야 합니다(맨 `user`는 거부되며, 메시지에 수정 방법이 적혀 있습니다). 데이터 파트는 스킬과 그 매개변수를 지정합니다. 데이터 파트 대신 텍스트 파트를 보내면 추측하지 않습니다. 에이전트는 *This is a deterministic telemetry agent — it does not interpret free text*(이것은 결정론적 텔레메트리 에이전트이며, 자유 텍스트를 해석하지 않습니다)라는 메시지로 답하고, 스킬 여덟 개를 예시와 함께 나열합니다.

## 접근 경로 3: MCP를 직접

```
POST /mcp   Content-Type: application/json   Accept: application/json, text/event-stream
{"jsonrpc": "2.0", "id": 1, "method": "initialize",
 "params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "my-client", "version": "0"}}}
```

답은 이벤트 스트림이며, 그 `serverInfo`에는 이름 `stablescan`, 버전 `1.4.0`이 적혀 있습니다. 응답 헤더 `Mcp-Session-Id`가 세션입니다. 이후의 모든 호출에 이것을 보내십시오. `{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}`는 도구 여덟 개를 주석과 함께 나열합니다. 헤더 없이 같은 호출을 하면 메시지가 `method "tools/list" is invalid during session initialization`인 오류로 응답합니다. 그다음 `{"name": "get_sanctions_status", "arguments": {}}`로 `tools/call`을 호출합니다. 스킬 id에서 하이픈을 밑줄로 바꾼 이름입니다.

## 만나게 될 거부

A2A에 맨 `{"method": "get-sanctions-status"}`만 보내면 HTTP 200 안에 `-32600` *Invalid Request: jsonrpc must be 2.0*이 담겨 옵니다. 매개변수가 틀리면 수정 방법과 함께 `-32602`가 옵니다. REST에서 `chain`을 받는 읽기(2026-10-13의 `/v1/addresses/{address}?chain=0x1`)는 허용되는 형식을 메시지에 명시한 `400 invalid_chain`으로 응답합니다(`/v1/sanctions`는 매개변수를 받지 않으며 붙여도 무시합니다. 2026-10-19에 그곳에서 `?chain=0x1`은 `200`으로 응답했습니다). 알 수 없는 `/v1` 경로는 설명서를 가리키는 JSON `404 not_found`로 응답합니다. 상태가 아니라 코드에 따라 분기하십시오.

## 핵심 정리

- REST, A2A 메서드, A2A 메시지, MCP 도구에서 같은 객체가 돌아옵니다
- A2A: JSON-RPC 봉투는 필수입니다. SendMessage에는 messageId, ROLE_USER, A2A-Version 헤더가 필요하고, 스킬 메서드에는 헤더가 필요 없습니다
- MCP: initialize하고, Mcp-Session-Id를 보관한 다음, 밑줄 이름으로 tools/list와 tools/call을 호출합니다
- 거부는 유형이 정해져 있으며 수정 방법을 담고 있습니다: -32600, -32602, invalid_chain, not_found, 세션 오류
- 텍스트는 해석되지 않습니다. 텍스트 메시지에는 추측이 아니라 사용 방법이 답으로 옵니다

## Stablecoin scanner ACHIVX에서 직접 해 보기

1. [/v1/sanctions](https://stablescan.achivx.com/v1/sanctions)를 열고 `total`과 `updated_at`을 읽습니다. 클라이언트가 헤더를 보여 준다면 `ETag` 응답 헤더를 기록합니다.
2. 위의 스킬 메서드 본문을 `/a2a`에 POST하고 `result`를 1단계와 비교합니다. `A2A-Extensions` 응답 헤더를 찾습니다.
3. 위의 `SendMessage` 본문을 `A2A-Version: 1.0` 헤더와 함께 POST합니다. 그다음 데이터 파트 대신 텍스트 파트 `{"text": "hello"}`로 다시 보내고, 에이전트가 무엇이라고 답하는지 읽습니다.
4. `/mcp`에 `initialize`를 POST하고, `Mcp-Session-Id`를 보관한 뒤 `tools/list`를 POST합니다. 도구 수를 세고 그중 하나의 `annotations`를 읽습니다.
5. 세션 헤더 없이 `tools/list`를 한 번 더 POST하고 오류 메시지를 읽습니다.

## 레슨 돌아보기

- 어느 접근 경로가 런타임이 파싱할 것을 가장 적게 주고, 어느 것이 보관할 것(세션, 헤더, 커서)을 가장 많이 줍니까?
- 코드의 어느 지점에서 JSON-RPC 오류를 담은 HTTP 200이 성공으로 오인되겠습니까?

## 다음 내용

답에는 무엇을 할 수 없었는지 밝히는 필드가 담겨 있습니다. 다음은 페이로드에서 정직성 계약을 읽는 방법입니다.

## 더 알아보기

- [Stablecoin scanner ACHIVX MCP 서버는 어떻게 연결합니까?](https://achivx.kr/academy/for-agents/how-to-connect-the-mcp-server/)
- [에이전트 카드는 무엇을 선언하며, A2A로 스킬을 어떻게 호출합니까?](https://achivx.kr/academy/for-agents/what-the-agent-card-declares/)
- [답은 어떤 것일 수 있습니까? REST, A2A, MCP의 모든 상태와 코드](https://achivx.kr/academy/for-agents/every-answer-code-on-every-door/)

레슨 2/5 · 에이전트를 위한 Stablecoin scanner ACHIVX · 위에 링크된 사용자 가이드를 바탕으로 합니다.

---

출처: https://achivx.kr/academy/courses/the-scanner-for-agents/the-scanner-for-agents-02-one-question-three-doors/ · 영어 원문: https://achivx.com/academy/courses/the-scanner-for-agents/the-scanner-for-agents-02-one-question-three-doors.html
