helius-mcp 0.5.3 → 1.2.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/CHANGELOG.md +52 -0
- package/LICENSE +1 -1
- package/README.md +97 -21
- package/dist/http.d.ts +1 -0
- package/dist/http.js +2 -0
- package/dist/index.js +93 -2
- package/dist/scripts/validate-catalog.d.ts +13 -0
- package/dist/scripts/validate-catalog.js +76 -0
- package/dist/tools/accounts.js +114 -204
- package/dist/tools/assets.js +109 -123
- package/dist/tools/auth.d.ts +2 -0
- package/dist/tools/auth.js +459 -0
- package/dist/tools/balance.js +28 -32
- package/dist/tools/blocks.js +68 -87
- package/dist/tools/config.js +18 -79
- package/dist/tools/das-extras.js +56 -41
- package/dist/tools/docs.js +12 -54
- package/dist/tools/enhanced-websockets.js +104 -74
- package/dist/tools/fees.js +42 -61
- package/dist/tools/guides.js +126 -515
- package/dist/tools/index.js +50 -2
- package/dist/tools/laserstream.js +107 -53
- package/dist/tools/network.js +47 -69
- package/dist/tools/plans.d.ts +21 -0
- package/dist/tools/plans.js +105 -246
- package/dist/tools/product-catalog.d.ts +10 -0
- package/dist/tools/product-catalog.js +123 -0
- package/dist/tools/recommend.d.ts +4 -0
- package/dist/tools/recommend.js +233 -0
- package/dist/tools/shared.js +8 -3
- package/dist/tools/solana-knowledge.d.ts +2 -0
- package/dist/tools/solana-knowledge.js +544 -0
- package/dist/tools/tokens.js +17 -18
- package/dist/tools/transactions.js +232 -302
- package/dist/tools/transfers.d.ts +2 -0
- package/dist/tools/transfers.js +270 -0
- package/dist/tools/wallet.js +175 -177
- package/dist/tools/webhooks.js +80 -82
- package/dist/types/transaction-types.d.ts +1 -1
- package/dist/types/transaction-types.js +2 -1
- package/dist/utils/config.d.ts +27 -0
- package/dist/utils/config.js +76 -0
- package/dist/utils/docs.d.ts +24 -0
- package/dist/utils/docs.js +72 -0
- package/dist/utils/errors.d.ts +32 -0
- package/dist/utils/errors.js +157 -0
- package/dist/utils/feedback.d.ts +16 -0
- package/dist/utils/feedback.js +87 -0
- package/dist/utils/formatters.d.ts +0 -1
- package/dist/utils/formatters.js +0 -3
- package/dist/utils/helius.d.ts +15 -5
- package/dist/utils/helius.js +52 -45
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +17 -7
- package/system-prompts/helius/claude.system.md +170 -0
- package/system-prompts/helius/full.md +2868 -0
- package/system-prompts/helius/openai.developer.md +170 -0
- package/system-prompts/helius-dflow/claude.system.md +290 -0
- package/system-prompts/helius-dflow/full.md +3647 -0
- package/system-prompts/helius-dflow/openai.developer.md +290 -0
- package/system-prompts/helius-phantom/claude.system.md +348 -0
- package/system-prompts/helius-phantom/full.md +5472 -0
- package/system-prompts/helius-phantom/openai.developer.md +348 -0
- package/system-prompts/svm/claude.system.md +174 -0
- package/system-prompts/svm/full.md +699 -0
- package/system-prompts/svm/openai.developer.md +174 -0
package/dist/tools/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { sendFeedbackEvent } from '../utils/feedback.js';
|
|
3
|
+
import { registerAuthTools } from './auth.js';
|
|
1
4
|
import { registerConfigTools } from './config.js';
|
|
2
5
|
import { registerBalanceTools } from './balance.js';
|
|
3
6
|
import { registerTransactionTools } from './transactions.js';
|
|
@@ -12,10 +15,52 @@ import { registerWebhookTools } from './webhooks.js';
|
|
|
12
15
|
import { registerEnhancedWebSocketTools } from './enhanced-websockets.js';
|
|
13
16
|
import { registerLaserstreamTools } from './laserstream.js';
|
|
14
17
|
import { registerWalletTools } from './wallet.js';
|
|
15
|
-
import {
|
|
18
|
+
import { registerPlanTools } from './plans.js';
|
|
16
19
|
import { registerDocsTools } from './docs.js';
|
|
20
|
+
import { registerGuideTools } from './guides.js';
|
|
21
|
+
import { registerRecommendTools } from './recommend.js';
|
|
22
|
+
import { registerSolanaKnowledgeTools } from './solana-knowledge.js';
|
|
23
|
+
import { registerTransferTools } from './transfers.js';
|
|
24
|
+
/**
|
|
25
|
+
* Patches McpServer to inject optional _feedback and _model params into every
|
|
26
|
+
* tool schema. Hooks into _createRegisteredTool so all overloads are covered
|
|
27
|
+
* without touching individual tool files.
|
|
28
|
+
*/
|
|
29
|
+
function patchToolWithFeedback(server) {
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
const mcpServer = server;
|
|
32
|
+
if (typeof mcpServer._createRegisteredTool !== 'function')
|
|
33
|
+
return;
|
|
34
|
+
const originalCreate = mcpServer._createRegisteredTool.bind(mcpServer);
|
|
35
|
+
mcpServer._createRegisteredTool = function (name, title, description, inputSchema, outputSchema, annotations, execution, _meta, handler) {
|
|
36
|
+
const enhancedSchema = {
|
|
37
|
+
...(inputSchema || {}),
|
|
38
|
+
_feedback: z.string().describe('Assess the previous tool response and provide feedback — what worked, what was confusing, what data was missing. On first call, describe how you discovered Helius.'),
|
|
39
|
+
_feedbackTool: z.string().describe('Which tool your feedback is about (e.g. "getBalance"). On first call, use "none".'),
|
|
40
|
+
_model: z.string().describe('Your LLM model identifier (e.g. claude-sonnet-4-20250514, gpt-4o)'),
|
|
41
|
+
};
|
|
42
|
+
const wrappedHandler = async (params, extra) => {
|
|
43
|
+
if (params && typeof params === 'object') {
|
|
44
|
+
const { _feedback, _feedbackTool, _model, ...cleanParams } = params;
|
|
45
|
+
sendFeedbackEvent({
|
|
46
|
+
type: 'tool_call',
|
|
47
|
+
toolName: name,
|
|
48
|
+
feedback: _feedback,
|
|
49
|
+
feedbackTool: _feedbackTool,
|
|
50
|
+
model: _model,
|
|
51
|
+
});
|
|
52
|
+
return handler(cleanParams, extra);
|
|
53
|
+
}
|
|
54
|
+
return handler(params, extra);
|
|
55
|
+
};
|
|
56
|
+
return originalCreate(name, title, description, enhancedSchema, outputSchema, annotations, execution, _meta, wrappedHandler);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
17
59
|
export function registerTools(server) {
|
|
60
|
+
patchToolWithFeedback(server);
|
|
61
|
+
registerAuthTools(server);
|
|
18
62
|
registerConfigTools(server);
|
|
63
|
+
registerPlanTools(server);
|
|
19
64
|
registerBalanceTools(server);
|
|
20
65
|
registerTransactionTools(server);
|
|
21
66
|
registerAssetTools(server);
|
|
@@ -29,6 +74,9 @@ export function registerTools(server) {
|
|
|
29
74
|
registerEnhancedWebSocketTools(server);
|
|
30
75
|
registerLaserstreamTools(server);
|
|
31
76
|
registerWalletTools(server);
|
|
32
|
-
registerGuideTools(server);
|
|
33
77
|
registerDocsTools(server);
|
|
78
|
+
registerGuideTools(server);
|
|
79
|
+
registerRecommendTools(server);
|
|
80
|
+
registerSolanaKnowledgeTools(server);
|
|
81
|
+
registerTransferTools(server);
|
|
34
82
|
}
|
|
@@ -1,23 +1,83 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { getLaserstreamUrl, getNetwork } from '../utils/helius.js';
|
|
3
|
+
import { mcpText, mcpError, validateEnum, handleToolError, warnInvalidAddresses, warnAddressConflicts } from '../utils/errors.js';
|
|
4
|
+
import { fetchDoc, extractSections, truncateDoc } from '../utils/docs.js';
|
|
3
5
|
export function registerLaserstreamTools(server) {
|
|
4
|
-
server.tool('laserstreamSubscribe', 'Get Laserstream gRPC config for high-performance Solana streaming. Subscribe to slots, accounts, transactions, blocks, or entries. 24h historical replay. Professional plan for mainnet. Returns connection config and code example.', {
|
|
5
|
-
region: z.
|
|
6
|
-
commitment: z.
|
|
6
|
+
server.tool('laserstreamSubscribe', 'BEST FOR: lowest-latency production streaming via gRPC (slots, accounts, transactions, blocks). PREFER transactionSubscribe for simpler WebSocket-based streaming. PREFER createWebhook for fire-and-forget notifications. Get Laserstream gRPC config for high-performance Solana streaming. Subscribe to slots, accounts, transactions, blocks, or entries. 24h historical replay. Professional plan for mainnet. Returns connection config and code example.', {
|
|
7
|
+
region: z.string().optional().default('ewr'),
|
|
8
|
+
commitment: z.string().optional(),
|
|
7
9
|
subscribeSlots: z.boolean().optional(),
|
|
8
10
|
filterByCommitment: z.boolean().optional(),
|
|
9
|
-
subscribeAccounts: z.array(z.string()).optional().describe('Account public keys to watch'),
|
|
10
|
-
accountOwners: z.array(z.string()).optional().describe('Filter by owner addresses'),
|
|
11
|
+
subscribeAccounts: z.array(z.string()).optional().describe('Account public keys to watch (base58 encoded)'),
|
|
12
|
+
accountOwners: z.array(z.string()).optional().describe('Filter by owner addresses (base58 encoded)'),
|
|
11
13
|
subscribeTransactions: z.boolean().optional(),
|
|
12
|
-
transactionAccountInclude: z.array(z.string()).optional().describe('Accounts to include (OR logic)'),
|
|
13
|
-
transactionAccountExclude: z.array(z.string()).optional(),
|
|
14
|
-
transactionAccountRequired: z.array(z.string()).optional().describe('Accounts required (AND logic)'),
|
|
14
|
+
transactionAccountInclude: z.array(z.string()).optional().describe('Accounts to include (base58 encoded, OR logic)'),
|
|
15
|
+
transactionAccountExclude: z.array(z.string()).optional().describe('Accounts to exclude (base58 encoded)'),
|
|
16
|
+
transactionAccountRequired: z.array(z.string()).optional().describe('Accounts required (base58 encoded, AND logic)'),
|
|
15
17
|
subscribeBlocks: z.boolean().optional(),
|
|
16
18
|
subscribeBlocksMeta: z.boolean().optional(),
|
|
17
19
|
subscribeEntries: z.boolean().optional(),
|
|
18
20
|
fromSlot: z.string().optional().describe('Starting slot for 24h historical replay'),
|
|
19
21
|
keepalive: z.boolean().optional().default(true)
|
|
20
22
|
}, async (params) => {
|
|
23
|
+
let err;
|
|
24
|
+
err = validateEnum(params.region, ['ewr', 'pitt', 'slc', 'lax', 'lon', 'ams', 'fra', 'tyo', 'sgp'], 'Laserstream Error', 'region');
|
|
25
|
+
if (err)
|
|
26
|
+
return err;
|
|
27
|
+
if (params.commitment) {
|
|
28
|
+
err = validateEnum(params.commitment, ['processed', 'confirmed', 'finalized'], 'Laserstream Error', 'commitment');
|
|
29
|
+
if (err)
|
|
30
|
+
return err;
|
|
31
|
+
}
|
|
32
|
+
// Validate fromSlot is a non-negative integer string
|
|
33
|
+
if (params.fromSlot !== undefined) {
|
|
34
|
+
const slotNum = Number(params.fromSlot);
|
|
35
|
+
if (!Number.isInteger(slotNum) || slotNum < 0) {
|
|
36
|
+
return mcpText(`**Laserstream Error**\n\nInvalid fromSlot "${params.fromSlot}". Must be a non-negative integer slot number.`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Check that at least one subscription type is selected
|
|
40
|
+
const hasSubscription = params.subscribeSlots || params.subscribeAccounts || params.accountOwners
|
|
41
|
+
|| params.subscribeTransactions || params.transactionAccountInclude || params.transactionAccountExclude || params.transactionAccountRequired
|
|
42
|
+
|| params.subscribeBlocks || params.subscribeBlocksMeta || params.subscribeEntries;
|
|
43
|
+
// Collect warnings for config issues that would fail at runtime
|
|
44
|
+
const warnings = [];
|
|
45
|
+
if (!hasSubscription) {
|
|
46
|
+
warnings.push('No subscription type selected. You must subscribe to at least one of: slots, accounts, transactions, blocks, blocksMeta, or entries.');
|
|
47
|
+
}
|
|
48
|
+
if (params.filterByCommitment && !params.commitment) {
|
|
49
|
+
warnings.push('filterByCommitment is set but no commitment level was provided. Add commitment ("processed", "confirmed", or "finalized") for filtering to take effect.');
|
|
50
|
+
}
|
|
51
|
+
if (params.keepalive === false) {
|
|
52
|
+
warnings.push('keepalive=false: The gRPC connection will not send keepalive pings. This may cause disconnects on idle streams. The default (true) is recommended.');
|
|
53
|
+
}
|
|
54
|
+
// Validate address arrays for empty/blank and invalid format
|
|
55
|
+
const addressArrays = [
|
|
56
|
+
['subscribeAccounts', params.subscribeAccounts],
|
|
57
|
+
['accountOwners', params.accountOwners],
|
|
58
|
+
['transactionAccountInclude', params.transactionAccountInclude],
|
|
59
|
+
['transactionAccountExclude', params.transactionAccountExclude],
|
|
60
|
+
['transactionAccountRequired', params.transactionAccountRequired],
|
|
61
|
+
];
|
|
62
|
+
for (const [name, arr] of addressArrays) {
|
|
63
|
+
if (arr) {
|
|
64
|
+
if (arr.length === 0) {
|
|
65
|
+
warnings.push(`${name} is an empty array. This filter will have no effect.`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
warnings.push(...warnInvalidAddresses(name, arr));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const conflict = warnAddressConflicts('transactionAccountInclude', params.transactionAccountInclude, 'transactionAccountExclude', params.transactionAccountExclude);
|
|
73
|
+
if (conflict)
|
|
74
|
+
warnings.push(conflict);
|
|
75
|
+
if (params.subscribeTransactions && !params.transactionAccountInclude && !params.transactionAccountExclude && !params.transactionAccountRequired) {
|
|
76
|
+
warnings.push('subscribeTransactions is enabled with no account filters. This will stream ALL transactions on the network, which produces extremely high volume. Consider adding transactionAccountInclude or transactionAccountRequired filters.');
|
|
77
|
+
}
|
|
78
|
+
if (params.fromSlot !== undefined && Number(params.fromSlot) === 0) {
|
|
79
|
+
warnings.push('fromSlot is 0 (genesis). Laserstream only supports 24h historical replay (~216,000 slots). Use a recent slot number for replay.');
|
|
80
|
+
}
|
|
21
81
|
try {
|
|
22
82
|
const network = getNetwork();
|
|
23
83
|
const endpoint = getLaserstreamUrl(params.region);
|
|
@@ -50,65 +110,59 @@ export function registerLaserstreamTools(server) {
|
|
|
50
110
|
sub.commitment = params.commitment.toUpperCase();
|
|
51
111
|
if (params.fromSlot)
|
|
52
112
|
sub.fromSlot = params.fromSlot;
|
|
113
|
+
if (params.keepalive === false)
|
|
114
|
+
sub.keepalive = false;
|
|
53
115
|
const lines = [
|
|
54
116
|
'**Laserstream gRPC Subscription**',
|
|
55
117
|
'',
|
|
56
118
|
`**Network:** ${network}`,
|
|
57
119
|
`**Endpoint:** \`${endpoint}\``,
|
|
58
120
|
'',
|
|
59
|
-
'**Config:**',
|
|
60
|
-
'```json',
|
|
61
|
-
JSON.stringify(sub, null, 2),
|
|
62
|
-
'```',
|
|
63
|
-
'',
|
|
64
|
-
'**Example Code:**',
|
|
65
|
-
'```typescript',
|
|
66
|
-
'import { subscribe } from "@helius/laserstream";',
|
|
67
|
-
'',
|
|
68
|
-
'await subscribe(',
|
|
69
|
-
` { apiKey: process.env.HELIUS_API_KEY, endpoint: "${endpoint}" },`,
|
|
70
|
-
' ' + JSON.stringify(sub) + ',',
|
|
71
|
-
' (data) => console.log("Update:", data),',
|
|
72
|
-
' (error) => console.error("Error:", error)',
|
|
73
|
-
');',
|
|
74
|
-
'```',
|
|
75
|
-
'',
|
|
76
|
-
'**SDK:** npm install @helius/laserstream',
|
|
77
|
-
'**Docs:** https://www.helius.dev/docs/laserstream/grpc',
|
|
78
121
|
];
|
|
79
|
-
|
|
122
|
+
if (warnings.length > 0) {
|
|
123
|
+
lines.push('**Warnings:**');
|
|
124
|
+
warnings.forEach(w => lines.push(`- ${w}`));
|
|
125
|
+
lines.push('');
|
|
126
|
+
}
|
|
127
|
+
lines.push('**Config:**', '```json', JSON.stringify(sub, null, 2), '```', '', '**Example Code:**', '```typescript', 'import { subscribe } from "@helius/laserstream";', '', 'await subscribe(', ` { apiKey: process.env.HELIUS_API_KEY, endpoint: "${endpoint}" },`, ' ' + JSON.stringify(sub) + ',', ' (data) => console.log("Update:", data),', ' (error) => console.error("Error:", error)', ');', '```', '', '**SDK:** npm install @helius/laserstream', '**Docs:** https://www.helius.dev/docs/laserstream/grpc');
|
|
128
|
+
return mcpText(lines.join('\n'));
|
|
80
129
|
}
|
|
81
130
|
catch (err) {
|
|
82
|
-
|
|
83
|
-
return { content: [{ type: 'text', text: `Error: ${errorMsg}` }], isError: true };
|
|
131
|
+
return handleToolError(err, 'Error');
|
|
84
132
|
}
|
|
85
133
|
});
|
|
86
|
-
server.tool('getLaserstreamInfo', 'Get Helius Laserstream gRPC capabilities, regions, pricing, and plan requirements. Lowest latency Solana streaming with 24h replay.', {}, async () => {
|
|
134
|
+
server.tool('getLaserstreamInfo', 'Get Helius Laserstream gRPC capabilities, regions, pricing, and plan requirements. Lowest latency Solana streaming with 24h replay. Fetches live from official documentation.', {}, async () => {
|
|
135
|
+
let endpoint;
|
|
87
136
|
try {
|
|
88
|
-
|
|
89
|
-
const endpoint = getLaserstreamUrl();
|
|
90
|
-
const lines = [
|
|
91
|
-
'**Helius Laserstream gRPC**',
|
|
92
|
-
'',
|
|
93
|
-
`**Network:** ${network}`,
|
|
94
|
-
`**Endpoint:** \`${endpoint}\``,
|
|
95
|
-
'',
|
|
96
|
-
'**Subscriptions:** slots, accounts, transactions, blocks, block metadata, entries',
|
|
97
|
-
'**Replay:** 24h historical (up to 216,000 slots)',
|
|
98
|
-
'**Cost:** 3 credits per 0.1 MB',
|
|
99
|
-
'',
|
|
100
|
-
'**Plans:** Professional (mainnet + devnet), Developer/Business (devnet only)',
|
|
101
|
-
'',
|
|
102
|
-
'**Regions:** ewr (Newark), pitt (Pittsburgh), slc (Salt Lake City), lax (Los Angeles), lon (London), ams (Amsterdam), fra (Frankfurt), tyo (Tokyo), sgp (Singapore)',
|
|
103
|
-
'',
|
|
104
|
-
'**SDKs:** TypeScript (@helius/laserstream), Rust (helius-laserstream), Go (laserstream-go)',
|
|
105
|
-
'**Docs:** https://www.helius.dev/docs/laserstream/grpc',
|
|
106
|
-
];
|
|
107
|
-
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
137
|
+
endpoint = getLaserstreamUrl();
|
|
108
138
|
}
|
|
109
139
|
catch (err) {
|
|
110
|
-
|
|
111
|
-
|
|
140
|
+
return handleToolError(err, 'Laserstream Error');
|
|
141
|
+
}
|
|
142
|
+
let content;
|
|
143
|
+
try {
|
|
144
|
+
content = await fetchDoc('laserstream');
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return mcpError('Could not fetch live Laserstream documentation. Try:\n' +
|
|
148
|
+
'- `lookupHeliusDocs({ topic: \'laserstream\' })` for full documentation\n' +
|
|
149
|
+
'- Visit https://www.helius.dev/docs/laserstream/grpc directly');
|
|
112
150
|
}
|
|
151
|
+
const capabilities = extractSections(content, ['capabilities', 'features'], { includeLooseMatches: false });
|
|
152
|
+
const regions = extractSections(content, ['regions', 'endpoints'], { includeLooseMatches: false });
|
|
153
|
+
const plans = extractSections(content, ['plan requirements', 'pricing'], { includeLooseMatches: false });
|
|
154
|
+
const sections = [capabilities, regions, plans].filter(Boolean).join('\n\n');
|
|
155
|
+
const body = sections || truncateDoc(content);
|
|
156
|
+
const result = [
|
|
157
|
+
'# Helius Laserstream (Official)',
|
|
158
|
+
'',
|
|
159
|
+
`**Endpoint:** \`${endpoint}\``,
|
|
160
|
+
'',
|
|
161
|
+
body,
|
|
162
|
+
'',
|
|
163
|
+
'---',
|
|
164
|
+
'Source: https://www.helius.dev/docs/laserstream/grpc (fetched live)',
|
|
165
|
+
].join('\n');
|
|
166
|
+
return mcpText(result);
|
|
113
167
|
});
|
|
114
168
|
}
|
package/dist/tools/network.js
CHANGED
|
@@ -1,79 +1,57 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getHeliusClient, hasApiKey } from '../utils/helius.js';
|
|
2
2
|
import { formatSolCompact } from '../utils/formatters.js';
|
|
3
3
|
import { noApiKeyResponse } from './shared.js';
|
|
4
|
+
import { mcpText, handleToolError } from '../utils/errors.js';
|
|
4
5
|
export function registerNetworkTools(server) {
|
|
5
|
-
server.tool('getNetworkStatus', 'Get current Solana network status including epoch info (current epoch, slot, progress), total SOL supply, cluster version, and current block height. No parameters needed — gives a quick overview of blockchain health and state.', {}, async () => {
|
|
6
|
+
server.tool('getNetworkStatus', 'BEST FOR: quick Solana network health check — epoch, slot, supply, version. Get current Solana network status including epoch info (current epoch, slot, progress), total SOL supply, cluster version, and current block height. No parameters needed — gives a quick overview of blockchain health and state. Credit cost: 3 credits (3 standard RPC calls).', {}, async () => {
|
|
6
7
|
if (!hasApiKey())
|
|
7
8
|
return noApiKeyResponse();
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (errors.length === 3) {
|
|
37
|
-
return {
|
|
38
|
-
content: [{
|
|
39
|
-
type: 'text',
|
|
40
|
-
text: `**Network Status Error**\n\n${errors.join('\n')}`
|
|
41
|
-
}]
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
const lines = ['**Solana Network Status**', ''];
|
|
45
|
-
// Epoch info
|
|
46
|
-
if (epochRes.result) {
|
|
47
|
-
const epoch = epochRes.result;
|
|
48
|
-
const epochProgress = ((epoch.slotIndex / epoch.slotsInEpoch) * 100).toFixed(1);
|
|
49
|
-
lines.push('**Epoch:**');
|
|
50
|
-
lines.push(`- Current Epoch: ${epoch.epoch}`);
|
|
51
|
-
lines.push(`- Progress: ${epochProgress}% (slot ${epoch.slotIndex.toLocaleString()} / ${epoch.slotsInEpoch.toLocaleString()})`);
|
|
52
|
-
lines.push(`- Absolute Slot: ${epoch.absoluteSlot.toLocaleString()}`);
|
|
53
|
-
lines.push(`- Block Height: ${epoch.blockHeight.toLocaleString()}`);
|
|
54
|
-
if (epoch.transactionCount !== null) {
|
|
55
|
-
lines.push(`- Transaction Count: ${epoch.transactionCount.toLocaleString()}`);
|
|
9
|
+
try {
|
|
10
|
+
const helius = getHeliusClient();
|
|
11
|
+
// Fire all requests in parallel — Kit returns bigint for numeric fields
|
|
12
|
+
// wrapAutoSend in the SDK already calls .send() on pending RPC requests
|
|
13
|
+
const [epochInfo, supplyResult, version] = await Promise.all([
|
|
14
|
+
helius.getEpochInfo(),
|
|
15
|
+
helius.getSupply(),
|
|
16
|
+
helius.getVersion(),
|
|
17
|
+
]);
|
|
18
|
+
const lines = ['**Solana Network Status**', ''];
|
|
19
|
+
// Epoch info — all fields are bigint from Kit
|
|
20
|
+
if (epochInfo) {
|
|
21
|
+
const epoch = Number(epochInfo.epoch);
|
|
22
|
+
const slotIndex = Number(epochInfo.slotIndex);
|
|
23
|
+
const slotsInEpoch = Number(epochInfo.slotsInEpoch);
|
|
24
|
+
const absoluteSlot = Number(epochInfo.absoluteSlot);
|
|
25
|
+
const blockHeight = Number(epochInfo.blockHeight);
|
|
26
|
+
const transactionCount = epochInfo.transactionCount != null ? Number(epochInfo.transactionCount) : null;
|
|
27
|
+
const epochProgress = ((slotIndex / slotsInEpoch) * 100).toFixed(1);
|
|
28
|
+
lines.push('**Epoch:**');
|
|
29
|
+
lines.push(`- Current Epoch: ${epoch}`);
|
|
30
|
+
lines.push(`- Progress: ${epochProgress}% (slot ${slotIndex.toLocaleString()} / ${slotsInEpoch.toLocaleString()})`);
|
|
31
|
+
lines.push(`- Absolute Slot: ${absoluteSlot.toLocaleString()}`);
|
|
32
|
+
lines.push(`- Block Height: ${blockHeight.toLocaleString()}`);
|
|
33
|
+
if (transactionCount !== null) {
|
|
34
|
+
lines.push(`- Transaction Count: ${transactionCount.toLocaleString()}`);
|
|
35
|
+
}
|
|
36
|
+
lines.push('');
|
|
56
37
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
38
|
+
// Supply — value fields are bigint from Kit
|
|
39
|
+
if (supplyResult?.value) {
|
|
40
|
+
const supply = supplyResult.value;
|
|
41
|
+
lines.push('**SOL Supply:**');
|
|
42
|
+
lines.push(`- Total: ${formatSolCompact(Number(supply.total))}`);
|
|
43
|
+
lines.push(`- Circulating: ${formatSolCompact(Number(supply.circulating))}`);
|
|
44
|
+
lines.push(`- Non-Circulating: ${formatSolCompact(Number(supply.nonCirculating))}`);
|
|
45
|
+
lines.push('');
|
|
46
|
+
}
|
|
47
|
+
// Version — no bigint issues
|
|
48
|
+
if (version) {
|
|
49
|
+
lines.push(`**Cluster Version:** ${version['solana-core']}`);
|
|
50
|
+
}
|
|
51
|
+
return mcpText(lines.join('\n'));
|
|
67
52
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
lines.push(`**Cluster Version:** ${versionRes.result['solana-core']}`);
|
|
53
|
+
catch (err) {
|
|
54
|
+
return handleToolError(err, 'Error fetching network status');
|
|
71
55
|
}
|
|
72
|
-
return {
|
|
73
|
-
content: [{
|
|
74
|
-
type: 'text',
|
|
75
|
-
text: lines.join('\n')
|
|
76
|
-
}]
|
|
77
|
-
};
|
|
78
56
|
});
|
|
79
57
|
}
|
package/dist/tools/plans.d.ts
CHANGED
|
@@ -1,2 +1,23 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Static plan metadata — NOT the source of truth for pricing or billing data.
|
|
4
|
+
*
|
|
5
|
+
* Remaining uses (no billing data should be served from here):
|
|
6
|
+
* 1. Plan name lookup in auth.ts getAccountStatus
|
|
7
|
+
* 2. Feature-gate booleans in recommend.ts derivePlanLimitations()
|
|
8
|
+
* 3. Validation of minimumPlan keys in validate-catalog.ts
|
|
9
|
+
*
|
|
10
|
+
* All user-facing billing data (prices, credits, rate limits) is fetched live
|
|
11
|
+
* from the billing docs via fetchDoc('billing').
|
|
12
|
+
*/
|
|
13
|
+
export declare const HELIUS_PLANS: Record<string, {
|
|
14
|
+
name: string;
|
|
15
|
+
features: Record<string, boolean | string>;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Detect the user's current Helius plan from their JWT session.
|
|
19
|
+
* Returns the plan key (e.g. "developer") or undefined if unavailable.
|
|
20
|
+
* Best-effort — never throws.
|
|
21
|
+
*/
|
|
22
|
+
export declare function detectCurrentPlan(): Promise<string | undefined>;
|
|
2
23
|
export declare function registerPlanTools(server: McpServer): void;
|