@moneolabs/mcp 0.1.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/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/cli.js +292 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +318 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +62 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +288 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
buildTools: () => buildTools,
|
|
24
|
+
createMcpServer: () => createMcpServer,
|
|
25
|
+
createSandbox: () => createSandbox,
|
|
26
|
+
serveStdio: () => serveStdio
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/server.ts
|
|
31
|
+
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
32
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
33
|
+
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
34
|
+
|
|
35
|
+
// src/tools.ts
|
|
36
|
+
var import_core = require("@moneolabs/core");
|
|
37
|
+
var import_guard = require("@moneolabs/guard");
|
|
38
|
+
var import_wallet = require("@moneolabs/wallet");
|
|
39
|
+
function buildTools(options) {
|
|
40
|
+
const walletTools = (0, import_wallet.toolkit)(options.wallet, {
|
|
41
|
+
...options.guard ? { guard: options.guard } : {},
|
|
42
|
+
...options.include ? { include: options.include } : {}
|
|
43
|
+
});
|
|
44
|
+
const trading = options.trading;
|
|
45
|
+
const tradingTools = trading ? {
|
|
46
|
+
get_quote: {
|
|
47
|
+
definition: {
|
|
48
|
+
name: "get_quote",
|
|
49
|
+
description: "Price a trade across every venue that can fill it, without committing to anything. Returns the best route.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
sell: { type: "string", description: 'Asset given up, for example "USDG".' },
|
|
54
|
+
buy: { type: "string", description: 'Asset acquired, for example "AAPLX".' },
|
|
55
|
+
notional: {
|
|
56
|
+
type: "string",
|
|
57
|
+
description: 'How much to spend, for example "300 USDG".'
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
required: ["sell", "buy", "notional"]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
async run(input) {
|
|
64
|
+
const quote = await trading.quote({
|
|
65
|
+
sell: String(input.sell),
|
|
66
|
+
buy: String(input.buy),
|
|
67
|
+
notional: String(input.notional)
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
quoteId: quote.id,
|
|
71
|
+
venue: quote.venue,
|
|
72
|
+
sells: (0, import_core.formatMoney)(quote.sellAmount),
|
|
73
|
+
buys: (0, import_core.formatMoney)(quote.buyAmount),
|
|
74
|
+
price: quote.price,
|
|
75
|
+
fee: (0, import_core.formatMoney)(quote.fee),
|
|
76
|
+
impact: quote.impact,
|
|
77
|
+
expiresAt: new Date(quote.expiresAt).toISOString()
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
execute_order: {
|
|
82
|
+
definition: {
|
|
83
|
+
name: "execute_order",
|
|
84
|
+
description: "Quote and execute a trade. Policy runs before anything is signed: a refusal returns the reason and costs nothing. Attach takeProfit and stopLoss to ship the exit with the entry.",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: {
|
|
88
|
+
sell: { type: "string", description: "Asset given up." },
|
|
89
|
+
buy: { type: "string", description: "Asset acquired." },
|
|
90
|
+
notional: { type: "string", description: 'How much to spend, e.g. "300 USDG".' },
|
|
91
|
+
type: {
|
|
92
|
+
type: "string",
|
|
93
|
+
enum: ["market", "limit", "twap", "bracket"],
|
|
94
|
+
description: "Order type. Defaults to market."
|
|
95
|
+
},
|
|
96
|
+
maxSlippage: {
|
|
97
|
+
type: "number",
|
|
98
|
+
description: "Largest acceptable adverse move as a fraction, e.g. 0.003. Exceeding it rejects the order instead of filling it worse."
|
|
99
|
+
},
|
|
100
|
+
limitPrice: { type: "number", description: "limit: price to rest at." },
|
|
101
|
+
window: {
|
|
102
|
+
type: "string",
|
|
103
|
+
description: 'twap: window to spread across, e.g. "30m".'
|
|
104
|
+
},
|
|
105
|
+
takeProfit: { type: "number", description: "bracket: exit price above." },
|
|
106
|
+
stopLoss: { type: "number", description: "bracket: exit price below." }
|
|
107
|
+
},
|
|
108
|
+
required: ["sell", "buy", "notional"]
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
async run(input) {
|
|
112
|
+
const orderOptions = {
|
|
113
|
+
...input.type ? { type: input.type } : {},
|
|
114
|
+
...typeof input.maxSlippage === "number" ? { maxSlippage: input.maxSlippage } : {},
|
|
115
|
+
...typeof input.limitPrice === "number" ? { limitPrice: input.limitPrice } : {},
|
|
116
|
+
...input.window ? { window: String(input.window) } : {},
|
|
117
|
+
...typeof input.takeProfit === "number" ? { takeProfit: input.takeProfit } : {},
|
|
118
|
+
...typeof input.stopLoss === "number" ? { stopLoss: input.stopLoss } : {}
|
|
119
|
+
};
|
|
120
|
+
try {
|
|
121
|
+
const quote = await trading.quote({
|
|
122
|
+
sell: String(input.sell),
|
|
123
|
+
buy: String(input.buy),
|
|
124
|
+
notional: String(input.notional)
|
|
125
|
+
});
|
|
126
|
+
const order = await trading.execute(quote, orderOptions);
|
|
127
|
+
return { ok: true, ...formatOrder(await order.settled()) };
|
|
128
|
+
} catch (error) {
|
|
129
|
+
if (error instanceof import_guard.PolicyDeniedError) {
|
|
130
|
+
return {
|
|
131
|
+
ok: false,
|
|
132
|
+
refused: true,
|
|
133
|
+
reason: error.decision.reason,
|
|
134
|
+
rule: error.decision.rule,
|
|
135
|
+
hint: "This limit is set by the wallet owner. Ask them to raise it rather than retrying."
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
list_positions: {
|
|
143
|
+
definition: {
|
|
144
|
+
name: "list_positions",
|
|
145
|
+
description: "Open positions with cost basis and unrealized P&L at the latest mark.",
|
|
146
|
+
inputSchema: { type: "object", properties: {} }
|
|
147
|
+
},
|
|
148
|
+
async run() {
|
|
149
|
+
return trading.positions().map((p) => ({
|
|
150
|
+
asset: p.asset,
|
|
151
|
+
quantity: (0, import_core.formatMoney)(p.quantity),
|
|
152
|
+
averageCost: p.averageCost,
|
|
153
|
+
costBasis: (0, import_core.formatMoney)(p.costBasis),
|
|
154
|
+
marketValue: (0, import_core.formatMoney)(p.marketValue),
|
|
155
|
+
unrealized: (0, import_core.formatMoney)(p.unrealized),
|
|
156
|
+
realized: (0, import_core.formatMoney)(p.realized)
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
close_position: {
|
|
161
|
+
definition: {
|
|
162
|
+
name: "close_position",
|
|
163
|
+
description: "Exit a position with the same guarantees the entry had: policy first, slippage bound enforced.",
|
|
164
|
+
inputSchema: {
|
|
165
|
+
type: "object",
|
|
166
|
+
properties: {
|
|
167
|
+
asset: { type: "string", description: "Asset to close." },
|
|
168
|
+
maxSlippage: {
|
|
169
|
+
type: "number",
|
|
170
|
+
description: "Largest acceptable adverse move as a fraction."
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
required: ["asset"]
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
async run(input) {
|
|
177
|
+
try {
|
|
178
|
+
const order = await trading.close(String(input.asset), {
|
|
179
|
+
type: "market",
|
|
180
|
+
...typeof input.maxSlippage === "number" ? { maxSlippage: input.maxSlippage } : {}
|
|
181
|
+
});
|
|
182
|
+
return { ok: true, ...formatOrder(await order.settled()) };
|
|
183
|
+
} catch (error) {
|
|
184
|
+
if (error instanceof import_guard.PolicyDeniedError) {
|
|
185
|
+
return {
|
|
186
|
+
ok: false,
|
|
187
|
+
refused: true,
|
|
188
|
+
reason: error.decision.reason,
|
|
189
|
+
rule: error.decision.rule
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} : {};
|
|
197
|
+
return {
|
|
198
|
+
definitions: [
|
|
199
|
+
...walletTools.definitions,
|
|
200
|
+
...Object.values(tradingTools).map((tool) => tool.definition)
|
|
201
|
+
],
|
|
202
|
+
async handle(name, input) {
|
|
203
|
+
const tradingTool = tradingTools[name];
|
|
204
|
+
if (tradingTool) return tradingTool.run(input ?? {});
|
|
205
|
+
return walletTools.handle(name, input ?? {});
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function formatOrder(result) {
|
|
210
|
+
return {
|
|
211
|
+
orderId: result.id,
|
|
212
|
+
status: result.status,
|
|
213
|
+
type: result.type,
|
|
214
|
+
sell: result.sell,
|
|
215
|
+
buy: result.buy,
|
|
216
|
+
filled: (0, import_core.formatMoney)(result.filled),
|
|
217
|
+
received: (0, import_core.formatMoney)(result.received),
|
|
218
|
+
averagePrice: result.averagePrice,
|
|
219
|
+
slippage: result.slippage,
|
|
220
|
+
fees: (0, import_core.formatMoney)(result.fees),
|
|
221
|
+
...result.reason ? { reason: result.reason } : {},
|
|
222
|
+
...result.decision ? { policyVersion: result.decision.policyVersion } : {}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/server.ts
|
|
227
|
+
function createMcpServer(options) {
|
|
228
|
+
const tools = buildTools(options);
|
|
229
|
+
const server = new import_server.Server(
|
|
230
|
+
{ name: options.name ?? "moneo", version: options.version ?? "0.1.0" },
|
|
231
|
+
{ capabilities: { tools: {} } }
|
|
232
|
+
);
|
|
233
|
+
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({
|
|
234
|
+
tools: tools.definitions.map((d) => ({
|
|
235
|
+
name: d.name,
|
|
236
|
+
description: d.description,
|
|
237
|
+
inputSchema: d.inputSchema
|
|
238
|
+
}))
|
|
239
|
+
}));
|
|
240
|
+
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
241
|
+
try {
|
|
242
|
+
const result = await tools.handle(
|
|
243
|
+
request.params.name,
|
|
244
|
+
request.params.arguments ?? {}
|
|
245
|
+
);
|
|
246
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
247
|
+
} catch (error) {
|
|
248
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
249
|
+
return {
|
|
250
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
251
|
+
isError: true
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
return server;
|
|
256
|
+
}
|
|
257
|
+
async function serveStdio(server) {
|
|
258
|
+
const transport = new import_stdio.StdioServerTransport();
|
|
259
|
+
await server.connect(transport);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/sandbox.ts
|
|
263
|
+
var import_node_fs = require("fs");
|
|
264
|
+
var import_core2 = require("@moneolabs/core");
|
|
265
|
+
var import_guard2 = require("@moneolabs/guard");
|
|
266
|
+
var import_trading = require("@moneolabs/trading");
|
|
267
|
+
var import_wallet2 = require("@moneolabs/wallet");
|
|
268
|
+
var DEFAULT_POLICY = {
|
|
269
|
+
perTransaction: { max: "$500" },
|
|
270
|
+
rolling24h: { max: "$2,000" },
|
|
271
|
+
velocity: { max: 20, per: "1m" },
|
|
272
|
+
counterparties: "allowlist-only",
|
|
273
|
+
allow: ["x402:*", "venue:*", "vendor:*"],
|
|
274
|
+
escalate: { above: "$1,000" }
|
|
275
|
+
};
|
|
276
|
+
var SANDBOX_PRICES = {
|
|
277
|
+
AAPLX: 228.41,
|
|
278
|
+
TSLAX: 312.76,
|
|
279
|
+
NVDAX: 171.34,
|
|
280
|
+
SPYX: 563.02
|
|
281
|
+
};
|
|
282
|
+
async function createSandbox(options = {}) {
|
|
283
|
+
const agent = options.agent ?? process.env.MONEO_AGENT ?? "sandbox-agent";
|
|
284
|
+
const funding = options.funding ?? process.env.MONEO_FUNDING ?? "5,000 USDG";
|
|
285
|
+
const asset = options.asset ?? process.env.MONEO_ASSET ?? "USDG";
|
|
286
|
+
const policyPath = options.policyPath ?? process.env.MONEO_POLICY;
|
|
287
|
+
const policy = policyPath ? JSON.parse((0, import_node_fs.readFileSync)(policyPath, "utf8")) : DEFAULT_POLICY;
|
|
288
|
+
const guard = (0, import_guard2.createGuard)(policy, { agent, prices: (0, import_core2.fixedPrices)(SANDBOX_PRICES) });
|
|
289
|
+
const wallet = await (0, import_wallet2.createWallet)({
|
|
290
|
+
agent,
|
|
291
|
+
signer: (0, import_wallet2.localSigner)(),
|
|
292
|
+
rail: (0, import_wallet2.memoryRail)(),
|
|
293
|
+
asset,
|
|
294
|
+
guard,
|
|
295
|
+
funding
|
|
296
|
+
});
|
|
297
|
+
const prices = {};
|
|
298
|
+
for (const [symbol, usdg] of Object.entries(SANDBOX_PRICES)) {
|
|
299
|
+
(0, import_core2.registerAsset)({ symbol, decimals: 18 });
|
|
300
|
+
prices[`${asset}/${symbol}`] = 1 / usdg;
|
|
301
|
+
prices[`${symbol}/${asset}`] = usdg;
|
|
302
|
+
}
|
|
303
|
+
const trading = (0, import_trading.createTrading)({
|
|
304
|
+
agent,
|
|
305
|
+
guard,
|
|
306
|
+
quoteAsset: asset,
|
|
307
|
+
venues: [(0, import_trading.simulatedVenue)({ name: "sandbox-pool", prices, feeRate: 5e-4 })]
|
|
308
|
+
});
|
|
309
|
+
return { wallet, guard, trading };
|
|
310
|
+
}
|
|
311
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
312
|
+
0 && (module.exports = {
|
|
313
|
+
buildTools,
|
|
314
|
+
createMcpServer,
|
|
315
|
+
createSandbox,
|
|
316
|
+
serveStdio
|
|
317
|
+
});
|
|
318
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/tools.ts","../src/sandbox.ts"],"sourcesContent":["export { createMcpServer, serveStdio, type McpServerOptions } from \"./server.js\";\nexport { buildTools, type McpTools, type McpToolsOptions } from \"./tools.js\";\nexport { createSandbox, type Sandbox, type SandboxOptions } from \"./sandbox.js\";\n","import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { CallToolRequestSchema, ListToolsRequestSchema } from \"@modelcontextprotocol/sdk/types.js\";\nimport { buildTools, type McpToolsOptions } from \"./tools.js\";\n\nexport interface McpServerOptions extends McpToolsOptions {\n /** Server name reported to the host. */\n name?: string;\n version?: string;\n}\n\n/**\n * Wrap a wallet (and optionally a guard and a trading instance) in an MCP\n * server. The transport is yours to choose; `serveStdio` covers the common\n * case of a host that spawns the server as a subprocess.\n */\nexport function createMcpServer(options: McpServerOptions): Server {\n const tools = buildTools(options);\n const server = new Server(\n { name: options.name ?? \"moneo\", version: options.version ?? \"0.1.0\" },\n { capabilities: { tools: {} } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: tools.definitions.map((d) => ({\n name: d.name,\n description: d.description,\n inputSchema: d.inputSchema,\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n try {\n const result = await tools.handle(\n request.params.name,\n (request.params.arguments ?? {}) as Record<string, unknown>,\n );\n return { content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }] };\n } catch (error) {\n // Policy refusals never reach here: they come back as ordinary results\n // with a reason. This path is for genuinely broken calls.\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: \"text\", text: JSON.stringify({ error: message }) }],\n isError: true,\n };\n }\n });\n\n return server;\n}\n\n/** Connect a server to stdio and keep the process alive until the host hangs up. */\nexport async function serveStdio(server: Server): Promise<void> {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","import { formatMoney } from \"@moneolabs/core\";\nimport { PolicyDeniedError, type Guard } from \"@moneolabs/guard\";\nimport type { OrderOptions, OrderResult, Trading } from \"@moneolabs/trading\";\nimport { toolkit, type ToolDefinition, type ToolName, type Wallet } from \"@moneolabs/wallet\";\n\n/**\n * One flat tool surface for an MCP host: the wallet toolkit as-is, plus the\n * trading calls when a trading instance is supplied. Same contract as the\n * toolkit: a refusal is a result with a reason, never an exception, so the\n * model reads why it was stopped instead of retrying blind.\n */\nexport interface McpToolsOptions {\n wallet: Wallet;\n guard?: Guard;\n trading?: Trading;\n /** Restrict the wallet tools. Trading tools ride on `trading` being set. */\n include?: readonly ToolName[];\n}\n\nexport interface McpTools {\n definitions: ToolDefinition[];\n handle(name: string, input: Record<string, unknown>): Promise<unknown>;\n}\n\nexport function buildTools(options: McpToolsOptions): McpTools {\n const walletTools = toolkit(options.wallet, {\n ...(options.guard ? { guard: options.guard } : {}),\n ...(options.include ? { include: options.include } : {}),\n });\n\n const trading = options.trading;\n const tradingTools: Record<string, { definition: ToolDefinition; run: Handler }> = trading\n ? {\n get_quote: {\n definition: {\n name: \"get_quote\",\n description:\n \"Price a trade across every venue that can fill it, without committing to anything. Returns the best route.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sell: { type: \"string\", description: 'Asset given up, for example \"USDG\".' },\n buy: { type: \"string\", description: 'Asset acquired, for example \"AAPLX\".' },\n notional: {\n type: \"string\",\n description: 'How much to spend, for example \"300 USDG\".',\n },\n },\n required: [\"sell\", \"buy\", \"notional\"],\n },\n },\n async run(input) {\n const quote = await trading.quote({\n sell: String(input.sell),\n buy: String(input.buy),\n notional: String(input.notional),\n });\n return {\n quoteId: quote.id,\n venue: quote.venue,\n sells: formatMoney(quote.sellAmount),\n buys: formatMoney(quote.buyAmount),\n price: quote.price,\n fee: formatMoney(quote.fee),\n impact: quote.impact,\n expiresAt: new Date(quote.expiresAt).toISOString(),\n };\n },\n },\n\n execute_order: {\n definition: {\n name: \"execute_order\",\n description:\n \"Quote and execute a trade. Policy runs before anything is signed: a refusal returns the reason and costs nothing. Attach takeProfit and stopLoss to ship the exit with the entry.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sell: { type: \"string\", description: \"Asset given up.\" },\n buy: { type: \"string\", description: \"Asset acquired.\" },\n notional: { type: \"string\", description: 'How much to spend, e.g. \"300 USDG\".' },\n type: {\n type: \"string\",\n enum: [\"market\", \"limit\", \"twap\", \"bracket\"],\n description: \"Order type. Defaults to market.\",\n },\n maxSlippage: {\n type: \"number\",\n description:\n \"Largest acceptable adverse move as a fraction, e.g. 0.003. Exceeding it rejects the order instead of filling it worse.\",\n },\n limitPrice: { type: \"number\", description: \"limit: price to rest at.\" },\n window: {\n type: \"string\",\n description: 'twap: window to spread across, e.g. \"30m\".',\n },\n takeProfit: { type: \"number\", description: \"bracket: exit price above.\" },\n stopLoss: { type: \"number\", description: \"bracket: exit price below.\" },\n },\n required: [\"sell\", \"buy\", \"notional\"],\n },\n },\n async run(input) {\n const orderOptions: OrderOptions = {\n ...(input.type ? { type: input.type as OrderOptions[\"type\"] } : {}),\n ...(typeof input.maxSlippage === \"number\" ? { maxSlippage: input.maxSlippage } : {}),\n ...(typeof input.limitPrice === \"number\" ? { limitPrice: input.limitPrice } : {}),\n ...(input.window ? { window: String(input.window) } : {}),\n ...(typeof input.takeProfit === \"number\" ? { takeProfit: input.takeProfit } : {}),\n ...(typeof input.stopLoss === \"number\" ? { stopLoss: input.stopLoss } : {}),\n };\n try {\n const quote = await trading.quote({\n sell: String(input.sell),\n buy: String(input.buy),\n notional: String(input.notional),\n });\n const order = await trading.execute(quote, orderOptions);\n return { ok: true, ...formatOrder(await order.settled()) };\n } catch (error) {\n if (error instanceof PolicyDeniedError) {\n return {\n ok: false,\n refused: true,\n reason: error.decision.reason,\n rule: error.decision.rule,\n hint: \"This limit is set by the wallet owner. Ask them to raise it rather than retrying.\",\n };\n }\n throw error;\n }\n },\n },\n\n list_positions: {\n definition: {\n name: \"list_positions\",\n description: \"Open positions with cost basis and unrealized P&L at the latest mark.\",\n inputSchema: { type: \"object\", properties: {} },\n },\n async run() {\n return trading.positions().map((p) => ({\n asset: p.asset,\n quantity: formatMoney(p.quantity),\n averageCost: p.averageCost,\n costBasis: formatMoney(p.costBasis),\n marketValue: formatMoney(p.marketValue),\n unrealized: formatMoney(p.unrealized),\n realized: formatMoney(p.realized),\n }));\n },\n },\n\n close_position: {\n definition: {\n name: \"close_position\",\n description:\n \"Exit a position with the same guarantees the entry had: policy first, slippage bound enforced.\",\n inputSchema: {\n type: \"object\",\n properties: {\n asset: { type: \"string\", description: \"Asset to close.\" },\n maxSlippage: {\n type: \"number\",\n description: \"Largest acceptable adverse move as a fraction.\",\n },\n },\n required: [\"asset\"],\n },\n },\n async run(input) {\n try {\n const order = await trading.close(String(input.asset), {\n type: \"market\",\n ...(typeof input.maxSlippage === \"number\"\n ? { maxSlippage: input.maxSlippage }\n : {}),\n });\n return { ok: true, ...formatOrder(await order.settled()) };\n } catch (error) {\n if (error instanceof PolicyDeniedError) {\n return {\n ok: false,\n refused: true,\n reason: error.decision.reason,\n rule: error.decision.rule,\n };\n }\n throw error;\n }\n },\n },\n }\n : {};\n\n return {\n definitions: [\n ...walletTools.definitions,\n ...Object.values(tradingTools).map((tool) => tool.definition),\n ],\n async handle(name, input) {\n const tradingTool = tradingTools[name];\n if (tradingTool) return tradingTool.run(input ?? {});\n return walletTools.handle(name, input ?? {});\n },\n };\n}\n\nfunction formatOrder(result: OrderResult) {\n return {\n orderId: result.id,\n status: result.status,\n type: result.type,\n sell: result.sell,\n buy: result.buy,\n filled: formatMoney(result.filled),\n received: formatMoney(result.received),\n averagePrice: result.averagePrice,\n slippage: result.slippage,\n fees: formatMoney(result.fees),\n ...(result.reason ? { reason: result.reason } : {}),\n ...(result.decision ? { policyVersion: result.decision.policyVersion } : {}),\n };\n}\n\ntype Handler = (input: Record<string, unknown>) => Promise<unknown>;\n","import { readFileSync } from \"node:fs\";\nimport { fixedPrices, registerAsset } from \"@moneolabs/core\";\nimport { createGuard, type Guard, type Policy } from \"@moneolabs/guard\";\nimport { createTrading, simulatedVenue, type Trading } from \"@moneolabs/trading\";\nimport { createWallet, localSigner, memoryRail, type Wallet } from \"@moneolabs/wallet\";\n\n/**\n * The zero-config environment `npx @moneolabs/mcp` serves: a funded wallet on\n * the in-memory rail, a deliberately cautious default policy, and a simulated\n * venue quoting a few tokenized equities. Nothing here touches real value —\n * it exists so an agent host can try the whole surface in one command.\n */\nexport interface SandboxOptions {\n /** Agent identity recorded on every decision. Env: MONEO_AGENT. */\n agent?: string;\n /** Starting balance. Env: MONEO_FUNDING. */\n funding?: string;\n /** Default asset. Env: MONEO_ASSET. */\n asset?: string;\n /** Path to a policy JSON file. Env: MONEO_POLICY. */\n policyPath?: string;\n}\n\nexport interface Sandbox {\n wallet: Wallet;\n guard: Guard;\n trading: Trading;\n}\n\n// Policy amounts are USD; the guard settles them against the dollar-pegged wallet.\nconst DEFAULT_POLICY: Policy = {\n perTransaction: { max: \"$500\" },\n rolling24h: { max: \"$2,000\" },\n velocity: { max: 20, per: \"1m\" },\n counterparties: \"allowlist-only\",\n allow: [\"x402:*\", \"venue:*\", \"vendor:*\"],\n escalate: { above: \"$1,000\" },\n};\n\n/** Simulated marks, in USDG per share. The venue quotes the inverse. */\nconst SANDBOX_PRICES: Record<string, number> = {\n AAPLX: 228.41,\n TSLAX: 312.76,\n NVDAX: 171.34,\n SPYX: 563.02,\n};\n\nexport async function createSandbox(options: SandboxOptions = {}): Promise<Sandbox> {\n const agent = options.agent ?? process.env.MONEO_AGENT ?? \"sandbox-agent\";\n const funding = options.funding ?? process.env.MONEO_FUNDING ?? \"5,000 USDG\";\n const asset = options.asset ?? process.env.MONEO_ASSET ?? \"USDG\";\n const policyPath = options.policyPath ?? process.env.MONEO_POLICY;\n\n const policy: Policy = policyPath\n ? (JSON.parse(readFileSync(policyPath, \"utf8\")) as Policy)\n : DEFAULT_POLICY;\n\n // The guard prices non-pegged assets in USD to enforce dollar limits, so it\n // gets the same marks the venue quotes from.\n const guard = createGuard(policy, { agent, prices: fixedPrices(SANDBOX_PRICES) });\n\n const wallet = await createWallet({\n agent,\n signer: localSigner(),\n rail: memoryRail(),\n asset,\n guard,\n funding,\n });\n\n const prices: Record<string, number> = {};\n for (const [symbol, usdg] of Object.entries(SANDBOX_PRICES)) {\n registerAsset({ symbol, decimals: 18 });\n prices[`${asset}/${symbol}`] = 1 / usdg; // how much of the share one USDG buys\n prices[`${symbol}/${asset}`] = usdg; // and the way back out\n }\n\n const trading = createTrading({\n agent,\n guard,\n quoteAsset: asset,\n venues: [simulatedVenue({ name: \"sandbox-pool\", prices, feeRate: 0.0005 })],\n });\n\n return { wallet, guard, trading };\n}\n"],"mappings":"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","names":["import_core","import_guard","import_wallet"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { Guard } from '@moneolabs/guard';
|
|
3
|
+
import { Trading } from '@moneolabs/trading';
|
|
4
|
+
import { Wallet, ToolName, ToolDefinition } from '@moneolabs/wallet';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One flat tool surface for an MCP host: the wallet toolkit as-is, plus the
|
|
8
|
+
* trading calls when a trading instance is supplied. Same contract as the
|
|
9
|
+
* toolkit: a refusal is a result with a reason, never an exception, so the
|
|
10
|
+
* model reads why it was stopped instead of retrying blind.
|
|
11
|
+
*/
|
|
12
|
+
interface McpToolsOptions {
|
|
13
|
+
wallet: Wallet;
|
|
14
|
+
guard?: Guard;
|
|
15
|
+
trading?: Trading;
|
|
16
|
+
/** Restrict the wallet tools. Trading tools ride on `trading` being set. */
|
|
17
|
+
include?: readonly ToolName[];
|
|
18
|
+
}
|
|
19
|
+
interface McpTools {
|
|
20
|
+
definitions: ToolDefinition[];
|
|
21
|
+
handle(name: string, input: Record<string, unknown>): Promise<unknown>;
|
|
22
|
+
}
|
|
23
|
+
declare function buildTools(options: McpToolsOptions): McpTools;
|
|
24
|
+
|
|
25
|
+
interface McpServerOptions extends McpToolsOptions {
|
|
26
|
+
/** Server name reported to the host. */
|
|
27
|
+
name?: string;
|
|
28
|
+
version?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Wrap a wallet (and optionally a guard and a trading instance) in an MCP
|
|
32
|
+
* server. The transport is yours to choose; `serveStdio` covers the common
|
|
33
|
+
* case of a host that spawns the server as a subprocess.
|
|
34
|
+
*/
|
|
35
|
+
declare function createMcpServer(options: McpServerOptions): Server;
|
|
36
|
+
/** Connect a server to stdio and keep the process alive until the host hangs up. */
|
|
37
|
+
declare function serveStdio(server: Server): Promise<void>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The zero-config environment `npx @moneolabs/mcp` serves: a funded wallet on
|
|
41
|
+
* the in-memory rail, a deliberately cautious default policy, and a simulated
|
|
42
|
+
* venue quoting a few tokenized equities. Nothing here touches real value —
|
|
43
|
+
* it exists so an agent host can try the whole surface in one command.
|
|
44
|
+
*/
|
|
45
|
+
interface SandboxOptions {
|
|
46
|
+
/** Agent identity recorded on every decision. Env: MONEO_AGENT. */
|
|
47
|
+
agent?: string;
|
|
48
|
+
/** Starting balance. Env: MONEO_FUNDING. */
|
|
49
|
+
funding?: string;
|
|
50
|
+
/** Default asset. Env: MONEO_ASSET. */
|
|
51
|
+
asset?: string;
|
|
52
|
+
/** Path to a policy JSON file. Env: MONEO_POLICY. */
|
|
53
|
+
policyPath?: string;
|
|
54
|
+
}
|
|
55
|
+
interface Sandbox {
|
|
56
|
+
wallet: Wallet;
|
|
57
|
+
guard: Guard;
|
|
58
|
+
trading: Trading;
|
|
59
|
+
}
|
|
60
|
+
declare function createSandbox(options?: SandboxOptions): Promise<Sandbox>;
|
|
61
|
+
|
|
62
|
+
export { type McpServerOptions, type McpTools, type McpToolsOptions, type Sandbox, type SandboxOptions, buildTools, createMcpServer, createSandbox, serveStdio };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { Guard } from '@moneolabs/guard';
|
|
3
|
+
import { Trading } from '@moneolabs/trading';
|
|
4
|
+
import { Wallet, ToolName, ToolDefinition } from '@moneolabs/wallet';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One flat tool surface for an MCP host: the wallet toolkit as-is, plus the
|
|
8
|
+
* trading calls when a trading instance is supplied. Same contract as the
|
|
9
|
+
* toolkit: a refusal is a result with a reason, never an exception, so the
|
|
10
|
+
* model reads why it was stopped instead of retrying blind.
|
|
11
|
+
*/
|
|
12
|
+
interface McpToolsOptions {
|
|
13
|
+
wallet: Wallet;
|
|
14
|
+
guard?: Guard;
|
|
15
|
+
trading?: Trading;
|
|
16
|
+
/** Restrict the wallet tools. Trading tools ride on `trading` being set. */
|
|
17
|
+
include?: readonly ToolName[];
|
|
18
|
+
}
|
|
19
|
+
interface McpTools {
|
|
20
|
+
definitions: ToolDefinition[];
|
|
21
|
+
handle(name: string, input: Record<string, unknown>): Promise<unknown>;
|
|
22
|
+
}
|
|
23
|
+
declare function buildTools(options: McpToolsOptions): McpTools;
|
|
24
|
+
|
|
25
|
+
interface McpServerOptions extends McpToolsOptions {
|
|
26
|
+
/** Server name reported to the host. */
|
|
27
|
+
name?: string;
|
|
28
|
+
version?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Wrap a wallet (and optionally a guard and a trading instance) in an MCP
|
|
32
|
+
* server. The transport is yours to choose; `serveStdio` covers the common
|
|
33
|
+
* case of a host that spawns the server as a subprocess.
|
|
34
|
+
*/
|
|
35
|
+
declare function createMcpServer(options: McpServerOptions): Server;
|
|
36
|
+
/** Connect a server to stdio and keep the process alive until the host hangs up. */
|
|
37
|
+
declare function serveStdio(server: Server): Promise<void>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The zero-config environment `npx @moneolabs/mcp` serves: a funded wallet on
|
|
41
|
+
* the in-memory rail, a deliberately cautious default policy, and a simulated
|
|
42
|
+
* venue quoting a few tokenized equities. Nothing here touches real value —
|
|
43
|
+
* it exists so an agent host can try the whole surface in one command.
|
|
44
|
+
*/
|
|
45
|
+
interface SandboxOptions {
|
|
46
|
+
/** Agent identity recorded on every decision. Env: MONEO_AGENT. */
|
|
47
|
+
agent?: string;
|
|
48
|
+
/** Starting balance. Env: MONEO_FUNDING. */
|
|
49
|
+
funding?: string;
|
|
50
|
+
/** Default asset. Env: MONEO_ASSET. */
|
|
51
|
+
asset?: string;
|
|
52
|
+
/** Path to a policy JSON file. Env: MONEO_POLICY. */
|
|
53
|
+
policyPath?: string;
|
|
54
|
+
}
|
|
55
|
+
interface Sandbox {
|
|
56
|
+
wallet: Wallet;
|
|
57
|
+
guard: Guard;
|
|
58
|
+
trading: Trading;
|
|
59
|
+
}
|
|
60
|
+
declare function createSandbox(options?: SandboxOptions): Promise<Sandbox>;
|
|
61
|
+
|
|
62
|
+
export { type McpServerOptions, type McpTools, type McpToolsOptions, type Sandbox, type SandboxOptions, buildTools, createMcpServer, createSandbox, serveStdio };
|