Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
882586b
Add layout traversal utilities for Dash component trees
KoolADE85 Apr 1, 2026
4d55ef8
Make Dash components compatible with Pydantic types
KoolADE85 Apr 1, 2026
998d8d7
Extract get_layout() from serve_layout()
KoolADE85 Apr 1, 2026
66eda33
Fix build issues for dash-table and dash-core-components
KoolADE85 Apr 1, 2026
0cdb67a
Add CallbackDispatchBody type hints to dispatch methods
KoolADE85 Apr 1, 2026
b64c3fe
Use python3.8 compatible pydantic
KoolADE85 Apr 1, 2026
a85aa6c
lint
KoolADE85 Apr 1, 2026
4ecaf7d
Fix lint error on CI
KoolADE85 Apr 1, 2026
069b049
Rename layout.py to _layout_utils.py
KoolADE85 Apr 6, 2026
d684507
Make NumberType import backwards-compatible in generated components
KoolADE85 Apr 6, 2026
17a7541
Fix type checker for NumberType implementation
KoolADE85 Apr 6, 2026
dc35bff
Clean up import for pyright
KoolADE85 Apr 7, 2026
00eb203
Add callback adapter core for MCP tool generation
KoolADE85 Apr 1, 2026
fcfa765
Fix type errors
KoolADE85 Apr 1, 2026
8c89d51
Fix import path
KoolADE85 Apr 6, 2026
eeadb7f
tighten up types used around callbacks
KoolADE85 Apr 13, 2026
5b09f99
Remove redundant error code
KoolADE85 Apr 13, 2026
fa99ab0
lint
KoolADE85 Apr 14, 2026
cd1f4d4
Add MCP resource providers for layout, components, pages, and clients…
KoolADE85 Apr 1, 2026
2f00c0e
Fix import path
KoolADE85 Apr 6, 2026
5e472b2
Implement base class for each resource type
KoolADE85 Apr 13, 2026
f8d9739
lint
KoolADE85 Apr 16, 2026
6d4e2a0
Fix pylint errors
KoolADE85 Apr 22, 2026
ef1ea3f
Implement callbacks as tools with rich input/output schema and descri…
KoolADE85 Apr 1, 2026
9060647
Refactor description sources to accept CallbackAdapter instances
KoolADE85 Apr 8, 2026
554ddc0
Fix pylint error
KoolADE85 Apr 8, 2026
2cfa193
Fix regression in CallbackAdapter
KoolADE85 Apr 16, 2026
dce8e9a
Refactor tool descriptions/schemas to use a base class (just as resou…
KoolADE85 Apr 16, 2026
e29cb9c
Disable docstrings by default in MCP tool descriptions
KoolADE85 Apr 21, 2026
991dfa5
lint
KoolADE85 Apr 22, 2026
4d7411c
Move all hard-coded text into a `prop_roles.py` file where it can be …
KoolADE85 Apr 24, 2026
b357495
Add pattern-matching callback support to input schemas and descriptions
KoolADE85 Apr 1, 2026
6906b3d
clean up duplicated code
KoolADE85 Apr 16, 2026
6a52dba
Refactor unit tests to conform to existing test patterns
KoolADE85 Apr 23, 2026
7ce9939
Add result formatters for Plotly figures and tabular data
KoolADE85 Apr 1, 2026
acf75a0
Update type names
KoolADE85 Apr 16, 2026
d01d43a
Refactor tool result formatters to use a base class (just as resource…
KoolADE85 Apr 16, 2026
92cf27b
lint
KoolADE85 Apr 16, 2026
13d0fbf
Make import top-level
KoolADE85 Apr 22, 2026
ef8fc34
Refactor unit tests to conform to existing test patterns
KoolADE85 Apr 23, 2026
88589cb
Use TABULAR/PLOTLY_FIGURE PropRole.matches() in formatters
KoolADE85 Apr 30, 2026
55f6514
Tighten formatter types: required-field access + plotly stub ignore
KoolADE85 Apr 30, 2026
0be83d3
code review feedback
KoolADE85 May 8, 2026
bcc86c8
Add get_dash_component tool and callback tool dispatch pipeline
KoolADE85 Apr 1, 2026
a95b3bf
Refactor tools to use a base class (just as resources do)
KoolADE85 Apr 16, 2026
9e4cc2c
lint
KoolADE85 Apr 16, 2026
c079065
Refactor unit tests to conform to existing test patterns
KoolADE85 Apr 23, 2026
9988753
Implement a mapping of "id+prop" to callbacks that are outputs/inputs…
KoolADE85 May 8, 2026
c2f06ae
Code review feedback
KoolADE85 May 8, 2026
34a4d98
Make run_callback compatible with 4.2.0 changes
KoolADE85 May 12, 2026
227eeed
Wire MCP server, SSE transport, and Dash app integration
KoolADE85 Apr 1, 2026
001a7b7
Enforce session management per MCP spec (404 for unknown sessions, 40…
KoolADE85 Apr 9, 2026
3fe035b
remove unused code
KoolADE85 Apr 15, 2026
3b44944
Fix types for mypy
KoolADE85 Apr 17, 2026
9dc1f10
Remove unused SSE code for initial MCP implementation
KoolADE85 Apr 20, 2026
f640328
add app-level config for exposing callback docstrings in MCP tools
KoolADE85 Apr 21, 2026
d108faf
Disable MCP server by default
KoolADE85 Apr 21, 2026
eb94e14
lint
KoolADE85 Apr 22, 2026
fdaf822
fix leaky state in tests
KoolADE85 Apr 23, 2026
bfc61f2
Refactor unit tests to conform to existing test patterns
KoolADE85 Apr 23, 2026
8c7d720
Add decorator to make any function mcp-enabled
KoolADE85 May 4, 2026
4f7329c
Notify connected agents of server restarts and hot-reloads so they ca…
KoolADE85 May 8, 2026
cf8e9d9
Migrate MCP server to use v4.2.0 backend abstractions
KoolADE85 May 13, 2026
6c3fec8
Fix async (Quart) route registration
KoolADE85 May 13, 2026
5e47755
Fix session management with multiple workers
KoolADE85 May 13, 2026
9566de0
Fix CI errors after rebase
KoolADE85 May 13, 2026
296b7ac
code review feedback
KoolADE85 May 14, 2026
15f2111
Implement background callback support
KoolADE85 Apr 8, 2026
ee4e48c
Ensure that background callback expiry is communicated in MCP tool
KoolADE85 Apr 8, 2026
bf442f7
lint
KoolADE85 Apr 30, 2026
576145c
Install diskcache extra in lint-unit and typing CI jobs
KoolADE85 May 8, 2026
0fef9b8
Fix mypy errors in CI
KoolADE85 May 8, 2026
fd8c8d9
Fix bug storing metadata on background callbacks
KoolADE85 May 12, 2026
3cc14d8
Enable programmatic querying of background callback status/result; re…
KoolADE85 May 13, 2026
9d5fa61
Fix get_task status race and CallbackExecutionResponse type annotation
robertclaus May 15, 2026
ef778a2
code review feedback
KoolADE85 May 19, 2026
b78fe2a
Revert match/case refactor due to compatibility problems
KoolADE85 May 20, 2026
16da30a
automatically load env vars with direnv
KoolADE85 May 20, 2026
1861302
bump version and changelog
KoolADE85 May 21, 2026
3558bd3
changelog
KoolADE85 May 21, 2026
3aed371
Merge pull request #3793 from plotly/release/4.3.0rc0
KoolADE85 May 21, 2026
f1ec286
Merge remote-tracking branch 'origin/dev' into mcp
KoolADE85 Jun 2, 2026
d04009c
Implement configuration function to customize MCP server
KoolADE85 May 26, 2026
17f67ec
Fix CI test
KoolADE85 Jun 1, 2026
52b2858
Fix @mcp_enabled decorator not working if defined after the app const…
KoolADE85 Jun 1, 2026
c5c4829
Address PR feedback
KoolADE85 Jun 3, 2026
28fd89d
Merge pull request #3796 from plotly/feature/mcp-configuration-function
KoolADE85 Jun 3, 2026
63e61d1
Merge remote-tracking branch 'origin/dev' into mcp
KoolADE85 Jun 3, 2026
0966b07
Merge branch 'dev' into mcp
KoolADE85 Jun 17, 2026
b14961f
Fix claude code connectivity timeouts
KoolADE85 Jun 18, 2026
664efdd
attempt fix on table test
KoolADE85 Jun 18, 2026
c793778
changelog
KoolADE85 Jun 18, 2026
b39255a
Merge remote-tracking branch 'origin/mcp' into bugfix/claude-mcp-time…
KoolADE85 Jun 18, 2026
f62582c
Merge pull request #3830 from plotly/bugfix/claude-mcp-timeouts
KoolADE85 Jun 18, 2026
ff4d66d
Merge remote-tracking branch 'origin/dev' into mcp
KoolADE85 Jun 18, 2026
7fe7a32
Fix failing mcp test
KoolADE85 Jun 18, 2026
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
Prev Previous commit
Next Next commit
lint
  • Loading branch information
KoolADE85 committed May 20, 2026
commit bf442f789362ed7e251859affe82ff83c99e55d8
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from typing import TYPE_CHECKING

from ..tool_background_tasks import GET_RESULT_TOOL_NAME
from .base import ToolDescriptionSource

if TYPE_CHECKING:
Expand All @@ -19,9 +20,9 @@ class BackgroundCallbackDescription(ToolDescriptionSource):

@classmethod
def describe(cls, callback: CallbackAdapter) -> list[str]:
# pylint: disable-next=protected-access
if not callback._cb_info.get("background"):
return []
from ..tool_background_tasks import GET_RESULT_TOOL_NAME

return [
"",
Expand Down
34 changes: 20 additions & 14 deletions dash/mcp/primitives/tools/results/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@
from __future__ import annotations

import json
from typing import Any
from typing import TYPE_CHECKING, Any

from mcp.types import CallToolResult, CreateTaskResult, TextContent

from dash.types import CallbackExecutionResponse
from dash.mcp.primitives.tools.callback_adapter import CallbackAdapter

from .base import ResultFormatter
from .result_dataframe import DataFrameResult
from .result_plotly_figure import PlotlyFigureResult

if TYPE_CHECKING:
from dash.mcp.primitives.tools.callback_adapter import CallbackAdapter

_RESULT_FORMATTERS: list[type[ResultFormatter]] = [
PlotlyFigureResult,
DataFrameResult,
Expand Down Expand Up @@ -61,17 +63,21 @@ def task_result_to_tool_result(create_task_result: CreateTaskResult) -> CallTool
"""
task = create_task_result.task
return CallToolResult(
content=[TextContent(
type="text",
text=json.dumps({
"taskId": task.taskId,
"status": task.status,
"pollInterval": task.pollInterval,
"message": (
"This is a long-running background callback. "
"Call the get_background_task_result tool with this taskId "
"to poll for the result."
content=[
TextContent(
type="text",
text=json.dumps(
{
"taskId": task.taskId,
"status": task.status,
"pollInterval": task.pollInterval,
"message": (
"This is a long-running background callback. "
"Call the get_background_task_result tool with this taskId "
"to poll for the result."
),
}
),
}),
)],
)
],
)
5 changes: 1 addition & 4 deletions dash/mcp/primitives/tools/tool_background_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@


def _has_background_callbacks() -> bool:
return any(
cb_info.get("background")
for cb_info in get_app().callback_map.values()
)
return any(cb_info.get("background") for cb_info in get_app().callback_map.values())


class BackgroundTaskTools(MCPToolProvider):
Expand Down
1 change: 1 addition & 0 deletions dash/mcp/primitives/tools/tools_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def call_tool(
" Please call tools/list to refresh your tool list."
)

# pylint: disable-next=protected-access
is_background = bool(cb._cb_info.get("background"))

try:
Expand Down
16 changes: 10 additions & 6 deletions dash/mcp/tasks/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from datetime import datetime, timezone
from typing import Any

from mcp.types import CreateTaskResult, GetTaskResult, Task
from mcp.types import CancelTaskResult, CreateTaskResult, GetTaskResult, Task

from dash import get_app
from dash.mcp.primitives.tools.results import format_callback_response
Expand All @@ -33,6 +33,7 @@ def create_task(dispatch_response: dict[str, Any], callback) -> CreateTaskResult
cache_key = dispatch_response["cacheKey"]
job_id = str(dispatch_response["job"])
task_id = f"{callback.tool_name}:{job_id}:{cache_key}"
# pylint: disable-next=protected-access
interval = callback._cb_info.get("background", {}).get("interval", 1000)
now = datetime.now(timezone.utc)
return CreateTaskResult(
Expand Down Expand Up @@ -75,14 +76,17 @@ def get_task(task_id: str) -> GetTaskResult:
adapter = get_app().mcp_callback_map.find_by_tool_name(tool_name)
interval = None
if adapter is not None:
# pylint: disable-next=protected-access
interval = adapter._cb_info.get("background", {}).get("interval", 1000)

now = datetime.now(timezone.utc)
return GetTaskResult(
taskId=task_id,
status=status,
statusMessage=str(progress) if progress else None,
createdAt=datetime.fromisoformat(manager.handle.get(f"{cache_key}-created_at") or now.isoformat()),
createdAt=datetime.fromisoformat(
manager.handle.get(f"{cache_key}-created_at") or now.isoformat()
),
lastUpdatedAt=now,
ttl=manager.expire * 1000 if manager.expire else None,
pollInterval=interval,
Expand Down Expand Up @@ -117,7 +121,9 @@ def get_task_result(task_id: str) -> Any:
response_data = json.loads(response.get_data(as_text=True))

if "response" not in response_data:
raise MCPError("Task result not ready. Poll tasks/get until status is 'completed'.")
raise MCPError(
"Task result not ready. Poll tasks/get until status is 'completed'."
)

return format_callback_response(response_data, adapter)

Expand All @@ -127,9 +133,7 @@ def cancel_task(task_id: str) -> Any:

Same underlying mechanism as the renderer's cancelJob query param.
"""
from mcp.types import CancelTaskResult

tool_name, job_id, cache_key = parse_task_id(task_id)
_tool_name, job_id, cache_key = parse_task_id(task_id)

manager = _get_callback_manager()
if manager is None:
Expand Down