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.
Files changed (67) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +1 -1
  3. package/README.md +97 -21
  4. package/dist/http.d.ts +1 -0
  5. package/dist/http.js +2 -0
  6. package/dist/index.js +93 -2
  7. package/dist/scripts/validate-catalog.d.ts +13 -0
  8. package/dist/scripts/validate-catalog.js +76 -0
  9. package/dist/tools/accounts.js +114 -204
  10. package/dist/tools/assets.js +109 -123
  11. package/dist/tools/auth.d.ts +2 -0
  12. package/dist/tools/auth.js +459 -0
  13. package/dist/tools/balance.js +28 -32
  14. package/dist/tools/blocks.js +68 -87
  15. package/dist/tools/config.js +18 -79
  16. package/dist/tools/das-extras.js +56 -41
  17. package/dist/tools/docs.js +12 -54
  18. package/dist/tools/enhanced-websockets.js +104 -74
  19. package/dist/tools/fees.js +42 -61
  20. package/dist/tools/guides.js +126 -515
  21. package/dist/tools/index.js +50 -2
  22. package/dist/tools/laserstream.js +107 -53
  23. package/dist/tools/network.js +47 -69
  24. package/dist/tools/plans.d.ts +21 -0
  25. package/dist/tools/plans.js +105 -246
  26. package/dist/tools/product-catalog.d.ts +10 -0
  27. package/dist/tools/product-catalog.js +123 -0
  28. package/dist/tools/recommend.d.ts +4 -0
  29. package/dist/tools/recommend.js +233 -0
  30. package/dist/tools/shared.js +8 -3
  31. package/dist/tools/solana-knowledge.d.ts +2 -0
  32. package/dist/tools/solana-knowledge.js +544 -0
  33. package/dist/tools/tokens.js +17 -18
  34. package/dist/tools/transactions.js +232 -302
  35. package/dist/tools/transfers.d.ts +2 -0
  36. package/dist/tools/transfers.js +270 -0
  37. package/dist/tools/wallet.js +175 -177
  38. package/dist/tools/webhooks.js +80 -82
  39. package/dist/types/transaction-types.d.ts +1 -1
  40. package/dist/types/transaction-types.js +2 -1
  41. package/dist/utils/config.d.ts +27 -0
  42. package/dist/utils/config.js +76 -0
  43. package/dist/utils/docs.d.ts +24 -0
  44. package/dist/utils/docs.js +72 -0
  45. package/dist/utils/errors.d.ts +32 -0
  46. package/dist/utils/errors.js +157 -0
  47. package/dist/utils/feedback.d.ts +16 -0
  48. package/dist/utils/feedback.js +87 -0
  49. package/dist/utils/formatters.d.ts +0 -1
  50. package/dist/utils/formatters.js +0 -3
  51. package/dist/utils/helius.d.ts +15 -5
  52. package/dist/utils/helius.js +52 -45
  53. package/dist/version.d.ts +1 -0
  54. package/dist/version.js +1 -0
  55. package/package.json +17 -7
  56. package/system-prompts/helius/claude.system.md +170 -0
  57. package/system-prompts/helius/full.md +2868 -0
  58. package/system-prompts/helius/openai.developer.md +170 -0
  59. package/system-prompts/helius-dflow/claude.system.md +290 -0
  60. package/system-prompts/helius-dflow/full.md +3647 -0
  61. package/system-prompts/helius-dflow/openai.developer.md +290 -0
  62. package/system-prompts/helius-phantom/claude.system.md +348 -0
  63. package/system-prompts/helius-phantom/full.md +5472 -0
  64. package/system-prompts/helius-phantom/openai.developer.md +348 -0
  65. package/system-prompts/svm/claude.system.md +174 -0
  66. package/system-prompts/svm/full.md +699 -0
  67. package/system-prompts/svm/openai.developer.md +174 -0
@@ -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 { registerGuideTools } from './guides.js';
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.enum(['ewr', 'pitt', 'slc', 'lax', 'lon', 'ams', 'fra', 'tyo', 'sgp']).optional().default('ewr'),
6
- commitment: z.enum(['processed', 'confirmed', 'finalized']).optional(),
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
- return { content: [{ type: 'text', text: lines.join('\n') }] };
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
- const errorMsg = err instanceof Error ? err.message : String(err);
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
- const network = getNetwork();
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
- const errorMsg = err instanceof Error ? err.message : String(err);
111
- return { content: [{ type: 'text', text: `Error: ${errorMsg}` }], isError: true };
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
  }
@@ -1,79 +1,57 @@
1
- import { hasApiKey, getRpcUrl } from '../utils/helius.js';
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
- const url = getRpcUrl();
9
- const makeRequest = async (method, params = []) => {
10
- const response = await fetch(url, {
11
- method: 'POST',
12
- headers: { 'Content-Type': 'application/json' },
13
- body: JSON.stringify({
14
- jsonrpc: '2.0',
15
- id: method,
16
- method,
17
- params
18
- })
19
- });
20
- return response.json();
21
- };
22
- // Fire all requests in parallel
23
- const [epochRes, supplyRes, versionRes] = await Promise.all([
24
- makeRequest('getEpochInfo'),
25
- makeRequest('getSupply'),
26
- makeRequest('getVersion')
27
- ]);
28
- // Check for errors
29
- const errors = [];
30
- if (epochRes.error)
31
- errors.push(`Epoch info: ${epochRes.error.message}`);
32
- if (supplyRes.error)
33
- errors.push(`Supply: ${supplyRes.error.message}`);
34
- if (versionRes.error)
35
- errors.push(`Version: ${versionRes.error.message}`);
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
- lines.push('');
58
- }
59
- // Supply
60
- if (supplyRes.result) {
61
- const supply = supplyRes.result.value;
62
- lines.push('**SOL Supply:**');
63
- lines.push(`- Total: ${formatSolCompact(supply.total)}`);
64
- lines.push(`- Circulating: ${formatSolCompact(supply.circulating)}`);
65
- lines.push(`- Non-Circulating: ${formatSolCompact(supply.nonCirculating)}`);
66
- lines.push('');
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
- // Version
69
- if (versionRes.result) {
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
  }
@@ -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;