Skip to content

[Feat] Let run_agent run as an MCP task (2025-11-25 experimental tasks on the 1.x SDK) - #106

Draft
Birfy wants to merge 1 commit into
mainfrom
issue-102-mcp-tasks
Draft

Birfy wants to merge 1 commit into
mainfrom
issue-102-mcp-tasks

Conversation

@Birfy

@Birfy Birfy commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Required human contributor answers

Per the repo owner's (Danyang, @Birfy) standing instruction, these are filled from the issue (#102) instead of waiting for separate human answers.

  1. What outcome are you trying to achieve?

    Answer: A host can start a long run_agent without holding one tools/call request open for the whole browser budget, then poll and cancel it ([MCP] Adopt MCP Tasks so long run_agent can outlive the host session #102).

  2. What is the highest-leverage variable for that outcome?

    Answer: Whether s1a-mcp can answer a task-augmented tools/call while staying on mcp<2 ([Deps] Bound mcp below 2 and record what blocks the move to the 2026-07-28 SDK #74).

  3. How will this work move that variable rather than create busywork?

    Answer: It does the spike from scope item 1 and lands the path the 1.x SDK supports, with contract tests for the task path, the plain path and cancel, and docs that say what is and is not verified.

  4. Who is the customer or user, and what do they actually need?

    Answer: People calling S1A agents from MCP hosts (Claude Code, Codex) whose tool timeouts are shorter than a browser run.

After answering the four questions: is a PR needed at all to achieve this outcome?

Human decision and rationale (or explicit source reference): Yes; #102 scopes this as one opt-in PR.

For a bug fix: link actual observed failure evidence.

Evidence: Not a bug fix: a new opt-in call mode.

Why

run_agent can take minutes (Allrecipes budgets 300 s), and today a host must keep the request open the whole time. Closes #102.

How

Spike result (scope item 1): the installed mcp 1.30.0 implements tasks as the 2025-11-25 experimental API (SEP-1686: capabilities.tasks, params.task, tasks/get|result|list|cancel). It does not implement the 2026-07-28 extension form, and it marks the experimental API deprecated ("tasks (SEP-1686) were removed from the MCP specification and are expected to return as a separate MCP extension"). So tasks can land on 1.x, but only in the 2025-11-25 shape; a host that speaks only the extension form will keep the plain call. The mcp 2 move from #74 is not needed for this, and it would not give the extension form either.

Start with s1a/mcp_server.py, then TestRunAgentAsTask in tests/test_mcp_server.py.

  • _TaskServer(FastMCP) marks run_agent execution.taskSupport: "optional" in tools/list. A tools/call without task takes FastMCP's unchanged path. With task, it calls run_task, returns a CreateTaskResult at once, and runs the same FastMCP tool call in the session's task group.
  • Progress messages (episode N/M, step N/M) become the task's statusMessage via update_status (rate-bounded like progress notifications; the limiter is now shared as _rate_bounded).
  • tasks/cancel wraps the SDK's handler (session scope and terminal-state checks) and then cancels the run's anyio.CancelScope, which is the same cancellation notifications/cancelled triggers today, so the slot is freed, the browser closed and the cancellation recorded ([MCP] Keep long run_agent calls inside host tool timeouts: progress, bounded lock wait, cancellation, documented settings #83).
  • _TaskStore(InMemoryTaskStore) keeps a cancelled task cancelled: the SDK otherwise raises "Cannot transition from terminal status" when the unwinding run completes.
  • A task's ttl is raised to at least 1 h, because the in-memory store counts it from creation and the client default (60 s) would drop a run part-way.
  • Bad flags and the busy refusal complete the task with an isError result (as they are the plain call's result). A task call of decide or list_agents is a -32601 protocol error.

What

  • s1a-mcp advertises the tasks capability; run_agent is task-optional. No change for clients that send no task.
  • Docs: docs/skills.md § Long runs as MCP tasks (what is and is not verified), docs/architecture.md § MCP SDK 2.x (the port must move or drop this path), CHANGELOG.
  • No host flags are documented: no host has been verified against this path yet, so the raised tool timeout advice stays.

Verification

  • uv run ruff format --check . && uv run ruff check . && uv run ty check (all pass)
  • uv run pytest -q: 1356 passed, 123 skipped; scripts/smoke.sh: smoke: ok
  • CHANGELOG.md and the docs say what the code does now

New tests (in-memory client using the SDK's session.experimental task calls): capability and taskSupport advertisement; task returns at once, working with episode 1/2, holds the run slot, then completed with the summary; a real counter run as a task returns the same summary and job folder; bad flags and busy refusal end as isError results; tasks/cancel tears the browser and session down, frees the slot, leaves the task cancelled; task call of decide is -32601.

Demo / evidence

  • Video link, or exemption/blocker with follow-up: N/A for a video (MCP protocol change, no application run). Blocker for "verified host": no Claude Code / Codex run against this path yet; kept as draft until one is checked or a maintainer accepts that.
  • Application/task → agent actions → independently checked result: contract tests only.
  • System1-Agents / System1-Omni commits, checkpoint and worker/frontend provenance: base main 113ef26; no System1-Omni involved.

…SDK)

A task-augmented run_agent returns a task id at once; tasks/get reports the
latest episode or step, tasks/result the usual result and tasks/cancel stops the
run through the existing cancellation path. Plain calls are unchanged; decide and
list_agents refuse task calls with -32601.

Closes #102

@Birfy Birfy left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Self-review (Birfy; cannot approve own PR).

Ready-to-merge-from-my-side as the #102 spike + 1.x experimental path: the finding that mcp 1.30 only speaks the deprecated 2025-11-25 experimental tasks API (not the 2026-07-28 extension) is correctly recorded, and the implementation matches that constraint — run_agent task-optional, sync path unchanged, progress → statusMessage, cancel through the same CancelScope as #83, TTL ≥ 1 h, tool errors complete the task with isError. Contract tests cover the important branches.

What's left / follow-ups:

  1. Still draft until a real Claude Code / Codex host is checked against this path, or a maintainer accepts contract tests alone.
  2. Hosts that only negotiate the official Tasks extension (io.modelcontextprotocol/tasks, SEP-2663 / 2026-07-28) will keep the plain call — tracked as new issue #115 so we do not pretend this PR covers them.
  3. Docs correctly refuse to invent unverified host flags; keep that discipline on merge.

No code-change request from this pass; CI green. From my side the experimental path is mergeable once the host-verification / maintainer call is made; the extension port is out of scope here (#115).

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.

[MCP] Adopt MCP Tasks so long run_agent can outlive the host session

1 participant