gnnepcsaft-mcp-server 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of gnnepcsaft-mcp-server might be problematic. Click here for more details.
- gnnepcsaft_mcp_server/__init__.py +1 -0
- gnnepcsaft_mcp_server/mcp_server.py +38 -0
- gnnepcsaft_mcp_server/models/.gitignore +0 -0
- gnnepcsaft_mcp_server/models/assoc_8.onnx +0 -0
- gnnepcsaft_mcp_server/models/assoc_8.onnx.data +0 -0
- gnnepcsaft_mcp_server/models/msigmae_7.onnx +0 -0
- gnnepcsaft_mcp_server/models/msigmae_7.onnx.data +0 -0
- gnnepcsaft_mcp_server/utils.py +136 -0
- gnnepcsaft_mcp_server-0.1.0.dist-info/METADATA +63 -0
- gnnepcsaft_mcp_server-0.1.0.dist-info/RECORD +12 -0
- gnnepcsaft_mcp_server-0.1.0.dist-info/WHEEL +4 -0
- gnnepcsaft_mcp_server-0.1.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"GNNePCSAFT MCP Server"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"GNNePCSAFT MCP Server"
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable, List
|
|
4
|
+
|
|
5
|
+
from gnnepcsaft.data.rdkit_util import inchitosmiles, mw, smilestoinchi
|
|
6
|
+
from gnnepcsaft.epcsaft.epcsaft_feos import (
|
|
7
|
+
mix_den_feos,
|
|
8
|
+
mix_vp_feos,
|
|
9
|
+
pure_den_feos,
|
|
10
|
+
pure_h_lv_feos,
|
|
11
|
+
pure_vp_feos,
|
|
12
|
+
)
|
|
13
|
+
from mcp.server.fastmcp import FastMCP
|
|
14
|
+
|
|
15
|
+
from .utils import mixture_phase, prediction, pubchem_description, pure_phase
|
|
16
|
+
|
|
17
|
+
mcp = FastMCP("gnnepcsaft")
|
|
18
|
+
fn_list: List[Callable[..., Any]] = [
|
|
19
|
+
pure_vp_feos,
|
|
20
|
+
pure_den_feos,
|
|
21
|
+
mix_den_feos,
|
|
22
|
+
mix_vp_feos,
|
|
23
|
+
pure_phase,
|
|
24
|
+
mixture_phase,
|
|
25
|
+
pubchem_description,
|
|
26
|
+
mw,
|
|
27
|
+
smilestoinchi,
|
|
28
|
+
prediction,
|
|
29
|
+
inchitosmiles,
|
|
30
|
+
pure_h_lv_feos,
|
|
31
|
+
]
|
|
32
|
+
for fn in fn_list:
|
|
33
|
+
mcp.add_tool(fn)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def run():
|
|
37
|
+
"run stdio"
|
|
38
|
+
mcp.run("stdio")
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"Utils for MCP Server"
|
|
2
|
+
|
|
3
|
+
from json import loads
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Literal
|
|
6
|
+
from urllib.parse import quote
|
|
7
|
+
from urllib.request import HTTPError, urlopen
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import onnxruntime as ort
|
|
11
|
+
from gnnepcsaft.data.ogb_utils import smiles2graph
|
|
12
|
+
from gnnepcsaft.data.rdkit_util import assoc_number, smilestoinchi
|
|
13
|
+
|
|
14
|
+
file_dir = Path(__file__).parent
|
|
15
|
+
model_dir = file_dir / "models"
|
|
16
|
+
ort.set_default_logger_severity(3)
|
|
17
|
+
|
|
18
|
+
msigmae_onnx = ort.InferenceSession(model_dir / "msigmae_7.onnx")
|
|
19
|
+
assoc_onnx = ort.InferenceSession(model_dir / "assoc_8.onnx")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def prediction(
|
|
23
|
+
smiles: str,
|
|
24
|
+
) -> List[float]:
|
|
25
|
+
"""Predict ePC-SAFT parameters
|
|
26
|
+
`[m, sigma, epsilon/kB, kappa_ab, epsilon_ab/kB, dipole moment, na, nb]`
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
smiles (str): SMILES of the molecule.
|
|
30
|
+
"""
|
|
31
|
+
lower_bounds = np.asarray([1.0, 1.9, 50.0, 0.0, 0.0, 0, 0, 0])
|
|
32
|
+
upper_bounds = np.asarray([25.0, 4.5, 550.0, 0.9, 5000.0, np.inf, np.inf, np.inf])
|
|
33
|
+
|
|
34
|
+
inchi = smilestoinchi(smiles)
|
|
35
|
+
|
|
36
|
+
graph = smiles2graph(smiles)
|
|
37
|
+
na, nb = assoc_number(inchi)
|
|
38
|
+
x, edge_index, edge_attr = (
|
|
39
|
+
graph["node_feat"],
|
|
40
|
+
graph["edge_index"],
|
|
41
|
+
graph["edge_feat"],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
assoc = 10 ** (
|
|
45
|
+
assoc_onnx.run(
|
|
46
|
+
None,
|
|
47
|
+
{
|
|
48
|
+
"x": x,
|
|
49
|
+
"edge_index": edge_index,
|
|
50
|
+
"edge_attr": edge_attr,
|
|
51
|
+
},
|
|
52
|
+
)[0][0]
|
|
53
|
+
* np.asarray([-1.0, 1.0])
|
|
54
|
+
)
|
|
55
|
+
if na == 0 and nb == 0:
|
|
56
|
+
assoc *= 0
|
|
57
|
+
msigmae = msigmae_onnx.run(
|
|
58
|
+
None,
|
|
59
|
+
{
|
|
60
|
+
"x": x,
|
|
61
|
+
"edge_index": edge_index,
|
|
62
|
+
"edge_attr": edge_attr,
|
|
63
|
+
},
|
|
64
|
+
)[0][0]
|
|
65
|
+
munanb = np.asarray([0.0, na, nb])
|
|
66
|
+
pred = np.hstack([msigmae, assoc, munanb], dtype=np.float64)
|
|
67
|
+
np.clip(pred, lower_bounds, upper_bounds, out=pred)
|
|
68
|
+
|
|
69
|
+
return pred.tolist() # type: ignore
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def pure_phase(
|
|
73
|
+
vapor_pressure: float, system_pressure: float
|
|
74
|
+
) -> Literal["liquid", "vapor"]:
|
|
75
|
+
"""
|
|
76
|
+
Given the vapor pressure and system pressure, return the phase of the molecule.
|
|
77
|
+
Both pressures must be in the same unit.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
vapor_pressure (float): The calculated vapor pressure of the pure component.
|
|
81
|
+
system_pressure (float): The actual system pressure.
|
|
82
|
+
|
|
83
|
+
"""
|
|
84
|
+
assert isinstance(vapor_pressure, (int, float)), "vapor_pressure must be a number"
|
|
85
|
+
assert isinstance(system_pressure, (int, float)), "system_pressure must be a number"
|
|
86
|
+
assert vapor_pressure > 0, "vapor_pressure must be positive"
|
|
87
|
+
assert system_pressure > 0, "system_pressure must be positive"
|
|
88
|
+
|
|
89
|
+
return "liquid" if vapor_pressure < system_pressure else "vapor"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def mixture_phase(
|
|
93
|
+
bubble_point: float,
|
|
94
|
+
dew_point: float,
|
|
95
|
+
system_pressure: float,
|
|
96
|
+
) -> Literal["liquid", "vapor", "two-phase"]:
|
|
97
|
+
"""
|
|
98
|
+
Given the bubble/dew point of the mixture and the system pressure,
|
|
99
|
+
return the phase of the mixture.
|
|
100
|
+
All pressures must be in the same unit.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
bubble_point (float): The calculated bubble point of the mixture.
|
|
104
|
+
dew_point (float): The calculated dew point of the mixture.
|
|
105
|
+
system_pressure (float): The actual system pressure.
|
|
106
|
+
"""
|
|
107
|
+
assert isinstance(bubble_point, (int, float)), "bubble_point must be a number"
|
|
108
|
+
assert isinstance(dew_point, (int, float)), "dew_point must be a number"
|
|
109
|
+
assert isinstance(system_pressure, (int, float)), "system_pressure must be a number"
|
|
110
|
+
assert bubble_point > 0, "bubble_point must be positive"
|
|
111
|
+
assert dew_point > 0, "dew_point must be positive"
|
|
112
|
+
assert system_pressure > 0, "system_pressure must be positive"
|
|
113
|
+
return (
|
|
114
|
+
"liquid"
|
|
115
|
+
if bubble_point < system_pressure
|
|
116
|
+
else ("two-phase" if dew_point <= system_pressure else "vapor")
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def pubchem_description(inchi: str) -> str:
|
|
121
|
+
"""
|
|
122
|
+
Look for information on PubChem for the InChI.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
inchi (str): The InChI of the molecule.
|
|
126
|
+
"""
|
|
127
|
+
url = (
|
|
128
|
+
"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/inchi/description/json?inchi="
|
|
129
|
+
+ quote(inchi, safe="")
|
|
130
|
+
)
|
|
131
|
+
try:
|
|
132
|
+
with urlopen(url) as ans:
|
|
133
|
+
ans = loads(ans.read().decode("utf8").strip())
|
|
134
|
+
except (TypeError, HTTPError, ValueError):
|
|
135
|
+
ans = "no data available on this molecule in PubChem."
|
|
136
|
+
return ans
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: gnnepcsaft-mcp-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Model Context Protocol server for GNNePCSAFT tools
|
|
5
|
+
License: GNU General Public License v3.0
|
|
6
|
+
Author: wildsonbbl
|
|
7
|
+
Author-email: wil_bbl@hotmail.com
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Classifier: License :: Other/Proprietary License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Dist: feos (>=0.8.0,<0.9.0)
|
|
16
|
+
Requires-Dist: gnnepcsaft (>=0.2.2,<0.3.0)
|
|
17
|
+
Requires-Dist: mcp (>=1.6.0,<2.0.0)
|
|
18
|
+
Requires-Dist: numpy (>=2.2.4,<3.0.0)
|
|
19
|
+
Requires-Dist: onnxruntime (>=1.21.0,<2.0.0)
|
|
20
|
+
Requires-Dist: rdkit (>=2024.9.6,<2025.0.0)
|
|
21
|
+
Requires-Dist: si-units (>=0.11.0,<0.12.0)
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# GNNEPCSAFT MCP Server
|
|
25
|
+
|
|
26
|
+
## Overview
|
|
27
|
+
|
|
28
|
+
This is the Model Context Protocol ([MCP](https://modelcontextprotocol.io/introduction)) server implementation for [GNNePCSAFT](https://github.com/wildsonbbl/gnnepcsaft) tools. The server handles communication and context management between models and clients using the MCP protocol.
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- Model context management
|
|
33
|
+
- Protocol handling for model communication
|
|
34
|
+
- Client request processing
|
|
35
|
+
- Context state synchronization
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
You're gonna need [pipx](https://pipx.pypa.io/latest/installation/) for this.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pipx install gnnepcsaft-mcp-server
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
stdio command to start the MCP server:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"mcpServers": {
|
|
52
|
+
"gnnepcsaft": {
|
|
53
|
+
"command": "gnnepcsaftmcp",
|
|
54
|
+
"args": []
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
GNU General Public License v3.0
|
|
63
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
gnnepcsaft_mcp_server/__init__.py,sha256=Npbt9RPLtKrFDK-oeyrAbz0b7lg9Y1Le1mxAQVtD_PY,24
|
|
2
|
+
gnnepcsaft_mcp_server/mcp_server.py,sha256=rkWyUA5_tZY9ArhwFObccShaq5jMNF9RQruuk7a7OrM,768
|
|
3
|
+
gnnepcsaft_mcp_server/models/.gitignore,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
gnnepcsaft_mcp_server/models/assoc_8.onnx,sha256=FBSU3cP1NyelkwCtLaWVhaeX8QuzQGp6Mf3lSV97mzE,2287889
|
|
5
|
+
gnnepcsaft_mcp_server/models/assoc_8.onnx.data,sha256=AMg5VrBZi1F-kZ_YAQay_BDaQQtbs8ihfn4BgWbYzeM,11468800
|
|
6
|
+
gnnepcsaft_mcp_server/models/msigmae_7.onnx,sha256=TiKHrwBbNPyoOeeRQ_W_xnEqEtopmI_FIBtZJyN4afk,2288073
|
|
7
|
+
gnnepcsaft_mcp_server/models/msigmae_7.onnx.data,sha256=kExPbT75jMLRAYRQQZ8WPeY0rYvAfDZx-Bnji_dLJ1s,11469056
|
|
8
|
+
gnnepcsaft_mcp_server/utils.py,sha256=Be62JR9tfJiCP3BOaRExGcetu1Q3xoFAps6r_JXw0nM,4288
|
|
9
|
+
gnnepcsaft_mcp_server-0.1.0.dist-info/METADATA,sha256=z4r5A-MtvI73bLP00VEqs56fsRpcJbbHqSrUOF4tBTg,1694
|
|
10
|
+
gnnepcsaft_mcp_server-0.1.0.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
11
|
+
gnnepcsaft_mcp_server-0.1.0.dist-info/entry_points.txt,sha256=5tsnxZG8Vtdrr3CT-8Pv35RjpcDiR0L28cYxxHeCsPI,70
|
|
12
|
+
gnnepcsaft_mcp_server-0.1.0.dist-info/RECORD,,
|