mseep-dify-mcp-server 0.1.3__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.
- mseep_dify_mcp_server-0.1.4.dist-info/METADATA +34 -0
- mseep_dify_mcp_server-0.1.4.dist-info/RECORD +4 -0
- {mseep_dify_mcp_server-0.1.3.dist-info → mseep_dify_mcp_server-0.1.4.dist-info}/WHEEL +2 -1
- mseep_dify_mcp_server-0.1.4.dist-info/top_level.txt +1 -0
- dify_mcp_server/__init__.py +0 -9
- dify_mcp_server/server.py +0 -281
- mseep_dify_mcp_server-0.1.3.dist-info/METADATA +0 -16
- mseep_dify_mcp_server-0.1.3.dist-info/RECORD +0 -6
- mseep_dify_mcp_server-0.1.3.dist-info/entry_points.txt +0 -2
@@ -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,,
|
@@ -0,0 +1 @@
|
|
1
|
+
|
dify_mcp_server/__init__.py
DELETED
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,16 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: mseep-dify-mcp-server
|
3
|
-
Version: 0.1.3
|
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
|
-
# Package managed by MseeP.ai
|
@@ -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.3.dist-info/METADATA,sha256=mGZ2wE7Neze3UthGzTUs_ffYJ4we4NzUPhGD1ntBHBY,455
|
4
|
-
mseep_dify_mcp_server-0.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
5
|
-
mseep_dify_mcp_server-0.1.3.dist-info/entry_points.txt,sha256=YughlZESvmM9v4WMtY4GAUzFWY-udx_CBKQUa3WXxeU,57
|
6
|
-
mseep_dify_mcp_server-0.1.3.dist-info/RECORD,,
|