mcp-openapi-proxy 0.1.1741477332__tar.gz → 0.1.1741479690__tar.gz
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.
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/PKG-INFO +5 -5
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/README.md +3 -4
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy/server_fastmcp.py +9 -14
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy/server_lowlevel.py +14 -14
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy/utils.py +23 -75
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy.egg-info/PKG-INFO +5 -5
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/pyproject.toml +3 -1
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/LICENSE +0 -0
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy/__init__.py +0 -0
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy.egg-info/SOURCES.txt +0 -0
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy.egg-info/dependency_links.txt +0 -0
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy.egg-info/entry_points.txt +0 -0
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy.egg-info/requires.txt +0 -0
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy.egg-info/top_level.txt +0 -0
- {mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/setup.cfg +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: mcp-openapi-proxy
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1741479690
|
|
4
4
|
Summary: MCP server for exposing OpenAPI specifications as MCP tools.
|
|
5
5
|
Author-email: Matthew Hand <matthewhandau@gmail.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
6
7
|
Description-Content-Type: text/markdown
|
|
7
8
|
License-File: LICENSE
|
|
8
9
|
Requires-Dist: mcp[cli]>=1.2.0
|
|
@@ -197,9 +198,8 @@ Update your configuration:
|
|
|
197
198
|
"env": {
|
|
198
199
|
"OPENAPI_SPEC_URL": "https://raw.githubusercontent.com/slackapi/slack-api-specs/master/web-api/slack_web_openapi_v2.json",
|
|
199
200
|
"TOOL_WHITELIST": "/chat,/bots,/conversations,/reminders,/files,/users",
|
|
200
|
-
"API_KEY": "<your_slack_bot_token>",
|
|
201
|
-
"
|
|
202
|
-
"TOOL_NAME_PREFIX": "slack_"
|
|
201
|
+
"API_KEY": "<your_slack_bot_token, starts with xoxb>",
|
|
202
|
+
"STRIP_PARAM": "token"
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -234,7 +234,7 @@ Try these commands in your MCP client:
|
|
|
234
234
|
|
|
235
235
|
### GetZep Example
|
|
236
236
|
|
|
237
|
-

|
|
238
238
|
|
|
239
239
|
GetZep offers a free cloud API for memory management with detailed endpoints. Since GetZep did not provide an official OpenAPI specification, this project includes a generated spec hosted on GitHub for convenience. This approach—creating a spec from documentation—is a reusable pattern: users can similarly generate OpenAPI specs for any REST API and reference them locally (e.g., `file:///path/to/spec.json`). Obtain an API key from [GetZep's documentation](https://docs.getzep.com/).
|
|
240
240
|
|
|
@@ -181,9 +181,8 @@ Update your configuration:
|
|
|
181
181
|
"env": {
|
|
182
182
|
"OPENAPI_SPEC_URL": "https://raw.githubusercontent.com/slackapi/slack-api-specs/master/web-api/slack_web_openapi_v2.json",
|
|
183
183
|
"TOOL_WHITELIST": "/chat,/bots,/conversations,/reminders,/files,/users",
|
|
184
|
-
"API_KEY": "<your_slack_bot_token>",
|
|
185
|
-
"
|
|
186
|
-
"TOOL_NAME_PREFIX": "slack_"
|
|
184
|
+
"API_KEY": "<your_slack_bot_token, starts with xoxb>",
|
|
185
|
+
"STRIP_PARAM": "token"
|
|
187
186
|
}
|
|
188
187
|
}
|
|
189
188
|
}
|
|
@@ -218,7 +217,7 @@ Try these commands in your MCP client:
|
|
|
218
217
|
|
|
219
218
|
### GetZep Example
|
|
220
219
|
|
|
221
|
-

|
|
222
221
|
|
|
223
222
|
GetZep offers a free cloud API for memory management with detailed endpoints. Since GetZep did not provide an official OpenAPI specification, this project includes a generated spec hosted on GitHub for convenience. This approach—creating a spec from documentation—is a reusable pattern: users can similarly generate OpenAPI specs for any REST API and reference them locally (e.g., `file:///path/to/spec.json`). Obtain an API key from [GetZep's documentation](https://docs.getzep.com/).
|
|
224
223
|
|
|
@@ -7,9 +7,8 @@ Configuration is controlled via environment variables:
|
|
|
7
7
|
- OPENAPI_SPEC_URL_<hash>: Unique URL per test, falls back to OPENAPI_SPEC_URL.
|
|
8
8
|
- TOOL_WHITELIST: Comma-separated list of allowed endpoint paths.
|
|
9
9
|
- SERVER_URL_OVERRIDE: Optional override for the base URL from the OpenAPI spec.
|
|
10
|
-
- API_KEY:
|
|
11
|
-
-
|
|
12
|
-
- API_KEY_JMESPATH: Optional JMESPath expression to map API_KEY into request parameters.
|
|
10
|
+
- API_KEY: Generic token for Bearer header.
|
|
11
|
+
- STRIP_PARAM: Param name (e.g., "auth") to remove from parameters.
|
|
13
12
|
"""
|
|
14
13
|
|
|
15
14
|
import os
|
|
@@ -19,7 +18,7 @@ import requests
|
|
|
19
18
|
from typing import Dict, Any
|
|
20
19
|
from mcp import types
|
|
21
20
|
from mcp.server.fastmcp import FastMCP
|
|
22
|
-
from mcp_openapi_proxy.utils import setup_logging, is_tool_whitelisted, fetch_openapi_spec,
|
|
21
|
+
from mcp_openapi_proxy.utils import setup_logging, is_tool_whitelisted, fetch_openapi_spec, build_base_url, normalize_tool_name, handle_auth, strip_parameters, get_tool_prefix
|
|
23
22
|
|
|
24
23
|
logger = setup_logging(debug=os.getenv("DEBUG", "").lower() in ("true", "1", "yes"))
|
|
25
24
|
|
|
@@ -112,8 +111,8 @@ def list_functions(*, env_key: str = "OPENAPI_SPEC_URL") -> str:
|
|
|
112
111
|
def call_function(*, function_name: str, parameters: dict = None, env_key: str = "OPENAPI_SPEC_URL") -> str:
|
|
113
112
|
"""Calls a function derived from the OpenAPI specification."""
|
|
114
113
|
logger.debug(f"call_function invoked with function_name='{function_name}' and parameters={parameters}")
|
|
115
|
-
logger.debug(f"API_KEY
|
|
116
|
-
logger.debug(f"
|
|
114
|
+
logger.debug(f"API_KEY: {os.getenv('API_KEY', '<not set>')[:5] + '...' if os.getenv('API_KEY') else '<not set>'}")
|
|
115
|
+
logger.debug(f"STRIP_PARAM: {os.getenv('STRIP_PARAM', '<not set>')}")
|
|
117
116
|
if not function_name:
|
|
118
117
|
logger.error("function_name is empty or None")
|
|
119
118
|
return json.dumps({"error": "function_name is required"})
|
|
@@ -159,8 +158,10 @@ def call_function(*, function_name: str, parameters: dict = None, env_key: str =
|
|
|
159
158
|
|
|
160
159
|
operation = function_def["operation"]
|
|
161
160
|
operation["method"] = function_def["method"]
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
headers = handle_auth(operation)
|
|
162
|
+
parameters = strip_parameters(parameters)
|
|
163
|
+
if function_def["method"] != "GET":
|
|
164
|
+
headers["Content-Type"] = "application/json"
|
|
164
165
|
|
|
165
166
|
if not is_tool_whitelisted(function_def["path"]):
|
|
166
167
|
logger.error(f"Access to function '{function_name}' is not allowed.")
|
|
@@ -173,14 +174,9 @@ def call_function(*, function_name: str, parameters: dict = None, env_key: str =
|
|
|
173
174
|
|
|
174
175
|
path = function_def["path"]
|
|
175
176
|
api_url = f"{base_url.rstrip('/')}/{path.lstrip('/')}"
|
|
176
|
-
headers = {}
|
|
177
|
-
if function_def["method"] != "GET":
|
|
178
|
-
headers["Content-Type"] = "application/json"
|
|
179
|
-
headers.update(get_auth_headers(spec))
|
|
180
177
|
request_params = {}
|
|
181
178
|
request_body = None
|
|
182
179
|
|
|
183
|
-
# Map all path parameters dynamically from the spec
|
|
184
180
|
if isinstance(parameters, dict):
|
|
185
181
|
path_params_in_openapi = [
|
|
186
182
|
param["name"] for param in operation.get("parameters", []) if param.get("in") == "path"
|
|
@@ -197,7 +193,6 @@ def call_function(*, function_name: str, parameters: dict = None, env_key: str =
|
|
|
197
193
|
if param_name in parameters:
|
|
198
194
|
api_url = api_url.replace(f"{{{param_name}}}", str(parameters.pop(param_name)))
|
|
199
195
|
logger.debug(f"Replaced path param {param_name} in URL: {api_url}")
|
|
200
|
-
# Remaining parameters go to query (GET) or body (non-GET)
|
|
201
196
|
if function_def["method"] == "GET":
|
|
202
197
|
request_params = parameters
|
|
203
198
|
else:
|
|
@@ -15,12 +15,12 @@ from mcp import types
|
|
|
15
15
|
from mcp.server.lowlevel import Server
|
|
16
16
|
from mcp.server.models import InitializationOptions
|
|
17
17
|
from mcp.server.stdio import stdio_server
|
|
18
|
-
from mcp_openapi_proxy.utils import setup_logging, normalize_tool_name, is_tool_whitelisted, fetch_openapi_spec,
|
|
18
|
+
from mcp_openapi_proxy.utils import setup_logging, normalize_tool_name, is_tool_whitelisted, fetch_openapi_spec, build_base_url, handle_auth, strip_parameters, detect_response_type
|
|
19
19
|
|
|
20
20
|
DEBUG = os.getenv("DEBUG", "").lower() in ("true", "1", "yes")
|
|
21
21
|
logger = setup_logging(debug=DEBUG)
|
|
22
22
|
|
|
23
|
-
tools: List[types.Tool] = []
|
|
23
|
+
tools: List[types.Tool] = [] # Global tools list
|
|
24
24
|
openapi_spec_data = None
|
|
25
25
|
|
|
26
26
|
mcp = Server("OpenApiProxy-LowLevel")
|
|
@@ -31,8 +31,8 @@ async def dispatcher_handler(request: types.CallToolRequest) -> types.ServerResu
|
|
|
31
31
|
try:
|
|
32
32
|
function_name = request.params.name
|
|
33
33
|
logger.debug(f"Dispatcher received CallToolRequest for function: {function_name}")
|
|
34
|
-
logger.debug(f"API_KEY
|
|
35
|
-
logger.debug(f"
|
|
34
|
+
logger.debug(f"API_KEY: {os.getenv('API_KEY', '<not set>')[:5] + '...' if os.getenv('API_KEY') else '<not set>'}")
|
|
35
|
+
logger.debug(f"STRIP_PARAM: {os.getenv('STRIP_PARAM', '<not set>')}")
|
|
36
36
|
tool = next((tool for tool in tools if tool.name == function_name), None)
|
|
37
37
|
if not tool:
|
|
38
38
|
logger.error(f"Unknown function requested: {function_name}")
|
|
@@ -42,7 +42,7 @@ async def dispatcher_handler(request: types.CallToolRequest) -> types.ServerResu
|
|
|
42
42
|
)
|
|
43
43
|
)
|
|
44
44
|
arguments = request.params.arguments or {}
|
|
45
|
-
logger.debug(f"Raw arguments before
|
|
45
|
+
logger.debug(f"Raw arguments before processing: {arguments}")
|
|
46
46
|
|
|
47
47
|
operation_details = lookup_operation_details(function_name, openapi_spec_data)
|
|
48
48
|
if not operation_details:
|
|
@@ -55,11 +55,13 @@ async def dispatcher_handler(request: types.CallToolRequest) -> types.ServerResu
|
|
|
55
55
|
|
|
56
56
|
operation = operation_details['operation']
|
|
57
57
|
operation['method'] = operation_details['method']
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
headers = handle_auth(operation)
|
|
59
|
+
parameters = strip_parameters(arguments)
|
|
60
|
+
method = operation_details['method']
|
|
61
|
+
if method != "GET":
|
|
62
|
+
headers["Content-Type"] = "application/json"
|
|
60
63
|
|
|
61
64
|
path = operation_details['path']
|
|
62
|
-
method = operation_details['method']
|
|
63
65
|
|
|
64
66
|
base_url = build_base_url(openapi_spec_data)
|
|
65
67
|
if not base_url:
|
|
@@ -71,14 +73,9 @@ async def dispatcher_handler(request: types.CallToolRequest) -> types.ServerResu
|
|
|
71
73
|
)
|
|
72
74
|
|
|
73
75
|
api_url = f"{base_url.rstrip('/')}/{path.lstrip('/')}"
|
|
74
|
-
headers = {}
|
|
75
|
-
if method != "GET":
|
|
76
|
-
headers["Content-Type"] = "application/json"
|
|
77
|
-
headers.update(get_auth_headers(openapi_spec_data))
|
|
78
76
|
request_params = {}
|
|
79
77
|
request_body = None
|
|
80
78
|
|
|
81
|
-
# Map all path parameters dynamically from the spec
|
|
82
79
|
if isinstance(parameters, dict):
|
|
83
80
|
path_params_in_openapi = [
|
|
84
81
|
param['name'] for param in operation.get('parameters', []) if param.get('in') == 'path'
|
|
@@ -99,7 +96,6 @@ async def dispatcher_handler(request: types.CallToolRequest) -> types.ServerResu
|
|
|
99
96
|
if param_name in parameters:
|
|
100
97
|
api_url = api_url.replace(f"{{{param_name}}}", str(parameters.pop(param_name)))
|
|
101
98
|
logger.debug(f"Replaced path param {param_name} in URL: {api_url}")
|
|
102
|
-
# Remaining parameters go to query (GET) or body (non-GET)
|
|
103
99
|
if method == "GET":
|
|
104
100
|
request_params = parameters
|
|
105
101
|
else:
|
|
@@ -158,7 +154,11 @@ async def list_tools(request: types.ListToolsRequest) -> types.ServerResult:
|
|
|
158
154
|
return result
|
|
159
155
|
|
|
160
156
|
def register_functions(spec: Dict) -> List[types.Tool]:
|
|
157
|
+
"""Register tools from OpenAPI spec, preserving across calls if already populated."""
|
|
161
158
|
global tools
|
|
159
|
+
if tools: # If tools already exist, don’t reset unless spec changes
|
|
160
|
+
logger.debug("Tools already registered, skipping re-registration")
|
|
161
|
+
return tools
|
|
162
162
|
tools = []
|
|
163
163
|
if not spec:
|
|
164
164
|
logger.error("OpenAPI spec is None or empty.")
|
{mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy/utils.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Utility functions for mcp_openapi_proxy, including logging setup,
|
|
3
3
|
OpenAPI fetching, name normalization, whitelist filtering, auth handling,
|
|
4
|
-
and response type detection.
|
|
4
|
+
parameter stripping, and response type detection.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import os
|
|
@@ -11,7 +11,6 @@ import requests
|
|
|
11
11
|
import re
|
|
12
12
|
import json
|
|
13
13
|
import yaml
|
|
14
|
-
import jmespath
|
|
15
14
|
from urllib.parse import urlparse
|
|
16
15
|
from dotenv import load_dotenv
|
|
17
16
|
from mcp import types
|
|
@@ -151,84 +150,33 @@ def fetch_openapi_spec(spec_url: str) -> dict:
|
|
|
151
150
|
logger.error(f"Error parsing OpenAPI spec from {spec_url}: {e}")
|
|
152
151
|
return None
|
|
153
152
|
|
|
154
|
-
def
|
|
153
|
+
def handle_auth(operation: dict) -> dict:
|
|
154
|
+
"""
|
|
155
|
+
Handles authentication for API requests.
|
|
156
|
+
- API_KEY: Sets Bearer header.
|
|
157
|
+
Returns: headers
|
|
158
|
+
"""
|
|
159
|
+
api_key = os.getenv("API_KEY")
|
|
155
160
|
headers = {}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
logger.debug(f"
|
|
159
|
-
|
|
160
|
-
auth_type_override = os.getenv("API_AUTH_TYPE")
|
|
161
|
-
if auth_type_override:
|
|
162
|
-
headers["Authorization"] = f"{auth_type_override} {auth_token}"
|
|
163
|
-
logger.debug(f"Using API_AUTH_TYPE override: Authorization: {auth_type_override} {redact_api_key(auth_token)}")
|
|
164
|
-
return headers
|
|
165
|
-
security_defs = spec.get('securityDefinitions', {})
|
|
166
|
-
for name, definition in security_defs.items():
|
|
167
|
-
if definition.get('type') == 'apiKey' and definition.get('in') == 'header' and definition.get('name') == 'Authorization':
|
|
168
|
-
desc = definition.get('description', '')
|
|
169
|
-
match = re.search(r'(\w+(?:-\w+)*)\s+<token>', desc)
|
|
170
|
-
if match:
|
|
171
|
-
prefix = match.group(1)
|
|
172
|
-
headers["Authorization"] = f"{prefix} {auth_token}"
|
|
173
|
-
logger.debug(f"Using apiKey with prefix from spec description: Authorization: {prefix} {redact_api_key(auth_token)}")
|
|
174
|
-
else:
|
|
175
|
-
headers["Authorization"] = auth_token
|
|
176
|
-
logger.debug(f"Using raw apiKey auth from spec: Authorization: {redact_api_key(auth_token)}")
|
|
177
|
-
return headers
|
|
178
|
-
elif definition.get('type') == 'oauth2':
|
|
179
|
-
headers["Authorization"] = f"Bearer {auth_token}"
|
|
180
|
-
logger.debug(f"Using Bearer auth from spec: Authorization: Bearer {redact_api_key(auth_token)}")
|
|
181
|
-
return headers
|
|
182
|
-
headers["Authorization"] = auth_token
|
|
183
|
-
logger.warning(f"No clear auth type in spec, using raw API key: Authorization: {redact_api_key(auth_token)}")
|
|
161
|
+
if api_key:
|
|
162
|
+
headers["Authorization"] = f"Bearer {api_key}"
|
|
163
|
+
logger.debug(f"Using API_KEY as Bearer: {redact_api_key(api_key)}")
|
|
164
|
+
logger.debug(f"Headers after auth: {headers}")
|
|
184
165
|
return headers
|
|
185
166
|
|
|
186
|
-
def
|
|
167
|
+
def strip_parameters(parameters: dict = None) -> dict:
|
|
168
|
+
"""
|
|
169
|
+
Strips specified parameter from parameters if STRIP_PARAM is set.
|
|
170
|
+
Returns: updated_parameters
|
|
171
|
+
"""
|
|
187
172
|
if parameters is None:
|
|
188
173
|
parameters = {}
|
|
189
|
-
logger.debug(f"Raw parameters before
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
logger.debug("
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
method = operation.get("method", "GET").upper()
|
|
197
|
-
request_data = {"query": {}, "body": {}}
|
|
198
|
-
# Preserve original params, split by method
|
|
199
|
-
if parameters:
|
|
200
|
-
for key, value in parameters.items():
|
|
201
|
-
param_in = next((p.get("in") for p in operation.get("parameters", []) if p.get("name") == key), None)
|
|
202
|
-
if param_in == "query" or (method == "GET" and param_in not in ["path", "header"]):
|
|
203
|
-
request_data["query"][key] = value
|
|
204
|
-
elif param_in == "header":
|
|
205
|
-
request_data["body"][key] = value
|
|
206
|
-
elif param_in != "path": # Path params handled elsewhere
|
|
207
|
-
request_data["body"][key] = value
|
|
208
|
-
|
|
209
|
-
# Apply API_KEY via JMESPath
|
|
210
|
-
try:
|
|
211
|
-
if jmespath_expr:
|
|
212
|
-
parts = jmespath_expr.split(".")
|
|
213
|
-
target = request_data[parts[0]] if parts[0] in request_data else {}
|
|
214
|
-
current = target
|
|
215
|
-
for i, part in enumerate(parts[1:], 1):
|
|
216
|
-
if i == len(parts) - 1:
|
|
217
|
-
current[part] = api_key # Overwrite at final key
|
|
218
|
-
else:
|
|
219
|
-
current = current.setdefault(part, {})
|
|
220
|
-
if parts[0] in request_data:
|
|
221
|
-
request_data[parts[0]] = target
|
|
222
|
-
logger.debug(f"Applied API_KEY to {jmespath_expr}: {redact_api_key(api_key)}")
|
|
223
|
-
except Exception as e:
|
|
224
|
-
logger.error(f"Error applying JMESPath expression {jmespath_expr}: {e}")
|
|
225
|
-
|
|
226
|
-
# Merge back, overwriting original params
|
|
227
|
-
if method == "GET":
|
|
228
|
-
parameters = {**parameters, **request_data["query"]}
|
|
229
|
-
else:
|
|
230
|
-
parameters = {**parameters, **request_data["body"]}
|
|
231
|
-
logger.debug(f"Parameters after custom auth merge: {parameters}")
|
|
174
|
+
logger.debug(f"Raw parameters before stripping: {parameters}")
|
|
175
|
+
strip_param = os.getenv("STRIP_PARAM")
|
|
176
|
+
if strip_param and isinstance(parameters, dict) and strip_param in parameters:
|
|
177
|
+
del parameters[strip_param]
|
|
178
|
+
logger.debug(f"Stripped param '{strip_param}' from parameters")
|
|
179
|
+
logger.debug(f"Parameters after stripping: {parameters}")
|
|
232
180
|
return parameters
|
|
233
181
|
|
|
234
182
|
def map_schema_to_tools(schema: dict) -> list:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: mcp-openapi-proxy
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1741479690
|
|
4
4
|
Summary: MCP server for exposing OpenAPI specifications as MCP tools.
|
|
5
5
|
Author-email: Matthew Hand <matthewhandau@gmail.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
6
7
|
Description-Content-Type: text/markdown
|
|
7
8
|
License-File: LICENSE
|
|
8
9
|
Requires-Dist: mcp[cli]>=1.2.0
|
|
@@ -197,9 +198,8 @@ Update your configuration:
|
|
|
197
198
|
"env": {
|
|
198
199
|
"OPENAPI_SPEC_URL": "https://raw.githubusercontent.com/slackapi/slack-api-specs/master/web-api/slack_web_openapi_v2.json",
|
|
199
200
|
"TOOL_WHITELIST": "/chat,/bots,/conversations,/reminders,/files,/users",
|
|
200
|
-
"API_KEY": "<your_slack_bot_token>",
|
|
201
|
-
"
|
|
202
|
-
"TOOL_NAME_PREFIX": "slack_"
|
|
201
|
+
"API_KEY": "<your_slack_bot_token, starts with xoxb>",
|
|
202
|
+
"STRIP_PARAM": "token"
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -234,7 +234,7 @@ Try these commands in your MCP client:
|
|
|
234
234
|
|
|
235
235
|
### GetZep Example
|
|
236
236
|
|
|
237
|
-

|
|
238
238
|
|
|
239
239
|
GetZep offers a free cloud API for memory management with detailed endpoints. Since GetZep did not provide an official OpenAPI specification, this project includes a generated spec hosted on GitHub for convenience. This approach—creating a spec from documentation—is a reusable pattern: users can similarly generate OpenAPI specs for any REST API and reference them locally (e.g., `file:///path/to/spec.json`). Obtain an API key from [GetZep's documentation](https://docs.getzep.com/).
|
|
240
240
|
|
|
@@ -4,7 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mcp-openapi-proxy"
|
|
7
|
-
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
version = "0.1.1741479690"
|
|
8
9
|
description = "MCP server for exposing OpenAPI specifications as MCP tools."
|
|
9
10
|
readme = "README.md"
|
|
10
11
|
authors = [
|
|
@@ -27,6 +28,7 @@ mcp-openapi-proxy = "mcp_openapi_proxy:main" # Correct entry pointing to __init
|
|
|
27
28
|
[dependency-groups]
|
|
28
29
|
dev = [
|
|
29
30
|
"pytest>=8.3.4",
|
|
31
|
+
"pytest-asyncio>=0.21.0",
|
|
30
32
|
]
|
|
31
33
|
|
|
32
34
|
[tool.pytest.ini_options]
|
|
File without changes
|
{mcp_openapi_proxy-0.1.1741477332 → mcp_openapi_proxy-0.1.1741479690}/mcp_openapi_proxy/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|