Skip to content

Enable programmatic querying of background callback status/result; re…

f4254e2
Select commit
Loading
Failed to load commit list.
Sign in for the full log view
Open

MCP Server Part 9: Background callbacks #3766

Enable programmatic querying of background callback status/result; re…
f4254e2
Select commit
Loading
Failed to load commit list.
GitHub Actions / Test Results Summary succeeded May 14, 2026 in 0s

831 passed, 2 failed and 14 skipped

Tests failed

Report Passed Failed Skipped Time
test-results/background-test-results-py3.12/junit_background.xml 35✅ 1❌ 2⚪ 423s
test-results/background-test-results-py3.9/junit_async.xml 26✅ 75s
test-results/background-test-results-py3.9/junit_background.xml 36✅ 2⚪ 423s
test-results/test-main-results-py3.12-group1/junit_intg.xml 158✅ 3⚪ 367s
test-results/test-main-results-py3.12-group2/junit_intg.xml 131✅ 1❌ 1⚪ 456s
test-results/test-main-results-py3.12-group3/junit_intg.xml 106✅ 1⚪ 292s
test-results/test-main-results-py3.8-group1/junit_intg.xml 132✅ 2⚪ 269s
test-results/test-main-results-py3.8-group2/junit_intg.xml 111✅ 2⚪ 433s
test-results/test-main-results-py3.8-group3/junit_intg.xml 96✅ 1⚪ 248s

❌ test-results/background-test-results-py3.12/junit_background.xml

38 tests were completed in 423s with 35 passed, 1 failed and 2 skipped.

Test suite Passed Failed Skipped Time
pytest 35✅ 1❌ 2⚪ 423s

❌ pytest

bgtests.tests.background_callback.test_basic_long_callback001
  ✅ test_lcbc001_fast_input[celery]
  ✅ test_lcbc001_fast_input[diskcache]
bgtests.tests.background_callback.test_basic_long_callback002
  ✅ test_lcbc002_long_callback_running[celery]
  ✅ test_lcbc002_long_callback_running[diskcache]
bgtests.tests.background_callback.test_basic_long_callback003
  ✅ test_lcbc003_long_callback_running_cancel[celery]
  ✅ test_lcbc003_long_callback_running_cancel[diskcache]
bgtests.tests.background_callback.test_basic_long_callback004
  ✅ test_lcbc004_long_callback_progress[celery]
  ✅ test_lcbc004_long_callback_progress[diskcache]
bgtests.tests.background_callback.test_basic_long_callback005
  ⚪ test_lcbc005_long_callback_caching[celery]
  ⚪ test_lcbc005_long_callback_caching[diskcache]
bgtests.tests.background_callback.test_basic_long_callback006
  ✅ test_lcbc006_long_callback_caching_multi[celery]
  ✅ test_lcbc006_long_callback_caching_multi[diskcache]
bgtests.tests.background_callback.test_basic_long_callback007
  ✅ test_lcbc007_validation_layout[celery]
  ✅ test_lcbc007_validation_layout[diskcache]
bgtests.tests.background_callback.test_basic_long_callback008
  ✅ test_lcbc008_long_callbacks_error[celery]
  ❌ test_lcbc008_long_callbacks_error[diskcache]
	self = <dash.testing.composite.DashComposite object at 0x7f989243ae70>
bgtests.tests.background_callback.test_basic_long_callback009
  ✅ test_lcbc009_short_interval[celery]
  ✅ test_lcbc009_short_interval[diskcache]
bgtests.tests.background_callback.test_basic_long_callback010
  ✅ test_lcbc010_side_updates[celery]
  ✅ test_lcbc010_side_updates[diskcache]
bgtests.tests.background_callback.test_basic_long_callback011
  ✅ test_lcbc011_long_pattern_matching[celery]
  ✅ test_lcbc011_long_pattern_matching[diskcache]
bgtests.tests.background_callback.test_basic_long_callback012
  ✅ test_lcbc012_long_callback_ctx[celery]
  ✅ test_lcbc012_long_callback_ctx[diskcache]
bgtests.tests.background_callback.test_basic_long_callback013
  ✅ test_lcbc013_unordered_state_input[celery]
  ✅ test_lcbc013_unordered_state_input[diskcache]
bgtests.tests.background_callback.test_basic_long_callback014
  ✅ test_lcbc014_progress_delete[celery]
  ✅ test_lcbc014_progress_delete[diskcache]
bgtests.tests.background_callback.test_basic_long_callback015
  ✅ test_lcbc015_diff_outputs_same_func[celery]
  ✅ test_lcbc015_diff_outputs_same_func[diskcache]
bgtests.tests.background_callback.test_basic_long_callback016
  ✅ test_lcbc016_multi_page_cancel[celery]
  ✅ test_lcbc016_multi_page_cancel[diskcache]
bgtests.tests.background_callback.test_basic_long_callback017
  ✅ test_lcbc017_long_callback_set_props[celery]
  ✅ test_lcbc017_long_callback_set_props[diskcache]
bgtests.tests.background_callback.test_basic_long_callback018
  ✅ test_lcbc018_background_callback_on_error[celery]
  ✅ test_lcbc018_background_callback_on_error[diskcache]
bgtests.tests.background_callback.test_ctx_cookies
  ✅ test_lcbc019_ctx_cookies[celery]
  ✅ test_lcbc019_ctx_cookies[diskcache]

✅ test-results/background-test-results-py3.9/junit_async.xml

26 tests were completed in 75s with 26 passed, 0 failed and 0 skipped.

✅ test-results/background-test-results-py3.9/junit_background.xml

38 tests were completed in 423s with 36 passed, 0 failed and 2 skipped.

✅ test-results/test-main-results-py3.12-group1/junit_intg.xml

161 tests were completed in 367s with 158 passed, 0 failed and 3 skipped.

❌ test-results/test-main-results-py3.12-group2/junit_intg.xml

133 tests were completed in 456s with 131 passed, 1 failed and 1 skipped.

Test suite Passed Failed Skipped Time
pytest 131✅ 1❌ 1⚪ 456s

❌ pytest

tests.integration.devtools.test_callback_validation
  ✅ test_dvcv002_blank_id_prop
  ✅ test_dvcv003_duplicate_outputs_same_callback
  ✅ test_dvcv004_duplicate_outputs_across_callbacks
  ✅ test_dvcv005_input_output_overlap
  ✅ test_dvcv006_inconsistent_wildcards
  ✅ test_dvcv007_disallowed_ids
  ✅ test_dvcv008_wrong_callback_id
  ✅ test_dvcv009_suppress_callback_exceptions
  ✅ test_dvcv010_bad_props
  ✅ test_dvcv011_duplicate_outputs_simple
  ✅ test_dvcv012_circular_2_step
  ✅ test_dvcv013_circular_3_step
  ✅ test_dvcv014_multipage_errors
  ✅ test_dvcv015_multipage_validation_layout[function]
  ✅ test_dvcv015_multipage_validation_layout[attribute]
  ✅ test_dvcv015_multipage_validation_layout[suppress]
  ✅ test_dvcv016_circular_with_input_output
  ✅ test_dvcv017_match_input_permitted_no_output_match
tests.integration.devtools.test_devtools_error_handling
  ✅ test_dveh001_python_errors
  ✅ test_dveh006_long_python_errors
  ✅ test_dveh002_prevent_update_not_in_error_msg
  ✅ test_dveh003_validation_errors_in_place
  ✅ test_dveh004_validation_errors_creation
  ✅ test_dveh005_multiple_outputs
tests.integration.devtools.test_devtools_ui
  ✅ test_dvui001_disable_props_check_config
  ✅ test_dvui002_disable_ui_config
  ✅ test_dvui003_callback_graph
  ✅ test_dvui004_width_props
  ✅ test_dvui005_undo_redo
  ✅ test_dvui006_no_undo_redo
  ✅ test_dvui007_other_before_request_func
tests.integration.devtools.test_hot_reload
  ✅ test_dvhr001_hot_reload
tests.integration.devtools.test_props_check
  ⚪ test_dvpc001_prop_check_errors_with_path
tests.integration.mcp.primitives.tools.test_tool_decorated_mcp_functions
  ✅ test_mcpd001_bare_decorator_appears_as_tool
  ✅ test_mcpd002_expose_docstring
  ✅ test_mcpd003_custom_name_overrides_function_name
  ✅ test_mcpd004_typed_params_produce_schema
  ✅ test_mcpd005_optional_param_not_required
  ✅ test_mcpd006_return_annotation_becomes_output_schema
  ✅ test_mcpd007_call_returns_result
  ✅ test_mcpd008_call_with_custom_name
  ✅ test_mcpd009_call_error_returns_is_error
tests.integration.mcp.test_mcp_background_tasks
  ✅ test_mcpbg012_trigger_poll_and_retrieve
  ✅ test_mcpbg013_result_expires
  ✅ test_mcpbg014_progress_in_poll_response
  ✅ test_mcpbg015_background_tools_in_tools_list
  ❌ test_mcpbg016_per_callback_manager_lookup
	def test_mcpbg016_per_callback_manager_lookup():
tests.integration.mcp.test_mcp_callback_behavior
  ✅ test_mcpb001_positional_callback
  ✅ test_mcpb002_positional_with_state
  ✅ test_mcpb003_multi_output_positional
  ✅ test_mcpb004_dict_based_inputs_and_state
  ✅ test_mcpb005_dict_based_outputs
  ✅ test_mcpb006_mixed_input_state_in_inputs
  ✅ test_mcpb007_tuple_grouped_inputs
  ✅ test_mcpb008_initial_values_from_chained_callbacks
  ✅ test_mcpb009_dict_based_reordered_state_input
  ✅ test_mcpb010_pattern_matching_callback
  ✅ test_mcpb011_pattern_matching_with_all_wildcard
  ✅ test_mcpb012_pattern_matching_mixed_outputs
  ✅ test_mcpb013_pattern_matching_with_match_wildcard
  ✅ test_mcpb014_pattern_matching_with_allsmaller_wildcard
  ✅ test_mcpb015_prevent_initial_call_uses_layout_default
  ✅ test_mcpb016_initial_callback_overrides_layout_value
  ✅ test_mcpb017_callback_context_triggered_id
  ✅ test_mcpb018_no_output_callback_does_not_crash_tools_list
  ✅ test_mcpb019_duplicate_outputs_both_tools_listed
  ✅ test_mcpb020_duplicate_outputs_both_callable
  ✅ test_mcpb021_duplicate_outputs_find_by_output_returns_primary
  ✅ test_mcpb022_tool_names_within_64_chars
  ✅ test_mcpb023_long_callback_ids_within_64_chars
  ✅ test_mcpb024_pattern_matching_ids_within_64_chars
  ✅ test_mcpb025_duplicate_func_names_produce_unique_tools
  ✅ test_mcpb026_builtin_tools_always_present
  ✅ test_mcpb027_mcp_tool_with_label_and_date_picker_schema
  ✅ test_mcpb028_query_component_returns_structured_output
tests.integration.mcp.test_mcp_endpoint
  ✅ test_mcpe001_post_initialize_returns_protocol_version
  ✅ test_mcpe002_post_tools_list
  ✅ test_mcpe003_notification_returns_202
  ✅ test_mcpe004_delete_returns_405
  ✅ test_mcpe005_get_returns_405
  ✅ test_mcpe006_post_rejects_wrong_content_type
  ✅ test_mcpe007_routes_not_registered_when_disabled
  ✅ test_mcpe008_routes_respect_pathname_prefix
  ✅ test_mcpe009_enable_mcp_env_var_false
  ✅ test_mcpe010_constructor_overrides_env_var
tests.integration.mcp.test_mcp_resources
  ✅ test_mcpz001_resources_list_includes_layout
  ✅ test_mcpz002_read_layout_resource
tests.integration.mcp.test_mcp_session
  ✅ test_mcpse_e2e001_full_session_lifecycle
  ✅ test_mcpse_e2e002_stale_session_recovers_with_notifications
  ✅ test_mcpse_e2e003_capabilities_advertise_list_changed
tests.integration.multi_page.test_pages_layout
  ✅ test_pala001_layout
  ✅ test_pala002_meta_tags_default
  ✅ test_pala003_meta_tags_custom
  ✅ test_pala004_no_layout_exception
  ✅ test_pala005_routing_inputs
  ✅ test_pala006_pages_external_library
  ✅ test_pala007_app_title_discription
tests.integration.multi_page.test_pages_order
  ✅ test_paor001_order
tests.integration.multi_page.test_pages_relative_path
  ✅ test_pare001_relative_path
  ✅ test_pare002_relative_path_with_url_base_pathname
  ✅ test_pare003_absolute_path
tests.integration.renderer.test_add_receive_props
  ✅ test_rdarp001_add_receive_props
tests.integration.renderer.test_array_of_exact_or_shape_with_node_prop_assign_none
  ✅ test_aoeoswnpsn001_array_of_exact_or_shape_with_node_prop_assign_none
tests.integration.renderer.test_benchmarking
  ✅ test_compute_graph_timing[dev_tools0-disabled]
  ✅ test_compute_graph_timing[dev_tools1-enabled]
tests.integration.renderer.test_children_reorder
  ✅ test_roc001_reorder_children
tests.integration.renderer.test_component_as_prop
  ✅ test_rdcap001_component_as_prop
  ✅ test_rdcap002_component_as_props_dynamic_id
  ✅ test_rdcap003_side_effect_regression
  ✅ test_rdcap003_side_effect_regression
  ✅ test_rdcap004_side_effect_same_component
tests.integration.renderer.test_dependencies
  ✅ test_rddp001_dependencies_on_components_that_dont_exist
tests.integration.renderer.test_descendant_listening
  ✅ test_dcl001_descendant_tabs
tests.integration.renderer.test_due_diligence
  ✅ test_rddd001_initial_state
  ✅ test_rddd002_falsy_child[0]
  ✅ test_rddd002_falsy_child[child1]
tests.integration.renderer.test_external_component
  ✅ test_rext001_render_external_component
  ✅ test_rext002_render_external_component_temp
tests.integration.renderer.test_iframe
  ✅ test_rdif001_sandbox_allow_scripts
tests.integration.renderer.test_loading_states
  ✅ test_rdls001_multi_loading_components
  ✅ test_rdls002_chained_loading_states
  ✅ test_rdls003_update_title[kwargs0-Updating...-False]
  ✅ test_rdls003_update_title[kwargs1-Dash-False]
  ✅ test_rdls003_update_title[kwargs2-Dash-False]
  ✅ test_rdls003_update_title[kwargs3-Hello World-False]
  ✅ test_rdls003_update_title[kwargs4-Updating...-True]
  ✅ test_rdls003_update_title[kwargs5-Dash-True]
  ✅ test_rdls003_update_title[kwargs6-Dash-True]
  ✅ test_rdls003_update_title[kwargs7-Hello World-True]
  ✅ test_rdls004_update_title_chained_callbacks[None]
  ✅ test_rdls004_update_title_chained_callbacks[Custom Update Title]
  ✅ test_rdls005_persistent_callback_no_update_title
tests.integration.renderer.test_multi_output
  ✅ test_rdmo001_single_input_multi_outputs_on_multiple_components

✅ test-results/test-main-results-py3.12-group3/junit_intg.xml

107 tests were completed in 292s with 106 passed, 0 failed and 1 skipped.

✅ test-results/test-main-results-py3.8-group1/junit_intg.xml

134 tests were completed in 269s with 132 passed, 0 failed and 2 skipped.

✅ test-results/test-main-results-py3.8-group2/junit_intg.xml

113 tests were completed in 433s with 111 passed, 0 failed and 2 skipped.

✅ test-results/test-main-results-py3.8-group3/junit_intg.xml

97 tests were completed in 248s with 96 passed, 0 failed and 1 skipped.

Annotations

Check failure on line 0 in test-results/background-test-results-py3.12/junit_background.xml

See this annotation in the file changed.

@github-actions github-actions / Test Results Summary

pytest ► bgtests.tests.background_callback.test_basic_long_callback008 ► test_lcbc008_long_callbacks_error[diskcache]

Failed test found in:
  test-results/background-test-results-py3.12/junit_background.xml
Error:
  self = <dash.testing.composite.DashComposite object at 0x7f989243ae70>
Raw output
self = <dash.testing.composite.DashComposite object at 0x7f989243ae70>
method = <function presence_of_element_located.<locals>._predicate at 0x7f989282ede0>
timeout = None
msg = 'timeout 10s => waiting for selector #button:not([disabled])'

    def _wait_for(self, method, timeout, msg):
        """Abstract generic pattern for explicit WebDriverWait."""
        try:
            _wait = (
                self._wd_wait
                if timeout is None
                else WebDriverWait(self.driver, timeout)
            )
            logger.debug(
                "method, timeout, poll => %s %s %s",
                method,
                _wait._timeout,  # pylint: disable=protected-access
                _wait._poll,  # pylint: disable=protected-access
            )
    
>           return _wait.until(method)
                   ^^^^^^^^^^^^^^^^^^^

/opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/dash/testing/browser.py:287: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.support.wait.WebDriverWait (session="721b313d8174ae7cd06f8b78f89200c2")>
method = <function presence_of_element_located.<locals>._predicate at 0x7f989282ede0>
message = ''

    def until(self, method, message=''):
        """Calls the method provided with the driver as an argument until the \
        return value does not evaluate to ``False``.
    
        :param method: callable(WebDriver)
        :param message: optional message for :exc:`TimeoutException`
        :returns: the result of the last call to `method`
        :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs
        """
        screen = None
        stacktrace = None
    
        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, 'screen', None)
                stacktrace = getattr(exc, 'stacktrace', None)
            time.sleep(self._poll)
            if time.monotonic() > end_time:
                break
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message: 
E       Stacktrace:
E       #0 0x55a84290ab6a <unknown>
E       #1 0x55a84230c265 <unknown>
E       #2 0x55a84235ef76 <unknown>
E       #3 0x55a84235f1b1 <unknown>
E       #4 0x55a8423aa7d4 <unknown>
E       #5 0x55a8423a7969 <unknown>
E       #6 0x55a8423525cf <unknown>
E       #7 0x55a842353391 <unknown>
E       #8 0x55a8428d004b <unknown>
E       #9 0x55a8428d300d <unknown>
E       #10 0x55a8428bc808 <unknown>
E       #11 0x55a8428d3ba0 <unknown>
E       #12 0x55a8428a3280 <unknown>
E       #13 0x55a8428f7db8 <unknown>
E       #14 0x55a8428f7f88 <unknown>
E       #15 0x55a8429095de <unknown>
E       #16 0x7fdd47a9caa4 <unknown>
E       #17 0x7fdd47b29c6c <unknown>

/opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/selenium/webdriver/support/wait.py:87: TimeoutException

The above exception was the direct cause of the following exception:

dash_duo = <dash.testing.composite.DashComposite object at 0x7f989243ae70>
manager = 'diskcache'

    @pytest.mark.skipif(
        sys.version_info < (3, 7), reason="Python 3.6 long callbacks tests hangs up"
    )
    def test_lcbc008_long_callbacks_error(dash_duo, manager):
        with setup_background_callback_app(manager, "app_error") as app:
            dash_duo.start_server(
                app,
                debug=True,
                use_reloader=False,
                use_debugger=True,
                dev_tools_hot_reload=False,
                dev_tools_ui=True,
            )
    
            clicker = dash_duo.wait_for_element("#button")
    
            def click_n_wait():
                clicker.click()
                dash_duo.wait_for_element("#button:disabled")
                dash_duo.wait_for_element("#button:not([disabled])")
    
            clicker.click()
            dash_duo.wait_for_text_to_equal("#output", "Clicked 1 times")
    
            click_n_wait()
            dash_duo.wait_for_element(".dash-fe-error__title").click()
    
            dash_duo.driver.switch_to.frame(dash_duo.find_element("iframe"))
            assert (
                "dash.exceptions.BackgroundCallbackError: "
                "An error occurred inside a background callback:"
                in dash_duo.wait_for_element(".errormsg").text
            )
            dash_duo.driver.switch_to.default_content()
    
>           click_n_wait()

tests/background_callback/test_basic_long_callback008.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/background_callback/test_basic_long_callback008.py:27: in click_n_wait
    dash_duo.wait_for_element("#button:not([disabled])")
/opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/dash/testing/browser.py:298: in wait_for_element
    return self.wait_for_element_by_css_selector(selector, timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/dash/testing/browser.py:304: in wait_for_element_by_css_selector
    return self._wait_for(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <dash.testing.composite.DashComposite object at 0x7f989243ae70>
method = <function presence_of_element_located.<locals>._predicate at 0x7f989282ede0>
timeout = None
msg = 'timeout 10s => waiting for selector #button:not([disabled])'

    def _wait_for(self, method, timeout, msg):
        """Abstract generic pattern for explicit WebDriverWait."""
        try:
            _wait = (
                self._wd_wait
                if timeout is None
                else WebDriverWait(self.driver, timeout)
            )
            logger.debug(
                "method, timeout, poll => %s %s %s",
                method,
                _wait._timeout,  # pylint: disable=protected-access
                _wait._poll,  # pylint: disable=protected-access
            )
    
            return _wait.until(method)
        except Exception as err:
            if callable(msg):
                message = msg(self.driver)
            else:
                message = msg
>           raise TimeoutException(str(message)) from err
E           selenium.common.exceptions.TimeoutException: Message: timeout 10s => waiting for selector #button:not([disabled])

/opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/dash/testing/browser.py:293: TimeoutException

Check failure on line 0 in test-results/test-main-results-py3.12-group2/junit_intg.xml

See this annotation in the file changed.

@github-actions github-actions / Test Results Summary

pytest ► tests.integration.mcp.test_mcp_background_tasks ► test_mcpbg016_per_callback_manager_lookup

Failed test found in:
  test-results/test-main-results-py3.12-group2/junit_intg.xml
Error:
  def test_mcpbg016_per_callback_manager_lookup():
Raw output
def test_mcpbg016_per_callback_manager_lookup():
        """``tasks/get`` uses the manager attached to the specific callback."""
        manager_a = DiskcacheManager(diskcache.Cache())
        manager_b = DiskcacheManager(diskcache.Cache())
    
        app = Dash(__name__)
        app.layout = html.Div(
            [
                html.Div(id="input_a"),
                html.Div(id="output_a"),
                html.Div(id="input_b"),
                html.Div(id="output_b"),
            ]
        )
    
        @app.callback(
            Output("output_a", "children"),
            Input("input_a", "children"),
            background=True,
            manager=manager_a,
        )
        def callback_a(value):
            time.sleep(0.5)
            return f"a: {value}"
    
        @app.callback(
            Output("output_b", "children"),
            Input("input_b", "children"),
            background=True,
            manager=manager_b,
        )
        def callback_b(value):
            time.sleep(0.5)
            return f"b: {value}"
    
        client = app.server.test_client()
    
        r = _post(
            client,
            "tools/call",
            {"name": "callback_b", "arguments": {"value": "hello"}},
        )
        assert r.status_code == 200
        task_info = json.loads(json.loads(r.data)["result"]["content"][0]["text"])
        task_id = task_info["taskId"]
        cache_key = task_id.split(":")[2]
    
        deadline = time.time() + 5
        while time.time() < deadline:
            if manager_b.result_ready(cache_key):
                break
            time.sleep(0.1)
    
        assert manager_b.result_ready(cache_key)
        assert not manager_a.result_ready(cache_key)
    
        r = _post(client, "tasks/get", {"taskId": task_id}, request_id=2)
        assert r.status_code == 200
>       assert json.loads(r.data)["result"]["status"] == "completed"
E       AssertionError: assert 'working' == 'completed'
E         
E         - completed
E         + working

tests/integration/mcp/test_mcp_background_tasks.py:326: AssertionError