ims-mcp 1.0.9__py3-none-any.whl → 1.0.10__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.
- ims_mcp/__init__.py +1 -1
- ims_mcp/server.py +54 -10
- {ims_mcp-1.0.9.dist-info → ims_mcp-1.0.10.dist-info}/METADATA +2 -1
- ims_mcp-1.0.10.dist-info/RECORD +9 -0
- ims_mcp-1.0.9.dist-info/RECORD +0 -9
- {ims_mcp-1.0.9.dist-info → ims_mcp-1.0.10.dist-info}/WHEEL +0 -0
- {ims_mcp-1.0.9.dist-info → ims_mcp-1.0.10.dist-info}/entry_points.txt +0 -0
- {ims_mcp-1.0.9.dist-info → ims_mcp-1.0.10.dist-info}/licenses/LICENSE +0 -0
- {ims_mcp-1.0.9.dist-info → ims_mcp-1.0.10.dist-info}/top_level.txt +0 -0
ims_mcp/__init__.py
CHANGED
ims_mcp/server.py
CHANGED
|
@@ -15,15 +15,60 @@ configuration is needed when running via uvx or other launchers.
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
import functools
|
|
18
|
+
import logging
|
|
18
19
|
import os
|
|
20
|
+
import signal
|
|
19
21
|
import sys
|
|
20
22
|
import uuid
|
|
21
23
|
from r2r import R2RClient, R2RException
|
|
22
24
|
|
|
25
|
+
# Debug mode controlled by environment variable
|
|
26
|
+
DEBUG_MODE = os.getenv('IMS_DEBUG', '').lower() in ('1', 'true', 'yes', 'on')
|
|
27
|
+
|
|
28
|
+
# Configure logging based on debug mode
|
|
29
|
+
if DEBUG_MODE:
|
|
30
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
31
|
+
else:
|
|
32
|
+
# Suppress all logging output from R2R and other libraries
|
|
33
|
+
logging.basicConfig(level=logging.CRITICAL)
|
|
34
|
+
# Specifically suppress httpx and httpcore which R2R uses
|
|
35
|
+
logging.getLogger('httpx').setLevel(logging.CRITICAL)
|
|
36
|
+
logging.getLogger('httpcore').setLevel(logging.CRITICAL)
|
|
37
|
+
logging.getLogger('r2r').setLevel(logging.CRITICAL)
|
|
38
|
+
|
|
23
39
|
# Global client instance with authentication
|
|
24
40
|
_authenticated_client = None
|
|
25
41
|
|
|
26
42
|
|
|
43
|
+
def debug_print(msg: str):
|
|
44
|
+
"""Print debug message to stderr if debug mode enabled."""
|
|
45
|
+
if DEBUG_MODE:
|
|
46
|
+
print(msg, file=sys.stderr)
|
|
47
|
+
sys.stderr.flush()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def cleanup_and_exit(signum=None, frame=None):
|
|
51
|
+
"""Gracefully shutdown the server on termination signals."""
|
|
52
|
+
global _authenticated_client
|
|
53
|
+
|
|
54
|
+
debug_print(f"[ims-mcp] Shutting down gracefully...")
|
|
55
|
+
|
|
56
|
+
# Cleanup authenticated client if exists
|
|
57
|
+
if _authenticated_client is not None:
|
|
58
|
+
try:
|
|
59
|
+
# R2R client cleanup if needed
|
|
60
|
+
_authenticated_client = None
|
|
61
|
+
except Exception:
|
|
62
|
+
pass # Ignore errors during shutdown
|
|
63
|
+
|
|
64
|
+
debug_print(f"[ims-mcp] Shutdown complete")
|
|
65
|
+
sys.exit(0)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Register signal handlers for graceful shutdown
|
|
69
|
+
signal.signal(signal.SIGTERM, cleanup_and_exit)
|
|
70
|
+
signal.signal(signal.SIGINT, cleanup_and_exit)
|
|
71
|
+
|
|
27
72
|
def get_authenticated_client() -> R2RClient:
|
|
28
73
|
"""Get or create an authenticated R2R client.
|
|
29
74
|
|
|
@@ -48,13 +93,12 @@ def get_authenticated_client() -> R2RClient:
|
|
|
48
93
|
email = os.getenv("R2R_EMAIL")
|
|
49
94
|
password = os.getenv("R2R_PASSWORD")
|
|
50
95
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
sys.stderr.flush()
|
|
96
|
+
debug_print(f"[ims-mcp v{__version__}]")
|
|
97
|
+
debug_print(f" server={base_url}")
|
|
98
|
+
debug_print(f" collection={collection}")
|
|
99
|
+
debug_print(f" api_key={api_key[:3] + '...' if api_key else 'none'}")
|
|
100
|
+
debug_print(f" email={email if email else 'none'}")
|
|
101
|
+
debug_print(f" password={password[:3] + '...' if password else 'none'}")
|
|
58
102
|
|
|
59
103
|
# Create new client
|
|
60
104
|
client = R2RClient()
|
|
@@ -67,9 +111,9 @@ def get_authenticated_client() -> R2RClient:
|
|
|
67
111
|
try:
|
|
68
112
|
# Login - R2RClient automatically handles token internally
|
|
69
113
|
client.users.login(email=email, password=password)
|
|
70
|
-
|
|
114
|
+
debug_print(f"[ims-mcp] Login successful")
|
|
71
115
|
except Exception as e:
|
|
72
|
-
|
|
116
|
+
debug_print(f"[ims-mcp] Login failed: {e}")
|
|
73
117
|
# If login fails, continue without authentication (might work for local servers)
|
|
74
118
|
pass
|
|
75
119
|
|
|
@@ -97,7 +141,7 @@ def retry_on_auth_error(func):
|
|
|
97
141
|
except R2RException as e:
|
|
98
142
|
# Check if this is an authentication error (token expired)
|
|
99
143
|
if hasattr(e, 'status_code') and e.status_code in [401, 403]:
|
|
100
|
-
|
|
144
|
+
debug_print(f"[ims-mcp] Token expired, re-authenticating...")
|
|
101
145
|
invalidate_client()
|
|
102
146
|
# Retry once with fresh authentication
|
|
103
147
|
return await func(*args, **kwargs)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ims-mcp
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.10
|
|
4
4
|
Summary: Model Context Protocol server for IMS (Instruction Management Systems)
|
|
5
5
|
Author: Igor Solomatov
|
|
6
6
|
License-Expression: MIT
|
|
@@ -84,6 +84,7 @@ The server automatically reads configuration from environment variables:
|
|
|
84
84
|
| `R2R_API_KEY` | API key for authentication | None |
|
|
85
85
|
| `R2R_EMAIL` | Email for authentication (requires R2R_PASSWORD) | None |
|
|
86
86
|
| `R2R_PASSWORD` | Password for authentication (requires R2R_EMAIL) | None |
|
|
87
|
+
| `IMS_DEBUG` | Enable debug logging to stderr (1/true/yes/on) | None (disabled) |
|
|
87
88
|
|
|
88
89
|
**Authentication Priority:**
|
|
89
90
|
1. If `R2R_API_KEY` is set, it will be used
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
ims_mcp/__init__.py,sha256=UDBzaafXhi3dqq6YFTXY4e08onAmmAIHZwOgGzwr-no,632
|
|
2
|
+
ims_mcp/__main__.py,sha256=z4P1aCVfOgS3cTM2wgJd2pxjMmKCkGkiqYDRGgrspxw,191
|
|
3
|
+
ims_mcp/server.py,sha256=obc9TM_HyfLDg_U6tp-_6SugkvUs356wiH2MS9-ssm4,25159
|
|
4
|
+
ims_mcp-1.0.10.dist-info/licenses/LICENSE,sha256=4d1dlH04mbnN3ya4lybcVOUwljRHGy-aSc9MYqGYW44,2534
|
|
5
|
+
ims_mcp-1.0.10.dist-info/METADATA,sha256=7T0IiSLk0UjIky3sgT06TDazs2hz47vzinkpnP1pzI4,9379
|
|
6
|
+
ims_mcp-1.0.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
ims_mcp-1.0.10.dist-info/entry_points.txt,sha256=xCH9I8g1pTTEqrfjnE-ANHaZo4W6EBJVy0Lg5z8SaIQ,48
|
|
8
|
+
ims_mcp-1.0.10.dist-info/top_level.txt,sha256=wEXA33qFr_eov3S1PY2OF6EQBA2rtAWB_ZNJOzNNQuM,8
|
|
9
|
+
ims_mcp-1.0.10.dist-info/RECORD,,
|
ims_mcp-1.0.9.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
ims_mcp/__init__.py,sha256=_a0FNt-0K9A50hDS6XdMk9mKSBodMX3vDosAcy8AdLI,631
|
|
2
|
-
ims_mcp/__main__.py,sha256=z4P1aCVfOgS3cTM2wgJd2pxjMmKCkGkiqYDRGgrspxw,191
|
|
3
|
-
ims_mcp/server.py,sha256=DeObwXtOSVnolp04llFXBWjQLdMcY6-BSdsZfeJIBhU,23807
|
|
4
|
-
ims_mcp-1.0.9.dist-info/licenses/LICENSE,sha256=4d1dlH04mbnN3ya4lybcVOUwljRHGy-aSc9MYqGYW44,2534
|
|
5
|
-
ims_mcp-1.0.9.dist-info/METADATA,sha256=PvR-jzu9736vKBEfKNonN25dhPgfpKcmxkJ1XyIYmFA,9295
|
|
6
|
-
ims_mcp-1.0.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
ims_mcp-1.0.9.dist-info/entry_points.txt,sha256=xCH9I8g1pTTEqrfjnE-ANHaZo4W6EBJVy0Lg5z8SaIQ,48
|
|
8
|
-
ims_mcp-1.0.9.dist-info/top_level.txt,sha256=wEXA33qFr_eov3S1PY2OF6EQBA2rtAWB_ZNJOzNNQuM,8
|
|
9
|
-
ims_mcp-1.0.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|