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.
- healthcloud_cli-0.1.0/.gitignore +81 -0
- healthcloud_cli-0.1.0/PKG-INFO +236 -0
- healthcloud_cli-0.1.0/README.md +221 -0
- healthcloud_cli-0.1.0/hatch_build.py +28 -0
- healthcloud_cli-0.1.0/healthcloud_cli/__init__.py +4 -0
- healthcloud_cli-0.1.0/healthcloud_cli/cli.py +275 -0
- healthcloud_cli-0.1.0/healthcloud_cli/context.py +80 -0
- healthcloud_cli-0.1.0/healthcloud_cli/contracts/__init__.py +0 -0
- healthcloud_cli-0.1.0/healthcloud_cli/contracts/mcp-tools.manifest.json +33376 -0
- healthcloud_cli-0.1.0/healthcloud_cli/main.py +19 -0
- healthcloud_cli-0.1.0/healthcloud_cli/manifest.py +68 -0
- healthcloud_cli-0.1.0/healthcloud_cli/output.py +128 -0
- healthcloud_cli-0.1.0/healthcloud_cli/params.py +231 -0
- healthcloud_cli-0.1.0/healthcloud_cli/util.py +29 -0
- healthcloud_cli-0.1.0/pyproject.toml +42 -0
- healthcloud_cli-0.1.0/scripts/__init__.py +0 -0
- healthcloud_cli-0.1.0/scripts/bundle_manifest.py +57 -0
|
@@ -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()
|