@stellar-agent-services/dev-mcp 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -2
  3. package/dist/docs.d.ts +35 -0
  4. package/dist/docs.d.ts.map +1 -0
  5. package/dist/docs.js +92 -0
  6. package/dist/docs.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +6 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/server.d.ts +14 -0
  12. package/dist/server.d.ts.map +1 -0
  13. package/dist/server.js +125 -0
  14. package/dist/server.js.map +1 -0
  15. package/package.json +40 -4
  16. package/repository/AGENTS.md +162 -0
  17. package/repository/CONTRIBUTING.md +95 -0
  18. package/repository/IMPLEMENTATION_PLAN.md +560 -0
  19. package/repository/README.md +80 -0
  20. package/repository/SECURITY.md +22 -0
  21. package/repository/apps/wallet/README.md +78 -0
  22. package/repository/docs/client-integration/README-AI.md +495 -0
  23. package/repository/docs/client-integration/README.md +138 -0
  24. package/repository/docs/dx-improvements.md +670 -0
  25. package/repository/docs/erc-compatibility.md +163 -0
  26. package/repository/docs/job-recovery.md +201 -0
  27. package/repository/docs/payment-client.md +290 -0
  28. package/repository/docs/provider-setup-guide.md +348 -0
  29. package/repository/docs/provider-standard.md +728 -0
  30. package/repository/docs/recovery/README-AI.md +288 -0
  31. package/repository/docs/recovery/README.md +119 -0
  32. package/repository/docs/sow-closeout.md +67 -0
  33. package/repository/docs/standard/README-AI.md +614 -0
  34. package/repository/docs/standard/README.md +108 -0
  35. package/repository/docs/verification.md +504 -0
  36. package/repository/examples/paid-service/README.md +33 -0
  37. package/repository/examples/python-upstream/README.md +44 -0
  38. package/repository/llms.txt +65 -0
  39. package/repository/packages/create-stellar-service/README.md +143 -0
  40. package/repository/packages/dev-mcp/README.md +51 -0
  41. package/repository/packages/payment-client/README.md +98 -0
  42. package/repository/packages/protocol/README.md +15 -0
  43. package/repository/packages/protocol/schemas/manifest.schema.json +272 -0
  44. package/repository/packages/protocol/test-vectors/README.md +45 -0
  45. package/repository/packages/provider-kit/README.md +509 -0
  46. package/repository/packages/provider-kit/schemas/gateway-config.schema.json +140 -0
  47. package/repository/packages/verifier/README.md +131 -0
  48. package/repository/plugins/stellar-agent-services/README.md +31 -0
@@ -0,0 +1,348 @@
1
+ # Provider setup guide
2
+
3
+ This guide takes you from an idea or an existing API to a paid AI service on Stellar that any client can find,
4
+ pay in USDC and recover jobs from, following [Provider Standard v1](provider-standard.md). It uses Stellar
5
+ **testnet** throughout.
6
+
7
+ You never give the provider a Stellar secret key. It knows only the public address it is paid to (`payTo`); an
8
+ x402 facilitator verifies and settles payments. Your own wallet is the payout account, and you need it only when the
9
+ service goes live: until then, test payments go to a throwaway testnet account. Going live is one page in your
10
+ wallet, which `provider-kit launch` opens on your computer. No key is ever exported, imported or stored by the kit,
11
+ and the income lands in the wallet you already use.
12
+
13
+ ## Quick start
14
+
15
+ ```bash
16
+ npm create stellar-service my-service
17
+ cd my-service
18
+ npm run dev # runs it here, paid to a throwaway testnet account: no wallet needed yet
19
+ npm run try # pays for one call with test money, from another terminal
20
+ npm run launch # goes live: one approval in your wallet, then Fly.io
21
+ npm run status # where it stands, and what to run next
22
+ ```
23
+
24
+ The rest of this guide is what those commands do, and how to do each step yourself.
25
+
26
+ ## 1. Pick a path
27
+
28
+ | Path | Choose it when | You write |
29
+ | --- | --- | --- |
30
+ | **Gateway** | You already have an HTTP API, in any language | A JSON config file |
31
+ | **TypeScript library** | You are writing a new service in TypeScript | A `defineService(...)` per service |
32
+ | **Native** | You want no dependency on the kit | The standard, in your own stack ([provider-standard.md](provider-standard.md)) |
33
+
34
+ Both kit paths give you the same things: the manifest, the `402` challenge, payment checks, job recovery,
35
+ capacity limits and a job store that survives restarts.
36
+
37
+ **Fastest start:** `npm create stellar-service` makes a project for either kit path, or a new Python service behind
38
+ the gateway, with the scripts above, a Dockerfile and `fly.toml` ([create-stellar-service](../packages/create-stellar-service)).
39
+
40
+ ## 2. Prerequisites
41
+
42
+ - **Node.js 22.13 or later** for the library and the CLI, or **Docker** for the gateway.
43
+ - **The kit.** A project made by `npm create stellar-service` has it already, and `npm run <script>` runs its
44
+ commands. Otherwise, `npm install @stellar-agent-services/provider-kit` in your project, and run the `provider-kit`
45
+ commands below as `npx provider-kit`. Add the override from the
46
+ [provider-kit README](../packages/provider-kit/README.md) to its `package.json`. The gateway image is
47
+ `ghcr.io/algorialabs/provider-kit`.
48
+
49
+ - **A Stellar wallet, to go live** (§7): the one you already use, such as Freighter, xBull, Albedo, Rabet, Hana,
50
+ MetaMask or a Ledger ([Stellar Wallets Kit](https://stellarwalletskit.dev) lists them). Its account becomes your
51
+ payout account, `payTo`. Tip: add a second account in the same wallet just for the service. You don't need it to
52
+ build and try the service.
53
+
54
+ ## 3a. Gateway: an existing API
55
+
56
+ Your API needs one endpoint per service that takes the input as a JSON body (`POST`) and answers with a JSON
57
+ object. It needs to know nothing about payments.
58
+
59
+ **If your API has an OpenAPI document**, start from it. FastAPI serves one at `/openapi.json`; Django
60
+ (drf-spectacular), Spring, NestJS and most frameworks can write one:
61
+
62
+ ```bash
63
+ provider-kit init --openapi http://127.0.0.1:8000/openapi.json # or a .json or .yaml file, with --upstream <url>
64
+ ```
65
+
66
+ This writes `provider.config.json` with a service for each `POST` endpoint the gateway can call: its schemas
67
+ (converted to JSON Schema 2020-12), title, description, tags and example come from the document. It lists every
68
+ other operation with the reason it was skipped, such as a path parameter or a file upload, and checks the config as
69
+ `serve` would. If the API needs its own key, it is sent from an environment variable that `init` names. Then
70
+ review the guesses below, starting with the price.
71
+
72
+ **Otherwise**, start from one service and write its schemas yourself:
73
+
74
+ ```bash
75
+ provider-kit init --upstream http://127.0.0.1:5000/run
76
+ ```
77
+
78
+ This writes `provider.config.json`. Edit each service:
79
+
80
+ - `name`, `title` and `description`. Write the description for an agent deciding whether to call you: what it
81
+ does, when to use it and its limits (spec §3.4).
82
+ - `price` in USDC, such as `"0.05"`.
83
+ - `charge`: `"on-success"` charges only if the call succeeds, and suits work that finishes in under half a minute.
84
+ `"upfront"` charges first and suits longer or expensive work (spec §3.2). `init` starts with `on-success`.
85
+ - `expectedDurationSeconds`, and `timeoutSeconds` if the call may take longer than twice that.
86
+ - `inputSchema` and `outputSchema`: JSON Schemas whose root is `"type": "object"`, inline or as file paths. The
87
+ gateway refuses input that doesn't match before anyone pays, and output that doesn't match is a failed job.
88
+ - `examples`: an example input and output. Agents and catalogs show them.
89
+ - `upstream.url`, and `upstream.headers` for your API's own key, written `"env:NAME"` so it stays out of the file.
90
+
91
+ Then run your API and the gateway:
92
+
93
+ ```bash
94
+ provider-kit dev --config provider.config.json
95
+ ```
96
+
97
+ `dev` reads `.env`, and with `PAY_TO` empty it makes a throwaway testnet account to be paid to (§5). `--with
98
+ '<command>'` also starts your API next to the gateway, such as `--with 'uvicorn app:app --port 8000'`, and stops both
99
+ together. The gateway checks the whole config and refuses to start, listing every problem, if something would fail
100
+ the standard. [examples/python-upstream](../examples/python-upstream) is a complete example with a Python API.
101
+
102
+ **With Docker** instead of Node, run the gateway image each release publishes:
103
+
104
+ ```bash
105
+ docker run -p 8787:8787 -e PAY_TO -v "$PWD/provider.config.json:/config/provider.config.json:ro" \
106
+ -v provider-jobs:/data ghcr.io/algorialabs/provider-kit:0.1.0
107
+ ```
108
+
109
+ Set `"store": "/data/jobs.sqlite"` in the config so jobs live on the volume. If the config refers to schema files,
110
+ mount them next to it under `/config`.
111
+
112
+ ## 3b. TypeScript library: a new service
113
+
114
+ Copy [examples/paid-service](../examples/paid-service), the template for new providers, and replace its two
115
+ services with yours:
116
+
117
+ ```ts
118
+ import { createProvider, defineService, sqliteStore } from "@stellar-agent-services/provider-kit";
119
+
120
+ export const translate = defineService({
121
+ name: "translate",
122
+ description: "Translates English text to Turkish. Up to 5,000 characters.",
123
+ price: "0.02",
124
+ charge: "on-success",
125
+ expectedDurationSeconds: 5,
126
+ inputSchema: { type: "object", required: ["text"], properties: { text: { type: "string", maxLength: 5000 } }, additionalProperties: false },
127
+ outputSchema: { type: "object", required: ["text"], properties: { text: { type: "string" } } },
128
+ examples: [{ input: { text: "Hello" }, output: { text: "Merhaba" } }],
129
+ handler: async ({ text }, { signal }) => ({ text: await myModel.translate(text, { signal }) }),
130
+ });
131
+ ```
132
+
133
+ The handler gets only the validated input and `{ signal, jobId }`, never payment data. Stop work when `signal`
134
+ aborts. An `upfront` job whose worker died is run again, so use `jobId` to make side effects happen once.
135
+
136
+ `createProvider(...)` throws at startup if anything would fail the standard; `await provider.ready()` checks the
137
+ facilitator and resumes jobs from before a restart. Use `sqliteStore(path)`: the default memory store loses jobs on
138
+ restart. Read `baseUrl` from `PUBLIC_ORIGIN` and `payTo` from `PAY_TO`, as the template's `src/server.ts` does, so
139
+ `provider-kit dev -- node dist/server.js` and `launch --start 'node dist/server.js'` can run it.
140
+
141
+ ## 4. Set capacity
142
+
143
+ Each service runs `capacity.concurrency` jobs at once (default 4) and queues the rest. A new job that would wait
144
+ longer than `capacity.maxQueueWaitSeconds` (default 60) is turned away with `503` and `Retry-After` **before
145
+ payment**, so nobody pays for work you can't do. Set `concurrency` to what your GPU, worker pool or upstream quota
146
+ takes, per process. With the SQLite store, several processes on one machine share one queue and one limit; see
147
+ [the kit README](../packages/provider-kit/README.md#restarts-several-processes-separate-workers). A native
148
+ implementation follows rules Q1–Q9 of spec §5.8.
149
+
150
+ ## 5. Run and check it locally
151
+
152
+ ```bash
153
+ provider-kit dev --config provider.config.json # a gateway
154
+ provider-kit dev -- node dist/server.js # any other provider, by its own command
155
+ ```
156
+
157
+ **The throwaway payout account.** With `PAY_TO` empty, `dev` makes a new testnet account, gets it test XLM from
158
+ Friendbot and signs its USDC trustline [P2] with a key that lives in memory only. Then the key is dropped. The
159
+ provider only ever sees the public address, which goes in `.env` as `PAY_TO` and `DEV_PAY_TO`. Test payments land
160
+ there, and nobody can spend them. `launch` replaces it with your own account (§7). It is testnet only.
161
+
162
+ `--tunnel` also serves the provider at a temporary public HTTPS address (a Cloudflare quick tunnel, which needs
163
+ `cloudflared`), so a teammate, an agent on another computer or `verifier check` can reach it. The address changes
164
+ every run, so `launch` never registers it.
165
+
166
+ Then check it:
167
+
168
+ ```bash
169
+ provider-kit check --config provider.config.json --dev # gateway
170
+ provider-kit check --manifest http://localhost:8787/.well-known/stellar-agent-services.json --dev # any provider
171
+ ```
172
+
173
+ `check` costs nothing and needs no key. It verifies the manifest against the standard, that the facilitator settles
174
+ testnet payments with sponsored fees, that `payTo` exists with a USDC trustline, and your 8004 registration once
175
+ you have one. Before `launch`, it notes that the provider isn't registered yet; that doesn't fail the check.
176
+
177
+ It ends with how agents see you. Search matches your provider's name and description and, on testnet, your services'
178
+ names, titles, descriptions and tags too, once the manifest is live and bound to the registration. On mainnet it
179
+ reads only the name and description, so `check` lists the words from your services' names, titles and tags that a
180
+ search there wouldn't find, and `--fix` writes them into a gateway config's `provider.description`. It also flags services whose description is too thin to choose by [§3.4], or that
181
+ have no example ([details](../packages/provider-kit/README.md#how-agents-see-you)). These hints never fail the check.
182
+ `--json` prints the result for scripts and coding agents.
183
+
184
+ Then check it from outside, the way a verifier will, with the [verifier](../packages/verifier). It calls your
185
+ running service: invalid input, the `402` challenge, an oversized body, CORS, and a burst of 20 requests. Kit
186
+ providers pass it; it matters most for native implementations.
187
+
188
+ ```bash
189
+ npx @stellar-agent-services/verifier check http://localhost:8787/.well-known/stellar-agent-services.json --dev
190
+ ```
191
+
192
+ ## 6. Make a paid testnet request
193
+
194
+ Pay your own service once, the way any client will:
195
+
196
+ ```bash
197
+ provider-kit try <service> # with the service's example input
198
+ provider-kit try <service> '<input JSON>' # or your own input, or @input.json
199
+ ```
200
+
201
+ It shows the exact payment and asks first. Then it pays from a throwaway testnet account it makes for this call,
202
+ with test XLM from Friendbot and the price in test USDC from the testnet DEX, and shows the result and the
203
+ `transfer` on chain. You need no payer wallet, and the throwaway key is never written anywhere. A gateway is found
204
+ from `provider.config.json`, any other provider with `--manifest <url>`, and without either it tries
205
+ `http://localhost:8787`. When nothing answers, it starts the provider for the call: the gateway config in its own
206
+ process, or `--start '<command>'`, such as `--start 'npm run dev'`. `--json` prints the outcome as JSON.
207
+
208
+ <details>
209
+ <summary>Pay from your own test wallet instead</summary>
210
+
211
+ The payment client's CLI keeps a payer wallet, a spending policy and a journal, as a real client does, and can
212
+ recover a job after a lost response ([job-recovery.md](job-recovery.md)):
213
+
214
+ ```bash
215
+ npx stellar-pay wallet create
216
+ npx stellar-pay wallet fund --usdc 2
217
+ MANIFEST=http://localhost:8787/.well-known/stellar-agent-services.json
218
+ npx stellar-pay pay $MANIFEST <service> '<input JSON>' --dev
219
+ ```
220
+
221
+ The web page in [apps/wallet](../apps/wallet) does the same in a browser.
222
+
223
+ </details>
224
+
225
+ ## 7. Go live: `provider-kit launch`
226
+
227
+ ```bash
228
+ provider-kit launch --config provider.config.json # a gateway
229
+ provider-kit launch --start 'node dist/server.js' --url https://api.example.com # any provider this computer runs
230
+ ```
231
+
232
+ 1. **The public address.** `--url`, else the app in `fly.toml` (`https://<app>.fly.dev`), else an `https://`
233
+ `PUBLIC_ORIGIN`. It is known before the first deploy, so the service is registered first and deployed once, with
234
+ its agent id in place.
235
+ 2. **The manifest as that address will serve it**, checked against the standard: built from the gateway config, or
236
+ from your provider's own command, started on this computer with `PUBLIC_ORIGIN` set (`--start`). For a provider
237
+ already deployed, `--manifest <url>` reads it from there.
238
+ 3. **One page in your wallet.** Connect the wallet you already use and approve, in one go: test XLM for a new testnet
239
+ account, the USDC trustline [P2], the Stellar 8004 registration [I1]–[I3], and a validation request to a verifier
240
+ (§9). The account that connects becomes `payTo` and the agent's owner and wallet, unless `PAY_TO` already names an
241
+ account of yours, which must then connect.
242
+ 4. **Saved where the provider reads it.** `PAY_TO` and `AGENT_ID` go in `.env`, the agent id where the gateway config
243
+ reads it (`"agentId": "env:AGENT_ID"`, or the config itself), and `PUBLIC_ORIGIN`, `PAY_TO` and `AGENT_ID` in
244
+ `fly.toml`'s `[env]`. A new agent's id is saved even when a later step stops, so nothing is registered twice: run
245
+ `launch` again to finish.
246
+ 5. **Deploy, then check.** With `fly.toml` and your yes (`--deploy` skips the question), it deploys with `flyctl`:
247
+ it creates the app the first time, stages your API's key from `.env` as a Fly secret, and runs `fly deploy` with
248
+ one machine and the job database on a volume. Then it waits until the public manifest serves the agent id, and
249
+ checks the registration from outside. Elsewhere, it prints the settings to deploy with. A gateway whose
250
+ `upstream.url` is on 127.0.0.1 isn't deployed: in a container that is the container itself, so point it at an
251
+ address the container reaches, such as your API's public URL.
252
+
253
+ Running `launch` again is safe: it signs nothing when the registration already names the manifest and the verifier
254
+ was asked. After you move the manifest, or change the name or description search reads, it updates the registration.
255
+
256
+ **On a computer without a browser**, such as over SSH, add `--no-open` and open the printed link wherever your
257
+ wallet is: the link reaches only this computer, so forward its port (`ssh -L 8790:localhost:8790`).
258
+
259
+ <details>
260
+ <summary>The same steps one by one, and for scripts and CI</summary>
261
+
262
+ `launch` runs the owner steps that `trustline`, `register` and `request-validation` run one at a time. They also
263
+ take `--source <key>` to sign with a key from the [Stellar CLI](https://developers.stellar.org/docs/tools/cli)
264
+ keychain instead of a wallet, for scripts and CI, and with it `--dry-run` prints the Stellar CLI command:
265
+
266
+ ```bash
267
+ stellar keys generate payto --network testnet --fund --secure-store
268
+ provider-kit trustline --config provider.config.json --source payto
269
+ provider-kit register --config provider.config.json --source payto
270
+ provider-kit request-validation --config provider.config.json --validator <verifier G…> --source payto
271
+ ```
272
+
273
+ `register` registers from the `payTo` account, so the registry makes it the agent's owner and wallet [I3]. It saves the
274
+ new agent id as `"agentId"` under `provider` in your config, or prints it for a library provider.
275
+
276
+ </details>
277
+
278
+ ## 8. Run it in production
279
+
280
+ Clients accept `http://` only in development [M6]. `launch` deploys to Fly.io; on any other host, run the project's
281
+ `Dockerfile` (or the gateway image) behind HTTPS at a stable origin:
282
+
283
+ - set `PUBLIC_ORIGIN` (the gateway config's `baseUrl`) to the public URL, such as `https://api.example.com`, without
284
+ `dev`;
285
+ - keep the SQLite file on persistent disk: paid jobs and recovery depend on it. The project's image gives `/data` to
286
+ its `node` user at start, so a host's new volume works as it comes;
287
+ - give the provider a Soroban RPC (`rpcUrl` in the gateway config, `rpc` in `createProvider()`). It decides
288
+ `payment_uncertain` jobs from the chain by itself. Testnet uses the public RPC by default; mainnet has none,
289
+ so set yours. `provider-kit reconcile --config provider.config.json --dry-run` shows where uncertain jobs
290
+ stand (see [job-recovery.md](job-recovery.md#reconciliation));
291
+ - for `rateLimit`, set `keyHeader` to the header your proxy puts the client address in;
292
+ - health checks can use `GET /healthz`.
293
+
294
+ ### On mainnet
295
+
296
+ Everything above holds on `stellar:pubnet`, where clients pay real USDC. `npm create stellar-service -- --network
297
+ mainnet` starts a project there; a testnet project moves by hand
298
+ ([create-stellar-service](../packages/create-stellar-service/README.md#mainnet)). What is different:
299
+
300
+ - **The facilitator.** x402.org's settles testnet only. Stellar's docs list OpenZeppelin's for mainnet,
301
+ `https://channels.openzeppelin.com/x402`, which wants an API key from
302
+ [channels.openzeppelin.com/gen](https://channels.openzeppelin.com/gen). A gateway config sends it with
303
+ `"facilitatorHeaders": { "Authorization": "env:FACILITATOR_AUTH" }` and `FACILITATOR_AUTH="Bearer <key>"` in `.env`;
304
+ the library takes `httpFacilitator(url, { headers })`. The provider checks it when it starts, before any payment.
305
+ - **The RPC.** Mainnet has no public default: set `rpcUrl` or `rpc`. The Stellar 8004 SDK uses
306
+ `https://mainnet.sorobanrpc.com`; for production traffic, an
307
+ [RPC provider](https://developers.stellar.org/docs/data/apis/rpc/providers)'s is safer.
308
+ - **No test money.** `provider-kit try` and the throwaway account are testnet only. `launch` connects an account of
309
+ yours, which needs a few XLM for the trustline's reserve and the fees. It stages the facilitator's key and the RPC
310
+ as Fly secrets.
311
+ - **Search.** On mainnet, search matches only the provider's name and description: `provider-kit check --fix` writes
312
+ the missing words in.
313
+
314
+ ## 9. Get verified
315
+
316
+ A verifier checks a provider from outside, issues a verification receipt and badges, and records the result in
317
+ the Stellar 8004 Validation Registry (see [verification.md](verification.md)).
318
+
319
+ `launch` asks for it: the validation request names a verifier (`--validator <G…>`, `STELLAR_VALIDATOR`, or the kit's
320
+ default) and goes on chain with the manifest's URL in it. A verifier that runs `verifier watch` picks the request up by
321
+ itself, checks the provider (paying for a few jobs from its own test account), publishes the receipt and answers on
322
+ chain. Nothing needs to be sent to anyone. Its receipt gives your badges: Standard v1, Payment verified, Recovery
323
+ verified, Load-safe and 8004 validated.
324
+
325
+ Before that, run `verifier check <your manifest URL>`: every check should pass, and C2 confirms your 8004
326
+ registration.
327
+
328
+ ## 10. See where it stands
329
+
330
+ ```bash
331
+ provider-kit status # --json for scripts and coding agents
332
+ ```
333
+
334
+ ```text
335
+ Status on Stellar Testnet
336
+ ✓ local Text Tools runs at http://localhost:8787/.well-known/stellar-agent-services.json
337
+ ✓ payTo GC2W…A4DJ, your account, can receive USDC
338
+ ✓ paid payTo holds 0.0300000 USDC: paid calls reached it
339
+ ✓ registered agent 42: its registration lists https://text-tools.fly.dev/.well-known/stellar-agent-services.json, its wallet is payTo
340
+ ✓ live https://text-tools.fly.dev/.well-known/stellar-agent-services.json answers
341
+ ✗ verified requested from GBRP…OX2H, no answer yet
342
+
343
+ Next: Waiting for the verifier GBRP…OX2H to answer: it checks the service and answers on chain.
344
+ ```
345
+
346
+ It reads this computer, the chain and the public address, and names the one command to run next. It finds the
347
+ public manifest from `--url`, `fly.toml` or an `https://` `PUBLIC_ORIGIN`, else from the registration itself. It
348
+ only reads: no key, no payment, no transaction.