Skip to content

Commit dc13fc0

Browse files
authored
feat: add mcp support (#1964) (#1977)
* feat: add mcp support * chore: split mcp button component * feat: persist mcps in localstorage & reconnect * feat: add copy button for mcp command/url * feat: add mcp reconnect button
1 parent 764863c commit dc13fc0

File tree

42 files changed

+1679
-1331
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1679
-1331
lines changed

.github/actions/poetry-python-install/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ inputs:
55
python-version:
66
description: Python version
77
required: true
8-
default: '3.9'
8+
default: '3.10'
99
poetry-version:
1010
description: Poetry version
1111
required: true

.github/workflows/pytest.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
python-version: ['3.9', '3.10', '3.11', '3.12']
12+
python-version: ['3.10', '3.11', '3.12']
1313
fastapi-version: ['0.115']
1414
env:
1515
BACKEND_DIR: ./backend

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to Chainlit will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

7+
## [2.4.0rc0] - 2025-03-09
8+
9+
### Added
10+
11+
- MCP support through `@cl.on_mcp_connect` and `@cl.on_mcp_disconnect`
12+
713
## [2.3.0] - 2025-03-09
814

915
### Added

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ I've copy/pasted the whole document there, and then formatted it with prettier.
2525

2626
### Requirements
2727

28-
1. Python >= `3.9`
28+
1. Python >= `3.10`
2929
2. Poetry ([See how to install](https://python-poetry.org/docs/#installation))
3030
3. NodeJS >= `16` ([See how to install](https://nodejs.org/en/download))
3131
4. Pnpm ([See how to install](https://pnpm.io/installation))

backend/chainlit/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
on_chat_resume,
6868
on_chat_start,
6969
on_logout,
70+
on_mcp_connect,
71+
on_mcp_disconnect,
7072
on_message,
7173
on_settings_update,
7274
on_stop,
@@ -78,7 +80,6 @@
7880
)
7981

8082
if TYPE_CHECKING:
81-
from chainlit.haystack.callbacks import HaystackAgentCallbackHandler
8283
from chainlit.langchain.callbacks import (
8384
AsyncLangchainCallbackHandler,
8485
LangchainCallbackHandler,
@@ -111,7 +112,6 @@ def acall(self):
111112
"LangchainCallbackHandler": "chainlit.langchain.callbacks",
112113
"AsyncLangchainCallbackHandler": "chainlit.langchain.callbacks",
113114
"LlamaIndexCallbackHandler": "chainlit.llama_index.callbacks",
114-
"HaystackAgentCallbackHandler": "chainlit.haystack.callbacks",
115115
"instrument_openai": "chainlit.openai",
116116
"instrument_mistralai": "chainlit.mistralai",
117117
}
@@ -135,7 +135,6 @@ def acall(self):
135135
"ErrorMessage",
136136
"File",
137137
"GenerationMessage",
138-
"HaystackAgentCallbackHandler",
139138
"Image",
140139
"InputAudioChunk",
141140
"LangchainCallbackHandler",
@@ -174,6 +173,8 @@ def acall(self):
174173
"on_chat_resume",
175174
"on_chat_start",
176175
"on_logout",
176+
"on_mcp_connect",
177+
"on_mcp_disconnect",
177178
"on_message",
178179
"on_settings_update",
179180
"on_stop",

backend/chainlit/auth/jwt.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ def create_jwt(data: User) -> str:
2929

3030

3131
def decode_jwt(token: str) -> User:
32+
secret = get_jwt_secret()
33+
assert secret
34+
3235
dict = pyjwt.decode(
3336
token,
34-
get_jwt_secret(),
37+
secret,
3538
algorithms=["HS256"],
3639
options={"verify_signature": True},
3740
)

backend/chainlit/callbacks.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
from typing import Any, Awaitable, Callable, Dict, List, Optional
33

44
from fastapi import Request, Response
5+
from mcp import ClientSession
56
from starlette.datastructures import Headers
67

78
from chainlit.action import Action
89
from chainlit.config import config
910
from chainlit.context import context
1011
from chainlit.data.base import BaseDataLayer
12+
from chainlit.mcp import McpConnection
1113
from chainlit.message import Message
1214
from chainlit.oauth_providers import get_configured_oauth_providers
1315
from chainlit.step import Step, step
@@ -300,6 +302,26 @@ def author_rename(
300302
return func
301303

302304

305+
@trace
306+
def on_mcp_connect(func: Callable[[McpConnection, ClientSession], None]) -> Callable:
307+
"""
308+
Called everytime an MCP is connected
309+
"""
310+
311+
config.code.on_mcp_connect = wrap_user_function(func)
312+
return func
313+
314+
315+
@trace
316+
def on_mcp_disconnect(func: Callable[[str, ClientSession], None]) -> Callable:
317+
"""
318+
Called everytime an MCP is disconnected
319+
"""
320+
321+
config.code.on_mcp_disconnect = wrap_user_function(func)
322+
return func
323+
324+
303325
@trace
304326
def on_stop(func: Callable) -> Callable:
305327
"""

backend/chainlit/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ class AudioFeature(DataClassJsonMixin):
214214
class FeaturesSettings(DataClassJsonMixin):
215215
spontaneous_file_upload: Optional[SpontaneousFileUploadFeature] = None
216216
audio: Optional[AudioFeature] = Field(default_factory=AudioFeature)
217+
mcp: bool = False
217218
latex: bool = False
218219
unsafe_allow_html: bool = False
219220
auto_tag_thread: bool = True
@@ -273,6 +274,8 @@ class CodeSettings:
273274
on_audio_start: Optional[Callable[[], Any]] = None
274275
on_audio_chunk: Optional[Callable[["InputAudioChunk"], Any]] = None
275276
on_audio_end: Optional[Callable[[], Any]] = None
277+
on_mcp_connect: Optional[Callable] = None
278+
on_mcp_disconnect: Optional[Callable] = None
276279

277280
author_rename: Optional[Callable[[str], Awaitable[str]]] = None
278281
on_settings_update: Optional[Callable[[Dict[str, Any]], Any]] = None
@@ -297,7 +300,7 @@ class ProjectSettings(DataClassJsonMixin):
297300
lc_cache_path: Optional[str] = None
298301
# Path to the local chat db
299302
# Duration (in seconds) during which the session is saved when the connection is lost
300-
session_timeout: int = 3600
303+
session_timeout: int = 300
301304
# Duration (in seconds) of the user session expiry
302305
user_session_timeout: int = 1296000 # 15 days
303306
# Enable third parties caching (e.g LangChain cache)

backend/chainlit/discord/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ async def process_discord_message(
292292
except Exception as e:
293293
logger.error(f"Error updating thread: {e}")
294294

295-
ctx.session.delete()
295+
await ctx.session.delete()
296296

297297

298298
@client.event

backend/chainlit/haystack/__init__.py

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)