Skip to content

Commit 6fde755

Browse files
author
Donato Azevedo
committed
fix: implement suggestions from scoschre on customizing run configuration
1 parent 98de341 commit 6fde755

File tree

4 files changed

+186
-5
lines changed

4 files changed

+186
-5
lines changed

src/openapi-mcp-server/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,13 @@ export SERVER_PORT=8000
209209
export SERVER_TRANSPORT="stdio" # Option: stdio, streamable-http
210210
export LOG_LEVEL="INFO" # Options: DEBUG, INFO, WARNING, ERROR, CRITICAL
211211

212+
# HTTP transport configuration
213+
export TRANSPORT="stdio" # Transport protocol: "stdio" (default) or "streamable-http"
214+
export MCP_PATH="/mcp" # Path for MCP remote connection URL (only used with streamable-http)
215+
export STATELESS_HTTP="true" # Enable stateless HTTP mode (only used with streamable-http)
216+
export JSON_RESPONSE="true" # Use JSON responses instead of SSE stream (only used with streamable-http)
217+
export FASTMCP_LOG_LEVEL="INFO" # FastMCP logging level: DEBUG, INFO, WARNING, ERROR, CRITICAL
218+
212219
# Metrics and monitoring configuration
213220
export ENABLE_PROMETHEUS="false" # Enable/disable Prometheus metrics (default: false)
214221
export PROMETHEUS_PORT=9090 # Port for Prometheus metrics server

src/openapi-mcp-server/awslabs/openapi_mcp_server/api/config.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,16 @@ class Config:
5353
host: str = '127.0.0.1'
5454
port: int = 8000
5555
debug: bool = False
56-
transport: str = 'stdio' # stdio only
56+
transport: str = 'stdio' # stdio or streamable-http
5757
message_timeout: int = 60
5858
version: str = '0.2.0'
5959

60+
# HTTP transport configuration
61+
mcp_path: str = '/mcp'
62+
stateless_http: bool = True
63+
json_response: bool = True
64+
fastmcp_log_level: str = 'INFO'
65+
6066

6167
def load_config(args: Any = None) -> Config:
6268
"""Load configuration from arguments and environment variables.
@@ -107,6 +113,12 @@ def load_config(args: Any = None) -> Config:
107113
'SERVER_DEBUG': (lambda v: setattr(config, 'debug', v.lower() == 'true')),
108114
'SERVER_TRANSPORT': (lambda v: setattr(config, 'transport', v)),
109115
'SERVER_MESSAGE_TIMEOUT': (lambda v: setattr(config, 'message_timeout', int(v))),
116+
# HTTP transport configuration
117+
'TRANSPORT': (lambda v: setattr(config, 'transport', v)),
118+
'MCP_PATH': (lambda v: setattr(config, 'mcp_path', v)),
119+
'STATELESS_HTTP': (lambda v: setattr(config, 'stateless_http', v.lower() == 'true')),
120+
'JSON_RESPONSE': (lambda v: setattr(config, 'json_response', v.lower() == 'true')),
121+
'FASTMCP_LOG_LEVEL': (lambda v: setattr(config, 'fastmcp_log_level', v)),
110122
}
111123

112124
# Load environment variables
@@ -140,6 +152,10 @@ def load_config(args: Any = None) -> Config:
140152
logger.debug(f'Setting API spec path from arguments: {args.spec_path}')
141153
config.api_spec_path = args.spec_path
142154

155+
if hasattr(args, 'host') and args.host:
156+
logger.debug(f'Setting host from arguments: {args.host}')
157+
config.host = args.host
158+
143159
if hasattr(args, 'port') and args.port:
144160
logger.debug(f'Setting port from arguments: {args.port}')
145161
config.port = args.port
@@ -148,6 +164,14 @@ def load_config(args: Any = None) -> Config:
148164
logger.debug('Setting debug mode from arguments')
149165
config.debug = True
150166

167+
if hasattr(args, 'transport') and args.transport:
168+
logger.debug(f'Setting transport from arguments: {args.transport}')
169+
config.transport = args.transport
170+
171+
if hasattr(args, 'mcp_path') and args.mcp_path:
172+
logger.debug(f'Setting MCP path from arguments: {args.mcp_path}')
173+
config.mcp_path = args.mcp_path
174+
151175
# Authentication arguments
152176
if hasattr(args, 'auth_type') and args.auth_type:
153177
logger.debug(f'Setting auth type from arguments: {args.auth_type}')

src/openapi-mcp-server/awslabs/openapi_mcp_server/server.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def create_mcp_server(config: Config) -> FastMCP:
5656
# Create the FastMCP server
5757
server = FastMCP(
5858
'awslabs.openapi-mcp-server',
59+
json_response=config.json_response,
5960
instructions='This server acts as a bridge between OpenAPI specifications and LLMs, allowing models to have a better understanding of available API capabilities without requiring manual tool definitions.',
6061
dependencies=[
6162
'pydantic',
@@ -200,6 +201,7 @@ def handle_auth_error(auth_type, error_message):
200201
client=client,
201202
name=config.api_name or 'OpenAPI MCP Server',
202203
route_maps=custom_mappings, # Custom mappings take precedence over default mappings
204+
json_response=config.json_response,
203205
)
204206

205207
# Log route information at debug level
@@ -450,6 +452,15 @@ def main():
450452
help='Comma-separated list of scopes for Cognito OAuth 2.0 client credentials flow',
451453
)
452454

455+
parser.add_argument(
456+
'--transport',
457+
help='Transport prototocol. stdio or streamable-http.',
458+
)
459+
460+
parser.add_argument('--host', help='Server host (default: 127.0.0.1)')
461+
parser.add_argument('--port', type=int, help='Server port (default: 8000)')
462+
parser.add_argument('--mcp-path', help='The path for the mcp server (default: /mcp)')
463+
453464
args = parser.parse_args()
454465

455466
# Set up logging with loguru at specified level
@@ -512,12 +523,22 @@ async def get_all_counts(server):
512523
logger.error(f'Traceback: {traceback.format_exc()}')
513524
sys.exit(1)
514525

526+
run_params = {}
515527
if config.transport == 'streamable-http':
516-
logger.info('Running server with streamable-http transport')
517-
mcp_server.run(transport='streamable-http', stateless_http=True, host='0.0.0.0')
528+
logger.info(
529+
f'Starting OpenAPI-MCP-SERVER on {config.host}:{config.port} with transport=streamable-http...'
530+
)
531+
run_params = {
532+
'host': config.host,
533+
'port': config.port,
534+
'path': config.mcp_path,
535+
'stateless_http': config.stateless_http,
536+
'log_level': config.fastmcp_log_level,
537+
}
518538
else:
519-
logger.info('Running server with stdio transport')
520-
mcp_server.run()
539+
logger.info('Starting OpenAPI-MCP-SERVER with transport=stdio...')
540+
541+
mcp_server.run(transport=config.transport, **run_params)
521542

522543

523544
if __name__ == '__main__':
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Tests for HTTP transport configuration."""
15+
16+
import os
17+
import pytest
18+
from unittest.mock import patch
19+
from awslabs.openapi_mcp_server.api.config import Config, load_config
20+
21+
22+
class TestConfigTransport:
23+
"""Test Config HTTP transport settings."""
24+
25+
def test_default_config_values(self):
26+
"""Test that default config values are correct for HTTP transport."""
27+
config = Config()
28+
29+
# Test default transport settings
30+
assert config.transport == 'stdio'
31+
assert config.mcp_path == '/mcp'
32+
assert config.stateless_http == True
33+
assert config.json_response == True
34+
assert config.fastmcp_log_level == 'INFO'
35+
36+
@patch.dict(
37+
os.environ,
38+
{
39+
'TRANSPORT': 'streamable-http',
40+
'MCP_PATH': '/custom-mcp',
41+
'STATELESS_HTTP': 'false',
42+
'JSON_RESPONSE': 'false',
43+
'FASTMCP_LOG_LEVEL': 'DEBUG',
44+
},
45+
clear=True,
46+
)
47+
def test_env_var_overrides(self):
48+
"""Test that environment variables override default values."""
49+
config = load_config()
50+
51+
assert config.transport == 'streamable-http'
52+
assert config.mcp_path == '/custom-mcp'
53+
assert config.stateless_http == False
54+
assert config.json_response == False
55+
assert config.fastmcp_log_level == 'DEBUG'
56+
57+
@patch.dict(
58+
os.environ,
59+
{
60+
'SERVER_HOST': '0.0.0.0',
61+
'SERVER_PORT': '9000',
62+
'TRANSPORT': 'streamable-http',
63+
},
64+
clear=True,
65+
)
66+
def test_existing_server_env_vars(self):
67+
"""Test that existing SERVER_HOST and SERVER_PORT work with new transport."""
68+
config = load_config()
69+
70+
assert config.host == '0.0.0.0'
71+
assert config.port == 9000
72+
assert config.transport == 'streamable-http'
73+
74+
@patch.dict(
75+
os.environ,
76+
{
77+
'SERVER_TRANSPORT': 'streamable-http',
78+
'TRANSPORT': 'stdio',
79+
},
80+
clear=True,
81+
)
82+
def test_both_transport_env_vars(self):
83+
"""Test that both SERVER_TRANSPORT and TRANSPORT can set transport."""
84+
# TRANSPORT should take precedence as it's processed later
85+
config = load_config()
86+
87+
assert config.transport == 'stdio'
88+
89+
@patch.dict(os.environ, {'STATELESS_HTTP': 'invalid'}, clear=True)
90+
def test_boolean_parsing(self):
91+
"""Test boolean environment variable parsing."""
92+
config = load_config()
93+
94+
# Invalid boolean should default to False
95+
assert config.stateless_http == False
96+
97+
@patch.dict(os.environ, {'STATELESS_HTTP': 'TRUE'}, clear=True)
98+
def test_boolean_parsing_case_insensitive(self):
99+
"""Test boolean parsing is case insensitive."""
100+
config = load_config()
101+
102+
assert config.stateless_http == True
103+
104+
def test_config_with_args(self):
105+
"""Test config loading with command line arguments."""
106+
107+
class MockArgs:
108+
def __init__(self):
109+
self.api_name = 'test-api'
110+
self.debug = True
111+
self.host = '0.0.0.0'
112+
self.port = 9999
113+
self.transport = 'streamable-http'
114+
self.mcp_path = '/custom-mcp'
115+
116+
args = MockArgs()
117+
config = load_config(args)
118+
119+
assert config.api_name == 'test-api'
120+
assert config.debug == True
121+
assert config.mcp_path == '/custom-mcp'
122+
assert config.transport == 'streamable-http'
123+
assert config.host == '0.0.0.0'
124+
assert config.port == 9999
125+
126+
# HTTP transport settings should keep defaults
127+
assert config.stateless_http == True
128+
assert config.json_response == True
129+
assert config.fastmcp_log_level == 'INFO'

0 commit comments

Comments
 (0)