@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 +17 -0
- package/README.md +118 -0
- package/bin/hashnet-mcp.js +2 -0
- package/dist/cli/up.js +119 -0
- package/dist/cli/up.js.map +1 -0
- package/dist/index.js +2223 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
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.
|
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":[]}
|