# 서비스 키트

@shard-lab/agentpay-service-kit의 주요 공개 API 스냅샷.

`@shard-lab/agentpay-service-kit`의 주요 공개 API 선언 스냅샷입니다. 루트(`@shard-lab/agentpay-service-kit`)에서 모두 가져올 수 있고, 하위 경로(`/intent` 등)로 나눠 가져와도 됩니다.

**생성 기준**
agent-pay `7489776`에서 만들었습니다. 설명은 소스의 영어 주석입니다.

## 서비스 MCP · `/service`

### createMerchantClient

function · service.d.mts

Signed calls from a service to the gateway.

```ts
function createMerchantClient(gatewayUrl: string): MerchantClient;
```

### startServiceMcp

function · service.d.mts

Starts a service MCP: /mcp, /intents/, /agentpay/mandates, /.well-known/agentpay-service, /health.

```ts
function startServiceMcp({ id, name, version, port, bind, publicUrl, gatewayUrl, instructions, tools, callTool, routes, onMandate, allowedOrigins, log }: ServiceMcpOptions): ServiceMcp;
```

### Intent

type · service.d.mts

```ts
type Intent = import("./intent.mjs").Intent;
```

### Call

type · service.d.mts

```ts
type Call = import("./intent.mjs").Call;
```

### ToolDef

type · service.d.mts

```ts
type ToolDef = import("./mcp.mjs").ToolDef;
```

### CallTool

type · service.d.mts

```ts
type CallTool = import("./mcp.mjs").CallTool;
```

### MandateCredential

type · service.d.mts

Delivered by the gateway server to server when the user approves a mandate that allows merchant charges.
Store it like a card token: it can charge only inside that one mandate.

```ts
type MandateCredential = {
    mandate_id: string;
    credential_id: string;
    secret: string;
};
```

### GatewayReply

type · service.d.mts

```ts
type GatewayReply = {
    http: number;
    error?: string;
    message?: string;
    [k: string]: any;
};
```

### MerchantClient

type · service.d.mts

```ts
type MerchantClient = {
    /**
     * Reads the live mandate (status, remaining, runs).
     */
    mandate: (cred: MandateCredential) => Promise<GatewayReply>;
    /**
     * Runs one charge inside the mandate. The same `charge_id` runs at most once (a replay returns the first result).
     */
    charge: (cred: MandateCredential, charge: {
        charge_id: string;
        summary: string;
        spend_okrw: number;
        calls: Call[];
    }) => Promise<GatewayReply>;
    /**
     * Gives up the mandate (stops charges at once).
     */
    release: (cred: MandateCredential, reason?: string) => Promise<GatewayReply>;
};
```

### IntentInput

type · service.d.mts

```ts
type IntentInput = Omit<Intent, "type" | "version" | "id" | "service" | "expires_at" | "calls" | "spend_okrw"> & {
    calls?: Call[];
    spend_okrw?: number;
};
```

### BuiltIntent

type · service.d.mts

```ts
type BuiltIntent = {
    intent_id: string;
    intent_url: string;
    intent: Intent & {
        created_at: number;
    };
};
```

### ServiceMcpOptions

type · service.d.mts

```ts
type ServiceMcpOptions = {
    /**
     * Service id as registered with the tenant (`[a-z0-9-]`, 2..40).
     */
    id: string;
    /**
     * Display name.
     */
    name: string;
    version?: string;
    port: number;
    /**
     * Default 127.0.0.1. Use 0.0.0.0 in a container.
     */
    bind?: string;
    /**
     * The registered origin (https in production). Intent URLs are built from it.
     */
    publicUrl?: string;
    /**
     * Needed for merchant charges.
     */
    gatewayUrl?: string;
    /**
     * MCP server instructions for the agent.
     */
    instructions?: string;
    tools: ToolDef[] | (() => ToolDef[]);
    callTool: CallTool;
    /**
     * Extra HTTP routes. Return undefined to fall through to 404.
     */
    routes?: (req: import("node:http").IncomingMessage, res: import("node:http").ServerResponse, url: URL, helpers: {
        json: Function;
        readJson: Function;
    }) => Promise<unknown>;
    /**
     * Receives a confirmed mandate credential. Throw to refuse it.
     */
    onMandate?: (delivery: {
        credential: MandateCredential;
        intentId: string;
        mandate: GatewayReply;
    }) => void | Promise<void>;
    /**
     * Browser origins allowed to call /mcp.
     */
    allowedOrigins?: string[];
    log?: (...a: unknown[]) => void;
};
```

### ServiceMcp

type · service.d.mts

```ts
type ServiceMcp = {
    /**
     * Builds an intent and serves it at `<publicUrl>/intents/<id>` for 15 minutes.
     */
    intent: (body: IntentInput) => BuiltIntent;
    merchant: MerchantClient | undefined;
    server: import("node:http").Server;
    ready: Promise<void>;
    base: string;
    close: () => Promise<void>;
};
```

## intent와 권한 · `/intent`

### compileScope

function · intent.d.mts

Compiles a mandate to the scope the gateway checks calls against.

```ts
function compileScope(mandate: Mandate, { asset, unit }: {
    asset: AssetRef;
    unit: bigint;
}): Scope;
```

### callAllowed

function · intent.d.mts

```ts
function callAllowed(scope: Scope, call: Call): string | undefined;
```

### callsCovered

function · intent.d.mts

```ts
function callsCovered(scope: Scope, calls: Call[]): {
    ok: true;
} | {
    ok: false;
    reason: string;
    index: number;
};
```

### validateIntent

function · intent.d.mts

```ts
function validateIntent(raw: unknown, { service, asset, unit, now }: {
    service: ServiceRef;
    asset: AssetRef;
    unit: bigint;
    now: number;
}): Intent;
```

### validateCharge

function · intent.d.mts

```ts
function validateCharge(b: unknown): ChargeRequest;
```

### word

function · intent.d.mts

```ts
function word(v: bigint | number | string): Hex;
```

### selectorOf

function · intent.d.mts

```ts
function selectorOf(signature: string): Hex;
```

### mandateDigest

function · intent.d.mts

```ts
function mandateDigest(mandate: Mandate): Hex;
```

### periodWindow

function · intent.d.mts

```ts
function periodWindow(validAfter: number, seconds: number, at: number): {
    index: number;
    start: number;
    end: number;
};
```

### INTENT_TYPE

const · intent.d.mts

The `type` every intent carries.

```ts
const INTENT_TYPE: "agentpay.intent";
```

### MAX_INTENT_BYTES

const · intent.d.mts

Largest intent JSON the gateway accepts.

```ts
const MAX_INTENT_BYTES: number;
```

### APPROVE_SELECTOR

const · intent.d.mts

```ts
const APPROVE_SELECTOR: "0x095ea7b3";
```

### FULL_MASK

const · intent.d.mts

```ts
const FULL_MASK: string;
```

### IntentError

class · intent.d.mts

Thrown by the validators. `code` is a stable machine code (e.g. `CONTRACT_NOT_REGISTERED`), `why` the detail.

```ts
class IntentError extends Error {
    /** @param {string} why @param {string} [code] */
    constructor(why: string, code?: string);
    code: string;
    why: string;
}
```

### Hex

type · intent.d.mts

```ts
type Hex = `0x${string}`;
```

### Call

type · intent.d.mts

One contract call. `value` must be "0" (payments use the ERC-20 payment asset).

```ts
type Call = {
    target: string;
    value?: string;
    data: string;
};
```

### Predicate

type · intent.d.mts

A condition on one 32-byte argument (`arg` is the zero-based argument index). Give exactly one value kind:
`okrw` (whole payment-asset units, scaled by the asset decimals), `uint`, `bytes32` or `address`.

```ts
type Predicate = {
    arg: number;
    op: "eq" | "lte";
    okrw?: number;
    uint?: string;
    bytes32?: string;
    address?: string;
};
```

### Permission

type · intent.d.mts

One function the mandate allows on one registered contract, e.g. `deposit(uint256)`.

```ts
type Permission = {
    target: string;
    name?: string;
    signature: string;
    predicates: Predicate[];
};
```

### Period

type · intent.d.mts

Fixed windows from `valid_after` (V4 period limits). At least one of `max_runs` or `max_spend_okrw`.

```ts
type Period = {
    seconds: number;
    max_runs?: number;
    max_spend_okrw?: number;
};
```

### MandateUpdate

type · intent.d.mts

```ts
type MandateUpdate = {
    add_total_okrw?: number;
    add_calls?: number;
    add_days?: number;
    per_okrw?: number;
};
```

### IntentAction

type · intent.d.mts

```ts
type IntentAction = "purchase" | "mandate" | "mandate.update";
```

### ServiceRef

type · intent.d.mts

```ts
type ServiceRef = {
    id: string;
    contracts: string[];
    merchantCharges?: boolean;
};
```

### AssetRef

type · intent.d.mts

```ts
type AssetRef = {
    address: string;
};
```

### ChargeRequest

type · intent.d.mts

A merchant-initiated charge (the user is not present).

```ts
type ChargeRequest = {
    mandate_id: string;
    charge_id: string;
    summary: string;
    spend_okrw: number;
    calls: Call[];
};
```

### Mandate

type · intent.d.mts

The scope and limits the user approves once. The wallet contract enforces the same limits on chain.

```ts
type Mandate = {
    /**
     * Stable id within the service. Must start with `<service id>:` (e.g. `acme:plan`).
     */
    key: string;
    /**
     * Short label shown on the approval screen.
     */
    label: string;
    /**
     * Total the mandate may spend.
     */
    total_okrw: number;
    /**
     * Most one run may spend.
     */
    per_okrw: number;
    /**
     * Most one payment-token `approve` inside a run may allow.
     */
    approve_cap_okrw: number;
    /**
     * Number of runs (default 100, 1..1000).
     */
    calls?: number;
    /**
     * Validity in days (default 30, 1..365).
     */
    days?: number;
    /**
     * Unix seconds the mandate starts (reservations).
     */
    valid_after?: number;
    /**
     * Whether the service may charge later without the agent (needs a registry opt-in).
     */
    merchant_charges?: boolean;
    /**
     * Per-window limits.
     */
    period?: Period;
    /**
     * Display names of the places the service may pick.
     */
    venues?: string[];
    /**
     * 1..16 functions on contracts registered to the service.
     */
    permissions: Permission[];
};
```

### Intent

type · intent.d.mts

What a service asks the wallet to run. Served as JSON at an absolute URL on the service's registered origin.

```ts
type Intent = {
    type: "agentpay.intent";
    version: 1;
    /**
     * `int_` + 8..64 url-safe characters.
     */
    id: string;
    /**
     * The service id. Must match the origin the intent was fetched from.
     */
    service: string;
    action: IntentAction;
    /**
     * One line for the user, up to 160 characters.
     */
    summary: string;
    /**
     * What the calls spend now.
     */
    spend_okrw: number;
    /**
     * Balance the wallet should hold for this mandate (top-up hint).
     */
    prefund_okrw?: number;
    /**
     * Unix seconds, at most one hour ahead.
     */
    expires_at: number;
    /**
     * Calls to run now (0..8). They must already fit the mandate.
     */
    calls: Call[];
    mandate: Mandate | {
        key: string;
    };
    /**
     * For `mandate.update` only.
     */
    update?: MandateUpdate;
};
```

### Scope

type · intent.d.mts

A mandate compiled to the wallet policy's own terms (target, selector, argument predicates).

```ts
type Scope = {
    asset: string;
    approveCapWei: string;
    spenders: string[];
    permissions: Array<{
        target: string;
        name?: string;
        signature: string;
        selector: Hex;
        predicates: Array<{
            offset: number;
            operator: string;
            mask: string;
            expected: string;
        }>;
    }>;
};
```

## 청구 서명 · `/auth`

### newCredentialId

function · auth.d.mts

```ts
function newCredentialId(): string;
```

### deriveSecret

function · auth.d.mts

Gateway side: the credential secret, derived (never stored).

```ts
function deriveSecret(masterKey: string | Buffer, credentialId: string): string;
```

### signRequest

function · auth.d.mts

Service side: the Authorization header for one request to the gateway.

```ts
function signRequest({ credentialId, secret, method, path, body, ts }: {
    credentialId: string;
    secret: string;
    method: string;
    path: string;
    body?: string;
    ts?: number;
}): string;
```

### verifyRequest

function · auth.d.mts

Gateway side: checks a signed request.

```ts
function verifyRequest(header: string | undefined, { masterKey, method, path, body, now, maxSkew }: {
    masterKey: string | Buffer;
    method: string;
    path: string;
    body?: string;
    now?: number;
    maxSkew?: number;
}): {
    ok: true;
    credentialId: string;
} | {
    ok: false;
    code: "CREDENTIAL_REQUIRED" | "REQUEST_EXPIRED" | "BAD_SIGNATURE";
};
```

### SCHEME

const · auth.d.mts

The Authorization scheme of a signed service request.

```ts
const SCHEME: "AgentPay-Mandate-HMAC";
```

### MAX_SKEW_SECONDS

const · auth.d.mts

```ts
const MAX_SKEW_SECONDS: 300;
```

## MCP 전송 · `/mcp`

### checkArgs

function · mcp.d.mts

```ts
function checkArgs(schema: InputSchema | undefined, args: unknown): string | undefined;
```

### createMcpHttp

function · mcp.d.mts

Streamable HTTP MCP handler. Mount `handle` on your own HTTP server at `/mcp`.

```ts
function createMcpHttp({ serverInfo, instructions, tools, callTool, authenticate, onUnauthorized, allowedOrigins, maxSessions, sessionTtlMs, keepAliveMs, log }: {
    serverInfo: ServerInfo;
    instructions?: string;
    tools: ToolDef[] | (() => ToolDef[]);
    callTool: CallTool;
    authenticate?: (req: import("node:http").IncomingMessage) => unknown | Promise<unknown>;
    onUnauthorized?: (res: import("node:http").ServerResponse) => void;
    allowedOrigins?: string[];
    maxSessions?: number;
    sessionTtlMs?: number;
    keepAliveMs?: number;
    log?: (...a: unknown[]) => void;
}): {
    handle(req: import("node:http").IncomingMessage, res: import("node:http").ServerResponse): Promise<void>;
    sessions: Map<string, unknown>;
};
```

### serveStdio

function · mcp.d.mts

The same tools over stdio (one client). Reads JSON-RPC lines from stdin, writes to stdout.

```ts
function serveStdio({ serverInfo, instructions, tools, callTool, onInitialize, log }: {
    serverInfo: ServerInfo;
    instructions?: string;
    tools: ToolDef[] | (() => ToolDef[]);
    callTool: CallTool;
    onInitialize?: (info: {
        caps: Record<string, unknown>;
        clientName?: string;
        clientInfo?: unknown;
    }) => void | Promise<void>;
    log?: (...a: unknown[]) => void;
}): {
    ui: Ui;
    clientName(): string | undefined;
    caps(): Record<string, unknown>;
};
```

### mcpHttpClient

function · mcp.d.mts

Minimal Streamable HTTP client for tests and service-to-service checks.

```ts
function mcpHttpClient(url: string, { token, onElicit, clientInfo, elicitation }?: {
    token?: string;
    onElicit?: (message: string) => Promise<"accept" | "decline" | "cancel">;
    clientInfo?: {
        name: string;
        version: string;
    };
    elicitation?: boolean;
}): Promise<McpClient>;
```

### PROTOCOL_VERSIONS

const · mcp.d.mts

MCP protocol versions this server speaks, newest first.

```ts
const PROTOCOL_VERSIONS: string[];
```

### McpClient

type · mcp.d.mts

```ts
type McpClient = {
    /**
     * The initialize result.
     */
    init: Record<string, any>;
    sessionId: () => string | null;
    rpc: (method: string, params?: unknown) => Promise<{
        response: any;
        headers: Headers;
        events: any[];
    }>;
    tools: () => Promise<ToolDef[]>;
    /**
     * Parsed JSON result of one tool.
     */
    call: (name: string, args?: Record<string, unknown>) => Promise<any>;
    close: () => Promise<void>;
};
```

### InputSchema

type · mcp.d.mts

The JSON Schema subset tool arguments are checked against (type, required, enum, range, maxLength).

```ts
type InputSchema = {
    type: "object";
    properties?: Record<string, {
        type?: string;
        description?: string;
        enum?: unknown[];
        minimum?: number;
        maximum?: number;
        maxLength?: number;
    }>;
    required?: string[];
    additionalProperties?: boolean;
};
```

### ToolDef

type · mcp.d.mts

```ts
type ToolDef = {
    name: string;
    title?: string;
    description: string;
    inputSchema: InputSchema;
    annotations?: Record<string, unknown>;
};
```

### ServerInfo

type · mcp.d.mts

```ts
type ServerInfo = {
    name: string;
    title?: string;
    version: string;
};
```

### Prompt

type · mcp.d.mts

```ts
type Prompt = {
    answer: Promise<string>;
    cancel(): void;
};
```

### Ui

type · mcp.d.mts

Prompts the user through the agent app (MCP elicitation). `canPrompt` is false when the client cannot show one.

```ts
type Ui = {
    canPrompt: boolean;
    showLink(message: string): Prompt;
    ask?(message: string, timeoutMs?: number): Promise<string>;
};
```

### ToolContext

type · mcp.d.mts

```ts
type ToolContext = {
    principal: unknown;
    session: {
        caps?: Record<string, unknown>;
        clientName?: string;
    };
    ui: Ui;
    signal?: AbortSignal;
};
```

### CallTool

type · mcp.d.mts

Runs one tool. Return a JSON-able object; `{ error: "CODE", message }` marks the result as an error.

```ts
type CallTool = (name: string, args: Record<string, any>, ctx: ToolContext) => unknown | Promise<unknown>;
```

## 레지스트리 · `/registry`

### originOf

function · registry.d.mts

```ts
function originOf(url: string): string;
```

### loadRegistry

function · registry.d.mts

```ts
function loadRegistry(path: string, env?: Record<string, string | undefined>): Registry;
```

### serviceByUrl

function · registry.d.mts

The service whose registered origin serves `url`.

```ts
function serviceByUrl(reg: Registry, url: string): RegistryService | undefined;
```

### contractByAddress

function · registry.d.mts

```ts
function contractByAddress(reg: Registry, address: string): any;
```

### serviceById

function · registry.d.mts

```ts
function serviceById(reg: Registry, id: string): RegistryService | undefined;
```

### RegistryService

type · registry.d.mts

```ts
type RegistryService = {
    id: string;
    name: string;
    /**
     * scheme + host + port the service serves intents from.
     */
    origin: string;
    mcp: string;
    merchantCharges: boolean;
    /**
     * Lowercase addresses.
     */
    contracts: string[];
};
```

### Registry

type · registry.d.mts

```ts
type Registry = {
    asset: {
        address: string;
        symbol: string;
        decimals: number;
        type?: string;
    };
    shops?: any[];
    finance?: any;
    services: RegistryService[];
    [k: string]: any;
};
```

## 테스트 · `/testing`

### startTestGateway

function · testing.d.mts

```ts
function startTestGateway({ service, asset, port }: {
    service: {
        id: string;
        origin: string;
        contracts: string[];
        merchantCharges?: boolean;
    };
    asset?: {
        address: string;
        decimals?: number;
    };
    port?: number;
}): Promise<TestGateway>;
```

### Intent

type · testing.d.mts

```ts
type Intent = import("./intent.mjs").Intent;
```

### Mandate

type · testing.d.mts

```ts
type Mandate = import("./intent.mjs").Mandate;
```

### TestMandate

type · testing.d.mts

```ts
type TestMandate = {
    mandate_id: string;
    service: string;
    intent_id: string;
    key: string;
    label: string;
    status: "active" | "released" | "revoked" | "expired";
    valid_after: number;
    valid_until: number;
    per_okrw: number;
    total_okrw: number;
    remaining_okrw: number;
    calls_left: number;
    period?: import("./intent.mjs").Period;
    runs: Array<{
        charge_id?: string;
        summary: string;
        spend_okrw: number;
        by: "agent" | "service";
        run_at: number;
    }>;
};
```

### TestGateway

type · testing.d.mts

```ts
type TestGateway = {
    /**
     * Pass this as the service's `gatewayUrl`.
     */
    url: string;
    /**
     * Fetches and validates an intent from the service's origin, approves its mandate, runs its calls, and (when the
     * mandate allows merchant charges) delivers a credential to `<origin>/agentpay/mandates`.
     */
    approve: (intentUrl: string) => Promise<{
        mandate_id: string;
        intent: Intent;
        ran: boolean;
        credential_delivered: boolean;
    }>;
    mandate: (mandateId: string) => TestMandate | undefined;
    /**
     * The user turns the mandate off.
     */
    revoke: (mandateId: string) => void;
    /**
     * Moves the gateway clock forward for mandates (period windows, expiry).
     */
    advance: (seconds: number) => void;
    close: () => Promise<void>;
};
```
