awslabs.openapi-mcp-server 0.1.1__py3-none-any.whl → 0.2.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.
- awslabs/openapi_mcp_server/__init__.py +1 -1
- awslabs/openapi_mcp_server/api/config.py +22 -6
- awslabs/openapi_mcp_server/auth/cognito_auth.py +168 -24
- awslabs/openapi_mcp_server/server.py +11 -1
- {awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/METADATA +40 -36
- {awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/RECORD +10 -10
- {awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/WHEEL +0 -0
- {awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/entry_points.txt +0 -0
- {awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/licenses/NOTICE +0 -0
|
@@ -42,17 +42,20 @@ class Config:
|
|
|
42
42
|
auth_cognito_client_id: str = ''
|
|
43
43
|
auth_cognito_username: str = ''
|
|
44
44
|
auth_cognito_password: str = ''
|
|
45
|
+
auth_cognito_client_secret: str = ''
|
|
46
|
+
auth_cognito_domain: str = '' # Required for client credentials flow
|
|
47
|
+
auth_cognito_scopes: str = '' # Optional, comma-separated list of scopes
|
|
45
48
|
auth_cognito_user_pool_id: str = ''
|
|
46
49
|
auth_cognito_region: str = 'us-east-1'
|
|
47
50
|
|
|
48
51
|
# Server configuration
|
|
49
|
-
port: int = 8000
|
|
50
52
|
# Default to localhost for security; use SERVER_HOST env var to override when needed (e.g. in Docker)
|
|
51
53
|
host: str = '127.0.0.1'
|
|
54
|
+
port: int = 8000
|
|
52
55
|
debug: bool = False
|
|
53
56
|
transport: str = 'stdio' # stdio only
|
|
54
57
|
message_timeout: int = 60
|
|
55
|
-
version: str = '0.
|
|
58
|
+
version: str = '0.2.0'
|
|
56
59
|
|
|
57
60
|
|
|
58
61
|
def load_config(args: Any = None) -> Config:
|
|
@@ -93,11 +96,14 @@ def load_config(args: Any = None) -> Config:
|
|
|
93
96
|
'AUTH_COGNITO_CLIENT_ID': (lambda v: setattr(config, 'auth_cognito_client_id', v)),
|
|
94
97
|
'AUTH_COGNITO_USERNAME': (lambda v: setattr(config, 'auth_cognito_username', v)),
|
|
95
98
|
'AUTH_COGNITO_PASSWORD': (lambda v: setattr(config, 'auth_cognito_password', v)),
|
|
99
|
+
'AUTH_COGNITO_CLIENT_SECRET': (lambda v: setattr(config, 'auth_cognito_client_secret', v)),
|
|
100
|
+
'AUTH_COGNITO_DOMAIN': (lambda v: setattr(config, 'auth_cognito_domain', v)),
|
|
101
|
+
'AUTH_COGNITO_SCOPES': (lambda v: setattr(config, 'auth_cognito_scopes', v)),
|
|
96
102
|
'AUTH_COGNITO_USER_POOL_ID': (lambda v: setattr(config, 'auth_cognito_user_pool_id', v)),
|
|
97
103
|
'AUTH_COGNITO_REGION': (lambda v: setattr(config, 'auth_cognito_region', v)),
|
|
98
104
|
# Server configuration
|
|
99
|
-
'SERVER_PORT': (lambda v: setattr(config, 'port', int(v))),
|
|
100
105
|
'SERVER_HOST': (lambda v: setattr(config, 'host', v)),
|
|
106
|
+
'SERVER_PORT': (lambda v: setattr(config, 'port', int(v))),
|
|
101
107
|
'SERVER_DEBUG': (lambda v: setattr(config, 'debug', v.lower() == 'true')),
|
|
102
108
|
'SERVER_TRANSPORT': (lambda v: setattr(config, 'transport', v)),
|
|
103
109
|
'SERVER_MESSAGE_TIMEOUT': (lambda v: setattr(config, 'message_timeout', int(v))),
|
|
@@ -184,6 +190,18 @@ def load_config(args: Any = None) -> Config:
|
|
|
184
190
|
logger.debug('Setting Cognito password from arguments')
|
|
185
191
|
config.auth_cognito_password = args.auth_cognito_password
|
|
186
192
|
|
|
193
|
+
if hasattr(args, 'auth_cognito_client_secret') and args.auth_cognito_client_secret:
|
|
194
|
+
logger.debug('Setting Cognito client secret from arguments')
|
|
195
|
+
config.auth_cognito_client_secret = args.auth_cognito_client_secret
|
|
196
|
+
|
|
197
|
+
if hasattr(args, 'auth_cognito_domain') and args.auth_cognito_domain:
|
|
198
|
+
logger.debug('Setting Cognito domain from arguments')
|
|
199
|
+
config.auth_cognito_domain = args.auth_cognito_domain
|
|
200
|
+
|
|
201
|
+
if hasattr(args, 'auth_cognito_scopes') and args.auth_cognito_scopes:
|
|
202
|
+
logger.debug('Setting Cognito scopes from arguments')
|
|
203
|
+
config.auth_cognito_scopes = args.auth_cognito_scopes
|
|
204
|
+
|
|
187
205
|
if hasattr(args, 'auth_cognito_user_pool_id') and args.auth_cognito_user_pool_id:
|
|
188
206
|
logger.debug('Setting Cognito user pool ID from arguments')
|
|
189
207
|
config.auth_cognito_user_pool_id = args.auth_cognito_user_pool_id
|
|
@@ -193,8 +211,6 @@ def load_config(args: Any = None) -> Config:
|
|
|
193
211
|
config.auth_cognito_region = args.auth_cognito_region
|
|
194
212
|
|
|
195
213
|
# Log final configuration details
|
|
196
|
-
logger.info(
|
|
197
|
-
f'Configuration loaded: API name={config.api_name}, transport={config.transport}, port={config.port}'
|
|
198
|
-
)
|
|
214
|
+
logger.info(f'Configuration loaded: API name={config.api_name}, transport={config.transport}')
|
|
199
215
|
|
|
200
216
|
return config
|
|
@@ -32,9 +32,9 @@ from typing import Dict, Optional
|
|
|
32
32
|
class CognitoAuthProvider(BearerAuthProvider):
|
|
33
33
|
"""Cognito User Pool authentication provider.
|
|
34
34
|
|
|
35
|
-
This provider obtains
|
|
35
|
+
This provider obtains tokens from AWS Cognito User Pools
|
|
36
36
|
and delegates to BearerAuthProvider for adding Authorization headers
|
|
37
|
-
to all HTTP requests.
|
|
37
|
+
to all HTTP requests. Supports both password and client credentials flows.
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
40
|
def __init__(self, config: Config):
|
|
@@ -48,15 +48,35 @@ class CognitoAuthProvider(BearerAuthProvider):
|
|
|
48
48
|
self._client_id = config.auth_cognito_client_id
|
|
49
49
|
self._username = config.auth_cognito_username
|
|
50
50
|
self._password = config.auth_cognito_password
|
|
51
|
+
self._client_secret = config.auth_cognito_client_secret
|
|
52
|
+
self._domain = config.auth_cognito_domain
|
|
53
|
+
self._scopes = config.auth_cognito_scopes.split(',') if config.auth_cognito_scopes else []
|
|
51
54
|
self._user_pool_id = config.auth_cognito_user_pool_id
|
|
52
55
|
self._region = config.auth_cognito_region
|
|
53
56
|
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
# Determine grant type based on provided credentials
|
|
58
|
+
self._grant_type = self._determine_grant_type()
|
|
59
|
+
|
|
60
|
+
# Log grant type selection at INFO level
|
|
61
|
+
logger.info(
|
|
62
|
+
f'Cognito auth using grant type: {self._grant_type} '
|
|
63
|
+
f'({"client_id and client_secret provided" if self._grant_type == "client_credentials" else "username and password provided"})'
|
|
58
64
|
)
|
|
59
65
|
|
|
66
|
+
# Add debug log early in initialization
|
|
67
|
+
if self._grant_type == 'client_credentials':
|
|
68
|
+
logger.debug(
|
|
69
|
+
f'Cognito auth configuration: ClientID={self._client_id}, '
|
|
70
|
+
f'Client Secret={"SET" if self._client_secret else "NOT SET"}, '
|
|
71
|
+
f'Domain={self._domain or "NOT SET"}, '
|
|
72
|
+
f'Region={self._region}'
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
logger.debug(
|
|
76
|
+
f'Cognito auth configuration: Username={self._username}, ClientID={self._client_id}, '
|
|
77
|
+
f'Password={"SET" if self._password else "NOT SET"}, UserPoolID={self._user_pool_id or "NOT SET"}'
|
|
78
|
+
)
|
|
79
|
+
|
|
60
80
|
# Token management
|
|
61
81
|
self._token_expires_at = 0
|
|
62
82
|
self._refresh_token_value = None
|
|
@@ -65,7 +85,17 @@ class CognitoAuthProvider(BearerAuthProvider):
|
|
|
65
85
|
# Get initial token before parent initialization
|
|
66
86
|
try:
|
|
67
87
|
# Only try to get token if we have the minimum required credentials
|
|
68
|
-
if
|
|
88
|
+
if (
|
|
89
|
+
self._grant_type == 'client_credentials'
|
|
90
|
+
and self._client_id
|
|
91
|
+
and self._client_secret
|
|
92
|
+
and self._domain
|
|
93
|
+
) or (
|
|
94
|
+
self._grant_type == 'password'
|
|
95
|
+
and self._client_id
|
|
96
|
+
and self._username
|
|
97
|
+
and self._password
|
|
98
|
+
):
|
|
69
99
|
token = self._get_cognito_token()
|
|
70
100
|
if token:
|
|
71
101
|
# Set token in config for parent class to use
|
|
@@ -76,12 +106,28 @@ class CognitoAuthProvider(BearerAuthProvider):
|
|
|
76
106
|
)
|
|
77
107
|
except Exception as e:
|
|
78
108
|
logger.warning(f'Failed to get initial Cognito token: {e}')
|
|
79
|
-
#
|
|
109
|
+
# Set a placeholder token to avoid parent validation errors
|
|
110
|
+
config.auth_token = 'PENDING_COGNITO_TOKEN'
|
|
80
111
|
|
|
81
112
|
# Call parent initializer which will validate and initialize auth
|
|
82
113
|
# This will set self._token from config.auth_token
|
|
83
114
|
super().__init__(config)
|
|
84
115
|
|
|
116
|
+
def _determine_grant_type(self) -> str:
|
|
117
|
+
"""Determine the grant type based on provided credentials.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
str: The grant type to use ('client_credentials' or 'password')
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
if self._client_id and self._client_secret and self._domain:
|
|
124
|
+
return 'client_credentials'
|
|
125
|
+
elif self._client_id and self._username and self._password:
|
|
126
|
+
return 'password'
|
|
127
|
+
else:
|
|
128
|
+
# Default to password flow for backward compatibility
|
|
129
|
+
return 'password'
|
|
130
|
+
|
|
85
131
|
def _validate_config(self) -> bool:
|
|
86
132
|
"""Validate the configuration.
|
|
87
133
|
|
|
@@ -102,21 +148,38 @@ class CognitoAuthProvider(BearerAuthProvider):
|
|
|
102
148
|
},
|
|
103
149
|
)
|
|
104
150
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
'
|
|
110
|
-
|
|
111
|
-
|
|
151
|
+
# Validate based on grant type
|
|
152
|
+
if self._grant_type == 'client_credentials':
|
|
153
|
+
if not self._client_secret:
|
|
154
|
+
raise MissingCredentialsError(
|
|
155
|
+
'Client credentials flow requires a client secret',
|
|
156
|
+
{
|
|
157
|
+
'help': 'Provide client secret using --auth-cognito-client-secret command line argument or AUTH_COGNITO_CLIENT_SECRET environment variable'
|
|
158
|
+
},
|
|
159
|
+
)
|
|
160
|
+
if not self._domain:
|
|
161
|
+
raise MissingCredentialsError(
|
|
162
|
+
'Client credentials flow requires a domain',
|
|
163
|
+
{
|
|
164
|
+
'help': 'Provide domain using --auth-cognito-domain command line argument or AUTH_COGNITO_DOMAIN environment variable'
|
|
165
|
+
},
|
|
166
|
+
)
|
|
167
|
+
else: # password grant type
|
|
168
|
+
if not self._username:
|
|
169
|
+
raise MissingCredentialsError(
|
|
170
|
+
'Password flow requires a username',
|
|
171
|
+
{
|
|
172
|
+
'help': 'Provide username using --auth-cognito-username command line argument or AUTH_COGNITO_USERNAME environment variable'
|
|
173
|
+
},
|
|
174
|
+
)
|
|
112
175
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
176
|
+
if not self._password:
|
|
177
|
+
raise MissingCredentialsError(
|
|
178
|
+
'Password flow requires a password',
|
|
179
|
+
{
|
|
180
|
+
'help': 'Provide password using --auth-cognito-password command line argument or AUTH_COGNITO_PASSWORD environment variable'
|
|
181
|
+
},
|
|
182
|
+
)
|
|
120
183
|
|
|
121
184
|
# Let parent class validate the token
|
|
122
185
|
return super()._validate_config()
|
|
@@ -193,10 +256,91 @@ class CognitoAuthProvider(BearerAuthProvider):
|
|
|
193
256
|
raise ExpiredTokenError('Token refresh failed', {'error': str(e)})
|
|
194
257
|
|
|
195
258
|
def _get_cognito_token(self) -> Optional[str]:
|
|
196
|
-
"""Get a new token from Cognito using username/password.
|
|
259
|
+
"""Get a new token from Cognito using username/password or client credentials.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
str: Cognito token or None if authentication fails
|
|
263
|
+
|
|
264
|
+
Raises:
|
|
265
|
+
AuthenticationError: If authentication fails
|
|
266
|
+
|
|
267
|
+
"""
|
|
268
|
+
if self._grant_type == 'client_credentials':
|
|
269
|
+
return self._get_token_client_credentials()
|
|
270
|
+
else:
|
|
271
|
+
return self._get_token_password()
|
|
272
|
+
|
|
273
|
+
def _get_token_client_credentials(self) -> Optional[str]:
|
|
274
|
+
"""Get a token using the client credentials flow.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
str: Access token or None if authentication fails
|
|
278
|
+
|
|
279
|
+
Raises:
|
|
280
|
+
AuthenticationError: If authentication fails
|
|
281
|
+
|
|
282
|
+
"""
|
|
283
|
+
try:
|
|
284
|
+
# Construct token endpoint using the provided domain
|
|
285
|
+
token_endpoint = (
|
|
286
|
+
f'https://{self._domain}.auth.{self._region}.amazoncognito.com/oauth2/token'
|
|
287
|
+
)
|
|
288
|
+
logger.debug(f'Using token endpoint: {token_endpoint}')
|
|
289
|
+
|
|
290
|
+
# Make the token request
|
|
291
|
+
import base64
|
|
292
|
+
import requests
|
|
293
|
+
|
|
294
|
+
# Create authorization header
|
|
295
|
+
auth_header = base64.b64encode(
|
|
296
|
+
f'{self._client_id}:{self._client_secret}'.encode('utf-8')
|
|
297
|
+
).decode('utf-8')
|
|
298
|
+
|
|
299
|
+
headers = {
|
|
300
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
301
|
+
'Authorization': f'Basic {auth_header}',
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
data = {'grant_type': 'client_credentials'}
|
|
305
|
+
if self._scopes:
|
|
306
|
+
data['scope'] = ' '.join(self._scopes)
|
|
307
|
+
logger.debug(f'Using scopes: {data["scope"]}')
|
|
308
|
+
|
|
309
|
+
logger.debug(f'Making token request to: {token_endpoint}')
|
|
310
|
+
response = requests.post(token_endpoint, headers=headers, data=data)
|
|
311
|
+
|
|
312
|
+
if response.status_code != 200:
|
|
313
|
+
logger.error(f'Token request failed: {response.status_code} {response.text}')
|
|
314
|
+
raise InvalidCredentialsError(
|
|
315
|
+
'Failed to obtain token with client credentials',
|
|
316
|
+
{
|
|
317
|
+
'error': response.text,
|
|
318
|
+
'help': 'Check your client ID, client secret, domain, and region',
|
|
319
|
+
},
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
# Process the response
|
|
323
|
+
token_data = response.json()
|
|
324
|
+
access_token = token_data.get('access_token')
|
|
325
|
+
expires_in = token_data.get('expires_in', 3600)
|
|
326
|
+
|
|
327
|
+
if access_token:
|
|
328
|
+
self._token_expires_at = int(time.time()) + expires_in
|
|
329
|
+
logger.info(f'Successfully obtained access token (expires in {expires_in} seconds)')
|
|
330
|
+
return access_token
|
|
331
|
+
else:
|
|
332
|
+
logger.error('No access token in response')
|
|
333
|
+
return None
|
|
334
|
+
|
|
335
|
+
except Exception as e:
|
|
336
|
+
logger.error(f'Error in client credentials flow: {e}')
|
|
337
|
+
raise
|
|
338
|
+
|
|
339
|
+
def _get_token_password(self) -> Optional[str]:
|
|
340
|
+
"""Get a token using the password flow.
|
|
197
341
|
|
|
198
342
|
Returns:
|
|
199
|
-
str:
|
|
343
|
+
str: ID token or None if authentication fails
|
|
200
344
|
|
|
201
345
|
Raises:
|
|
202
346
|
AuthenticationError: If authentication fails
|
|
@@ -393,7 +393,6 @@ def main():
|
|
|
393
393
|
description='This project is a server that dynamically creates Model Context Protocol (MCP) tools and resources from OpenAPI specifications. It allows Large Language Models (LLMs) to interact with APIs through the Model Context Protocol.'
|
|
394
394
|
)
|
|
395
395
|
# Server configuration
|
|
396
|
-
parser.add_argument('--port', type=int, help='Port to run the server on')
|
|
397
396
|
parser.add_argument(
|
|
398
397
|
'--log-level',
|
|
399
398
|
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
|
|
@@ -439,6 +438,17 @@ def main():
|
|
|
439
438
|
'--auth-cognito-user-pool-id', help='User Pool ID for Cognito authentication'
|
|
440
439
|
)
|
|
441
440
|
parser.add_argument('--auth-cognito-region', help='AWS region for Cognito (default: us-east-1)')
|
|
441
|
+
parser.add_argument(
|
|
442
|
+
'--auth-cognito-client-secret',
|
|
443
|
+
help='Client secret for Cognito OAuth 2.0 client credentials flow',
|
|
444
|
+
)
|
|
445
|
+
parser.add_argument(
|
|
446
|
+
'--auth-cognito-domain', help='Domain prefix for Cognito OAuth 2.0 client credentials flow'
|
|
447
|
+
)
|
|
448
|
+
parser.add_argument(
|
|
449
|
+
'--auth-cognito-scopes',
|
|
450
|
+
help='Comma-separated list of scopes for Cognito OAuth 2.0 client credentials flow',
|
|
451
|
+
)
|
|
442
452
|
|
|
443
453
|
args = parser.parse_args()
|
|
444
454
|
|
{awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: awslabs.openapi-mcp-server
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: An AWS Labs Model Context Protocol (MCP) server for OpenAPI
|
|
5
5
|
Project-URL: Homepage, https://awslabs.github.io/mcp/
|
|
6
6
|
Project-URL: Documentation, https://awslabs.github.io/mcp/servers/openapi-mcp-server/
|
|
@@ -21,40 +21,40 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.13
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
|
-
Requires-Dist: bcrypt>=4.
|
|
25
|
-
Requires-Dist: boto3>=1.
|
|
26
|
-
Requires-Dist: cachetools>=
|
|
27
|
-
Requires-Dist: fastmcp>=
|
|
28
|
-
Requires-Dist: httpx>=0.
|
|
29
|
-
Requires-Dist: loguru>=0.7.
|
|
30
|
-
Requires-Dist: openapi-spec-validator>=0.
|
|
31
|
-
Requires-Dist: prance>=
|
|
32
|
-
Requires-Dist: pydantic>=2.
|
|
33
|
-
Requires-Dist: pyyaml>=6.0.
|
|
34
|
-
Requires-Dist: tenacity>=
|
|
35
|
-
Requires-Dist: typing-extensions>=4.
|
|
36
|
-
Requires-Dist: uvicorn>=0.
|
|
24
|
+
Requires-Dist: bcrypt>=4.3.0
|
|
25
|
+
Requires-Dist: boto3>=1.39.3
|
|
26
|
+
Requires-Dist: cachetools>=6.1.0
|
|
27
|
+
Requires-Dist: fastmcp>=2.10.2
|
|
28
|
+
Requires-Dist: httpx>=0.28.1
|
|
29
|
+
Requires-Dist: loguru>=0.7.3
|
|
30
|
+
Requires-Dist: openapi-spec-validator>=0.7.2
|
|
31
|
+
Requires-Dist: prance>=25.4.8.0
|
|
32
|
+
Requires-Dist: pydantic>=2.11.7
|
|
33
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
34
|
+
Requires-Dist: tenacity>=9.1.2
|
|
35
|
+
Requires-Dist: typing-extensions>=4.14.1
|
|
36
|
+
Requires-Dist: uvicorn>=0.35.0
|
|
37
37
|
Provides-Extra: all
|
|
38
38
|
Requires-Dist: prometheus-client>=0.17.0; extra == 'all'
|
|
39
39
|
Requires-Dist: pyyaml>=6.0.0; extra == 'all'
|
|
40
40
|
Provides-Extra: dev
|
|
41
|
-
Requires-Dist: commitizen>=4.
|
|
42
|
-
Requires-Dist: lxml>=
|
|
41
|
+
Requires-Dist: commitizen>=4.8.3; extra == 'dev'
|
|
42
|
+
Requires-Dist: lxml>=6.0.0; extra == 'dev'
|
|
43
43
|
Requires-Dist: pre-commit>=4.2.0; extra == 'dev'
|
|
44
|
-
Requires-Dist: pyright>=1.1.
|
|
45
|
-
Requires-Dist: pytest-asyncio>=0.
|
|
46
|
-
Requires-Dist: pytest-cov>=
|
|
47
|
-
Requires-Dist: pytest>=
|
|
48
|
-
Requires-Dist: ruff>=0.
|
|
44
|
+
Requires-Dist: pyright>=1.1.402; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest-asyncio>=1.0.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: pytest-cov>=6.2.1; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest>=8.4.1; extra == 'dev'
|
|
48
|
+
Requires-Dist: ruff>=0.12.2; extra == 'dev'
|
|
49
49
|
Provides-Extra: prometheus
|
|
50
|
-
Requires-Dist: prometheus-client>=0.
|
|
50
|
+
Requires-Dist: prometheus-client>=0.22.1; extra == 'prometheus'
|
|
51
51
|
Provides-Extra: test
|
|
52
|
-
Requires-Dist: pytest-asyncio>=0.
|
|
53
|
-
Requires-Dist: pytest-cov>=
|
|
54
|
-
Requires-Dist: pytest-mock>=3.
|
|
55
|
-
Requires-Dist: pytest>=
|
|
52
|
+
Requires-Dist: pytest-asyncio>=1.0.0; extra == 'test'
|
|
53
|
+
Requires-Dist: pytest-cov>=6.2.1; extra == 'test'
|
|
54
|
+
Requires-Dist: pytest-mock>=3.14.1; extra == 'test'
|
|
55
|
+
Requires-Dist: pytest>=8.4.1; extra == 'test'
|
|
56
56
|
Provides-Extra: yaml
|
|
57
|
-
Requires-Dist: pyyaml>=6.0.
|
|
57
|
+
Requires-Dist: pyyaml>=6.0.2; extra == 'yaml'
|
|
58
58
|
Description-Content-Type: text/markdown
|
|
59
59
|
|
|
60
60
|
# AWS Labs OpenAPI MCP Server
|
|
@@ -86,6 +86,10 @@ This project is a server that dynamically creates Model Context Protocol (MCP) t
|
|
|
86
86
|
|
|
87
87
|
## Installation
|
|
88
88
|
|
|
89
|
+
| Cursor | VS Code |
|
|
90
|
+
|:------:|:-------:|
|
|
91
|
+
| [](https://cursor.com/en/install-mcp?name=awslabs.openapi-mcp-server&config=eyJjb21tYW5kIjoidXZ4IGF3c2xhYnMub3BlbmFwaS1tY3Atc2VydmVyQGxhdGVzdCIsImVudiI6eyJBUElfTkFNRSI6InlvdXItYXBpLW5hbWUiLCJBUElfQkFTRV9VUkwiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbSIsIkFQSV9TUEVDX1VSTCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tL29wZW5hcGkuanNvbiIsIkxPR19MRVZFTCI6IkVSUk9SIiwiRU5BQkxFX1BST01FVEhFVVMiOiJmYWxzZSIsIkVOQUJMRV9PUEVSQVRJT05fUFJPTVBUUyI6InRydWUiLCJVVklDT1JOX1RJTUVPVVRfR1JBQ0VGVUxfU0hVVERPV04iOiI1LjAiLCJVVklDT1JOX0dSQUNFRlVMX1NIVVRET1dOIjoidHJ1ZSJ9LCJkaXNhYmxlZCI6ZmFsc2UsImF1dG9BcHByb3ZlIjpbXX0%3D) | [](https://insiders.vscode.dev/redirect/mcp/install?name=OpenAPI%20MCP%20Server&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.openapi-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22API_NAME%22%3A%22your-api-name%22%2C%22API_BASE_URL%22%3A%22https%3A%2F%2Fapi.example.com%22%2C%22API_SPEC_URL%22%3A%22https%3A%2F%2Fapi.example.com%2Fopenapi.json%22%2C%22LOG_LEVEL%22%3A%22ERROR%22%2C%22ENABLE_PROMETHEUS%22%3A%22false%22%2C%22ENABLE_OPERATION_PROMPTS%22%3A%22true%22%2C%22UVICORN_TIMEOUT_GRACEFUL_SHUTDOWN%22%3A%225.0%22%2C%22UVICORN_GRACEFUL_SHUTDOWN%22%3A%22true%22%7D%2C%22disabled%22%3Afalse%2C%22autoApprove%22%3A%5B%5D%7D) |
|
|
92
|
+
|
|
89
93
|
### From PyPI
|
|
90
94
|
|
|
91
95
|
```bash
|
|
@@ -174,7 +178,7 @@ awslabs.openapi-mcp-server --api-url https://api.example.com --spec-url https://
|
|
|
174
178
|
awslabs.openapi-mcp-server --api-url https://api.example.com --spec-url https://api.example.com/openapi.json --auth-type api_key --auth-api-key YOUR_API_KEY --auth-api-key-name X-API-Key --auth-api-key-in header # pragma: allowlist secret
|
|
175
179
|
```
|
|
176
180
|
|
|
177
|
-
For detailed information about authentication methods, configuration options, and examples, see [AUTHENTICATION.md](AUTHENTICATION.md).
|
|
181
|
+
For detailed information about authentication methods, configuration options, and examples, see [AUTHENTICATION.md](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/AUTHENTICATION.md).
|
|
178
182
|
|
|
179
183
|
### Local OpenAPI Specification
|
|
180
184
|
|
|
@@ -259,11 +263,11 @@ export AUTH_API_KEY_IN="header" # Where to place the API key (options: header,
|
|
|
259
263
|
|
|
260
264
|
The OpenAPI MCP Server includes comprehensive documentation to help you get started and make the most of its features:
|
|
261
265
|
|
|
262
|
-
- [**AUTHENTICATION.md**](AUTHENTICATION.md): Detailed information about authentication methods, configuration options, and troubleshooting
|
|
263
|
-
- [**DEPLOYMENT.md**](DEPLOYMENT.md): Guidelines for deploying the server in various environments, including Docker and AWS
|
|
264
|
-
- [**AWS_BEST_PRACTICES.md**](AWS_BEST_PRACTICES.md): AWS best practices implemented in the server for resilience, caching, and efficiency
|
|
265
|
-
- [**OBSERVABILITY.md**](OBSERVABILITY.md): Information about metrics, logging, and monitoring capabilities
|
|
266
|
-
- [**tests/README.md**](tests/README.md): Overview of the test structure and strategy
|
|
266
|
+
- [**AUTHENTICATION.md**](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/AUTHENTICATION.md): Detailed information about authentication methods, configuration options, and troubleshooting
|
|
267
|
+
- [**DEPLOYMENT.md**](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/DEPLOYMENT.md): Guidelines for deploying the server in various environments, including Docker and AWS
|
|
268
|
+
- [**AWS_BEST_PRACTICES.md**](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/AWS_BEST_PRACTICES.md): AWS best practices implemented in the server for resilience, caching, and efficiency
|
|
269
|
+
- [**OBSERVABILITY.md**](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/OBSERVABILITY.md): Information about metrics, logging, and monitoring capabilities
|
|
270
|
+
- [**tests/README.md**](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/tests/README.md): Overview of the test structure and strategy
|
|
267
271
|
|
|
268
272
|
## AWS Best Practices
|
|
269
273
|
|
|
@@ -273,7 +277,7 @@ The OpenAPI MCP Server implements AWS best practices for building resilient, obs
|
|
|
273
277
|
- **Resilience**: Patterns to handle transient failures and ensure high availability
|
|
274
278
|
- **Observability**: Comprehensive monitoring, metrics, and logging features
|
|
275
279
|
|
|
276
|
-
For detailed information about these features, including implementation details and configuration options, see [AWS_BEST_PRACTICES.md](AWS_BEST_PRACTICES.md).
|
|
280
|
+
For detailed information about these features, including implementation details and configuration options, see [AWS_BEST_PRACTICES.md](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/AWS_BEST_PRACTICES.md).
|
|
277
281
|
|
|
278
282
|
## Docker Deployment
|
|
279
283
|
|
|
@@ -299,7 +303,7 @@ docker run -p 8000:8000 \
|
|
|
299
303
|
openapi-mcp-server:latest
|
|
300
304
|
```
|
|
301
305
|
|
|
302
|
-
For detailed information about Docker deployment, AWS service integration, and transport considerations, see the [DEPLOYMENT.md](DEPLOYMENT.md) file.
|
|
306
|
+
For detailed information about Docker deployment, AWS service integration, and transport considerations, see the [DEPLOYMENT.md](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/DEPLOYMENT.md) file.
|
|
303
307
|
|
|
304
308
|
## Testing
|
|
305
309
|
|
|
@@ -331,7 +335,7 @@ The test suite covers:
|
|
|
331
335
|
5. **Metrics**: Tests for metrics collection and reporting
|
|
332
336
|
6. **OpenAPI Validation**: Tests for OpenAPI specification validation
|
|
333
337
|
|
|
334
|
-
For more information about the test structure and strategy, see the [tests/README.md](tests/README.md) file.
|
|
338
|
+
For more information about the test structure and strategy, see the [tests/README.md](https://github.com/awslabs/mcp/blob/main/src/openapi-mcp-server/tests/README.md) file.
|
|
335
339
|
|
|
336
340
|
## Instructions
|
|
337
341
|
|
{awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/RECORD
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
awslabs/__init__.py,sha256=WuqxdDgUZylWNmVoPKiK7qGsTB_G4UmuXIrJ-VBwDew,731
|
|
2
|
-
awslabs/openapi_mcp_server/__init__.py,sha256=
|
|
3
|
-
awslabs/openapi_mcp_server/server.py,sha256=
|
|
2
|
+
awslabs/openapi_mcp_server/__init__.py,sha256=0aJ0v_y0NpVNNAL-lNWFXzVQjlGi8q9HrvyU4GsoG30,2060
|
|
3
|
+
awslabs/openapi_mcp_server/server.py,sha256=C_uJoyhCwxe6ohCZZL04HqDCOzUDbJHtPc-dBuX8U18,21746
|
|
4
4
|
awslabs/openapi_mcp_server/api/__init__.py,sha256=KWcmd1bH1vact1QJBfR0zFX7knWhFrBgaMEe9Tu9qi0,774
|
|
5
|
-
awslabs/openapi_mcp_server/api/config.py,sha256=
|
|
5
|
+
awslabs/openapi_mcp_server/api/config.py,sha256=WT9ELzBOtZkd_DrzrkL_uuVoDibw2k94tU28CvHL32Q,9503
|
|
6
6
|
awslabs/openapi_mcp_server/auth/__init__.py,sha256=wDFPpe2PmaDVvlYSdzR4saSKthgQmVPr9lwaKe3Z2RE,1109
|
|
7
7
|
awslabs/openapi_mcp_server/auth/api_key_auth.py,sha256=VfnyTaMkVOpdYDKjjjEuJ3rBOmvWAkQgmoUxNn9_ftM,7107
|
|
8
8
|
awslabs/openapi_mcp_server/auth/auth_cache.py,sha256=bCLKBD5kMcD0XwoTa3hKD9TG9rZoEYBBzK0rvaaSWZ0,5256
|
|
@@ -13,7 +13,7 @@ awslabs/openapi_mcp_server/auth/auth_provider.py,sha256=z9OSkbxxIrOysxN4-L3D7ZLk
|
|
|
13
13
|
awslabs/openapi_mcp_server/auth/base_auth.py,sha256=9xkqh4GvQiD4jHH-_rqFa6tVOQaO_hNsEstkq0NzPMI,7021
|
|
14
14
|
awslabs/openapi_mcp_server/auth/basic_auth.py,sha256=3sdNEZYX3qnkINmpvNKWVqTx31X1eOwbWMvkQkOda2Y,6166
|
|
15
15
|
awslabs/openapi_mcp_server/auth/bearer_auth.py,sha256=KbX1GVeiI_-XNteM66jyRYilO461qXXg6mO5yyaDoG8,3769
|
|
16
|
-
awslabs/openapi_mcp_server/auth/cognito_auth.py,sha256=
|
|
16
|
+
awslabs/openapi_mcp_server/auth/cognito_auth.py,sha256=mKuQpKyKoqtxTa8FcJsER6BL8xvlODa6XwJLQ0Ki7y4,28529
|
|
17
17
|
awslabs/openapi_mcp_server/auth/register.py,sha256=p6rGLNSkbI-Y4KlSG24koMtS-4vvI_K0d5iZisVqLn0,4104
|
|
18
18
|
awslabs/openapi_mcp_server/patch/__init__.py,sha256=sks2igP1hnfrjYhQmW5e7UpOQ_ZQ_O3NK67lcQMRDa0,795
|
|
19
19
|
awslabs/openapi_mcp_server/prompts/__init__.py,sha256=exMV01HgSORPPbkPC7AZE2UqfrnK1INNW7nrv73wZ_4,783
|
|
@@ -30,9 +30,9 @@ awslabs/openapi_mcp_server/utils/http_client.py,sha256=a2wu7lfyuq1O_6ilaFQ9geFJy
|
|
|
30
30
|
awslabs/openapi_mcp_server/utils/metrics_provider.py,sha256=1R__ZUxUrrB5KoKx4q6WYWHhaDTpFnr0UWTgZO28HVI,17731
|
|
31
31
|
awslabs/openapi_mcp_server/utils/openapi.py,sha256=eRQUC5AidkyR1ALQNsR0kLXlr0Mq8ZXCduLVWUXXhuA,8802
|
|
32
32
|
awslabs/openapi_mcp_server/utils/openapi_validator.py,sha256=MVJj84a8vw0BUn21pfkav6oJagDF1dSotcLK9otXzE4,9614
|
|
33
|
-
awslabs_openapi_mcp_server-0.
|
|
34
|
-
awslabs_openapi_mcp_server-0.
|
|
35
|
-
awslabs_openapi_mcp_server-0.
|
|
36
|
-
awslabs_openapi_mcp_server-0.
|
|
37
|
-
awslabs_openapi_mcp_server-0.
|
|
38
|
-
awslabs_openapi_mcp_server-0.
|
|
33
|
+
awslabs_openapi_mcp_server-0.2.1.dist-info/METADATA,sha256=d45aQj7DUXGL6-Yz8i8lxjqOPJiJpZ17Nr_bqmm4is4,18552
|
|
34
|
+
awslabs_openapi_mcp_server-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
35
|
+
awslabs_openapi_mcp_server-0.2.1.dist-info/entry_points.txt,sha256=0BwvRNOdGm62ExFDks-9tSTWgtOdI3qmg-aemCMXQkM,86
|
|
36
|
+
awslabs_openapi_mcp_server-0.2.1.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
|
|
37
|
+
awslabs_openapi_mcp_server-0.2.1.dist-info/licenses/NOTICE,sha256=fG29aqEG3L4KHNXheKdyD5TdsgFh7eaaFlXu-okbf5o,94
|
|
38
|
+
awslabs_openapi_mcp_server-0.2.1.dist-info/RECORD,,
|
{awslabs_openapi_mcp_server-0.1.1.dist-info → awslabs_openapi_mcp_server-0.2.1.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|