MCP server#
GLOW’s Solution API server can optionally expose a Model Context Protocol (MCP) server, allowing AI agents and MCP-compatible clients to interact with your solution programmatically.
When enabled, the MCP server is automatically mounted on the GLOW API server process.
The MCP URL will be http://$SOLUTION_API_URL/$GLOW_MCP_PATH (default path: /sse).
It’s independent of how you launch the API Server, either through SAF Desktop Orchestrator, with a Docker compose file, using the GLOW CLI or manually launching the server.
The MCP server provides resources listing the available tools and expected solution workflow, and tools for managing projects, setting and retrieving step fields, uploading and downloading entity handle files (including entity handles nested in lists, dictionaries, or custom objects), and running transaction methods, both sync and long running.
Important
This is an experimental feature and it’s disabled by default. The following limitations apply:
Not supporting uploading/downloading directories.
Not recommended to upload/download large files. At the moment, they are injected into the LLM context/output.
Not supporting websockets
Not supporting authentication. The MCP will be automatically disabled if
GLOW_AUTH_DISABLEDis set tofalse.
Enable the MCP server#
The following steps assume you are using SAF CLI to manage your solution. For different environments, adjust accordingly.
Add the
core-mcpextra to theansys-saf-sdkdependency in your solution’spyproject.toml. Afterwards, update your lock file and install the new dependencies:ansys-saf-sdk = {version = "^0.2.0", extras = ["core-mcp"]}
saf execute my_solution "poetry lock" saf install my_solution
In your solution’s
.envfile, enable MCP by setting:GLOW_MCP_DISABLED=False
Run your solution. No need to launch the UI:
saf run --no-uiCheck the GLOW API logs and confirm that MCP is mounted. Look for an
INFOline similar to:MCP mounted at path /sse
Configuration#
The MCP server is configured through the following environment variables:
Environment variable |
Default |
Description |
|---|---|---|
|
|
Set to |
|
|
The subpath at which the MCP server is mounted on the GLOW API server.
For example, with the default value and the API running on |
|
|
The transport protocol used by the MCP server. Accepted values: |
The SOLUTION.md file#
The MCP server reads an optional Markdown file named SOLUTION.md located in the same directory as
definition.py of your solution. This file provides custom human-readable context to the AI agent using the MCP server.
File format#
The file uses standard Markdown with two recognised level-2 headings:
# My Solution
<this will be ignored>
## Instructions
<Content describing the purpose of the solution and any important constraints for the AI agent.
This text is passed to the MCP server as its system-level instructions.>
## Workflow
<A step-by-step description of how to use the solution.
This text is returned by the ``solution_workflow`` tool.>
## Other section
<this will be ignored>
Both sections are optional and any other section will be ignored. If a section is missing, a default is generated.
Tip
Generic SAF concepts (what a project, step, field, or entity handle is, that transactions download and
upload step fields, or that long-running transactions must be awaited with
wait_for_longrunning_transaction) are already explained to the agent by the saf_concepts
tool. Keep SOLUTION.md focused on what is specific to your solution: the meaning of its steps
and fields, the order transactions must run in, and any domain constraints, rather than restating how
SAF or its generic tools work.
Example#
# My Solution
## Instructions
This solution runs structural analyses using Ansys Mechanical.
Do not run `solve` until `setup_geometry` has completed successfully.
## Workflow
1. In a fresh project, upload the geometry file on the `pre_processing` step, field `geometry_file`.
2. Run `setup_geometry` to prepare the model.
3. Set mesh parameters on the `meshing` step.
4. Run `generate_mesh`.
5. Run `solve`.
6. Download the results on the `post_processing` step, field `result_file`.
Available tools#
Workflow guidance#
Tool |
Description |
|---|---|
|
Returns the step-by-step workflow guide for the solution, sourced from the |
|
Explains the generic SAF solution concepts (projects, steps, fields, entity handles, transactions, long-running transactions) that apply to every solution, regardless of its specific steps or fields. |
Project management#
Tool |
Description |
|---|---|
|
Creates a new project in the solution and returns its name. Accepts an optional
|
|
Lists existing projects and their names, with optional pagination, ordering, and filtering. Use it to discover projects before using, exporting, or deleting them. |
|
Deletes one or more projects and their data. This is destructive and irreversible. Deletion is attempted for every name, so a failure on one project does not prevent the others from being deleted. Returns the outcome per project name. |
|
Imports a |
|
Exports a project as a |
Data management#
Tool |
Description |
|---|---|
|
Sets one or more step field values on an existing project. |
|
Gets the current values of one or more step fields from an existing project. |
|
Uploads binary content to an |
|
Downloads binary content from an |
Addressing nested entity handles#
upload_data and download_data locate the target EntityHandle through their field_path
argument, a slash-separated list of segments:
The first segment is always the step field name.
Each following segment navigates one level into the value stored in that field: a list index (
0,1, …), a dictionary key, or an attribute name of a custom (Pydantic model) object.
There is no depth limit, so arbitrary combinations of lists, dictionaries, and custom objects can be traversed:
|
Field value it addresses |
|---|---|
|
The step field |
|
First item of the list stored in the |
|
Value under the |
|
The |
|
First item of the |
|
Value under |
download_data returns the bytes referenced by the addressed entity handle. upload_data stores the
given content as a new entity in the project storage, replaces the addressed entity handle with the new one,
and writes the whole step field back, so the surrounding list, dictionary, or custom object is preserved.
Note
Both tools only read and replace entity handles that already exist at the given path. They do not create missing list items, dictionary keys, or object attributes.
Expected errors#
Both tools fail with an error (surfaced to the MCP client as a tool error) in the following cases:
Situation |
Error message |
|---|---|
The first segment is not a field of the step. |
|
A list index is not an integer. |
|
A list index is out of range. |
|
A dictionary key is missing. |
|
A custom object has no such attribute. |
|
A segment tries to navigate into a value that is not a list, dictionary, or custom object (for example, a string or a number). |
|
The value addressed by the full path is not an |
|
When upload_data fails, no entity handle is replaced and the step field is left unchanged.
Important
Directories are not supported: an entity handle referencing a directory cannot be uploaded or downloaded through these tools. Large files should also be avoided, since their content goes through the agent’s context.
Transaction execution#
Tool |
Description |
|---|---|
|
Runs a transaction method. One tool is registered per transaction method defined in the solution.
If a regular synchronous transaction is called, it’s a blocking call and the result (if there is) is returned at the end.
If a long-running transaction is called, the call ends immediately and returns nothing. Use the tool |
|
Waits for a previously started long-running transaction to complete and returns its result. |
Connect an MCP client#
Once the MCP server is running, connect any MCP-compatible client (for example, a GitHub Copilot agent,
Claude Code, or a FastMCP client) to $SOLUTION_API_URL$GLOW_MCP_PATH.
Example using the FastMCP Python client, assuming the Solution API is running at http://localhost:8000 and the MCP server is mounted at the default value of /sse:
import asyncio
from fastmcp import Client
from fastmcp.client.transports import StreamableHttpTransport
async def main():
transport = StreamableHttpTransport(url="http://localhost:8000/sse")
async with Client(transport=transport) as client:
resources = await client.list_resources()
print([r.name for r in resources])
tools = await client.list_tools()
print([t.name for t in tools])
asyncio.run(main())