agentnode-sdk 0.21.0__tar.gz → 0.23.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.
Files changed (229) hide show
  1. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/CHANGELOG.md +40 -0
  2. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/PKG-INFO +1 -1
  3. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/__init__.py +1 -1
  4. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/commands.py +8 -3
  5. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/main.py +29 -1
  6. agentnode_sdk-0.23.0/agentnode_sdk/cli/mcp_ownership.py +207 -0
  7. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/publish.py +14 -0
  8. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/templates.py +86 -0
  9. agentnode_sdk-0.23.0/agentnode_sdk/compatibility.py +144 -0
  10. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/data/compatibility/current.json +3303 -999
  11. agentnode_sdk-0.23.0/data/compatibility/removed_2026-07-09.txt +40 -0
  12. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/pyproject.toml +1 -1
  13. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/scripts/check_model_drift.py +6 -4
  14. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/scripts/ci_smoke_test.py +9 -1
  15. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/scripts/generate_compatibility_artifacts.py +8 -1
  16. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/scripts/merge_batches.py +259 -196
  17. agentnode_sdk-0.23.0/tests/test_mcp_cli_scaffold.py +91 -0
  18. agentnode_sdk-0.23.0/tests/test_mcp_ownership_cli.py +243 -0
  19. agentnode_sdk-0.21.0/agentnode_sdk/compatibility.py +0 -139
  20. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/.env.example +0 -0
  21. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/.gitignore +0 -0
  22. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/README.md +0 -0
  23. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/REGISTRY_SIGNING_ACTIVATION.md +0 -0
  24. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/REGISTRY_SIGNING_SPEC.md +0 -0
  25. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/THREAT_MODEL.md +0 -0
  26. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/TRUST_STACK.md +0 -0
  27. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode.lock +0 -0
  28. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/_fileutil.py +0 -0
  29. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/async_client.py +0 -0
  30. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/capability_graph.py +0 -0
  31. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/capability_taxonomy.py +0 -0
  32. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/__init__.py +0 -0
  33. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/__main__.py +0 -0
  34. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/audit.py +0 -0
  35. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/auth.py +0 -0
  36. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/cassette_audit.py +0 -0
  37. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/complements.py +0 -0
  38. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/init.py +0 -0
  39. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/mcp_commands.py +0 -0
  40. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/mcp_status.py +0 -0
  41. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/mcp_submit.py +0 -0
  42. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/mcp_verify.py +0 -0
  43. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/output.py +0 -0
  44. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/record_cases.py +0 -0
  45. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/sandbox_commands.py +0 -0
  46. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/serve.py +0 -0
  47. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/setup_wizard.py +0 -0
  48. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/smart_run.py +0 -0
  49. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/validate.py +0 -0
  50. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/cli/verify_local.py +0 -0
  51. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/client.py +0 -0
  52. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/config.py +0 -0
  53. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/credential_handle.py +0 -0
  54. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/credential_resolver.py +0 -0
  55. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/credential_store.py +0 -0
  56. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/detect.py +0 -0
  57. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/exceptions.py +0 -0
  58. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/guard.py +0 -0
  59. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/input_guard.py +0 -0
  60. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/installer.py +0 -0
  61. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/key_status.py +0 -0
  62. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/llm_providers.py +0 -0
  63. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/lock_integrity.py +0 -0
  64. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/mcp_server.py +0 -0
  65. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/models.py +0 -0
  66. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/planner.py +0 -0
  67. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/policy.py +0 -0
  68. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/references.py +0 -0
  69. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/registry_trust.py +0 -0
  70. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/resolve.py +0 -0
  71. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/resource_provider.py +0 -0
  72. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/risk_profile.py +0 -0
  73. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/run_log.py +0 -0
  74. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runner.py +0 -0
  75. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtime.py +0 -0
  76. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/__init__.py +0 -0
  77. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/agent_llm_broker.py +0 -0
  78. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/agent_llm_policy.py +0 -0
  79. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/agent_runner.py +0 -0
  80. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/agent_sandbox.py +0 -0
  81. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/mcp_consent.py +0 -0
  82. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/mcp_consent_store.py +0 -0
  83. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/mcp_runner.py +0 -0
  84. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/python_runner.py +0 -0
  85. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/remote_runner.py +0 -0
  86. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/runtimes/toolpack_credentials.py +0 -0
  87. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/__init__.py +0 -0
  88. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/agent_container_wrapper.py +0 -0
  89. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/agent_rpc.py +0 -0
  90. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/agent_session.py +0 -0
  91. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/backend.py +0 -0
  92. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/container_backend.py +0 -0
  93. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/domain_policy.py +0 -0
  94. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/egress.py +0 -0
  95. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/egress_proxy.py +0 -0
  96. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/mcp_preinstall.py +0 -0
  97. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/policy.py +0 -0
  98. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/sandbox/types.py +0 -0
  99. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/signature.py +0 -0
  100. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/signing_key.py +0 -0
  101. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/agentnode_sdk/skill.py +0 -0
  102. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/dist-0.18.0/.gitignore +0 -0
  103. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/dist-0.19.0/.gitignore +0 -0
  104. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/sandbox-image/Dockerfile +0 -0
  105. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/sandbox-image/README.md +0 -0
  106. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/scripts/analyze_scores.py +0 -0
  107. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/scripts/batch_verify.py +0 -0
  108. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/scripts/verify_toolcalls.py +0 -0
  109. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/scripts/weekly_retest.sh +0 -0
  110. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/spikes/agent_sandbox_routing/README.md +0 -0
  111. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/spikes/agent_sandbox_routing/__init__.py +0 -0
  112. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/spikes/agent_sandbox_routing/container_agent_wrapper.py +0 -0
  113. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/spikes/agent_sandbox_routing/fake_llm.py +0 -0
  114. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/spikes/agent_sandbox_routing/host_driver.py +0 -0
  115. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/spikes/agent_sandbox_routing/trivial_agent.py +0 -0
  116. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/__init__.py +0 -0
  117. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/conftest.py +0 -0
  118. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/data/allowed_domains_vectors.json +0 -0
  119. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_llm_broker.py +0 -0
  120. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_llm_policy.py +0 -0
  121. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_rpc.py +0 -0
  122. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_runner.py +0 -0
  123. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_sandbox_e2e.py +0 -0
  124. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_sandbox_hardening.py +0 -0
  125. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_sandbox_routing.py +0 -0
  126. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_sandbox_spike.py +0 -0
  127. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_agent_session_container.py +0 -0
  128. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_async_client.py +0 -0
  129. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_audit_ux.py +0 -0
  130. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_auth_cli_vault.py +0 -0
  131. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_auto_upgrade_policy.py +0 -0
  132. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_cli.py +0 -0
  133. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_cli_lock.py +0 -0
  134. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_cli_run_resolution.py +0 -0
  135. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_client.py +0 -0
  136. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_client_json_guard.py +0 -0
  137. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_client_sprint_b.py +0 -0
  138. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_config.py +0 -0
  139. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_consent_prompt.py +0 -0
  140. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_credential_handle.py +0 -0
  141. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_credential_integration.py +0 -0
  142. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_credential_resolver.py +0 -0
  143. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_credential_store.py +0 -0
  144. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_credential_vault.py +0 -0
  145. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_detect.py +0 -0
  146. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_detect_and_install.py +0 -0
  147. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_domain_policy.py +0 -0
  148. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_e2e_runtime.py +0 -0
  149. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_edge_cases.py +0 -0
  150. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_egress_domain_validation.py +0 -0
  151. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_egress_e2e.py +0 -0
  152. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_egress_lifecycle.py +0 -0
  153. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_egress_proxy_unit.py +0 -0
  154. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_egress_wrap.py +0 -0
  155. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_env_passthrough_wrap.py +0 -0
  156. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard.py +0 -0
  157. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_check.py +0 -0
  158. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_config_cache.py +0 -0
  159. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_policy.py +0 -0
  160. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_preview.py +0 -0
  161. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_schema.py +0 -0
  162. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_set.py +0 -0
  163. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_status.py +0 -0
  164. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_tool_override.py +0 -0
  165. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_tool_override_audit.py +0 -0
  166. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_tool_override_cli.py +0 -0
  167. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_guard_ux.py +0 -0
  168. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_host_trust_policy.py +0 -0
  169. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_host_trust_policy_routing.py +0 -0
  170. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_input_guard.py +0 -0
  171. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_input_guard_escalation.py +0 -0
  172. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_install_hardening.py +0 -0
  173. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_installer_sprint_b.py +0 -0
  174. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_intelligence.py +0 -0
  175. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_key_status.py +0 -0
  176. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_llm_binding.py +0 -0
  177. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_llm_call_runlog.py +0 -0
  178. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_llm_providers.py +0 -0
  179. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_llm_vault_binding.py +0 -0
  180. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_lock_integrity.py +0 -0
  181. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_lock_runtime.py +0 -0
  182. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_allowed_domains_seal.py +0 -0
  183. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_audit.py +0 -0
  184. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_consent.py +0 -0
  185. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_consent_resolver.py +0 -0
  186. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_consent_store.py +0 -0
  187. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_credentialed_launch.py +0 -0
  188. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_doctor.py +0 -0
  189. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_preinstall.py +0 -0
  190. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_preinstall_run.py +0 -0
  191. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_sandbox.py +0 -0
  192. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_server.py +0 -0
  193. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_mcp_submit.py +0 -0
  194. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_observability.py +0 -0
  195. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_planner.py +0 -0
  196. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_policy.py +0 -0
  197. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_policy_integration.py +0 -0
  198. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_prompt_specs.py +0 -0
  199. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_provider_matrix.py +0 -0
  200. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_publish.py +0 -0
  201. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_references.py +0 -0
  202. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_registry_trust.py +0 -0
  203. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_remote_hardening.py +0 -0
  204. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_remote_runner.py +0 -0
  205. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_resource_provider.py +0 -0
  206. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_resource_specs.py +0 -0
  207. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_risk_profile.py +0 -0
  208. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_run_log.py +0 -0
  209. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_runner.py +0 -0
  210. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_runtime.py +0 -0
  211. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_runtime_audit.py +0 -0
  212. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_sandbox_backend.py +0 -0
  213. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_sandbox_doctor.py +0 -0
  214. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_sandbox_e2e.py +0 -0
  215. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_sandbox_gate.py +0 -0
  216. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_security_hardening.py +0 -0
  217. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_setup_wizard.py +0 -0
  218. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_signature.py +0 -0
  219. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_signing_key.py +0 -0
  220. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_skill.py +0 -0
  221. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_smart.py +0 -0
  222. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_stability.py +0 -0
  223. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_toolpack_credentials.py +0 -0
  224. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_toolpack_credentials_b.py +0 -0
  225. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_toolpack_sandbox.py +0 -0
  226. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_v02.py +0 -0
  227. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_validate.py +0 -0
  228. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/test_validate_skill.py +0 -0
  229. {agentnode_sdk-0.21.0 → agentnode_sdk-0.23.0}/tests/validation_lockfile.json +0 -0
@@ -1,5 +1,45 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.23.0 — Prove MCP package ownership from the terminal
4
+
5
+ ### Added
6
+
7
+ - `agentnode mcp ownership challenge --registry npm|pypi <package>` issues a
8
+ one-time challenge: the server returns a token and a keyword
9
+ (`agentnode-ownership-<token>`). Add the keyword to your package's metadata
10
+ and publish a new version — only someone with publish rights can do that. The
11
+ token is shown once and is stored server-side only as a hash; it is never
12
+ written to local config.
13
+ - `agentnode mcp ownership verify --registry npm|pypi <package>` checks the
14
+ latest published version for the keyword and, on a match, records strong
15
+ ownership evidence. It reports `verified` / `pending` / expired / no-challenge
16
+ / package-not-found / registry-unavailable clearly, and exits non-zero until
17
+ ownership is verified (CI-gateable).
18
+
19
+ Verifying ownership does **not** publish anything: MCP listings still remain
20
+ review-gated until the sandbox-smoke gate is built. The same flow is available
21
+ in the browser on `/mcp/submit`.
22
+
23
+ ## 0.22.0 — MCP from the terminal + refreshed compatibility
24
+
25
+ ### Added
26
+
27
+ - `agentnode init --type mcp` scaffolds an MCP server listing: a schema-valid
28
+ manifest (runtime `mcp`, a pinned `mcp_server` command with an npm/PyPI
29
+ package and `source_repo`, honest permissions) plus a README that walks
30
+ `agentnode mcp verify` → `agentnode mcp submit`. MCP now has the same
31
+ terminal starting point as toolpacks, skills, and agents.
32
+
33
+ ### Changed
34
+
35
+ - `agentnode publish` detects an MCP manifest (runtime `mcp` or an `mcp_server`
36
+ block) and routes you to `agentnode mcp verify` / `agentnode mcp submit`
37
+ instead of failing deep in toolpack validation. Non-MCP manifests are
38
+ unaffected.
39
+ - Refreshed model compatibility data: 246 scored models (222 S-tier), current
40
+ flagships added, models untestable in the latest batch kept with their prior
41
+ result marked legacy, and only hard-evidence removals delisted.
42
+
3
43
  ## 0.21.0 — Community agents run sandboxed by default
4
44
 
5
45
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentnode-sdk
3
- Version: 0.21.0
3
+ Version: 0.23.0
4
4
  Summary: Python SDK for AgentNode — the open upgrade and discovery infrastructure for AI agents.
5
5
  Project-URL: Homepage, https://agentnode.net
6
6
  Project-URL: Repository, https://github.com/agentnode-ai/agentnode
@@ -38,7 +38,7 @@ from agentnode_sdk.runtime import AgentNodeRuntime
38
38
  Client = AgentNodeClient
39
39
  ToolError = AgentNodeToolError
40
40
 
41
- __version__ = "0.21.0"
41
+ __version__ = "0.23.0"
42
42
  __all__ = [
43
43
  "AgentNode",
44
44
  "AsyncAgentNode",
@@ -2338,9 +2338,14 @@ def cmd_init(name: str | None = None, template_type: str | None = None) -> int:
2338
2338
  print()
2339
2339
  print(dim(" Next steps:"))
2340
2340
  print(dim(f" cd {pkg_id}"))
2341
- print(dim(" # Edit the tool code and manifest"))
2342
- print(dim(" agentnode validate ."))
2343
- print(dim(" # Publish via web UI at agentnode.net/publish"))
2341
+ if chosen == "mcp":
2342
+ print(dim(" # Fill in npm_package/pypi_package, pin the version, set source_repo"))
2343
+ print(dim(" agentnode mcp verify . --test # check ownership, package, pinning"))
2344
+ print(dim(" agentnode mcp submit . # submit for the catalog"))
2345
+ else:
2346
+ print(dim(" # Edit the tool code and manifest"))
2347
+ print(dim(" agentnode validate ."))
2348
+ print(dim(" agentnode publish . # or publish via agentnode.net/publish"))
2344
2349
  print()
2345
2350
  return 0
2346
2351
 
@@ -61,6 +61,19 @@ def main(argv: list[str] | None = None) -> int:
61
61
  mcp_revoke_p.add_argument("--key", default=None, help="Revoke only this consent_key")
62
62
  mcp_grants_p = mcp_sub.add_parser("grants", help="List stored consent grants (metadata only)")
63
63
  mcp_grants_p.add_argument("--json", dest="json_output", action="store_true", help="JSON output")
64
+ # Slice 2b-2: prove package ownership via a publish-challenge (npm/PyPI).
65
+ mcp_own_p = mcp_sub.add_parser("ownership", help="Prove package ownership (publish-challenge)")
66
+ mcp_own_sub = mcp_own_p.add_subparsers(dest="ownership_command")
67
+ mcp_own_ch = mcp_own_sub.add_parser("challenge", help="Issue a one-time publish-challenge token")
68
+ mcp_own_ch.add_argument("package", help="Package name on the registry")
69
+ mcp_own_ch.add_argument("--registry", required=True, choices=["npm", "pypi"], help="Package registry")
70
+ mcp_own_ch.add_argument("--token", default=None, help="API key (default: AGENTNODE_API_KEY)")
71
+ mcp_own_ch.add_argument("--json", dest="json_output", action="store_true", help="JSON output")
72
+ mcp_own_vf = mcp_own_sub.add_parser("verify", help="Verify a pending publish-challenge")
73
+ mcp_own_vf.add_argument("package", help="Package name on the registry")
74
+ mcp_own_vf.add_argument("--registry", required=True, choices=["npm", "pypi"], help="Package registry")
75
+ mcp_own_vf.add_argument("--token", default=None, help="API key (default: AGENTNODE_API_KEY)")
76
+ mcp_own_vf.add_argument("--json", dest="json_output", action="store_true", help="JSON output")
64
77
 
65
78
  # reset
66
79
  sub.add_parser("reset", help="Reset configuration")
@@ -149,7 +162,7 @@ def main(argv: list[str] | None = None) -> int:
149
162
  # init
150
163
  init_parser = sub.add_parser("init", help="Create a new package from template")
151
164
  init_parser.add_argument("name", nargs="?", default=None, help="Package ID (optional, prompted if omitted)")
152
- init_parser.add_argument("--type", dest="template_type", choices=["local", "api", "file", "agent", "skill"], default=None)
165
+ init_parser.add_argument("--type", dest="template_type", choices=["local", "api", "file", "agent", "skill", "mcp"], default=None)
153
166
 
154
167
  # validate
155
168
  validate_parser = sub.add_parser("validate", help="Validate package before publishing")
@@ -268,6 +281,21 @@ def main(argv: list[str] | None = None) -> int:
268
281
  if args.mcp_command == "grants":
269
282
  from agentnode_sdk.cli.mcp_commands import cmd_mcp_grants
270
283
  return cmd_mcp_grants(json_output=args.json_output)
284
+ if args.mcp_command == "ownership":
285
+ from agentnode_sdk.cli.mcp_ownership import (
286
+ cmd_mcp_ownership_challenge,
287
+ cmd_mcp_ownership_verify,
288
+ )
289
+ if args.ownership_command == "challenge":
290
+ return cmd_mcp_ownership_challenge(
291
+ args.registry, args.package, token=args.token, json_output=args.json_output
292
+ )
293
+ if args.ownership_command == "verify":
294
+ return cmd_mcp_ownership_verify(
295
+ args.registry, args.package, token=args.token, json_output=args.json_output
296
+ )
297
+ mcp_own_p.print_help()
298
+ return 0
271
299
  mcp_parser.print_help()
272
300
  return 0
273
301
  if args.command == "sandbox":
@@ -0,0 +1,207 @@
1
+ """Publish-challenge ownership for MCP packages (Slice 2b-2 UX).
2
+
3
+ Two verbs let a publisher prove they control an npm/PyPI package:
4
+
5
+ agentnode mcp ownership challenge --registry npm|pypi <package>
6
+ agentnode mcp ownership verify --registry npm|pypi <package>
7
+
8
+ `challenge` asks the backend for a one-time token + keyword; the publisher adds
9
+ the keyword to their package's metadata and publishes a new version. `verify`
10
+ then asks the backend to look at the latest published version and confirm the
11
+ keyword -- only someone with publish rights can put it there, so a match is
12
+ strong ownership evidence.
13
+
14
+ The token is never written to disk here -- it is shown once, straight from the
15
+ API response. Verifying ownership does NOT publish anything: MCP listings stay
16
+ review-gated until the sandbox-smoke gate is built.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import json
21
+ import os
22
+ import sys
23
+
24
+ import httpx
25
+
26
+ _REVIEW_NOTE = (
27
+ " Ownership can be verified, but MCP listings still remain review-gated\n"
28
+ " until the sandbox-smoke gate is built."
29
+ )
30
+
31
+
32
+ def _resolve_api_base() -> str:
33
+ from agentnode_sdk.client import DEFAULT_BASE_URL
34
+ return os.environ.get("AGENTNODE_API_URL", DEFAULT_BASE_URL).rstrip("/")
35
+
36
+
37
+ def _api_key(token: str | None) -> str:
38
+ return token or os.environ.get("AGENTNODE_API_KEY", "")
39
+
40
+
41
+ def _no_key() -> int:
42
+ print(
43
+ " Error: No AgentNode API key configured.\n"
44
+ " Set AGENTNODE_API_KEY or pass --token <key>.",
45
+ file=sys.stderr,
46
+ )
47
+ return 1
48
+
49
+
50
+ def _handle_error(resp: httpx.Response, json_output: bool) -> int:
51
+ """Print a clear error for a non-2xx response and return 1.
52
+
53
+ Backend error messages are already user-facing (expired challenge, no
54
+ challenge, package not found, registry unavailable), so we surface them
55
+ directly rather than re-inventing copy per status code.
56
+ """
57
+ try:
58
+ err = resp.json()
59
+ code = err.get("code", "")
60
+ message = err.get("message", resp.text)
61
+ except Exception:
62
+ err = None
63
+ code = ""
64
+ message = resp.text
65
+
66
+ if json_output and err is not None:
67
+ print(json.dumps(err, indent=2))
68
+ return 1
69
+
70
+ if resp.status_code == 401:
71
+ print(" Error: Authentication failed. Check your API key.", file=sys.stderr)
72
+ elif resp.status_code == 403:
73
+ if "PUBLISHER" in code:
74
+ print(" Error: You need a publisher profile.", file=sys.stderr)
75
+ print(" Create one at https://agentnode.net/dashboard", file=sys.stderr)
76
+ else:
77
+ print(f" Error: {message}", file=sys.stderr)
78
+ else:
79
+ print(f" Error ({resp.status_code}): {message}", file=sys.stderr)
80
+ return 1
81
+
82
+
83
+ def cmd_mcp_ownership_challenge(
84
+ registry: str,
85
+ package: str,
86
+ *,
87
+ token: str | None = None,
88
+ json_output: bool = False,
89
+ ) -> int:
90
+ """Issue a one-time publish-challenge for a package."""
91
+ api_key = _api_key(token)
92
+ if not api_key:
93
+ return _no_key()
94
+
95
+ registry = (registry or "").strip().lower()
96
+ url = f"{_resolve_api_base()}/v1/mcp/ownership/challenge"
97
+ try:
98
+ resp = httpx.post(
99
+ url,
100
+ json={"registry": registry, "package_name": package},
101
+ headers={"Authorization": f"Bearer {api_key}"},
102
+ timeout=30,
103
+ )
104
+ except Exception as e:
105
+ print(f" Error: Connection failed: {e}", file=sys.stderr)
106
+ return 1
107
+
108
+ if resp.status_code != 200:
109
+ return _handle_error(resp, json_output)
110
+
111
+ data = resp.json()
112
+ if json_output:
113
+ print(json.dumps(data, indent=2))
114
+ return 0
115
+
116
+ keyword = data.get("keyword", "")
117
+ tok = data.get("token", "")
118
+ expires = (data.get("expires_at") or "")[:10]
119
+ verify_cmd = f"agentnode mcp ownership verify --registry {registry} {package}"
120
+
121
+ print()
122
+ print(" AgentNode Ownership Challenge")
123
+ print(" " + "-" * 29)
124
+ print(f" Registry: {registry}")
125
+ print(f" Package: {package}")
126
+ print()
127
+ print(" Prove package ownership by publishing this keyword in your package")
128
+ print(" metadata. Only someone with publish rights can do that.")
129
+ print()
130
+ print(f" Token (shown once): {tok}")
131
+ print(f" Keyword: {keyword}")
132
+ if expires:
133
+ print(f" Expires: {expires}")
134
+ print()
135
+ print(" Next steps:")
136
+ print(f' 1. Add "{keyword}" to your package\'s keywords.')
137
+ print(f" 2. Publish a new version to {registry}.")
138
+ print(f" 3. Run: {verify_cmd}")
139
+ print()
140
+ print(" The token is shown only once and is stored only as a hash. If you")
141
+ print(" lose it, just issue a new challenge -- that replaces the old one.")
142
+ print()
143
+ print(_REVIEW_NOTE)
144
+ print()
145
+ return 0
146
+
147
+
148
+ def cmd_mcp_ownership_verify(
149
+ registry: str,
150
+ package: str,
151
+ *,
152
+ token: str | None = None,
153
+ json_output: bool = False,
154
+ ) -> int:
155
+ """Verify a pending publish-challenge against the published package."""
156
+ api_key = _api_key(token)
157
+ if not api_key:
158
+ return _no_key()
159
+
160
+ registry = (registry or "").strip().lower()
161
+ url = f"{_resolve_api_base()}/v1/mcp/ownership/challenge/verify"
162
+ try:
163
+ resp = httpx.post(
164
+ url,
165
+ json={"registry": registry, "package_name": package},
166
+ headers={"Authorization": f"Bearer {api_key}"},
167
+ timeout=30,
168
+ )
169
+ except Exception as e:
170
+ print(f" Error: Connection failed: {e}", file=sys.stderr)
171
+ return 1
172
+
173
+ if resp.status_code != 200:
174
+ return _handle_error(resp, json_output)
175
+
176
+ data = resp.json()
177
+ verified = bool(data.get("verified"))
178
+ if json_output:
179
+ print(json.dumps(data, indent=2))
180
+ return 0 if verified else 1
181
+
182
+ status = data.get("status", "?")
183
+ message = data.get("message", "")
184
+ version = data.get("version")
185
+
186
+ print()
187
+ print(" AgentNode Ownership Verify")
188
+ print(" " + "-" * 26)
189
+ print(f" Registry: {registry}")
190
+ print(f" Package: {package}")
191
+ print(f" Status: {status}")
192
+ if version:
193
+ print(f" Version: {version}")
194
+ print()
195
+ if message:
196
+ print(f" {message}")
197
+ if verified:
198
+ print(" Strong ownership evidence recorded for this package.")
199
+ else:
200
+ print(
201
+ f" Not verified yet. Publish a version carrying the challenge keyword, "
202
+ f"then run:\n agentnode mcp ownership verify --registry {registry} {package}"
203
+ )
204
+ print()
205
+ print(_REVIEW_NOTE)
206
+ print()
207
+ return 0 if verified else 1
@@ -389,6 +389,20 @@ def cmd_publish(
389
389
  print(" Error: package_id and version are required in agentnode.yaml.", file=sys.stderr)
390
390
  return 1
391
391
 
392
+ # MCP listings go through the dedicated submit flow (registry re-verification
393
+ # + ownership), not the toolpack/skill/agent publish path. Route the user
394
+ # cleanly instead of failing deep in validation.
395
+ if manifest.get("runtime") == "mcp" or manifest.get("mcp_server"):
396
+ print()
397
+ print(section(" This is an MCP server listing"))
398
+ print(" MCP servers are listed with a dedicated command, not `publish`:")
399
+ print()
400
+ print(" agentnode mcp verify . # check ownership, package, pinning")
401
+ print(" agentnode mcp submit . # submit for the catalog")
402
+ print()
403
+ print(" (`publish` is for toolpacks, skills, and agents.)")
404
+ return 1
405
+
392
406
  print()
393
407
  print(section(" AgentNode Publish"))
394
408
  print(kv("Package", f"{pkg_id}@{version}"))
@@ -598,6 +598,92 @@ This is an example of the expected output quality and format.
598
598
  ## Summary
599
599
 
600
600
  A concise summary of the analysis.
601
+ """,
602
+ },
603
+ },
604
+ "mcp": {
605
+ "label": "MCP server (list an existing npm/PyPI MCP server)",
606
+ "description": "A listing for an MCP server already published to npm or PyPI. No code is uploaded — you point AgentNode at the package. Submit with `agentnode mcp submit` after `agentnode mcp verify`.",
607
+ "files": {
608
+ "agentnode.yaml": """\
609
+ manifest_version: "0.3"
610
+ package_id: "{package_id}"
611
+ package_type: "toolpack"
612
+ name: "{name}"
613
+ publisher: "{publisher}"
614
+ version: "1.0.0"
615
+ summary: "{summary}"
616
+ description: |
617
+ {description}
618
+
619
+ runtime: "mcp"
620
+ install_mode: "package"
621
+ hosting_type: "agentnode_hosted"
622
+
623
+ # The MCP server to run. Fill in ONE of npm_package / pypi_package and pin the
624
+ # EXACT version in the command (e.g. @0.1.0 for npm, ==0.1.0 for PyPI) — an
625
+ # unpinned command is not reproducible and is flagged on submit.
626
+ mcp_server:
627
+ # npm example (delete the pypi_package line):
628
+ command: ["npx", "-y", "REPLACE_ME_PACKAGE@REPLACE_VERSION"]
629
+ npm_package: "REPLACE_ME_PACKAGE"
630
+ # pypi example (swap the command + use pypi_package instead of npm_package):
631
+ # command: ["uvx", "REPLACE_ME_PACKAGE==REPLACE_VERSION"]
632
+ # pypi_package: "REPLACE_ME_PACKAGE"
633
+ # Ownership is checked against this repo — it must match the package's
634
+ # registry metadata (npm/PyPI "repository" / homepage).
635
+ source_repo: "https://github.com/REPLACE_ME_OWNER/REPLACE_ME_REPO"
636
+
637
+ tags: []
638
+ categories: []
639
+
640
+ compatibility:
641
+ frameworks: ["generic"]
642
+
643
+ # Declare honestly what the MCP server needs. Verification compares these
644
+ # against what the server actually requests.
645
+ permissions:
646
+ network:
647
+ level: "restricted"
648
+ allowed_domains: []
649
+ filesystem:
650
+ level: "none"
651
+ code_execution:
652
+ level: "none"
653
+ data_access:
654
+ level: "input_only"
655
+ user_approval:
656
+ required: "high_risk_only"
657
+ external_integrations: []
658
+ """,
659
+ "README.md": """\
660
+ # {name} (MCP server listing)
661
+
662
+ This package LISTS an existing MCP server (published on npm or PyPI) in the
663
+ AgentNode catalog. No code is uploaded — AgentNode points at the upstream
664
+ package.
665
+
666
+ ## Before you submit
667
+
668
+ 1. Edit `agentnode.yaml`:
669
+ - Set `mcp_server.npm_package` OR `mcp_server.pypi_package` (not both).
670
+ - Pin the EXACT version in `mcp_server.command` (npm `@x.y.z`, PyPI `==x.y.z`).
671
+ - Set `mcp_server.source_repo` to the repo that owns the package.
672
+ - Declare `permissions` honestly.
673
+ 2. Verify locally:
674
+
675
+ ```
676
+ agentnode mcp verify . --test
677
+ ```
678
+
679
+ 3. Submit for the catalog (server re-verifies authoritatively):
680
+
681
+ ```
682
+ agentnode mcp submit . --token $AGENTNODE_API_KEY
683
+ ```
684
+
685
+ `agentnode publish` is for toolpacks / skills / agents; MCP listings go
686
+ through `agentnode mcp submit`.
601
687
  """,
602
688
  },
603
689
  },
@@ -0,0 +1,144 @@
1
+ """AgentNode compatibility data and model recommendations.
2
+
3
+ Auto-generated by sdk/scripts/generate_compatibility_artifacts.py
4
+ Manual edits to _RECOMMENDED are preserved across regeneration.
5
+ """
6
+ from __future__ import annotations
7
+
8
+
9
+ _TIER_ORDER = {"S": 0, "A": 1, "B": 2, "C": 3, "F": 4}
10
+
11
+
12
+ def _tier_passes(tier: str, minimum: str) -> bool:
13
+ """Check if a tier meets the minimum requirement."""
14
+ return _TIER_ORDER.get(tier, 99) <= _TIER_ORDER.get(minimum, 0)
15
+
16
+
17
+ # Generated from current.json — provider -> [(model, tier), ...]
18
+ _TIER_DATA: dict[str, list[tuple[str, str]]] = {
19
+ "ai21": [("jamba-large-1.7", "C")],
20
+ "aion-labs": [("aion-2.0", "S"), ("aion-3.0", "S"), ("aion-3.0-mini", "S")],
21
+ "amazon": [("nova-2-lite-v1", "S"), ("nova-lite-v1", "S"), ("nova-micro-v1", "S"), ("nova-premier-v1", "S"), ("nova-pro-v1", "S")],
22
+ "anthropic": [("claude-3-haiku", "S"), ("claude-fable-5", "S"), ("claude-haiku-4.5", "S"), ("claude-opus-4", "S"), ("claude-opus-4.1", "S"), ("claude-opus-4.5", "S"), ("claude-opus-4.6", "S"), ("claude-opus-4.7", "S"), ("claude-opus-4.8", "S"), ("claude-opus-4.8-fast", "S"), ("claude-sonnet-4", "S"), ("claude-sonnet-4.5", "S"), ("claude-sonnet-4.6", "S"), ("claude-sonnet-5", "A")],
23
+ "arcee-ai": [("trinity-large-thinking", "A"), ("trinity-mini", "C")],
24
+ "bytedance-seed": [("seed-1.6", "S"), ("seed-1.6-flash", "S"), ("seed-2.0-lite", "S"), ("seed-2.0-mini", "S")],
25
+ "cohere": [("command-r-08-2024", "S"), ("command-r-plus-08-2024", "S"), ("north-mini-code:free", "S")],
26
+ "deepseek": [("deepseek-chat", "S"), ("deepseek-chat-v3-0324", "S"), ("deepseek-chat-v3.1", "S"), ("deepseek-r1", "S"), ("deepseek-r1-0528", "A"), ("deepseek-v3.1-terminus", "S"), ("deepseek-v3.2", "S"), ("deepseek-v3.2-exp", "S"), ("deepseek-v4-flash", "S"), ("deepseek-v4-pro", "A")],
27
+ "google": [("gemini-2.5-flash", "S"), ("gemini-2.5-flash-lite", "S"), ("gemini-2.5-flash-lite-preview-09-2025", "S"), ("gemini-2.5-pro", "S"), ("gemini-2.5-pro-preview", "S"), ("gemini-2.5-pro-preview-05-06", "S"), ("gemini-3-flash-preview", "A"), ("gemini-3-pro-image", "S"), ("gemini-3.1-flash-lite", "S"), ("gemini-3.1-flash-lite-preview", "S"), ("gemini-3.1-pro-preview", "A"), ("gemini-3.1-pro-preview-customtools", "S"), ("gemini-3.5-flash", "S"), ("gemma-3-12b-it", "F"), ("gemma-3-27b-it", "C"), ("gemma-4-26b-a4b-it", "S"), ("gemma-4-26b-a4b-it:free", "F"), ("gemma-4-31b-it", "S")],
28
+ "ibm-granite": [("granite-4.1-8b", "S")],
29
+ "inception": [("mercury-2", "S")],
30
+ "inclusionai": [("ling-2.6-1t", "S"), ("ling-2.6-flash", "A"), ("ring-2.6-1t", "S")],
31
+ "kwaipilot": [("kat-coder-pro-v2", "S")],
32
+ "meta-llama": [("llama-3-8b-instruct", "S"), ("llama-3.1-70b-instruct", "S"), ("llama-3.1-8b-instruct", "S"), ("llama-3.3-70b-instruct", "S"), ("llama-4-maverick", "S"), ("llama-4-scout", "S")],
33
+ "minimax": [("minimax-m1", "S"), ("minimax-m2", "S"), ("minimax-m2.1", "S"), ("minimax-m2.5", "S"), ("minimax-m2.7", "S"), ("minimax-m3", "S")],
34
+ "mistralai": [("codestral-2508", "S"), ("devstral-2512", "S"), ("ministral-14b-2512", "S"), ("ministral-3b-2512", "S"), ("ministral-8b-2512", "S"), ("mistral-large", "S"), ("mistral-large-2407", "S"), ("mistral-large-2512", "S"), ("mistral-medium-3", "S"), ("mistral-medium-3-5", "S"), ("mistral-medium-3.1", "S"), ("mistral-nemo", "S"), ("mistral-saba", "S"), ("mistral-small-2603", "S"), ("mistral-small-3.2-24b-instruct", "S"), ("mixtral-8x22b-instruct", "S"), ("voxtral-small-24b-2507", "S")],
35
+ "moonshotai": [("kimi-k2", "S"), ("kimi-k2-0905", "S"), ("kimi-k2-thinking", "S"), ("kimi-k2.5", "S"), ("kimi-k2.6", "S"), ("kimi-k2.7-code", "S")],
36
+ "nex-agi": [("nex-n2-mini", "S"), ("nex-n2-pro", "S")],
37
+ "nvidia": [("llama-3.3-nemotron-super-49b-v1.5", "S"), ("nemotron-3-nano-30b-a3b", "S"), ("nemotron-3-nano-30b-a3b:free", "A"), ("nemotron-3-nano-omni-30b-a3b-reasoning:free", "S"), ("nemotron-3-super-120b-a12b", "S"), ("nemotron-3-super-120b-a12b:free", "A"), ("nemotron-3-ultra-550b-a55b", "S"), ("nemotron-3-ultra-550b-a55b:free", "S"), ("nemotron-nano-12b-v2-vl:free", "C"), ("nemotron-nano-9b-v2:free", "A")],
38
+ "openai": [("gpt-3.5-turbo", "S"), ("gpt-3.5-turbo-0613", "S"), ("gpt-3.5-turbo-16k", "S"), ("gpt-4", "S"), ("gpt-4-turbo", "S"), ("gpt-4.1", "S"), ("gpt-4.1-mini", "S"), ("gpt-4.1-nano", "S"), ("gpt-4o", "S"), ("gpt-4o-2024-05-13", "S"), ("gpt-4o-2024-08-06", "S"), ("gpt-4o-2024-11-20", "S"), ("gpt-4o-mini", "S"), ("gpt-4o-mini-2024-07-18", "S"), ("gpt-5", "S"), ("gpt-5-codex", "S"), ("gpt-5-mini", "S"), ("gpt-5-nano", "S"), ("gpt-5-pro", "S"), ("gpt-5.1", "S"), ("gpt-5.1-chat", "S"), ("gpt-5.1-codex", "S"), ("gpt-5.1-codex-max", "S"), ("gpt-5.1-codex-mini", "S"), ("gpt-5.2", "S"), ("gpt-5.2-chat", "S"), ("gpt-5.2-codex", "S"), ("gpt-5.3-chat", "S"), ("gpt-5.3-codex", "S"), ("gpt-5.4", "S"), ("gpt-5.4-mini", "S"), ("gpt-5.4-nano", "S"), ("gpt-5.5", "S"), ("gpt-audio", "F"), ("gpt-chat-latest", "S"), ("gpt-oss-120b", "S"), ("gpt-oss-120b:free", "C"), ("gpt-oss-20b", "S"), ("gpt-oss-20b:free", "S"), ("gpt-oss-safeguard-20b", "B"), ("o1", "S"), ("o3", "S"), ("o3-mini", "S"), ("o3-mini-high", "S"), ("o3-pro", "S"), ("o4-mini", "S"), ("o4-mini-high", "S")],
39
+ "openrouter": [("auto", "S"), ("free", "S")],
40
+ "poolside": [("laguna-m.1", "S"), ("laguna-m.1:free", "A"), ("laguna-xs-2.1", "S"), ("laguna-xs-2.1:free", "S"), ("laguna-xs.2", "S"), ("laguna-xs.2:free", "S")],
41
+ "qwen": [("qwen-2.5-72b-instruct", "S"), ("qwen-2.5-7b-instruct", "S"), ("qwen-plus", "S"), ("qwen-plus-2025-07-28", "S"), ("qwen-plus-2025-07-28:thinking", "S"), ("qwen3-14b", "S"), ("qwen3-235b-a22b", "S"), ("qwen3-235b-a22b-2507", "S"), ("qwen3-235b-a22b-thinking-2507", "C"), ("qwen3-30b-a3b", "S"), ("qwen3-30b-a3b-instruct-2507", "S"), ("qwen3-30b-a3b-thinking-2507", "S"), ("qwen3-32b", "S"), ("qwen3-8b", "S"), ("qwen3-coder", "S"), ("qwen3-coder-30b-a3b-instruct", "S"), ("qwen3-coder-flash", "S"), ("qwen3-coder-next", "S"), ("qwen3-coder-plus", "S"), ("qwen3-max", "S"), ("qwen3-max-thinking", "S"), ("qwen3-next-80b-a3b-instruct", "S"), ("qwen3-next-80b-a3b-thinking", "S"), ("qwen3-vl-235b-a22b-instruct", "S"), ("qwen3-vl-235b-a22b-thinking", "S"), ("qwen3-vl-30b-a3b-instruct", "S"), ("qwen3-vl-30b-a3b-thinking", "S"), ("qwen3-vl-32b-instruct", "S"), ("qwen3-vl-8b-instruct", "S"), ("qwen3-vl-8b-thinking", "S"), ("qwen3.5-122b-a10b", "S"), ("qwen3.5-27b", "S"), ("qwen3.5-35b-a3b", "S"), ("qwen3.5-397b-a17b", "S"), ("qwen3.5-9b", "S"), ("qwen3.5-flash-02-23", "S"), ("qwen3.5-plus-02-15", "S"), ("qwen3.5-plus-20260420", "S"), ("qwen3.6-27b", "S"), ("qwen3.6-35b-a3b", "S"), ("qwen3.6-flash", "S"), ("qwen3.6-max-preview", "S"), ("qwen3.6-plus", "S"), ("qwen3.7-max", "S"), ("qwen3.7-plus", "S")],
42
+ "rekaai": [("reka-edge", "A")],
43
+ "relace": [("relace-search", "S")],
44
+ "stepfun": [("step-3.5-flash", "S"), ("step-3.7-flash", "S")],
45
+ "tencent": [("hy3", "S"), ("hy3-preview", "S"), ("hy3:free", "S")],
46
+ "thedrummer": [("unslopnemo-12b", "F")],
47
+ "upstage": [("solar-pro-3", "S")],
48
+ "x-ai": [("grok-4.20", "S"), ("grok-build-0.1", "S")],
49
+ "xiaomi": [("mimo-v2.5", "S"), ("mimo-v2.5-pro", "S")],
50
+ "z-ai": [("glm-4.5", "S"), ("glm-4.5-air", "S"), ("glm-4.5v", "S"), ("glm-4.6", "S"), ("glm-4.6v", "S"), ("glm-4.7", "S"), ("glm-4.7-flash", "S"), ("glm-5", "S"), ("glm-5-turbo", "S"), ("glm-5.1", "S"), ("glm-5.2", "S"), ("glm-5v-turbo", "S")],
51
+ "~anthropic": [("claude-haiku-latest", "S"), ("claude-opus-latest", "S"), ("claude-sonnet-latest", "S")],
52
+ "~google": [("gemini-flash-latest", "S")],
53
+ "~moonshotai": [("kimi-latest", "S")],
54
+ "~openai": [("gpt-latest", "S"), ("gpt-mini-latest", "A")],
55
+ "~x-ai": [("grok-latest", "S")],
56
+ }
57
+
58
+ # Curated recommendations — override layer
59
+ _RECOMMENDED: dict[str | None, dict[str, str]] = {
60
+ None: {"best": "gpt-4o", "cheapest": "gpt-4o-mini"},
61
+ "openai": {"best": "gpt-4o", "cheapest": "gpt-4o-mini"},
62
+ "anthropic": {"best": "claude-sonnet-4.6", "cheapest": "claude-haiku-4.5"},
63
+ "google": {"best": "gemini-2.5-flash", "cheapest": "gemini-2.0-flash-001"},
64
+ "mistralai": {"best": "mistral-large", "cheapest": "mistral-nemo"},
65
+ "meta-llama": {"best": "llama-4-maverick", "cheapest": "llama-3.1-8b-instruct"},
66
+ "deepseek": {"best": "deepseek-chat", "cheapest": "deepseek-chat"},
67
+ "qwen": {"best": "qwen3-235b-a22b", "cheapest": "qwen3-30b-a3b"},
68
+ "x-ai": {"best": "grok-4", "cheapest": "grok-3-mini"},
69
+ "cohere": {"best": "command-r-plus-08-2024", "cheapest": "command-r-08-2024"},
70
+ "nvidia": {"best": "llama-3.3-nemotron-super-49b-v1.5", "cheapest": "nemotron-nano-9b-v2"},
71
+ "amazon": {"best": "nova-pro-v1", "cheapest": "nova-micro-v1"},
72
+ "minimax": {"best": "minimax-m2.7", "cheapest": "minimax-m1"},
73
+ "z-ai": {"best": "glm-5", "cheapest": "glm-4.7-flash"},
74
+ "inception": {"best": "mercury-2", "cheapest": "mercury"},
75
+ "moonshotai": {"best": "kimi-k2.5", "cheapest": "kimi-k2"},
76
+ "xiaomi": {"best": "mimo-v2-pro", "cheapest": "mimo-v2-flash"},
77
+ "bytedance-seed": {"best": "seed-1.6", "cheapest": "seed-2.0-mini"},
78
+ }
79
+
80
+
81
+ def recommend_model(
82
+ provider: str | None = None,
83
+ *,
84
+ prefer: str = "best",
85
+ minimum_tier: str = "S",
86
+ ) -> str | None:
87
+ """Recommend a model for a given provider.
88
+
89
+ Args:
90
+ provider: Provider name (e.g. "openai", "anthropic"). None for overall best.
91
+ prefer: "best" or "cheapest".
92
+ minimum_tier: Minimum acceptable tier ("S", "A", "B", "C", "F").
93
+
94
+ Returns:
95
+ Model name string, or None if no model meets the criteria.
96
+
97
+ Raises:
98
+ ValueError: If prefer or minimum_tier is invalid.
99
+ """
100
+ if prefer not in ("best", "cheapest"):
101
+ raise ValueError(f"Unknown prefer value: {prefer!r}. Use 'best' or 'cheapest'.")
102
+ if minimum_tier not in _TIER_ORDER:
103
+ raise ValueError(
104
+ f"Unknown minimum_tier: {minimum_tier!r}. Use one of: {', '.join(_TIER_ORDER)}."
105
+ )
106
+
107
+ if provider is not None:
108
+ provider = provider.lower()
109
+
110
+ # Try curated recommendation first
111
+ recs = _RECOMMENDED.get(provider)
112
+ if recs:
113
+ candidate = recs.get(prefer)
114
+ if candidate:
115
+ # Verify the candidate meets the minimum tier
116
+ tier_list = _TIER_DATA.get(provider, [])
117
+ for model_name, tier in tier_list:
118
+ if model_name == candidate and _tier_passes(tier, minimum_tier):
119
+ return candidate
120
+
121
+ # Fallback: find best model from tier data that meets minimum
122
+ if provider is None:
123
+ # Overall: check all providers
124
+ for prov, models in _TIER_DATA.items():
125
+ for model_name, tier in models:
126
+ if _tier_passes(tier, minimum_tier):
127
+ # Return overall curated default if available
128
+ overall = _RECOMMENDED.get(None, {})
129
+ fallback = overall.get(prefer)
130
+ if fallback:
131
+ return fallback
132
+ return model_name
133
+ return None
134
+
135
+ tier_list = _TIER_DATA.get(provider, [])
136
+ if not tier_list:
137
+ return None
138
+
139
+ # Find any model meeting the minimum tier
140
+ for model_name, tier in tier_list:
141
+ if _tier_passes(tier, minimum_tier):
142
+ return model_name
143
+
144
+ return None