@agentwonderland/mcp 0.1.52 → 0.1.54
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/dist/core/__tests__/api-client.test.js +40 -0
- package/dist/core/__tests__/link-cli.test.d.ts +1 -0
- package/dist/core/__tests__/link-cli.test.js +102 -0
- package/dist/core/api-client.js +18 -0
- package/dist/core/link-cli.d.ts +5 -0
- package/dist/core/link-cli.js +25 -25
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/index.js +8 -5
- package/dist/tools/__tests__/playbooks.test.d.ts +1 -0
- package/dist/tools/__tests__/playbooks.test.js +2043 -0
- package/dist/tools/__tests__/run.test.js +26 -0
- package/dist/tools/__tests__/wallet.test.js +5 -4
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/passes.js +4 -21
- package/dist/tools/playbooks.d.ts +2 -0
- package/dist/tools/playbooks.js +880 -0
- package/dist/tools/run.js +10 -18
- package/dist/tools/solve.js +12 -19
- package/dist/tools/wallet.js +9 -12
- package/package.json +1 -1
- package/src/core/__tests__/api-client.test.ts +44 -0
- package/src/core/__tests__/link-cli.test.ts +125 -0
- package/src/core/api-client.ts +18 -0
- package/src/core/link-cli.ts +25 -27
- package/src/core/version.ts +1 -1
- package/src/index.ts +8 -5
- package/src/tools/__tests__/playbooks.test.ts +2285 -0
- package/src/tools/__tests__/run.test.ts +33 -0
- package/src/tools/__tests__/wallet.test.ts +5 -4
- package/src/tools/index.ts +1 -0
- package/src/tools/passes.ts +3 -21
- package/src/tools/playbooks.ts +1100 -0
- package/src/tools/run.ts +10 -17
- package/src/tools/solve.ts +11 -18
- package/src/tools/wallet.ts +9 -12
|
@@ -56,4 +56,44 @@ describe("api-client headers", () => {
|
|
|
56
56
|
}),
|
|
57
57
|
}));
|
|
58
58
|
});
|
|
59
|
+
it("labels playbook API calls with MCP surface, version, tool, and action headers", async () => {
|
|
60
|
+
const fetchMock = vi.fn(async () => new Response(JSON.stringify({ ok: true }), {
|
|
61
|
+
status: 200,
|
|
62
|
+
headers: { "content-type": "application/json" },
|
|
63
|
+
}));
|
|
64
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
65
|
+
const { apiGet, apiPost } = await import("../api-client.js");
|
|
66
|
+
await apiGet("/playbooks?limit=1");
|
|
67
|
+
await apiGet("/playbooks/competitor-ads");
|
|
68
|
+
await apiGet("/playbooks/competitor-ads/versions");
|
|
69
|
+
await apiGet("/playbooks/competitor-ads/versions/1");
|
|
70
|
+
await apiPost("/playbooks/competitor-ads/favorite", {});
|
|
71
|
+
await apiPost("/playbooks/competitor-ads/feedback", { rating: 5 });
|
|
72
|
+
await apiPost("/playbook-quotes", { slug: "competitor-ads", budget: 5 });
|
|
73
|
+
await apiPost("/playbook-runs", { slug: "competitor-ads", budget: 5 });
|
|
74
|
+
await apiGet("/playbook-runs/run-1");
|
|
75
|
+
await apiPost("/playbook-runs/run-1/steps/ads", { status: "running" });
|
|
76
|
+
const calls = fetchMock.mock.calls.map(([url, init]) => ({
|
|
77
|
+
url: String(url).replace("https://api.agentwonderland.test", ""),
|
|
78
|
+
headers: init.headers,
|
|
79
|
+
}));
|
|
80
|
+
for (const call of calls) {
|
|
81
|
+
expect(call.headers).toMatchObject({
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
Accept: "application/json",
|
|
84
|
+
"X-AW-Surface": "mcp",
|
|
85
|
+
"X-AW-MCP-Version": MCP_PACKAGE_VERSION,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
expect(calls[0]).toMatchObject({ url: "/playbooks?limit=1", headers: { "X-AW-MCP-Tool": "search_playbooks", "X-AW-MCP-Action": "search" } });
|
|
89
|
+
expect(calls[1]).toMatchObject({ url: "/playbooks/competitor-ads", headers: { "X-AW-MCP-Tool": "get_playbook", "X-AW-MCP-Action": "view" } });
|
|
90
|
+
expect(calls[2]).toMatchObject({ url: "/playbooks/competitor-ads/versions", headers: { "X-AW-MCP-Tool": "get_playbook", "X-AW-MCP-Action": "view" } });
|
|
91
|
+
expect(calls[3]).toMatchObject({ url: "/playbooks/competitor-ads/versions/1", headers: { "X-AW-MCP-Tool": "get_playbook", "X-AW-MCP-Action": "view" } });
|
|
92
|
+
expect(calls[4]).toMatchObject({ url: "/playbooks/competitor-ads/favorite", headers: { "X-AW-MCP-Tool": "favorite_playbook", "X-AW-MCP-Action": "favorite" } });
|
|
93
|
+
expect(calls[5]).toMatchObject({ url: "/playbooks/competitor-ads/feedback", headers: { "X-AW-MCP-Tool": "rate_playbook", "X-AW-MCP-Action": "feedback" } });
|
|
94
|
+
expect(calls[6]).toMatchObject({ url: "/playbook-quotes", headers: { "X-AW-MCP-Tool": "run_playbook", "X-AW-MCP-Action": "quote" } });
|
|
95
|
+
expect(calls[7]).toMatchObject({ url: "/playbook-runs", headers: { "X-AW-MCP-Tool": "run_playbook", "X-AW-MCP-Action": "execute" } });
|
|
96
|
+
expect(calls[8]).toMatchObject({ url: "/playbook-runs/run-1", headers: { "X-AW-MCP-Tool": "run_playbook", "X-AW-MCP-Action": "poll" } });
|
|
97
|
+
expect(calls[9]).toMatchObject({ url: "/playbook-runs/run-1/steps/ads", headers: { "X-AW-MCP-Tool": "run_playbook", "X-AW-MCP-Action": "execute" } });
|
|
98
|
+
});
|
|
59
99
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
const { execCalls, outputs, state, mockExecFile, } = vi.hoisted(() => {
|
|
3
|
+
const execCalls = [];
|
|
4
|
+
const outputs = [];
|
|
5
|
+
const state = {
|
|
6
|
+
pending: null,
|
|
7
|
+
pendingWrites: [],
|
|
8
|
+
};
|
|
9
|
+
const mockExecFile = vi.fn((file, args, _options, callback) => {
|
|
10
|
+
execCalls.push({ file, args });
|
|
11
|
+
const next = outputs.shift();
|
|
12
|
+
if (next instanceof Error) {
|
|
13
|
+
callback(next);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
callback(null, JSON.stringify(next ?? null), "");
|
|
17
|
+
});
|
|
18
|
+
mockExecFile[Symbol.for("nodejs.util.promisify.custom")] = async (file, args) => {
|
|
19
|
+
execCalls.push({ file, args });
|
|
20
|
+
const next = outputs.shift();
|
|
21
|
+
if (next instanceof Error) {
|
|
22
|
+
throw next;
|
|
23
|
+
}
|
|
24
|
+
return { stdout: JSON.stringify(next ?? null), stderr: "" };
|
|
25
|
+
};
|
|
26
|
+
return { execCalls, outputs, state, mockExecFile };
|
|
27
|
+
});
|
|
28
|
+
vi.mock("node:child_process", () => ({
|
|
29
|
+
execFile: mockExecFile,
|
|
30
|
+
}));
|
|
31
|
+
vi.mock("../config.js", () => ({
|
|
32
|
+
getPendingLinkSpendRequest: () => state.pending,
|
|
33
|
+
setPendingLinkSpendRequest: (pending) => {
|
|
34
|
+
state.pending = pending;
|
|
35
|
+
state.pendingWrites.push(pending);
|
|
36
|
+
},
|
|
37
|
+
setLinkCooldown: vi.fn(),
|
|
38
|
+
}));
|
|
39
|
+
describe("Link CLI spend requests", () => {
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
vi.clearAllMocks();
|
|
42
|
+
execCalls.length = 0;
|
|
43
|
+
outputs.length = 0;
|
|
44
|
+
state.pending = null;
|
|
45
|
+
state.pendingWrites = [];
|
|
46
|
+
});
|
|
47
|
+
it("returns an approval-required error immediately instead of blocking on Link approval", async () => {
|
|
48
|
+
outputs.push([
|
|
49
|
+
{
|
|
50
|
+
id: "lsrq_test_123",
|
|
51
|
+
approval_url: "https://link.example/approve/lsrq_test_123",
|
|
52
|
+
status: "pending_approval",
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
const { createLinkSharedPaymentToken, LinkApprovalRequiredError } = await import("../link-cli.js");
|
|
56
|
+
await expect(createLinkSharedPaymentToken({
|
|
57
|
+
amount: "10",
|
|
58
|
+
currency: "usd",
|
|
59
|
+
context: "Agent Wonderland test",
|
|
60
|
+
expiresAt: Math.floor(Date.now() / 1000) + 300,
|
|
61
|
+
networkId: "profile_test",
|
|
62
|
+
paymentMethodId: "csmrpd_test_123",
|
|
63
|
+
})).rejects.toBeInstanceOf(LinkApprovalRequiredError);
|
|
64
|
+
expect(execCalls).toHaveLength(1);
|
|
65
|
+
expect(execCalls[0]?.args).toContain("create");
|
|
66
|
+
expect(state.pendingWrites[0]).toMatchObject({
|
|
67
|
+
id: "lsrq_test_123",
|
|
68
|
+
approvalUrl: "https://link.example/approve/lsrq_test_123",
|
|
69
|
+
amount: "10",
|
|
70
|
+
currency: "usd",
|
|
71
|
+
networkId: "profile_test",
|
|
72
|
+
paymentMethodId: "csmrpd_test_123",
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
it("resumes a stored Link spend request and returns the approved shared payment token", async () => {
|
|
76
|
+
const expiresAt = Math.floor(Date.now() / 1000) + 300;
|
|
77
|
+
state.pending = {
|
|
78
|
+
id: "lsrq_test_123",
|
|
79
|
+
approvalUrl: "https://link.example/approve/lsrq_test_123",
|
|
80
|
+
amount: "10",
|
|
81
|
+
currency: "usd",
|
|
82
|
+
context: "Agent Wonderland test",
|
|
83
|
+
expiresAt,
|
|
84
|
+
networkId: "profile_test",
|
|
85
|
+
paymentMethodId: "csmrpd_test_123",
|
|
86
|
+
createdAt: new Date().toISOString(),
|
|
87
|
+
};
|
|
88
|
+
outputs.push({ shared_payment_token: "spt_test_123" });
|
|
89
|
+
const { createLinkSharedPaymentToken } = await import("../link-cli.js");
|
|
90
|
+
await expect(createLinkSharedPaymentToken({
|
|
91
|
+
amount: "10",
|
|
92
|
+
currency: "usd",
|
|
93
|
+
context: "Agent Wonderland test",
|
|
94
|
+
expiresAt,
|
|
95
|
+
networkId: "profile_test",
|
|
96
|
+
paymentMethodId: "csmrpd_test_123",
|
|
97
|
+
})).resolves.toBe("spt_test_123");
|
|
98
|
+
expect(execCalls).toHaveLength(1);
|
|
99
|
+
expect(execCalls[0]?.args).toEqual(expect.arrayContaining(["spend-request", "retrieve", "lsrq_test_123"]));
|
|
100
|
+
expect(state.pendingWrites).toEqual([null]);
|
|
101
|
+
});
|
|
102
|
+
});
|
package/dist/core/api-client.js
CHANGED
|
@@ -23,6 +23,24 @@ function inferToolHeaders(path, method) {
|
|
|
23
23
|
if (path.startsWith("/agents?") || path === "/agents" || path === "/agents/search") {
|
|
24
24
|
return { "X-AW-MCP-Tool": "search_agents", "X-AW-MCP-Action": "search" };
|
|
25
25
|
}
|
|
26
|
+
if (path.startsWith("/playbooks?") || path === "/playbooks") {
|
|
27
|
+
return { "X-AW-MCP-Tool": "search_playbooks", "X-AW-MCP-Action": "search" };
|
|
28
|
+
}
|
|
29
|
+
if (/^\/playbooks\/[^/]+(?:\/versions(?:\/[^/]+)?)?$/.test(path)) {
|
|
30
|
+
return { "X-AW-MCP-Tool": "get_playbook", "X-AW-MCP-Action": "view" };
|
|
31
|
+
}
|
|
32
|
+
if (/^\/playbooks\/[^/]+\/favorite$/.test(path)) {
|
|
33
|
+
return { "X-AW-MCP-Tool": "favorite_playbook", "X-AW-MCP-Action": "favorite" };
|
|
34
|
+
}
|
|
35
|
+
if (/^\/playbooks\/[^/]+\/feedback$/.test(path)) {
|
|
36
|
+
return { "X-AW-MCP-Tool": "rate_playbook", "X-AW-MCP-Action": "feedback" };
|
|
37
|
+
}
|
|
38
|
+
if (path === "/playbook-quotes") {
|
|
39
|
+
return { "X-AW-MCP-Tool": "run_playbook", "X-AW-MCP-Action": "quote" };
|
|
40
|
+
}
|
|
41
|
+
if (path === "/playbook-runs" || path.startsWith("/playbook-runs/")) {
|
|
42
|
+
return { "X-AW-MCP-Tool": "run_playbook", "X-AW-MCP-Action": method === "GET" ? "poll" : "execute" };
|
|
43
|
+
}
|
|
26
44
|
if (/^\/agents\/[^/]+$/.test(path)) {
|
|
27
45
|
return { "X-AW-MCP-Tool": "get_agent", "X-AW-MCP-Action": "view" };
|
|
28
46
|
}
|
package/dist/core/link-cli.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export declare class LinkApprovalRequiredError extends Error {
|
|
2
|
+
readonly spendRequestId: string;
|
|
3
|
+
readonly approvalUrl?: string | undefined;
|
|
4
|
+
constructor(spendRequestId: string, approvalUrl?: string | undefined);
|
|
5
|
+
}
|
|
1
6
|
export interface LinkCliAuthStatus {
|
|
2
7
|
authenticated: boolean;
|
|
3
8
|
credentialsPath?: string;
|
package/dist/core/link-cli.js
CHANGED
|
@@ -4,8 +4,23 @@ import { getPendingLinkSpendRequest, setLinkCooldown, setPendingLinkSpendRequest
|
|
|
4
4
|
const execFileAsync = promisify(execFile);
|
|
5
5
|
const LINK_CLI_PACKAGE = "@stripe/link-cli";
|
|
6
6
|
const LINK_CLI_TIMEOUT_MS = 10 * 60 * 1000;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
export class LinkApprovalRequiredError extends Error {
|
|
8
|
+
spendRequestId;
|
|
9
|
+
approvalUrl;
|
|
10
|
+
constructor(spendRequestId, approvalUrl) {
|
|
11
|
+
super(formatLinkApprovalRequiredMessage(spendRequestId, approvalUrl));
|
|
12
|
+
this.spendRequestId = spendRequestId;
|
|
13
|
+
this.approvalUrl = approvalUrl;
|
|
14
|
+
this.name = "LinkApprovalRequiredError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function formatLinkApprovalRequiredMessage(spendRequestId, approvalUrl) {
|
|
18
|
+
return [
|
|
19
|
+
"Link approval required.",
|
|
20
|
+
"The agent has not run yet and no charge has been captured.",
|
|
21
|
+
approvalUrl ? `Approve this spend request in Link: ${approvalUrl}` : `Spend request: ${spendRequestId}`,
|
|
22
|
+
"After approving, rerun the same tool call with confirmed: true.",
|
|
23
|
+
].join("\n");
|
|
9
24
|
}
|
|
10
25
|
async function runLinkCli(args, timeout = LINK_CLI_TIMEOUT_MS) {
|
|
11
26
|
try {
|
|
@@ -220,6 +235,9 @@ export async function createLinkSharedPaymentToken(params) {
|
|
|
220
235
|
}
|
|
221
236
|
catch (err) {
|
|
222
237
|
const message = err instanceof Error ? err.message : String(err);
|
|
238
|
+
if (err instanceof LinkApprovalRequiredError) {
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
223
241
|
if (!/denied|expired|not found|without a shared payment token|POLLING_TIMEOUT/i.test(message)) {
|
|
224
242
|
throw err;
|
|
225
243
|
}
|
|
@@ -293,39 +311,21 @@ export async function createLinkSharedPaymentToken(params) {
|
|
|
293
311
|
if (approval.approvalUrl) {
|
|
294
312
|
console.error(`Link approval required: ${approval.approvalUrl}`);
|
|
295
313
|
}
|
|
296
|
-
|
|
297
|
-
setPendingLinkSpendRequest(null);
|
|
298
|
-
return retrievedSpt;
|
|
314
|
+
throw new LinkApprovalRequiredError(approval.id, approval.approvalUrl);
|
|
299
315
|
}
|
|
300
316
|
{
|
|
301
317
|
throw new Error("Link spend request completed without a shared payment token in the CLI response.");
|
|
302
318
|
}
|
|
303
319
|
}
|
|
304
320
|
async function retrieveSharedPaymentToken(spendRequestId, approvalUrl) {
|
|
305
|
-
|
|
321
|
+
const retrieved = await runLinkCli([
|
|
306
322
|
"spend-request",
|
|
307
323
|
"retrieve",
|
|
308
324
|
spendRequestId,
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
"--max-attempts",
|
|
312
|
-
"150",
|
|
313
|
-
]);
|
|
314
|
-
let retrievedSpt = extractSharedPaymentToken(retrieved);
|
|
315
|
-
for (let attempt = 0; !retrievedSpt && attempt < 30; attempt += 1) {
|
|
316
|
-
await sleep(2_000);
|
|
317
|
-
retrieved = await runLinkCli([
|
|
318
|
-
"spend-request",
|
|
319
|
-
"retrieve",
|
|
320
|
-
spendRequestId,
|
|
321
|
-
]);
|
|
322
|
-
retrievedSpt = extractSharedPaymentToken(retrieved);
|
|
323
|
-
}
|
|
325
|
+
], 30_000);
|
|
326
|
+
const retrievedSpt = extractSharedPaymentToken(retrieved);
|
|
324
327
|
if (retrievedSpt) {
|
|
325
328
|
return retrievedSpt;
|
|
326
329
|
}
|
|
327
|
-
throw new
|
|
328
|
-
"Link spend request finished without a shared payment token.",
|
|
329
|
-
approvalUrl ? `Approval URL: ${approvalUrl}` : undefined,
|
|
330
|
-
].filter(Boolean).join("\n"));
|
|
330
|
+
throw new LinkApprovalRequiredError(spendRequestId, approvalUrl);
|
|
331
331
|
}
|
package/dist/core/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MCP_PACKAGE_VERSION = "0.1.
|
|
1
|
+
export declare const MCP_PACKAGE_VERSION = "0.1.54";
|
package/dist/core/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const MCP_PACKAGE_VERSION = "0.1.
|
|
1
|
+
export const MCP_PACKAGE_VERSION = "0.1.54";
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { registerRebateTools } from "./tools/rebates.js";
|
|
|
16
16
|
import { registerUploadTools } from "./tools/upload.js";
|
|
17
17
|
import { registerProbeTools } from "./tools/probe.js";
|
|
18
18
|
import { registerProviderTools } from "./tools/providers.js";
|
|
19
|
+
import { registerPlaybookTools } from "./tools/playbooks.js";
|
|
19
20
|
// ── Resources ────────────────────────────────────────────────────
|
|
20
21
|
import { registerAgentResources } from "./resources/agents.js";
|
|
21
22
|
import { registerWalletResources } from "./resources/wallet.js";
|
|
@@ -41,16 +42,17 @@ export async function startMcpServer() {
|
|
|
41
42
|
"WORKFLOW:",
|
|
42
43
|
"1. solve(intent, input, budget) — one call: find best agent + pay + run. Use when the task is clear.",
|
|
43
44
|
" OR: search_agents() → get_agent() to inspect schema → run_agent() with required fields.",
|
|
45
|
+
" For multi-agent workflows, use search_playbooks() → get_playbook() → run_playbook().",
|
|
44
46
|
"2. If the agent returns status 'processing', poll with get_job(). Async runs resolve automatically.",
|
|
45
|
-
"3. After a successful run, rate_agent() and optionally tip_agent() if the result was useful.",
|
|
47
|
+
"3. After a successful agent run, rate_agent() and optionally tip_agent() if the result was useful.",
|
|
48
|
+
" After a successful playbook run, offer favorite_playbook() or rate_playbook() using the returned run_id.",
|
|
46
49
|
"4. Use list_jobs() to recover state across sessions (it checks every configured wallet).",
|
|
47
50
|
"",
|
|
48
51
|
"PAYMENT:",
|
|
49
|
-
"- Supported payment methods:
|
|
50
|
-
"- Link payments may ask the user to approve a spend request in Link before the first charge.",
|
|
52
|
+
"- Supported launch payment methods: Tempo USDC, Base USDC, and Solana USDC.",
|
|
51
53
|
"- Tempo and Base share one EVM wallet key. Solana uses a separate ed25519 key. One OWS wallet can manage both.",
|
|
52
54
|
"- If pay_with is omitted, the MCP auto-selects a compatible configured rail. Pass pay_with explicitly",
|
|
53
|
-
" (tempo | base | solana |
|
|
55
|
+
" (tempo | base | solana | wallet-id) for deterministic behavior.",
|
|
54
56
|
"- Payment is automatic: on a 402 challenge the MCP signs on-chain, submits, then retries. Failed runs are refunded.",
|
|
55
57
|
"- If a specific rail fails, surface the real reason — do NOT silently retry with a different method.",
|
|
56
58
|
"- Headless/automation: set wallet_set_policy() to cap max_per_tx and max_per_day so a runaway loop can't drain funds.",
|
|
@@ -66,7 +68,7 @@ export async function startMcpServer() {
|
|
|
66
68
|
"WALLET HYGIENE:",
|
|
67
69
|
"- wallet_status shows per-chain USDC balance and the active network (mainnet vs testnet).",
|
|
68
70
|
"- rebate_status shows accrued, pending, paid, and blocked consumer rebates plus recent payout transactions.",
|
|
69
|
-
"- To set up payments: wallet_setup({ action: \"start\" }).
|
|
71
|
+
"- To set up payments: wallet_setup({ action: \"start\" }). Use Tempo, Base, or Solana USDC for launch runs.",
|
|
70
72
|
"- To create or import a crypto wallet directly: wallet_setup({ action: \"create\" }) or { action: \"import\", key }.",
|
|
71
73
|
"- NEVER delete or rotate keys programmatically. Direct users to edit ~/.agentwonderland/config.json or ~/.ows/ manually.",
|
|
72
74
|
].join("\n"),
|
|
@@ -86,6 +88,7 @@ export async function startMcpServer() {
|
|
|
86
88
|
registerUploadTools(server);
|
|
87
89
|
registerProbeTools(server);
|
|
88
90
|
registerProviderTools(server);
|
|
91
|
+
registerPlaybookTools(server);
|
|
89
92
|
// Register resources
|
|
90
93
|
registerAgentResources(server);
|
|
91
94
|
registerWalletResources(server);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|