Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions src/oci-api-mcp-server/oracle/oci_api_mcp_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,30 @@ def run_oci_command(
check=True,
shell=False,
)
return (
json.loads(result.stdout)
if result.stdout
else {
"error": result.stderr,
}
)

result.check_returncode()

response = {
"command": command,
"output": result.stdout,
"error": result.stderr,
"returncode": result.returncode,
}

try:
response["output"] = json.loads(result.stdout)
except TypeError:
pass
except json.JSONDecodeError:
pass

return response
except subprocess.CalledProcessError as e:
return {
"error": e.stderr,
"command": command,
"output": e.stdout,
"error": e.stderr,
"returncode": e.returncode,
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import importlib.metadata
import json
import subprocess
from unittest.mock import ANY, MagicMock, patch

Expand Down Expand Up @@ -72,47 +73,77 @@ async def test_get_oci_command_help_failure(self, mock_run):

@pytest.mark.asyncio
@patch("oracle.oci_api_mcp_server.server.subprocess.run")
@patch("oracle.oci_api_mcp_server.server.json.loads")
async def test_run_oci_command_success(self, mock_json_loads, mock_run):
async def test_run_oci_command_success(self, mock_run):
command = "compute instance list"

mock_result = MagicMock()
mock_result.stdout = '{"key": "value"}'
mock_result.stderr = ""
mock_result.returncode = 0
mock_run.return_value = mock_result
mock_json_loads.return_value = {"key": "value"}

async with Client(mcp) as client:
result = (
await client.call_tool(
"run_oci_command", {"command": "compute instance list"}
)
await client.call_tool("run_oci_command", {"command": command})
).data

assert result == {
"command": command,
"output": json.loads(mock_result.stdout),
"error": mock_result.stderr,
"returncode": mock_result.returncode,
}

@pytest.mark.asyncio
@patch("oracle.oci_api_mcp_server.server.subprocess.run")
async def test_run_oci_command_string_success(self, mock_run):
command = "compute instance list"

mock_result = MagicMock()
mock_result.stdout = "This is not JSON"
mock_result.stderr = ""
mock_result.returncode = 0
mock_run.return_value = mock_result

async with Client(mcp) as client:
result = (
await client.call_tool("run_oci_command", {"command": command})
).data

assert result == {"key": "value"}
mock_json_loads.assert_called_once_with('{"key": "value"}')
assert result == {
"command": command,
"output": mock_result.stdout,
"error": mock_result.stderr,
"returncode": mock_result.returncode,
}

@pytest.mark.asyncio
@patch("oracle.oci_api_mcp_server.server.subprocess.run")
async def test_run_oci_command_failure(self, mock_run):
command = "compute instance list"

mock_result = MagicMock()
mock_result.stdout = "Some output"
mock_result.stderr = "Some error"
mock_result.returncode = 1

mock_run.side_effect = subprocess.CalledProcessError(
returncode=1,
cmd=["oci", "compute", "instance", "list"],
returncode=mock_result.returncode,
cmd=["oci"] + command.split(),
output=mock_result.stdout,
stderr=mock_result.stderr,
)

async with Client(mcp) as client:
result = (
await client.call_tool(
"run_oci_command", {"command": "compute instance list"}
)
await client.call_tool("run_oci_command", {"command": command})
).data

assert result == {
"error": "Some error",
"output": "Some output",
"command": command,
"output": mock_result.stdout,
"error": mock_result.stderr,
"returncode": mock_result.returncode,
}

@pytest.mark.asyncio
Expand Down