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
@@ -0,0 +1,157 @@
1
+ // ─── MCP Response Builders ───
2
+ export function mcpText(text) {
3
+ return { content: [{ type: 'text', text }] };
4
+ }
5
+ export function mcpError(text) {
6
+ return { content: [{ type: 'text', text }], isError: true };
7
+ }
8
+ // ─── Error Message Extraction ───
9
+ export function getErrorMessage(err) {
10
+ return err instanceof Error ? err.message : String(err);
11
+ }
12
+ // ─── Error Classifiers ───
13
+ export function isAddressError(msg) {
14
+ return msg.includes('Pubkey Validation Err')
15
+ || msg.includes('Invalid param')
16
+ || msg.includes('Invalid pubkey')
17
+ || msg.includes('Validation Error');
18
+ }
19
+ export function isPaginationError(msg) {
20
+ return msg.includes('Pagination Error')
21
+ || msg.includes('invalid value')
22
+ || msg.includes('expected u32')
23
+ || msg.includes('expected u64');
24
+ }
25
+ export function isNotFoundError(msg) {
26
+ return msg.includes('RecordNotFound')
27
+ || msg.includes('Asset Not Found')
28
+ || msg.includes('Asset Proof Not Found');
29
+ }
30
+ export function isHttp404Error(msg) {
31
+ return msg.includes('404')
32
+ || msg.includes('not found')
33
+ || msg.includes('Method not found');
34
+ }
35
+ export function isHttp400Error(msg) {
36
+ return msg.includes('400');
37
+ }
38
+ export function parseHttp400Messages(msg) {
39
+ try {
40
+ const json = JSON.parse(msg.replace(/^HTTP 400:\s*/, ''));
41
+ const messages = Array.isArray(json.message) ? json.message : [json.message];
42
+ return messages;
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ // ─── Enum Validation ───
49
+ export function validateEnum(value, validOptions, context, fieldName) {
50
+ if (!validOptions.includes(value)) {
51
+ return mcpText(`**${context}**\n\nInvalid ${fieldName} "${value}". Valid options: ${validOptions.join(', ')}`);
52
+ }
53
+ return null;
54
+ }
55
+ // ─── HTTP Status Guidance ───
56
+ const HTTP_GUIDANCE = {
57
+ '401': 'API key is invalid or expired. Call `setHeliusApiKey` with a valid key, or call `getAccountStatus` to check your current auth state.',
58
+ '403': 'This endpoint is restricted on your current plan. Call `getAccountStatus` to check your plan tier and remaining credits. Some endpoints (Enhanced Transactions, Token API) require Developer plan or higher. Call `getHeliusPlanInfo` to compare plans, or `previewUpgrade` to see upgrade pricing.',
59
+ '429': 'Rate limited. Call `getAccountStatus` to check your remaining credits and rate limits. Back off and retry, or call `previewUpgrade` to see upgrade options for higher limits.',
60
+ '502': 'Backend temporarily unavailable. Retry after a few seconds.',
61
+ '504': 'Gateway timeout — the request took too long. Try reducing the query scope (fewer addresses, smaller limit, narrower time range).',
62
+ };
63
+ function extractHttpGuidance(msg) {
64
+ for (const [status, guidance] of Object.entries(HTTP_GUIDANCE)) {
65
+ if (msg.includes(`HTTP ${status}`) || msg.includes(`status: ${status}`) || msg.includes(`(${status})`)) {
66
+ return guidance;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ export function handleToolError(err, fallbackPrefix, handlers) {
72
+ const msg = getErrorMessage(err);
73
+ if (handlers) {
74
+ for (const handler of handlers) {
75
+ if (handler.match(msg))
76
+ return handler.respond(msg);
77
+ }
78
+ }
79
+ const guidance = extractHttpGuidance(msg);
80
+ if (guidance) {
81
+ return mcpError(`**${fallbackPrefix}:** ${msg}\n\n${guidance}`);
82
+ }
83
+ return mcpError(`**${fallbackPrefix}:** ${msg}`);
84
+ }
85
+ // ─── Pre-built Handler Factories ───
86
+ export function addressError(header, detail) {
87
+ return {
88
+ match: isAddressError,
89
+ respond: () => mcpText(`**${header}**\n\n${detail || 'Invalid Solana address. Please provide a valid base58-encoded address.'}`),
90
+ };
91
+ }
92
+ export function paginationError(header, detail) {
93
+ return {
94
+ match: isPaginationError,
95
+ respond: () => mcpText(`**${header}**\n\n${detail || 'Invalid pagination parameters. Page must be at least 1 and limit must be between 1 and 1000.'}`),
96
+ };
97
+ }
98
+ export function notFoundError(header, detail) {
99
+ return {
100
+ match: isNotFoundError,
101
+ respond: () => mcpText(`**${header}**\n\n${detail || 'Asset not found. This mint address does not exist or has not been indexed.'}`),
102
+ };
103
+ }
104
+ export function http404Error(header, detail) {
105
+ return {
106
+ match: isHttp404Error,
107
+ respond: () => header ? mcpText(`**${header}**\n\n${detail}`) : mcpText(detail),
108
+ };
109
+ }
110
+ export function http400Error(header) {
111
+ return {
112
+ match: isHttp400Error,
113
+ respond: (msg) => {
114
+ const messages = parseHttp400Messages(msg);
115
+ if (messages) {
116
+ return mcpText(`**${header}**\n\n${messages.map((m) => `- ${m}`).join('\n')}`);
117
+ }
118
+ return mcpError(`**${header}:** ${msg}`);
119
+ },
120
+ };
121
+ }
122
+ // ─── Address Format Validation (for config-generation warnings) ───
123
+ const SOLANA_ADDRESS_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
124
+ export function isValidAddressFormat(address) {
125
+ return SOLANA_ADDRESS_REGEX.test(address);
126
+ }
127
+ export function warnInvalidAddresses(paramName, addresses) {
128
+ const warnings = [];
129
+ const empty = addresses.filter(a => !a || !a.trim());
130
+ if (empty.length > 0) {
131
+ warnings.push(`${paramName} contains ${empty.length} empty/blank address(es). These will be rejected by the endpoint.`);
132
+ }
133
+ const invalid = addresses.filter(a => a && a.trim() && !isValidAddressFormat(a.trim()));
134
+ if (invalid.length > 0) {
135
+ warnings.push(`${paramName} contains ${invalid.length} address(es) with invalid format: ${invalid.slice(0, 3).map(a => `"${a}"`).join(', ')}${invalid.length > 3 ? `, ... (${invalid.length} total)` : ''}. Solana addresses are 32-44 base58 characters.`);
136
+ }
137
+ return warnings;
138
+ }
139
+ export function warnInvalidAddress(paramName, address) {
140
+ if (!address || !address.trim()) {
141
+ return `${paramName} is empty/blank. A valid Solana address is required.`;
142
+ }
143
+ if (!isValidAddressFormat(address.trim())) {
144
+ return `${paramName} "${address}" does not look like a valid Solana address (expected 32-44 base58 characters).`;
145
+ }
146
+ return null;
147
+ }
148
+ export function warnAddressConflicts(includeName, includeAddresses, excludeName, excludeAddresses) {
149
+ if (!includeAddresses || !excludeAddresses)
150
+ return null;
151
+ const includeSet = new Set(includeAddresses.map(a => a.trim()));
152
+ const overlap = excludeAddresses.filter(a => includeSet.has(a.trim()));
153
+ if (overlap.length > 0) {
154
+ return `${overlap.length} address(es) appear in both ${includeName} and ${excludeName}: ${overlap.slice(0, 3).map(a => `"${a}"`).join(', ')}${overlap.length > 3 ? `, ... (${overlap.length} total)` : ''}. These addresses will be included and excluded simultaneously, which may cause unexpected behavior.`;
155
+ }
156
+ return null;
157
+ }
@@ -0,0 +1,16 @@
1
+ interface FeedbackEvent {
2
+ type: 'tool_call' | 'discovery';
3
+ toolName?: string;
4
+ feedback?: string;
5
+ feedbackTool?: string;
6
+ model?: string;
7
+ discoveryPath?: string;
8
+ frictionPoints?: string;
9
+ }
10
+ export declare function captureClientInfo(info: {
11
+ name: string;
12
+ version: string;
13
+ }): void;
14
+ export declare function captureWalletAddress(address: string): void;
15
+ export declare function sendFeedbackEvent(event: FeedbackEvent): void;
16
+ export {};
@@ -0,0 +1,87 @@
1
+ import { version } from '../version.js';
2
+ import crypto from 'crypto';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import os from 'os';
6
+ const POSTHOG_ENDPOINT = 'https://www.helius.dev/relay-RMqE/capture/';
7
+ const POSTHOG_API_KEY = 'phc_aLmID5mMwUZi3pVhG4HomDeZaWZ1PqAEkWTempDogzi';
8
+ const HELIUS_DIR = path.join(os.homedir(), '.helius');
9
+ const ANON_ID_PATH = path.join(HELIUS_DIR, 'anon-id');
10
+ let clientInfo = null;
11
+ let feedbackEnabled = true;
12
+ let walletAddress = null;
13
+ let identifySent = false;
14
+ // Persistent anonymous ID shared with helius-cli.
15
+ let sessionId;
16
+ try {
17
+ if (fs.existsSync(ANON_ID_PATH)) {
18
+ sessionId = fs.readFileSync(ANON_ID_PATH, 'utf-8').trim();
19
+ }
20
+ else {
21
+ sessionId = crypto.randomUUID();
22
+ try {
23
+ fs.mkdirSync(HELIUS_DIR, { recursive: true });
24
+ fs.writeFileSync(ANON_ID_PATH, sessionId, 'utf-8');
25
+ }
26
+ catch { }
27
+ }
28
+ }
29
+ catch {
30
+ sessionId = crypto.randomUUID();
31
+ }
32
+ export function captureClientInfo(info) {
33
+ clientInfo = info;
34
+ }
35
+ export function captureWalletAddress(address) {
36
+ const previousId = walletAddress ? null : sessionId;
37
+ walletAddress = address;
38
+ if (previousId && !identifySent) {
39
+ identifySent = true;
40
+ posthogCapture('$identify', {
41
+ distinct_id: address,
42
+ $anon_distinct_id: previousId,
43
+ });
44
+ }
45
+ }
46
+ function getDistinctId() {
47
+ return walletAddress || sessionId;
48
+ }
49
+ function posthogCapture(event, properties) {
50
+ if (!feedbackEnabled)
51
+ return;
52
+ fetch(POSTHOG_ENDPOINT, {
53
+ method: 'POST',
54
+ headers: { 'Content-Type': 'application/json' },
55
+ body: JSON.stringify({
56
+ api_key: POSTHOG_API_KEY,
57
+ event,
58
+ properties,
59
+ }),
60
+ }).catch(() => {
61
+ feedbackEnabled = false;
62
+ });
63
+ }
64
+ export function sendFeedbackEvent(event) {
65
+ const eventName = event.type === 'discovery' ? 'agent_discovery' : 'agent_invocation';
66
+ const properties = {
67
+ distinct_id: getDistinctId(),
68
+ helius_client: 'helius-mcp',
69
+ helius_version: version,
70
+ };
71
+ if (clientInfo) {
72
+ properties.mcp_client = `${clientInfo.name}/${clientInfo.version}`;
73
+ }
74
+ if (event.toolName)
75
+ properties.current_tool = event.toolName;
76
+ if (event.feedback)
77
+ properties.feedback = event.feedback;
78
+ if (event.feedbackTool)
79
+ properties.feedback_tool = event.feedbackTool;
80
+ if (event.model)
81
+ properties.llm_model = event.model;
82
+ if (event.discoveryPath)
83
+ properties.discovery_path = event.discoveryPath;
84
+ if (event.frictionPoints)
85
+ properties.friction_points = event.frictionPoints;
86
+ posthogCapture(eventName, properties);
87
+ }
@@ -4,4 +4,3 @@ export declare function formatAddress(address: string): string;
4
4
  export declare function formatTimestamp(unixTime: number): string;
5
5
  export declare function formatTokenAmount(amount: number, decimals: number): string;
6
6
  export declare function formatSolCompact(lamports: number): string;
7
- export declare function getOrbExplorerUrl(addressOrSignature: string, type?: 'address' | 'tx'): string;
@@ -18,6 +18,3 @@ export function formatTokenAmount(amount, decimals) {
18
18
  export function formatSolCompact(lamports) {
19
19
  return `${(lamports / LAMPORTS_PER_SOL).toLocaleString(undefined, { maximumFractionDigits: 0 })} SOL`;
20
20
  }
21
- export function getOrbExplorerUrl(addressOrSignature, type = 'address') {
22
- return `https://orbmarkets.io/${type}/${addressOrSignature}`;
23
- }
@@ -1,13 +1,23 @@
1
1
  import { type HeliusClient } from 'helius-sdk';
2
+ export declare function setSessionSecretKey(key: Uint8Array): void;
3
+ export declare function getSessionSecretKey(): Uint8Array | null;
4
+ export declare function setSessionWalletAddress(address: string): void;
5
+ export declare function getSessionWalletAddress(): string | null;
2
6
  export declare function setApiKey(apiKey: string): void;
3
7
  export declare function getApiKey(): string;
4
8
  export declare function hasApiKey(): boolean;
5
9
  export declare function getHeliusClient(): HeliusClient;
6
- export declare function setNetwork(network: 'mainnet' | 'devnet'): void;
7
- export declare function getNetwork(): 'mainnet' | 'devnet';
8
- export declare function getRpcUrl(): string;
10
+ export declare function setNetwork(network: 'mainnet-beta' | 'devnet'): void;
11
+ export declare function getNetwork(): 'mainnet-beta' | 'devnet';
9
12
  export declare function getEnhancedWebSocketUrl(): string;
10
13
  export declare function getLaserstreamUrl(region?: 'ewr' | 'pitt' | 'slc' | 'lax' | 'lon' | 'ams' | 'fra' | 'tyo' | 'sgp'): string;
11
- export declare function rpcRequest(method: string, params?: any[]): Promise<any>;
12
- export declare function dasRequest(method: string, params?: any): Promise<any>;
14
+ /**
15
+ * Load the signer keypair from session or disk.
16
+ * Returns the raw secret key bytes and the wallet address string.
17
+ * Throws with message 'NO_KEYPAIR' if no keypair is available.
18
+ */
19
+ export declare function loadSignerOrFail(): Promise<{
20
+ secretKey: Uint8Array;
21
+ walletAddress: string;
22
+ }>;
13
23
  export declare function restRequest(endpoint: string, options?: RequestInit): Promise<any>;
@@ -1,28 +1,42 @@
1
1
  import { createHelius } from 'helius-sdk';
2
+ import { MCP_USER_AGENT } from '../http.js';
3
+ import { getSharedApiKey } from './config.js';
2
4
  let sessionApiKey = null;
3
- let sessionNetwork = 'mainnet';
5
+ let sessionNetwork = 'mainnet-beta';
4
6
  let heliusClient = null;
7
+ // Session keypair storage for auth flow
8
+ let sessionSecretKey = null;
9
+ let sessionWalletAddress = null;
10
+ export function setSessionSecretKey(key) {
11
+ sessionSecretKey = key;
12
+ }
13
+ export function getSessionSecretKey() {
14
+ return sessionSecretKey;
15
+ }
16
+ export function setSessionWalletAddress(address) {
17
+ sessionWalletAddress = address;
18
+ }
19
+ export function getSessionWalletAddress() {
20
+ return sessionWalletAddress;
21
+ }
5
22
  export function setApiKey(apiKey) {
6
23
  sessionApiKey = apiKey;
7
24
  heliusClient = null; // Reset client so it picks up new key
8
25
  }
9
26
  export function getApiKey() {
10
- const apiKey = sessionApiKey || process.env.HELIUS_API_KEY;
27
+ const apiKey = sessionApiKey || process.env.HELIUS_API_KEY || getSharedApiKey();
11
28
  if (!apiKey) {
12
- throw new Error('API key not set. Please use the setHeliusApiKey tool first:\n\n' +
13
- ' Tool: setHeliusApiKey\n' +
14
- ' Arguments: { "apiKey": "your-helius-api-key" }\n\n' +
15
- 'Get your free API key at: https://dashboard.helius.dev/api-keys');
29
+ throw new Error('NO_API_KEY: Set HELIUS_API_KEY environment variable or use setHeliusApiKey tool');
16
30
  }
17
31
  return apiKey;
18
32
  }
19
33
  export function hasApiKey() {
20
- return !!(sessionApiKey || process.env.HELIUS_API_KEY);
34
+ return !!(sessionApiKey || process.env.HELIUS_API_KEY || getSharedApiKey());
21
35
  }
22
36
  export function getHeliusClient() {
23
37
  if (!heliusClient) {
24
38
  const apiKey = getApiKey();
25
- heliusClient = createHelius({ apiKey });
39
+ heliusClient = createHelius({ apiKey, userAgent: MCP_USER_AGENT });
26
40
  }
27
41
  return heliusClient;
28
42
  }
@@ -31,19 +45,11 @@ export function setNetwork(network) {
31
45
  }
32
46
  export function getNetwork() {
33
47
  const envNetwork = process.env.HELIUS_NETWORK;
34
- if (envNetwork === 'devnet' || envNetwork === 'mainnet') {
48
+ if (envNetwork === 'devnet' || envNetwork === 'mainnet-beta') {
35
49
  return envNetwork;
36
50
  }
37
51
  return sessionNetwork;
38
52
  }
39
- export function getRpcUrl() {
40
- const apiKey = getApiKey();
41
- const network = getNetwork();
42
- if (network === 'devnet') {
43
- return `https://devnet.helius-rpc.com/?api-key=${apiKey}`;
44
- }
45
- return `https://mainnet.helius-rpc.com/?api-key=${apiKey}`;
46
- }
47
53
  export function getEnhancedWebSocketUrl() {
48
54
  const apiKey = getApiKey();
49
55
  const network = getNetwork();
@@ -61,43 +67,44 @@ export function getLaserstreamUrl(region) {
61
67
  const selectedRegion = region || 'ewr';
62
68
  return `https://laserstream-mainnet-${selectedRegion}.helius-rpc.com`;
63
69
  }
64
- export async function rpcRequest(method, params = []) {
65
- const url = getRpcUrl();
66
- const response = await fetch(url, {
67
- method: 'POST',
68
- headers: { 'Content-Type': 'application/json' },
69
- body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params }),
70
- });
71
- if (!response.ok) {
72
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
73
- }
74
- const data = await response.json();
75
- if (data.error) {
76
- throw new Error(`RPC Error: ${data.error.message || JSON.stringify(data.error)}`);
70
+ /**
71
+ * Load the signer keypair from session or disk.
72
+ * Returns the raw secret key bytes and the wallet address string.
73
+ * Throws with message 'NO_KEYPAIR' if no keypair is available.
74
+ */
75
+ export async function loadSignerOrFail() {
76
+ // Lazy-import to avoid circular deps (config → helius → config)
77
+ const { loadKeypairFromDisk } = await import('./config.js');
78
+ const { loadKeypair } = await import('helius-sdk/auth/loadKeypair');
79
+ const { getAddress } = await import('helius-sdk/auth/getAddress');
80
+ let secretKey = getSessionSecretKey();
81
+ if (!secretKey) {
82
+ secretKey = loadKeypairFromDisk();
83
+ if (secretKey) {
84
+ const walletKeypair = loadKeypair(secretKey);
85
+ const addr = await getAddress(walletKeypair);
86
+ setSessionSecretKey(secretKey);
87
+ setSessionWalletAddress(addr);
88
+ }
77
89
  }
78
- return data.result;
79
- }
80
- export async function dasRequest(method, params = {}) {
81
- const url = getRpcUrl();
82
- const response = await fetch(url, {
83
- method: 'POST',
84
- headers: { 'Content-Type': 'application/json' },
85
- body: JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method, params }),
86
- });
87
- if (!response.ok) {
88
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
90
+ if (!secretKey) {
91
+ throw new Error('NO_KEYPAIR');
89
92
  }
90
- const data = await response.json();
91
- if (data.error) {
92
- throw new Error(`DAS Error: ${data.error.message || JSON.stringify(data.error)}`);
93
+ // Derive the address from the key if not already cached in session
94
+ let walletAddress = getSessionWalletAddress();
95
+ if (!walletAddress) {
96
+ const walletKeypair = loadKeypair(secretKey);
97
+ walletAddress = await getAddress(walletKeypair);
98
+ setSessionWalletAddress(walletAddress);
93
99
  }
94
- return data.result;
100
+ return { secretKey, walletAddress };
95
101
  }
96
102
  export async function restRequest(endpoint, options = {}) {
97
103
  const apiKey = getApiKey();
98
104
  const separator = endpoint.includes('?') ? '&' : '?';
99
105
  const url = `https://api.helius.xyz${endpoint}${separator}api-key=${apiKey}`;
100
106
  const headers = { ...options.headers };
107
+ headers['User-Agent'] = MCP_USER_AGENT;
101
108
  if (options.body) {
102
109
  headers['Content-Type'] ??= 'application/json';
103
110
  }
@@ -0,0 +1 @@
1
+ export declare const version = "1.2.0";
@@ -0,0 +1 @@
1
+ export const version = '1.2.0';
package/package.json CHANGED
@@ -1,26 +1,31 @@
1
1
  {
2
2
  "name": "helius-mcp",
3
- "version": "0.5.3",
4
- "description": "Official Helius MCP Server - Complete Solana blockchain data access for Claude",
3
+ "version": "1.2.0",
4
+ "description": "Official Helius MCP Server - Complete Solana blockchain data access for AI assistants",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "helius-mcp": "dist/index.js"
9
9
  },
10
10
  "scripts": {
11
+ "prebuild": "node -p \"'export const version = \\'' + require('./package.json').version + '\\';'\" > src/version.ts",
11
12
  "build": "tsc",
12
13
  "dev": "tsc --watch",
13
14
  "start": "node dist/index.js",
14
- "prepublishOnly": "pnpm build",
15
- "test": "vitest run"
15
+ "validate": "node dist/scripts/validate-catalog.js",
16
+ "test": "pnpm build && pnpm validate && vitest run",
17
+ "changelog": "auto-changelog --tag-prefix helius-mcp@",
18
+ "prepublishOnly": "pnpm build"
16
19
  },
17
20
  "keywords": [
18
21
  "helius",
19
22
  "solana",
20
23
  "blockchain",
21
24
  "mcp",
22
- "claude",
25
+ "model-context-protocol",
23
26
  "ai",
27
+ "llm",
28
+ "claude",
24
29
  "web3",
25
30
  "nft",
26
31
  "defi",
@@ -36,18 +41,23 @@
36
41
  "homepage": "https://github.com/helius-labs/core-ai#readme",
37
42
  "dependencies": {
38
43
  "@modelcontextprotocol/sdk": "^1.0.0",
44
+ "@solana-program/system": "^0.10.0",
45
+ "@solana-program/token": "^0.9.0",
46
+ "@solana/kit": "^5.0.0",
39
47
  "bs58": "^6.0.0",
40
- "helius-sdk": "^2.0.5",
48
+ "helius-sdk": "^2.2.2",
41
49
  "zod": "^3.23.0"
42
50
  },
43
51
  "devDependencies": {
44
52
  "@types/node": "^20.0.0",
45
- "@vitest/coverage-v8": "^2.0.0",
53
+ "auto-changelog": "^2.5.0",
46
54
  "typescript": "^5.4.0",
47
55
  "vitest": "^2.0.0"
48
56
  },
49
57
  "files": [
50
58
  "dist",
59
+ "system-prompts",
60
+ "CHANGELOG.md",
51
61
  "README.md",
52
62
  "LICENSE"
53
63
  ]