@cryptoquant_official/mcp 0.0.4 → 0.0.6-alpha
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 +330 -37
- package/dist/ai-sdk/anthropic.d.ts +125 -0
- package/dist/ai-sdk/anthropic.d.ts.map +1 -0
- package/dist/ai-sdk/anthropic.js +278 -0
- package/dist/ai-sdk/anthropic.js.map +1 -0
- package/dist/ai-sdk/execute.d.ts +35 -0
- package/dist/ai-sdk/execute.d.ts.map +1 -0
- package/dist/ai-sdk/execute.js +531 -0
- package/dist/ai-sdk/execute.js.map +1 -0
- package/dist/ai-sdk/index.d.ts +53 -0
- package/dist/ai-sdk/index.d.ts.map +1 -0
- package/dist/ai-sdk/index.js +56 -0
- package/dist/ai-sdk/index.js.map +1 -0
- package/dist/ai-sdk/prompts.d.ts +34 -0
- package/dist/ai-sdk/prompts.d.ts.map +1 -0
- package/dist/ai-sdk/prompts.js +74 -0
- package/dist/ai-sdk/prompts.js.map +1 -0
- package/dist/ai-sdk/schemas.d.ts +66 -0
- package/dist/ai-sdk/schemas.d.ts.map +1 -0
- package/dist/ai-sdk/schemas.js +136 -0
- package/dist/ai-sdk/schemas.js.map +1 -0
- package/dist/ai-sdk/tools.d.ts +165 -0
- package/dist/ai-sdk/tools.d.ts.map +1 -0
- package/dist/ai-sdk/tools.js +152 -0
- package/dist/ai-sdk/tools.js.map +1 -0
- package/dist/ai-sdk/types.d.ts +149 -0
- package/dist/ai-sdk/types.d.ts.map +1 -0
- package/dist/ai-sdk/types.js +5 -0
- package/dist/ai-sdk/types.js.map +1 -0
- package/dist/core/auth/storage.d.ts.map +1 -0
- package/dist/core/auth/storage.js.map +1 -0
- package/dist/core/cache/storage.d.ts +110 -0
- package/dist/core/cache/storage.d.ts.map +1 -0
- package/dist/core/cache/storage.js +356 -0
- package/dist/core/cache/storage.js.map +1 -0
- package/dist/core/cache/summary.d.ts.map +1 -0
- package/dist/core/cache/summary.js.map +1 -0
- package/dist/{cache → core/cache}/types.d.ts +25 -0
- package/dist/{cache → core/cache}/types.d.ts.map +1 -1
- package/dist/core/cache/types.js.map +1 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/discovery.d.ts.map +1 -0
- package/dist/{discovery.js → core/discovery.js} +14 -2
- package/dist/core/discovery.js.map +1 -0
- package/dist/core/index.d.ts +16 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +19 -0
- package/dist/core/index.js.map +1 -0
- package/dist/{permissions.d.ts → core/permissions.d.ts} +2 -2
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/{permissions.js → core/permissions.js} +38 -14
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/plan-limits.d.ts.map +1 -0
- package/dist/core/plan-limits.js.map +1 -0
- package/dist/{utils.d.ts → core/utils.d.ts} +13 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/{utils.js → core/utils.js} +34 -0
- package/dist/core/utils.js.map +1 -0
- package/dist/data/metrics.toon +8 -5
- package/dist/http/chat-proxy.d.ts +32 -0
- package/dist/http/chat-proxy.d.ts.map +1 -0
- package/dist/http/chat-proxy.js +310 -0
- package/dist/http/chat-proxy.js.map +1 -0
- package/dist/http/index.d.ts +12 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +30 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/server.d.ts +20 -0
- package/dist/http/server.d.ts.map +1 -0
- package/dist/http/server.js +231 -0
- package/dist/http/server.js.map +1 -0
- package/dist/shared/metrics-data.generated.d.ts +176 -0
- package/dist/shared/metrics-data.generated.d.ts.map +1 -0
- package/dist/shared/metrics-data.generated.js +3077 -0
- package/dist/shared/metrics-data.generated.js.map +1 -0
- package/dist/stdio/index.d.ts +10 -0
- package/dist/stdio/index.d.ts.map +1 -0
- package/dist/stdio/index.js +30 -0
- package/dist/stdio/index.js.map +1 -0
- package/dist/stdio/tools/auth.d.ts +3 -0
- package/dist/stdio/tools/auth.d.ts.map +1 -0
- package/dist/{tools → stdio/tools}/auth.js +38 -12
- package/dist/stdio/tools/auth.js.map +1 -0
- package/dist/stdio/tools/core.d.ts +3 -0
- package/dist/stdio/tools/core.d.ts.map +1 -0
- package/dist/{tools → stdio/tools}/core.js +122 -162
- package/dist/stdio/tools/core.js.map +1 -0
- package/package.json +55 -14
- package/dist/auth/storage.d.ts.map +0 -1
- package/dist/auth/storage.js.map +0 -1
- package/dist/cache/storage.d.ts +0 -47
- package/dist/cache/storage.d.ts.map +0 -1
- package/dist/cache/storage.js +0 -140
- package/dist/cache/storage.js.map +0 -1
- package/dist/cache/summary.d.ts.map +0 -1
- package/dist/cache/summary.js.map +0 -1
- package/dist/cache/types.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/discovery.d.ts.map +0 -1
- package/dist/discovery.js.map +0 -1
- package/dist/index.d.ts +0 -18
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -46
- package/dist/index.js.map +0 -1
- package/dist/permissions.d.ts.map +0 -1
- package/dist/permissions.js.map +0 -1
- package/dist/plan-limits.d.ts.map +0 -1
- package/dist/plan-limits.js.map +0 -1
- package/dist/tools/auth.d.ts +0 -3
- package/dist/tools/auth.d.ts.map +0 -1
- package/dist/tools/auth.js.map +0 -1
- package/dist/tools/core.d.ts +0 -3
- package/dist/tools/core.d.ts.map +0 -1
- package/dist/tools/core.js.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js.map +0 -1
- /package/dist/{auth → core/auth}/storage.d.ts +0 -0
- /package/dist/{auth → core/auth}/storage.js +0 -0
- /package/dist/{cache → core/cache}/summary.d.ts +0 -0
- /package/dist/{cache → core/cache}/summary.js +0 -0
- /package/dist/{cache → core/cache}/types.js +0 -0
- /package/dist/{config.d.ts → core/config.d.ts} +0 -0
- /package/dist/{config.js → core/config.js} +0 -0
- /package/dist/{discovery.d.ts → core/discovery.d.ts} +0 -0
- /package/dist/{plan-limits.d.ts → core/plan-limits.d.ts} +0 -0
- /package/dist/{plan-limits.js → core/plan-limits.js} +0 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat Proxy Module
|
|
3
|
+
* Handles Claude API integration with automatic tool execution
|
|
4
|
+
*/
|
|
5
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
6
|
+
import { executeDescribeMetric, executeDiscoverEndpoints, executeInitialize, executeMarketSummary, executeQueryData, executeTradingSignal, executeWhaleActivity, } from "../ai-sdk/execute.js";
|
|
7
|
+
import { INTERPRETATION_SYSTEM_PROMPT } from "../shared/metrics-data.generated.js";
|
|
8
|
+
import { logger } from "../core/utils.js";
|
|
9
|
+
const conversations = new Map();
|
|
10
|
+
// Clean up old conversations (older than 1 hour)
|
|
11
|
+
setInterval(() => {
|
|
12
|
+
const maxAge = 60 * 60 * 1000;
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
for (const [id, conv] of conversations) {
|
|
15
|
+
if (now - conv.updated_at > maxAge) {
|
|
16
|
+
conversations.delete(id);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}, 15 * 60 * 1000);
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Claude Tools Definition
|
|
22
|
+
// ============================================================================
|
|
23
|
+
const CLAUDE_TOOLS = [
|
|
24
|
+
{
|
|
25
|
+
name: "initialize",
|
|
26
|
+
description: "Initialize CryptoQuant session. Must be called before querying data.",
|
|
27
|
+
input_schema: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
api_key: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "CryptoQuant API key (optional if already provided)",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
required: [],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "discover_endpoints",
|
|
40
|
+
description: "Discover available API endpoints. Filter by asset (btc, eth, alt, stablecoin, erc20) and/or category (market-data, exchange-flows, network-data, etc.)",
|
|
41
|
+
input_schema: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
asset: {
|
|
45
|
+
type: "string",
|
|
46
|
+
enum: ["btc", "eth", "alt", "stablecoin", "erc20", "trx", "xrp"],
|
|
47
|
+
description: "Asset to filter by",
|
|
48
|
+
},
|
|
49
|
+
category: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "Category filter (e.g., market-data, exchange-flows)",
|
|
52
|
+
},
|
|
53
|
+
query: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Search term to filter endpoints",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
required: [],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "query_data",
|
|
63
|
+
description: "Query on-chain data from CryptoQuant API. Common endpoints: /v1/btc/market-data/mvrv (MVRV ratio), /v1/btc/market-indicator/sopr (SOPR), /v1/btc/exchange-flows/netflow (Exchange netflow)",
|
|
64
|
+
input_schema: {
|
|
65
|
+
type: "object",
|
|
66
|
+
properties: {
|
|
67
|
+
endpoint: {
|
|
68
|
+
type: "string",
|
|
69
|
+
description: "API endpoint path (e.g., /v1/btc/market-data/mvrv)",
|
|
70
|
+
},
|
|
71
|
+
window: {
|
|
72
|
+
type: "string",
|
|
73
|
+
enum: ["hour", "day", "block"],
|
|
74
|
+
description: "Time window granularity",
|
|
75
|
+
},
|
|
76
|
+
limit: {
|
|
77
|
+
type: "number",
|
|
78
|
+
description: "Number of data points to return (default: 30, max: 1000)",
|
|
79
|
+
},
|
|
80
|
+
from: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "Start date in ISO 8601 format (e.g., 2024-01-01)",
|
|
83
|
+
},
|
|
84
|
+
to: {
|
|
85
|
+
type: "string",
|
|
86
|
+
description: "End date in ISO 8601 format",
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
required: ["endpoint"],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "describe_metric",
|
|
94
|
+
description: "Get explanation of a specific metric including thresholds and interpretation guidance. Use when user asks 'what is X?' about metrics like MVRV, SOPR, NUPL, etc.",
|
|
95
|
+
input_schema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
metric_id: {
|
|
99
|
+
type: "string",
|
|
100
|
+
description: "Metric ID (e.g., mvrv, sopr, nupl, netflow)",
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
required: ["metric_id"],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "market_summary",
|
|
108
|
+
description: "Get quick market status summary using key on-chain metrics (MVRV, SOPR, Netflow). Returns overall market sentiment with bullish/bearish signals.",
|
|
109
|
+
input_schema: {
|
|
110
|
+
type: "object",
|
|
111
|
+
properties: {
|
|
112
|
+
asset: {
|
|
113
|
+
type: "string",
|
|
114
|
+
enum: ["btc", "eth"],
|
|
115
|
+
description: "Asset to analyze (default: btc)",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
required: [],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "trading_signal",
|
|
123
|
+
description: "Generate Buy/Sell/Hold trading signal with confidence score based on weighted on-chain metrics. Returns signal (STRONG BUY/BUY/HOLD/CAUTION/SELL) with detailed breakdown.",
|
|
124
|
+
input_schema: {
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: {
|
|
127
|
+
asset: {
|
|
128
|
+
type: "string",
|
|
129
|
+
enum: ["btc", "eth"],
|
|
130
|
+
description: "Asset to analyze (default: btc)",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
required: [],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "whale_activity",
|
|
138
|
+
description: "Monitor whale (large holder) activity including exchange flows and whale ratio. Identifies accumulation or distribution patterns by large players.",
|
|
139
|
+
input_schema: {
|
|
140
|
+
type: "object",
|
|
141
|
+
properties: {
|
|
142
|
+
asset: {
|
|
143
|
+
type: "string",
|
|
144
|
+
enum: ["btc", "eth"],
|
|
145
|
+
description: "Asset to analyze (default: btc)",
|
|
146
|
+
},
|
|
147
|
+
timeframe: {
|
|
148
|
+
type: "string",
|
|
149
|
+
enum: ["24h", "7d", "30d"],
|
|
150
|
+
description: "Timeframe for analysis (default: 24h)",
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
required: [],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
];
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// Tool Execution
|
|
159
|
+
// ============================================================================
|
|
160
|
+
async function executeTool(name, input, cryptoquantApiKey) {
|
|
161
|
+
logger.debug(`[chat-proxy] executing tool: ${name}`, input);
|
|
162
|
+
const context = { cryptoquantApiKey };
|
|
163
|
+
switch (name) {
|
|
164
|
+
case "initialize":
|
|
165
|
+
return executeInitialize({ api_key: input.api_key }, context);
|
|
166
|
+
case "discover_endpoints":
|
|
167
|
+
return executeDiscoverEndpoints({
|
|
168
|
+
asset: input.asset,
|
|
169
|
+
category: input.category,
|
|
170
|
+
query: input.query,
|
|
171
|
+
});
|
|
172
|
+
case "query_data":
|
|
173
|
+
return executeQueryData({
|
|
174
|
+
endpoint: input.endpoint,
|
|
175
|
+
window: input.window,
|
|
176
|
+
limit: input.limit,
|
|
177
|
+
from: input.from,
|
|
178
|
+
to: input.to,
|
|
179
|
+
}, context);
|
|
180
|
+
case "describe_metric":
|
|
181
|
+
return executeDescribeMetric({
|
|
182
|
+
metric_id: input.metric_id,
|
|
183
|
+
});
|
|
184
|
+
case "market_summary":
|
|
185
|
+
return executeMarketSummary({ asset: input.asset || "btc" }, context);
|
|
186
|
+
case "trading_signal":
|
|
187
|
+
return executeTradingSignal({ asset: input.asset || "btc" }, context);
|
|
188
|
+
case "whale_activity":
|
|
189
|
+
return executeWhaleActivity({
|
|
190
|
+
asset: input.asset || "btc",
|
|
191
|
+
timeframe: input.timeframe || "24h",
|
|
192
|
+
}, context);
|
|
193
|
+
default:
|
|
194
|
+
return { error: `Unknown tool: ${name}` };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// Main Chat Handler
|
|
199
|
+
// ============================================================================
|
|
200
|
+
export async function handleChat(request) {
|
|
201
|
+
const { message, claude_api_key, cryptoquant_api_key, conversation_id, model = "claude-sonnet-4-20250514", system_prompt, } = request;
|
|
202
|
+
if (!claude_api_key) {
|
|
203
|
+
return { success: false, error: "claude_api_key is required" };
|
|
204
|
+
}
|
|
205
|
+
const anthropic = new Anthropic({ apiKey: claude_api_key });
|
|
206
|
+
const toolCalls = [];
|
|
207
|
+
// Get or create conversation
|
|
208
|
+
const convId = conversation_id || crypto.randomUUID();
|
|
209
|
+
let conversation = conversations.get(convId);
|
|
210
|
+
if (!conversation) {
|
|
211
|
+
conversation = {
|
|
212
|
+
messages: [],
|
|
213
|
+
cryptoquant_api_key,
|
|
214
|
+
created_at: Date.now(),
|
|
215
|
+
updated_at: Date.now(),
|
|
216
|
+
};
|
|
217
|
+
conversations.set(convId, conversation);
|
|
218
|
+
}
|
|
219
|
+
// Update API key if provided
|
|
220
|
+
if (cryptoquant_api_key) {
|
|
221
|
+
conversation.cryptoquant_api_key = cryptoquant_api_key;
|
|
222
|
+
}
|
|
223
|
+
// Add user message
|
|
224
|
+
conversation.messages.push({ role: "user", content: message });
|
|
225
|
+
conversation.updated_at = Date.now();
|
|
226
|
+
// Use the shared system prompt with comprehensive metric interpretation guidance
|
|
227
|
+
// User-provided system_prompt is appended, not replaced, to prevent prompt injection
|
|
228
|
+
const finalSystemPrompt = system_prompt
|
|
229
|
+
? `${INTERPRETATION_SYSTEM_PROMPT}\n\n--- Additional Instructions ---\n${system_prompt}`
|
|
230
|
+
: INTERPRETATION_SYSTEM_PROMPT;
|
|
231
|
+
try {
|
|
232
|
+
const messages = [...conversation.messages];
|
|
233
|
+
let finalResponse = "";
|
|
234
|
+
let totalInputTokens = 0;
|
|
235
|
+
let totalOutputTokens = 0;
|
|
236
|
+
// Agentic loop - continue until Claude stops calling tools
|
|
237
|
+
while (true) {
|
|
238
|
+
const response = await anthropic.messages.create({
|
|
239
|
+
model,
|
|
240
|
+
max_tokens: 4096,
|
|
241
|
+
system: finalSystemPrompt,
|
|
242
|
+
tools: CLAUDE_TOOLS,
|
|
243
|
+
messages,
|
|
244
|
+
});
|
|
245
|
+
totalInputTokens += response.usage.input_tokens;
|
|
246
|
+
totalOutputTokens += response.usage.output_tokens;
|
|
247
|
+
// Check if Claude wants to use tools
|
|
248
|
+
const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
|
|
249
|
+
if (toolUseBlocks.length === 0) {
|
|
250
|
+
// No more tools, extract final text response
|
|
251
|
+
const textBlocks = response.content.filter((block) => block.type === "text");
|
|
252
|
+
finalResponse = textBlocks
|
|
253
|
+
.map((block) => (block.type === "text" ? block.text : ""))
|
|
254
|
+
.join("\n");
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
// Execute each tool and collect results
|
|
258
|
+
const toolResults = [];
|
|
259
|
+
for (const block of toolUseBlocks) {
|
|
260
|
+
if (block.type !== "tool_use")
|
|
261
|
+
continue;
|
|
262
|
+
const result = await executeTool(block.name, block.input, conversation.cryptoquant_api_key);
|
|
263
|
+
toolCalls.push({
|
|
264
|
+
name: block.name,
|
|
265
|
+
input: block.input,
|
|
266
|
+
result,
|
|
267
|
+
});
|
|
268
|
+
toolResults.push({
|
|
269
|
+
type: "tool_result",
|
|
270
|
+
tool_use_id: block.id,
|
|
271
|
+
content: JSON.stringify(result),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
// Add assistant message and tool results to continue the conversation
|
|
275
|
+
messages.push({ role: "assistant", content: response.content });
|
|
276
|
+
messages.push({ role: "user", content: toolResults });
|
|
277
|
+
}
|
|
278
|
+
// Update conversation history with final response
|
|
279
|
+
conversation.messages.push({
|
|
280
|
+
role: "assistant",
|
|
281
|
+
content: finalResponse,
|
|
282
|
+
});
|
|
283
|
+
return {
|
|
284
|
+
success: true,
|
|
285
|
+
response: finalResponse,
|
|
286
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
287
|
+
conversation_id: convId,
|
|
288
|
+
usage: {
|
|
289
|
+
input_tokens: totalInputTokens,
|
|
290
|
+
output_tokens: totalOutputTokens,
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
// Only log error message, not full error object to avoid leaking sensitive data (API keys)
|
|
296
|
+
const errorMessage = error instanceof Error ? error.message : "Chat request failed";
|
|
297
|
+
logger.error("[chat-proxy] error:", errorMessage);
|
|
298
|
+
return {
|
|
299
|
+
success: false,
|
|
300
|
+
error: errorMessage,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
// ============================================================================
|
|
305
|
+
// Get Tools Schema (for external use)
|
|
306
|
+
// ============================================================================
|
|
307
|
+
export function getToolsSchema() {
|
|
308
|
+
return CLAUDE_TOOLS;
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=chat-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-proxy.js","sourceRoot":"","sources":["../../src/http/chat-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* HTTP module - HTTP server and chat proxy
|
|
4
|
+
*
|
|
5
|
+
* Can be used as:
|
|
6
|
+
* 1. Standalone: node dist/http/index.js
|
|
7
|
+
* 2. Library: import { startHttpServer } from '@cryptoquant_official/mcp/http'
|
|
8
|
+
*/
|
|
9
|
+
export { startHttpServer, cleanupStaleSessions } from "./server.js";
|
|
10
|
+
export { handleChat, getToolsSchema } from "./chat-proxy.js";
|
|
11
|
+
export type { ChatRequest, ChatResponse, ToolCall } from "./chat-proxy.js";
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG;AAKH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC7D,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* HTTP module - HTTP server and chat proxy
|
|
4
|
+
*
|
|
5
|
+
* Can be used as:
|
|
6
|
+
* 1. Standalone: node dist/http/index.js
|
|
7
|
+
* 2. Library: import { startHttpServer } from '@cryptoquant_official/mcp/http'
|
|
8
|
+
*/
|
|
9
|
+
import { logger } from "../core/utils.js";
|
|
10
|
+
// Re-exports for library usage
|
|
11
|
+
export { startHttpServer, cleanupStaleSessions } from "./server.js";
|
|
12
|
+
export { handleChat, getToolsSchema } from "./chat-proxy.js";
|
|
13
|
+
/**
|
|
14
|
+
* HTTP server main entry point
|
|
15
|
+
*/
|
|
16
|
+
async function main() {
|
|
17
|
+
const { startHttpServer } = await import("./server.js");
|
|
18
|
+
await startHttpServer({
|
|
19
|
+
port: parseInt(process.env.MCP_HTTP_PORT ?? "3100", 10),
|
|
20
|
+
host: process.env.MCP_HTTP_HOST ?? "127.0.0.1",
|
|
21
|
+
corsOrigins: process.env.MCP_CORS_ORIGINS ?? "http://localhost:3000,http://localhost:5173",
|
|
22
|
+
enableLegacySse: process.env.MCP_ENABLE_LEGACY_SSE === "true",
|
|
23
|
+
});
|
|
24
|
+
logger.info("CryptoQuant HTTP Server started");
|
|
25
|
+
}
|
|
26
|
+
main().catch((error) => {
|
|
27
|
+
logger.error("Failed to start HTTP server:", error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,+BAA+B;AAC/B,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG7D;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAExD,MAAM,eAAe,CAAC;QACpB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,MAAM,EAAE,EAAE,CAAC;QACvD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,WAAW;QAC9C,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,6CAA6C;QAC1F,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,MAAM;KAC9D,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;AACjD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;IACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Transport Server for MCP
|
|
3
|
+
* Enables web applications to connect to the MCP server via HTTP/SSE
|
|
4
|
+
*/
|
|
5
|
+
interface HttpServerConfig {
|
|
6
|
+
port?: number;
|
|
7
|
+
host?: string;
|
|
8
|
+
corsOrigins?: string | string[];
|
|
9
|
+
enableLegacySse?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Start HTTP server with Streamable HTTP transport
|
|
13
|
+
*/
|
|
14
|
+
export declare function startHttpServer(config?: HttpServerConfig): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Clean up stale sessions (older than 1 hour)
|
|
17
|
+
*/
|
|
18
|
+
export declare function cleanupStaleSessions(): void;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/http/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,UAAU,gBAAgB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA4BD;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqNlF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAW3C"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Transport Server for MCP
|
|
3
|
+
* Enables web applications to connect to the MCP server via HTTP/SSE
|
|
4
|
+
*/
|
|
5
|
+
import express from "express";
|
|
6
|
+
import cors from "cors";
|
|
7
|
+
import rateLimit from "express-rate-limit";
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
10
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
11
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
+
import { randomUUID } from "crypto";
|
|
13
|
+
import { registerAuthTools } from "../stdio/tools/auth.js";
|
|
14
|
+
import { registerCoreTools } from "../stdio/tools/core.js";
|
|
15
|
+
import { logger } from "../core/utils.js";
|
|
16
|
+
import { handleChat, getToolsSchema } from "./chat-proxy.js";
|
|
17
|
+
// Session storage for Streamable HTTP
|
|
18
|
+
const sessions = new Map();
|
|
19
|
+
// Legacy SSE transport storage - Map for multi-client support
|
|
20
|
+
const legacySseSessions = new Map();
|
|
21
|
+
/**
|
|
22
|
+
* Create and configure the MCP server instance
|
|
23
|
+
*/
|
|
24
|
+
function createMcpServer() {
|
|
25
|
+
const server = new McpServer({
|
|
26
|
+
name: "cryptoquant",
|
|
27
|
+
version: "1.0.0",
|
|
28
|
+
});
|
|
29
|
+
registerAuthTools(server);
|
|
30
|
+
registerCoreTools(server);
|
|
31
|
+
return server;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Start HTTP server with Streamable HTTP transport
|
|
35
|
+
*/
|
|
36
|
+
export async function startHttpServer(config = {}) {
|
|
37
|
+
const port = config.port ?? parseInt(process.env.MCP_HTTP_PORT ?? "3100", 10);
|
|
38
|
+
const host = config.host ?? process.env.MCP_HTTP_HOST ?? "127.0.0.1";
|
|
39
|
+
const corsOriginsRaw = config.corsOrigins ?? process.env.MCP_CORS_ORIGINS ?? "http://localhost:3000,http://localhost:5173";
|
|
40
|
+
// Parse comma-separated origins into array, or use as-is if already an array
|
|
41
|
+
const corsOrigins = Array.isArray(corsOriginsRaw)
|
|
42
|
+
? corsOriginsRaw
|
|
43
|
+
: corsOriginsRaw.split(",").map((origin) => origin.trim());
|
|
44
|
+
const enableLegacySse = config.enableLegacySse ?? process.env.MCP_ENABLE_LEGACY_SSE === "true";
|
|
45
|
+
const app = express();
|
|
46
|
+
// Rate limiting - general limiter for all routes
|
|
47
|
+
const generalLimiter = rateLimit({
|
|
48
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
49
|
+
max: 100, // 100 requests per 15 minutes
|
|
50
|
+
message: { error: "Too many requests, please try again later" },
|
|
51
|
+
standardHeaders: true,
|
|
52
|
+
legacyHeaders: false,
|
|
53
|
+
});
|
|
54
|
+
// Stricter rate limit for /chat endpoint (uses external API)
|
|
55
|
+
const chatLimiter = rateLimit({
|
|
56
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
57
|
+
max: 30, // 30 requests per 15 minutes
|
|
58
|
+
message: { error: "Too many chat requests, please try again later" },
|
|
59
|
+
standardHeaders: true,
|
|
60
|
+
legacyHeaders: false,
|
|
61
|
+
});
|
|
62
|
+
// Middleware
|
|
63
|
+
app.use(generalLimiter);
|
|
64
|
+
app.use(cors({
|
|
65
|
+
origin: corsOrigins,
|
|
66
|
+
credentials: true,
|
|
67
|
+
exposedHeaders: ["mcp-session-id"],
|
|
68
|
+
}));
|
|
69
|
+
app.use(express.json());
|
|
70
|
+
// Health check endpoint - minimal info to avoid information disclosure
|
|
71
|
+
app.get("/health", (_req, res) => {
|
|
72
|
+
res.json({ status: "ok" });
|
|
73
|
+
});
|
|
74
|
+
// =========================================================================
|
|
75
|
+
// Chat Proxy Endpoints (Claude API Integration)
|
|
76
|
+
// =========================================================================
|
|
77
|
+
// POST /chat - Chat with Claude + automatic tool execution
|
|
78
|
+
app.post("/chat", chatLimiter, async (req, res) => {
|
|
79
|
+
const chatRequest = req.body;
|
|
80
|
+
if (!chatRequest.message) {
|
|
81
|
+
res.status(400).json({ error: "message is required" });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!chatRequest.claude_api_key) {
|
|
85
|
+
res.status(400).json({ error: "claude_api_key is required" });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const result = await handleChat(chatRequest);
|
|
90
|
+
res.json(result);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
// Only log error message, not full error object to avoid leaking sensitive data
|
|
94
|
+
const errorMessage = error instanceof Error ? error.message : "Chat request failed";
|
|
95
|
+
logger.error("[/chat] error:", errorMessage);
|
|
96
|
+
res.status(500).json({
|
|
97
|
+
success: false,
|
|
98
|
+
error: errorMessage,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
// GET /tools/schema - Get Claude-compatible tool definitions
|
|
103
|
+
app.get("/tools/schema", (_req, res) => {
|
|
104
|
+
res.json({
|
|
105
|
+
tools: getToolsSchema(),
|
|
106
|
+
usage: "Use these tool definitions with Claude API's tool_use feature",
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
// =========================================================================
|
|
110
|
+
// Streamable HTTP Transport (Modern)
|
|
111
|
+
// =========================================================================
|
|
112
|
+
// POST /mcp - Handle MCP requests
|
|
113
|
+
app.post("/mcp", async (req, res) => {
|
|
114
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
115
|
+
const session = sessionId ? sessions.get(sessionId) : undefined;
|
|
116
|
+
// Check if this is an initialization request
|
|
117
|
+
const isInit = isInitializeRequest(req.body);
|
|
118
|
+
if (isInit || !session) {
|
|
119
|
+
// Create new session
|
|
120
|
+
const newSessionId = randomUUID();
|
|
121
|
+
const server = createMcpServer();
|
|
122
|
+
const transport = new StreamableHTTPServerTransport({
|
|
123
|
+
sessionIdGenerator: () => newSessionId,
|
|
124
|
+
onsessioninitialized: (id) => {
|
|
125
|
+
logger.info(`Session initialized: ${id}`);
|
|
126
|
+
sessions.set(id, { transport, createdAt: Date.now() });
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
transport.onclose = () => {
|
|
130
|
+
logger.info(`Session closed: ${newSessionId}`);
|
|
131
|
+
sessions.delete(newSessionId);
|
|
132
|
+
};
|
|
133
|
+
await server.connect(transport);
|
|
134
|
+
await transport.handleRequest(req, res, req.body);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// Use existing session
|
|
138
|
+
await session.transport.handleRequest(req, res, req.body);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
// GET /mcp - SSE stream for server-to-client notifications
|
|
142
|
+
app.get("/mcp", async (req, res) => {
|
|
143
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
144
|
+
if (!sessionId) {
|
|
145
|
+
res.status(400).json({ error: "Missing mcp-session-id header" });
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const session = sessions.get(sessionId);
|
|
149
|
+
if (!session) {
|
|
150
|
+
res.status(404).json({ error: "Session not found" });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
await session.transport.handleRequest(req, res);
|
|
154
|
+
});
|
|
155
|
+
// DELETE /mcp - Close session
|
|
156
|
+
app.delete("/mcp", async (req, res) => {
|
|
157
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
158
|
+
if (!sessionId) {
|
|
159
|
+
res.status(400).json({ error: "Missing mcp-session-id header" });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const session = sessions.get(sessionId);
|
|
163
|
+
if (!session) {
|
|
164
|
+
res.status(404).json({ error: "Session not found" });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
await session.transport.close();
|
|
168
|
+
sessions.delete(sessionId);
|
|
169
|
+
res.status(204).send();
|
|
170
|
+
});
|
|
171
|
+
// =========================================================================
|
|
172
|
+
// Legacy SSE Transport (for backwards compatibility)
|
|
173
|
+
// =========================================================================
|
|
174
|
+
if (enableLegacySse) {
|
|
175
|
+
// GET /sse - Establish SSE connection
|
|
176
|
+
app.get("/sse", async (_req, res) => {
|
|
177
|
+
const sessionId = randomUUID();
|
|
178
|
+
logger.info(`Legacy SSE connection requested: ${sessionId}`);
|
|
179
|
+
const server = createMcpServer();
|
|
180
|
+
// Include session ID in the messages endpoint path
|
|
181
|
+
const transport = new SSEServerTransport(`/messages?sessionId=${sessionId}`, res);
|
|
182
|
+
legacySseSessions.set(sessionId, transport);
|
|
183
|
+
transport.onclose = () => {
|
|
184
|
+
logger.info(`Legacy SSE connection closed: ${sessionId}`);
|
|
185
|
+
legacySseSessions.delete(sessionId);
|
|
186
|
+
};
|
|
187
|
+
await server.connect(transport);
|
|
188
|
+
});
|
|
189
|
+
// POST /messages - Handle client messages for legacy SSE
|
|
190
|
+
app.post("/messages", async (req, res) => {
|
|
191
|
+
const sessionId = req.query.sessionId;
|
|
192
|
+
if (!sessionId) {
|
|
193
|
+
res.status(400).json({ error: "Missing sessionId query parameter" });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const transport = legacySseSessions.get(sessionId);
|
|
197
|
+
if (!transport) {
|
|
198
|
+
res.status(404).json({ error: "Session not found or expired" });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
await transport.handlePostMessage(req, res);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// Start server
|
|
205
|
+
app.listen(port, host, () => {
|
|
206
|
+
logger.info(`CryptoQuant MCP HTTP Server running at http://${host}:${port}`);
|
|
207
|
+
logger.info(` - Chat Proxy: POST /chat`);
|
|
208
|
+
logger.info(` - Tool Schema: GET /tools/schema`);
|
|
209
|
+
logger.info(` - Streamable HTTP: POST/GET/DELETE /mcp`);
|
|
210
|
+
if (enableLegacySse) {
|
|
211
|
+
logger.info(` - Legacy SSE: GET /sse, POST /messages`);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Clean up stale sessions (older than 1 hour)
|
|
217
|
+
*/
|
|
218
|
+
export function cleanupStaleSessions() {
|
|
219
|
+
const maxAge = 60 * 60 * 1000; // 1 hour
|
|
220
|
+
const now = Date.now();
|
|
221
|
+
for (const [id, session] of sessions) {
|
|
222
|
+
if (now - session.createdAt > maxAge) {
|
|
223
|
+
logger.info(`Cleaning up stale session: ${id}`);
|
|
224
|
+
session.transport.close();
|
|
225
|
+
sessions.delete(id);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Run cleanup every 15 minutes
|
|
230
|
+
setInterval(cleanupStaleSessions, 15 * 60 * 1000);
|
|
231
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/http/server.ts"],"names":[],"mappings":"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"}
|