@hol-org/hashnet-mcp 0.1.0-canary.15.745b5eb

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/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # HOL MCP Server POC
2
+
3
+ No-stubs MCP server that bridges MCP tools to the HOL Registry Broker using `@hashgraphonline/standards-sdk`.
4
+
5
+ ## Quickstart
6
+
7
+ 1. Install dependencies:
8
+ - `pnpm install`
9
+ 2. Configure env:
10
+ - `cp .env.example .env`
11
+ - set `REGISTRY_BROKER_API_KEY` for paid flows, or configure ledger auth with `LEDGER_ACCOUNT_ID`/`HEDERA_ACCOUNT_ID` plus the matching network and private key
12
+ 3. Run transports:
13
+ - HTTP: `pnpm dev:http`
14
+ - stdio: `pnpm dev:stdio`
15
+ - HTTP + legacy SSE: `pnpm dev:http:compat`
16
+
17
+ ## NPX Launch
18
+
19
+ Once this package is published, you can launch it directly with `npx`:
20
+
21
+ - stdio: `REGISTRY_BROKER_API_KEY=... npx @hol-org/hashnet-mcp --stdio`
22
+ - HTTP: `REGISTRY_BROKER_API_KEY=... npx @hol-org/hashnet-mcp --http --host 127.0.0.1 --port 3333`
23
+ - help: `npx @hol-org/hashnet-mcp --help`
24
+
25
+ Ledger-auth launches use the same binary and env-based credentials:
26
+
27
+ - stdio: `LEDGER_ACCOUNT_ID=0.0.12345 HEDERA_NETWORK=hedera:testnet HEDERA_PRIVATE_KEY=... npx @hol-org/hashnet-mcp --stdio`
28
+
29
+ When installed globally or linked locally, the binary name is `hashnet-mcp`.
30
+
31
+ Supported CLI flags:
32
+
33
+ - `--transport <stdio|http>`
34
+ - `--stdio`
35
+ - `--http`
36
+ - `--host <host>`
37
+ - `--port <port>`
38
+ - `--allowed-origins <csv>`
39
+ - `--broker-url <url>`
40
+ - `--bearer-token <token>`
41
+ - `--log-level <level>`
42
+ - `--legacy-sse`
43
+
44
+ ## Commands
45
+
46
+ - `pnpm build`
47
+ - `pnpm start`
48
+ - `pnpm test:run`
49
+ - `pnpm test:coverage`
50
+ - `pnpm check:no-stubs`
51
+ - `pnpm smoke:http`
52
+ - `pnpm smoke:stdio`
53
+
54
+ ## Security Defaults
55
+
56
+ - Binds to `127.0.0.1` by default.
57
+ - Validates `Origin` for HTTP requests when present.
58
+ - Supports optional `MCP_SERVER_BEARER_TOKEN` gate for HTTP transport.
59
+ - Reaps idle HTTP sessions and enforces a maximum active session count.
60
+ - Redacts sensitive secrets in logs.
61
+
62
+ ## Tool Surface
63
+
64
+ - Discovery: `hol.stats`, `hol.capabilities`, `hol.search`, `hol.vectorSearch`, `hol.resolveUaid`
65
+ - Chat: `hol.chat.createSession`, `hol.chat.sendMessage`, `hol.chat.history`, `hol.chat.end`
66
+ - Registration: `hol.getRegistrationQuote`, `hol.registerAgent`, `hol.waitForRegistrationCompletion`
67
+ - Workflows: `workflow.discovery`, `workflow.delegate`, `workflow.registration`
68
+
69
+ All tools now return a structured success envelope in `structuredContent`:
70
+
71
+ - `ok`
72
+ - `data`
73
+ - `meta`
74
+
75
+ Tool failures return `isError: true` plus a structured error envelope with machine-readable `code`, `category`, and `retryable` fields.
76
+
77
+ ## Transport Compatibility
78
+
79
+ | Transport | Endpoint(s) | Status |
80
+ |---|---|---|
81
+ | stdio | process stdin/stdout | supported |
82
+ | Streamable HTTP | `/mcp`, `/mcp/stream` | supported |
83
+ | legacy HTTP+SSE | `/mcp/sse`, `/mcp/messages` | supported behind `FEATURE_LEGACY_SSE=1` |
84
+
85
+ ## HTTP Runtime Endpoints
86
+
87
+ - MCP: `/mcp`, `/mcp/stream`
88
+ - Health: `/healthz`
89
+ - Readiness: `/readyz`
90
+ - Metrics: `/metrics`
91
+
92
+ ## Environment Matrix
93
+
94
+ | Variable | Required | Notes |
95
+ |---|---|---|
96
+ | `REGISTRY_BROKER_API_URL` | no | defaults to `https://hol.org/registry/api/v1` |
97
+ | `REGISTRY_BROKER_API_KEY` | no | enables paid tools with a static broker API key |
98
+ | `BROKER_REQUEST_TIMEOUT_MS` | no | default upstream request timeout is `15000` |
99
+ | `MCP_TRANSPORT` | no | `http` (default) or `stdio` |
100
+ | `MCP_HOST` | no | defaults to `127.0.0.1` |
101
+ | `MCP_PORT` | no | defaults to `3333` |
102
+ | `MCP_ALLOWED_ORIGINS` | no | used for HTTP Origin validation |
103
+ | `MCP_SERVER_BEARER_TOKEN` | no | required when binding to non-local host |
104
+ | `MCP_SESSION_IDLE_TTL_MS` | no | idle HTTP session timeout, defaults to `900000` |
105
+ | `MCP_SESSION_MAX_COUNT` | no | maximum active HTTP sessions, defaults to `250` |
106
+ | `MCP_SESSION_REAP_INTERVAL_MS` | no | idle session reap interval, defaults to `60000` |
107
+ | `LEDGER_ACCOUNT_ID` | no | generic ledger identity used for ledger-auth flows; falls back to `HEDERA_ACCOUNT_ID` |
108
+ | `HEDERA_ACCOUNT_ID` | no | Hedera account id for ledger auth and backwards compatibility |
109
+ | `HEDERA_NETWORK` | no | Hedera ledger network, for example `hedera:testnet` |
110
+ | `HEDERA_PRIVATE_KEY` | no | Hedera private key for broker ledger auth |
111
+ | `EVM_LEDGER_NETWORK` | no | EVM CAIP-2 network id, for example `eip155:1` |
112
+ | `ETH_PK` | no | EVM private key for broker ledger auth |
113
+
114
+ ## No-Stubs Validation
115
+
116
+ - Static stub ban check in CI.
117
+ - Smoke tests validate initialize -> tools/list -> real tool calls.
118
+ - Live Broker calls required for final acceptance gates.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/cli/up.js";
package/dist/cli/up.js ADDED
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/args.ts
4
+ var HELP_TEXT = `HOL MCP Server
5
+
6
+ Usage:
7
+ npx @hol-org/hashnet-mcp [options]
8
+
9
+ Options:
10
+ --transport <stdio|http> Select MCP transport
11
+ --stdio Shortcut for --transport stdio
12
+ --http Shortcut for --transport http
13
+ --host <host> HTTP bind host
14
+ --port <port> HTTP bind port
15
+ --allowed-origins <csv> Comma-separated HTTP origin allowlist
16
+ --broker-url <url> Registry Broker base URL
17
+ --bearer-token <token> HTTP bearer token gate
18
+ --log-level <level> Pino log level
19
+ --legacy-sse Enable legacy SSE compatibility routes
20
+ --help Show this help
21
+
22
+ Examples:
23
+ npx @hol-org/hashnet-mcp --stdio
24
+ npx @hol-org/hashnet-mcp --http --host 127.0.0.1 --port 3333
25
+ REGISTRY_BROKER_API_KEY=... npx @hol-org/hashnet-mcp --stdio
26
+ `;
27
+ function requireValue(argv, index, flag) {
28
+ const value = argv[index];
29
+ if (!value || value.startsWith("--")) {
30
+ throw new Error(`${flag} requires a value`);
31
+ }
32
+ return value;
33
+ }
34
+ function parsePort(value) {
35
+ const parsed = Number(value);
36
+ if (!Number.isInteger(parsed) || parsed <= 0) {
37
+ throw new Error(`--port must be a positive integer, received "${value}"`);
38
+ }
39
+ return String(parsed);
40
+ }
41
+ function parseCliArgs(argv) {
42
+ const env = {};
43
+ for (let index = 0; index < argv.length; index += 1) {
44
+ const arg = argv[index];
45
+ switch (arg) {
46
+ case "--help":
47
+ return {
48
+ env,
49
+ helpText: HELP_TEXT
50
+ };
51
+ case "--transport": {
52
+ const value = requireValue(argv, index + 1, "--transport");
53
+ if (value !== "stdio" && value !== "http") {
54
+ throw new Error(`--transport must be "stdio" or "http", received "${value}"`);
55
+ }
56
+ env.MCP_TRANSPORT = value;
57
+ index += 1;
58
+ break;
59
+ }
60
+ case "--stdio":
61
+ env.MCP_TRANSPORT = "stdio";
62
+ break;
63
+ case "--http":
64
+ env.MCP_TRANSPORT = "http";
65
+ break;
66
+ case "--host":
67
+ env.MCP_HOST = requireValue(argv, index + 1, "--host");
68
+ index += 1;
69
+ break;
70
+ case "--port":
71
+ env.MCP_PORT = parsePort(requireValue(argv, index + 1, "--port"));
72
+ index += 1;
73
+ break;
74
+ case "--allowed-origins":
75
+ env.MCP_ALLOWED_ORIGINS = requireValue(argv, index + 1, "--allowed-origins");
76
+ index += 1;
77
+ break;
78
+ case "--broker-url":
79
+ env.REGISTRY_BROKER_API_URL = requireValue(argv, index + 1, "--broker-url");
80
+ index += 1;
81
+ break;
82
+ case "--bearer-token":
83
+ env.MCP_SERVER_BEARER_TOKEN = requireValue(argv, index + 1, "--bearer-token");
84
+ index += 1;
85
+ break;
86
+ case "--log-level":
87
+ env.LOG_LEVEL = requireValue(argv, index + 1, "--log-level");
88
+ index += 1;
89
+ break;
90
+ case "--legacy-sse":
91
+ env.FEATURE_LEGACY_SSE = "1";
92
+ break;
93
+ default:
94
+ throw new Error(`Unknown argument: ${arg}`);
95
+ }
96
+ }
97
+ return { env };
98
+ }
99
+
100
+ // src/cli/up.ts
101
+ async function main() {
102
+ try {
103
+ const parsed = parseCliArgs(process.argv.slice(2));
104
+ if (parsed.helpText) {
105
+ process.stdout.write(`${parsed.helpText}
106
+ `);
107
+ return;
108
+ }
109
+ Object.assign(process.env, parsed.env);
110
+ await import("../index.js");
111
+ } catch (error) {
112
+ const message = error instanceof Error ? error.message : String(error);
113
+ process.stderr.write(`${message}
114
+ `);
115
+ process.exitCode = 1;
116
+ }
117
+ }
118
+ void main();
119
+ //# sourceMappingURL=up.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/args.ts","../../src/cli/up.ts"],"sourcesContent":["export interface CliParseResult {\n env: Record<string, string>;\n helpText?: string;\n}\n\nconst HELP_TEXT = `HOL MCP Server\n\nUsage:\n npx @hol-org/hashnet-mcp [options]\n\nOptions:\n --transport <stdio|http> Select MCP transport\n --stdio Shortcut for --transport stdio\n --http Shortcut for --transport http\n --host <host> HTTP bind host\n --port <port> HTTP bind port\n --allowed-origins <csv> Comma-separated HTTP origin allowlist\n --broker-url <url> Registry Broker base URL\n --bearer-token <token> HTTP bearer token gate\n --log-level <level> Pino log level\n --legacy-sse Enable legacy SSE compatibility routes\n --help Show this help\n\nExamples:\n npx @hol-org/hashnet-mcp --stdio\n npx @hol-org/hashnet-mcp --http --host 127.0.0.1 --port 3333\n REGISTRY_BROKER_API_KEY=... npx @hol-org/hashnet-mcp --stdio\n`;\n\nfunction requireValue(argv: string[], index: number, flag: string): string {\n const value = argv[index];\n if (!value || value.startsWith(\"--\")) {\n throw new Error(`${flag} requires a value`);\n }\n\n return value;\n}\n\nfunction parsePort(value: string): string {\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new Error(`--port must be a positive integer, received \"${value}\"`);\n }\n\n return String(parsed);\n}\n\nexport function parseCliArgs(argv: string[]): CliParseResult {\n const env: Record<string, string> = {};\n\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index];\n\n switch (arg) {\n case \"--help\":\n return {\n env,\n helpText: HELP_TEXT,\n };\n case \"--transport\": {\n const value = requireValue(argv, index + 1, \"--transport\");\n if (value !== \"stdio\" && value !== \"http\") {\n throw new Error(`--transport must be \"stdio\" or \"http\", received \"${value}\"`);\n }\n env.MCP_TRANSPORT = value;\n index += 1;\n break;\n }\n case \"--stdio\":\n env.MCP_TRANSPORT = \"stdio\";\n break;\n case \"--http\":\n env.MCP_TRANSPORT = \"http\";\n break;\n case \"--host\":\n env.MCP_HOST = requireValue(argv, index + 1, \"--host\");\n index += 1;\n break;\n case \"--port\":\n env.MCP_PORT = parsePort(requireValue(argv, index + 1, \"--port\"));\n index += 1;\n break;\n case \"--allowed-origins\":\n env.MCP_ALLOWED_ORIGINS = requireValue(argv, index + 1, \"--allowed-origins\");\n index += 1;\n break;\n case \"--broker-url\":\n env.REGISTRY_BROKER_API_URL = requireValue(argv, index + 1, \"--broker-url\");\n index += 1;\n break;\n case \"--bearer-token\":\n env.MCP_SERVER_BEARER_TOKEN = requireValue(argv, index + 1, \"--bearer-token\");\n index += 1;\n break;\n case \"--log-level\":\n env.LOG_LEVEL = requireValue(argv, index + 1, \"--log-level\");\n index += 1;\n break;\n case \"--legacy-sse\":\n env.FEATURE_LEGACY_SSE = \"1\";\n break;\n default:\n throw new Error(`Unknown argument: ${arg}`);\n }\n }\n\n return { env };\n}\n\nexport function getCliHelpText(): string {\n return HELP_TEXT;\n}\n","#!/usr/bin/env node\n\nimport { parseCliArgs } from \"./args.js\";\n\nasync function main(): Promise<void> {\n try {\n const parsed = parseCliArgs(process.argv.slice(2));\n\n if (parsed.helpText) {\n process.stdout.write(`${parsed.helpText}\\n`);\n return;\n }\n\n Object.assign(process.env, parsed.env);\n await import(\"../index.js\");\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`${message}\\n`);\n process.exitCode = 1;\n }\n}\n\nvoid main();\n"],"mappings":";;;AAKA,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBlB,SAAS,aAAa,MAAgB,OAAe,MAAsB;AACzE,QAAM,QAAQ,KAAK,KAAK;AACxB,MAAI,CAAC,SAAS,MAAM,WAAW,IAAI,GAAG;AACpC,UAAM,IAAI,MAAM,GAAG,IAAI,mBAAmB;AAAA,EAC5C;AAEA,SAAO;AACT;AAEA,SAAS,UAAU,OAAuB;AACxC,QAAM,SAAS,OAAO,KAAK;AAC3B,MAAI,CAAC,OAAO,UAAU,MAAM,KAAK,UAAU,GAAG;AAC5C,UAAM,IAAI,MAAM,gDAAgD,KAAK,GAAG;AAAA,EAC1E;AAEA,SAAO,OAAO,MAAM;AACtB;AAEO,SAAS,aAAa,MAAgC;AAC3D,QAAM,MAA8B,CAAC;AAErC,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAM,MAAM,KAAK,KAAK;AAEtB,YAAQ,KAAK;AAAA,MACX,KAAK;AACH,eAAO;AAAA,UACL;AAAA,UACA,UAAU;AAAA,QACZ;AAAA,MACF,KAAK,eAAe;AAClB,cAAM,QAAQ,aAAa,MAAM,QAAQ,GAAG,aAAa;AACzD,YAAI,UAAU,WAAW,UAAU,QAAQ;AACzC,gBAAM,IAAI,MAAM,oDAAoD,KAAK,GAAG;AAAA,QAC9E;AACA,YAAI,gBAAgB;AACpB,iBAAS;AACT;AAAA,MACF;AAAA,MACA,KAAK;AACH,YAAI,gBAAgB;AACpB;AAAA,MACF,KAAK;AACH,YAAI,gBAAgB;AACpB;AAAA,MACF,KAAK;AACH,YAAI,WAAW,aAAa,MAAM,QAAQ,GAAG,QAAQ;AACrD,iBAAS;AACT;AAAA,MACF,KAAK;AACH,YAAI,WAAW,UAAU,aAAa,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAChE,iBAAS;AACT;AAAA,MACF,KAAK;AACH,YAAI,sBAAsB,aAAa,MAAM,QAAQ,GAAG,mBAAmB;AAC3E,iBAAS;AACT;AAAA,MACF,KAAK;AACH,YAAI,0BAA0B,aAAa,MAAM,QAAQ,GAAG,cAAc;AAC1E,iBAAS;AACT;AAAA,MACF,KAAK;AACH,YAAI,0BAA0B,aAAa,MAAM,QAAQ,GAAG,gBAAgB;AAC5E,iBAAS;AACT;AAAA,MACF,KAAK;AACH,YAAI,YAAY,aAAa,MAAM,QAAQ,GAAG,aAAa;AAC3D,iBAAS;AACT;AAAA,MACF,KAAK;AACH,YAAI,qBAAqB;AACzB;AAAA,MACF;AACE,cAAM,IAAI,MAAM,qBAAqB,GAAG,EAAE;AAAA,IAC9C;AAAA,EACF;AAEA,SAAO,EAAE,IAAI;AACf;;;ACvGA,eAAe,OAAsB;AACnC,MAAI;AACF,UAAM,SAAS,aAAa,QAAQ,KAAK,MAAM,CAAC,CAAC;AAEjD,QAAI,OAAO,UAAU;AACnB,cAAQ,OAAO,MAAM,GAAG,OAAO,QAAQ;AAAA,CAAI;AAC3C;AAAA,IACF;AAEA,WAAO,OAAO,QAAQ,KAAK,OAAO,GAAG;AACrC,UAAM,OAAO,aAAa;AAAA,EAC5B,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AACnC,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,KAAK,KAAK;","names":[]}