@mantyx/sdk 0.1.1 → 0.3.0

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ### Added
9
9
 
10
+ - Add support for a2a, mcp and local versions
11
+
12
+ ### Fixed
13
+
14
+ - Changelo
15
+
16
+ ## [0.2.0] — 2026-05-04
17
+
18
+ ### Fixed
19
+
20
+ - Use correct default base url
21
+
22
+ ## [0.1.1] — 2026-05-03
23
+
24
+ ### Added
25
+
10
26
  - Python package & gh pages doc
11
27
 
12
28
  ### Fixed
@@ -15,5 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
31
 
16
32
  ## [0.1.0] — 2026-05-02
17
33
 
18
- [unreleased]: https://github.com/mantyx-io/mantyx-sdk/compare/v0.1.0..HEAD
34
+ [unreleased]: https://github.com/mantyx-io/mantyx-sdk/compare/v0.2.0..HEAD
35
+ [0.2.0]: https://github.com/mantyx-io/mantyx-sdk/compare/v0.1.1..v0.2.0
36
+ [0.1.1]: https://github.com/mantyx-io/mantyx-sdk/compare/v0.1.0..v0.1.1
19
37
  [0.1.0]: https://github.com/mantyx-io/mantyx-sdk/releases/tag/v0.1.0
package/README.md CHANGED
@@ -6,13 +6,20 @@ locally-executed tools, run them remotely, and stream events back into your
6
6
  process.
7
7
 
8
8
  - LLM loop runs on MANTYX (BYOK or platform-hosted models).
9
- - Server-side tools (`mantyx`, `mantyx_plugin`) execute inside MANTYX.
10
- - Local tools execute inside *your* process; the SDK shuttles inputs and
11
- outputs over an SSE stream + a tool-result POST.
9
+ - Server-resolved tools (`mantyx`, `mantyx_plugin`, `a2a`, `mcp`) execute
10
+ inside MANTYX including remote Agent2Agent peers and remote MCP servers.
11
+ - Client-resolved tools (`local`, `a2a_local`, `mcp_local`) execute inside
12
+ *your* process; the SDK shuttles inputs and outputs over an SSE stream +
13
+ a tool-result POST.
14
+ - Tunable provider thinking via `reasoningLevel` (string anchors or 0–100).
12
15
  - One-shot runs and multi-turn sessions, both with persisted observability.
13
16
  - Authenticated with a single workspace API key.
14
17
 
15
- For background, see the [agent-runs protocol spec](./docs/agent-runs-protocol.md).
18
+ For background, see the [agent-runs protocol spec](./docs/agent-runs-protocol.md)
19
+ and the messaging-layer reference in [`docs/wire-protocol.md`](./docs/wire-protocol.md)
20
+ — the latter pins down the exact `local_tool_call` event shape and the
21
+ resolved data structures (`a2a_local` Agent Card, `mcp_local` `Tool[]`)
22
+ that this SDK ships.
16
23
 
17
24
  ## Install
18
25
 
@@ -22,9 +29,11 @@ npm install @mantyx/sdk zod
22
29
  # or: yarn add @mantyx/sdk zod
23
30
  ```
24
31
 
25
- Requires Node.js 18.17+ (for `fetch` and `ReadableStream`). `zod` is the only
26
- runtime dependency the SDK adds; the rest is the standard library and your
27
- own modules.
32
+ Requires Node.js 18.17+ (for `fetch` and `ReadableStream`). The SDK depends
33
+ on `zod` (parameter schemas) and `@modelcontextprotocol/sdk` (the official
34
+ MCP TypeScript SDK that powers `defineLocalMcp`'s stdio + Streamable HTTP
35
+ transports). The MCP SDK is loaded lazily — apps that never use
36
+ `defineLocalMcp` don't pay its startup cost.
28
37
 
29
38
  ## Quickstart
30
39
 
@@ -36,7 +45,7 @@ import { MantyxClient, defineLocalTool, mantyxTool } from "@mantyx/sdk";
36
45
  const client = new MantyxClient({
37
46
  apiKey: process.env.MANTYX_API_KEY!,
38
47
  workspaceSlug: process.env.MANTYX_WORKSPACE_SLUG!,
39
- // baseUrl: "https://api.mantyx.com", // override for self-hosted
48
+ // baseUrl: "https://app.mantyx.io", // override for self-hosted
40
49
  });
41
50
 
42
51
  const result = await client.runAgent({
@@ -103,6 +112,190 @@ Notes:
103
112
  The same `agentId` field works on `client.createSession({ ... })` for
104
113
  multi-turn conversations against a persisted agent.
105
114
 
115
+ ## Agent2Agent delegation
116
+
117
+ Hand a turn off to another agent — either a remote peer MANTYX dials directly
118
+ (`mantyxA2A`) or a peer that only the SDK can reach (`defineLocalA2A`). The
119
+ model addresses both with the same `{ message: string }` argument shape, so
120
+ an agent prompt that uses one works unchanged with the other.
121
+
122
+ `defineLocalA2A` is fully URL-driven: pass the Agent Card URL and the SDK
123
+ takes care of the rest — fetching the card on the first run, shipping it
124
+ inline as part of the spec, and POSTing JSON-RPC `message/send` to the
125
+ card's `url` whenever MANTYX emits a `local_tool_call`. You don't write any
126
+ A2A code yourself.
127
+
128
+ ```ts
129
+ import { MantyxClient, defineLocalA2A, mantyxA2A } from "@mantyx/sdk";
130
+
131
+ const client = new MantyxClient({ apiKey: "...", workspaceSlug: "acme" });
132
+
133
+ await client.runAgent({
134
+ systemPrompt: "You are a helpful router. Delegate billing to billing_agent.",
135
+ prompt: "Why was I charged twice last month?",
136
+ tools: [
137
+ // Public peer MANTYX dials directly.
138
+ mantyxA2A({
139
+ name: "billing_agent",
140
+ description: "Delegate billing questions to the Acme billing agent.",
141
+ agentCardUrl: "https://billing.acme.com/.well-known/agent-card.json",
142
+ headers: { Authorization: `Bearer ${process.env.BILLING_TOKEN}` },
143
+ }),
144
+ // Intranet peer the SDK reaches on MANTYX's behalf — URL only.
145
+ defineLocalA2A({
146
+ name: "intranet_hr",
147
+ agentCardUrl: "https://hr.intranet.acme/.well-known/agent-card.json",
148
+ headers: { Authorization: `Bearer ${process.env.HR_TOKEN}` },
149
+ }),
150
+ ],
151
+ });
152
+ ```
153
+
154
+ The same `headers` are sent on both the card fetch *and* every subsequent
155
+ `message/send` POST, which is typically what intranet peers want. The SDK
156
+ caches the resolved card on the tool ref for the duration of the run /
157
+ session — re-construct the ref to force a refetch.
158
+
159
+ > **Headers and secrets.** The `headers` you pass to `mantyxA2A` are forwarded
160
+ > as-is. For long-lived credentials, register the peer as a workspace
161
+ > `ExternalAgent` instead — those headers support `{{secret:NAME}}`
162
+ > placeholders. Use `mantyxA2A` for short-lived, per-run tokens minted by
163
+ > your application.
164
+
165
+ ### Exposing an agent over A2A
166
+
167
+ The inverse direction also works: wrap a MANTYX agent (ephemeral spec or a
168
+ persisted `agentId`) and serve it as an Agent2Agent peer using the official
169
+ [`@a2a-js/sdk`](https://www.npmjs.com/package/@a2a-js/sdk) library. Other
170
+ agents can then discover it at `/.well-known/agent-card.json` and call
171
+ `message/send` over JSON-RPC — including MANTYX agents elsewhere in your
172
+ estate consuming this one via `mantyxA2A` or `defineLocalA2A`.
173
+
174
+ ```ts
175
+ import { MantyxClient } from "@mantyx/sdk";
176
+ import { serveAgentOverA2A } from "@mantyx/sdk/a2a-server";
177
+
178
+ const client = new MantyxClient({ apiKey: "...", workspaceSlug: "acme" });
179
+
180
+ const handle = await serveAgentOverA2A({
181
+ client,
182
+ agent: { agentId: "agent_cm6abc123" }, // or { systemPrompt, modelId, tools }
183
+ port: 4000,
184
+ agentCard: {
185
+ name: "Acme Support",
186
+ description: "Customer support questions.",
187
+ protocolVersion: "0.3.0",
188
+ version: "1.0.0",
189
+ url: "http://localhost:4000",
190
+ skills: [{ id: "support", name: "Support", tags: ["support"] }],
191
+ capabilities: { streaming: true, pushNotifications: false },
192
+ defaultInputModes: ["text"],
193
+ defaultOutputModes: ["text"],
194
+ },
195
+ });
196
+
197
+ console.log(`A2A peer up on ${handle.url}`);
198
+ // later: await handle.close();
199
+ ```
200
+
201
+ `@a2a-js/sdk` and `express` are declared as **optional peer dependencies**,
202
+ so apps that don't expose an A2A server pay zero bundle cost. Install them
203
+ on demand:
204
+
205
+ ```bash
206
+ npm install @a2a-js/sdk express
207
+ ```
208
+
209
+ Each unique A2A `contextId` opens a long-lived MANTYX session by default, so
210
+ multi-turn `message/send` calls share conversational history. Pass
211
+ `conversation: "stateless"` to reduce every A2A request to a one-shot
212
+ `runAgent` call.
213
+
214
+ For lower-level integration (mounting the executor in your own Express /
215
+ Fastify / Connect app), `@mantyx/sdk/a2a-server` also exports a
216
+ `MantyxAgentExecutor` class implementing `@a2a-js/sdk/server`'s
217
+ `AgentExecutor` interface.
218
+
219
+ ## MCP connectors
220
+
221
+ Expose every tool published by an MCP server to the agent loop in one go,
222
+ without listing them individually.
223
+
224
+ ```ts
225
+ import { MantyxClient, mantyxMcp, defineLocalMcp } from "@mantyx/sdk";
226
+
227
+ const client = new MantyxClient({ apiKey: "...", workspaceSlug: "acme" });
228
+
229
+ await client.runAgent({
230
+ systemPrompt: "You are a developer assistant with GitHub + filesystem access.",
231
+ prompt: "Summarize the latest 5 issues on octocat/hello-world.",
232
+ tools: [
233
+ // Remote MCP server (Streamable HTTP) — MANTYX lists the catalog at run
234
+ // start and proxies every call. Tools surface as `github_<tool>`.
235
+ mantyxMcp({
236
+ name: "github",
237
+ url: "https://mcp.github.com/v1",
238
+ headers: { Authorization: `Bearer ${process.env.GH_PAT}` },
239
+ toolFilter: ["search_issues", "get_repo"],
240
+ }),
241
+ // Local MCP server — fully managed by the SDK. Pass either a
242
+ // Streamable HTTP `url` *or* an stdio `command`; the SDK opens the
243
+ // transport, runs `Initialize` + `tools/list`, ships the resolved
244
+ // catalog inline, and forwards every invocation to `tools/call`. The
245
+ // model sees `<server>_<tool>` (`fs_read_file`, `fs_list_dir`, …) —
246
+ // same shape as `mantyxMcp` above.
247
+
248
+ // (a) Streamable HTTP MCP server.
249
+ defineLocalMcp({
250
+ name: "fs",
251
+ url: "http://localhost:8080/mcp",
252
+ headers: { Authorization: `Bearer ${process.env.FS_TOKEN}` },
253
+ }),
254
+
255
+ // (b) stdio MCP server — the SDK spawns the process for you.
256
+ // defineLocalMcp({
257
+ // name: "fs",
258
+ // command: "mcp-server-filesystem",
259
+ // args: ["/workspace"],
260
+ // env: { LOG_LEVEL: "info" },
261
+ // }),
262
+ ],
263
+ });
264
+ ```
265
+
266
+ The MCP transport is opened lazily on the first `runAgent` / first
267
+ `session.send`, kept warm for subsequent calls within the same run /
268
+ session, and closed when the run completes or `session.end()` is called.
269
+ If the MCP server can't be reached, the SDK throws before submitting the
270
+ spec — you get the failure synchronously rather than mid-conversation.
271
+
272
+ If a remote (`kind: "mcp"`) MCP server is unreachable when the run starts,
273
+ MANTYX still exposes a single `<server>_unavailable` stub so the model can
274
+ tell the user why the connector is missing.
275
+
276
+ ## Reasoning effort (`reasoningLevel`)
277
+
278
+ Crank up provider thinking on reasoning models without writing
279
+ provider-specific code:
280
+
281
+ ```ts
282
+ await client.runAgent({
283
+ systemPrompt: "...",
284
+ prompt: "Plan a multi-week migration.",
285
+ reasoningLevel: "high", // or 80, etc.
286
+ });
287
+ ```
288
+
289
+ | Form | Values | Notes |
290
+ | ------------ | -------------------------------------------- | ----- |
291
+ | String | `"off"`, `"low"`, `"medium"`, `"high"` | Snaps to the same anchors the web composer uses (Fast=30, Moderate=50, Smart=80; off=0). |
292
+ | Number | integer `0`–`100` | `0` explicitly disables provider thinking on reasoning models. |
293
+
294
+ The server maps this onto each LLM's native dial — `reasoning.effort` for
295
+ OpenAI, `thinkingConfig` for Gemini, extended-thinking budget for Anthropic.
296
+ Non-reasoning models silently ignore it. On sessions, `reasoningLevel`
297
+ inherits from the session and can be overridden per `session.send`.
298
+
106
299
  ## Picking a model
107
300
 
108
301
  ```ts
@@ -228,7 +421,7 @@ const session = await client.resumeSession(sessionId, {
228
421
  interface MantyxClientOptions {
229
422
  apiKey: string;
230
423
  workspaceSlug: string;
231
- baseUrl?: string; // default: https://api.mantyx.com
424
+ baseUrl?: string; // default: https://app.mantyx.io
232
425
  fetch?: typeof fetch;
233
426
  timeoutMs?: number; // default: 60_000
234
427
  }
@@ -248,11 +441,15 @@ interface MantyxClientOptions {
248
441
 
249
442
  ### Tools
250
443
 
251
- | Helper | Use case |
252
- | -------------------------- | ------------------------------------------------------------ |
253
- | `defineLocalTool(opts)` | Define a local tool with a Zod parameter schema and handler. |
254
- | `mantyxTool(id)` | Reference an existing MANTYX tool by id. |
255
- | `mantyxPluginTool(name)` | Reference an installed platform plugin tool by name. |
444
+ | Helper | Use case |
445
+ | -------------------------- | ----------------------------------------------------------------------- |
446
+ | `defineLocalTool(opts)` | Define a local tool with a Zod parameter schema and handler. |
447
+ | `defineLocalA2A(opts)` | Local Agent2Agent peer — pass an `agentCardUrl`; the SDK fetches the card and speaks `message/send` for you. |
448
+ | `defineLocalMcp(opts)` | Local MCP server — pass either a Streamable HTTP `url` or an stdio `command`; the SDK runs `Initialize` + `tools/list` + `tools/call` for you. |
449
+ | `mantyxTool(id)` | Reference an existing MANTYX tool by id. |
450
+ | `mantyxPluginTool(name)` | Reference an installed platform plugin tool by name. |
451
+ | `mantyxA2A(opts)` | Remote Agent2Agent peer reachable from MANTYX (server-resolved). |
452
+ | `mantyxMcp(opts)` | Remote MCP server (Streamable HTTP) MANTYX dials and proxies for you. |
256
453
 
257
454
  ### Errors
258
455
 
@@ -272,6 +469,8 @@ Self-contained example projects live under [`examples/`](./examples/):
272
469
  - `examples/mixed-tools` — combines local, MANTYX, and plugin tools.
273
470
  - `examples/streaming` — token streaming to stdout.
274
471
  - `examples/list-models` — model catalog + pick-and-run.
472
+ - `examples/a2a-tools` — remote (`mantyxA2A`) + local (`defineLocalA2A`) Agent2Agent peers.
473
+ - `examples/mcp-tools` — remote (`mantyxMcp`) + local (`defineLocalMcp`) MCP servers.
275
474
 
276
475
  Each example is its own project (`package.json`, `tsconfig.json`, `README.md`)
277
476
  so you can copy any one of them out of the repo and run it standalone.