modulector-sdk 2.4.0__tar.gz → 2.5.2__tar.gz
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.
- {modulector_sdk-2.4.0/src/modulector_sdk.egg-info → modulector_sdk-2.5.2}/PKG-INFO +4 -1
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/README.md +3 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/pyproject.toml +1 -1
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk/mcp_server.py +81 -9
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2/src/modulector_sdk.egg-info}/PKG-INFO +4 -1
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/LICENSE +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/setup.cfg +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk/__init__.py +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk/py.typed +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk/services.py +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk/utils.py +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk.egg-info/SOURCES.txt +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk.egg-info/dependency_links.txt +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk.egg-info/entry_points.txt +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk.egg-info/requires.txt +0 -0
- {modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modulector-sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.2
|
|
4
4
|
Summary: Typed Python SDK for the Modulector API.
|
|
5
5
|
Author: omicsdatascience
|
|
6
6
|
License-Expression: MIT
|
|
@@ -101,6 +101,9 @@ disease associations, drug associations, and PubMed news subscriptions. Use
|
|
|
101
101
|
`MODULECTOR_API_BASE_URL` or each tool's `base_url` argument to target a custom
|
|
102
102
|
Modulector deployment.
|
|
103
103
|
|
|
104
|
+
When deployed with the root Docker Compose stack, nginx proxies the MCP
|
|
105
|
+
Streamable HTTP endpoint at `https://<mydomain.com>/mcp`.
|
|
106
|
+
|
|
104
107
|
## Development
|
|
105
108
|
|
|
106
109
|
Build this SDK from the `sdk/` directory:
|
|
@@ -70,6 +70,9 @@ disease associations, drug associations, and PubMed news subscriptions. Use
|
|
|
70
70
|
`MODULECTOR_API_BASE_URL` or each tool's `base_url` argument to target a custom
|
|
71
71
|
Modulector deployment.
|
|
72
72
|
|
|
73
|
+
When deployed with the root Docker Compose stack, nginx proxies the MCP
|
|
74
|
+
Streamable HTTP endpoint at `https://<mydomain.com>/mcp`.
|
|
75
|
+
|
|
73
76
|
## Development
|
|
74
77
|
|
|
75
78
|
Build this SDK from the `sdk/` directory:
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import argparse
|
|
6
|
+
import os
|
|
6
7
|
from typing import Any, Final, Literal, TypeVar, cast
|
|
8
|
+
from urllib.parse import urlparse
|
|
7
9
|
|
|
8
10
|
from mcp.server.fastmcp import FastMCP
|
|
11
|
+
from mcp.server.transport_security import TransportSecuritySettings
|
|
9
12
|
|
|
10
13
|
from . import services
|
|
11
14
|
from .utils import PaginatedResponse
|
|
@@ -21,11 +24,15 @@ SERVER_INSTRUCTIONS: Final[str] = (
|
|
|
21
24
|
"paginated tools with explicit identifiers. The returned data comes from "
|
|
22
25
|
"the configured Modulector API deployment."
|
|
23
26
|
)
|
|
27
|
+
PUBLIC_BASE_URL: Final[str] = os.getenv(
|
|
28
|
+
"MODULECTOR_PUBLIC_BASE_URL",
|
|
29
|
+
services.MODULECTOR_API_BASE_URL,
|
|
30
|
+
)
|
|
24
31
|
|
|
25
32
|
mcp = FastMCP(
|
|
26
33
|
name="modulector",
|
|
27
34
|
instructions=SERVER_INSTRUCTIONS,
|
|
28
|
-
website_url=
|
|
35
|
+
website_url=PUBLIC_BASE_URL,
|
|
29
36
|
)
|
|
30
37
|
|
|
31
38
|
|
|
@@ -48,6 +55,7 @@ def about_modulector() -> str:
|
|
|
48
55
|
"miRNA-drug associations, and Illumina Infinium MethylationEPIC 2.0 "
|
|
49
56
|
"site annotations.\n\n"
|
|
50
57
|
f"Default API base URL: `{services.MODULECTOR_API_BASE_URL}`\n\n"
|
|
58
|
+
f"Public website URL: `{PUBLIC_BASE_URL}`\n\n"
|
|
51
59
|
"Use the finder tools for partial identifiers, then query detail or "
|
|
52
60
|
"paginated tools with exact miRNA, gene, disease, drug, or methylation "
|
|
53
61
|
"site filters."
|
|
@@ -135,10 +143,13 @@ def get_mirna_details(
|
|
|
135
143
|
:return: miRNA detail record.
|
|
136
144
|
"""
|
|
137
145
|
|
|
138
|
-
return
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
return cast(
|
|
147
|
+
dict[str, Any],
|
|
148
|
+
services.get_mirna_details(
|
|
149
|
+
mirna,
|
|
150
|
+
base_url=_base_url(base_url),
|
|
151
|
+
timeout=timeout,
|
|
152
|
+
),
|
|
142
153
|
)
|
|
143
154
|
|
|
144
155
|
|
|
@@ -308,10 +319,13 @@ def get_methylation_details(
|
|
|
308
319
|
:return: Methylation site detail record.
|
|
309
320
|
"""
|
|
310
321
|
|
|
311
|
-
return
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
322
|
+
return cast(
|
|
323
|
+
dict[str, Any],
|
|
324
|
+
services.get_methylation_details(
|
|
325
|
+
methylation_site,
|
|
326
|
+
base_url=_base_url(base_url),
|
|
327
|
+
timeout=timeout,
|
|
328
|
+
),
|
|
315
329
|
)
|
|
316
330
|
|
|
317
331
|
|
|
@@ -400,6 +414,7 @@ def main() -> None:
|
|
|
400
414
|
mcp.settings.host = args.host
|
|
401
415
|
mcp.settings.port = args.port
|
|
402
416
|
mcp.settings.json_response = args.json_response
|
|
417
|
+
_configure_http_transport_security()
|
|
403
418
|
mcp.run(transport=transport)
|
|
404
419
|
|
|
405
420
|
|
|
@@ -447,6 +462,63 @@ def _base_url(base_url: str | None) -> str:
|
|
|
447
462
|
return base_url or services.MODULECTOR_API_BASE_URL
|
|
448
463
|
|
|
449
464
|
|
|
465
|
+
def _configure_http_transport_security() -> None:
|
|
466
|
+
"""Configure DNS rebinding protection for HTTP MCP transports.
|
|
467
|
+
|
|
468
|
+
:return: None.
|
|
469
|
+
"""
|
|
470
|
+
|
|
471
|
+
mcp.settings.transport_security = TransportSecuritySettings(
|
|
472
|
+
allowed_hosts=_allowed_hosts(),
|
|
473
|
+
allowed_origins=_allowed_origins(),
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def _allowed_hosts() -> list[str]:
|
|
478
|
+
"""Return allowed Host headers for the MCP HTTP transport.
|
|
479
|
+
|
|
480
|
+
:return: Host header allow-list.
|
|
481
|
+
"""
|
|
482
|
+
|
|
483
|
+
configured_hosts = _csv_env("MODULECTOR_MCP_ALLOWED_HOSTS")
|
|
484
|
+
if configured_hosts:
|
|
485
|
+
return configured_hosts
|
|
486
|
+
|
|
487
|
+
parsed_public_url = urlparse(PUBLIC_BASE_URL)
|
|
488
|
+
public_host = parsed_public_url.netloc
|
|
489
|
+
hosts = ["127.0.0.1:*", "localhost:*", "[::1]:*"]
|
|
490
|
+
if public_host:
|
|
491
|
+
hosts.append(public_host)
|
|
492
|
+
return hosts
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def _allowed_origins() -> list[str]:
|
|
496
|
+
"""Return allowed Origin headers for the MCP HTTP transport.
|
|
497
|
+
|
|
498
|
+
:return: Origin header allow-list.
|
|
499
|
+
"""
|
|
500
|
+
|
|
501
|
+
configured_origins = _csv_env("MODULECTOR_MCP_ALLOWED_ORIGINS")
|
|
502
|
+
if configured_origins:
|
|
503
|
+
return configured_origins
|
|
504
|
+
|
|
505
|
+
parsed_public_url = urlparse(PUBLIC_BASE_URL)
|
|
506
|
+
origins = ["http://127.0.0.1:*", "http://localhost:*", "http://[::1]:*"]
|
|
507
|
+
if parsed_public_url.scheme and parsed_public_url.netloc:
|
|
508
|
+
origins.append(f"{parsed_public_url.scheme}://{parsed_public_url.netloc}")
|
|
509
|
+
return origins
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def _csv_env(name: str) -> list[str]:
|
|
513
|
+
"""Return comma-separated environment variable values.
|
|
514
|
+
|
|
515
|
+
:param name: Environment variable name.
|
|
516
|
+
:return: Non-empty stripped values.
|
|
517
|
+
"""
|
|
518
|
+
|
|
519
|
+
return [value.strip() for value in os.getenv(name, "").split(",") if value.strip()]
|
|
520
|
+
|
|
521
|
+
|
|
450
522
|
def _page_to_dict(page: PaginatedResponse[T]) -> dict[str, Any]:
|
|
451
523
|
"""Convert a paginated SDK response into a JSON-serializable mapping.
|
|
452
524
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modulector-sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.2
|
|
4
4
|
Summary: Typed Python SDK for the Modulector API.
|
|
5
5
|
Author: omicsdatascience
|
|
6
6
|
License-Expression: MIT
|
|
@@ -101,6 +101,9 @@ disease associations, drug associations, and PubMed news subscriptions. Use
|
|
|
101
101
|
`MODULECTOR_API_BASE_URL` or each tool's `base_url` argument to target a custom
|
|
102
102
|
Modulector deployment.
|
|
103
103
|
|
|
104
|
+
When deployed with the root Docker Compose stack, nginx proxies the MCP
|
|
105
|
+
Streamable HTTP endpoint at `https://<mydomain.com>/mcp`.
|
|
106
|
+
|
|
104
107
|
## Development
|
|
105
108
|
|
|
106
109
|
Build this SDK from the `sdk/` directory:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{modulector_sdk-2.4.0 → modulector_sdk-2.5.2}/src/modulector_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|