swiftmcp 0.0.1__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.
- swiftmcp/__init__.py +0 -0
- swiftmcp/cli/main.py +39 -0
- swiftmcp/cli/proxy_serve.py +33 -0
- swiftmcp/core/composition/mcp_composition.py +54 -0
- swiftmcp/core/openapi/openapi2mcp.py +47 -0
- swiftmcp/core/proxy/mcp_proxy.py +25 -0
- swiftmcp/core/tools/http_tool/api_tool.py +271 -0
- swiftmcp/core/tools/http_tool/parser.py +537 -0
- swiftmcp/core/tools/http_tool/ssrf_proxy.py +167 -0
- swiftmcp/core/tools/http_tool/tool_bundle.py +30 -0
- swiftmcp/core/tools/http_tool/tool_entities.py +122 -0
- swiftmcp/core/tools/mcp_tool/mcp_tool.py +52 -0
- swiftmcp/utils/file_db.py +75 -0
- swiftmcp-0.0.1.dist-info/METADATA +18 -0
- swiftmcp-0.0.1.dist-info/RECORD +20 -0
- swiftmcp-0.0.1.dist-info/WHEEL +5 -0
- swiftmcp-0.0.1.dist-info/entry_points.txt +2 -0
- swiftmcp-0.0.1.dist-info/licenses/LICENSE +674 -0
- swiftmcp-0.0.1.dist-info/top_level.txt +1 -0
- swiftmcp-0.0.1.dist-info/zip-safe +1 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Proxy requests to avoid SSRF
|
|
3
|
+
"""
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import time
|
|
7
|
+
from typing import Any, Dict
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
|
|
11
|
+
# Configuration
|
|
12
|
+
SSRF_PROXY_ALL_URL = os.getenv('SSRF_PROXY_ALL_URL', '')
|
|
13
|
+
SSRF_PROXY_HTTP_URL = os.getenv('SSRF_PROXY_HTTP_URL', '')
|
|
14
|
+
SSRF_PROXY_HTTPS_URL = os.getenv('SSRF_PROXY_HTTPS_URL', '')
|
|
15
|
+
SSRF_DEFAULT_MAX_RETRIES = int(os.getenv('SSRF_DEFAULT_MAX_RETRIES', '3'))
|
|
16
|
+
|
|
17
|
+
# Proxy configuration
|
|
18
|
+
proxies = {
|
|
19
|
+
'http://': SSRF_PROXY_HTTP_URL,
|
|
20
|
+
'https://': SSRF_PROXY_HTTPS_URL
|
|
21
|
+
} if SSRF_PROXY_HTTP_URL and SSRF_PROXY_HTTPS_URL else None
|
|
22
|
+
|
|
23
|
+
# Retry configuration
|
|
24
|
+
BACKOFF_FACTOR = 0.5
|
|
25
|
+
STATUS_FORCELIST = [429, 500, 502, 503, 504]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def make_request(method: str, url: str, max_retries: int = SSRF_DEFAULT_MAX_RETRIES, **kwargs) -> httpx.Response:
|
|
29
|
+
"""
|
|
30
|
+
Make HTTP request with retry logic.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
method: HTTP method
|
|
34
|
+
url: Request URL
|
|
35
|
+
max_retries: Maximum number of retries
|
|
36
|
+
**kwargs: Additional arguments for the request
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
HTTP response
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
Exception: If maximum retries exceeded
|
|
43
|
+
"""
|
|
44
|
+
# Handle redirect parameter name change between libraries
|
|
45
|
+
if "allow_redirects" in kwargs:
|
|
46
|
+
allow_redirects = kwargs.pop("allow_redirects")
|
|
47
|
+
if "follow_redirects" not in kwargs:
|
|
48
|
+
kwargs["follow_redirects"] = allow_redirects
|
|
49
|
+
|
|
50
|
+
retries = 0
|
|
51
|
+
while retries <= max_retries:
|
|
52
|
+
try:
|
|
53
|
+
# Make request based on proxy configuration
|
|
54
|
+
if SSRF_PROXY_ALL_URL:
|
|
55
|
+
response = httpx.request(method=method, url=url, proxy=SSRF_PROXY_ALL_URL, **kwargs)
|
|
56
|
+
elif proxies:
|
|
57
|
+
response = httpx.request(method=method, url=url, proxies=proxies, **kwargs)
|
|
58
|
+
else:
|
|
59
|
+
response = httpx.request(method=method, url=url, **kwargs)
|
|
60
|
+
|
|
61
|
+
# Check if we should retry based on status code
|
|
62
|
+
if response.status_code not in STATUS_FORCELIST:
|
|
63
|
+
return response
|
|
64
|
+
else:
|
|
65
|
+
logging.warning(
|
|
66
|
+
f"Received status code {response.status_code} for URL {url} which is in the force list"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
except httpx.RequestError as e:
|
|
70
|
+
logging.warning(f"Request to URL {url} failed on attempt {retries + 1}: {e}")
|
|
71
|
+
|
|
72
|
+
# Wait before retry with exponential backoff
|
|
73
|
+
retries += 1
|
|
74
|
+
if retries <= max_retries:
|
|
75
|
+
time.sleep(BACKOFF_FACTOR * (2 ** (retries - 1)))
|
|
76
|
+
|
|
77
|
+
raise Exception(f"Reached maximum retries ({max_retries}) for URL {url}")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get(url: str, max_retries: int = SSRF_DEFAULT_MAX_RETRIES, **kwargs) -> httpx.Response:
|
|
81
|
+
"""
|
|
82
|
+
Make GET request.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
url: Request URL
|
|
86
|
+
max_retries: Maximum number of retries
|
|
87
|
+
**kwargs: Additional arguments for the request
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
HTTP response
|
|
91
|
+
"""
|
|
92
|
+
return make_request('GET', url, max_retries=max_retries, **kwargs)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def post(url: str, max_retries: int = SSRF_DEFAULT_MAX_RETRIES, **kwargs) -> httpx.Response:
|
|
96
|
+
"""
|
|
97
|
+
Make POST request.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
url: Request URL
|
|
101
|
+
max_retries: Maximum number of retries
|
|
102
|
+
**kwargs: Additional arguments for the request
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
HTTP response
|
|
106
|
+
"""
|
|
107
|
+
return make_request('POST', url, max_retries=max_retries, **kwargs)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def put(url: str, max_retries: int = SSRF_DEFAULT_MAX_RETRIES, **kwargs) -> httpx.Response:
|
|
111
|
+
"""
|
|
112
|
+
Make PUT request.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
url: Request URL
|
|
116
|
+
max_retries: Maximum number of retries
|
|
117
|
+
**kwargs: Additional arguments for the request
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
HTTP response
|
|
121
|
+
"""
|
|
122
|
+
return make_request('PUT', url, max_retries=max_retries, **kwargs)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def patch(url: str, max_retries: int = SSRF_DEFAULT_MAX_RETRIES, **kwargs) -> httpx.Response:
|
|
126
|
+
"""
|
|
127
|
+
Make PATCH request.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
url: Request URL
|
|
131
|
+
max_retries: Maximum number of retries
|
|
132
|
+
**kwargs: Additional arguments for the request
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
HTTP response
|
|
136
|
+
"""
|
|
137
|
+
return make_request('PATCH', url, max_retries=max_retries, **kwargs)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def delete(url: str, max_retries: int = SSRF_DEFAULT_MAX_RETRIES, **kwargs) -> httpx.Response:
|
|
141
|
+
"""
|
|
142
|
+
Make DELETE request.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
url: Request URL
|
|
146
|
+
max_retries: Maximum number of retries
|
|
147
|
+
**kwargs: Additional arguments for the request
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
HTTP response
|
|
151
|
+
"""
|
|
152
|
+
return make_request('DELETE', url, max_retries=max_retries, **kwargs)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def head(url: str, max_retries: int = SSRF_DEFAULT_MAX_RETRIES, **kwargs) -> httpx.Response:
|
|
156
|
+
"""
|
|
157
|
+
Make HEAD request.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
url: Request URL
|
|
161
|
+
max_retries: Maximum number of retries
|
|
162
|
+
**kwargs: Additional arguments for the request
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
HTTP response
|
|
166
|
+
"""
|
|
167
|
+
return make_request('HEAD', url, max_retries=max_retries, **kwargs)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from typing import Optional, List, Dict, Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from .tool_entities import ToolParameter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ApiToolBundle(BaseModel):
|
|
9
|
+
"""
|
|
10
|
+
This class is used to store the schema information of an API based tool,
|
|
11
|
+
such as the URL, the method, the parameters, etc.
|
|
12
|
+
"""
|
|
13
|
+
# Server URL
|
|
14
|
+
server_url: str
|
|
15
|
+
# HTTP method
|
|
16
|
+
method: str
|
|
17
|
+
# Summary/description of the operation
|
|
18
|
+
summary: Optional[str] = None
|
|
19
|
+
# Operation ID
|
|
20
|
+
operation_id: str
|
|
21
|
+
# Input parameters
|
|
22
|
+
parameters: Optional[List[ToolParameter]] = None
|
|
23
|
+
# Return values
|
|
24
|
+
returns: Optional[List[ToolParameter]] = None
|
|
25
|
+
# Author of the tool
|
|
26
|
+
author: str = ""
|
|
27
|
+
# Icon for the tool
|
|
28
|
+
icon: Optional[str] = None
|
|
29
|
+
# OpenAPI operation definition
|
|
30
|
+
openapi: Dict[str, Any]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Any, Optional, Union, List
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, field_validator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MultilingualText(BaseModel):
|
|
8
|
+
"""
|
|
9
|
+
Supports multiple languages with fallback to English.
|
|
10
|
+
"""
|
|
11
|
+
zh_Hans: Optional[str] = None
|
|
12
|
+
en_US: str
|
|
13
|
+
|
|
14
|
+
def __init__(self, **data):
|
|
15
|
+
super().__init__(**data)
|
|
16
|
+
if not self.zh_Hans:
|
|
17
|
+
self.zh_Hans = self.en_US
|
|
18
|
+
|
|
19
|
+
def to_dict(self) -> dict:
|
|
20
|
+
return {
|
|
21
|
+
'zh_Hans': self.zh_Hans,
|
|
22
|
+
'en_US': self.en_US,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ToolParameterOption(BaseModel):
|
|
27
|
+
"""Option for SELECT type parameters"""
|
|
28
|
+
value: str = Field(..., description="The value of the option")
|
|
29
|
+
label: MultilingualText = Field(..., description="The label of the option")
|
|
30
|
+
|
|
31
|
+
@field_validator('value', mode='before')
|
|
32
|
+
@classmethod
|
|
33
|
+
def transform_id_to_str(cls, value) -> str:
|
|
34
|
+
"""Convert value to string if needed"""
|
|
35
|
+
if not isinstance(value, str):
|
|
36
|
+
return str(value)
|
|
37
|
+
else:
|
|
38
|
+
return value
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ToolParameter(BaseModel):
|
|
42
|
+
"""Defines a parameter for a tool"""
|
|
43
|
+
|
|
44
|
+
class ToolParameterType(str, Enum):
|
|
45
|
+
"""Supported parameter types"""
|
|
46
|
+
STRING = "string"
|
|
47
|
+
NUMBER = "number"
|
|
48
|
+
BOOLEAN = "boolean"
|
|
49
|
+
SELECT = "select"
|
|
50
|
+
SECRET_INPUT = "secret-input"
|
|
51
|
+
FILE = "file"
|
|
52
|
+
INT = "int"
|
|
53
|
+
BOOL = "bool"
|
|
54
|
+
FLOAT = "float"
|
|
55
|
+
|
|
56
|
+
class ToolParameterForm(Enum):
|
|
57
|
+
"""When the parameter value should be provided"""
|
|
58
|
+
SCHEMA = "schema" # Set while adding tool
|
|
59
|
+
FORM = "form" # Set before invoking tool
|
|
60
|
+
LLM = "llm" # Set by LLM
|
|
61
|
+
|
|
62
|
+
# Parameter name
|
|
63
|
+
name: str = Field(..., description="The name of the parameter")
|
|
64
|
+
# Label presented to the user
|
|
65
|
+
label: MultilingualText = Field(..., description="The label presented to the user")
|
|
66
|
+
# Description presented to the user
|
|
67
|
+
human_description: Optional[MultilingualText] = Field(None, description="The description presented to the user")
|
|
68
|
+
# Placeholder text for input fields
|
|
69
|
+
placeholder: Optional[MultilingualText] = Field(None, description="The placeholder presented to the user")
|
|
70
|
+
# Parameter type
|
|
71
|
+
type: ToolParameterType = Field(..., description="The type of the parameter")
|
|
72
|
+
# When the parameter should be set
|
|
73
|
+
form: ToolParameterForm = Field(..., description="The form of the parameter, schema/form/llm")
|
|
74
|
+
# Description for LLM
|
|
75
|
+
llm_description: Optional[str] = None
|
|
76
|
+
# Whether the parameter is required
|
|
77
|
+
required: bool = False
|
|
78
|
+
# Default value
|
|
79
|
+
default: Optional[Union[float, int, str]] = None
|
|
80
|
+
# Minimum allowed value (for numeric types)
|
|
81
|
+
min: Optional[Union[float, int]] = None
|
|
82
|
+
# Maximum allowed value (for numeric types)
|
|
83
|
+
max: Optional[Union[float, int]] = None
|
|
84
|
+
# Options for SELECT type parameters
|
|
85
|
+
options: Optional[List[ToolParameterOption]] = None
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def get_simple_instance(cls, name: str, llm_description: str, param_type: ToolParameterType,
|
|
89
|
+
required: bool, options: Optional[List[str]] = None) -> 'ToolParameter':
|
|
90
|
+
"""
|
|
91
|
+
Create a simple tool parameter.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
name: The name of the parameter
|
|
95
|
+
llm_description: The description presented to the LLM
|
|
96
|
+
param_type: The type of the parameter
|
|
97
|
+
required: If the parameter is required
|
|
98
|
+
options: The options of the parameter (for SELECT type)
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
A new ToolParameter instance
|
|
102
|
+
"""
|
|
103
|
+
# Convert options to ToolParameterOption objects
|
|
104
|
+
param_options = None
|
|
105
|
+
if options:
|
|
106
|
+
param_options = [
|
|
107
|
+
ToolParameterOption(
|
|
108
|
+
value=option,
|
|
109
|
+
label=MultilingualText(en_US=option, zh_Hans=option)
|
|
110
|
+
) for option in options
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
return cls(
|
|
114
|
+
name=name,
|
|
115
|
+
label=MultilingualText(en_US='', zh_Hans=''),
|
|
116
|
+
human_description=MultilingualText(en_US='', zh_Hans=''),
|
|
117
|
+
type=param_type,
|
|
118
|
+
form=cls.ToolParameterForm.LLM,
|
|
119
|
+
llm_description=llm_description,
|
|
120
|
+
required=required,
|
|
121
|
+
options=param_options,
|
|
122
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) 2025 yaqiang.sun.
|
|
3
|
+
# This source code is licensed under the license found in the LICENSE file
|
|
4
|
+
# in the root directory of this source tree.
|
|
5
|
+
#########################################################################
|
|
6
|
+
# Author: yaqiangsun
|
|
7
|
+
# Created Time: 2025/08/29 17:37:59
|
|
8
|
+
########################################################################
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
from typing import Any, Literal, cast
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from mcp.server.fastmcp import FastMCP as FastMCP1x
|
|
16
|
+
import pydantic_core
|
|
17
|
+
import fastmcp
|
|
18
|
+
from fastmcp import Client
|
|
19
|
+
from fastmcp.server.server import FastMCP
|
|
20
|
+
from fastmcp.utilities.inspect import (
|
|
21
|
+
FastMCPInfo,
|
|
22
|
+
ToolInfo,
|
|
23
|
+
inspect_fastmcp
|
|
24
|
+
)
|
|
25
|
+
import json
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class MCPTool(object):
|
|
29
|
+
def __init__(self,mcp: FastMCP[Any]
|
|
30
|
+
):
|
|
31
|
+
self.mcp = mcp
|
|
32
|
+
pass
|
|
33
|
+
async def inspect_tools(self) -> list[ToolInfo]:
|
|
34
|
+
mcp_info = await inspect_fastmcp(self.mcp)
|
|
35
|
+
return mcp_info.tools
|
|
36
|
+
async def get_tools_names(self) -> list[str]:
|
|
37
|
+
tools = await self.inspect_tools()
|
|
38
|
+
return [tool.name for tool in tools]
|
|
39
|
+
async def get_tool(self, tool_name: str) -> ToolInfo:
|
|
40
|
+
tools = await self.inspect_tools()
|
|
41
|
+
for tool_info in tools:
|
|
42
|
+
if tool_info.name == tool_name:
|
|
43
|
+
return tool_info
|
|
44
|
+
return None
|
|
45
|
+
async def get_tool_json(self,tool:ToolInfo) -> dict:
|
|
46
|
+
return tool.__dict__
|
|
47
|
+
async def restore_tool(self, tool_json:ToolInfo) -> ToolInfo:
|
|
48
|
+
tool = ToolInfo(**tool_json)
|
|
49
|
+
return tool
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Copyright (c) 2024 yaqiang.sun.
|
|
4
|
+
# This source code is licensed under the license found in the LICENSE file
|
|
5
|
+
# in the root directory of this source tree.
|
|
6
|
+
#########################################################################
|
|
7
|
+
# Author: yaqiangsun
|
|
8
|
+
# Created Time: 2024/09/09 17:22:40
|
|
9
|
+
########################################################################
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import yaml
|
|
14
|
+
from miniolite.FileSQLite import FileSQLite
|
|
15
|
+
|
|
16
|
+
class AgentFileDB(object):
|
|
17
|
+
def __init__(self,db_path="tmp/test.db"):
|
|
18
|
+
pass
|
|
19
|
+
# initalize the database
|
|
20
|
+
self.file_db = FileSQLite(db_path)
|
|
21
|
+
def create_folder(self):
|
|
22
|
+
# create folder
|
|
23
|
+
self.file_db.force_add_folder("/data/flows")
|
|
24
|
+
self.file_db.force_add_folder("/data/flows_simple")
|
|
25
|
+
self.file_db.force_add_folder("/data/tools")
|
|
26
|
+
self.file_db.force_add_folder("/data/tools_simple")
|
|
27
|
+
create_folder()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def delete_file(self,path):
|
|
31
|
+
self.file_db.delete_file(path)
|
|
32
|
+
|
|
33
|
+
def list_file(self,path):
|
|
34
|
+
name_list = self.file_db.list_files(path)
|
|
35
|
+
return name_list
|
|
36
|
+
|
|
37
|
+
def write_json(self,json_obj,file_path):
|
|
38
|
+
json_str = json.dumps(json_obj)
|
|
39
|
+
self.file_db.add_file(file_path,content=json_str)
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
def read_json(self,path):
|
|
43
|
+
try:
|
|
44
|
+
file = self.file_db.read_file(path)
|
|
45
|
+
data = json.loads(file)
|
|
46
|
+
except (FileNotFoundError, json.JSONDecodeError):
|
|
47
|
+
# 如果文件不存在或为空,则初始化为空列表/字典
|
|
48
|
+
data = {}
|
|
49
|
+
return data
|
|
50
|
+
|
|
51
|
+
def write_yml(self,json_obj,file_path):
|
|
52
|
+
json_str = json.dumps(json_obj)
|
|
53
|
+
self.file_db.add_file(file_path,content=json_str)
|
|
54
|
+
def load_yaml_file(self,file_path: str, ignore_error: bool = True):
|
|
55
|
+
|
|
56
|
+
file = self.file_db.read_file(file_path)
|
|
57
|
+
try:
|
|
58
|
+
yaml_content = yaml.safe_load(file)
|
|
59
|
+
if not yaml_content:
|
|
60
|
+
raise ValueError(f'YAML file {file_path} is empty')
|
|
61
|
+
return yaml_content
|
|
62
|
+
except Exception as e:
|
|
63
|
+
raise ValueError(f'Failed to load YAML file {file_path}: {e}')
|
|
64
|
+
|
|
65
|
+
if __name__ == "__main__":
|
|
66
|
+
agent_db = AgentFileDB()
|
|
67
|
+
json_obj = {
|
|
68
|
+
"demo":"test"
|
|
69
|
+
}
|
|
70
|
+
agent_db.create_folder()
|
|
71
|
+
# write_json(json_obj=json_obj,file_path="/data/tools/out.json")
|
|
72
|
+
data = agent_db.read_json(path="/data/tools/out.json")
|
|
73
|
+
print(data)
|
|
74
|
+
|
|
75
|
+
pass
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: swiftmcp
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: multimoda MCP framework
|
|
5
|
+
Home-page: https://github.com/yaqiangsun/SwiftMCP
|
|
6
|
+
Author: Yaqiang Sun
|
|
7
|
+
Author-email: Yaqiang Sun <sunyaking@163.com>
|
|
8
|
+
License: GPL-3.0
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Dynamic: author
|
|
13
|
+
Dynamic: home-page
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
Dynamic: requires-python
|
|
16
|
+
|
|
17
|
+
# SwiftMCP
|
|
18
|
+
SwiftMCP: multimoda MCP framework
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
swiftmcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
swiftmcp/cli/main.py,sha256=-RVObk7J3lqAJUIlM5hDC564ZdVfIxsppSLHXu1CnRA,1220
|
|
3
|
+
swiftmcp/cli/proxy_serve.py,sha256=24DIFTjAXM-Q2KQFV1-klyH3_A8x87EiSDiVAH0pgJo,1200
|
|
4
|
+
swiftmcp/core/composition/mcp_composition.py,sha256=EF3wVjDXQKr_Q01WD3bU974OVxJfYuWQEQFbJYroa-8,1844
|
|
5
|
+
swiftmcp/core/openapi/openapi2mcp.py,sha256=siOVVJvXKkDDjU00ZNQ_ofXKA3QDYt7OOCFm_MAvs8Y,1496
|
|
6
|
+
swiftmcp/core/proxy/mcp_proxy.py,sha256=ZCl4pyZ2hlm_kR8EAmFYSwMDzf1bR4yrAt8Z2XAUQ9A,761
|
|
7
|
+
swiftmcp/core/tools/http_tool/api_tool.py,sha256=uXIBlyD8putFB4_8t2lkDw7Gdajxk4_yg9-I9QZvWig,10721
|
|
8
|
+
swiftmcp/core/tools/http_tool/parser.py,sha256=0GFAcEOHeHRyfSRBUArFCOoF_Tsogf5I-7alCpcAhFk,21501
|
|
9
|
+
swiftmcp/core/tools/http_tool/ssrf_proxy.py,sha256=Pnw4zAKb-P0olDluqrdUTEUr12wUFbsHZsojQGG6u2s,4887
|
|
10
|
+
swiftmcp/core/tools/http_tool/tool_bundle.py,sha256=Jb79BlN6gbRY5bdxXhSbDiSlVsdiYJDVeogmIjwmBnk,799
|
|
11
|
+
swiftmcp/core/tools/http_tool/tool_entities.py,sha256=TkZEQmpF1R4q9vWLmgze8DPxahFukr2e7wHCikKLAVw,4302
|
|
12
|
+
swiftmcp/core/tools/mcp_tool/mcp_tool.py,sha256=6wBvhwqVCoPL5FP2e0cS_MlzKFTivSFW9Ye1XEs-MPg,1556
|
|
13
|
+
swiftmcp/utils/file_db.py,sha256=AR6HCIQa2i7qyvUZ3AuFyD3LAti2ap6m6cZSDPz_WCs,2436
|
|
14
|
+
swiftmcp-0.0.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
15
|
+
swiftmcp-0.0.1.dist-info/METADATA,sha256=UT3LghucE02RNYOfjqBX0mk9t9t09pezzy47iHVxM68,432
|
|
16
|
+
swiftmcp-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
17
|
+
swiftmcp-0.0.1.dist-info/entry_points.txt,sha256=UbHiFJOH8od4ttDl0zZP6V7bxVPZVmvtCr09W4x2FMQ,56
|
|
18
|
+
swiftmcp-0.0.1.dist-info/top_level.txt,sha256=5ZqHG227k0vTAEQiUfQzQEU-PsGUmHhR9Smyz4JdnrQ,9
|
|
19
|
+
swiftmcp-0.0.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
20
|
+
swiftmcp-0.0.1.dist-info/RECORD,,
|