Skip to content

Commit 7334633

Browse files
Nayana-R-GowdaNAYANAR0502crivetimihai
authored
452Remove-Integration-Type (#678)
* Remove Integration Type: MCP Signed-off-by: NAYANAR <[email protected]> * testcase fixed Signed-off-by: NAYANAR <[email protected]> * Fix validation logic and tests after MCP integration type removal - Update ToolCreate and ToolUpdate validation to only accept REST integration type - Fix test cases that still referenced MCP integration type - Update mock return values and assertions in test files - Ensure all doctests pass with REST-only validation - Maintain full test suite compatibility All tests now pass: 1307 passed, 10 skipped --------- Signed-off-by: NAYANAR <[email protected]> Co-authored-by: NAYANAR <[email protected]> Co-authored-by: Mihai Criveti <[email protected]>
1 parent a90df79 commit 7334633

File tree

8 files changed

+124
-86
lines changed

8 files changed

+124
-86
lines changed

docs/docs/testing/basic.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ curl -s -k -X POST $BASE_URL/tools \
119119
"url": "'"$LOCAL_MCP_TOOL_URL"'",
120120
"description": "Returns current time",
121121
"request_type": "POST",
122-
"integration_type": "MCP",
122+
"integration_type": "REST",
123123
"input_schema": {
124124
"type": "object",
125125
"properties": {

mcpgateway/admin.py

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,8 +1835,8 @@ async def admin_add_tool(
18351835
>>> form_data_success = FormData([
18361836
... ("name", "New_Tool"),
18371837
... ("url", "http://new.tool.com"),
1838-
... ("requestType", "SSE"),
1839-
... ("integrationType", "MCP"),
1838+
... ("requestType", "GET"),
1839+
... ("integrationType", "REST"),
18401840
... ("headers", '{"X-Api-Key": "abc"}')
18411841
... ])
18421842
>>> mock_request_success = MagicMock(spec=Request)
@@ -1855,8 +1855,8 @@ async def admin_add_tool(
18551855
>>> form_data_conflict = FormData([
18561856
... ("name", "Existing_Tool"),
18571857
... ("url", "http://existing.com"),
1858-
... ("requestType", "SSE"),
1859-
... ("integrationType", "MCP")
1858+
... ("requestType", "GET"),
1859+
... ("integrationType", "REST")
18601860
... ])
18611861
>>> mock_request_conflict = MagicMock(spec=Request)
18621862
>>> mock_request_conflict.form = AsyncMock(return_value=form_data_conflict)
@@ -1873,8 +1873,8 @@ async def admin_add_tool(
18731873
>>> # Error path: Missing required field (Pydantic ValidationError)
18741874
>>> form_data_missing = FormData([
18751875
... ("url", "http://missing.com"),
1876-
... ("requestType", "SSE"),
1877-
... ("integrationType", "MCP")
1876+
... ("requestType", "GET"),
1877+
... ("integrationType", "REST")
18781878
... ])
18791879
>>> mock_request_missing = MagicMock(spec=Request)
18801880
>>> mock_request_missing.form = AsyncMock(return_value=form_data_missing)
@@ -1890,8 +1890,8 @@ async def admin_add_tool(
18901890
>>> form_data_generic_error = FormData([
18911891
... ("name", "Generic_Error_Tool"),
18921892
... ("url", "http://generic.com"),
1893-
... ("requestType", "SSE"),
1894-
... ("integrationType", "MCP")
1893+
... ("requestType", "GET"),
1894+
... ("integrationType", "REST")
18951895
... ])
18961896
>>> mock_request_generic_error = MagicMock(spec=Request)
18971897
>>> mock_request_generic_error.form = AsyncMock(return_value=form_data_generic_error)
@@ -1912,6 +1912,17 @@ async def admin_add_tool(
19121912
form = await request.form()
19131913
logger.debug(f"Received form data: {dict(form)}")
19141914

1915+
integration_type = form.get("integrationType", "REST")
1916+
request_type = form.get("requestType")
1917+
1918+
if request_type is None:
1919+
if integration_type == "REST":
1920+
request_type = "GET" # or any valid REST method default
1921+
elif integration_type == "MCP":
1922+
request_type = "SSE"
1923+
else:
1924+
request_type = "GET"
1925+
19151926
# Parse tags from comma-separated string
19161927
tags_str = form.get("tags", "")
19171928
tags = [tag.strip() for tag in tags_str.split(",") if tag.strip()] if tags_str else []
@@ -1920,8 +1931,8 @@ async def admin_add_tool(
19201931
"name": form.get("name"),
19211932
"url": form.get("url"),
19221933
"description": form.get("description"),
1923-
"request_type": form.get("requestType", "SSE"),
1924-
"integration_type": form.get("integrationType", "MCP"),
1934+
"request_type": request_type,
1935+
"integration_type": integration_type,
19251936
"headers": json.loads(form.get("headers") or "{}"),
19261937
"input_schema": json.loads(form.get("input_schema") or "{}"),
19271938
"jsonpath_filter": form.get("jsonpath_filter", ""),
@@ -1949,6 +1960,7 @@ async def admin_add_tool(
19491960
except ToolError as ex:
19501961
return JSONResponse(content={"message": str(ex), "success": False}, status_code=500)
19511962
except ValidationError as ex: # This block should catch ValidationError
1963+
19521964
logger.error(f"ValidationError in admin_add_tool: {str(ex)}")
19531965
return JSONResponse(content=ErrorFormatter.format_validation_error(ex), status_code=422)
19541966
except Exception as ex:
@@ -2018,9 +2030,11 @@ async def admin_edit_tool(
20182030
>>> form_data_success = FormData([
20192031
... ("name", "Updated_Tool"),
20202032
... ("url", "http://updated.com"),
2021-
... ("is_inactive_checked", "false"),
2022-
... ("requestType", "SSE"),
2023-
... ("integrationType", "MCP")
2033+
... ("requestType", "GET"),
2034+
... ("integrationType", "REST"),
2035+
... ("headers", '{"X-Api-Key": "abc"}'),
2036+
... ("input_schema", '{}'), # ✅ Required field
2037+
... ("description", "Sample tool")
20242038
... ])
20252039
>>> mock_request_success = MagicMock(spec=Request, scope={"root_path": ""})
20262040
>>> mock_request_success.form = AsyncMock(return_value=form_data_success)
@@ -2039,8 +2053,8 @@ async def admin_edit_tool(
20392053
... ("name", "Inactive_Edit"),
20402054
... ("url", "http://inactive.com"),
20412055
... ("is_inactive_checked", "true"),
2042-
... ("requestType", "SSE"),
2043-
... ("integrationType", "MCP")
2056+
... ("requestType", "GET"),
2057+
... ("integrationType", "REST")
20442058
... ])
20452059
>>> mock_request_inactive = MagicMock(spec=Request, scope={"root_path": "/api"})
20462060
>>> mock_request_inactive.form = AsyncMock(return_value=form_data_inactive)
@@ -2056,8 +2070,8 @@ async def admin_edit_tool(
20562070
>>> form_data_conflict = FormData([
20572071
... ("name", "Conflicting_Name"),
20582072
... ("url", "http://conflict.com"),
2059-
... ("requestType", "SSE"),
2060-
... ("integrationType", "MCP")
2073+
... ("requestType", "GET"),
2074+
... ("integrationType", "REST")
20612075
... ])
20622076
>>> mock_request_conflict = MagicMock(spec=Request, scope={"root_path": ""})
20632077
>>> mock_request_conflict.form = AsyncMock(return_value=form_data_conflict)
@@ -2074,8 +2088,8 @@ async def admin_edit_tool(
20742088
>>> form_data_tool_error = FormData([
20752089
... ("name", "Tool_Error"),
20762090
... ("url", "http://toolerror.com"),
2077-
... ("requestType", "SSE"),
2078-
... ("integrationType", "MCP")
2091+
... ("requestType", "GET"),
2092+
... ("integrationType", "REST")
20792093
... ])
20802094
>>> mock_request_tool_error = MagicMock(spec=Request, scope={"root_path": ""})
20812095
>>> mock_request_tool_error.form = AsyncMock(return_value=form_data_tool_error)
@@ -2092,8 +2106,8 @@ async def admin_edit_tool(
20922106
>>> form_data_validation_error = FormData([
20932107
... ("name", "Bad_URL"),
20942108
... ("url", "not-a-valid-url"),
2095-
... ("requestType", "SSE"),
2096-
... ("integrationType", "MCP")
2109+
... ("requestType", "GET"),
2110+
... ("integrationType", "REST")
20972111
... ])
20982112
>>> mock_request_validation_error = MagicMock(spec=Request, scope={"root_path": ""})
20992113
>>> mock_request_validation_error.form = AsyncMock(return_value=form_data_validation_error)
@@ -2109,8 +2123,8 @@ async def admin_edit_tool(
21092123
>>> form_data_unexpected = FormData([
21102124
... ("name", "Crash_Tool"),
21112125
... ("url", "http://crash.com"),
2112-
... ("requestType", "SSE"),
2113-
... ("integrationType", "MCP")
2126+
... ("requestType", "GET"),
2127+
... ("integrationType", "REST")
21142128
... ])
21152129
>>> mock_request_unexpected = MagicMock(spec=Request, scope={"root_path": ""})
21162130
>>> mock_request_unexpected.form = AsyncMock(return_value=form_data_unexpected)
@@ -2139,7 +2153,7 @@ async def admin_edit_tool(
21392153
"url": form.get("url"),
21402154
"description": form.get("description"),
21412155
"request_type": form.get("requestType", "SSE"),
2142-
"integration_type": form.get("integrationType", "MCP"),
2156+
"integration_type": form.get("integrationType", "REST"),
21432157
"headers": json.loads(form.get("headers") or "{}"),
21442158
"input_schema": json.loads(form.get("input_schema") or "{}"),
21452159
"jsonpath_filter": form.get("jsonpathFilter", ""),

mcpgateway/schemas.py

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,8 @@ class ToolCreate(BaseModel):
294294
name (str): Unique name for the tool.
295295
url (Union[str, AnyHttpUrl]): Tool endpoint URL.
296296
description (Optional[str]): Tool description.
297-
integration_type (Literal["MCP", "REST"]): Tool integration type. 'MCP' for MCP-compliant tools, 'REST' for REST integrations.
298-
request_type (Literal["GET", "POST", "PUT", "DELETE", "SSE", "STDIO", "STREAMABLEHTTP"]): HTTP method to be used for invoking the tool.
297+
integration_type (Literal["REST"]): Tool integration type for REST integrations.
298+
request_type (Literal["GET", "POST", "PUT", "DELETE", "PATCH"]): HTTP method to be used for invoking the tool.
299299
headers (Optional[Dict[str, str]]): Additional headers to send when invoking the tool.
300300
input_schema (Optional[Dict[str, Any]]): JSON Schema for validating tool parameters. Alias 'inputSchema'.
301301
annotations (Optional[Dict[str, Any]]): Tool annotations for behavior hints such as title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint.
@@ -309,7 +309,7 @@ class ToolCreate(BaseModel):
309309
name: str = Field(..., description="Unique name for the tool")
310310
url: Union[str, AnyHttpUrl] = Field(None, description="Tool endpoint URL")
311311
description: Optional[str] = Field(None, description="Tool description")
312-
integration_type: Literal["MCP", "REST"] = Field("MCP", description="Tool integration type: 'MCP' for MCP-compliant tools, 'REST' for REST integrations")
312+
integration_type: Literal["REST"] = Field("REST", description="'REST' for REST integrations")
313313
request_type: Literal["GET", "POST", "PUT", "DELETE", "PATCH", "SSE", "STDIO", "STREAMABLEHTTP"] = Field("SSE", description="HTTP method to be used for invoking the tool")
314314
headers: Optional[Dict[str, str]] = Field(None, description="Additional headers to send when invoking the tool")
315315
input_schema: Optional[Dict[str, Any]] = Field(default_factory=lambda: {"type": "object", "properties": {}}, description="JSON Schema for validating tool parameters", alias="inputSchema")
@@ -447,11 +447,11 @@ def validate_request_type(cls, v: str, info: ValidationInfo) -> str:
447447
ValueError: When value is unsafe
448448
449449
Examples:
450-
>>> # Test MCP integration types
450+
>>> # Test REST integration types with valid method
451451
>>> from pydantic import ValidationInfo
452-
>>> info = type('obj', (object,), {'data': {'integration_type': 'MCP'}})
453-
>>> ToolCreate.validate_request_type('SSE', info)
454-
'SSE'
452+
>>> info = type('obj', (object,), {'data': {'integration_type': 'REST'}})
453+
>>> ToolCreate.validate_request_type('POST', info)
454+
'POST'
455455
456456
>>> # Test REST integration types
457457
>>> info = type('obj', (object,), {'data': {'integration_type': 'REST'}})
@@ -467,24 +467,24 @@ def validate_request_type(cls, v: str, info: ValidationInfo) -> str:
467467
... "not allowed for REST" in str(e)
468468
True
469469
470-
>>> # Test invalid MCP type
471-
>>> info = type('obj', (object,), {'data': {'integration_type': 'MCP'}})
470+
>>> # Test invalid integration type
471+
>>> info = type('obj', (object,), {'data': {'integration_type': 'INVALID'}})
472472
>>> try:
473473
... ToolCreate.validate_request_type('GET', info)
474474
... except ValueError as e:
475-
... "not allowed for MCP" in str(e)
475+
... "Unknown integration type" in str(e)
476476
True
477477
"""
478-
data = info.data
479-
integration_type = data.get("integration_type")
480478

481-
if integration_type == "MCP":
482-
allowed = ["SSE", "STREAMABLEHTTP", "STDIO"]
483-
else: # REST
484-
allowed = ["GET", "POST", "PUT", "DELETE", "PATCH"]
479+
integration_type = info.data.get("integration_type")
485480

481+
if integration_type != "REST":
482+
raise ValueError(f"Unknown integration type: {integration_type}")
483+
484+
allowed = ["GET", "POST", "PUT", "DELETE", "PATCH"]
486485
if v not in allowed:
487-
raise ValueError(f"Request type '{v}' not allowed for {integration_type} integration")
486+
raise ValueError(f"Request type '{v}' not allowed for REST. Only {allowed} methods are accepted.")
487+
488488
return v
489489

490490
@model_validator(mode="before")
@@ -565,8 +565,8 @@ class ToolUpdate(BaseModelWithConfigDict):
565565
name: Optional[str] = Field(None, description="Unique name for the tool")
566566
url: Optional[Union[str, AnyHttpUrl]] = Field(None, description="Tool endpoint URL")
567567
description: Optional[str] = Field(None, description="Tool description")
568-
integration_type: Optional[Literal["MCP", "REST"]] = Field(None, description="Tool integration type")
569-
request_type: Optional[Literal["GET", "POST", "PUT", "DELETE", "PATCH", "SSE", "STDIO", "STREAMABLEHTTP"]] = Field(None, description="HTTP method to be used for invoking the tool")
568+
integration_type: Optional[Literal["REST"]] = Field(None, description="Tool integration type")
569+
request_type: Optional[Literal["GET", "POST", "PUT", "DELETE", "PATCH"]] = Field(None, description="HTTP method to be used for invoking the tool")
570570
headers: Optional[Dict[str, str]] = Field(None, description="Additional headers to send when invoking the tool")
571571
input_schema: Optional[Dict[str, Any]] = Field(None, description="JSON Schema for validating tool parameters")
572572
annotations: Optional[Dict[str, Any]] = Field(None, description="Tool annotations for behavior hints")
@@ -677,11 +677,8 @@ def validate_request_type(cls, v: str, values: Dict[str, Any]) -> str:
677677
ValueError: When value is unsafe
678678
"""
679679

680-
integration_type = values.data.get("integration_type", "MCP")
681-
if integration_type == "MCP":
682-
allowed = ["SSE", "STREAMABLEHTTP", "STDIO"]
683-
else: # REST
684-
allowed = ["GET", "POST", "PUT", "DELETE", "PATCH"]
680+
integration_type = values.data.get("integration_type", "REST")
681+
allowed = ["GET", "POST", "PUT", "DELETE", "PATCH"]
685682

686683
if v not in allowed:
687684
raise ValueError(f"Request type '{v}' not allowed for {integration_type} integration")

mcpgateway/templates/admin.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ <h3 class="text-lg font-bold mb-4 dark:text-gray-200">
10021002
class="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300"
10031003
onchange="updateRequestTypeOptions()"
10041004
>
1005-
<option value="MCP">MCP</option>
1005+
10061006
<option value="REST">REST</option>
10071007
</select>
10081008
</div>
@@ -2676,7 +2676,7 @@ <h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">
26762676
id="edit-tool-type"
26772677
class="mt-1 block w-full rounded-md border border-gray-300 dark:border-gray-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 dark:placeholder-gray-300 dark:text-gray-300"
26782678
>
2679-
<option value="MCP">MCP</option>
2679+
26802680
<option value="REST">REST</option>
26812681
</select>
26822682
</div>

tests/security/test_input_validation.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -495,12 +495,12 @@ def test_tool_create_request_type_validation(self):
495495
"""Test request type validation based on integration type."""
496496
logger.debug("Testing tool request type validation")
497497

498-
# MCP integration types
499-
mcp_valid = ["SSE", "STREAMABLEHTTP", "STDIO"]
500-
for req_type in mcp_valid:
501-
logger.debug(f"Testing MCP request type: {req_type}")
502-
tool = ToolCreate(name=self.VALID_TOOL_NAME, url=self.VALID_URL, integration_type="MCP", request_type=req_type)
503-
assert tool.request_type == req_type
498+
# # MCP integration types
499+
# mcp_valid = ["SSE", "STREAMABLEHTTP", "STDIO"]
500+
# for req_type in mcp_valid:
501+
# logger.debug(f"Testing MCP request type: {req_type}")
502+
# tool = ToolCreate(name=self.VALID_TOOL_NAME, url=self.VALID_URL, integration_type="MCP", request_type=req_type)
503+
# assert tool.request_type == req_type
504504

505505
# REST integration types
506506
rest_valid = ["GET", "POST", "PUT", "DELETE", "PATCH"]
@@ -1738,7 +1738,7 @@ def test_optional_field_defaults(self):
17381738

17391739
# Check defaults
17401740
assert tool.description is None
1741-
assert tool.integration_type == "MCP"
1741+
assert tool.integration_type == "REST"
17421742
assert tool.request_type == "SSE"
17431743
assert tool.headers is None or tool.headers == {}
17441744
assert tool.input_schema is not None # Has default

tests/unit/mcpgateway/services/test_gateway_service.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,8 @@ async def test_register_gateway_with_tools(self, gateway_service, test_db, monke
311311
ToolCreate(
312312
name="test_tool",
313313
description="A test tool",
314-
integration_type="MCP",
315-
request_type="SSE",
314+
integration_type="REST",
315+
request_type="POST",
316316
input_schema={"type": "object"}
317317
)
318318
]
@@ -555,8 +555,8 @@ async def test_register_gateway_with_existing_tools(self, gateway_service, test_
555555
ToolCreate(
556556
name="existing_tool", # This tool already exists
557557
description="An existing tool",
558-
integration_type="MCP",
559-
request_type="SSE",
558+
integration_type="REST",
559+
request_type="POST",
560560
input_schema={"type": "object"}
561561
)
562562
]
@@ -1010,15 +1010,15 @@ async def test_update_gateway_url_change_with_tools(self, gateway_service, mock_
10101010
ToolCreate(
10111011
name="existing_tool",
10121012
description="Updated tool",
1013-
integration_type="MCP",
1014-
request_type="SSE",
1013+
integration_type="REST",
1014+
request_type="POST",
10151015
input_schema={"type": "object"}
10161016
),
10171017
ToolCreate(
10181018
name="new_tool",
10191019
description="Brand new tool",
1020-
integration_type="MCP",
1021-
request_type="SSE",
1020+
integration_type="REST",
1021+
request_type="POST",
10221022
input_schema={"type": "object"}
10231023
)
10241024
]

0 commit comments

Comments
 (0)