- DEV Community에 게재된 Prakash Rao Bethapudi, Marco Gonzalez의 글을 원저자의 허락 하에 번역하였습니다.
- 이 글이 여러 차례 인용하는 AAIF 글, 402 Payment Required: 엔터프라이즈 MCP 서버가 비용을 지불하는 에이전트에게 지켜야 할 것도 함께 번역하였습니다.
- 원문은 아래 링크에서 확인하실 수 있습니다.
x402 + MCP: 예산 확인은 어디에서 해야 할까
x402 + MCP: where does the budget check go?
- 저자: Prakash Rao Bethapudi, Marco Gonzalez
- 게시일: 2026년 9월 26일
에이전트가 고객 레코드를 보강(enrich)해야 합니다. 그 작업을 하는 도구는 돈이 듭니다.
An agent needs to enrich a customer record. The tool that does it costs money.
x402 v2 어디에도 누가 그것을 승인할 수 있는지는 적혀 있지 않습니다. MCP 2026-07-28에도 적혀 있지 않습니다. 두 사양 모두 가격과 라우팅 메타데이터를 HTTP 헤더로 옮겼고, 이는 이제 게이트웨이가 도구 호출의 비용을 볼 수 있다 는 뜻입니다. 가격을 볼 수 있다는 것은 그 가격을 승인할 권한을 갖는 것과 같지 않습니다.
Nothing in x402 v2 says who is allowed to approve that. Nothing in MCP 2026-07-28 says it either. Both specs moved price and routing metadata into HTTP headers, which means your gateway can now see what a tool call costs. Seeing a price is not the same as having the authority to approve one.
그 권한이 어디에 있어야 하는지는 Agentic AI Foundation과 함께 쓴 402 Payment Required: What Enterprise MCP Servers Owe the Agents That Pay Them에서 다뤘습니다. 그리고 그 내용을 도쿄에서 열린 AGNTCon + MCPCon Japan 에 가져가, 테스트 네트워크에서 에이전트가 실제로, 라이브로 그것을 하게 했습니다.
We wrote about where that authority should sit in 402 Payment Required: What Enterprise MCP Servers Owe the Agents That Pay Them, with the Agentic AI Foundation. Then we took it to AGNTCon + MCPCon Japan in Tokyo and let an agent actually do it, live, on a test network.
글과 세션 중 어느 쪽이든 놓치셨다면, 시작하기 전에 알아야 할 모든 것을 여기에 정리했습니다.
If you missed either the post or the session, here is everything you need before we start.
먼저, 따라잡기 / First, the catch-up
x402란. HTTP에는 1997년부터 402 Payment Required 상태 코드가 사용되지 않은 채 놓여 있었습니다. 예약만 되어 있을 뿐, 한 번도 명세된 적이 없었습니다. x402는 마침내 여기에 의미를 부여했습니다. 서버는 원하는 조건과 함께 402 로 응답하고, 클라이언트는 서명된 결제 승인(payment authorization)을 붙여 재시도하며, 서버는 결과와 함께 정산(settlement)의 증거를 반환합니다. v2(2025년 12월)는 이 모든 것을 본문에 묻어 두는 대신 헤더로 옮겼습니다: PAYMENT-REQUIRED, PAYMENT-SIGNATURE, PAYMENT-RESPONSE 입니다.
What x402 is. HTTP has had a
402 Payment Requiredstatus code sitting unused since 1997, reserved but never specified. x402 finally gave it a meaning: a server answers402with the terms it wants, the client retries with a signed payment authorization, and the server returns the result plus evidence of settlement. v2 (December 2025) moved all of that into headers:PAYMENT-REQUIRED,PAYMENT-SIGNATUREandPAYMENT-RESPONSE, instead of burying it in bodies.
MCP란. Model Context Protocol은 AI 에이전트가 도구를 발견하고 호출하는 방식입니다. 2026-07-28 개정판 은 세션과 Mcp-Session-Id 헤더를 제거하고, Mcp-Method 와 Mcp-Name 을 헤더로 추가했으며, RFC 9207에 따른 발급자(issuer) 검증으로 인가(authorization)를 강화했습니다.
What MCP is. The Model Context Protocol is how an AI agent discovers and calls tools. The 2026-07-28 revision removed sessions and the
Mcp-Session-Idheader, addedMcp-MethodandMcp-Nameas headers, and hardened authorization with issuer validation per RFC 9207.
두 릴리즈가 함께 중요한 이유. 두 릴리즈 모두 중요한 메타데이터를 요청 본문에서 헤더로 옮겼습니다. 이제 게이트웨이, 속도 제한기(rate limiter), WAF는 JSON-RPC 본문을 하나도 파싱하지 않고도 누가 호출하는지, 어떤 도구인지, 비용이 얼마인지 볼 수 있습니다. 유료 에이전트 트래픽의 사용량 측정(metering)과 라우팅이 극적으로 저렴해졌습니다.
Why those two releases matter together. Both moved the interesting metadata out of request bodies and into headers. Your gateway, rate limiter and WAF can now see who is calling, which tool, and what it costs, without parsing a single JSON-RPC body. Metering and routing for paid agent traffic got dramatically cheaper.
그리고 바로 그곳에서 문제가 시작됩니다. 헤더가 보인다고 해서 권한이 생기지는 않습니다. 인프라가 가격을 볼 수 있게 되는 순간 그에 대해 무언가를 결정해야 하는데, 어느 사양도 누가 그 결정을 내리는지 알려주지 않습니다. 그것이 AAIF 글의 주장이었습니다. 지출 결정은 에이전트가 닿을 수 없는 예산 권한(budget authority)에 속하며, 그것을 어디에 두느냐가 프로토콜의 세부 사항이 바뀐 뒤에도 여전히 중요한 부분이라는 것입니다.
And that is exactly where the problem starts. Header visibility is not authority. The moment your infrastructure can see the price, it has to decide something about it, and neither spec tells you who gets to make that call. That was the argument in our AAIF post: the spending decision belongs to a budget authority the agent cannot reach, and where you put it is the part that will still matter after the protocol details have moved on.
도쿄에서 한 일. 논쟁을 멈추고 실제로 실행했습니다. 라이브 에이전트가 테스트 네트워크에서 MCP 도구 호출에 비용을 지불했고, 에이전트가 승인받지 않은 것에 지출하려고 시도하는 경로도 포함했습니다.
What we did in Tokyo. Stopped arguing and ran it: a live agent paying for MCP tool calls on a test network, including the path where it tries to spend on something it was not approved for.
등장하는 구성 요소 / The cast
다섯 가지 구성 요소가 계속 등장합니다. 외울 필요는 없습니다. 다이어그램을 깔끔하게 읽을 수 있도록 여기에 정리해 둡니다.
Five moving parts appear throughout. You do not need to memorize these; they are here so the diagrams read cleanly.
| 구성 요소 / Component | 맡은 한 가지 일 / Its one job |
|---|---|
| 에이전트(Agent) | 어떤 작업을 할지 결정합니다. 처음부터 끝까지 적대적인 존재로 취급합니다. 개인 키를 갖지 않습니다. |
| 집행 게이트웨이(Enforcement gateway) | 밖으로 나가는 유일하게 허용된 경로입니다. 모든 요청을 두 번 보며, 경계에서 거부할 수 있습니다. |
| 승인 서비스(Authorization service) | 지출이 허용되는지 결정하고, 예산을 예약합니다. 에이전트는 여기에 영향을 줄 수 없습니다. |
| 서명 서비스(Signing service) | 서명을 만듭니다. 서명하는 내용을 읽으며, 거부할 수 있습니다. |
| 보호된 리소스(Protected resource) | 유료 서버 뒤에 있는, 돈이 드는 도구입니다. |
Component Its one job Agent Decides what work to do. Treated as hostile throughout. Holds no private key. Enforcement gateway The only permitted route out. Sees every request twice and can refuse at the boundary. Authorization service Decides whether spending is permitted, and reserves the budget. The agent cannot influence it. Signing service Produces signatures. Reads what it signs, and can refuse. Protected resource The tool that costs money, behind a paid server.
무엇을 방어하고 무엇을 방어하지 않는지 알 수 있도록 위협 모델(threat model)을 밝혀 둡니다. 에이전트 프로세스와 그에 들어가는 모든 입력은 적대적 입니다. 게이트웨이, 서비스, 그리고 그 정책들은 정직하지만 실수할 수 있습니다. 침해된 바이너리, 악의적인 운영자, 하드웨어에서의 키 추출, 체인 수준의 공격은 범위 밖 입니다. 다른 문제이니, 다른 글에서 다루겠습니다.
Our threat model, so you know what is and is not being defended: the agent process and every input to it are hostile. The gateway, the services and their policies are honest but fallible. Compromised binaries, malicious operators, key extraction from hardware and chain-level attacks are out of scope. Different problem, different post.
이제 요청 하나를 끝까지 따라가 보겠습니다. 3분의 2쯤 내려가면 흥미로워지는데, 경계에 도착한 요청이 승인된 그 요청이 아니었다는 것이 드러나는 부분입니다.
Now follow one request all the way through. It gets interesting about two-thirds of the way down, when the request that arrives at the boundary turns out not to be the request that was approved.
에이전트, 쇼핑을 나서다 / The agent goes shopping
에이전트에게는 업무 용어로 적힌 과제가 있습니다: 42번 레코드를 보강하라(enrich record 42). 에이전트는 이 작업의 비용이 얼마인지도, 어느 제공자가 처리할지도 모릅니다.
Our agent has a task stated in business terms: enrich record 42. It does not know what that costs, and it does not know which provider will do it.
그래서 첫 번째 문제가 곧바로 나타납니다. 적대적인 존재에게 지갑부터 쥐여주지 않고, 어떻게 가격을 비교하게 할 수 있을까요?
So the first problem is immediate: how do you let a hostile thing shop around, without handing it a wallet first?
에이전트는 요청하고, 의도적으로 거부당합니다:
It asks, and gets refused on purpose:
GET /tools/enrich?record=42 HTTP/1.1
Host: resource.example
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: eyJ2IjoyLCJhY2NlcHRzIjpbey...
그 헤더는 base64로 인코딩된 JSON입니다. 디코딩하면 제안(offer)이 됩니다:
That header is base64 JSON. Decoded, it is an offer:
{
"v": 2,
"accepts": [{
"scheme": "exact",
"network": "<test-network>",
"asset": "<stablecoin-contract>",
"payTo": "<payee-address>",
"maxAmountRequired": "<amount>",
"resource": "https://resource.example/tools/enrich",
"maxTimeoutSeconds": 60,
"nonce": "<server-chosen>"
}]
}
이것이 HTTP 바인딩(binding)입니다. MCP에서도 같은 협상이 일어나지만, 같은 위치에서 일어나지는 않습니다. 경계에서 무언가를 측정하기 전에 알아둘 만한 차이입니다:
That is the HTTP binding. Over MCP the same negotiation happens, but not in the same place. Worth knowing before you meter anything at the edge:
| HTTP 바인딩 / HTTP binding | MCP 바인딩 / MCP binding | |
|---|---|---|
| 가격 요구가 도착하는 형태 / Price challenge arrives as | 402 상태 코드 + PAYMENT-REQUIRED |
도구 결과 안의 조건 |
| 라우팅 메타데이터 / Routing metadata | URL 경로 | Mcp-Method / Mcp-Name 헤더 |
| 본문을 파싱하지 않고 인프라가 볼 수 있는가 / Visible to infra without parsing a body | 예 | 가격 요구는 볼 수 없음 |
HTTP binding MCP binding Price challenge arrives as 402status +PAYMENT-REQUIREDterms in the tool result Routing metadata the URL path Mcp-Method/Mcp-NameheadersVisible to infra without parsing a body yes the challenge is not
MCP 바인딩은 아직 아무도 지불하지 않은 호출에 대해 게이트웨이에 200 을 돌려줍니다. 사용량 측정 로직이 상태 코드를 기준으로 동작한다면, 이 호출을 그대로 지나쳐 버립니다.
The MCP binding hands your gateway a
200for a call nobody has paid for yet. If your metering logic keys on status codes, it will sail straight past that.
여기서 겉보기보다 중요한 첫 번째 설계 결정이 나옵니다. 묻는 것은 무료입니다.
Here is the first design decision that matters more than it looks. Asking is free.
무언가의 비용을 알아내는 일 자체에 돈이 든다면, 모든 에이전트가 계획을 세우기 전에 지출 권한을 가져야 하고, 이는 승인 결정을 전체 흐름에서 가장 정보가 적은 순간으로 밀어냅니다. 탐색이 무료이기 때문에, 이 첫 번째 단계는 가치를 소비할 권한을 전혀 갖지 않아도 됩니다. 경계가 이 요청을 받아들일 수 있는 것은 바로, 받아들여도 조직이 아무것도 약속하지 않기 때문입니다.
If finding out what something costs itself costs money, then every agent needs spending authority before it can plan, which pushes the authorization decision to the least informed moment in the entire flow. Free discovery is what lets this first pass carry no authority to consume value at all. The boundary can admit it precisely because admitting it commits the organization to nothing.
그리고 이 단계를 허용하는 비용이 적기 때문에, 경계는 요청을 전달하는 동안 조용하지만 중요한 일을 할 수 있습니다:
And because this pass is cheap to allow, the boundary can do something quietly important while it is forwarding:
게이트웨이는 돌아오는 길에 견적을 직접 보았습니다. 이 점을 기억해 두세요. 경계에서는 이것이 승부의 전부가 됩니다.
The gateway saw the quote itself, on the way back. Remember that. It becomes the whole game at the boundary.
무엇이 경계를 넘어갔는지에도 주목하세요. 기업의 자격 증명이 아니라, 리소스 하나와 동작 하나로 범위가 제한된, 새로 발급된 자격 증명입니다. 다른 어떤 용도로도 쓸모가 없습니다. 이것이 대상 변환(audience translation)이며, 하위 서비스가 받아서 다른 곳에 재사용할 수 있는 무언가를 건네지 않는 방법입니다.
Note also what crossed the boundary: not the enterprise credential, but a freshly minted one restricted to one resource and one action. Useful for nothing else. That is audience translation, and it is how you avoid handing a downstream service something it could turn around and reuse.
누군가는 승인해야 합니다 / Someone has to approve it
이제 에이전트가 실제로 작업을 하려 합니다. 돈이 실제로 움직이는 순간이며, 에이전트가 아닌 누군가가 허락해야 하는 순간입니다.
Now the agent wants to actually do it. This is the moment the money becomes real, and the moment somebody other than the agent has to say yes.
여기에는 네 가지 결정이 얽혀 있으며, 유용한 방법은 이들을 떼어 내어 각각에 주인을 정해 주는 것입니다:
Four decisions are tangled together here, and the useful move is to pull them apart and give each one an owner:
| 결정 / Decision | 누가 소유하는가 / Who owns it |
|---|---|
| 어떤 작업을 할 것인가 | 에이전트 |
| 누가 요청하는가 | ID 공급자(identity provider), 게이트웨이에서 |
| 비용은 얼마인가 | 리소스 서버, 인자(arguments)로부터 |
| 지출이 허용되는가 | 에이전트가 닿을 수 없는 예산 권한 |
Decision Who owns it What work to do the agent Who is asking identity provider, at the gateway What it costs the resource server, from the arguments Whether it is permitted a budget authority the agent cannot reach
사람들이 다른 결정과 한데 뭉뚱그려 버리는 것이 마지막 행이며, 이것을 뭉뚱그리면 에이전트가 자신의 지출을 스스로 승인할 수 있게 됩니다.
That last row is the one people collapse, and collapsing it is how an agent ends up able to approve its own spending.
승인 서비스는 네 가지 일을 순서대로 합니다. 하나하나가 모두 구조를 지탱하는 역할을 합니다:
The authorization service does four things in order. Each one is load-bearing:
견적은 요청이 아니라 게이트웨이에서 가져옵니다. 에이전트는 적대적이므로, 무엇을 제안받았다는 에이전트의 주장은 아무 가치가 없습니다. 에이전트가 가격을 알아보는 동안 경계가 실제 조건을 목격했습니다.
It fetches the quote from the gateway, never from the request. The agent is hostile; its claim about what it was offered is worthless. The boundary witnessed the real terms while the agent was shopping.
가격을 보기 전에 기능(capability)으로 먼저 거릅니다. 기능과 규정 준수(compliance) 요건이 먼저 후보를 좁힙니다. 순위를 매기는 것이 아니라 거르는 것입니다. 가격이 아무리 유리해도 제외된 후보는 되살아나지 않습니다. 이 순서를 거꾸로 하면, 규제 대상 데이터를 서슴없이 싼 곳으로 보내는 시스템이 됩니다.
It filters on capability before it looks at price. Capability and compliance narrow the field first. A filter, not a ranking. No price advantage restores an excluded candidate. Get this backwards and you have a system that will happily route regulated data somewhere cheap.
어떤 시도를 하기 전에 먼저 예산을 예약합니다. 나눌 수 없는(indivisible) 하나의 상태 전이로 처리합니다. 이것이 하나의 할당을 공유하는 동시 실행 에이전트들이 합쳐서 한도를 초과하는 것을 막습니다. 지출 약속을 나중에 발견하는 것이 아니라 미리 확보합니다.
It reserves the budget before any attempt is made, as one indivisible state transition. This is what stops concurrent agents sharing an allocation from collectively overspending it: the commitment is taken up front rather than discovered afterwards.
그런 다음 행동(action)의 의미 전체를 하나의 다이제스트(digest)에 묶고, 그 위에 영수증(receipt)을 서명합니다.
Then it binds the whole meaning of the action into one digest, and signs a receipt over it.
// 승인 서비스 / authorization service
const fields = deriveActionFields(proposal, witnessedTerms, selection);
const digest = sha256(canonicalize(fields)); // RFC 8785 직렬화 / RFC 8785 serialization
await reserveAtomically(allocation, ceiling); // 어떤 시도보다도 먼저 / before any attempt
const receipt = signReceipt({
decision: 'allow',
digest, // 결합(binding) / the binding
policyVersion,
expiresAt: now() + SHORT_TTL
});
행동의 의미 전체에 대한 하나의 결합입니다. 결합된 요소 중 어느 하나라도 바꾸면 다이제스트가 달라집니다.
One binding, over the whole meaning of the action. Alter any bound element and the digest differs.
여전히 거부할 수 있는 서명자 / The signer that can still say no
에이전트에게는 영수증이 있습니다. 이제 서명이 필요합니다. 그리고 여기서 이 아키텍처는 사람들을 놀라게 하는 일을 합니다:
The agent has a receipt. It needs a signature. And here the architecture does something that surprises people:
행동을 승인한 구성 요소는 그것에 서명할 수 없습니다. 서명하는 구성 요소는 여전히 거부할 수 있습니다.
The component that approved the action cannot sign it. The component that signs it can still refuse.
// 정책을 인식하는 서명 서비스 / policy-aware signing service
async function sign(request) {
const payload = parseStructuredPayload(request); // 서명할 내용을 읽을 수 있음 / it can read what it signs
const params = recoverConsequentialParameters(payload);
if (!withinOwnConstraints(params)) {
return refuse('constraint_violation'); // 게이트가 승인했더라도 / even though the gate approved
}
return signWithNonExportableKey(payload);
}
불투명한 다이제스트에 그대로 서명하는 수탁(custody) 서비스는 의미에 관해 아무것도 집행하지 못합니다. 데이터 덩어리를 건네받기만 해서는, 판단을 내릴 근거가 전혀 없습니다. 이 서명 서비스는 먼저 페이로드를 파싱하고, 실제로 중요한 파라미터들을 복원한 뒤, 자신의 제약을 적용합니다. 그래서 승인 게이트가 이미 승인한 행동도 거부할 수 있습니다.
A custody service that signs an opaque digest enforces nothing about meaning. Handed a blob, it has no basis on which to form an opinion at all. This one parses the payload first, recovers the parameters that actually matter, and applies its own constraints. It can refuse an action the authorization gate already approved.
한편 게이트는 키를 전혀 갖고 있지 않습니다. 서명을 만들어낼 능력이 없습니다. 이는 실수로 설정을 바꿔 없애 버릴 수 있는 정책 선택이 아닙니다. 누가 무엇을 보유하는가에서 나오는 속성입니다.
Meanwhile the gate holds no key whatsoever. It is incapable of producing a signature. That is not a policy choice you can accidentally configure away. It is a property of who holds what.
이 분리가 로드맵과 부딪혀도 살아남는 데에는 따분한 이유가 하나 있는데, 보안 논거보다 엔지니어를 더 빨리 설득합니다. 키를 무엇에 쓸 수 있는지에 관한 규칙과 정책이 무엇을 허용하는지에 관한 규칙은, 서로 다른 이유로 서로 다른 속도로 바뀌며, 서로 다른 팀이 소유합니다. 둘을 한 구성 요소에 두면, 정책을 바꿀 때마다 키를 보관하는 구성 요소를 건드려야 합니다. 아무도 그런 것을 원하지 않습니다.
There is a boring reason this split survives contact with a roadmap, and it persuades engineers faster than the security argument: the rules about what a key may be used for and the rules about what policy permits change at different rates, for different reasons, owned by different teams. Putting them in one component means every policy change touches the thing holding your keys. Nobody wants that.
그리고 거부됩니다 / And then it gets refused
서명된 요청이 출구로 향합니다. 영수증은 유효합니다. 서명도 검증됩니다.
The signed request heads for the exit. The receipt is valid. The signature verifies.
그리고 경계는 그 요청을 거부합니다.
And the boundary refuses it.
그 이유는 다음과 같으며, 설계 전체에서 가장 중요한 한 줄입니다:
Here is why, and it is the single most important line in the whole design:
게이트웨이는 영수증에서 다이제스트를 읽어 오지 않습니다. 실제로 나가는 바이트에서 다이제스트를 다시 만듭니다.
The gateway does not read the digest out of the receipt. It rebuilds it from the bytes that are actually leaving.
// 집행 게이트웨이, 송신 경로 / enforcement gateway, egress path
async function release(outgoing, receipt) {
if (!verifySignature(receipt)) return failClosed('bad_receipt');
if (expired(receipt)) return failClosed('expired_receipt');
// 영수증이 아니라, 실제로 나갈 요청에서 다시 도출합니다.
// RFC 8785는 직렬화 방식을 고정하고, 양쪽이 기준으로 삼아 구현하는
// 규범적 규칙이 어떤 필드가 참여하는지를 고정합니다.
// Re-derive from the request that will actually leave, not from the receipt.
// RFC 8785 fixes the serialization; a normative rule both sides build
// against fixes which fields participate.
const rebuilt = canonicalize(deriveActionFields(outgoing));
if (sha256(rebuilt) !== receipt.digest) {
return failClosed('digest_mismatch'); // 바꿔치기되었거나, 승인 이후 변경됨 / substituted, or altered after approval
}
// 유효한 영수증은 필요조건이지, 충분조건이 아닙니다.
// A valid receipt is necessary, not sufficient.
const verdict = await policy.evaluate(deriveActionFields(outgoing));
if (!verdict.allow) return failClosed(verdict.reason);
return forward(translateAudience(outgoing));
}
서로 독립적인 두 의견이 일치해야 합니다. 하나는 승인 시점에 제안(proposal)으로부터 형성되었고, 다른 하나는 이 자리에서 실제로부터 형성됩니다. 결정 을 검증하는 것은 그 결정의 대상 을 검증하는 것과 같지 않으며, 이를 잘못 구현하는 시스템은 거의 모두 바로 이 지점에서 잘못합니다.
Two independent opinions have to agree. One was formed at approval time, from the proposal; the other is formed here, from reality. Verifying a decision is not the same as verifying the thing the decision was about, and almost every system that gets this wrong gets it wrong right here.
불일치가 양쪽 방향을 모두 잡아낸다는 점에 주목하세요. 더 비싼 리소스로 바꿔치기하는 것은 예산 실패입니다. 더 싼 리소스로 바꿔치기하면, 규제 대상 데이터를 승인되지 않은 곳으로 보낼 수 있습니다. 같은 불일치이고, 같은 거부입니다.
Notice what a mismatch catches in both directions. Substituting to a more expensive resource is a budget failure. Substituting to a cheaper one can send regulated data somewhere not approved for it. Same mismatch, same refusal.
그리고 모든 경로에 있는 failClosed 에 주목하세요. 필요한 검증을 끝마칠 수 없으면 요청은 거부됩니다. 답하지 못한 검증기를 허락한 검증기로 취급하는 일은 결코 없습니다.
And notice
failClosedon every path. Where required verification cannot be completed, the request is denied. A verifier that cannot answer is never treated as one that said yes.
정산하기 / Settling up
요청이 통과하면, 마무리는 의도적으로 수수합니다. 에이전트는 가치 이전 승인에 서명하지만, 아무것도 제출하지 않습니다. 퍼실리테이터(facilitator)가 그것을 제출하고 실행 수수료를 부담하므로, 워크로드는 어떤 종류, 어떤 자산의 로컬 잔고도 필요하지 않습니다. 그런 다음 하나의 추적 식별자(trace identifier)가 신원 주체, 서명 요청, 논스(nonce), 정산 기록을 함께 묶어, 완료된 행동을 전적으로 에이전트 바깥 에 보관된 증거만으로 처음부터 끝까지 재구성할 수 있게 합니다.
When a request does pass, the ending is deliberately unglamorous. The agent signs the value authorization but submits nothing; a facilitator submits it and bears the execution fee, so the workload needs no local balance of any kind, of any asset. Then one trace identifier binds the identity subject, the signing request, the nonce and the settlement record together, so a completed action can be reconstructed end to end from evidence held entirely outside the agent.
어느 방향으로도 에이전트를 신뢰할 필요가 없습니다. 그것이 핵심입니다.
Neither direction requires trusting it. That is the point.
이제 각 단계가 무엇을 방어하는지 알았으니, 전체 경로를 한 번에 살펴보겠습니다:
Here is the whole path, once, now that you know what each step is defending against:
무대에서 배운 것 / What the stage taught us
사람들 앞에서 실제로 실행해 보기 전까지는 제대로 알지 못했던 세 가지입니다.
Three things we did not fully appreciate until it was running in front of people.
거부가 곧 데모입니다. 성공 경로와 거부 경로를 모두 준비했지만, 성공 경로를 더 열심히 연습했습니다. 거꾸로였습니다. 인가 아키텍처가 가장 설득력 있는 순간은 아무 일도 일어나지 않는 순간입니다. 영수증은 유효하고, 서명도 문제가 없는데, 요청은 여전히 나가지 않습니다. 이런 구조를 시연한다면, 무대 시간을 거부 장면에 배정하세요.
The refusal is the demo. We prepared a success path and a denial path and rehearsed the success path harder. That was backwards. An authorization architecture is most convincing at the moment nothing happens. The receipt is valid, the signature is good, and the request still does not leave. If you demo one of these, budget your stage time for the refusal.
정규화(canonicalization)의 결정성은 세부 사항이 아니라 설계 그 자체입니다. 독립적인 두 도출은 서로 일치할 때에만 도움이 됩니다. RFC 8785는 어떻게 직렬화할지는 정하지만, 어떤 필드가 참여하는지 는 정하지 않습니다. 이 질문에 남겨 둔 모든 모호함은 미래의 장애가 되며, 원인을 알 수 없는 거부로 나타났다가 세 계층 떨어진 곳에서야 해결됩니다. 필드 구성 규칙은 양쪽이 각자 산문을 읽고 다시 구현하는 동작으로 두지 말고, 양쪽이 기준으로 삼아 구현하는 규범적 산출물(normative artifact)로 작성해 두세요.
Canonicalization determinism is not a detail, it is the design. Two independent derivations only help if they agree. RFC 8785 fixes how to serialize; it does not fix which fields participate. Every ambiguity you leave in that question becomes a future incident that presents as a mysterious denial and resolves three layers away. Write the membership rule down as a normative artifact both sides build against, not as behaviour each side reimplements from prose.
도달할 수 있다는 것이 권한은 아닙니다. 이 흐름의 에이전트는 다른 클라이언트와 마찬가지로 일반 API를 통해 승인 서비스를 호출합니다. 다만 자신의 한도를 옮길 수 없을 뿐입니다. 승인 서비스에 닿을 수 없는 에이전트는 격리된(isolated) 것이고, 닿을 수는 있지만 여전히 답을 바꿀 수 없는 에이전트는 통제되는(governed) 것입니다. 둘은 매우 다른 시스템이며, 그중 쓸모 있는 것은 하나뿐입니다.
Reachability is not authority. The agent in this flow calls the authorization service over an ordinary API, like any client. It simply cannot move its own limit. An agent that cannot reach the authorization service is isolated; an agent that reaches it and still cannot change the answer is governed. Those are very different systems and only one of them is useful.
x402 v2도, MCP 2026-07-28도 지출 결정을 대신 내려주지 않습니다. 두 사양은 가격을 보이게 하고 라우팅을 저렴하게 만들 뿐입니다. 권한을 어디에 둘지는 여전히 여러분이 정해야 하며, 그 배치는 두 프로토콜보다 오래 남을 것입니다.
Neither x402 v2 nor MCP 2026-07-28 makes the spending decision for you. They make the price visible and the routing cheap. Where the authority sits is still yours to place, and that placement will outlive both protocols.
AAIF 글에는 전체 논증과, 유료 도구 서버가 호출자에게 지켜야 할 다섯 가지 의무가 정리되어 있습니다.
The AAIF post has the full argument and the five obligations a paid tool server owes its callers.
코드는 설명을 위한 것이며, 논의 중인 검사만 남기고 축약했습니다.
Code is illustrative and abbreviated to the checks under discussion.
특허 출원 중(Patent pending). 미국 특허 가출원(U.S. Provisional Application) 번호 64/149,249, 2026년 9월 6일 출원 (docket Y26S008-PPA)
Patent pending. U.S. Provisional Application No. 64/149,249, filed 6 September 2026 (docket Y26S008-PPA)
이 글은 GPT 모델로 정리한 초안을 바탕으로 한 것으로, 원문의 내용 또는 의도와 다르게 정리된 내용이 있을 수 있습니다. 관심있는 내용이시라면 원문도 함께 참고해주세요! 읽으시면서 어색하거나 잘못된 내용을 발견하시면 댓글로 알려주시기를 부탁드립니다. ![]()
파이토치 한국 사용자 모임
에서 이런 글들을 계속 정리하고 있습니다. 회원 가입으로 주요 글들을 이메일
로, 텔레그램(Telegram)이나 Slack/Discord/Teams/Dooray/GoogleChat 등으로 새 글 알림을 받아보세요! ![]()
아래
쪽에 좋아요
를 눌러주시면 새로운 소식들을 정리하고 공유하는데 힘이 됩니다~ ![]()



