healthcloud-cli 0.1.0__tar.gz

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.
@@ -0,0 +1,81 @@
1
+ # Logs
2
+ logs/
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+
9
+ # Environment files
10
+ .env
11
+ .env.*
12
+ !.env.example
13
+ **/live-state.json
14
+
15
+ # Node / npm
16
+ node_modules/
17
+ .npm/
18
+ .pnpm-store/
19
+ dist/
20
+ !packages/npm/dist/
21
+ !packages/npm/dist/**
22
+ build/
23
+
24
+ # packages/cli/npm bundles the manifest from packages/cli/contracts at build/
25
+ # test time (scripts/copy-manifest.cjs) — that copy is generated, not source.
26
+ packages/cli/npm/contracts/
27
+ coverage/
28
+ *.tsbuildinfo
29
+
30
+ # Python / pip
31
+ __pycache__/
32
+ *.py[cod]
33
+ *.pyo
34
+ .Python
35
+ .venv/
36
+ venv/
37
+ env/
38
+ pip-wheel-metadata/
39
+ *.egg-info/
40
+ .pytest_cache/
41
+ .mypy_cache/
42
+ .ruff_cache/
43
+ htmlcov/
44
+
45
+ # Java / Maven
46
+ target/
47
+ .mvn/timing.properties
48
+ .mvn/wrapper/maven-wrapper.jar
49
+ *.class
50
+ *.jar
51
+ *.war
52
+ *.ear
53
+
54
+ # .NET / NuGet
55
+ # Scoped to packages/nuget/ specifically — an unscoped `bin/`/`obj/` matches
56
+ # a directory of that name at ANY depth (gitignore has no implicit anchor),
57
+ # which silently swallowed the real source file packages/cli/npm/src/bin/hc.ts
58
+ # and broke that package's CI build (the file was never committed).
59
+ packages/nuget/**/bin/
60
+ packages/nuget/**/obj/
61
+ TestResults/
62
+ *.nupkg
63
+ *.snupkg
64
+ *.user
65
+ *.suo
66
+
67
+ # IDEs and editors
68
+ .idea/
69
+ .vscode/
70
+ *.swp
71
+ *.swo
72
+ .DS_Store
73
+ Thumbs.db
74
+
75
+ # Build outputs and caches
76
+ out/
77
+ tmp/
78
+ temp/
79
+ .cache/
80
+ .parcel-cache/
81
+ .turbo/
@@ -0,0 +1,236 @@
1
+ Metadata-Version: 2.4
2
+ Name: healthcloud-cli
3
+ Version: 0.1.0
4
+ Summary: Command-line interface for the HealthCloud MCP gateway, generated from the shared MCP tool manifest.
5
+ Author: Healthcheck Systems Inc
6
+ License-Expression: MIT
7
+ Keywords: cli,health-cloud,healthcare,healthcloud,mcp
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: click>=8.1
10
+ Requires-Dist: healthcloud-sdk>=0.9.0
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest>=8.0; extra == 'dev'
13
+ Requires-Dist: respx>=0.21; extra == 'dev'
14
+ Description-Content-Type: text/markdown
15
+
16
+ # healthcloud-cli
17
+
18
+ `hc` is the HealthCloud MCP gateway CLI. It has exactly one subcommand per
19
+ MCP tool -- **996 commands across 12 audiences** (`patient`, `fieldagent`,
20
+ `ehr`, `vitals`, `diagnostics`, `appointments`, `graph`, `person`,
21
+ `provider`, `tenantadmin`, `connectors`, `telehealth`) -- generated
22
+ dynamically at startup from a shared manifest. Nothing here is hand-written
23
+ per tool: the same manifest also drives the sibling NPM CLI (`@healthcloud
24
+ CLI` in `packages/cli/npm`), so command names match exactly between the two.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pip install healthcloud-cli
30
+ ```
31
+
32
+ This installs the `hc` console script plus its dependency, the
33
+ [`healthcloud-sdk`](../../pip) package, which does the actual HTTP/JSON-RPC
34
+ work against the MCP gateway.
35
+
36
+ ## Local development
37
+
38
+ `healthcloud-sdk` is not yet published to PyPI, so for local development you
39
+ must install it in editable mode from this repo *before* installing this
40
+ package:
41
+
42
+ ```bash
43
+ cd packages/cli/pip
44
+
45
+ # 1. Install the local SDK in editable mode (resolves `healthcloud-sdk` without PyPI)
46
+ pip install -e ../../pip
47
+
48
+ # 2. Install this CLI package (+ dev/test dependencies) in editable mode
49
+ pip install -e ".[dev]"
50
+
51
+ # 3. Run the test suite
52
+ python -m pytest
53
+
54
+ # 4. Try it
55
+ hc --help
56
+ hc mcp tools list --audience patient
57
+ hc mcp patient get-patient --help
58
+ ```
59
+
60
+ The bundled tool manifest (`healthcloud_cli/contracts/mcp-tools.manifest.json`)
61
+ is a copy of `packages/cli/contracts/mcp-tools.manifest.json`. Re-sync it
62
+ after pulling manifest changes with:
63
+
64
+ ```bash
65
+ python scripts/bundle_manifest.py
66
+ ```
67
+
68
+ This also runs automatically as a hatchling build hook whenever you `python
69
+ -m build`, so a built wheel/sdist is always self-contained and never depends
70
+ on a relative path outside the installed package.
71
+
72
+ ## Authentication & configuration
73
+
74
+ Every command accepts these global options (place them before the `mcp`
75
+ subcommand):
76
+
77
+ | Flag | Env var | Meaning |
78
+ |-------------------|--------------------|-----------------------------------------------|
79
+ | `--access-token` | `HC_ACCESS_TOKEN` | Bearer token sent to the MCP gateway |
80
+ | `--base-url` | `HC_MCP_BASE_URL` | Override the MCP gateway base URL |
81
+ | `--profile` | `HC_PROFILE` | Named profile (see below) |
82
+ | `--output` | -- | `pretty` (default) \| `json` \| `raw` |
83
+ | `--raw` | -- | Shortcut for `--output raw` |
84
+ | `--verbose` | -- | Print request diagnostics to stderr |
85
+
86
+ Precedence, highest wins: **explicit CLI flag > environment variable >
87
+ profile file value > built-in default** (`environment` defaults to `"dev"`;
88
+ `accessToken`/`baseUrl` default to unset). The resolved access token is never
89
+ written to logs, generated files, or test snapshots.
90
+
91
+ ### Optional profile file
92
+
93
+ `~/.healthcloud/cli/profiles.json`:
94
+
95
+ ```json
96
+ {
97
+ "dev-mia": {
98
+ "baseUrl": "https://dev-api-mcp.health.cloud",
99
+ "accessToken": "eyJ...",
100
+ "environment": "dev"
101
+ }
102
+ }
103
+ ```
104
+
105
+ A missing profiles file is not an error -- profiles are entirely optional. If
106
+ `--profile`/`HC_PROFILE` names a profile and the file (or that entry) is
107
+ missing, `hc` exits with a clear usage error rather than silently ignoring
108
+ it.
109
+
110
+ ```bash
111
+ hc --profile dev-mia mcp patient get-patient --patient-id patient-123
112
+ ```
113
+
114
+ ## Listing and inspecting tools
115
+
116
+ ```bash
117
+ # Local (bundled manifest, no network call)
118
+ hc mcp tools list
119
+ hc mcp tools list --audience patient
120
+
121
+ # Live gateway (requires --audience)
122
+ hc mcp tools list --audience patient --remote
123
+
124
+ # Full manifest entry for one tool (description, inputSchema, method/path)
125
+ hc mcp tools show patient add_insurance --output json
126
+ ```
127
+
128
+ ## Calling a tool
129
+
130
+ Every manifest tool is its own subcommand, grouped by audience:
131
+
132
+ ```bash
133
+ hc mcp patient get-patient --patient-id patient-123
134
+ hc mcp appointments book-appointment --patient-id patient-123 --slot-id slot-456
135
+ ```
136
+
137
+ Run `--help` on any generated command to see its real manifest description
138
+ and arguments:
139
+
140
+ ```bash
141
+ hc mcp patient get-patient --help
142
+ ```
143
+
144
+ ### Argument flags
145
+
146
+ - **Primitive properties** (`string`/`number`/`integer`/`boolean`) become a
147
+ normal flag in kebab-case, e.g. `patient_id` -> `--patient-id`.
148
+ - `enum` values are validated; invalid values are rejected before any
149
+ network call.
150
+ - `minimum`/`maximum`/`exclusiveMinimum`/`exclusiveMaximum` are enforced
151
+ the same way.
152
+ - Boolean properties are a tri-state flag pair: `--flag/--no-flag`.
153
+ Passing neither leaves the value unset (falls back to the manifest
154
+ default or an `--input`/`--stdin` value, if any); passing one sets it
155
+ explicitly to `true`/`false`.
156
+ - **Object/array properties are never flattened.** They get a single
157
+ `--<prop>-json` flag that takes a raw JSON string, e.g.:
158
+
159
+ ```bash
160
+ hc mcp patient create-medication \
161
+ --patient-id patient-123 \
162
+ --name "Metformin" \
163
+ --dosage-json '{"value":10,"unit":"mg","frequency":"once_daily"}'
164
+ ```
165
+ - Path parameters (from `{placeholders}` in the tool's HTTP path) are always
166
+ required, in addition to whatever `inputSchema.required` lists.
167
+
168
+ ### Bulk input: `--input` / `--stdin`
169
+
170
+ ```bash
171
+ hc mcp appointments book-appointment --input request.json
172
+ cat request.json | hc mcp appointments book-appointment --stdin
173
+ ```
174
+
175
+ `--input <file>` and `--stdin` both supply a *base* JSON object of
176
+ arguments. `--input` and `--stdin` cannot be combined. Merge precedence
177
+ (highest wins): **manifest defaults < `--input`/`--stdin` object < explicit
178
+ flags** -- i.e. an explicit flag you actually pass always overrides the same
179
+ key coming from a file or stdin, which in turn overrides the schema default.
180
+
181
+ After merging, the final object is validated against the tool's
182
+ `inputSchema` (required fields present, correct types, enum membership,
183
+ numeric bounds). Any validation failure prints a clear message to stderr and
184
+ exits **2**, without making a network call.
185
+
186
+ ### `hc mcp call` -- generic escape hatch
187
+
188
+ `hc mcp call` dispatches to any MCP tool by its exact snake_case tool name --
189
+ including one not yet present in the bundled manifest (the tool name itself
190
+ is never validated against the manifest, it's just forwarded):
191
+
192
+ ```bash
193
+ hc mcp call patient get_patient --input '{"patient_id":"patient-123"}'
194
+ hc mcp call patient get_patient --input-file request.json
195
+ cat request.json | hc mcp call patient get_patient --stdin
196
+ ```
197
+
198
+ Note the deliberate inconsistency versus named commands: here `--input` takes
199
+ an inline JSON **value**, not a file path -- use `--input-file` for a file.
200
+ Exactly one of `--input` / `--input-file` / `--stdin` may be given (or none,
201
+ meaning `{}`).
202
+
203
+ ## Output modes
204
+
205
+ The MCP tool-call result is `{ content: [{type:"text", text: "..."}],
206
+ is_error: bool }` from the JSON-RPC response's `.result`, or the JSON-RPC
207
+ `.error` object if the gateway returned one.
208
+
209
+ - **`pretty`** (default): if `content[0].text` parses as JSON, pretty-prints
210
+ the parsed value; otherwise prints the raw text. On a JSON-RPC error,
211
+ prints `error.message` (and `error.code` with `--verbose`) to stderr.
212
+ - **`json`**: prints the tool result's parsed JSON (or raw text if
213
+ unparseable) to stdout, with no envelope.
214
+ - **`raw`**: prints the complete JSON-RPC envelope (`id`, `jsonrpc`,
215
+ `result`, `error`) as returned by the gateway.
216
+
217
+ Diagnostics and `--verbose` logs always go to stderr -- stdout stays
218
+ pipeable in every mode.
219
+
220
+ ## Exit codes
221
+
222
+ | Code | Meaning |
223
+ |------|-----------------------------------------------------------------------|
224
+ | `0` | Success |
225
+ | `2` | Local input validation failure (bad JSON, missing required field, invalid enum/number, `--input`+`--stdin` both given, unknown option) -- no network call made |
226
+ | `3` | HTTP/network failure talking to the MCP gateway |
227
+ | `4` | JSON-RPC error response (`.error` is not `None`) |
228
+ | `5` | MCP tool result reported `is_error: true` |
229
+
230
+ ## Building
231
+
232
+ ```bash
233
+ pip install build
234
+ python -m build
235
+ python -m zipfile -l dist/*.whl # confirm the bundled manifest is included
236
+ ```
@@ -0,0 +1,221 @@
1
+ # healthcloud-cli
2
+
3
+ `hc` is the HealthCloud MCP gateway CLI. It has exactly one subcommand per
4
+ MCP tool -- **996 commands across 12 audiences** (`patient`, `fieldagent`,
5
+ `ehr`, `vitals`, `diagnostics`, `appointments`, `graph`, `person`,
6
+ `provider`, `tenantadmin`, `connectors`, `telehealth`) -- generated
7
+ dynamically at startup from a shared manifest. Nothing here is hand-written
8
+ per tool: the same manifest also drives the sibling NPM CLI (`@healthcloud
9
+ CLI` in `packages/cli/npm`), so command names match exactly between the two.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install healthcloud-cli
15
+ ```
16
+
17
+ This installs the `hc` console script plus its dependency, the
18
+ [`healthcloud-sdk`](../../pip) package, which does the actual HTTP/JSON-RPC
19
+ work against the MCP gateway.
20
+
21
+ ## Local development
22
+
23
+ `healthcloud-sdk` is not yet published to PyPI, so for local development you
24
+ must install it in editable mode from this repo *before* installing this
25
+ package:
26
+
27
+ ```bash
28
+ cd packages/cli/pip
29
+
30
+ # 1. Install the local SDK in editable mode (resolves `healthcloud-sdk` without PyPI)
31
+ pip install -e ../../pip
32
+
33
+ # 2. Install this CLI package (+ dev/test dependencies) in editable mode
34
+ pip install -e ".[dev]"
35
+
36
+ # 3. Run the test suite
37
+ python -m pytest
38
+
39
+ # 4. Try it
40
+ hc --help
41
+ hc mcp tools list --audience patient
42
+ hc mcp patient get-patient --help
43
+ ```
44
+
45
+ The bundled tool manifest (`healthcloud_cli/contracts/mcp-tools.manifest.json`)
46
+ is a copy of `packages/cli/contracts/mcp-tools.manifest.json`. Re-sync it
47
+ after pulling manifest changes with:
48
+
49
+ ```bash
50
+ python scripts/bundle_manifest.py
51
+ ```
52
+
53
+ This also runs automatically as a hatchling build hook whenever you `python
54
+ -m build`, so a built wheel/sdist is always self-contained and never depends
55
+ on a relative path outside the installed package.
56
+
57
+ ## Authentication & configuration
58
+
59
+ Every command accepts these global options (place them before the `mcp`
60
+ subcommand):
61
+
62
+ | Flag | Env var | Meaning |
63
+ |-------------------|--------------------|-----------------------------------------------|
64
+ | `--access-token` | `HC_ACCESS_TOKEN` | Bearer token sent to the MCP gateway |
65
+ | `--base-url` | `HC_MCP_BASE_URL` | Override the MCP gateway base URL |
66
+ | `--profile` | `HC_PROFILE` | Named profile (see below) |
67
+ | `--output` | -- | `pretty` (default) \| `json` \| `raw` |
68
+ | `--raw` | -- | Shortcut for `--output raw` |
69
+ | `--verbose` | -- | Print request diagnostics to stderr |
70
+
71
+ Precedence, highest wins: **explicit CLI flag > environment variable >
72
+ profile file value > built-in default** (`environment` defaults to `"dev"`;
73
+ `accessToken`/`baseUrl` default to unset). The resolved access token is never
74
+ written to logs, generated files, or test snapshots.
75
+
76
+ ### Optional profile file
77
+
78
+ `~/.healthcloud/cli/profiles.json`:
79
+
80
+ ```json
81
+ {
82
+ "dev-mia": {
83
+ "baseUrl": "https://dev-api-mcp.health.cloud",
84
+ "accessToken": "eyJ...",
85
+ "environment": "dev"
86
+ }
87
+ }
88
+ ```
89
+
90
+ A missing profiles file is not an error -- profiles are entirely optional. If
91
+ `--profile`/`HC_PROFILE` names a profile and the file (or that entry) is
92
+ missing, `hc` exits with a clear usage error rather than silently ignoring
93
+ it.
94
+
95
+ ```bash
96
+ hc --profile dev-mia mcp patient get-patient --patient-id patient-123
97
+ ```
98
+
99
+ ## Listing and inspecting tools
100
+
101
+ ```bash
102
+ # Local (bundled manifest, no network call)
103
+ hc mcp tools list
104
+ hc mcp tools list --audience patient
105
+
106
+ # Live gateway (requires --audience)
107
+ hc mcp tools list --audience patient --remote
108
+
109
+ # Full manifest entry for one tool (description, inputSchema, method/path)
110
+ hc mcp tools show patient add_insurance --output json
111
+ ```
112
+
113
+ ## Calling a tool
114
+
115
+ Every manifest tool is its own subcommand, grouped by audience:
116
+
117
+ ```bash
118
+ hc mcp patient get-patient --patient-id patient-123
119
+ hc mcp appointments book-appointment --patient-id patient-123 --slot-id slot-456
120
+ ```
121
+
122
+ Run `--help` on any generated command to see its real manifest description
123
+ and arguments:
124
+
125
+ ```bash
126
+ hc mcp patient get-patient --help
127
+ ```
128
+
129
+ ### Argument flags
130
+
131
+ - **Primitive properties** (`string`/`number`/`integer`/`boolean`) become a
132
+ normal flag in kebab-case, e.g. `patient_id` -> `--patient-id`.
133
+ - `enum` values are validated; invalid values are rejected before any
134
+ network call.
135
+ - `minimum`/`maximum`/`exclusiveMinimum`/`exclusiveMaximum` are enforced
136
+ the same way.
137
+ - Boolean properties are a tri-state flag pair: `--flag/--no-flag`.
138
+ Passing neither leaves the value unset (falls back to the manifest
139
+ default or an `--input`/`--stdin` value, if any); passing one sets it
140
+ explicitly to `true`/`false`.
141
+ - **Object/array properties are never flattened.** They get a single
142
+ `--<prop>-json` flag that takes a raw JSON string, e.g.:
143
+
144
+ ```bash
145
+ hc mcp patient create-medication \
146
+ --patient-id patient-123 \
147
+ --name "Metformin" \
148
+ --dosage-json '{"value":10,"unit":"mg","frequency":"once_daily"}'
149
+ ```
150
+ - Path parameters (from `{placeholders}` in the tool's HTTP path) are always
151
+ required, in addition to whatever `inputSchema.required` lists.
152
+
153
+ ### Bulk input: `--input` / `--stdin`
154
+
155
+ ```bash
156
+ hc mcp appointments book-appointment --input request.json
157
+ cat request.json | hc mcp appointments book-appointment --stdin
158
+ ```
159
+
160
+ `--input <file>` and `--stdin` both supply a *base* JSON object of
161
+ arguments. `--input` and `--stdin` cannot be combined. Merge precedence
162
+ (highest wins): **manifest defaults < `--input`/`--stdin` object < explicit
163
+ flags** -- i.e. an explicit flag you actually pass always overrides the same
164
+ key coming from a file or stdin, which in turn overrides the schema default.
165
+
166
+ After merging, the final object is validated against the tool's
167
+ `inputSchema` (required fields present, correct types, enum membership,
168
+ numeric bounds). Any validation failure prints a clear message to stderr and
169
+ exits **2**, without making a network call.
170
+
171
+ ### `hc mcp call` -- generic escape hatch
172
+
173
+ `hc mcp call` dispatches to any MCP tool by its exact snake_case tool name --
174
+ including one not yet present in the bundled manifest (the tool name itself
175
+ is never validated against the manifest, it's just forwarded):
176
+
177
+ ```bash
178
+ hc mcp call patient get_patient --input '{"patient_id":"patient-123"}'
179
+ hc mcp call patient get_patient --input-file request.json
180
+ cat request.json | hc mcp call patient get_patient --stdin
181
+ ```
182
+
183
+ Note the deliberate inconsistency versus named commands: here `--input` takes
184
+ an inline JSON **value**, not a file path -- use `--input-file` for a file.
185
+ Exactly one of `--input` / `--input-file` / `--stdin` may be given (or none,
186
+ meaning `{}`).
187
+
188
+ ## Output modes
189
+
190
+ The MCP tool-call result is `{ content: [{type:"text", text: "..."}],
191
+ is_error: bool }` from the JSON-RPC response's `.result`, or the JSON-RPC
192
+ `.error` object if the gateway returned one.
193
+
194
+ - **`pretty`** (default): if `content[0].text` parses as JSON, pretty-prints
195
+ the parsed value; otherwise prints the raw text. On a JSON-RPC error,
196
+ prints `error.message` (and `error.code` with `--verbose`) to stderr.
197
+ - **`json`**: prints the tool result's parsed JSON (or raw text if
198
+ unparseable) to stdout, with no envelope.
199
+ - **`raw`**: prints the complete JSON-RPC envelope (`id`, `jsonrpc`,
200
+ `result`, `error`) as returned by the gateway.
201
+
202
+ Diagnostics and `--verbose` logs always go to stderr -- stdout stays
203
+ pipeable in every mode.
204
+
205
+ ## Exit codes
206
+
207
+ | Code | Meaning |
208
+ |------|-----------------------------------------------------------------------|
209
+ | `0` | Success |
210
+ | `2` | Local input validation failure (bad JSON, missing required field, invalid enum/number, `--input`+`--stdin` both given, unknown option) -- no network call made |
211
+ | `3` | HTTP/network failure talking to the MCP gateway |
212
+ | `4` | JSON-RPC error response (`.error` is not `None`) |
213
+ | `5` | MCP tool result reported `is_error: true` |
214
+
215
+ ## Building
216
+
217
+ ```bash
218
+ pip install build
219
+ python -m build
220
+ python -m zipfile -l dist/*.whl # confirm the bundled manifest is included
221
+ ```
@@ -0,0 +1,28 @@
1
+ """Hatchling build hook: bundles the MCP manifest before wheel/sdist build.
2
+
3
+ Guarantees ``healthcloud_cli/contracts/mcp-tools.manifest.json`` is fresh at
4
+ build time even if a developer forgot to run ``scripts/bundle_manifest.py``
5
+ by hand. See that script for the source-of-truth path and rationale.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
14
+
15
+ # Hatchling loads this file standalone (via importlib from its file path), so
16
+ # the project root is not automatically on sys.path -- add it so the sibling
17
+ # `scripts` package (packages/cli/pip/scripts/) is importable regardless of
18
+ # the caller's working directory.
19
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
20
+
21
+ from scripts.bundle_manifest import bundle # noqa: E402
22
+
23
+
24
+ class BundleManifestBuildHook(BuildHookInterface):
25
+ PLUGIN_NAME = "bundle-manifest"
26
+
27
+ def initialize(self, version, build_data): # noqa: D102 - hatchling hook signature
28
+ bundle()
@@ -0,0 +1,4 @@
1
+ """HealthCloud CLI: `hc mcp <audience> <command>` generated from the shared MCP tool manifest."""
2
+
3
+ __version__ = "0.1.0"
4
+