Skip to content

First commit to interface ensemble launcher and chemgraph#92

Open
harikrishna1410 wants to merge 1 commit intomainfrom
ensemble_tool
Open

First commit to interface ensemble launcher and chemgraph#92
harikrishna1410 wants to merge 1 commit intomainfrom
ensemble_tool

Conversation

@harikrishna1410
Copy link
Copy Markdown

This pull request is a preliminary effort to integrate chemgraph with ensemble launcher. As a first step,

  1. I added a el_mcp_tools.py, which is a replication of mcp_tools.py tools.
  2. run_el_mcp.py: A runner script to start the mcp server

This is not expected to be the final version. I wanted to start the discussion here.

@harikrishna1410 harikrishna1410 requested a review from tdpham2 March 9, 2026 18:59
@tdpham2
Copy link
Copy Markdown
Collaborator

tdpham2 commented Mar 17, 2026

@harikrishna1410 Thanks for working on this! I have a few comments:

  • Could you retarget this PR to dev and rebase from the latest dev instead of main?
  • Architecture. I thought about this and I think there are two options for supporting both EL and Parsl:

Option 1: Parallel MCP Servers. Each backend gets its own MCP server file(s):

src/chemgraph/mcp/
---mcp_tools.py # Local execution (no parallelism)
---mace_mcp_parsl.py # MACE via Parsl
---graspa_mcp_parsl.py # gRASPA via Parsl
---mace_mcp_el.py # MACE via EnsembleLauncher
---graspa_mcp_el.py # gRASPA via EnsembleLauncher
---ase_mcp_el.py # General ASE via EL (NEW)

Option 2: Execution backend abstraction. A common interface so a single ensemble MCP server can dispatch to any backend:

class ExecutionBackend(ABC):
    """Abstraction for dispatching compute tasks."""
class EnsembleLauncherBackend(ExecutionBackend):
    """EL"""
class ParslBackend(ExecutionBackend):
    """Parsl"""

And a single ensemble MCP server:

backend = load_backend(os.getenv("EXECUTION_BACKEND", "local"))
@mcp.tool(name="run_mace_ensemble")
async def run_mace_ensemble(params: MaceEnsembleInput) -> dict:
    futures = []
    for struct in params.structures:
        fut = backend.submit(run_mace_core, {"params": struct})
        futures.append(fut)
    results = await backend.gather(futures)
    return {"status": "success", "results": results}

I think Option 2 is more scalable and future-proof. However, if you want to start with Option 1 to get something working first, that's fine. I can start refactoring toward Option 2 in a follow-up once both backends are functional.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants