web3-tools-mcp 1.0.0 → 1.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.
Files changed (135) hide show
  1. package/README.md +92 -259
  2. package/dist/client.d.ts +1653 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +142 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +78 -28274
  9. package/dist/index.js.map +1 -0
  10. package/dist/package.json +60 -0
  11. package/dist/src/client.d.ts +1653 -0
  12. package/dist/src/client.d.ts.map +1 -0
  13. package/dist/src/client.js +142 -0
  14. package/dist/src/client.js.map +1 -0
  15. package/dist/src/index.d.ts +3 -0
  16. package/dist/src/index.d.ts.map +1 -0
  17. package/dist/src/index.js +88 -0
  18. package/dist/src/index.js.map +1 -0
  19. package/dist/src/tools/advanced.d.ts +75 -0
  20. package/dist/src/tools/advanced.d.ts.map +1 -0
  21. package/dist/src/tools/advanced.js +234 -0
  22. package/dist/src/tools/advanced.js.map +1 -0
  23. package/dist/src/tools/balance.d.ts +55 -0
  24. package/dist/src/tools/balance.d.ts.map +1 -0
  25. package/dist/src/tools/balance.js +146 -0
  26. package/dist/src/tools/balance.js.map +1 -0
  27. package/dist/src/tools/contract-info.d.ts +79 -0
  28. package/dist/src/tools/contract-info.d.ts.map +1 -0
  29. package/dist/src/tools/contract-info.js +450 -0
  30. package/dist/src/tools/contract-info.js.map +1 -0
  31. package/dist/src/tools/contract.d.ts +79 -0
  32. package/dist/src/tools/contract.d.ts.map +1 -0
  33. package/dist/src/tools/contract.js +140 -0
  34. package/dist/src/tools/contract.js.map +1 -0
  35. package/dist/src/tools/index.d.ts +3 -0
  36. package/dist/src/tools/index.d.ts.map +1 -0
  37. package/dist/src/tools/index.js +27 -0
  38. package/dist/src/tools/index.js.map +1 -0
  39. package/dist/src/tools/logs.d.ts +39 -0
  40. package/dist/src/tools/logs.d.ts.map +1 -0
  41. package/dist/src/tools/logs.js +231 -0
  42. package/dist/src/tools/logs.js.map +1 -0
  43. package/dist/src/tools/signatures.d.ts +83 -0
  44. package/dist/src/tools/signatures.d.ts.map +1 -0
  45. package/dist/src/tools/signatures.js +93 -0
  46. package/dist/src/tools/signatures.js.map +1 -0
  47. package/dist/src/types.d.ts +22 -0
  48. package/dist/src/types.d.ts.map +1 -0
  49. package/dist/src/types.js +2 -0
  50. package/dist/src/types.js.map +1 -0
  51. package/dist/src/utils.d.ts +22 -0
  52. package/dist/src/utils.d.ts.map +1 -0
  53. package/dist/src/utils.js +183 -0
  54. package/dist/src/utils.js.map +1 -0
  55. package/dist/test/mcp-client.test.d.ts +2 -0
  56. package/dist/test/mcp-client.test.d.ts.map +1 -0
  57. package/dist/test/mcp-client.test.js +376 -0
  58. package/dist/test/mcp-client.test.js.map +1 -0
  59. package/dist/test/tools/advanced.test.d.ts +2 -0
  60. package/dist/test/tools/advanced.test.d.ts.map +1 -0
  61. package/dist/test/tools/advanced.test.js +235 -0
  62. package/dist/test/tools/advanced.test.js.map +1 -0
  63. package/dist/test/tools/balance.test.d.ts +2 -0
  64. package/dist/test/tools/balance.test.d.ts.map +1 -0
  65. package/dist/test/tools/balance.test.js +167 -0
  66. package/dist/test/tools/balance.test.js.map +1 -0
  67. package/dist/test/tools/contract-info.test.d.ts +2 -0
  68. package/dist/test/tools/contract-info.test.d.ts.map +1 -0
  69. package/dist/test/tools/contract-info.test.js +286 -0
  70. package/dist/test/tools/contract-info.test.js.map +1 -0
  71. package/dist/test/tools/contract.test.d.ts +2 -0
  72. package/dist/test/tools/contract.test.d.ts.map +1 -0
  73. package/dist/test/tools/contract.test.js +234 -0
  74. package/dist/test/tools/contract.test.js.map +1 -0
  75. package/dist/test/tools/logs.test.d.ts +2 -0
  76. package/dist/test/tools/logs.test.d.ts.map +1 -0
  77. package/dist/test/tools/logs.test.js +196 -0
  78. package/dist/test/tools/logs.test.js.map +1 -0
  79. package/dist/test/tools/signatures.test.d.ts +2 -0
  80. package/dist/test/tools/signatures.test.d.ts.map +1 -0
  81. package/dist/test/tools/signatures.test.js +112 -0
  82. package/dist/test/tools/signatures.test.js.map +1 -0
  83. package/dist/tools/advanced.d.ts +75 -0
  84. package/dist/tools/advanced.d.ts.map +1 -0
  85. package/dist/tools/advanced.js +234 -0
  86. package/dist/tools/advanced.js.map +1 -0
  87. package/dist/tools/balance.d.ts +55 -0
  88. package/dist/tools/balance.d.ts.map +1 -0
  89. package/dist/tools/balance.js +146 -0
  90. package/dist/tools/balance.js.map +1 -0
  91. package/dist/tools/batch.d.ts +122 -0
  92. package/dist/tools/batch.d.ts.map +1 -0
  93. package/dist/tools/batch.js +243 -0
  94. package/dist/tools/batch.js.map +1 -0
  95. package/dist/tools/contract-info.d.ts +79 -0
  96. package/dist/tools/contract-info.d.ts.map +1 -0
  97. package/dist/tools/contract-info.js +450 -0
  98. package/dist/tools/contract-info.js.map +1 -0
  99. package/dist/tools/contract.d.ts +79 -0
  100. package/dist/tools/contract.d.ts.map +1 -0
  101. package/dist/tools/contract.js +140 -0
  102. package/dist/tools/contract.js.map +1 -0
  103. package/dist/tools/index.d.ts +3 -0
  104. package/dist/tools/index.d.ts.map +1 -0
  105. package/dist/tools/index.js +27 -0
  106. package/dist/tools/index.js.map +1 -0
  107. package/dist/tools/logs.d.ts +39 -0
  108. package/dist/tools/logs.d.ts.map +1 -0
  109. package/dist/tools/logs.js +231 -0
  110. package/dist/tools/logs.js.map +1 -0
  111. package/dist/tools/signatures.d.ts +83 -0
  112. package/dist/tools/signatures.d.ts.map +1 -0
  113. package/dist/tools/signatures.js +93 -0
  114. package/dist/tools/signatures.js.map +1 -0
  115. package/dist/types.d.ts +22 -0
  116. package/dist/types.d.ts.map +1 -0
  117. package/dist/types.js +2 -0
  118. package/dist/types.js.map +1 -0
  119. package/dist/utils.d.ts +22 -0
  120. package/dist/utils.d.ts.map +1 -0
  121. package/dist/utils.js +183 -0
  122. package/dist/utils.js.map +1 -0
  123. package/package.json +35 -23
  124. package/src/client.ts +160 -0
  125. package/src/index.ts +96 -0
  126. package/src/tools/advanced.ts +262 -0
  127. package/src/tools/balance.ts +176 -0
  128. package/src/tools/contract-info.ts +582 -0
  129. package/src/tools/contract.ts +180 -0
  130. package/src/tools/index.ts +35 -0
  131. package/src/tools/logs.ts +291 -0
  132. package/src/tools/signatures.ts +126 -0
  133. package/src/types.ts +29 -0
  134. package/src/utils.ts +222 -0
  135. package/dist/hypersync-client.darwin-arm64-7fegfwn5.node +0 -0
@@ -0,0 +1,93 @@
1
+ import { keccak256, parseAbiItem, toBytes, toEventSignature, toFunctionSignature } from 'viem';
2
+ import { z } from 'zod';
3
+ import { createTool, formatResponse } from '../utils.js';
4
+ const FunctionAbiSchema = z.object({
5
+ functionAbi: z.string().describe('Function ABI definition (e.g., "function transfer(address to, uint256 amount)")')
6
+ });
7
+ const EventAbiSchema = z.object({
8
+ eventAbi: z
9
+ .string()
10
+ .describe('Event ABI definition (e.g., "event Transfer(address indexed from, address indexed to, uint256 value)")')
11
+ });
12
+ const ErrorAbiSchema = z.object({
13
+ errorAbi: z
14
+ .string()
15
+ .describe('Error ABI definition (e.g., "error InsufficientBalance(uint256 available, uint256 required)")')
16
+ });
17
+ export default {
18
+ get_function_signature: createTool('Calculate Function Signatures', 'Generate 4-byte function selectors from ABI definitions. BATCH OPTIMIZED - use for transaction decoding.', z.object({
19
+ items: z
20
+ .array(FunctionAbiSchema)
21
+ .describe('Array of function ABI definitions. Batch multiple functions for efficiency.')
22
+ }), async (args) => {
23
+ try {
24
+ const results = args.items.map((item) => {
25
+ const abiItem = parseAbiItem(item.functionAbi);
26
+ const signature = toFunctionSignature(abiItem);
27
+ const hash = keccak256(toBytes(signature));
28
+ const selector = hash.slice(0, 10);
29
+ return {
30
+ signature: selector,
31
+ fullSignature: signature,
32
+ functionName: abiItem.name,
33
+ inputs: abiItem.inputs,
34
+ outputs: abiItem.outputs || [],
35
+ stateMutability: abiItem.stateMutability,
36
+ originalAbi: item.functionAbi
37
+ };
38
+ });
39
+ return formatResponse(results);
40
+ }
41
+ catch (error) {
42
+ throw new Error(`Failed to parse function ABI: ${error}`);
43
+ }
44
+ }),
45
+ get_event_signature: createTool('Calculate Event Signatures', 'Generate event topic0 hashes from ABI definitions. BATCH OPTIMIZED - use for log filtering setup.', z.object({
46
+ items: z.array(EventAbiSchema).describe('Array of event ABI definitions. Batch multiple events for optimal performance.')
47
+ }), async (args) => {
48
+ try {
49
+ const results = args.items.map((item) => {
50
+ const abiItem = parseAbiItem(item.eventAbi);
51
+ const signature = toEventSignature(abiItem);
52
+ const hash = keccak256(toBytes(signature));
53
+ return {
54
+ signature: hash,
55
+ topic0: hash,
56
+ fullSignature: signature,
57
+ eventName: abiItem.name,
58
+ inputs: abiItem.inputs,
59
+ anonymous: abiItem.anonymous || false,
60
+ originalAbi: item.eventAbi
61
+ };
62
+ });
63
+ return formatResponse(results);
64
+ }
65
+ catch (error) {
66
+ throw new Error(`Failed to parse event ABI: ${error}`);
67
+ }
68
+ }),
69
+ get_error_signature: createTool('Calculate Error Signatures', 'Generate 4-byte error selectors from ABI definitions. BATCH OPTIMIZED - use for revert reason decoding.', z.object({
70
+ items: z.array(ErrorAbiSchema).describe('Array of error ABI definitions. Batch related errors for efficiency.')
71
+ }), async (args) => {
72
+ try {
73
+ const results = args.items.map((item) => {
74
+ const abiItem = parseAbiItem(item.errorAbi);
75
+ const signature = `${abiItem.name}(${abiItem.inputs.map((input) => input.type).join(',')})`;
76
+ const hash = keccak256(toBytes(signature));
77
+ const selector = hash.slice(0, 10);
78
+ return {
79
+ signature: selector,
80
+ fullSignature: signature,
81
+ errorName: abiItem.name,
82
+ inputs: abiItem.inputs,
83
+ originalAbi: item.errorAbi
84
+ };
85
+ });
86
+ return formatResponse(results);
87
+ }
88
+ catch (error) {
89
+ throw new Error(`Failed to parse error ABI: ${error}`);
90
+ }
91
+ })
92
+ };
93
+ //# sourceMappingURL=signatures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signatures.js","sourceRoot":"","sources":["../../src/tools/signatures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { AbiParameter } from 'viem';
2
+ export interface AbiError {
3
+ type: 'error';
4
+ name: string;
5
+ inputs: readonly AbiParameter[];
6
+ }
7
+ export interface Config {
8
+ etherscanApiKey?: string;
9
+ alchemyApiKey?: string;
10
+ infuraApiKey?: string;
11
+ customRpcUrls?: Record<string, string>;
12
+ hypersyncApiKey?: string;
13
+ }
14
+ export type ChainName = 'mainnet' | 'base' | 'arbitrum' | 'polygon' | 'optimism' | 'celo' | 'localhost';
15
+ export interface ToolResult {
16
+ [x: string]: unknown;
17
+ content: Array<{
18
+ type: 'text';
19
+ text: string;
20
+ }>;
21
+ }
22
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AAGxC,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;CAChC;AAGD,MAAM,WAAW,MAAM;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAGD,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,WAAW,CAAA;AAGvG,MAAM,WAAW,UAAU;IACzB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACpB,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;KACb,CAAC,CAAA;CACH"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ import type { AbiParameter } from 'viem';
2
+ import type { ToolResult } from './types.js';
3
+ import { z } from 'zod';
4
+ export declare function createTool<T extends z.ZodType>(title: string, description: string, schema: T, handler: (args: z.infer<T>) => Promise<ToolResult>): {
5
+ title: string;
6
+ description: string;
7
+ schema: T;
8
+ handler: (args: z.infer<T>) => Promise<ToolResult>;
9
+ };
10
+ export declare function convertBigIntToString(obj: unknown): unknown;
11
+ export declare function convertArgumentsToTypes(args: (string | number | boolean | null)[], abiInputs: readonly AbiParameter[]): unknown[];
12
+ export declare function convertEventArgsToTypes(eventArgs: Record<string, unknown>, abiInputs: readonly AbiParameter[]): Record<string, unknown>;
13
+ export declare function formatResponse(data: unknown): ToolResult;
14
+ export declare function parseCommandLineArgs(): {
15
+ etherscanApiKey?: string;
16
+ alchemyApiKey?: string;
17
+ infuraApiKey?: string;
18
+ customRpcUrls?: Record<string, string>;
19
+ hypersyncApiKey?: string;
20
+ showHelp?: boolean;
21
+ };
22
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAC5C,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC;;;;oBAAlC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC;EAQnD;AAGD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAe3D;AAGD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,EAAE,EAC1C,SAAS,EAAE,SAAS,YAAY,EAAE,GACjC,OAAO,EAAE,CAiDX;AAGD,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,SAAS,YAAY,EAAE,GACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA2DzB;AAGD,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAUxD;AAGD,wBAAgB,oBAAoB,IAAI;IACtC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CA2CA"}
package/dist/utils.js ADDED
@@ -0,0 +1,183 @@
1
+ // Create tool helper
2
+ export function createTool(title, description, schema, handler) {
3
+ return {
4
+ title,
5
+ description,
6
+ schema,
7
+ handler
8
+ };
9
+ }
10
+ // Convert BigInt values to strings for JSON serialization
11
+ export function convertBigIntToString(obj) {
12
+ if (typeof obj === 'bigint') {
13
+ return obj.toString();
14
+ }
15
+ if (Array.isArray(obj)) {
16
+ return obj.map(item => convertBigIntToString(item));
17
+ }
18
+ if (obj && typeof obj === 'object') {
19
+ const converted = {};
20
+ for (const [key, value] of Object.entries(obj)) {
21
+ converted[key] = convertBigIntToString(value);
22
+ }
23
+ return converted;
24
+ }
25
+ return obj;
26
+ }
27
+ // Convert arguments to appropriate types based on ABI
28
+ export function convertArgumentsToTypes(args, abiInputs) {
29
+ return args.map((arg, index) => {
30
+ if (index >= abiInputs.length) {
31
+ throw new Error(`Too many arguments provided. Expected ${abiInputs.length}, got ${args.length}`);
32
+ }
33
+ const param = abiInputs[index];
34
+ if (!param?.type) {
35
+ throw new Error(`Missing type information for parameter at index ${index}`);
36
+ }
37
+ const paramType = param.type;
38
+ // Handle null values
39
+ if (arg === null) {
40
+ return null;
41
+ }
42
+ // Handle different parameter types
43
+ if (paramType === 'address') {
44
+ return String(arg);
45
+ }
46
+ if (paramType === 'bool') {
47
+ if (typeof arg === 'boolean')
48
+ return arg;
49
+ if (typeof arg === 'string')
50
+ return arg.toLowerCase() === 'true';
51
+ return Boolean(arg);
52
+ }
53
+ if (paramType.startsWith('uint') || paramType.startsWith('int')) {
54
+ if (typeof arg === 'number')
55
+ return BigInt(arg);
56
+ if (typeof arg === 'string')
57
+ return BigInt(arg);
58
+ throw new Error(`Invalid type for ${paramType}: ${typeof arg}`);
59
+ }
60
+ if (paramType === 'string') {
61
+ return String(arg);
62
+ }
63
+ if (paramType === 'bytes' || paramType.startsWith('bytes')) {
64
+ return String(arg);
65
+ }
66
+ // For other types, try to convert appropriately
67
+ if (typeof arg === 'string' && arg.startsWith('0x')) {
68
+ return arg; // Assume it's already properly formatted
69
+ }
70
+ return arg;
71
+ });
72
+ }
73
+ // Convert event arguments to appropriate types
74
+ export function convertEventArgsToTypes(eventArgs, abiInputs) {
75
+ const converted = {};
76
+ for (const [argName, argValue] of Object.entries(eventArgs)) {
77
+ // Find the parameter definition for this argument name
78
+ const param = abiInputs.find(input => input.name === argName);
79
+ if (!param) {
80
+ throw new Error(`Parameter '${argName}' not found in event ABI`);
81
+ }
82
+ if (!param.type) {
83
+ throw new Error(`Missing type information for parameter '${argName}'`);
84
+ }
85
+ const paramType = param.type;
86
+ // Handle null/undefined values
87
+ if (argValue === null || argValue === undefined) {
88
+ converted[argName] = null;
89
+ continue;
90
+ }
91
+ // Handle different parameter types
92
+ if (paramType === 'address') {
93
+ converted[argName] = String(argValue);
94
+ }
95
+ else if (paramType === 'bool') {
96
+ if (typeof argValue === 'boolean') {
97
+ converted[argName] = argValue;
98
+ }
99
+ else if (typeof argValue === 'string') {
100
+ converted[argName] = argValue.toLowerCase() === 'true';
101
+ }
102
+ else {
103
+ converted[argName] = Boolean(argValue);
104
+ }
105
+ }
106
+ else if (paramType.startsWith('uint') || paramType.startsWith('int')) {
107
+ if (typeof argValue === 'number') {
108
+ converted[argName] = BigInt(argValue);
109
+ }
110
+ else if (typeof argValue === 'string') {
111
+ converted[argName] = BigInt(argValue);
112
+ }
113
+ else {
114
+ throw new Error(`Invalid type for ${paramType}: ${typeof argValue}`);
115
+ }
116
+ }
117
+ else if (paramType === 'string') {
118
+ converted[argName] = String(argValue);
119
+ }
120
+ else if (paramType === 'bytes' || paramType.startsWith('bytes')) {
121
+ converted[argName] = String(argValue);
122
+ }
123
+ else {
124
+ // For other types, handle arrays and try to convert appropriately
125
+ if (Array.isArray(argValue)) {
126
+ converted[argName] = argValue;
127
+ }
128
+ else if (typeof argValue === 'string' && argValue.startsWith('0x')) {
129
+ converted[argName] = argValue; // Assume it's already properly formatted
130
+ }
131
+ else {
132
+ converted[argName] = argValue;
133
+ }
134
+ }
135
+ }
136
+ return converted;
137
+ }
138
+ // Format response as tool result
139
+ export function formatResponse(data) {
140
+ const serializable = convertBigIntToString(data);
141
+ return {
142
+ content: [
143
+ {
144
+ type: 'text',
145
+ text: JSON.stringify(serializable, null, 2)
146
+ }
147
+ ]
148
+ };
149
+ }
150
+ // Parse command line arguments
151
+ export function parseCommandLineArgs() {
152
+ const config = {};
153
+ function getArgValue(argName) {
154
+ const args = process.argv;
155
+ const index = args.findIndex(arg => arg === argName);
156
+ return index !== -1 && index + 1 < args.length ? args[index + 1] : undefined;
157
+ }
158
+ function hasArg(argName) {
159
+ return process.argv.includes(argName);
160
+ }
161
+ // Check for help flag
162
+ if (hasArg('--help') || hasArg('-h')) {
163
+ config.showHelp = true;
164
+ return config;
165
+ }
166
+ // Parse environment variables and command line arguments
167
+ config.etherscanApiKey = process.env.ETHERSCAN_API_KEY || getArgValue('--etherscan-api-key');
168
+ config.alchemyApiKey = process.env.ALCHEMY_API_KEY || getArgValue('--alchemy-api-key');
169
+ config.infuraApiKey = process.env.INFURA_API_KEY || getArgValue('--infura-api-key');
170
+ config.hypersyncApiKey = process.env.HYPERSYNC_API_KEY || getArgValue('--hypersync-api-key');
171
+ // Parse custom RPC URLs
172
+ const customRpcs = getArgValue('--custom-rpc');
173
+ if (customRpcs) {
174
+ try {
175
+ config.customRpcUrls = JSON.parse(customRpcs);
176
+ }
177
+ catch {
178
+ console.error('Invalid JSON for --custom-rpc:', customRpcs);
179
+ }
180
+ }
181
+ return config;
182
+ }
183
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,28 +1,39 @@
1
1
  {
2
2
  "name": "web3-tools-mcp",
3
- "version": "1.0.0",
4
- "description": "MCP server for blockchain interactions using viem, etherscan and hypersync.",
3
+ "version": "1.1.0",
4
+ "description": "Model Context Protocol server for blockchain interactions using viem, Etherscan, and Hypersync",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
6
- "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
7
8
  "bin": {
8
9
  "web3-tools-mcp": "dist/index.js"
9
10
  },
10
- "type": "module",
11
11
  "files": [
12
- "dist/**/*",
12
+ "dist",
13
13
  "README.md",
14
- "LICENSE"
14
+ "LICENSE",
15
+ "src"
15
16
  ],
17
+ "engines": {
18
+ "node": ">=20.0.0"
19
+ },
16
20
  "scripts": {
17
- "start": "node dist/index.js",
18
- "dev": "bun --watch index.ts",
19
- "build": "bun build index.ts --outdir dist --target node --format esm && chmod +x dist/index.js",
20
- "clean": "rm -rf dist",
21
- "prepublishOnly": "npm run clean && npm run build",
22
- "type-check": "tsc --noEmit",
23
- "lint": "bun run type-check"
21
+ "build": "tsc",
22
+ "watch": "tsc --watch",
23
+ "prepare": "npm run build",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "test:ui": "vitest --ui"
24
27
  },
25
- "keywords": ["mcp", "ethereum", "viem", "blockchain", "web3", "model-context-protocol", "ai"],
28
+ "keywords": [
29
+ "mcp",
30
+ "ethereum",
31
+ "viem",
32
+ "blockchain",
33
+ "web3",
34
+ "model-context-protocol",
35
+ "ai"
36
+ ],
26
37
  "author": "Benjamin Hajnal <hajnalbenjamin@gmail.com>",
27
38
  "license": "MIT",
28
39
  "repository": {
@@ -33,16 +44,17 @@
33
44
  "url": "https://github.com/hajnalben/web3-tools-mcp/issues"
34
45
  },
35
46
  "homepage": "https://github.com/hajnalben/web3-tools-mcp#readme",
36
- "devDependencies": {
37
- "@types/bun": "latest",
38
- "@types/node": "^24.0.4"
39
- },
40
- "peerDependencies": {
41
- "typescript": "^5"
42
- },
43
47
  "dependencies": {
44
48
  "@envio-dev/hypersync-client": "^0.6.5",
45
- "@modelcontextprotocol/sdk": "^1.13.1",
46
- "viem": "^2.31.4"
49
+ "@modelcontextprotocol/sdk": "^1.20.1",
50
+ "viem": "^2.31.4",
51
+ "zod": "^3.25.76"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^20.19.23",
55
+ "@vitest/ui": "^3.2.4",
56
+ "dotenv": "^17.2.3",
57
+ "typescript": "^5.0.0",
58
+ "vitest": "^3.2.4"
47
59
  }
48
60
  }
package/src/client.ts ADDED
@@ -0,0 +1,160 @@
1
+ import { http, createPublicClient } from 'viem'
2
+ import { arbitrum, base, celo, localhost, mainnet, optimism, polygon } from 'viem/chains'
3
+ import type { ChainName, Config } from './types.js'
4
+
5
+ // Enhanced RPC configuration with API keys
6
+ function getRpcUrl(chainName: string, config: Config): string {
7
+ // Check for custom RPC URLs first
8
+ if (config.customRpcUrls?.[chainName]) {
9
+ return config.customRpcUrls[chainName]
10
+ }
11
+
12
+ // Enhanced RPC URLs with API keys
13
+ const enhancedRpcs: Record<string, string> = {
14
+ mainnet: config.alchemyApiKey
15
+ ? `https://eth-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`
16
+ : config.infuraApiKey
17
+ ? `https://mainnet.infura.io/v3/${config.infuraApiKey}`
18
+ : 'https://eth.llamarpc.com',
19
+
20
+ base: config.alchemyApiKey
21
+ ? `https://base-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`
22
+ : 'https://base.llamarpc.com',
23
+
24
+ arbitrum: config.alchemyApiKey
25
+ ? `https://arb-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`
26
+ : config.infuraApiKey
27
+ ? `https://arbitrum-mainnet.infura.io/v3/${config.infuraApiKey}`
28
+ : 'https://arb1.arbitrum.io/rpc',
29
+
30
+ polygon: config.alchemyApiKey
31
+ ? `https://polygon-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`
32
+ : config.infuraApiKey
33
+ ? `https://polygon-mainnet.infura.io/v3/${config.infuraApiKey}`
34
+ : 'https://polygon-rpc.com/',
35
+
36
+ optimism: config.alchemyApiKey
37
+ ? `https://opt-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`
38
+ : config.infuraApiKey
39
+ ? `https://optimism-mainnet.infura.io/v3/${config.infuraApiKey}`
40
+ : 'https://mainnet.optimism.io',
41
+
42
+ celo: 'https://celo.drpc.org',
43
+ localhost: 'http://localhost:8545'
44
+ }
45
+
46
+ return enhancedRpcs[chainName] ?? 'https://eth.llamarpc.com'
47
+ }
48
+
49
+ // Supported chains with their RPC endpoints (now dynamic)
50
+ export const CHAINS = (config: Config) => ({
51
+ mainnet: {
52
+ chain: mainnet,
53
+ get rpc() {
54
+ return getRpcUrl('mainnet', config)
55
+ }
56
+ },
57
+ base: {
58
+ chain: base,
59
+ get rpc() {
60
+ return getRpcUrl('base', config)
61
+ }
62
+ },
63
+ arbitrum: {
64
+ chain: arbitrum,
65
+ get rpc() {
66
+ return getRpcUrl('arbitrum', config)
67
+ }
68
+ },
69
+ polygon: {
70
+ chain: polygon,
71
+ get rpc() {
72
+ return getRpcUrl('polygon', config)
73
+ }
74
+ },
75
+ optimism: {
76
+ chain: optimism,
77
+ get rpc() {
78
+ return getRpcUrl('optimism', config)
79
+ }
80
+ },
81
+ celo: {
82
+ chain: celo,
83
+ get rpc() {
84
+ return getRpcUrl('celo', config)
85
+ }
86
+ },
87
+ localhost: {
88
+ chain: localhost,
89
+ get rpc() {
90
+ return getRpcUrl('localhost', config)
91
+ }
92
+ }
93
+ })
94
+
95
+ // Hypersync URLs for supported chains (localhost is not supported)
96
+ export const HYPERSYNC_URLS: Partial<Record<ChainName, string>> = {
97
+ base: 'https://base.hypersync.xyz',
98
+ arbitrum: 'https://arbitrum.hypersync.xyz',
99
+ mainnet: 'https://eth.hypersync.xyz',
100
+ polygon: 'https://polygon.hypersync.xyz',
101
+ optimism: 'https://optimism.hypersync.xyz'
102
+ // celo and localhost are not supported by hypersync
103
+ }
104
+
105
+ export const SUPPORTED_CHAINS = ['mainnet', 'base', 'arbitrum', 'polygon', 'optimism', 'celo', 'localhost'] as const
106
+
107
+ // Client manager
108
+ export class ClientManager {
109
+ private clients: Map<ChainName, unknown> = new Map()
110
+ private config: Config
111
+
112
+ constructor(config: Config) {
113
+ this.config = config
114
+ }
115
+
116
+ getClient(chainName: ChainName) {
117
+ if (!this.clients.has(chainName)) {
118
+ const chains = CHAINS(this.config)
119
+ const { chain, rpc } = chains[chainName]
120
+ const client = createPublicClient({
121
+ chain,
122
+ transport: http(rpc)
123
+ })
124
+ this.clients.set(chainName, client)
125
+ }
126
+ const client = this.clients.get(chainName)
127
+ if (!client) {
128
+ throw new Error(`Failed to create client for chain: ${chainName}`)
129
+ }
130
+ return client as ReturnType<typeof createPublicClient>
131
+ }
132
+
133
+ getEtherscanDomain(chainName: ChainName): string {
134
+ const domains: Record<ChainName, string> = {
135
+ mainnet: 'etherscan.io',
136
+ base: 'basescan.org',
137
+ arbitrum: 'arbiscan.io',
138
+ polygon: 'polygonscan.com',
139
+ optimism: 'optimistic.etherscan.io',
140
+ celo: 'celoscan.io',
141
+ localhost: 'etherscan.io'
142
+ }
143
+ return domains[chainName] || 'etherscan.io'
144
+ }
145
+ }
146
+
147
+ // Export a global client manager instance
148
+ let clientManager: ClientManager | null = null
149
+
150
+ export function initializeClientManager(config: Config): ClientManager {
151
+ clientManager = new ClientManager(config)
152
+ return clientManager
153
+ }
154
+
155
+ export function getClientManager(): ClientManager {
156
+ if (!clientManager) {
157
+ throw new Error('Client manager not initialized')
158
+ }
159
+ return clientManager
160
+ }