x402scan-mcp 0.0.2 → 0.0.3

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 (2) hide show
  1. package/dist/index.js +167 -1
  2. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -1014,6 +1014,170 @@ function registerExecuteCallTool(server) {
1014
1014
  );
1015
1015
  }
1016
1016
 
1017
+ // src/tools/siwe.ts
1018
+ import { z as z4 } from "zod";
1019
+ import { SiweMessage, generateNonce } from "siwe";
1020
+ var CHAIN_IDS = {
1021
+ mainnet: 1,
1022
+ base: 8453,
1023
+ "base-sepolia": 84532,
1024
+ optimism: 10,
1025
+ arbitrum: 42161,
1026
+ polygon: 137,
1027
+ sepolia: 11155111
1028
+ };
1029
+ function registerCreateSiweProofTool(server) {
1030
+ server.tool(
1031
+ "create_siwe_proof",
1032
+ "Create a SIWE (Sign-In with Ethereum) proof for wallet authentication. Returns a proof string to use in X-SIWE-PROOF header.",
1033
+ {
1034
+ domain: z4.string().describe(
1035
+ 'Domain requesting auth (e.g., "localhost:3000" or "stablestudio.io")'
1036
+ ),
1037
+ uri: z4.string().url().describe('Full URI of the API (e.g., "http://localhost:3000")'),
1038
+ statement: z4.string().optional().default("Authenticate to API").describe("Human-readable statement"),
1039
+ chainId: z4.number().optional().describe(
1040
+ "Chain ID (default: 8453 for Base). Common IDs: 1=mainnet, 8453=base, 84532=base-sepolia, 10=optimism"
1041
+ ),
1042
+ chain: z4.enum(["mainnet", "base", "base-sepolia", "optimism", "arbitrum", "polygon", "sepolia"]).optional().describe("Chain name (alternative to chainId). Default: base"),
1043
+ expirationMinutes: z4.number().optional().default(60).describe("Proof validity in minutes")
1044
+ },
1045
+ async ({ domain, uri, statement, chainId, chain, expirationMinutes }) => {
1046
+ try {
1047
+ const { account, address } = await getOrCreateWallet();
1048
+ const resolvedChainId = chainId ?? (chain ? CHAIN_IDS[chain] : CHAIN_IDS.base);
1049
+ const siweMessage = new SiweMessage({
1050
+ domain,
1051
+ address,
1052
+ statement,
1053
+ uri,
1054
+ version: "1",
1055
+ chainId: resolvedChainId,
1056
+ nonce: generateNonce(),
1057
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
1058
+ expirationTime: new Date(
1059
+ Date.now() + expirationMinutes * 60 * 1e3
1060
+ ).toISOString()
1061
+ });
1062
+ const message = siweMessage.prepareMessage();
1063
+ const signature = await account.signMessage({ message });
1064
+ const proof = JSON.stringify({
1065
+ message: JSON.stringify(siweMessage),
1066
+ signature
1067
+ });
1068
+ return mcpSuccess({
1069
+ proof,
1070
+ address,
1071
+ chainId: resolvedChainId,
1072
+ expiresAt: siweMessage.expirationTime,
1073
+ usage: "Add to request headers as: X-SIWE-PROOF: <proof>"
1074
+ });
1075
+ } catch (err) {
1076
+ return mcpError(err, { tool: "create_siwe_proof" });
1077
+ }
1078
+ }
1079
+ );
1080
+ }
1081
+
1082
+ // src/tools/fetch_with_siwe.ts
1083
+ import { z as z5 } from "zod";
1084
+ import { SiweMessage as SiweMessage2, generateNonce as generateNonce2 } from "siwe";
1085
+ var CHAIN_IDS2 = {
1086
+ mainnet: 1,
1087
+ base: 8453,
1088
+ "base-sepolia": 84532,
1089
+ optimism: 10,
1090
+ arbitrum: 42161,
1091
+ polygon: 137,
1092
+ sepolia: 11155111
1093
+ };
1094
+ async function createSiweProof(account, domain, uri, chainId) {
1095
+ const siweMessage = new SiweMessage2({
1096
+ domain,
1097
+ address: account.address,
1098
+ statement: "Authenticate to API",
1099
+ uri,
1100
+ version: "1",
1101
+ chainId,
1102
+ nonce: generateNonce2(),
1103
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
1104
+ expirationTime: new Date(Date.now() + 36e5).toISOString()
1105
+ });
1106
+ const message = siweMessage.prepareMessage();
1107
+ const signature = await account.signMessage({ message });
1108
+ return JSON.stringify({
1109
+ message: JSON.stringify(siweMessage),
1110
+ signature
1111
+ });
1112
+ }
1113
+ function registerFetchWithSiweTool(server) {
1114
+ server.tool(
1115
+ "fetch_with_siwe",
1116
+ "Make an HTTP request with automatic SIWE wallet authentication. Useful for APIs that require wallet ownership proof.",
1117
+ {
1118
+ url: z5.string().url().describe("The URL to fetch"),
1119
+ method: z5.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).optional().default("GET"),
1120
+ body: z5.unknown().optional().describe("Request body for POST/PUT/PATCH"),
1121
+ headers: z5.record(z5.string()).optional().describe("Additional headers"),
1122
+ siweHeader: z5.string().optional().default("X-SIWE-PROOF").describe("Header name for SIWE proof"),
1123
+ chainId: z5.number().optional().describe(
1124
+ "Chain ID for SIWE proof (default: 8453 for Base). Common IDs: 1=mainnet, 8453=base, 84532=base-sepolia"
1125
+ ),
1126
+ chain: z5.enum(["mainnet", "base", "base-sepolia", "optimism", "arbitrum", "polygon", "sepolia"]).optional().describe("Chain name (alternative to chainId). Default: base")
1127
+ },
1128
+ async ({ url, method, body, headers, siweHeader, chainId, chain }) => {
1129
+ try {
1130
+ const { account } = await getOrCreateWallet();
1131
+ const parsedUrl = new URL(url);
1132
+ const resolvedChainId = chainId ?? (chain ? CHAIN_IDS2[chain] : CHAIN_IDS2.base);
1133
+ const proof = await createSiweProof(
1134
+ account,
1135
+ parsedUrl.host,
1136
+ parsedUrl.origin,
1137
+ resolvedChainId
1138
+ );
1139
+ const response = await fetch(url, {
1140
+ method,
1141
+ headers: {
1142
+ "Content-Type": "application/json",
1143
+ [siweHeader]: proof,
1144
+ ...headers
1145
+ },
1146
+ body: body ? JSON.stringify(body) : void 0
1147
+ });
1148
+ const responseHeaders = Object.fromEntries(response.headers.entries());
1149
+ if (!response.ok) {
1150
+ let errorBody;
1151
+ try {
1152
+ errorBody = await response.json();
1153
+ } catch {
1154
+ errorBody = await response.text();
1155
+ }
1156
+ return mcpError(`HTTP ${response.status}`, {
1157
+ statusCode: response.status,
1158
+ headers: responseHeaders,
1159
+ body: errorBody
1160
+ });
1161
+ }
1162
+ let data;
1163
+ const contentType = response.headers.get("content-type");
1164
+ if (contentType?.includes("application/json")) {
1165
+ data = await response.json();
1166
+ } else {
1167
+ data = await response.text();
1168
+ }
1169
+ return mcpSuccess({
1170
+ statusCode: response.status,
1171
+ headers: responseHeaders,
1172
+ data
1173
+ });
1174
+ } catch (err) {
1175
+ return mcpError(err, { tool: "fetch_with_siwe", url });
1176
+ }
1177
+ }
1178
+ );
1179
+ }
1180
+
1017
1181
  // src/index.ts
1018
1182
  async function main() {
1019
1183
  log.clear();
@@ -1026,7 +1190,9 @@ async function main() {
1026
1190
  registerQueryEndpointTool(server);
1027
1191
  registerValidatePaymentTool(server);
1028
1192
  registerExecuteCallTool(server);
1029
- log.info("Registered 4 tools: check_balance, query_endpoint, validate_payment, execute_call");
1193
+ registerCreateSiweProofTool(server);
1194
+ registerFetchWithSiweTool(server);
1195
+ log.info("Registered 6 tools: check_balance, query_endpoint, validate_payment, execute_call, create_siwe_proof, fetch_with_siwe");
1030
1196
  const transport = new StdioServerTransport();
1031
1197
  await server.connect(transport);
1032
1198
  log.info(`Connected to transport, ready for requests. Log file: ${log.path}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402scan-mcp",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Generic MCP server for calling x402-protected APIs with automatic payment handling",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -10,19 +10,11 @@
10
10
  "files": [
11
11
  "dist"
12
12
  ],
13
- "scripts": {
14
- "build": "tsup",
15
- "build:mcpb": "tsx scripts/build-mcpb.ts",
16
- "dev": "tsx src/index.ts",
17
- "dev:bun": "bun run src/index.ts",
18
- "typecheck": "tsc --noEmit",
19
- "publish-package": "tsx scripts/publish.ts",
20
- "prepublishOnly": "npm run build"
21
- },
22
13
  "dependencies": {
23
14
  "@modelcontextprotocol/sdk": "^1.6.1",
24
15
  "@x402/core": "^2.0.0",
25
16
  "@x402/evm": "^2.0.0",
17
+ "siwe": "^2.3.2",
26
18
  "viem": "^2.31.3",
27
19
  "zod": "^3.25.1"
28
20
  },
@@ -50,5 +42,13 @@
50
42
  "repository": {
51
43
  "type": "git",
52
44
  "url": "https://github.com/merit-systems/x402scan-mcp"
45
+ },
46
+ "scripts": {
47
+ "build": "tsup",
48
+ "build:mcpb": "tsx scripts/build-mcpb.ts",
49
+ "dev": "tsx src/index.ts",
50
+ "dev:bun": "bun run src/index.ts",
51
+ "typecheck": "tsc --noEmit",
52
+ "publish-package": "tsx scripts/publish.ts"
53
53
  }
54
- }
54
+ }