Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
otp: "27"
- elixir: "1.20"
otp: "29"
# Formatter output differs between Elixir versions.
check_format: true

steps:
- uses: actions/checkout@v7
Expand Down Expand Up @@ -52,6 +54,7 @@ jobs:
run: mix deps.unlock --check-unused

- name: Check formatting
if: matrix.check_format
run: mix format --check-formatted

- name: Compile (warnings as errors)
Expand Down
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
## Unreleased

- New: the Tasks extension (`io.modelcontextprotocol/tasks`) under MCP
2026-07-28. A tool returns `{:reply, %Phantom.Tasks{}, session}` to answer
with a task, and the router implements `c:Phantom.Router.get_task/2`, and
optionally `update_task/3`, `cancel_task/2`, and
`authorize_task_subscriptions/2`, for `tasks/get`, `tasks/update`, and
`tasks/cancel`. Phantom does not store tasks. See the Tasks guide for Ecto
and Oban examples.
- New: `Phantom.Session.tasks_supported?/1`, and
`Phantom.Tracker.notify_task_updated/1`. Each `subscriptions/listen` stream
that follows the task fetches it with `get_task/2` and sends
`notifications/tasks`.
- New: `Phantom.Test.get_task/3`, `update_task/4`, `cancel_task/3`,
`assert_task/2`, and a `:tasks` option for `call_tool/4`.
- New: `Phantom.Session.progress_ref/1` returns a JSON-safe reference to the
current request. `Phantom.Session.notify_progress/4` accepts it, so a job
on any node can report progress to a waiting `tools/call` or `prompts/get`
through PubSub.
- New: `Phantom.Elicit.to_input_request/1` renders one embedded
`elicitation/create` request to place under your own `inputRequests` key,
such as a task's input requests.
- New: `Phantom.Request.missing_task_capability/0`, the error for a tool that
only runs as a task when the client did not declare the extension.
- `Phantom.Request.missing_capability/1` accepts a `ClientCapabilities` map,
for capabilities whose names contain dots.

Streamable HTTP transport fixes for the protocol versions before 2026-07-28:

- New: `Phantom.Plug` option `validate_session: true` answers `404 Not Found`
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,10 @@ Phantom will implement these MCP requests on your behalf:
`input_required` result + encrypted `requestState`; both flows go through
`Phantom.Session.elicit/3` and behave identically from the tool's point
of view.
- `tasks/get`, `tasks/update`, `tasks/cancel` - the Tasks extension under MCP
`2026-07-28`, when the router implements `c:Phantom.Router.get_task/2`. A tool
answers with a `Phantom.Tasks` and you store and run the task, such as with
Oban. See the [Tasks guide](guides/tasks.md).

Phantom **does not yet support these methods**:

Expand Down Expand Up @@ -872,8 +876,10 @@ the JSON-RPC body into HTTP headers so load balancers, proxies, and WAFs
can route on the operation without parsing the body:

- `Mcp-Method` — mirrors `method`. Required on every POST.
- `Mcp-Name` — mirrors `params.name` (for `tools/call`, `prompts/get`)
or `params.uri` (for `resources/read`).
- `Mcp-Name` — mirrors `params.name` (for `tools/call`, `prompts/get`),
`params.uri` (for `resources/read`), or `params.taskId` (for `tasks/get`,
`tasks/update`, `tasks/cancel`). Route on it when tasks live in one node's
memory.

Header names are case-insensitive; values are case-sensitive (so
`Mcp-Method: TOOLS/CALL` does *not* match a body method of `tools/call`).
Expand Down
Loading
Loading