Skip to content

OpenDSS MCP server crashes on macOS arm64 before MCP initialize #47

@trashchenkov

Description

@trashchenkov

Summary

powermcp run opendss crashes during startup on macOS arm64 before the MCP server can complete initialize / list_tools.

In the same environment, other PowerMCP stdio servers start normally:

  • powermcp run pandapower: MCP initialize + list tools succeeds
  • powermcp run powerio: MCP initialize + list tools succeeds
  • powermcp run opendss: process exits; MCP client receives Connection closed

The failure appears to come from eager OpenDSS engine construction at import time:

# OpenDSS/core/engine.py
from py_dss_interface import DSS
from py_dss_toolkit import dss_tools

dss = DSS()
dss_tools.update_dss(dss)

On my macOS arm64 machine, DSS() raises before the FastMCP server is created, so MCP clients only see a generic connection failure.

Environment

  • PowerMCP commit tested: cc99f348b394766b9958962638b2b31dee982755
  • Installed package version: powermcp 0.1.3
  • Python: 3.12.11
  • Platform: macOS arm64
  • py-dss-interface: 2.2.1
  • py-dss-toolkit: 0.7.0

Reproduction

python -m powermcp run opendss

or via an MCP stdio client:

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

params = StdioServerParameters(
    command="python",
    args=["-m", "powermcp", "run", "opendss"],
)

async with stdio_client(params) as (read, write):
    async with ClientSession(read, write) as session:
        await session.initialize()
        await session.list_tools()

Actual behavior

The MCP client sees:

McpError: Connection closed

The server traceback ends with:

File ".../PowerMCP/OpenDSS/core/engine.py", line 6, in <module>
    dss = DSS()
File ".../py_dss_interface/DSS.py", line 93, in __init__
    os.chdir(self._dll_path)
AttributeError: 'DSS' object has no attribute '_dll_path'

Expected behavior

The OpenDSS MCP server should not crash before MCP initialization. Ideally it should either:

  1. initialize successfully, or
  2. expose the MCP tools and return an actionable structured error from OpenDSS tools when the backend cannot initialize, or
  3. fail during an explicit preflight/doctor step with a clear platform/dependency diagnostic before users add it to an MCP client config.

Proposed direction

Would you be open to a PR that makes OpenDSS backend initialization lazy?

The conservative fix would be:

  • do not construct py_dss_interface.DSS() at module import time;
  • let create_mcp() and initialize/list_tools complete even if the OpenDSS backend is unavailable on the current platform;
  • initialize DSS() on first OpenDSS tool call;
  • if backend initialization fails, return the existing _err(...) response shape with an actionable message instead of crashing the stdio process;
  • add a small regression test that server creation/listing tools does not instantiate DSS() or crash when DSS() is monkeypatched to raise.

This should be backwards-compatible for users where py_dss_interface already works: the default backend, tool names, and tool schemas would remain unchanged. The only behavior change would be that unsupported/misconfigured platforms get MCP-level diagnostics instead of a process-level Connection closed failure.

A separate follow-up could consider an optional opendssdirect.py / dss-python fallback for macOS, but I would keep that out of the first PR unless maintainers prefer that direction.

If this approach sounds acceptable, I can prepare a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions