feat(mcp): Align client to JSON-RPC and update Emma model

- Refactor opax_mcp_client to use the JSON-RPC 2.0 MCP protocol.

- Set the client fallback endpoint to: https://opax-mcp-357036551735.us-central1.run.app

- Set run_emma’s fallback model to qwen2.5:7b.

- Update run_emma’s MCP tool description to qwen2.5:7b.
This commit is contained in:
Chris Christiansen 2026-09-11 02:22:37 +00:00
parent a1d28db7c5
commit 054afd180c
2 changed files with 63 additions and 14 deletions

View File

@ -14,7 +14,7 @@ import httpx
import google.auth import google.auth
import google.auth.transport.requests import google.auth.transport.requests
OPAX_MCP_URL = os.environ.get("MCP_SERVER_URL", "https://opax-mcp-zjbqp3prqq-uc.a.run.app") OPAX_MCP_URL = os.environ.get("MCP_SERVER_URL", "https://opax-mcp-357036551735.us-central1.run.app")
MCP_SECRET = os.environ.get("MCP_SECRET", "") MCP_SECRET = os.environ.get("MCP_SECRET", "")
@ -44,22 +44,71 @@ def _headers() -> dict:
def call_tool(tool: str, params: dict = None) -> dict: def call_tool(tool: str, params: dict = None) -> dict:
"""Kall eit opax-mcp tool. Returnerer {tool, result}.""" """Kall eit tool på OPAX JSON-RPC MCP endepunktet."""
resp = httpx.post( endpoint = OPAX_MCP_URL.rstrip("/") + "/"
f"{OPAX_MCP_URL}/tools/call", payload = {
headers=_headers(), "jsonrpc": "2.0",
json={"tool": tool, "params": params or {}}, "id": "opax-client-tools-call",
timeout=30, "method": "tools/call",
) "params": {
"name": tool,
"arguments": params or {},
},
}
resp = httpx.post(endpoint, headers=_headers(), json=payload, timeout=30)
resp.raise_for_status() resp.raise_for_status()
return resp.json() json_resp = resp.json()
if not isinstance(json_resp, dict):
raise RuntimeError("JSON-RPC response must be an object.")
error = json_resp.get("error")
if error:
if isinstance(error, dict):
raise RuntimeError(
f"JSON-RPC error {error.get('code')}: {error.get('message')}"
)
raise RuntimeError("JSON-RPC response contains an invalid error object.")
if "result" not in json_resp:
raise RuntimeError("JSON-RPC response missing 'result' field.")
return json_resp["result"]
def list_tools() -> list: def list_tools() -> list:
"""List alle tilgjengelige tools i opax-mcp.""" """List alle tilgjengelige tools frå OPAX JSON-RPC MCP endepunktet."""
resp = httpx.get(f"{OPAX_MCP_URL}/tools", headers=_headers(), timeout=10) endpoint = OPAX_MCP_URL.rstrip("/") + "/"
payload = {
"jsonrpc": "2.0",
"id": "opax-client-tools-list",
"method": "tools/list",
"params": {},
}
resp = httpx.post(endpoint, headers=_headers(), json=payload, timeout=10)
resp.raise_for_status() resp.raise_for_status()
return resp.json().get("tools", []) json_resp = resp.json()
if not isinstance(json_resp, dict):
raise RuntimeError("JSON-RPC response must be an object.")
error = json_resp.get("error")
if error:
if isinstance(error, dict):
raise RuntimeError(
f"JSON-RPC error {error.get('code')}: {error.get('message')}"
)
raise RuntimeError("JSON-RPC response contains an invalid error object.")
result = json_resp.get("result")
if not isinstance(result, dict):
raise RuntimeError("JSON-RPC response missing object 'result' field.")
tools = result.get("tools")
if not isinstance(tools, list):
raise RuntimeError("JSON-RPC response missing 'result.tools' list.")
return tools
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

View File

@ -91,7 +91,7 @@ WORKSPACE_ADMIN_USER = "chris.christiansen@vauco.no"
# Emma-vm Ollama — direkte tilkobling # Emma-vm Ollama — direkte tilkobling
OLLAMA_BASE_URL = os.environ.get("OLLAMA_BASE_URL", "http://34.13.238.133:11434") OLLAMA_BASE_URL = os.environ.get("OLLAMA_BASE_URL", "http://34.13.238.133:11434")
EMMA_MODEL = os.environ.get("EMMA_MODEL", "gemma3:27b") EMMA_MODEL = os.environ.get("EMMA_MODEL", "qwen2.5:7b")
EMMA_FAST_MODEL = os.environ.get("EMMA_FAST_MODEL", "gemma3:4b") EMMA_FAST_MODEL = os.environ.get("EMMA_FAST_MODEL", "gemma3:4b")
EMMA_LIGHT_MODEL = os.environ.get("EMMA_LIGHT_MODEL", "qwen2.5:3b") EMMA_LIGHT_MODEL = os.environ.get("EMMA_LIGHT_MODEL", "qwen2.5:3b")
@ -775,7 +775,7 @@ TOOLS = {
), ),
# AI Agents # AI Agents
"run_jason": (run_jason, "Kjør Jason-agenten med en prompt", {"type":"object","properties":{"prompt":{"type":"string"},"mode":{"type":"string"}},"required":["prompt"]}), "run_jason": (run_jason, "Kjør Jason-agenten med en prompt", {"type":"object","properties":{"prompt":{"type":"string"},"mode":{"type":"string"}},"required":["prompt"]}),
"run_emma": (run_emma, "Emma Vauger (gemma3:27b) — primær lokal AI", {"type":"object","properties":{"prompt":{"type":"string"}}}), "run_emma": (run_emma, "Emma Vauger (qwen2.5:7b) — primær lokal AI", {"type":"object","properties":{"prompt":{"type":"string"}}}),
# Local models — read-only discovery # Local models — read-only discovery
"list_emma_models": ( "list_emma_models": (