Skip to content

Commit f411b12

Browse files
committed
add Authorization for mcp endpoint
1 parent db33d77 commit f411b12

File tree

6 files changed

+67
-1
lines changed

6 files changed

+67
-1
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,16 @@ The app's input schema must define its input parameters. For a chat dify app, en
4848
### 4. enjoy it!
4949
![5](./_assets/5.png)
5050

51+
### 5. To keep your data secure, you can add a `Auth Bearer Token` on the endpoint setting.
52+
53+
For example, if your `Auth Bearer Token` is setting to `sk-abcdefgh`, then the request header of MCP client must add `Authorization: Bearer sk-abcdefgh`
54+
5155

5256
## Changelog
5357

5458
### 0.0.4
5559
- Add response to the `ping` method of MCP client, some clients use this method to check server health
60+
- Add `Authorization: Bearer` token validator
5661

5762
### 0.0.3
5863
- To fix sse get non-exist key get lots error logs on the plugin daemon.

endpoints/auth.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import json
2+
from typing import Mapping, Optional
3+
4+
from werkzeug import Request, Response
5+
6+
def validate_bearer_token(r: Request, settings: Mapping) -> Optional[Response]:
7+
"""
8+
Validates the bearer token from the request.
9+
Returns a Response object if validation fails, otherwise None.
10+
"""
11+
if settings.get("auth-token"):
12+
auth_header = r.headers.get("Authorization")
13+
token = None
14+
if auth_header and auth_header.startswith("Bearer "):
15+
token = auth_header.removeprefix("Bearer ").strip()
16+
17+
if settings.get("auth-token") != token:
18+
req_id = r.json.get("id") if r.is_json else None
19+
error_response = {
20+
"jsonrpc": "2.0",
21+
"id": req_id,
22+
"error": {"code": -32000, "message": "Invalid or missing token"},
23+
}
24+
return Response(
25+
json.dumps(error_response),
26+
status=401,
27+
content_type="application/json",
28+
)
29+
return None

endpoints/http_post.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from dify_plugin import Endpoint
88
from dify_plugin.config.logger_format import plugin_logger_handler
99

10+
from .auth import validate_bearer_token
11+
1012
logger = logging.getLogger(__name__)
1113
logger.setLevel(logging.INFO)
1214
logger.addHandler(plugin_logger_handler)
@@ -23,6 +25,11 @@ def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response:
2325
"""
2426
logger.info(f"HTTPPostEndpoint request headers: {r.headers}")
2527
logger.info(f"HTTPPostEndpoint request json: {r.json}")
28+
29+
auth_error = validate_bearer_token(r, settings)
30+
if auth_error:
31+
return auth_error
32+
2633
app_id = settings.get("app").get("app_id")
2734
try:
2835
tool = json.loads(settings.get("app-input-schema"))

endpoints/messages.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
from dify_plugin import Endpoint
66
from dify_plugin.config.logger_format import plugin_logger_handler
77

8+
from .auth import validate_bearer_token
9+
810
logger = logging.getLogger(__name__)
911
logger.setLevel(logging.INFO)
1012
logger.addHandler(plugin_logger_handler)
@@ -17,6 +19,11 @@ def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response:
1719
"""
1820
logger.info(f"MessageEndpoint request headers: {r.headers}")
1921
logger.info(f"MessageEndpoint request json: {r.json}")
22+
23+
auth_error = validate_bearer_token(r, settings)
24+
if auth_error:
25+
return auth_error
26+
2027
app_id = settings.get("app").get("app_id")
2128
try:
2229
tool = json.loads(settings.get("app-input-schema"))
@@ -49,7 +56,7 @@ def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response:
4956
"id": data.get("id"),
5057
"result": {},
5158
}
52-
59+
5360
elif data.get("method") == "notifications/initialized":
5461
return Response("", status=202, content_type="application/json")
5562

endpoints/sse.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from dify_plugin import Endpoint
99
from dify_plugin.config.logger_format import plugin_logger_handler
1010

11+
from .auth import validate_bearer_token
12+
1113
logger = logging.getLogger(__name__)
1214
logger.setLevel(logging.INFO)
1315
logger.addHandler(plugin_logger_handler)
@@ -22,6 +24,11 @@ def _invoke(self, r: Request, values: Mapping, settings: Mapping) -> Response:
2224
Invokes the endpoint with the given request.
2325
"""
2426
logger.info(f"SSEEndpoint request headers: {r.headers}")
27+
28+
auth_error = validate_bearer_token(r, settings)
29+
if auth_error:
30+
return auth_error
31+
2532
session_id = str(uuid.uuid4()).replace("-", "")
2633

2734
def generate():

group/mcp-server.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ settings:
1313
required: true
1414
label:
1515
en_US: App Type
16+
zh_Hans: 应用类型
1617
options:
1718
- label:
1819
en_US: Chat
@@ -25,9 +26,19 @@ settings:
2526
required: true
2627
label:
2728
en_US: App Input Schema
29+
zh_Hans: 应用输入 schema
2830
placeholder:
2931
en_US: the json format of your app input schema
3032
zh_Hans: 请输入应用所需输入的 json 格式
33+
- name: auth-token
34+
type: secret-input
35+
required: false
36+
label:
37+
en_US: Auth Bearer Token
38+
zh_Hans: 认证Bearer token
39+
placeholder:
40+
en_US: the auth Bearer token of your app, if not provided, the app will not validate
41+
zh_Hans: 请输入应用的认证Bearer token,如果未提供,应用将不验证
3142
endpoints:
3243
- endpoints/sse.yaml
3344
- endpoints/messages.yaml

0 commit comments

Comments
 (0)