@cryptoquant_official/mcp 0.0.7 → 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 +109 -307
- package/dist/auth/storage.d.ts.map +1 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/cache/storage.d.ts +47 -0
- package/dist/cache/storage.d.ts.map +1 -0
- package/dist/cache/storage.js +140 -0
- package/dist/cache/storage.js.map +1 -0
- package/dist/cache/summary.d.ts.map +1 -0
- package/dist/cache/summary.js.map +1 -0
- package/dist/{core/cache → cache}/types.d.ts +0 -25
- package/dist/{core/cache → cache}/types.d.ts.map +1 -1
- package/dist/cache/types.js.map +1 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/{core/config.js → config.js} +1 -1
- package/dist/config.js.map +1 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +16 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -17
- package/dist/index.js.map +1 -1
- package/dist/{core/permissions.d.ts → permissions.d.ts} +1 -1
- package/dist/permissions.d.ts.map +1 -0
- package/dist/{core/permissions.js → permissions.js} +6 -6
- package/dist/permissions.js.map +1 -0
- package/dist/plan-limits.d.ts.map +1 -0
- package/dist/plan-limits.js.map +1 -0
- package/dist/tools/auth.d.ts.map +1 -0
- package/dist/{mcp/tools → tools}/auth.js +8 -10
- package/dist/tools/auth.js.map +1 -0
- package/dist/tools/core.d.ts.map +1 -0
- package/dist/{mcp/tools → tools}/core.js +145 -32
- package/dist/tools/core.js.map +1 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js.map +1 -0
- package/package.json +9 -45
- package/dist/ai-sdk/execute.d.ts +0 -35
- package/dist/ai-sdk/execute.d.ts.map +0 -1
- package/dist/ai-sdk/execute.js +0 -531
- package/dist/ai-sdk/execute.js.map +0 -1
- package/dist/ai-sdk/index.d.ts +0 -51
- package/dist/ai-sdk/index.d.ts.map +0 -1
- package/dist/ai-sdk/index.js +0 -54
- package/dist/ai-sdk/index.js.map +0 -1
- package/dist/ai-sdk/prompts.d.ts +0 -34
- package/dist/ai-sdk/prompts.d.ts.map +0 -1
- package/dist/ai-sdk/prompts.js +0 -74
- package/dist/ai-sdk/prompts.js.map +0 -1
- package/dist/ai-sdk/schemas.d.ts +0 -66
- package/dist/ai-sdk/schemas.d.ts.map +0 -1
- package/dist/ai-sdk/schemas.js +0 -136
- package/dist/ai-sdk/schemas.js.map +0 -1
- package/dist/ai-sdk/tools.d.ts +0 -165
- package/dist/ai-sdk/tools.d.ts.map +0 -1
- package/dist/ai-sdk/tools.js +0 -152
- package/dist/ai-sdk/tools.js.map +0 -1
- package/dist/ai-sdk/types.d.ts +0 -149
- package/dist/ai-sdk/types.d.ts.map +0 -1
- package/dist/ai-sdk/types.js +0 -5
- package/dist/ai-sdk/types.js.map +0 -1
- package/dist/core/auth/storage.d.ts.map +0 -1
- package/dist/core/auth/storage.js.map +0 -1
- package/dist/core/cache/storage.d.ts +0 -110
- package/dist/core/cache/storage.d.ts.map +0 -1
- package/dist/core/cache/storage.js +0 -356
- package/dist/core/cache/storage.js.map +0 -1
- package/dist/core/cache/summary.d.ts.map +0 -1
- package/dist/core/cache/summary.js.map +0 -1
- package/dist/core/cache/types.js.map +0 -1
- package/dist/core/config.d.ts.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/discovery.d.ts.map +0 -1
- package/dist/core/discovery.js.map +0 -1
- package/dist/core/index.d.ts +0 -16
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -19
- package/dist/core/index.js.map +0 -1
- package/dist/core/permissions.d.ts.map +0 -1
- package/dist/core/permissions.js.map +0 -1
- package/dist/core/plan-limits.d.ts.map +0 -1
- package/dist/core/plan-limits.js.map +0 -1
- package/dist/core/utils.d.ts.map +0 -1
- package/dist/core/utils.js.map +0 -1
- package/dist/http/chat-proxy.d.ts +0 -32
- package/dist/http/chat-proxy.d.ts.map +0 -1
- package/dist/http/chat-proxy.js +0 -305
- package/dist/http/chat-proxy.js.map +0 -1
- package/dist/http/index.d.ts +0 -16
- package/dist/http/index.d.ts.map +0 -1
- package/dist/http/index.js +0 -26
- package/dist/http/index.js.map +0 -1
- package/dist/http/server.d.ts +0 -20
- package/dist/http/server.d.ts.map +0 -1
- package/dist/http/server.js +0 -204
- package/dist/http/server.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -6
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.js +0 -6
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/tools/auth.d.ts.map +0 -1
- package/dist/mcp/tools/auth.js.map +0 -1
- package/dist/mcp/tools/core.d.ts.map +0 -1
- package/dist/mcp/tools/core.js.map +0 -1
- package/dist/shared/metrics-data.generated.d.ts +0 -176
- package/dist/shared/metrics-data.generated.d.ts.map +0 -1
- package/dist/shared/metrics-data.generated.js +0 -3077
- package/dist/shared/metrics-data.generated.js.map +0 -1
- /package/dist/{core/auth → auth}/storage.d.ts +0 -0
- /package/dist/{core/auth → auth}/storage.js +0 -0
- /package/dist/{core/cache → cache}/summary.d.ts +0 -0
- /package/dist/{core/cache → cache}/summary.js +0 -0
- /package/dist/{core/cache → cache}/types.js +0 -0
- /package/dist/{core/config.d.ts → config.d.ts} +0 -0
- /package/dist/{core/discovery.d.ts → discovery.d.ts} +0 -0
- /package/dist/{core/discovery.js → discovery.js} +0 -0
- /package/dist/{core/plan-limits.d.ts → plan-limits.d.ts} +0 -0
- /package/dist/{core/plan-limits.js → plan-limits.js} +0 -0
- /package/dist/{mcp/tools → tools}/auth.d.ts +0 -0
- /package/dist/{mcp/tools → tools}/core.d.ts +0 -0
- /package/dist/{core/utils.d.ts → utils.d.ts} +0 -0
- /package/dist/{core/utils.js → utils.js} +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 CryptoQuant
|
|
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
CHANGED
|
@@ -1,381 +1,183 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CryptoQuant MCP Server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>On-Chain Analytics for Claude and AI Coding Agents</strong>
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="#installation">Installation</a> •
|
|
9
|
+
<a href="#mcp-tools">MCP Tools</a> •
|
|
10
|
+
<a href="#authentication">Authentication</a>
|
|
11
|
+
</p>
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
| [**AI SDK**](#mode-2-ai-sdk-nextjs) | Next.js web apps | ✅ | npm package |
|
|
11
|
-
| [**HTTP**](#mode-3-http-chat-proxy) | Any backend / non-Node.js | ❌ | Standalone server |
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What is this?
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
CryptoQuant MCP Server brings on-chain analytics directly into your AI assistant:
|
|
18
|
+
|
|
19
|
+
- **Natural language queries**: Ask in any language - "비트코인 가격 전망?" or "Is BTC overvalued?"
|
|
20
|
+
- **Real-time metrics**: MVRV, SOPR, Exchange Flows, Funding Rates
|
|
21
|
+
- **Market insights**: AI-powered interpretation of on-chain data
|
|
22
|
+
- **Whale tracking**: Monitor large holder movements
|
|
14
23
|
|
|
15
24
|
---
|
|
16
25
|
|
|
17
|
-
##
|
|
26
|
+
## Installation
|
|
18
27
|
|
|
19
|
-
|
|
28
|
+
### Quick Start (Claude Desktop, Cursor, etc.)
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
**Step 1**: Add to your MCP config file:
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"args": ["-y", "@cryptoquant_official/mcp"],
|
|
30
|
-
"env": {
|
|
31
|
-
"CRYPTOQUANT_API_KEY": "your-api-key"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
```
|
|
32
|
+
| App | Config File |
|
|
33
|
+
|-----|-------------|
|
|
34
|
+
| **Claude Desktop (Mac)** | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
35
|
+
| **Claude Desktop (Windows)** | `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
36
|
+
| **Claude Code** | `~/.claude/mcp.json` or project `.mcp.json` |
|
|
37
|
+
| **Cursor** | Project `.cursor/mcp.json` |
|
|
37
38
|
|
|
38
|
-
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
39
39
|
```json
|
|
40
40
|
{
|
|
41
41
|
"mcpServers": {
|
|
42
42
|
"cryptoquant": {
|
|
43
43
|
"command": "npx",
|
|
44
|
-
"args": ["-y", "@cryptoquant_official/mcp"]
|
|
45
|
-
"env": {
|
|
46
|
-
"CRYPTOQUANT_API_KEY": "your-api-key"
|
|
47
|
-
}
|
|
44
|
+
"args": ["-y", "@cryptoquant_official/mcp"]
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
48
|
```
|
|
52
49
|
|
|
53
|
-
Restart your app
|
|
54
|
-
|
|
55
|
-
### Usage
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
User: "Is Bitcoin overvalued?"
|
|
59
|
-
|
|
60
|
-
Claude: Let me check the MVRV ratio...
|
|
61
|
-
→ Calls query_data({ endpoint: "/v1/btc/market-data/mvrv" })
|
|
62
|
-
→ Returns analysis with current valuation status
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
---
|
|
50
|
+
**Step 2**: Restart your app
|
|
66
51
|
|
|
67
|
-
|
|
52
|
+
**Step 3**: Call `initialize()` to verify connection. Done!
|
|
68
53
|
|
|
69
|
-
|
|
54
|
+
### Local Development
|
|
70
55
|
|
|
71
|
-
|
|
56
|
+
For contributors:
|
|
72
57
|
|
|
73
58
|
```bash
|
|
74
|
-
|
|
59
|
+
git clone https://github.com/CryptoQuantOfficial/mcp.git
|
|
60
|
+
cd mcp
|
|
61
|
+
npm install && npm run build
|
|
75
62
|
```
|
|
76
63
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```env
|
|
80
|
-
# .env.local
|
|
81
|
-
ANTHROPIC_API_KEY=sk-ant-...
|
|
82
|
-
CRYPTOQUANT_API_KEY=cq-...
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
> `@ai-sdk/anthropic` automatically reads `ANTHROPIC_API_KEY`.
|
|
86
|
-
|
|
87
|
-
### API Route
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
// app/api/chat/route.ts
|
|
91
|
-
import { streamText } from "ai";
|
|
92
|
-
import { anthropic } from "@ai-sdk/anthropic";
|
|
93
|
-
import { createCryptoQuantTools } from "@cryptoquant_official/mcp/ai-sdk";
|
|
94
|
-
|
|
95
|
-
export const maxDuration = 60;
|
|
96
|
-
|
|
97
|
-
export async function POST(req: Request) {
|
|
98
|
-
const { messages } = await req.json();
|
|
99
|
-
|
|
100
|
-
const result = streamText({
|
|
101
|
-
model: anthropic("claude-sonnet-4-20250514"),
|
|
102
|
-
messages,
|
|
103
|
-
tools: createCryptoQuantTools({
|
|
104
|
-
cryptoquantApiKey: process.env.CRYPTOQUANT_API_KEY!,
|
|
105
|
-
}),
|
|
106
|
-
maxSteps: 5,
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
return result.toDataStreamResponse();
|
|
110
|
-
}
|
|
111
|
-
```
|
|
64
|
+
---
|
|
112
65
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
```tsx
|
|
116
|
-
"use client";
|
|
117
|
-
import { useChat } from "@ai-sdk/react";
|
|
118
|
-
|
|
119
|
-
export function CryptoChat() {
|
|
120
|
-
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();
|
|
121
|
-
|
|
122
|
-
return (
|
|
123
|
-
<div>
|
|
124
|
-
{messages.map((m) => (
|
|
125
|
-
<div key={m.id}>{m.content}</div>
|
|
126
|
-
))}
|
|
127
|
-
<form onSubmit={handleSubmit}>
|
|
128
|
-
<input value={input} onChange={handleInputChange} />
|
|
129
|
-
<button type="submit" disabled={isLoading}>Send</button>
|
|
130
|
-
</form>
|
|
131
|
-
</div>
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
```
|
|
66
|
+
## MCP Tools
|
|
135
67
|
|
|
136
|
-
|
|
68
|
+
The MCP server provides these tools for API access:
|
|
137
69
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
70
|
+
| Tool | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `initialize` | Start session with API key, returns plan info |
|
|
73
|
+
| `discover_endpoints` | Browse 245+ available endpoints |
|
|
74
|
+
| `get_endpoint_info` | Get endpoint parameter details |
|
|
75
|
+
| `query_data` | Query raw API data |
|
|
76
|
+
| `describe_metric` | Get metric descriptions and thresholds |
|
|
77
|
+
| `list_assets` | List supported assets |
|
|
78
|
+
| `reset_session` | Clear session (logout) |
|
|
142
79
|
|
|
143
|
-
|
|
144
|
-
import { cryptoQuantTools } from "@cryptoquant_official/mcp/ai-sdk";
|
|
145
|
-
streamText({ tools: cryptoQuantTools, ... });
|
|
146
|
-
```
|
|
80
|
+
### Supported Assets
|
|
147
81
|
|
|
148
|
-
|
|
82
|
+
BTC, ETH, ALT, Stablecoin, ERC20, TRX, XRP
|
|
149
83
|
|
|
150
84
|
---
|
|
151
85
|
|
|
152
|
-
##
|
|
153
|
-
|
|
154
|
-
Standalone HTTP server for any backend or non-Node.js environments.
|
|
86
|
+
## Natural Language Queries
|
|
155
87
|
|
|
156
|
-
|
|
88
|
+
Ask questions in any language - Claude will route to the right metrics:
|
|
157
89
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
90
|
+
| Query | Intent | Metric |
|
|
91
|
+
|-------|--------|--------|
|
|
92
|
+
| "비트코인 가격 전망이 어때?" | VALUATION | MVRV |
|
|
93
|
+
| "Is BTC overvalued?" | VALUATION | MVRV |
|
|
94
|
+
| "고래들 움직임 보여줘" | WHALE_ACTIVITY | whale-ratio |
|
|
95
|
+
| "What's the funding rate?" | LEVERAGE | funding-rates |
|
|
96
|
+
| "익절/손절 상황?" | PROFIT_BEHAVIOR | SOPR |
|
|
162
97
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
| Endpoint | Method | Description |
|
|
166
|
-
|----------|--------|-------------|
|
|
167
|
-
| `/chat` | POST | Chat with Claude + automatic tool execution |
|
|
168
|
-
| `/tools/schema` | GET | Get Claude API tool definitions |
|
|
169
|
-
| `/health` | GET | Server health check |
|
|
170
|
-
| `/mcp` | POST/GET/DELETE | Streamable HTTP MCP protocol |
|
|
98
|
+
---
|
|
171
99
|
|
|
172
|
-
|
|
100
|
+
## Authentication
|
|
173
101
|
|
|
174
|
-
|
|
175
|
-
curl -X POST http://localhost:3100/chat \
|
|
176
|
-
-H "Content-Type: application/json" \
|
|
177
|
-
-d '{
|
|
178
|
-
"message": "Analyze Bitcoin MVRV",
|
|
179
|
-
"claude_api_key": "sk-ant-...",
|
|
180
|
-
"cryptoquant_api_key": "cq-..."
|
|
181
|
-
}'
|
|
182
|
-
```
|
|
102
|
+
### Option A. Environment Variable (Recommended)
|
|
183
103
|
|
|
184
|
-
|
|
185
|
-
```json
|
|
186
|
-
{
|
|
187
|
-
"message": "Is Bitcoin overvalued?",
|
|
188
|
-
"claude_api_key": "sk-ant-...",
|
|
189
|
-
"cryptoquant_api_key": "cq-...",
|
|
190
|
-
"conversation_id": "optional-session-id",
|
|
191
|
-
"model": "claude-sonnet-4-20250514"
|
|
192
|
-
}
|
|
193
|
-
```
|
|
104
|
+
Add your API key to the MCP config:
|
|
194
105
|
|
|
195
|
-
**Response:**
|
|
196
106
|
```json
|
|
197
107
|
{
|
|
198
|
-
"
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
"conversation_id": "abc-123",
|
|
205
|
-
"usage": { "input_tokens": 150, "output_tokens": 300 }
|
|
206
|
-
}
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Next.js with HTTP Mode
|
|
210
|
-
|
|
211
|
-
```typescript
|
|
212
|
-
// app/api/chat/route.ts
|
|
213
|
-
export async function POST(request: Request) {
|
|
214
|
-
const { message, conversation_id } = await request.json();
|
|
215
|
-
|
|
216
|
-
const response = await fetch("http://localhost:3100/chat", {
|
|
217
|
-
method: "POST",
|
|
218
|
-
headers: { "Content-Type": "application/json" },
|
|
219
|
-
body: JSON.stringify({
|
|
220
|
-
message,
|
|
221
|
-
claude_api_key: process.env.CLAUDE_API_KEY,
|
|
222
|
-
cryptoquant_api_key: process.env.CRYPTOQUANT_API_KEY,
|
|
223
|
-
conversation_id,
|
|
224
|
-
}),
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
return Response.json(await response.json());
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
See [examples/nextjs/](examples/nextjs/) for complete example.
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
## Custom Cache Storage
|
|
236
|
-
|
|
237
|
-
The MCP server caches API discovery data to reduce startup time. By default:
|
|
238
|
-
- **CLI/Local**: File storage (`~/.cryptoquant/discovery-cache.json`)
|
|
239
|
-
- **Web Server**: No caching (requires Redis configuration)
|
|
240
|
-
|
|
241
|
-
### Redis Storage for Web Servers
|
|
242
|
-
|
|
243
|
-
For production web servers or serverless environments, configure Redis storage:
|
|
244
|
-
|
|
245
|
-
```typescript
|
|
246
|
-
// app/lib/cryptoquant-cache.ts
|
|
247
|
-
import { createClient } from "redis";
|
|
248
|
-
import { setRedisStorage, type CacheStorage } from "@cryptoquant_official/mcp";
|
|
249
|
-
|
|
250
|
-
const redis = createClient({ url: process.env.REDIS_URL });
|
|
251
|
-
|
|
252
|
-
export async function configureRedisCache() {
|
|
253
|
-
if (!redis.isOpen) {
|
|
254
|
-
await redis.connect();
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const redisStorage: CacheStorage = {
|
|
258
|
-
type: "redis",
|
|
259
|
-
|
|
260
|
-
async read(apiUrl, apiKeyPrefix) {
|
|
261
|
-
const key = `cryptoquant:cache:${apiUrl}:${apiKeyPrefix}`;
|
|
262
|
-
const data = await redis.get(key);
|
|
263
|
-
return data ? JSON.parse(data) : null;
|
|
264
|
-
},
|
|
265
|
-
|
|
266
|
-
async write(apiUrl, cache) {
|
|
267
|
-
const key = `cryptoquant:cache:${apiUrl}:${cache.metadata.api_key_prefix}`;
|
|
268
|
-
const ttl = 7 * 24 * 60 * 60; // 7 days
|
|
269
|
-
await redis.setEx(key, ttl, JSON.stringify(cache));
|
|
270
|
-
},
|
|
271
|
-
|
|
272
|
-
async invalidate(apiUrl, apiKeyPrefix) {
|
|
273
|
-
if (apiKeyPrefix) {
|
|
274
|
-
await redis.del(`cryptoquant:cache:${apiUrl}:${apiKeyPrefix}`);
|
|
275
|
-
} else {
|
|
276
|
-
const keys = await redis.keys(`cryptoquant:cache:${apiUrl}:*`);
|
|
277
|
-
if (keys.length > 0) await redis.del(keys);
|
|
108
|
+
"mcpServers": {
|
|
109
|
+
"cryptoquant": {
|
|
110
|
+
"command": "npx",
|
|
111
|
+
"args": ["-y", "@cryptoquant_official/mcp"],
|
|
112
|
+
"env": {
|
|
113
|
+
"CRYPTOQUANT_API_KEY": "your-api-key"
|
|
278
114
|
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
async clearAll() {
|
|
282
|
-
const keys = await redis.keys("cryptoquant:cache:*");
|
|
283
|
-
if (keys.length > 0) await redis.del(keys);
|
|
284
|
-
},
|
|
285
|
-
|
|
286
|
-
getPath() {
|
|
287
|
-
return "[redis]";
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
setRedisStorage(redisStorage);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
292
117
|
}
|
|
293
118
|
```
|
|
294
119
|
|
|
295
|
-
|
|
296
|
-
// app/api/chat/route.ts
|
|
297
|
-
import { configureRedisCache } from "@/lib/cryptoquant-cache";
|
|
120
|
+
### Option B. Direct Parameter
|
|
298
121
|
|
|
299
|
-
|
|
300
|
-
await configureRedisCache();
|
|
122
|
+
Call `initialize()` with your API key:
|
|
301
123
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
124
|
+
```
|
|
125
|
+
initialize(api_key="your-api-key")
|
|
305
126
|
```
|
|
306
127
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
Implement this interface for custom storage backends:
|
|
310
|
-
|
|
311
|
-
```typescript
|
|
312
|
-
interface CacheStorage {
|
|
313
|
-
/** Storage type identifier */
|
|
314
|
-
readonly type: "file" | "redis" | "auto";
|
|
128
|
+
The key will be saved to `~/.cryptoquant/credentials` for future sessions.
|
|
315
129
|
|
|
316
|
-
|
|
317
|
-
read(apiUrl: string, apiKeyPrefix?: string): Promise<DiscoveryCacheSchema | null> | DiscoveryCacheSchema | null;
|
|
130
|
+
**Get your API key**: [https://cryptoquant.com/settings/api](https://cryptoquant.com/settings/api)
|
|
318
131
|
|
|
319
|
-
|
|
320
|
-
write(apiUrl: string, cache: DiscoveryCacheSchema): Promise<void> | void;
|
|
132
|
+
### Managing Credentials
|
|
321
133
|
|
|
322
|
-
|
|
323
|
-
|
|
134
|
+
```bash
|
|
135
|
+
# Switch accounts
|
|
136
|
+
reset_session(clear_stored=true)
|
|
137
|
+
initialize(api_key="new-api-key")
|
|
138
|
+
```
|
|
324
139
|
|
|
325
|
-
|
|
326
|
-
clearAll(): Promise<void> | void;
|
|
140
|
+
---
|
|
327
141
|
|
|
328
|
-
|
|
329
|
-
getPath(apiUrl: string): string;
|
|
330
|
-
}
|
|
331
|
-
```
|
|
142
|
+
## Requirements
|
|
332
143
|
|
|
333
|
-
|
|
144
|
+
| Component | Requirement |
|
|
145
|
+
|-----------|-------------|
|
|
146
|
+
| Node.js | v18+ |
|
|
147
|
+
| API Access | [CryptoQuant API key](https://cryptoquant.com/settings/api) |
|
|
334
148
|
|
|
335
149
|
---
|
|
336
150
|
|
|
337
|
-
##
|
|
151
|
+
## License
|
|
338
152
|
|
|
339
|
-
|
|
153
|
+
MIT License - see [LICENSE](LICENSE)
|
|
340
154
|
|
|
341
|
-
|
|
342
|
-
|------|-------------|
|
|
343
|
-
| `initialize` | Start session with API key |
|
|
344
|
-
| `discover_endpoints` | Browse 245+ available API endpoints |
|
|
345
|
-
| `get_endpoint_info` | Get endpoint parameter details |
|
|
346
|
-
| `query_data` | Query raw on-chain data |
|
|
347
|
-
| `describe_metric` | Get metric descriptions and thresholds |
|
|
348
|
-
| `list_assets` | List supported assets |
|
|
349
|
-
| `reset_session` | Clear session / switch accounts |
|
|
155
|
+
---
|
|
350
156
|
|
|
351
|
-
|
|
157
|
+
## Development
|
|
352
158
|
|
|
353
|
-
|
|
159
|
+
### Setup
|
|
354
160
|
|
|
355
|
-
|
|
161
|
+
After cloning the repository, install dependencies to set up git hooks:
|
|
356
162
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
| `ANTHROPIC_API_KEY` | Anthropic API key (AI SDK mode) | - |
|
|
361
|
-
| `MCP_TRANSPORT` | Transport mode (`stdio` / `http`) | `stdio` |
|
|
362
|
-
| `MCP_HTTP_PORT` | HTTP server port | `3100` |
|
|
363
|
-
| `MCP_HTTP_HOST` | HTTP server host | `0.0.0.0` |
|
|
364
|
-
| `MCP_CORS_ORIGINS` | CORS allowed origins | `*` |
|
|
365
|
-
| `DEBUG` | Enable debug logging | - |
|
|
163
|
+
```bash
|
|
164
|
+
npm install
|
|
165
|
+
```
|
|
366
166
|
|
|
367
|
-
|
|
167
|
+
This automatically configures [husky](https://typicode.github.io/husky/) for pre-commit hooks.
|
|
368
168
|
|
|
369
|
-
-
|
|
370
|
-
- CryptoQuant API key
|
|
371
|
-
- Anthropic API key (for AI SDK / HTTP mode)
|
|
169
|
+
### Pre-commit Hooks
|
|
372
170
|
|
|
373
|
-
|
|
171
|
+
When committing changes to `src/`, ESLint runs automatically:
|
|
374
172
|
|
|
375
|
-
-
|
|
376
|
-
-
|
|
377
|
-
-
|
|
173
|
+
- Lint check runs only when files in `src/` are staged
|
|
174
|
+
- Commit is blocked if lint errors are found
|
|
175
|
+
- Fix errors before committing: `npm run lint`
|
|
378
176
|
|
|
379
|
-
|
|
177
|
+
---
|
|
380
178
|
|
|
381
|
-
|
|
179
|
+
<p align="center">
|
|
180
|
+
<a href="https://cryptoquant.com">CryptoQuant</a> •
|
|
181
|
+
<a href="https://docs.cryptoquant.com">Docs</a> •
|
|
182
|
+
<a href="https://github.com/CryptoQuantOfficial/mcp/issues">Issues</a>
|
|
183
|
+
</p>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAQ/C;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAa/C;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CASxC;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAMvC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/F,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AACxD,MAAM,gBAAgB,GAAG,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;AAQ9D,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACjC,SAAS,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,IAAI,GAAsB;QAC9B,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACvC,CAAC;IAEF,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACtF,SAAS,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC;YAAE,OAAO;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAsB,CAAC;QACtF,IAAI,CAAC,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC7C,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,8CAA8C;IAChD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,gBAAgB,CAAC;YAAE,UAAU,CAAC,gBAAgB,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,kCAAkC;IACpC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,gBAAgB,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache storage operations for discovery response caching
|
|
3
|
+
*/
|
|
4
|
+
import { type DiscoveryCacheSchema, type MyDiscoveryRawResponse, type DiscoverySummaryData } from "./types.js";
|
|
5
|
+
import type { UserPlan, PlanLimits, ApiRateLimit } from "../plan-limits.js";
|
|
6
|
+
/**
|
|
7
|
+
* Get cache file path.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getCacheFilePath(_apiUrl: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Check if cache is still valid (not expired and version matches).
|
|
12
|
+
*/
|
|
13
|
+
export declare function isCacheValid(cache: DiscoveryCacheSchema, apiUrl: string, apiKeyPrefix: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Read cache from file.
|
|
16
|
+
* Returns null if cache doesn't exist or is invalid JSON.
|
|
17
|
+
*/
|
|
18
|
+
export declare function readCache(apiUrl: string): DiscoveryCacheSchema | null;
|
|
19
|
+
/**
|
|
20
|
+
* Write cache to file with secure permissions.
|
|
21
|
+
*/
|
|
22
|
+
export declare function writeCache(apiUrl: string, apiKey: string, rawResponse: MyDiscoveryRawResponse, parsed: {
|
|
23
|
+
limits: PlanLimits | null;
|
|
24
|
+
statics: string[];
|
|
25
|
+
apiRateLimit: ApiRateLimit | null;
|
|
26
|
+
}, summary: DiscoverySummaryData, plan: UserPlan): void;
|
|
27
|
+
/**
|
|
28
|
+
* Delete cache file.
|
|
29
|
+
*/
|
|
30
|
+
export declare function invalidateCache(apiUrl: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Delete the cache file.
|
|
33
|
+
*/
|
|
34
|
+
export declare function clearAllCaches(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Calculate cache age in days.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getCacheAgeDays(cache: DiscoveryCacheSchema): number;
|
|
39
|
+
/**
|
|
40
|
+
* Get human-readable cache status string.
|
|
41
|
+
*/
|
|
42
|
+
export declare function getCacheStatus(cache: DiscoveryCacheSchema | null, fromCache: boolean): string;
|
|
43
|
+
/**
|
|
44
|
+
* Get cache file path for user display.
|
|
45
|
+
*/
|
|
46
|
+
export declare function getCachePath(): string;
|
|
47
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/cache/storage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAG1B,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAK5E;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAuBvG;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAmBrE;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,sBAAsB,EACnC,MAAM,EAAE;IACN,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;CACnC,EACD,OAAO,EAAE,oBAAoB,EAC7B,IAAI,EAAE,QAAQ,GACb,IAAI,CA2BN;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAUpD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAQrC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAKnE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAM7F;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|