napistu 0.2.5.dev5__py3-none-any.whl → 0.2.5.dev7__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.
napistu/mcp/codebase.py CHANGED
@@ -45,7 +45,7 @@ async def initialize_components() -> bool:
45
45
 
46
46
  def register_components(mcp: FastMCP):
47
47
  """
48
- Register codebase exploration components with the MCP server.
48
+ Register codebase components with the MCP server.
49
49
 
50
50
  Args:
51
51
  mcp: FastMCP server instance
@@ -54,22 +54,14 @@ def register_components(mcp: FastMCP):
54
54
 
55
55
  # Register resources
56
56
  @mcp.resource("napistu://codebase/summary")
57
- async def get_codebase_summary() -> Dict[str, Any]:
57
+ async def get_codebase_summary():
58
58
  """
59
- Get a summary of the Napistu codebase structure.
59
+ Get a summary of all available codebase information.
60
60
  """
61
61
  return {
62
62
  "modules": list(_codebase_cache["modules"].keys()),
63
- "top_level_classes": [
64
- class_name
65
- for class_name, info in _codebase_cache["classes"].items()
66
- if "." not in class_name # Only include top-level classes
67
- ],
68
- "top_level_functions": [
69
- func_name
70
- for func_name, info in _codebase_cache["functions"].items()
71
- if "." not in func_name # Only include top-level functions
72
- ],
63
+ "classes": list(_codebase_cache["classes"].keys()),
64
+ "functions": list(_codebase_cache["functions"].keys()),
73
65
  }
74
66
 
75
67
  @mcp.resource("napistu://codebase/modules/{module_name}")
@@ -136,7 +136,7 @@ def register_components(mcp: FastMCP):
136
136
  return await documentation_utils.get_issue(repo, number)
137
137
 
138
138
  # Register tools
139
- @mcp.tool("search_documentation")
139
+ @mcp.tool()
140
140
  async def search_documentation(query: str):
141
141
  """
142
142
  Search all documentation for a specific query.
napistu/mcp/execution.py CHANGED
@@ -62,8 +62,8 @@ def register_components(mcp, session_context=None, object_registry=None):
62
62
  _session_context["napistu"] = napistu
63
63
 
64
64
  # Register resources
65
- @mcp.resource("napistu-local://registry")
66
- async def get_registry_summary() -> Dict[str, Any]:
65
+ @mcp.resource("napistu://execution/registry")
66
+ async def get_registry():
67
67
  """
68
68
  Get a summary of all objects registered with the server.
69
69
  """
@@ -75,7 +75,7 @@ def register_components(mcp, session_context=None, object_registry=None):
75
75
  },
76
76
  }
77
77
 
78
- @mcp.resource("napistu-local://environment")
78
+ @mcp.resource("napistu://execution/environment")
79
79
  async def get_environment_info() -> Dict[str, Any]:
80
80
  """
81
81
  Get information about the local Python environment.
napistu/mcp/health.py CHANGED
@@ -35,8 +35,8 @@ def register_components(mcp: FastMCP) -> None:
35
35
  """
36
36
  return _health_cache
37
37
 
38
- @mcp.tool("napistu://health/check")
39
- async def check_current_health() -> Dict[str, Any]:
38
+ @mcp.tool()
39
+ async def check_health() -> Dict[str, Any]:
40
40
  """
41
41
  Tool to actively check current component health.
42
42
  This performs real-time checks and updates the cached status.
napistu/mcp/server.py CHANGED
@@ -188,5 +188,4 @@ def start_mcp_server(
188
188
  logger.info("🚀 Starting MCP server...")
189
189
  logger.info(f"Using HTTP transport on http://{env_host}:{env_port}")
190
190
 
191
- # Simple, standard FastMCP run - no custom parameters
192
- mcp.run(transport="streamable-http", host=env_host, port=env_port)
191
+ mcp.run(transport="streamable-http")
napistu/mcp/tutorials.py CHANGED
@@ -50,7 +50,7 @@ def register_components(mcp: FastMCP) -> None:
50
50
 
51
51
  # Register resources
52
52
  @mcp.resource("napistu://tutorials/index")
53
- async def get_tutorial_index() -> List[Dict[str, Any]]:
53
+ async def get_tutorials_index() -> List[Dict[str, Any]]:
54
54
  """
55
55
  Get the index of all available tutorials.
56
56
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: napistu
3
- Version: 0.2.5.dev5
3
+ Version: 0.2.5.dev7
4
4
  Summary: Connecting high-dimensional data to curated pathways
5
5
  Home-page: https://github.com/napistu/napistu-py
6
6
  Author: Sean Hackett
@@ -28,16 +28,16 @@ napistu/ingestion/yeast.py,sha256=bwFBNxRq-dLDaddgBL1hpfZj0eQ56nBXyR_9n0NZT9Y,52
28
28
  napistu/mcp/__init__.py,sha256=gDkP4J4vAjgq96_760lXKDURPUpQxVIxaRO9XzYrqdA,1970
29
29
  napistu/mcp/__main__.py,sha256=UcxLERiTFp7H8OvA5bQ1KhCnmOQKp1DsQ4oYr5WFVw0,6410
30
30
  napistu/mcp/client.py,sha256=nTMKgEG-yEGM0bS54LXK85jVtlJvDXOniWsQbnj4FOI,6616
31
- napistu/mcp/codebase.py,sha256=H32R5vRJqsLpClURIUpemTO8F_YnFW1RDdaeEbYWotk,5674
31
+ napistu/mcp/codebase.py,sha256=88FR4e3n2RWlGrvqtisto2myNxwui5kfjTJIXi593jU,5323
32
32
  napistu/mcp/codebase_utils.py,sha256=r1nbDmGzq-NaH9cT11jC53mEjszQpwQ0uZUJkMHvgVs,10567
33
33
  napistu/mcp/constants.py,sha256=s0anHxVre6i6JYFQimB_ppRLDdqiCxbMHNVEYvf6O0U,2852
34
- napistu/mcp/documentation.py,sha256=L99GF5ilhq7CpzYkRy2BeOzKVQnolK_S9wqf8ChZY2Y,5216
34
+ napistu/mcp/documentation.py,sha256=eGiNkjZZnwwcVllkedI5AXAoCn2S5bfxnlp1xX4I1RE,5194
35
35
  napistu/mcp/documentation_utils.py,sha256=JH3BfVk2dpSLUvnC77iaeTIRknOBpNMBQ2qhquUhuJM,7099
36
- napistu/mcp/execution.py,sha256=cYhLzIvihtLjG4J195FZuCM8uVihtgW-R6J4zuPAY5s,12422
37
- napistu/mcp/health.py,sha256=l6Y8houdip7IOtYZ_pPJrFAFfynN6PntVJwdkcoQKmg,8249
36
+ napistu/mcp/execution.py,sha256=0udVpjAhYW51oyBzfeWuDsqnukjgBg56MHS2QoR3Q2c,12404
37
+ napistu/mcp/health.py,sha256=dCOK7OU3_IT-T7qQ3T0_kQlu2BpDAwjFbTvqTAaBUQo,8217
38
38
  napistu/mcp/profiles.py,sha256=Nbr1e-n7muJMcY0HxuEJQePUQWPM2koQ9roVLEZa7Pg,2027
39
- napistu/mcp/server.py,sha256=jP9JLHFfoS2iAeV7l5RcPt9CkRD5WX3bimrSh49Q5Wg,6129
40
- napistu/mcp/tutorials.py,sha256=QMX32aWaqRqj4vIc_PVDdT_t55ZBpw4xOWnfQyewZMk,3395
39
+ napistu/mcp/server.py,sha256=gCDcrUVirheJTF_P0NoKZSVD8VH51eKyDb21kx7P24c,6041
40
+ napistu/mcp/tutorials.py,sha256=vMW8WjV5G1F1LqTUu5CQtJ7XxZ3XY8annDew51zPJQc,3396
41
41
  napistu/mcp/tutorials_utils.py,sha256=6_s6FP2i8Na6VaKVzLDnSnA5JQVgyd3ZHEIz8HSHtzU,6599
42
42
  napistu/mcp/utils.py,sha256=WB4c6s8aPZLgi_Wvhhq0DE8Cnz2QGff0V8hrF1feVRg,1296
43
43
  napistu/modify/__init__.py,sha256=1kqmRHlEyI7VpILzurZb1URwC_UIc1PTMEBHQnjXW6s,246
@@ -59,7 +59,7 @@ napistu/rpy2/callr.py,sha256=76ICWj7Jso-qrYLNfiV-DgPyrMTdRXz_EhyGOD9CbFM,4301
59
59
  napistu/rpy2/constants.py,sha256=JpJqsxImZis8fFFfePXYdbkhUZhXDZoHSHVf92w1h8U,2619
60
60
  napistu/rpy2/netcontextr.py,sha256=fZKd3NXXu5nfB-z0UW6wedxBkZA8dJ4uB1uOD9wI_eg,16523
61
61
  napistu/rpy2/rids.py,sha256=lKyOujjdosuN-Oc54uCQI1nKchTx4zXPwgFbG7QX7d8,24153
62
- napistu-0.2.5.dev5.dist-info/licenses/LICENSE,sha256=kW8wVT__JWoHjl2BbbJDAZInWa9AxzJeR_uv6-i5x1g,1063
62
+ napistu-0.2.5.dev7.dist-info/licenses/LICENSE,sha256=kW8wVT__JWoHjl2BbbJDAZInWa9AxzJeR_uv6-i5x1g,1063
63
63
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
64
  tests/conftest.py,sha256=Xj5PWhedsR7HELbJfBY5XXzv_BAHbFMc1K2n6Nrbrno,2595
65
65
  tests/test_consensus.py,sha256=3dJvvPsPG7bHbw_FY4Pm647N_Gt_Ud9157OKYfPCUd4,9502
@@ -72,6 +72,7 @@ tests/test_identifiers.py,sha256=RyuPAMhYI8cDOl2r62idweLxgy7rAs9omeZQ62h56kY,501
72
72
  tests/test_igraph.py,sha256=vSGP13Bwaoznk6LsnOXoARxyh7VoT4fHvvTYcHT2lkw,11353
73
73
  tests/test_indices.py,sha256=-TrKfX4qXsofg_TPQEhHaQc_CuQMEd4_0maJgGCgSfE,2468
74
74
  tests/test_mcp_documentation_utils.py,sha256=lh9cKQIyMKntFVRG7Ui6oJ-gkawDta1Rfj_GEVG5k4M,470
75
+ tests/test_mcp_server.py,sha256=IPKxe0uRUFA-z1ndikD13GMMBMtC9dzuTQM4GtfmJLQ,6538
75
76
  tests/test_mechanism_matching.py,sha256=RYNlOG2voocPMv78xuvVIDZ8GpPyEEXaQXpkokn-EEI,28813
76
77
  tests/test_net_propagation.py,sha256=9pKkUdduWejH4iKNCJXKFzAkdNpCfrMbiUWySgI_LH4,3244
77
78
  tests/test_net_utils.py,sha256=QxZvZ5dPt-Of4zTOKe3_4Lv1VTZI3ClHiJWt2NJXZd0,4708
@@ -90,8 +91,8 @@ tests/test_uncompartmentalize.py,sha256=nAk5kfAVLU9a2VWe2x2HYVcKqj-EnwmwddERIPRa
90
91
  tests/test_utils.py,sha256=B9frW_ugWtGWsM-q7Lw7pnfE9a_d6LZTow9BrWU9UDw,17939
91
92
  tests/utils.py,sha256=SoWQ_5roJteFGcMaOeEiQ5ucwq3Z2Fa3AAs9iXHTsJY,749
92
93
  tests/test_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
93
- napistu-0.2.5.dev5.dist-info/METADATA,sha256=QBWh7R1Rmn-lFFxoHCxdutawA2bKIkk0CWDC4WB5Krs,3202
94
- napistu-0.2.5.dev5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
95
- napistu-0.2.5.dev5.dist-info/entry_points.txt,sha256=_QnaPOvJNA3IltxmZgWIiBoen-L1bPYX18YQfC7oJgQ,41
96
- napistu-0.2.5.dev5.dist-info/top_level.txt,sha256=Gpvk0a_PjrtqhYcQ9IDr3zR5LqpZ-uIHidQMIpjlvhY,14
97
- napistu-0.2.5.dev5.dist-info/RECORD,,
94
+ napistu-0.2.5.dev7.dist-info/METADATA,sha256=3FSO6fogLcCU1vbHeuRdVvmnSDGowyWPFaTnCqbzoNk,3202
95
+ napistu-0.2.5.dev7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
96
+ napistu-0.2.5.dev7.dist-info/entry_points.txt,sha256=_QnaPOvJNA3IltxmZgWIiBoen-L1bPYX18YQfC7oJgQ,41
97
+ napistu-0.2.5.dev7.dist-info/top_level.txt,sha256=Gpvk0a_PjrtqhYcQ9IDr3zR5LqpZ-uIHidQMIpjlvhY,14
98
+ napistu-0.2.5.dev7.dist-info/RECORD,,
@@ -0,0 +1,219 @@
1
+ """
2
+ Tests to validate MCP tool and resource naming conventions.
3
+ """
4
+
5
+ import re
6
+ from typing import List, Tuple
7
+ from fastmcp import FastMCP
8
+
9
+ from napistu.mcp import (
10
+ documentation,
11
+ codebase,
12
+ tutorials,
13
+ execution,
14
+ health,
15
+ )
16
+
17
+ # Regex patterns for validation
18
+ VALID_RESOURCE_PATH = re.compile(
19
+ r"^napistu://[a-zA-Z][a-zA-Z0-9_]*(?:/[a-zA-Z0-9_{}.-]+)*$"
20
+ )
21
+ VALID_TOOL_NAME = re.compile(r"^[a-zA-Z][a-zA-Z0-9_]*$")
22
+
23
+
24
+ def collect_resources_and_tools(mcp: FastMCP) -> Tuple[List[str], List[str]]:
25
+ """
26
+ Collect all registered resource paths and tool names from an MCP server instance.
27
+
28
+ Args:
29
+ mcp: FastMCP server instance
30
+
31
+ Returns:
32
+ Tuple of (resource_paths, tool_names)
33
+ """
34
+ # Get all registered resources and tools
35
+ resources = mcp._resource_manager.get_resources()
36
+ tool_names = mcp._tool_manager.get_tools()
37
+
38
+ # Extract resource paths from the resource objects
39
+ resource_paths = []
40
+
41
+ # Add all resources (including parameterized ones)
42
+ for resource in resources.values():
43
+ resource_paths.append(str(resource.uri))
44
+
45
+ return resource_paths, tool_names
46
+
47
+
48
+ def test_documentation_naming():
49
+ """Test that documentation component uses valid names."""
50
+ mcp = FastMCP("test")
51
+ documentation.register_components(mcp)
52
+
53
+ resource_paths, tool_names = collect_resources_and_tools(mcp)
54
+
55
+ # Check resource paths
56
+ for path in resource_paths:
57
+ assert VALID_RESOURCE_PATH.match(path), f"Invalid resource path: {path}"
58
+
59
+ # Check tool names
60
+ for name in tool_names:
61
+ assert VALID_TOOL_NAME.match(name), f"Invalid tool name: {name}"
62
+
63
+
64
+ def test_codebase_naming():
65
+ """Test that codebase component uses valid names."""
66
+ mcp = FastMCP("test")
67
+ codebase.register_components(mcp)
68
+
69
+ resource_paths, tool_names = collect_resources_and_tools(mcp)
70
+
71
+ # Check resource paths
72
+ for path in resource_paths:
73
+ assert VALID_RESOURCE_PATH.match(path), f"Invalid resource path: {path}"
74
+
75
+ # Check tool names
76
+ for name in tool_names:
77
+ assert VALID_TOOL_NAME.match(name), f"Invalid tool name: {name}"
78
+
79
+
80
+ def test_tutorials_naming():
81
+ """Test that tutorials component uses valid names."""
82
+ mcp = FastMCP("test")
83
+ tutorials.register_components(mcp)
84
+
85
+ resource_paths, tool_names = collect_resources_and_tools(mcp)
86
+
87
+ # Check resource paths
88
+ for path in resource_paths:
89
+ assert VALID_RESOURCE_PATH.match(path), f"Invalid resource path: {path}"
90
+
91
+ # Check tool names
92
+ for name in tool_names:
93
+ assert VALID_TOOL_NAME.match(name), f"Invalid tool name: {name}"
94
+
95
+
96
+ def test_execution_naming():
97
+ """Test that execution component uses valid names."""
98
+ mcp = FastMCP("test")
99
+ execution.register_components(mcp)
100
+
101
+ resource_paths, tool_names = collect_resources_and_tools(mcp)
102
+
103
+ # Check resource paths
104
+ for path in resource_paths:
105
+ assert VALID_RESOURCE_PATH.match(path), f"Invalid resource path: {path}"
106
+
107
+ # Check tool names
108
+ for name in tool_names:
109
+ assert VALID_TOOL_NAME.match(name), f"Invalid tool name: {name}"
110
+
111
+
112
+ def test_health_naming():
113
+ """Test that health component uses valid names."""
114
+ mcp = FastMCP("test")
115
+ health.register_components(mcp)
116
+
117
+ resource_paths, tool_names = collect_resources_and_tools(mcp)
118
+
119
+ # Check resource paths
120
+ for path in resource_paths:
121
+ assert VALID_RESOURCE_PATH.match(path), f"Invalid resource path: {path}"
122
+
123
+ # Check tool names
124
+ for name in tool_names:
125
+ assert VALID_TOOL_NAME.match(name), f"Invalid tool name: {name}"
126
+
127
+
128
+ def test_all_components_naming():
129
+ """Test that all components together use valid names without conflicts."""
130
+ mcp = FastMCP("test")
131
+
132
+ # Register all components
133
+ documentation.register_components(mcp)
134
+ codebase.register_components(mcp)
135
+ tutorials.register_components(mcp)
136
+ execution.register_components(mcp)
137
+ health.register_components(mcp)
138
+
139
+ resource_paths, tool_names = collect_resources_and_tools(mcp)
140
+
141
+ # Check for duplicate resource paths
142
+ path_counts = {}
143
+ for path in resource_paths:
144
+ assert VALID_RESOURCE_PATH.match(path), f"Invalid resource path: {path}"
145
+ path_counts[path] = path_counts.get(path, 0) + 1
146
+ assert path_counts[path] == 1, f"Duplicate resource path: {path}"
147
+
148
+ # Check for duplicate tool names
149
+ name_counts = {}
150
+ for name in tool_names:
151
+ assert VALID_TOOL_NAME.match(name), f"Invalid tool name: {name}"
152
+ name_counts[name] = name_counts.get(name, 0) + 1
153
+ assert name_counts[name] == 1, f"Duplicate tool name: {name}"
154
+
155
+
156
+ def test_expected_resources_exist():
157
+ """Test that all expected resources are registered."""
158
+ mcp = FastMCP("test")
159
+
160
+ # Register all components
161
+ documentation.register_components(mcp)
162
+ codebase.register_components(mcp)
163
+ tutorials.register_components(mcp)
164
+ execution.register_components(mcp)
165
+ health.register_components(mcp)
166
+
167
+ resource_paths, _ = collect_resources_and_tools(mcp)
168
+
169
+ # Debug: Print all registered resources
170
+ print("\nRegistered resources:")
171
+ for path in sorted(resource_paths):
172
+ print(f" {path}")
173
+ print()
174
+
175
+ # List of expected base resources (no templates)
176
+ expected_resources = {
177
+ "napistu://documentation/summary",
178
+ "napistu://codebase/summary",
179
+ "napistu://tutorials/index",
180
+ "napistu://execution/registry",
181
+ "napistu://execution/environment",
182
+ "napistu://health",
183
+ }
184
+
185
+ # Check that each expected resource exists
186
+ for resource in expected_resources:
187
+ assert resource in resource_paths, f"Missing expected resource: {resource}"
188
+
189
+
190
+ def test_expected_tools_exist():
191
+ """Test that all expected tools are registered."""
192
+ mcp = FastMCP("test")
193
+
194
+ # Register all components
195
+ documentation.register_components(mcp)
196
+ codebase.register_components(mcp)
197
+ tutorials.register_components(mcp)
198
+ execution.register_components(mcp)
199
+ health.register_components(mcp)
200
+
201
+ _, tool_names = collect_resources_and_tools(mcp)
202
+
203
+ # List of expected tools
204
+ expected_tools = {
205
+ "search_documentation",
206
+ "search_codebase",
207
+ "get_function_documentation",
208
+ "get_class_documentation",
209
+ "search_tutorials",
210
+ "list_registry",
211
+ "describe_object",
212
+ "execute_function",
213
+ "search_paths",
214
+ "check_health",
215
+ }
216
+
217
+ # Check that all expected tools exist
218
+ for tool in expected_tools:
219
+ assert tool in tool_names, f"Missing expected tool: {tool}"