Skip to content

Commit ddfdb45

Browse files
committed
initial commit
Signed-off-by: Richard Gebhardt <[email protected]>
1 parent 678141d commit ddfdb45

File tree

6 files changed

+187
-0
lines changed

6 files changed

+187
-0
lines changed

mcphost.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"mcpServers": {
3+
"oci_compute": {
4+
"type": "remote",
5+
"transport": "sse",
6+
"url": "http://localhost:8000/sse"
7+
},
8+
"oci_networking": {
9+
"type": "remote",
10+
"transport": "sse",
11+
"url": "http://localhost:8001/sse",
12+
"excludedTools": [
13+
"terminate_instance"
14+
]
15+
}
16+
}
17+
}

oci_compute.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import argparse
2+
from logging import Logger
3+
4+
import oci
5+
from fastmcp import FastMCP
6+
7+
logger = Logger("oci_compute_mcp", level="INFO")
8+
9+
mcp = FastMCP("oci_compute")
10+
11+
12+
def get_compute_client():
13+
logger.info("entering get_compute_client")
14+
config = oci.config.from_file()
15+
return oci.core.ComputeClient(config)
16+
17+
18+
@mcp.tool
19+
def list_instances(compartment_id: str):
20+
compute = get_compute_client()
21+
instances = compute.list_instances(compartment_id).data
22+
return [
23+
{
24+
"instance_id": inst.id,
25+
"display_name": inst.display_name,
26+
"lifecycle_state": inst.lifecycle_state,
27+
"shape": inst.shape,
28+
}
29+
for inst in instances
30+
]
31+
32+
33+
@mcp.tool
34+
def launch_instance(
35+
compartment_id: str,
36+
display_name: str,
37+
availability_domain: str,
38+
shape: str,
39+
image_id: str,
40+
subnet_id: str,
41+
):
42+
compute = get_compute_client()
43+
launch_details = oci.core.models.LaunchInstanceDetails(
44+
compartment_id=compartment_id,
45+
display_name=display_name,
46+
availability_domain=availability_domain,
47+
shape=shape,
48+
image_id=image_id,
49+
subnet_id=subnet_id,
50+
)
51+
instance = compute.launch_instance(launch_details).data
52+
return {
53+
"id": instance.id,
54+
"display_name": instance.display_name,
55+
"lifecycle_state": instance.lifecycle_state,
56+
}
57+
58+
59+
@mcp.tool
60+
def get_instance(instance_id: str):
61+
compute = get_compute_client()
62+
return compute.get_instance(instance_id).data
63+
64+
65+
# @mcp.tool
66+
# def terminate_instance(instance_id: str):
67+
# compute = get_compute_client()
68+
# response = compute.terminate_instance(instance_id)
69+
# return {
70+
# "status": "terminated",
71+
# "opc_request_id": response.headers.get("opc-request-id"),
72+
# }
73+
74+
75+
@mcp.tool
76+
def instance_action(instance_id: str, action: str):
77+
compute = get_compute_client()
78+
response = compute.instance_action(instance_id, action)
79+
return {"status": action, "opc_request_id": response.headers.get("opc-request-id")}
80+
81+
82+
if __name__ == "__main__":
83+
parser = argparse.ArgumentParser(
84+
description="Oracle Cloud Infrastructure Compute MCP server"
85+
)
86+
parser.add_argument("port", type=int, help="port number")
87+
88+
args = parser.parse_args()
89+
90+
# MCP spec: OpenAPI exposed at /openapi.json, native MCP at /mcp/v1
91+
# mcp.run(transport="http", host="127.0.0.1", port=8000, path="/mcp")
92+
93+
mcp.run(transport="sse", host="127.0.0.1", port=args.port)

oci_networking.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import argparse
2+
from logging import Logger
3+
4+
import oci
5+
from fastmcp import FastMCP
6+
7+
logger = Logger("oci_compute_mcp", level="INFO")
8+
9+
mcp = FastMCP("oci_compute")
10+
11+
12+
def get_networking_client():
13+
# Assumes you have ~/.oci/config with [DEFAULT] set up
14+
config = oci.config.from_file("~/.oci/config")
15+
return oci.core.VirtualNetworkClient(config)
16+
17+
18+
@mcp.tool
19+
def list_vcns(compartment_id: str):
20+
networking = get_networking_client()
21+
vcns = networking.list_vcns(compartment_id).data
22+
return [
23+
{
24+
"vcn_id": vcn.id,
25+
"display_name": vcn.display_name,
26+
"lifecycle_state": vcn.lifecycle_state,
27+
}
28+
for vcn in vcns
29+
]
30+
31+
32+
@mcp.tool
33+
def get_vcn(vcn_id: str):
34+
networking = get_networking_client()
35+
return networking.get_vcn(vcn_id).data
36+
37+
38+
@mcp.tool
39+
def delete_vcn(vcn_id: str):
40+
networking = get_networking_client()
41+
return networking.delete_vcn(vcn_id).data
42+
43+
44+
if __name__ == "__main__":
45+
parser = argparse.ArgumentParser(
46+
description="Oracle Cloud Infrastructure Networking MCP server"
47+
)
48+
parser.add_argument("port", type=int, help="port number")
49+
50+
args = parser.parse_args()
51+
# MCP spec: OpenAPI exposed at /openapi.json, native MCP at /mcp/v1
52+
# mcp.run(transport="http", host="127.0.0.1", port=8000, path="/mcp")
53+
mcp.run(transport="sse", host="127.0.0.1", port=args.port)

requirements-dev.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-r requirements.txt
2+
tox

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fastmcp
2+
oci

tox.ini

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[tox]
2+
isolated_build = True
3+
4+
[flake8]
5+
; to match Black
6+
max-line-length = 88
7+
8+
[testenv:linters]
9+
deps =
10+
black
11+
flake8
12+
isort
13+
json-lint-tools
14+
setenv =
15+
PYTHON = python3
16+
commands =
17+
black {posargs:.}
18+
flake8 --exclude .git,.venv,.tox {posargs:.}
19+
isort {posargs:.}
20+
jsonfmt --check {posargs:.}

0 commit comments

Comments
 (0)