Skip to content

feat(mcp): expose STRATEGY.md / STATE.json via 5 new MCP tools#74

Merged
hyoshi merged 1 commit intomainfrom
feat/mcp-strategy-state-tools
May 1, 2026
Merged

feat(mcp): expose STRATEGY.md / STATE.json via 5 new MCP tools#74
hyoshi merged 1 commit intomainfrom
feat/mcp-strategy-state-tools

Conversation

@hyoshi
Copy link
Copy Markdown
Collaborator

@hyoshi hyoshi commented May 1, 2026

Summary

Add 5 MCP tools that expose mureo's context layer (STRATEGY.md and STATE.json) so MCP hosts without filesystem access can read and update strategic context:

Tool Purpose
mureo_strategy_get Read STRATEGY.md as markdown
mureo_strategy_set Atomically replace STRATEGY.md (validates via parse_strategy)
mureo_state_get Read STATE.json as a parsed v2 doc
mureo_state_action_log_append Atomically append an action_log entry
mureo_state_upsert_campaign Atomically upsert a CampaignSnapshot

Why now

  • Claude Desktop chat / claude.ai web have no Read tool — without these MCP tools, users have to paste STRATEGY.md / STATE.json into chat manually.
  • Meta's official MCP has shipped; Google's is likely next. When raw API access becomes a commodity, mureo's value sits in the orchestration layer (strategy + state + action_log + rollback + synthesis). That layer needs its own MCP surface so mureo isn't invisible from non-Code hosts.
  • This is Phase 1 of the MCP-ization plan — Phase 2 (skill migration) and Phase 3 (synthesis tools) come later.

Security

  • _resolve_path refuses any path that resolves outside cwd, mirroring mureo/mcp/_handlers_rollback.py:_resolve_state_file. Path.resolve() follows symlinks, so a STRATEGY.md inside cwd that symlinks to /etc/passwd resolves to the target and is rejected.
  • All writes go through pre-existing atomic helpers in mureo.context.state / mureo.context.strategy (temp file + os.replace). A failed write leaves the original file intact (covered by test_strategy_set_is_atomic).
  • mureo_strategy_set round-trips input through parse_strategy() so a malformed payload raises before the file is overwritten.

Test plan

  • tests/test_mcp_tools_mureo_context.py — 13 unit tests covering all 5 tools, including atomic-write failure, missing-file defaults, required-field validation, upsert-create + upsert-update, and the path-traversal refusal.
  • tests/test_mcp_tool_name_spec.py — regression guard updated to include tools_mureo_context; all 5 names match ^[a-zA-Z0-9_-]{1,64}$.
  • tests/test_mcp_server.py::TestListTools::test_list_tools_returns_all_tools — total tool count updated 173 → 178.
  • ruff check, black --check, mypy --strict all pass on new files.
  • python-reviewer agent: addressed HIGH (unify path-resolve gate with rollback's relative_to idiom) and MEDIUM (drop redundant default in handle_state_get, add upsert-update test).

Out of scope

Pre-existing test failures in tests/test_mcp_tools_meta_ads_* and 4 tests in test_mcp_server.py (BYOD demo data leaking into expected "no credentials" assertions) are unrelated to this change and exist on the branch base.

Add `mureo_strategy_get`, `mureo_strategy_set`, `mureo_state_get`,
`mureo_state_action_log_append`, and `mureo_state_upsert_campaign`
so MCP hosts that lack a Read tool (Claude Desktop chat, claude.ai
web, remote MCP) can inspect and update mureo's context layer
without filesystem access.

Why: the existing google_ads_* / meta_ads_* tools already work over
MCP, but STRATEGY.md / STATE.json access still requires Claude Code
or a paste-into-chat workaround. With Meta's MCP shipping and
Google's likely to follow, mureo needs its own MCP surface for the
orchestration layer (strategy, state, action_log, rollback) — that's
where mureo's value lives once vendor MCPs handle raw API access.

Security:
- `_resolve_path` refuses paths outside cwd, mirroring the rollback
  surface's `_resolve_state_file` (Path.resolve() follows symlinks,
  so an in-cwd symlink to /etc/passwd resolves to its target and is
  rejected).
- All writes go through pre-existing atomic helpers in
  context.state and context.strategy (temp file + os.replace).
- mureo_strategy_set round-trips the input through parse_strategy()
  to refuse malformed markdown rather than corrupting the file.

Tool names match the MCP spec regex `^[a-zA-Z0-9_-]{1,64}$` and are
covered by the existing test_mcp_tool_name_spec regression guard.
@hyoshi hyoshi merged commit 03557c9 into main May 1, 2026
8 checks passed
@hyoshi hyoshi deleted the feat/mcp-strategy-state-tools branch May 1, 2026 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant