Skip to content

Commit b415bdf

Browse files
authored
feat(mcp-proxy): add paid cli activation install flow
Add bounded paid activate/status/deactivate CLI flow, local package install helpers, provider discovery bridge, and privacy/install tests for the paid preview path. Includes conflict resolution with role visibility so both paid and role commands remain available. Implemented with assistance from Codex.
1 parent eb4740e commit b415bdf

6 files changed

Lines changed: 2245 additions & 2 deletions

File tree

packages/agentveil-mcp-proxy/agentveil_mcp_proxy/cli.py

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@
135135
is_connect_all_target,
136136
)
137137
from agentveil_mcp_proxy.passthrough import DownstreamConfig, McpPassthrough, PassthroughError
138+
from agentveil_mcp_proxy.paid_activation import (
139+
PaidActivationError,
140+
run_paid_activate_cli,
141+
run_paid_deactivate_cli,
142+
run_paid_status_cli,
143+
)
138144
from agentveil_mcp_proxy.agent_templates import (
139145
AGENT_TEMPLATE_NAMES,
140146
AgentTemplateError,
@@ -3549,7 +3555,7 @@ def run_redirect_approval_demo_cli(
35493555
"\n"
35503556
"Advanced:\n"
35513557
" approval-center, client-config, client-doctor, client-run, configure-downstream,\n"
3552-
" connect, control, disconnect, downstream, evidence-summary, explain, hook, role,\n"
3558+
" connect, control, disconnect, downstream, evidence-summary, explain, hook, paid, role,\n"
35533559
" install-claude-hook, permission-doctor, reissue-grant, register, smoke,\n"
35543560
" status-claude-hook, templates, uninstall-claude-hook, wizard\n"
35553561
"\n"
@@ -3920,6 +3926,43 @@ def build_parser() -> argparse.ArgumentParser:
39203926
control_timeline.add_argument("--limit", type=int, default=20)
39213927
_add_json_arg(control_timeline)
39223928

3929+
paid = subparsers.add_parser(
3930+
"paid",
3931+
help="Paid activation, package install, and bounded local status",
3932+
)
3933+
paid_subparsers = paid.add_subparsers(dest="paid_action", required=True)
3934+
paid_activate = paid_subparsers.add_parser(
3935+
"activate",
3936+
help="Activate paid preview access and install the private provider package",
3937+
)
3938+
paid_activate.add_argument(
3939+
"license_key",
3940+
nargs="?",
3941+
default=None,
3942+
help="License key (raw value is not persisted; a bounded reference may be persisted)",
3943+
)
3944+
paid_activate.add_argument(
3945+
"--license-key-stdin",
3946+
action="store_true",
3947+
help="Read license key from stdin instead of argv (avoids shell history)",
3948+
)
3949+
_add_common_path_args(paid_activate)
3950+
_add_json_arg(paid_activate)
3951+
3952+
paid_status = paid_subparsers.add_parser(
3953+
"status",
3954+
help="Show bounded paid activation and install status",
3955+
)
3956+
_add_common_path_args(paid_status)
3957+
_add_json_arg(paid_status)
3958+
3959+
paid_deactivate = paid_subparsers.add_parser(
3960+
"deactivate",
3961+
help="Clear local paid activation metadata",
3962+
)
3963+
_add_common_path_args(paid_deactivate)
3964+
_add_json_arg(paid_deactivate)
3965+
39233966
permission_doctor = subparsers.add_parser(
39243967
"permission-doctor",
39253968
help="Show setup mode, control boundaries, and redirect coverage",
@@ -6727,6 +6770,25 @@ def main(argv: list[str] | None = None) -> int:
67276770
output_json=args.json_output,
67286771
)
67296772
raise ProxyCliError("control action must be status or timeline")
6773+
if args.command == "paid":
6774+
if args.paid_action == "activate":
6775+
return run_paid_activate_cli(
6776+
license_key=args.license_key,
6777+
license_key_stdin=args.license_key_stdin,
6778+
home=args.home,
6779+
output_json=args.json_output,
6780+
)
6781+
if args.paid_action == "status":
6782+
return run_paid_status_cli(
6783+
home=args.home,
6784+
output_json=args.json_output,
6785+
)
6786+
if args.paid_action == "deactivate":
6787+
return run_paid_deactivate_cli(
6788+
home=args.home,
6789+
output_json=args.json_output,
6790+
)
6791+
raise ProxyCliError("paid action must be activate, status, or deactivate")
67306792
if args.command == "permission-doctor":
67316793
return print_permission_doctor_cli(
67326794
home=args.home,
@@ -7011,6 +7073,7 @@ def main(argv: list[str] | None = None) -> int:
70117073
)
70127074
except (
70137075
ProxyCliError,
7076+
PaidActivationError,
70147077
ApprovalEvidenceError,
70157078
EvidenceExportError,
70167079
EvidenceVerificationError,
@@ -7036,7 +7099,7 @@ def main(argv: list[str] | None = None) -> int:
70367099
else:
70377100
error_message = str(exc)
70387101
print(f"ERROR: {error_message}", file=sys.stderr)
7039-
return exc.exit_code if isinstance(exc, ProxyCliError) else 1
7102+
return exc.exit_code if isinstance(exc, (ProxyCliError, PaidActivationError)) else 1
70407103
raise AssertionError(f"unhandled command: {args.command}")
70417104

70427105

0 commit comments

Comments
 (0)