Skip to content

Commit 81d2a31

Browse files
working mcp + phase diag tool
1 parent b570096 commit 81d2a31

File tree

6 files changed

+6212
-1025
lines changed

6 files changed

+6212
-1025
lines changed

mp_api/mcp/__init__.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
11
"""Get default MCP for Materials Project."""
2-
from __future__ import annotations
3-
4-
from mp_api.mcp.mp_mcp import MPMcp
5-
6-
__all__ = ["MPMcp"]

mp_api/mcp/mp_mcp.py

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,33 @@
11
"""Define custom MCP tools for the Materials Project API."""
22
from __future__ import annotations
33

4-
from typing import Any
54
from urllib.parse import urljoin
65

76
import httpx
87
from fastmcp import FastMCP
9-
from pydantic import BaseModel, Field, PrivateAttr
10-
11-
from mp_api.client import MPRester
12-
from mp_api.mcp import tools as mcp_tools
13-
14-
15-
class MPMcp(BaseModel):
16-
name: str = Field("Materials_Project_MCP")
17-
client_kwargs: dict[str, Any] | None = Field(None)
18-
_client: MPRester | None = PrivateAttr(None)
19-
20-
@property
21-
def client(self) -> MPRester:
22-
# Always return JSON compliant output for MCP
23-
if not self._client:
24-
kwargs = {
25-
**(self.client_kwargs or {}),
26-
"use_document_model": False,
27-
"monty_decode": False,
28-
}
29-
self._client = MPRester(**kwargs)
30-
return self._client
31-
32-
def mcp(self, **kwargs) -> FastMCP:
33-
mcp = FastMCP(self.name, **kwargs)
34-
35-
for attr in {x for x in dir(mcp_tools) if x.startswith("get")}:
36-
mcp.tool(getattr(mcp_tools, attr))
37-
38-
return mcp
39-
40-
def bootstrap_mcp(self, **kwargs) -> FastMCP:
41-
"""Bootstrap an MP API MCP only from the OpenAPI spec."""
42-
return FastMCP.from_openapi(
43-
openapi_spec=httpx.get(
44-
urljoin(self.client.endpoint, "openapi.json")
45-
).json(),
46-
client=httpx.AsyncClient(
47-
base_url=self.client.endpoint,
48-
headers={"x-api-key": self.client.api_key},
49-
),
50-
name=self.name,
51-
**kwargs,
52-
)
8+
9+
from mp_api.mcp.tools import MPMcpTools
10+
from mp_api.mcp.utils import _NeedsMPClient
11+
12+
13+
def get_mcp() -> FastMCP:
14+
"""MCP with finer depth of control over tool names."""
15+
mp_mcp = FastMCP("Materials_Project_MCP")
16+
mcp_tools = MPMcpTools()
17+
for attr in {x for x in dir(mcp_tools) if x.startswith("get_")}:
18+
mp_mcp.tool(getattr(mcp_tools, attr))
19+
return mp_mcp
20+
21+
22+
def get_bootstrap_mcp() -> FastMCP:
23+
"""Bootstrap an MP API MCP only from the OpenAPI spec."""
24+
client = _NeedsMPClient().client
25+
26+
return FastMCP.from_openapi(
27+
openapi_spec=httpx.get(urljoin(client.endpoint, "openapi.json")).json(),
28+
client=httpx.AsyncClient(
29+
base_url=client.endpoint,
30+
headers={"x-api-key": client.api_key},
31+
),
32+
name="MP_OpenAPI_MCP",
33+
)

mp_api/mcp/server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""Run MCP."""
22
from __future__ import annotations
33

4-
from mp_api.mcp.mp_mcp import MPMcp
4+
from mp_api.mcp.mp_mcp import get_mcp
55

6-
mcp = MPMcp().mcp()
6+
mcp = get_mcp()
77

88
if __name__ == "__main__":
99
mcp.run()

0 commit comments

Comments
 (0)