Skip to content

feat: remove write tools — read-only fork for LoyaltyLion - #1

Merged
m-sherman merged 2 commits into
mainfrom
mark/temporal-mcp-remove-write-actions
May 21, 2026
Merged

feat: remove write tools — read-only fork for LoyaltyLion#1
m-sherman merged 2 commits into
mainfrom
mark/temporal-mcp-remove-write-actions

Conversation

@m-sherman

Copy link
Copy Markdown

Summary

This downstream fork strips every mutating tool from GethosTheWalrus/temporal-mcp so AI clients (Claude Code, in-VPC agents) can only inspect our self-hosted Temporal cluster. Our self-hosted Temporal has no authorizer / claim mapper configured, so anything that can reach the frontend on 7233 can do anything — physically removing the write code in the image is the safest gate.

What's exposed (6 tools)

Tool Why
describe_workflow Workflow status, timing, metadata
get_workflow_history Full event history
get_workflow_result Result of completed workflows
list_workflows Query / paginate workflows
query_workflow Read-only by Temporal contract (queries don't write history); the only caveat is workflow-side query handlers that violate the contract
list_schedules Inspect schedules

What was removed

  • Workflow control: start_workflow, signal_workflow, cancel_workflow, terminate_workflow, continue_as_new
  • Batch ops: batch_signal, batch_cancel, batch_terminate
  • Schedule mutations: create_schedule, pause_schedule, unpause_schedule, delete_schedule, trigger_schedule

Deletions go all the way down — no Tool entries in tool_definitions.py, no elif branches in the dispatch in server.py, no handler functions in the handlers/ modules. batch_handlers.py is gone entirely.

Other cleanup

  • .github/workflows/release.yml removed — upstream's auto-publish-to-PyPI workflow is dangerous on a downstream fork. We install via pip install git+https://github.com/loyaltylion/temporal-mcp@<sha>, not from PyPI.
  • pyproject.toml URLs point at the fork; description / keywords note read-only.
  • README.md has a top-of-file fork notice and a trimmed Tools section.
  • Tests for removed handlers deleted; remaining tests pass (54 passing locally).

Test plan

  • pytest -v passes locally (54 / 54)
  • Lint workflow green on this PR
  • Consumer: aws-infrastructure Dockerfile pins this fork SHA and the resulting image builds in Buildkite

Tracking upstream

The fork's main will track GethosTheWalrus/temporal-mcp/main as a courtesy. Rebases happen on the loyaltylion/read-only family of branches, not main, so upstream history stays clean. We pin downstream consumers to specific SHAs, never to a branch name.

🤖 Generated with Claude Code

@m-sherman
m-sherman requested a review from frangz May 19, 2026 14:37

@loyaltylion-minerva loyaltylion-minerva Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a clean, well-scoped surface reduction. The removals go all the way down — Tool entries, dispatch branches, handler functions, and tests are all in lockstep, so a stale client requesting a removed tool just falls into the unknown_tool branch in server.py rather than hitting half-stripped code. Module docstrings flag the fork state, the README has a prominent fork notice, and the PR description is explicit about the threat model (no Temporal authorizer configured → physical removal in the image is the gate). The defense-in-depth framing is sound; I have no concerns with the security shape of the change.

A few small follow-ups worth landing now or in a quick follow-up — none are blockers:

  • The exceptions.py write-error formatters are now unreachable. The two write-only error subclasses (WorkflowAlreadyStartedError, ScheduleAlreadyRunningError) can no longer be raised because every code path that would have created a workflow or schedule is gone. The imports and helpers can be removed to keep the surface area honest.
  • A couple of README spots still describe the upstream surface ("manage Temporal workflows" in the Overview, the Distributions section pointing at upstream PyPI/Docker without inline disambiguation). The top-of-file notice covers this for an attentive reader, but a skim-reader could miss it.
  • pyproject.toml keeps the upstream version = "1.1.1" and drops the Issues URL. Since you're pinning consumers by SHA the version is mostly cosmetic, but worth a thought on whether to bump it (e.g. 1.1.1+loyaltylion.1) and to point Issues at the fork repo's issue tracker.

Tests look right — only the removed-tool tests went away; the read-path tests remain (54 passing matches the PR description). Good shape.

Comment thread pyproject.toml
@@ -1,14 +1,14 @@
[project]
name = "temporal-mcp-server"
version = "1.1.1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fork ships as version = "1.1.1" — identical to upstream's last release. Consumers pin by SHA per the PR description so this is mostly cosmetic, but it can create confusion if anything ever surfaces the version (e.g. pip show, --version output). Consider a fork-distinguishing form like 1.1.1+loyaltylion.1 (PEP 440 local version segment) so the lineage stays legible without affecting install ordering.

Comment thread pyproject.toml
Issues = "https://github.com/GethosTheWalrus/temporal-mcp/issues"
Homepage = "https://github.com/loyaltylion/temporal-mcp"
Repository = "https://github.com/loyaltylion/temporal-mcp"
Upstream = "https://github.com/GethosTheWalrus/temporal-mcp"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issues = "https://github.com/GethosTheWalrus/temporal-mcp/issues" was dropped from [project.urls]. Given the fork lives at loyaltylion/temporal-mcp, consider re-adding Issues = "https://github.com/loyaltylion/temporal-mcp/issues" so downstream consumers (or a future Slack-found PyPI lookup) have a canonical place to file bugs against the fork rather than against upstream.

@frangz frangz left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 thoughts:

  • This is a significant change over the upstream repo. It won't be straightforward to bring in new changes. Is there a more minimal way to remove or block write tools? e.g. just do not register them, but keep the code in place.
  • I do wonder if write tools would be handy. e.g. currently we can only start workflows using a luna or remus console, which is terribly annoying. It would be great if we could do it via Claude. Similarly to stop a workflow: you first need to find it on the UI, which is also not friendly. But I get the safety considerations, so you can move ahead.

@loyaltylion-minerva loyaltylion-minerva Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The delta since my last review is a single commit (chore: drop CI workflows) that deletes .github/dependabot.yml and every workflow under .github/workflows/ (lint, test, security, dependabot-auto-merge, labels). For a SHA-pinned read-only fork with no PyPI publish path, dropping the inherited upstream CI is a defensible call — the surface that mattered (the release workflow) was already gone in the previous commit, and downstream consumers run their own CI on the pinned SHA. The two unresolved comments from my previous review (pyproject.toml version and Issues URL) are not addressed by this commit; I've left them as-is since they're nits that the author is welcome to defer.

One small consistency note: the PR description's test plan still has "Lint workflow green on this PR" as a checkbox, which is now untestable. Worth a quick edit to the PR body to either drop that bullet or note that CI was intentionally removed in the latest commit.

Otherwise, no new issues — happy for this to merge.

Comment thread README.md
@@ -1,4 +1,8 @@
# Temporal MCP Server
# Temporal MCP Server — LoyaltyLion read-only fork

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Respond to this comment to discuss this review with me

@m-sherman
m-sherman merged commit d285b81 into main May 21, 2026
1 check passed
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.

2 participants