feat(mcp): built-in playbooks get steward_url from Steward itself
CI / lint (push) Successful in 3s
CI / integration (push) Successful in 48s
CI / unit (push) Successful in 1m11s
CI / publish (push) Successful in 1m23s

#5015 "Built-in host-agent playbooks make an MCP caller supply steward_url"

- run_playbook, create_schedule and set_alert_action fill a steward-builtin
  playbook's steward_url when the caller leaves it out or empty, from
  Settings → General → Public base URL, else the scheme and host the MCP
  request arrived on — the same source the web actions use.
- run_playbook's reply names what it filled (filled_by_steward), and
  get_playbook shows that value as the variable's default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 10:30:23 -04:00
co-authored by Claude Opus 5.5
parent 06e89308a8
commit 1d9ac2b46a
4 changed files with 78 additions and 6 deletions
+25
View File
@@ -107,3 +107,28 @@ def test_a_viewer_token_cannot_start_a_run(app):
assert "needs the operator role" in app.mcp_server.refusal("run_playbook", viewer)
assert app.mcp_server.refusal("run_playbook", operator) is None
assert "needs the admin role" in app.mcp_server.refusal("set_alert_action", operator)
def test_builtin_playbooks_get_steward_url_from_steward():
from steward.mcp import _context
app = NS(config={"PUBLIC_BASE_URL": ""})
a, u = _context._app_ctx.set(app), _context._base_url_ctx.set("http://steward.lan")
try:
declared = [{"name": "steward_url", "default": "", "secret": False, "required": False,
"prompt": None}]
builtin = {"name": "steward-builtin"}
got, filled = automation.steward_defaults(builtin, declared, {"agent_interval": 30})
assert got == {"agent_interval": 30, "steward_url": "http://steward.lan"}
assert filled == {"steward_url": "http://steward.lan"}
# The configured public URL wins over the address the request came in on.
app.config["PUBLIC_BASE_URL"] = "https://steward.example/"
assert automation.steward_defaults(builtin, declared, {})[1] == {
"steward_url": "https://steward.example"}
# A value the caller passed stands; another source's playbook is untouched.
assert automation.steward_defaults(builtin, declared, {"steward_url": "http://x"})[1] == {}
assert automation.steward_defaults({"name": "homelab"}, declared, {}) == ({}, {})
# A playbook that doesn't declare it gets nothing extra.
assert automation.steward_defaults(builtin, [], {}) == ({}, {})
finally:
_context._app_ctx.reset(a)
_context._base_url_ctx.reset(u)