@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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Moneo Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @moneolabs/mcp
|
|
2
|
+
|
|
3
|
+
An MCP server that hands any agent host a guarded wallet — and, when you want it, trading —
|
|
4
|
+
with keys the model never sees and a policy that runs before anything is signed. A refusal
|
|
5
|
+
comes back as a result with a reason, not an exception, so the model reads why it was
|
|
6
|
+
stopped instead of retrying into oblivion.
|
|
7
|
+
|
|
8
|
+
## Try it in one command
|
|
9
|
+
|
|
10
|
+
No API key, no account. The sandbox serves a funded wallet on an in-memory ledger with test
|
|
11
|
+
funds and a simulated venue:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx @moneolabs/mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Claude Code
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
claude mcp add moneo -- npx @moneolabs/mcp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Claude Desktop, Cursor, and friends
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"moneo": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["@moneolabs/mcp"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Tools
|
|
37
|
+
|
|
38
|
+
| Tool | What it does |
|
|
39
|
+
| --------------------- | ------------------------------------------------------------ |
|
|
40
|
+
| `get_balance` | Balance and what is not already committed |
|
|
41
|
+
| `preflight_payment` | Would this payment pass, without making it |
|
|
42
|
+
| `pay` | Pay an address, invoice, or x402 endpoint; policy runs first |
|
|
43
|
+
| `get_spending_limits` | Limits in force and what is left of each budget |
|
|
44
|
+
| `list_payments` | Payments made this session |
|
|
45
|
+
| `get_quote` | Price a trade across venues without committing |
|
|
46
|
+
| `execute_order` | Quote and execute: market, limit, TWAP, or bracket |
|
|
47
|
+
| `list_positions` | Open positions with cost basis and unrealized P&L |
|
|
48
|
+
| `close_position` | Exit with the same guarantees as entry |
|
|
49
|
+
|
|
50
|
+
## Configure the sandbox
|
|
51
|
+
|
|
52
|
+
Environment variables, because MCP host configs pass env:
|
|
53
|
+
|
|
54
|
+
| Variable | Default | |
|
|
55
|
+
| --------------- | ------------------------ | ----------------------------------- |
|
|
56
|
+
| `MONEO_AGENT` | `sandbox-agent` | Identity recorded on every decision |
|
|
57
|
+
| `MONEO_FUNDING` | `5,000 USDG` | Starting balance |
|
|
58
|
+
| `MONEO_ASSET` | `USDG` | Default asset |
|
|
59
|
+
| `MONEO_POLICY` | built-in cautious policy | Path to a policy JSON file |
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"moneo": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["@moneolabs/mcp"],
|
|
67
|
+
"env": {
|
|
68
|
+
"MONEO_POLICY": "/etc/agents/overnight-policy.json",
|
|
69
|
+
"MONEO_FUNDING": "10,000 USDG"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A policy file is the same shape `createGuard` takes:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"perTransaction": { "max": "$400" },
|
|
81
|
+
"rolling24h": { "max": "$2,000" },
|
|
82
|
+
"velocity": { "max": 10, "per": "1h" },
|
|
83
|
+
"counterparties": "allowlist-only",
|
|
84
|
+
"allow": ["x402:*", "venue:*"],
|
|
85
|
+
"escalate": { "above": "$1,000" }
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Serve your own wallet
|
|
90
|
+
|
|
91
|
+
The sandbox is a default, not a ceiling. Wire the server to whatever signer and rail you
|
|
92
|
+
run in production:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { createMcpServer, serveStdio } from "@moneolabs/mcp";
|
|
96
|
+
import { createGuard } from "@moneolabs/guard";
|
|
97
|
+
import { createWallet } from "@moneolabs/wallet";
|
|
98
|
+
|
|
99
|
+
const guard = createGuard(policy);
|
|
100
|
+
const wallet = await createWallet({ agent: "ops-03", signer, rail, guard });
|
|
101
|
+
|
|
102
|
+
await serveStdio(createMcpServer({ wallet, guard, trading }));
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Part of [Moneo](https://github.com/moneolabs/moneo): autonomous finance for AI agents on
|
|
106
|
+
Robinhood Chain. MIT.
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/sandbox.ts
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
import { fixedPrices, registerAsset } from "@moneolabs/core";
|
|
6
|
+
import { createGuard } from "@moneolabs/guard";
|
|
7
|
+
import { createTrading, simulatedVenue } from "@moneolabs/trading";
|
|
8
|
+
import { createWallet, localSigner, memoryRail } from "@moneolabs/wallet";
|
|
9
|
+
var DEFAULT_POLICY = {
|
|
10
|
+
perTransaction: { max: "$500" },
|
|
11
|
+
rolling24h: { max: "$2,000" },
|
|
12
|
+
velocity: { max: 20, per: "1m" },
|
|
13
|
+
counterparties: "allowlist-only",
|
|
14
|
+
allow: ["x402:*", "venue:*", "vendor:*"],
|
|
15
|
+
escalate: { above: "$1,000" }
|
|
16
|
+
};
|
|
17
|
+
var SANDBOX_PRICES = {
|
|
18
|
+
AAPLX: 228.41,
|
|
19
|
+
TSLAX: 312.76,
|
|
20
|
+
NVDAX: 171.34,
|
|
21
|
+
SPYX: 563.02
|
|
22
|
+
};
|
|
23
|
+
async function createSandbox(options = {}) {
|
|
24
|
+
const agent = options.agent ?? process.env.MONEO_AGENT ?? "sandbox-agent";
|
|
25
|
+
const funding = options.funding ?? process.env.MONEO_FUNDING ?? "5,000 USDG";
|
|
26
|
+
const asset = options.asset ?? process.env.MONEO_ASSET ?? "USDG";
|
|
27
|
+
const policyPath = options.policyPath ?? process.env.MONEO_POLICY;
|
|
28
|
+
const policy = policyPath ? JSON.parse(readFileSync(policyPath, "utf8")) : DEFAULT_POLICY;
|
|
29
|
+
const guard = createGuard(policy, { agent, prices: fixedPrices(SANDBOX_PRICES) });
|
|
30
|
+
const wallet = await createWallet({
|
|
31
|
+
agent,
|
|
32
|
+
signer: localSigner(),
|
|
33
|
+
rail: memoryRail(),
|
|
34
|
+
asset,
|
|
35
|
+
guard,
|
|
36
|
+
funding
|
|
37
|
+
});
|
|
38
|
+
const prices = {};
|
|
39
|
+
for (const [symbol, usdg] of Object.entries(SANDBOX_PRICES)) {
|
|
40
|
+
registerAsset({ symbol, decimals: 18 });
|
|
41
|
+
prices[`${asset}/${symbol}`] = 1 / usdg;
|
|
42
|
+
prices[`${symbol}/${asset}`] = usdg;
|
|
43
|
+
}
|
|
44
|
+
const trading = createTrading({
|
|
45
|
+
agent,
|
|
46
|
+
guard,
|
|
47
|
+
quoteAsset: asset,
|
|
48
|
+
venues: [simulatedVenue({ name: "sandbox-pool", prices, feeRate: 5e-4 })]
|
|
49
|
+
});
|
|
50
|
+
return { wallet, guard, trading };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/server.ts
|
|
54
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
55
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
56
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
57
|
+
|
|
58
|
+
// src/tools.ts
|
|
59
|
+
import { formatMoney } from "@moneolabs/core";
|
|
60
|
+
import { PolicyDeniedError } from "@moneolabs/guard";
|
|
61
|
+
import { toolkit } from "@moneolabs/wallet";
|
|
62
|
+
function buildTools(options) {
|
|
63
|
+
const walletTools = toolkit(options.wallet, {
|
|
64
|
+
...options.guard ? { guard: options.guard } : {},
|
|
65
|
+
...options.include ? { include: options.include } : {}
|
|
66
|
+
});
|
|
67
|
+
const trading = options.trading;
|
|
68
|
+
const tradingTools = trading ? {
|
|
69
|
+
get_quote: {
|
|
70
|
+
definition: {
|
|
71
|
+
name: "get_quote",
|
|
72
|
+
description: "Price a trade across every venue that can fill it, without committing to anything. Returns the best route.",
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: {
|
|
76
|
+
sell: { type: "string", description: 'Asset given up, for example "USDG".' },
|
|
77
|
+
buy: { type: "string", description: 'Asset acquired, for example "AAPLX".' },
|
|
78
|
+
notional: {
|
|
79
|
+
type: "string",
|
|
80
|
+
description: 'How much to spend, for example "300 USDG".'
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
required: ["sell", "buy", "notional"]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
async run(input) {
|
|
87
|
+
const quote = await trading.quote({
|
|
88
|
+
sell: String(input.sell),
|
|
89
|
+
buy: String(input.buy),
|
|
90
|
+
notional: String(input.notional)
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
quoteId: quote.id,
|
|
94
|
+
venue: quote.venue,
|
|
95
|
+
sells: formatMoney(quote.sellAmount),
|
|
96
|
+
buys: formatMoney(quote.buyAmount),
|
|
97
|
+
price: quote.price,
|
|
98
|
+
fee: formatMoney(quote.fee),
|
|
99
|
+
impact: quote.impact,
|
|
100
|
+
expiresAt: new Date(quote.expiresAt).toISOString()
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
execute_order: {
|
|
105
|
+
definition: {
|
|
106
|
+
name: "execute_order",
|
|
107
|
+
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.",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: {
|
|
111
|
+
sell: { type: "string", description: "Asset given up." },
|
|
112
|
+
buy: { type: "string", description: "Asset acquired." },
|
|
113
|
+
notional: { type: "string", description: 'How much to spend, e.g. "300 USDG".' },
|
|
114
|
+
type: {
|
|
115
|
+
type: "string",
|
|
116
|
+
enum: ["market", "limit", "twap", "bracket"],
|
|
117
|
+
description: "Order type. Defaults to market."
|
|
118
|
+
},
|
|
119
|
+
maxSlippage: {
|
|
120
|
+
type: "number",
|
|
121
|
+
description: "Largest acceptable adverse move as a fraction, e.g. 0.003. Exceeding it rejects the order instead of filling it worse."
|
|
122
|
+
},
|
|
123
|
+
limitPrice: { type: "number", description: "limit: price to rest at." },
|
|
124
|
+
window: {
|
|
125
|
+
type: "string",
|
|
126
|
+
description: 'twap: window to spread across, e.g. "30m".'
|
|
127
|
+
},
|
|
128
|
+
takeProfit: { type: "number", description: "bracket: exit price above." },
|
|
129
|
+
stopLoss: { type: "number", description: "bracket: exit price below." }
|
|
130
|
+
},
|
|
131
|
+
required: ["sell", "buy", "notional"]
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
async run(input) {
|
|
135
|
+
const orderOptions = {
|
|
136
|
+
...input.type ? { type: input.type } : {},
|
|
137
|
+
...typeof input.maxSlippage === "number" ? { maxSlippage: input.maxSlippage } : {},
|
|
138
|
+
...typeof input.limitPrice === "number" ? { limitPrice: input.limitPrice } : {},
|
|
139
|
+
...input.window ? { window: String(input.window) } : {},
|
|
140
|
+
...typeof input.takeProfit === "number" ? { takeProfit: input.takeProfit } : {},
|
|
141
|
+
...typeof input.stopLoss === "number" ? { stopLoss: input.stopLoss } : {}
|
|
142
|
+
};
|
|
143
|
+
try {
|
|
144
|
+
const quote = await trading.quote({
|
|
145
|
+
sell: String(input.sell),
|
|
146
|
+
buy: String(input.buy),
|
|
147
|
+
notional: String(input.notional)
|
|
148
|
+
});
|
|
149
|
+
const order = await trading.execute(quote, orderOptions);
|
|
150
|
+
return { ok: true, ...formatOrder(await order.settled()) };
|
|
151
|
+
} catch (error) {
|
|
152
|
+
if (error instanceof PolicyDeniedError) {
|
|
153
|
+
return {
|
|
154
|
+
ok: false,
|
|
155
|
+
refused: true,
|
|
156
|
+
reason: error.decision.reason,
|
|
157
|
+
rule: error.decision.rule,
|
|
158
|
+
hint: "This limit is set by the wallet owner. Ask them to raise it rather than retrying."
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
list_positions: {
|
|
166
|
+
definition: {
|
|
167
|
+
name: "list_positions",
|
|
168
|
+
description: "Open positions with cost basis and unrealized P&L at the latest mark.",
|
|
169
|
+
inputSchema: { type: "object", properties: {} }
|
|
170
|
+
},
|
|
171
|
+
async run() {
|
|
172
|
+
return trading.positions().map((p) => ({
|
|
173
|
+
asset: p.asset,
|
|
174
|
+
quantity: formatMoney(p.quantity),
|
|
175
|
+
averageCost: p.averageCost,
|
|
176
|
+
costBasis: formatMoney(p.costBasis),
|
|
177
|
+
marketValue: formatMoney(p.marketValue),
|
|
178
|
+
unrealized: formatMoney(p.unrealized),
|
|
179
|
+
realized: formatMoney(p.realized)
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
close_position: {
|
|
184
|
+
definition: {
|
|
185
|
+
name: "close_position",
|
|
186
|
+
description: "Exit a position with the same guarantees the entry had: policy first, slippage bound enforced.",
|
|
187
|
+
inputSchema: {
|
|
188
|
+
type: "object",
|
|
189
|
+
properties: {
|
|
190
|
+
asset: { type: "string", description: "Asset to close." },
|
|
191
|
+
maxSlippage: {
|
|
192
|
+
type: "number",
|
|
193
|
+
description: "Largest acceptable adverse move as a fraction."
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
required: ["asset"]
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
async run(input) {
|
|
200
|
+
try {
|
|
201
|
+
const order = await trading.close(String(input.asset), {
|
|
202
|
+
type: "market",
|
|
203
|
+
...typeof input.maxSlippage === "number" ? { maxSlippage: input.maxSlippage } : {}
|
|
204
|
+
});
|
|
205
|
+
return { ok: true, ...formatOrder(await order.settled()) };
|
|
206
|
+
} catch (error) {
|
|
207
|
+
if (error instanceof PolicyDeniedError) {
|
|
208
|
+
return {
|
|
209
|
+
ok: false,
|
|
210
|
+
refused: true,
|
|
211
|
+
reason: error.decision.reason,
|
|
212
|
+
rule: error.decision.rule
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} : {};
|
|
220
|
+
return {
|
|
221
|
+
definitions: [
|
|
222
|
+
...walletTools.definitions,
|
|
223
|
+
...Object.values(tradingTools).map((tool) => tool.definition)
|
|
224
|
+
],
|
|
225
|
+
async handle(name, input) {
|
|
226
|
+
const tradingTool = tradingTools[name];
|
|
227
|
+
if (tradingTool) return tradingTool.run(input ?? {});
|
|
228
|
+
return walletTools.handle(name, input ?? {});
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function formatOrder(result) {
|
|
233
|
+
return {
|
|
234
|
+
orderId: result.id,
|
|
235
|
+
status: result.status,
|
|
236
|
+
type: result.type,
|
|
237
|
+
sell: result.sell,
|
|
238
|
+
buy: result.buy,
|
|
239
|
+
filled: formatMoney(result.filled),
|
|
240
|
+
received: formatMoney(result.received),
|
|
241
|
+
averagePrice: result.averagePrice,
|
|
242
|
+
slippage: result.slippage,
|
|
243
|
+
fees: formatMoney(result.fees),
|
|
244
|
+
...result.reason ? { reason: result.reason } : {},
|
|
245
|
+
...result.decision ? { policyVersion: result.decision.policyVersion } : {}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/server.ts
|
|
250
|
+
function createMcpServer(options) {
|
|
251
|
+
const tools = buildTools(options);
|
|
252
|
+
const server2 = new Server(
|
|
253
|
+
{ name: options.name ?? "moneo", version: options.version ?? "0.1.0" },
|
|
254
|
+
{ capabilities: { tools: {} } }
|
|
255
|
+
);
|
|
256
|
+
server2.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
257
|
+
tools: tools.definitions.map((d) => ({
|
|
258
|
+
name: d.name,
|
|
259
|
+
description: d.description,
|
|
260
|
+
inputSchema: d.inputSchema
|
|
261
|
+
}))
|
|
262
|
+
}));
|
|
263
|
+
server2.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
264
|
+
try {
|
|
265
|
+
const result = await tools.handle(
|
|
266
|
+
request.params.name,
|
|
267
|
+
request.params.arguments ?? {}
|
|
268
|
+
);
|
|
269
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
270
|
+
} catch (error) {
|
|
271
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
272
|
+
return {
|
|
273
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
274
|
+
isError: true
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
return server2;
|
|
279
|
+
}
|
|
280
|
+
async function serveStdio(server2) {
|
|
281
|
+
const transport = new StdioServerTransport();
|
|
282
|
+
await server2.connect(transport);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/cli.ts
|
|
286
|
+
var sandbox = await createSandbox();
|
|
287
|
+
var server = createMcpServer({ ...sandbox, name: "moneo-sandbox" });
|
|
288
|
+
console.error(
|
|
289
|
+
`[moneo-mcp] sandbox ledger for "${sandbox.wallet.agent}" \u2014 wallet ${sandbox.wallet.address}, policy ${sandbox.guard.policy.version}. Test funds only; nothing here moves real value.`
|
|
290
|
+
);
|
|
291
|
+
await serveStdio(server);
|
|
292
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sandbox.ts","../src/server.ts","../src/tools.ts","../src/cli.ts"],"sourcesContent":["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","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","#!/usr/bin/env node\n/**\n * `npx @moneolabs/mcp` — serve the sandbox over stdio.\n *\n * Everything runs in this process against test funds. Configuration is\n * environment variables, because MCP host configs pass env, not flags:\n *\n * MONEO_AGENT agent identity on every decision (default sandbox-agent)\n * MONEO_FUNDING starting balance (default \"5,000 USDG\")\n * MONEO_ASSET default asset (default USDG)\n * MONEO_POLICY path to a policy JSON file (default: cautious built-in)\n *\n * Logs go to stderr. Stdout belongs to the protocol.\n */\nimport { createSandbox } from \"./sandbox.js\";\nimport { createMcpServer, serveStdio } from \"./server.js\";\n\nconst sandbox = await createSandbox();\nconst server = createMcpServer({ ...sandbox, name: \"moneo-sandbox\" });\n\nconsole.error(\n `[moneo-mcp] sandbox ledger for \"${sandbox.wallet.agent}\" — ` +\n `wallet ${sandbox.wallet.address}, policy ${sandbox.guard.policy.version}. ` +\n \"Test funds only; nothing here moves real value.\",\n);\n\nawait serveStdio(server);\n"],"mappings":"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","names":["server"]}
|