mseep-dify-mcp-server 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: mseep-dify-mcp-server
3
+ Version: 0.1.4
4
+ Summary: Add your description here
5
+ Home-page:
6
+ Author: mseep
7
+ Author-email: support@skydeck.ai
8
+ Maintainer: mseep
9
+ Maintainer-email: support@skydeck.ai
10
+ Keywords: mseep
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.6
15
+ Description-Content-Type: text/plain
16
+ Requires-Dist: httpx>=0.28.1
17
+ Requires-Dist: mcp>=1.1.2
18
+ Requires-Dist: omegaconf>=2.3.0
19
+ Requires-Dist: pip>=24.3.1
20
+ Requires-Dist: python-dotenv>=1.0.1
21
+ Requires-Dist: requests
22
+ Dynamic: author
23
+ Dynamic: author-email
24
+ Dynamic: classifier
25
+ Dynamic: description
26
+ Dynamic: description-content-type
27
+ Dynamic: keywords
28
+ Dynamic: maintainer
29
+ Dynamic: maintainer-email
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
33
+
34
+ Package managed by MseeP.ai
@@ -0,0 +1,4 @@
1
+ mseep_dify_mcp_server-0.1.4.dist-info/METADATA,sha256=DVsH-aOy8AuLNuYWu7RXeGyrPWxqKR5HkwlQvtedPAU,881
2
+ mseep_dify_mcp_server-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
3
+ mseep_dify_mcp_server-0.1.4.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
4
+ mseep_dify_mcp_server-0.1.4.dist-info/RECORD,,
@@ -1,4 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
+
@@ -1,9 +0,0 @@
1
- from . import server
2
- import asyncio
3
-
4
- def main():
5
- """Main entry point for the package."""
6
- asyncio.run(server.main())
7
-
8
- # Optionally expose other important items at package level
9
- __all__ = ['main', 'server']
dify_mcp_server/server.py DELETED
@@ -1,281 +0,0 @@
1
- import asyncio
2
- import json
3
- import os
4
- from abc import ABC
5
-
6
- import mcp.server.stdio
7
- import mcp.types as types
8
- import requests
9
- from mcp.server import NotificationOptions, Server
10
- from mcp.server.models import InitializationOptions
11
- from omegaconf import OmegaConf
12
-
13
-
14
- def get_app_info():
15
- config_path = os.getenv("CONFIG_PATH")
16
- base_url = os.getenv("DIFY_BASE_URL")
17
- dify_app_sks = os.getenv("DIFY_APP_SKS")
18
- if config_path is not None:
19
- print(f"Loading config from {config_path}")
20
- config = OmegaConf.load(config_path)
21
- dify_base_url = config.get('dify_base_url', "https://api.dify.ai/v1")
22
- dify_app_sks = config.get('dify_app_sks', [])
23
- return dify_base_url, dify_app_sks
24
- elif base_url is not None and dify_app_sks is not None:
25
- print(f"Loading config from env variables")
26
- dify_base_url = base_url
27
- dify_app_sks = dify_app_sks.split(",")
28
- return dify_base_url, dify_app_sks
29
-
30
- class DifyAPI(ABC):
31
- def __init__(self,
32
- base_url: str,
33
- dify_app_sks: list,
34
- user="default_user"):
35
- # dify configs
36
- self.dify_base_url = base_url
37
- self.dify_app_sks = dify_app_sks
38
- self.user = user
39
-
40
- # dify app infos
41
- dify_app_infos = []
42
- dify_app_params = []
43
- dify_app_metas = []
44
- for key in self.dify_app_sks:
45
- dify_app_infos.append(self.get_app_info(key))
46
- dify_app_params.append(self.get_app_parameters(key))
47
- dify_app_metas.append(self.get_app_meta(key))
48
- self.dify_app_infos = dify_app_infos
49
- self.dify_app_params = dify_app_params
50
- self.dify_app_metas = dify_app_metas
51
- self.dify_app_names = [x['name'] for x in dify_app_infos]
52
-
53
- def chat_message(
54
- self,
55
- api_key,
56
- inputs={},
57
- response_mode="streaming",
58
- conversation_id=None,
59
- user="default_user",
60
- files=None,):
61
- url = f"{self.dify_base_url}/workflows/run"
62
- headers = {
63
- "Authorization": f"Bearer {api_key}",
64
- "Content-Type": "application/json"
65
- }
66
- data = {
67
- "inputs": inputs,
68
- "response_mode": response_mode,
69
- "user": user,
70
- }
71
- if conversation_id:
72
- data["conversation_id"] = conversation_id
73
- if files:
74
- files_data = []
75
- for file_info in files:
76
- file_path = file_info.get('path')
77
- transfer_method = file_info.get('transfer_method')
78
- if transfer_method == 'local_file':
79
- files_data.append(('file', open(file_path, 'rb')))
80
- elif transfer_method == 'remote_url':
81
- pass
82
- response = requests.post(
83
- url, headers=headers, data=data, files=files_data, stream=response_mode == "streaming")
84
- else:
85
- response = requests.post(
86
- url, headers=headers, json=data, stream=response_mode == "streaming")
87
- response.raise_for_status()
88
- if response_mode == "streaming":
89
- for line in response.iter_lines():
90
- if line:
91
- if line.startswith(b'data:'):
92
- try:
93
- json_data = json.loads(line[5:].decode('utf-8'))
94
- yield json_data
95
- except json.JSONDecodeError:
96
- print(f"Error decoding JSON: {line}")
97
- else:
98
- return response.json()
99
-
100
- def upload_file(
101
- self,
102
- api_key,
103
- file_path,
104
- user="default_user"):
105
-
106
- url = f"{self.dify_base_url}/files/upload"
107
- headers = {
108
- "Authorization": f"Bearer {api_key}"
109
- }
110
- files = {
111
- "file": open(file_path, "rb")
112
- }
113
- data = {
114
- "user": user
115
- }
116
- response = requests.post(url, headers=headers, files=files, data=data)
117
- response.raise_for_status()
118
- return response.json()
119
-
120
- def stop_response(
121
- self,
122
- api_key,
123
- task_id,
124
- user="default_user"):
125
-
126
- url = f"{self.dify_base_url}/chat-messages/{task_id}/stop"
127
- headers = {
128
- "Authorization": f"Bearer {api_key}",
129
- "Content-Type": "application/json"
130
- }
131
- data = {
132
- "user": user
133
- }
134
- response = requests.post(url, headers=headers, json=data)
135
- response.raise_for_status()
136
- return response.json()
137
-
138
- def get_app_info(
139
- self,
140
- api_key,
141
- user="default_user"):
142
-
143
- url = f"{self.dify_base_url}/info"
144
- headers = {
145
- "Authorization": f"Bearer {api_key}"
146
- }
147
- params = {
148
- "user": user
149
- }
150
- response = requests.get(url, headers=headers, params=params)
151
- response.raise_for_status()
152
- return response.json()
153
-
154
- def get_app_parameters(
155
- self,
156
- api_key,
157
- user="default_user"):
158
- url = f"{self.dify_base_url}/parameters"
159
- headers = {
160
- "Authorization": f"Bearer {api_key}"
161
- }
162
- params = {
163
- "user": user
164
- }
165
- response = requests.get(url, headers=headers, params=params)
166
- response.raise_for_status()
167
- return response.json()
168
-
169
- def get_app_meta(
170
- self,
171
- api_key,
172
- user="default_user"):
173
- url = f"{self.dify_base_url}/meta"
174
- headers = {
175
- "Authorization": f"Bearer {api_key}"
176
- }
177
- params = {
178
- "user": user
179
- }
180
- response = requests.get(url, headers=headers, params=params)
181
- response.raise_for_status()
182
- return response.json()
183
-
184
-
185
- base_url, dify_app_sks = get_app_info()
186
- server = Server("dify_mcp_server")
187
- dify_api = DifyAPI(base_url, dify_app_sks)
188
-
189
-
190
- @server.list_tools()
191
- async def handle_list_tools() -> list[types.Tool]:
192
- """
193
- List available tools.
194
- Each tool specifies its arguments using JSON Schema validation.
195
- """
196
- tools = []
197
- tool_names = dify_api.dify_app_names
198
- tool_infos = dify_api.dify_app_infos
199
- tool_params = dify_api.dify_app_params
200
- tool_num = len(tool_names)
201
- for i in range(tool_num):
202
- # 0. load app info for each tool
203
- app_info = tool_infos[i]
204
- # 1. load app param for each tool
205
- inputSchema = dict(
206
- type="object",
207
- properties={},
208
- required=[],
209
- )
210
- app_param = tool_params[i]
211
- property_num = len(app_param['user_input_form'])
212
- if property_num > 0:
213
- for j in range(property_num):
214
- param = app_param['user_input_form'][j]
215
- # TODO: Add readme about strange dify user input param format
216
- param_type = list(param.keys())[0]
217
- param_info = param[param_type]
218
- property_name = param_info['variable']
219
- inputSchema["properties"][property_name] = dict(
220
- type=param_type,
221
- description=param_info['label'],
222
- )
223
- if param_info['required']:
224
- inputSchema['required'].append(property_name)
225
-
226
- tools.append(
227
- types.Tool(
228
- name=app_info['name'],
229
- description=app_info['description'],
230
- inputSchema=inputSchema,
231
- )
232
- )
233
- return tools
234
-
235
-
236
- @server.call_tool()
237
- async def handle_call_tool(
238
- name: str, arguments: dict | None
239
- ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
240
- tool_names = dify_api.dify_app_names
241
- if name in tool_names:
242
- tool_idx = tool_names.index(name)
243
- tool_sk = dify_api.dify_app_sks[tool_idx]
244
- responses = dify_api.chat_message(
245
- tool_sk,
246
- arguments,
247
- )
248
- for res in responses:
249
- if res['event'] == 'workflow_finished':
250
- outputs = res['data']['outputs']
251
- mcp_out = []
252
- for _, v in outputs.items():
253
- mcp_out.append(
254
- types.TextContent(
255
- type='text',
256
- text=v
257
- )
258
- )
259
- return mcp_out
260
- else:
261
- raise ValueError(f"Unknown tool: {name}")
262
-
263
-
264
- async def main():
265
- # Run the server using stdin/stdout streams
266
- async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
267
- await server.run(
268
- read_stream,
269
- write_stream,
270
- InitializationOptions(
271
- server_name="dify_mcp_server",
272
- server_version="0.1.0",
273
- capabilities=server.get_capabilities(
274
- notification_options=NotificationOptions(),
275
- experimental_capabilities={},
276
- ),
277
- ),
278
- )
279
-
280
- if __name__ == "__main__":
281
- asyncio.run(main())
@@ -1,172 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: mseep-dify-mcp-server
3
- Version: 0.1.2
4
- Summary: Add your description here
5
- Author-email: mseep <support@skydeck.ai>
6
- Maintainer-email: mseep <support@skydeck.ai>
7
- Requires-Python: >=3.10
8
- Requires-Dist: httpx>=0.28.1
9
- Requires-Dist: mcp>=1.1.2
10
- Requires-Dist: omegaconf>=2.3.0
11
- Requires-Dist: pip>=24.3.1
12
- Requires-Dist: python-dotenv>=1.0.1
13
- Requires-Dist: requests
14
- Description-Content-Type: text/markdown
15
-
16
- # Model Context Protocol (MCP) Server for dify workflows
17
- A simple implementation of an MCP server for using [dify](https://github.com/langgenius/dify). It achieves the invocation of the Dify workflow by calling the tools of MCP.
18
- ## 📰 News
19
- * [2025/4/15] zNow supports directly using environment variables to pass `base_url` and `app_sks`, making it more convenient to use with cloud-hosted platforms.
20
-
21
-
22
- ## 🔨Installation
23
- The server can be installed via [Smithery](https://smithery.ai/server/dify-mcp-server) or manually.
24
-
25
- ### Step1: prepare config.yaml or enviroments
26
- You can configure the server using either environment variables or a `config.yaml` file.
27
-
28
- #### Method 1: Using Environment Variables (Recommended for Cloud Platforms)
29
-
30
- Set the following environment variables:
31
-
32
- ```shell
33
- export DIFY_BASE_URL="https://cloud.dify.ai/v1"
34
- export DIFY_APP_SKS="app-sk1,app-sk2" # Comma-separated list of your Dify App SKs
35
- ```
36
-
37
- * `DIFY_BASE_URL`: The base URL for your Dify API.
38
- * `DIFY_APP_SKS`: A comma-separated list of your Dify App Secret Keys (SKs). Each SK typically corresponds to a different Dify workflow you want to make available via MCP.
39
-
40
- #### Method 2: Using `config.yaml`
41
-
42
- Create a `config.yaml` file to store your Dify base URL and App SKs.
43
-
44
- Example `config.yaml`:
45
-
46
- ```yaml
47
- dify_base_url: "https://cloud.dify.ai/v1"
48
- dify_app_sks:
49
- - "app-sk1" # SK for workflow 1
50
- - "app-sk2" # SK for workflow 2
51
- # Add more SKs as needed
52
- ```
53
-
54
- * `dify_base_url`: The base URL for your Dify API.
55
- * `dify_app_sks`: A list of your Dify App Secret Keys (SKs). Each SK typically corresponds to a different Dify workflow.
56
-
57
- You can create this file quickly using the following command (adjust the path and values as needed):
58
-
59
- ```bash
60
- # Create a directory if it doesn't exist
61
- mkdir -p ~/.config/dify-mcp-server
62
-
63
- # Create the config file
64
- cat > ~/.config/dify-mcp-server/config.yaml <<EOF
65
- dify_base_url: "https://cloud.dify.ai/v1"
66
- dify_app_sks:
67
- - "app-your-sk-1"
68
- - "app-your-sk-2"
69
- EOF
70
-
71
- echo "Configuration file created at ~/.config/dify-mcp-server/config.yaml"
72
- ```
73
-
74
- When running the server (as shown in Step 2), you will need to provide the path to this `config.yaml` file via the `CONFIG_PATH` environment variable if you choose this method.
75
-
76
- ### Step2: Installation on your client
77
- ❓ If you haven't installed uv or uvx yet, you can do it quickly with the following command:
78
- ```
79
- curl -Ls https://astral.sh/uv/install.sh | sh
80
- ```
81
-
82
- #### ✅ Method 1: Use uvx (no need to clone code, recommended)
83
-
84
- ```json
85
- {
86
- "mcpServers": {
87
- "dify-mcp-server": {
88
- "command": "uvx",
89
- "args": [
90
- "--from","git+https://github.com/YanxingLiu/dify-mcp-server","dify_mcp_server"
91
- ],
92
- "env": {
93
- "DIFY_BASE_URL": "https://cloud.dify.ai/v1",
94
- "DIFY_APP_SKS": "app-sk1,app-sk2",
95
- }
96
- }
97
- }
98
- }
99
- ```
100
- or
101
- ```json
102
- {
103
- "mcpServers": {
104
- "dify-mcp-server": {
105
- "command": "uvx",
106
- "args": [
107
- "--from","git+https://github.com/YanxingLiu/dify-mcp-server","dify_mcp_server"
108
- ],
109
- "env": {
110
- "CONFIG_PATH": "/Users/lyx/Downloads/config.yaml"
111
- }
112
- }
113
- }
114
- }
115
- ```
116
-
117
- #### ✅ Method 2: Use uv (local clone + uv start)
118
-
119
- You can also run the dify mcp server manually in your clients. The config of client should like the following format:
120
- ```json
121
- {
122
- "mcpServers": {
123
- "mcp-server-rag-web-browser": {
124
- "command": "uv",
125
- "args": [
126
- "--directory", "${DIFY_MCP_SERVER_PATH}",
127
- "run", "dify_mcp_server"
128
- ],
129
- "env": {
130
- "CONFIG_PATH": "$CONFIG_PATH"
131
- }
132
- }
133
- }
134
- }
135
- ```
136
- or
137
- ```json
138
- {
139
- "mcpServers": {
140
- "mcp-server-rag-web-browser": {
141
- "command": "uv",
142
- "args": [
143
- "--directory", "${DIFY_MCP_SERVER_PATH}",
144
- "run", "dify_mcp_server"
145
- ],
146
- "env": {
147
- "CONFIG_PATH": "$CONFIG_PATH"
148
- }
149
- }
150
- }
151
- }
152
- ```
153
- Example config:
154
- ```json
155
- {
156
- "mcpServers": {
157
- "dify-mcp-server": {
158
- "command": "uv",
159
- "args": [
160
- "--directory", "/Users/lyx/Downloads/dify-mcp-server",
161
- "run", "dify_mcp_server"
162
- ],
163
- "env": {
164
- "DIFY_BASE_URL": "https://cloud.dify.ai/v1",
165
- "DIFY_APP_SKS": "app-sk1,app-sk2",
166
- }
167
- }
168
- }
169
- }
170
- ```
171
- ### Enjoy it
172
- At last, you can use dify tools in any client who supports mcp.
@@ -1,6 +0,0 @@
1
- dify_mcp_server/__init__.py,sha256=kTuRDcmoAa4al59WMbwXx_TjJhMqmpzCMFCZ981BL1M,213
2
- dify_mcp_server/server.py,sha256=pTdMPTmvK1uO6Ki062bVSp-VQ9cBbFO2WtMSfowGgzU,8966
3
- mseep_dify_mcp_server-0.1.2.dist-info/METADATA,sha256=CpMacgzk8A6wfMzVcdKC7APEibnMC9UrbS0yNvOY7Bo,4605
4
- mseep_dify_mcp_server-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
5
- mseep_dify_mcp_server-0.1.2.dist-info/entry_points.txt,sha256=YughlZESvmM9v4WMtY4GAUzFWY-udx_CBKQUa3WXxeU,57
6
- mseep_dify_mcp_server-0.1.2.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- dify_mcp_server = dify_mcp_server:main