epistery 1.3.5 → 1.3.7

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/cli/epistery.mjs CHANGED
@@ -6,6 +6,7 @@
6
6
  * Usage:
7
7
  * epistery initialize <domain> Initialize domain with wallet
8
8
  * epistery curl [options] <url> Make authenticated HTTP request
9
+ * epistery mcp [options] <url> Stdio MCP bridge with bot-auth
9
10
  * epistery info [domain] Show domain information
10
11
  * epistery set-default <domain> Set default domain for CLI
11
12
  *
@@ -164,6 +165,9 @@ function showHelp() {
164
165
  console.log(
165
166
  " epistery initialize <domain> Initialize domain with wallet",
166
167
  );
168
+ console.log(
169
+ " epistery mcp [-w domain] <url> Stdio MCP bridge with bot-auth",
170
+ );
167
171
  console.log(
168
172
  " epistery curl [options] <url> Make authenticated HTTP request",
169
173
  );
@@ -225,6 +229,11 @@ function showHelp() {
225
229
  " -p, --port <port> Server port (for localhost development)",
226
230
  );
227
231
  console.log("");
232
+ console.log("mcp options:");
233
+ console.log(
234
+ " -w, --wallet <domain> Use specific domain wallet (overrides default)",
235
+ );
236
+ console.log("");
228
237
  console.log("curl options:");
229
238
  console.log(
230
239
  " -w, --wallet <domain> Use specific domain wallet (overrides default)",
@@ -261,6 +270,9 @@ function showHelp() {
261
270
  console.log(" epistery approve localhost channel::premium 0x1234... member -p 3001");
262
271
  console.log(" epistery deny localhost channel::premium 0x5678... -p 3001");
263
272
  console.log("");
273
+ console.log(" # MCP bridge (use with Claude Code or any MCP client)");
274
+ console.log(" claude mcp add --transport stdio geist-social -- epistery mcp https://geist.social");
275
+ console.log("");
264
276
  console.log(" # Make authenticated requests");
265
277
  console.log(" epistery curl https://example.com/api/data");
266
278
  console.log(' epistery curl --bot -X POST -d \'{"title":"Test"}\' <url>');
@@ -976,6 +988,112 @@ async function performCurl(options) {
976
988
  }
977
989
  }
978
990
 
991
+ /**
992
+ * MCP stdio bridge — reads JSON-RPC from stdin, POSTs to remote /mcp
993
+ * with bot-auth, writes responses to stdout.
994
+ *
995
+ * Usage: epistery mcp [-w domain] <url>
996
+ * claude mcp add --transport stdio my-site -- epistery mcp https://my-site.example
997
+ */
998
+ async function performMcp(args) {
999
+ // Parse args: [-w domain] <url>
1000
+ let domain = null;
1001
+ let url = null;
1002
+
1003
+ for (let i = 0; i < args.length; i++) {
1004
+ const arg = args[i];
1005
+ if (arg === '-w' || arg === '--wallet') {
1006
+ domain = args[++i];
1007
+ } else if (!arg.startsWith('-')) {
1008
+ url = arg;
1009
+ }
1010
+ }
1011
+
1012
+ if (!url) {
1013
+ console.error('Error: URL required');
1014
+ console.error('Usage: epistery mcp [-w domain] <url>');
1015
+ process.exit(1);
1016
+ }
1017
+
1018
+ // Ensure URL ends without trailing slash, append /mcp if not present
1019
+ const mcpUrl = url.replace(/\/+$/, '').endsWith('/mcp')
1020
+ ? url.replace(/\/+$/, '')
1021
+ : url.replace(/\/+$/, '') + '/mcp';
1022
+
1023
+ const wallet = CliWallet.load(domain);
1024
+ const fetch = (await import('node-fetch')).default;
1025
+
1026
+ // All log output to stderr so stdout stays clean for MCP JSON-RPC
1027
+ process.stderr.write(`[epistery-mcp] Bridge: ${wallet.address} -> ${mcpUrl}\n`);
1028
+
1029
+ const readline = await import('readline');
1030
+ const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
1031
+
1032
+ for await (const line of rl) {
1033
+ if (!line.trim()) continue;
1034
+
1035
+ let msg;
1036
+ try {
1037
+ msg = JSON.parse(line);
1038
+ } catch {
1039
+ // Not valid JSON — ignore
1040
+ continue;
1041
+ }
1042
+
1043
+ const isNotification = msg.id === undefined || msg.id === null;
1044
+
1045
+ try {
1046
+ // Fresh bot-auth header per request (timestamp-based replay protection)
1047
+ const authHeader = await wallet.createBotAuthHeader();
1048
+
1049
+ const res = await fetch(mcpUrl, {
1050
+ method: 'POST',
1051
+ headers: {
1052
+ 'Authorization': authHeader,
1053
+ 'Content-Type': 'application/json',
1054
+ 'Accept': 'application/json'
1055
+ },
1056
+ body: JSON.stringify(msg)
1057
+ });
1058
+
1059
+ if (res.status === 204) {
1060
+ // No content (notification acknowledged) — nothing to write
1061
+ continue;
1062
+ }
1063
+
1064
+ const body = await res.text();
1065
+
1066
+ if (!res.ok) {
1067
+ // Server error — wrap in JSON-RPC error if this was a request
1068
+ if (!isNotification) {
1069
+ const errResponse = {
1070
+ jsonrpc: '2.0',
1071
+ error: { code: -32000, message: `HTTP ${res.status}: ${body}` },
1072
+ id: msg.id
1073
+ };
1074
+ process.stdout.write(JSON.stringify(errResponse) + '\n');
1075
+ }
1076
+ continue;
1077
+ }
1078
+
1079
+ if (body) {
1080
+ process.stdout.write(body.trim() + '\n');
1081
+ }
1082
+ } catch (err) {
1083
+ // Network error
1084
+ if (!isNotification) {
1085
+ const errResponse = {
1086
+ jsonrpc: '2.0',
1087
+ error: { code: -32000, message: err.message },
1088
+ id: msg.id
1089
+ };
1090
+ process.stdout.write(JSON.stringify(errResponse) + '\n');
1091
+ }
1092
+ process.stderr.write(`[epistery-mcp] Error: ${err.message}\n`);
1093
+ }
1094
+ }
1095
+ }
1096
+
979
1097
  async function main() {
980
1098
  const command = process.argv[2];
981
1099
  const rawArgs = process.argv.slice(3);
@@ -996,6 +1114,18 @@ async function main() {
996
1114
  await initializeDomain(args[0]);
997
1115
  break;
998
1116
 
1117
+ case "mcp":
1118
+ if (rawArgs.length === 0) {
1119
+ console.error("Error: URL required");
1120
+ console.error("Usage: epistery mcp [-w domain] <url>");
1121
+ console.error("");
1122
+ console.error("Stdio MCP bridge with bot-auth. Register with Claude Code:");
1123
+ console.error(" claude mcp add --transport stdio my-site -- epistery mcp https://my-site.example");
1124
+ process.exit(1);
1125
+ }
1126
+ await performMcp(rawArgs);
1127
+ break;
1128
+
999
1129
  case "curl":
1000
1130
  if (rawArgs.length === 0) {
1001
1131
  console.error("Error: URL required");
package/default.ini CHANGED
@@ -1,6 +1,6 @@
1
1
  [profile]
2
- name=
3
- email=
2
+ name=Rootz Corp
3
+ email=support@rootz.global
4
4
 
5
5
  [ipfs]
6
6
  url=https://rootz.digital/api/v0
@@ -12,20 +12,3 @@ rpc=https://eth.llamarpc.com
12
12
  nativeCurrencyName=Ether
13
13
  nativeCurrencySymbol=ETH
14
14
  nativeCurrencyDecimals=18
15
-
16
- ; Additional supported chains:
17
- ; Polygon Mainnet (POL):
18
- ; chainId=137
19
- ; name=Polygon Mainnet
20
- ; rpc=https://polygon-rpc.com
21
- ; nativeCurrencyName=POL
22
- ; nativeCurrencySymbol=POL
23
- ; nativeCurrencyDecimals=18
24
- ;
25
- ; Japan Open Chain (JOC):
26
- ; chainId=81
27
- ; name=Japan Open Chain
28
- ; rpc=https://rpc-2.japanopenchain.org:8545
29
- ; nativeCurrencyName=Japan Open Chain Token
30
- ; nativeCurrencySymbol=JOC
31
- ; nativeCurrencyDecimals=18
package/index.mjs CHANGED
@@ -42,6 +42,15 @@ class EpisteryAttach {
42
42
  this.domain = getDomainConfig(domain);
43
43
  }
44
44
 
45
+ /**
46
+ * Get the server wallet as an ethers.js Signer for the current domain.
47
+ * Used by OAuthServer, MCPServer, and agents that need signing capability.
48
+ */
49
+ get signer() {
50
+ if (!this.domainName) return null;
51
+ return Utils.InitServerWallet(this.domainName) || null;
52
+ }
53
+
45
54
  async attach(app, rootPath) {
46
55
  this.rootPath = rootPath || "/.well-known/epistery";
47
56
  app.locals.epistery = this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epistery",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "Epistery brings blockchain capabilities to mundane web tasks like engagement metrics, authentication and commerce of all sorts.",
5
5
  "author": "Rootz Corp.",
6
6
  "license": "MIT",