@carbon-copy/mcp 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/tools.test.js +0 -4
- package/dist/__tests__/tools.test.js.map +1 -1
- package/dist/client.d.ts +11 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +10 -0
- package/dist/client.js.map +1 -1
- package/dist/tools/portfolio.d.ts.map +1 -1
- package/dist/tools/portfolio.js +59 -0
- package/dist/tools/portfolio.js.map +1 -1
- package/package.json +6 -2
- package/.github/workflows/publish.yml +0 -25
- package/CLAUDE.md +0 -69
- package/src/__tests__/client.test.ts +0 -427
- package/src/__tests__/resources.test.ts +0 -263
- package/src/__tests__/tools.test.ts +0 -516
- package/src/client.ts +0 -206
- package/src/index.ts +0 -41
- package/src/resources/portfolio.ts +0 -30
- package/src/resources/traders.ts +0 -29
- package/src/tools/account.ts +0 -48
- package/src/tools/orders.ts +0 -88
- package/src/tools/portfolio.ts +0 -106
- package/src/tools/traders.ts +0 -369
- package/tsconfig.json +0 -17
- package/vitest.config.ts +0 -9
package/src/client.ts
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
const BASE_URL =
|
|
2
|
-
process.env.CARBONCOPY_BASE_URL?.trim() || "https://www.carboncopy.inc";
|
|
3
|
-
|
|
4
|
-
function buildQuery(
|
|
5
|
-
params: Record<string, string | number | undefined>,
|
|
6
|
-
): string {
|
|
7
|
-
const qs = Object.entries(params)
|
|
8
|
-
.filter(([, v]) => v !== undefined)
|
|
9
|
-
.map(
|
|
10
|
-
([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`,
|
|
11
|
-
)
|
|
12
|
-
.join("&");
|
|
13
|
-
return qs ? `?${qs}` : "";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export class CarbonCopyClient {
|
|
17
|
-
private readonly apiKey: string;
|
|
18
|
-
|
|
19
|
-
constructor(apiKey: string) {
|
|
20
|
-
this.apiKey = apiKey;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
private async request<T>(
|
|
24
|
-
method: string,
|
|
25
|
-
path: string,
|
|
26
|
-
body?: unknown,
|
|
27
|
-
): Promise<T> {
|
|
28
|
-
const url = `${BASE_URL}${path}`;
|
|
29
|
-
const headers: Record<string, string> = {
|
|
30
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
31
|
-
"Content-Type": "application/json",
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const res = await fetch(url, {
|
|
35
|
-
method,
|
|
36
|
-
headers,
|
|
37
|
-
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
if (!res.ok) {
|
|
41
|
-
const cloned = res.clone();
|
|
42
|
-
let errorBody: unknown;
|
|
43
|
-
try {
|
|
44
|
-
errorBody = await cloned.json();
|
|
45
|
-
} catch {
|
|
46
|
-
errorBody = await res.text();
|
|
47
|
-
}
|
|
48
|
-
throw new Error(
|
|
49
|
-
`Carbon Copy API error ${res.status} ${res.statusText}: ${JSON.stringify(errorBody)}`,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (res.status === 204 || res.headers.get("content-length") === "0") {
|
|
54
|
-
return undefined as unknown as T;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const text = await res.text();
|
|
58
|
-
if (!text) return undefined as unknown as T;
|
|
59
|
-
return JSON.parse(text) as T;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Portfolio
|
|
63
|
-
getPortfolio(): Promise<unknown> {
|
|
64
|
-
return this.request("GET", "/api/v1/portfolio");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
getPortfolioHistory(params?: {
|
|
68
|
-
limit?: number;
|
|
69
|
-
cursor?: string;
|
|
70
|
-
since?: string;
|
|
71
|
-
until?: string;
|
|
72
|
-
}): Promise<unknown> {
|
|
73
|
-
const qs = buildQuery(params ?? {});
|
|
74
|
-
return this.request("GET", `/api/v1/portfolio/history${qs}`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
getPositions(params?: {
|
|
78
|
-
limit?: number;
|
|
79
|
-
cursor?: string;
|
|
80
|
-
since?: string;
|
|
81
|
-
until?: string;
|
|
82
|
-
}): Promise<unknown> {
|
|
83
|
-
const qs = buildQuery(params ?? {});
|
|
84
|
-
return this.request("GET", `/api/v1/portfolio/positions${qs}`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Traders
|
|
88
|
-
getTraders(): Promise<unknown> {
|
|
89
|
-
return this.request("GET", "/api/v1/portfolio/traders");
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
discoverTraders(params?: {
|
|
93
|
-
q?: string;
|
|
94
|
-
sortBy?: string;
|
|
95
|
-
minVolume?: number;
|
|
96
|
-
minRoi?: number;
|
|
97
|
-
minWinRate?: number;
|
|
98
|
-
limit?: number;
|
|
99
|
-
}): Promise<unknown> {
|
|
100
|
-
const qs = buildQuery(params ?? {});
|
|
101
|
-
return this.request("GET", `/api/v1/traders${qs}`);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
followTrader(body: {
|
|
105
|
-
wallet: string;
|
|
106
|
-
copyPercentage: number;
|
|
107
|
-
maxCopyAmount?: number;
|
|
108
|
-
notificationsEnabled?: boolean;
|
|
109
|
-
}): Promise<unknown> {
|
|
110
|
-
const { wallet, ...rest } = body;
|
|
111
|
-
return this.request("POST", "/api/v1/portfolio/traders", {
|
|
112
|
-
walletAddress: wallet,
|
|
113
|
-
...rest,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
getTrader(wallet: string): Promise<unknown> {
|
|
118
|
-
return this.request(
|
|
119
|
-
"GET",
|
|
120
|
-
`/api/v1/portfolio/traders/${encodeURIComponent(wallet)}`,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
getTraderPerformance(wallet: string): Promise<unknown> {
|
|
125
|
-
return this.request(
|
|
126
|
-
"GET",
|
|
127
|
-
`/api/v1/traders/${encodeURIComponent(wallet)}/performance`,
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
updateTrader(
|
|
132
|
-
wallet: string,
|
|
133
|
-
body: {
|
|
134
|
-
copyPercentage?: number;
|
|
135
|
-
maxCopyAmount?: number;
|
|
136
|
-
notificationsEnabled?: boolean;
|
|
137
|
-
copyTradingEnabled?: boolean;
|
|
138
|
-
},
|
|
139
|
-
): Promise<unknown> {
|
|
140
|
-
return this.request(
|
|
141
|
-
"PATCH",
|
|
142
|
-
`/api/v1/portfolio/traders/${encodeURIComponent(wallet)}`,
|
|
143
|
-
body,
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
batchUpdateTraders(
|
|
148
|
-
updates: Array<{
|
|
149
|
-
walletAddress: string;
|
|
150
|
-
copyPercentage?: number;
|
|
151
|
-
maxCopyAmount?: number;
|
|
152
|
-
notificationsEnabled?: boolean;
|
|
153
|
-
copyTradingEnabled?: boolean;
|
|
154
|
-
}>,
|
|
155
|
-
): Promise<unknown> {
|
|
156
|
-
return this.request("PATCH", "/api/v1/portfolio/traders/batch", {
|
|
157
|
-
updates,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
unfollowTrader(wallet: string): Promise<unknown> {
|
|
162
|
-
return this.request(
|
|
163
|
-
"DELETE",
|
|
164
|
-
`/api/v1/portfolio/traders/${encodeURIComponent(wallet)}`,
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
pauseTrader(wallet: string): Promise<unknown> {
|
|
169
|
-
return this.request(
|
|
170
|
-
"POST",
|
|
171
|
-
`/api/v1/portfolio/traders/${encodeURIComponent(wallet)}/pause`,
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
resumeTrader(wallet: string): Promise<unknown> {
|
|
176
|
-
return this.request(
|
|
177
|
-
"POST",
|
|
178
|
-
`/api/v1/portfolio/traders/${encodeURIComponent(wallet)}/resume`,
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Orders
|
|
183
|
-
getOrders(params?: {
|
|
184
|
-
status?: string;
|
|
185
|
-
limit?: number;
|
|
186
|
-
cursor?: string;
|
|
187
|
-
since?: string;
|
|
188
|
-
until?: string;
|
|
189
|
-
}): Promise<unknown> {
|
|
190
|
-
const qs = buildQuery(params ?? {});
|
|
191
|
-
return this.request("GET", `/api/v1/orders${qs}`);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
getOrder(id: string): Promise<unknown> {
|
|
195
|
-
return this.request("GET", `/api/v1/orders/${encodeURIComponent(id)}`);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Account
|
|
199
|
-
getAccount(): Promise<unknown> {
|
|
200
|
-
return this.request("GET", "/api/v1/account");
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
health(): Promise<unknown> {
|
|
204
|
-
return this.request("GET", "/api/v1/health");
|
|
205
|
-
}
|
|
206
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
-
import { CarbonCopyClient } from "./client.js";
|
|
6
|
-
import { registerPortfolioTools } from "./tools/portfolio.js";
|
|
7
|
-
import { registerTraderTools } from "./tools/traders.js";
|
|
8
|
-
import { registerOrderTools } from "./tools/orders.js";
|
|
9
|
-
import { registerAccountTools } from "./tools/account.js";
|
|
10
|
-
import { registerPortfolioResources } from "./resources/portfolio.js";
|
|
11
|
-
import { registerTraderResources } from "./resources/traders.js";
|
|
12
|
-
|
|
13
|
-
const apiKey = process.env.CARBONCOPY_API_KEY;
|
|
14
|
-
if (!apiKey) {
|
|
15
|
-
console.error(
|
|
16
|
-
"Error: CARBONCOPY_API_KEY environment variable is required.\n" +
|
|
17
|
-
"Set it to your Carbon Copy API key (format: cc_<64 hex chars>)."
|
|
18
|
-
);
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const client = new CarbonCopyClient(apiKey);
|
|
23
|
-
|
|
24
|
-
const server = new McpServer({
|
|
25
|
-
name: "carboncopy",
|
|
26
|
-
version: "0.1.0",
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Register tools
|
|
30
|
-
registerPortfolioTools(server, client);
|
|
31
|
-
registerTraderTools(server, client);
|
|
32
|
-
registerOrderTools(server, client);
|
|
33
|
-
registerAccountTools(server, client);
|
|
34
|
-
|
|
35
|
-
// Register resources
|
|
36
|
-
registerPortfolioResources(server, client);
|
|
37
|
-
registerTraderResources(server, client);
|
|
38
|
-
|
|
39
|
-
// Connect via stdio transport
|
|
40
|
-
const transport = new StdioServerTransport();
|
|
41
|
-
await server.connect(transport);
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { CarbonCopyClient } from "../client.js";
|
|
3
|
-
|
|
4
|
-
export function registerPortfolioResources(
|
|
5
|
-
server: McpServer,
|
|
6
|
-
client: CarbonCopyClient
|
|
7
|
-
): void {
|
|
8
|
-
server.registerResource(
|
|
9
|
-
"portfolio",
|
|
10
|
-
"carboncopy://portfolio",
|
|
11
|
-
{
|
|
12
|
-
title: "Carbon Copy Portfolio",
|
|
13
|
-
description:
|
|
14
|
-
"Current portfolio snapshot including total value, P&L, and allocation.",
|
|
15
|
-
mimeType: "application/json",
|
|
16
|
-
},
|
|
17
|
-
async () => {
|
|
18
|
-
const data = await client.getPortfolio();
|
|
19
|
-
return {
|
|
20
|
-
contents: [
|
|
21
|
-
{
|
|
22
|
-
uri: "carboncopy://portfolio",
|
|
23
|
-
mimeType: "application/json",
|
|
24
|
-
text: JSON.stringify(data ?? {}, null, 2),
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
);
|
|
30
|
-
}
|
package/src/resources/traders.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { CarbonCopyClient } from "../client.js";
|
|
3
|
-
|
|
4
|
-
export function registerTraderResources(
|
|
5
|
-
server: McpServer,
|
|
6
|
-
client: CarbonCopyClient
|
|
7
|
-
): void {
|
|
8
|
-
server.registerResource(
|
|
9
|
-
"traders",
|
|
10
|
-
"carboncopy://traders",
|
|
11
|
-
{
|
|
12
|
-
title: "Carbon Copy Traders",
|
|
13
|
-
description: "List of all traders you are currently following.",
|
|
14
|
-
mimeType: "application/json",
|
|
15
|
-
},
|
|
16
|
-
async () => {
|
|
17
|
-
const data = await client.getTraders();
|
|
18
|
-
return {
|
|
19
|
-
contents: [
|
|
20
|
-
{
|
|
21
|
-
uri: "carboncopy://traders",
|
|
22
|
-
mimeType: "application/json",
|
|
23
|
-
text: JSON.stringify(data ?? [], null, 2),
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
);
|
|
29
|
-
}
|
package/src/tools/account.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { CarbonCopyClient } from "../client.js";
|
|
4
|
-
|
|
5
|
-
export function registerAccountTools(
|
|
6
|
-
server: McpServer,
|
|
7
|
-
client: CarbonCopyClient
|
|
8
|
-
): void {
|
|
9
|
-
server.registerTool(
|
|
10
|
-
"get_account",
|
|
11
|
-
{
|
|
12
|
-
title: "Get Account",
|
|
13
|
-
description:
|
|
14
|
-
"Retrieve your Carbon Copy account details including wallet address, balance, and settings.",
|
|
15
|
-
inputSchema: z.object({}),
|
|
16
|
-
annotations: {
|
|
17
|
-
readOnlyHint: true,
|
|
18
|
-
openWorldHint: false,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
async () => {
|
|
22
|
-
const data = await client.getAccount();
|
|
23
|
-
return {
|
|
24
|
-
content: [{ type: "text", text: JSON.stringify(data ?? { success: true }, null, 2) }],
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
server.registerTool(
|
|
30
|
-
"health",
|
|
31
|
-
{
|
|
32
|
-
title: "Health Check",
|
|
33
|
-
description:
|
|
34
|
-
"Check the health and availability of the Carbon Copy API.",
|
|
35
|
-
inputSchema: z.object({}),
|
|
36
|
-
annotations: {
|
|
37
|
-
readOnlyHint: true,
|
|
38
|
-
openWorldHint: false,
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
async () => {
|
|
42
|
-
const data = await client.health();
|
|
43
|
-
return {
|
|
44
|
-
content: [{ type: "text", text: JSON.stringify(data ?? { success: true }, null, 2) }],
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
);
|
|
48
|
-
}
|
package/src/tools/orders.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import type { CarbonCopyClient } from "../client.js";
|
|
4
|
-
|
|
5
|
-
export function registerOrderTools(
|
|
6
|
-
server: McpServer,
|
|
7
|
-
client: CarbonCopyClient,
|
|
8
|
-
): void {
|
|
9
|
-
server.registerTool(
|
|
10
|
-
"list_orders",
|
|
11
|
-
{
|
|
12
|
-
title: "List Orders",
|
|
13
|
-
description:
|
|
14
|
-
"Retrieve a list of copy-trade orders with optional status filter, pagination, and date range.",
|
|
15
|
-
inputSchema: z.object({
|
|
16
|
-
status: z
|
|
17
|
-
.string()
|
|
18
|
-
.optional()
|
|
19
|
-
.describe(
|
|
20
|
-
"Filter by order status: 'pending', 'filled', 'failed', or 'cancelled'.",
|
|
21
|
-
),
|
|
22
|
-
limit: z
|
|
23
|
-
.number()
|
|
24
|
-
.int()
|
|
25
|
-
.positive()
|
|
26
|
-
.optional()
|
|
27
|
-
.describe("Maximum number of records to return."),
|
|
28
|
-
cursor: z
|
|
29
|
-
.string()
|
|
30
|
-
.optional()
|
|
31
|
-
.describe("Pagination cursor from a previous response."),
|
|
32
|
-
since: z
|
|
33
|
-
.string()
|
|
34
|
-
.optional()
|
|
35
|
-
.describe(
|
|
36
|
-
"ISO 8601 timestamp — only return records after this time.",
|
|
37
|
-
),
|
|
38
|
-
until: z
|
|
39
|
-
.string()
|
|
40
|
-
.optional()
|
|
41
|
-
.describe(
|
|
42
|
-
"ISO 8601 timestamp — only return records before this time.",
|
|
43
|
-
),
|
|
44
|
-
}),
|
|
45
|
-
annotations: {
|
|
46
|
-
readOnlyHint: true,
|
|
47
|
-
openWorldHint: false,
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
async (params) => {
|
|
51
|
-
const data = await client.getOrders(params);
|
|
52
|
-
return {
|
|
53
|
-
content: [
|
|
54
|
-
{
|
|
55
|
-
type: "text",
|
|
56
|
-
text: JSON.stringify(data ?? { success: true }, null, 2),
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
};
|
|
60
|
-
},
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
server.registerTool(
|
|
64
|
-
"get_order",
|
|
65
|
-
{
|
|
66
|
-
title: "Get Order",
|
|
67
|
-
description: "Retrieve details about a specific copy-trade order by ID.",
|
|
68
|
-
inputSchema: z.object({
|
|
69
|
-
id: z.string().describe("The order ID to retrieve."),
|
|
70
|
-
}),
|
|
71
|
-
annotations: {
|
|
72
|
-
readOnlyHint: true,
|
|
73
|
-
openWorldHint: false,
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
async ({ id }) => {
|
|
77
|
-
const data = await client.getOrder(id);
|
|
78
|
-
return {
|
|
79
|
-
content: [
|
|
80
|
-
{
|
|
81
|
-
type: "text",
|
|
82
|
-
text: JSON.stringify(data ?? { success: true }, null, 2),
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
};
|
|
86
|
-
},
|
|
87
|
-
);
|
|
88
|
-
}
|
package/src/tools/portfolio.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { CarbonCopyClient } from "../client.js";
|
|
4
|
-
|
|
5
|
-
export function registerPortfolioTools(
|
|
6
|
-
server: McpServer,
|
|
7
|
-
client: CarbonCopyClient
|
|
8
|
-
): void {
|
|
9
|
-
server.registerTool(
|
|
10
|
-
"get_portfolio",
|
|
11
|
-
{
|
|
12
|
-
title: "Get Portfolio",
|
|
13
|
-
description:
|
|
14
|
-
"Retrieve the current portfolio summary including total value, P&L, and allocation.",
|
|
15
|
-
inputSchema: z.object({}),
|
|
16
|
-
annotations: {
|
|
17
|
-
readOnlyHint: true,
|
|
18
|
-
openWorldHint: false,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
async () => {
|
|
22
|
-
const data = await client.getPortfolio();
|
|
23
|
-
return {
|
|
24
|
-
content: [{ type: "text", text: JSON.stringify(data ?? { success: true }, null, 2) }],
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
server.registerTool(
|
|
30
|
-
"get_portfolio_history",
|
|
31
|
-
{
|
|
32
|
-
title: "Get Portfolio History",
|
|
33
|
-
description:
|
|
34
|
-
"Retrieve paginated copy-trade history with optional date filtering.",
|
|
35
|
-
inputSchema: z.object({
|
|
36
|
-
limit: z
|
|
37
|
-
.number()
|
|
38
|
-
.int()
|
|
39
|
-
.positive()
|
|
40
|
-
.optional()
|
|
41
|
-
.describe("Maximum number of records to return."),
|
|
42
|
-
cursor: z
|
|
43
|
-
.string()
|
|
44
|
-
.optional()
|
|
45
|
-
.describe("Pagination cursor from a previous response."),
|
|
46
|
-
since: z
|
|
47
|
-
.string()
|
|
48
|
-
.optional()
|
|
49
|
-
.describe("ISO 8601 timestamp — only return records after this time."),
|
|
50
|
-
until: z
|
|
51
|
-
.string()
|
|
52
|
-
.optional()
|
|
53
|
-
.describe("ISO 8601 timestamp — only return records before this time."),
|
|
54
|
-
}),
|
|
55
|
-
annotations: {
|
|
56
|
-
readOnlyHint: true,
|
|
57
|
-
openWorldHint: false,
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
async (params) => {
|
|
61
|
-
const data = await client.getPortfolioHistory(params);
|
|
62
|
-
return {
|
|
63
|
-
content: [{ type: "text", text: JSON.stringify(data ?? { success: true }, null, 2) }],
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
server.registerTool(
|
|
69
|
-
"get_positions",
|
|
70
|
-
{
|
|
71
|
-
title: "Get Positions",
|
|
72
|
-
description:
|
|
73
|
-
"Retrieve current or historical portfolio positions with optional pagination and date filtering.",
|
|
74
|
-
inputSchema: z.object({
|
|
75
|
-
limit: z
|
|
76
|
-
.number()
|
|
77
|
-
.int()
|
|
78
|
-
.positive()
|
|
79
|
-
.optional()
|
|
80
|
-
.describe("Maximum number of records to return."),
|
|
81
|
-
cursor: z
|
|
82
|
-
.string()
|
|
83
|
-
.optional()
|
|
84
|
-
.describe("Pagination cursor from a previous response."),
|
|
85
|
-
since: z
|
|
86
|
-
.string()
|
|
87
|
-
.optional()
|
|
88
|
-
.describe("ISO 8601 timestamp — only return records after this time."),
|
|
89
|
-
until: z
|
|
90
|
-
.string()
|
|
91
|
-
.optional()
|
|
92
|
-
.describe("ISO 8601 timestamp — only return records before this time."),
|
|
93
|
-
}),
|
|
94
|
-
annotations: {
|
|
95
|
-
readOnlyHint: true,
|
|
96
|
-
openWorldHint: false,
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
async (params) => {
|
|
100
|
-
const data = await client.getPositions(params);
|
|
101
|
-
return {
|
|
102
|
-
content: [{ type: "text", text: JSON.stringify(data ?? { success: true }, null, 2) }],
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
}
|