materials-commons-cli 2.3.0b7__tar.gz → 2.3.0b8__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.
Files changed (105) hide show
  1. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/PKG-INFO +1 -1
  2. materials_commons_cli-2.3.0b8/materials_commons/cli/__init__.py +1 -0
  3. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/async_reconciler.py +26 -21
  4. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/downloader.py +2 -0
  5. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/parser.py +3 -1
  6. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/downloader/file_download_manager.py +3 -0
  7. materials_commons_cli-2.3.0b8/materials_commons/cli/subcommands/mcp.py +86 -0
  8. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/up.py +2 -1
  9. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/walk.py +0 -3
  10. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons_cli.egg-info/PKG-INFO +1 -1
  11. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons_cli.egg-info/SOURCES.txt +1 -0
  12. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons_cli.egg-info/requires.txt +1 -0
  13. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/setup.py +1 -0
  14. materials_commons_cli-2.3.0b7/materials_commons/cli/__init__.py +0 -1
  15. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/LICENSE +0 -0
  16. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/README.md +0 -0
  17. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/LICENSE.txt +0 -0
  18. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/config.py +0 -0
  19. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/filedb.py +0 -0
  20. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/local_project.py +0 -0
  21. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/models.py +0 -0
  22. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/__init__.py +0 -0
  23. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/cloned_project.py +0 -0
  24. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/exceptions.py +0 -0
  25. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/file_functions.py +0 -0
  26. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/functions.py +0 -0
  27. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/globus.py +0 -0
  28. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/list_objects.py +0 -0
  29. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/print_formatter.py +0 -0
  30. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/sqltable.py +0 -0
  31. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/tmp_functions.py +0 -0
  32. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/tree_functions.py +0 -0
  33. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/treedb.py +0 -0
  34. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/old/user_config.py +0 -0
  35. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/reconcile2.py +0 -0
  36. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/reconcile3.py +0 -0
  37. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/requests.py +0 -0
  38. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/run.py +0 -0
  39. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/__init__.py +0 -0
  40. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/command_handlers/__init__.py +0 -0
  41. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/command_handlers/admin_handler_lookup.py +0 -0
  42. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/command_handlers/download_handler_lookup.py +0 -0
  43. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/command_handlers/list_handler_lookup.py +0 -0
  44. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/command_handlers/multi_handler_lookup.py +0 -0
  45. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/command_handlers/protocol.py +0 -0
  46. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/command_handlers/search_find_handler_lookup.py +0 -0
  47. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/command_handlers/upload_handler_lookup.py +0 -0
  48. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/db/__init__.py +0 -0
  49. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/db/db_manager.py +0 -0
  50. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/downloader/__init__.py +0 -0
  51. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/downloader/file_downloader.py +0 -0
  52. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/indexer/__init__.py +0 -0
  53. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/indexer/file_index_manager.py +0 -0
  54. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/local_rest_server.py +0 -0
  55. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/ocommand_handlers.py +0 -0
  56. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/project_filedbs.py +0 -0
  57. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/projects.py +0 -0
  58. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/service_container.py +0 -0
  59. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/service_runtime.py +0 -0
  60. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/uploader/__init__.py +0 -0
  61. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/uploader/client_api.py +0 -0
  62. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/uploader/file_upload_manager.py +0 -0
  63. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/uploader/file_uploader.py +0 -0
  64. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/server/websocket_server.py +0 -0
  65. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/__init__.py +0 -0
  66. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/clone.py +0 -0
  67. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/config.py +0 -0
  68. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/dataset.py +0 -0
  69. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/down.py +0 -0
  70. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/down2.py +0 -0
  71. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/expt.py +0 -0
  72. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/fetch.py +0 -0
  73. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/globus.py +0 -0
  74. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/init.py +0 -0
  75. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/ls.py +0 -0
  76. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/ls2.py +0 -0
  77. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/mkdir.py +0 -0
  78. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/mv.py +0 -0
  79. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/proj.py +0 -0
  80. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/remote.py +0 -0
  81. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/rm.py +0 -0
  82. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/runners/__init__.py +0 -0
  83. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/runners/download_globus_runner.py +0 -0
  84. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/runners/download_v1_runner.py +0 -0
  85. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/scan.py +0 -0
  86. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/server.py +0 -0
  87. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons/cli/subcommands/versions.py +0 -0
  88. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons_cli.egg-info/dependency_links.txt +0 -0
  89. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons_cli.egg-info/entry_points.txt +0 -0
  90. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons_cli.egg-info/not-zip-safe +0 -0
  91. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/materials_commons_cli.egg-info/top_level.txt +0 -0
  92. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/setup.cfg +0 -0
  93. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_api.py +0 -0
  94. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_functions.py +0 -0
  95. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_mc_dataset.py +0 -0
  96. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_mc_down.py +0 -0
  97. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_mc_mkdir.py +0 -0
  98. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_mc_mv.py +0 -0
  99. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_mc_proj.py +0 -0
  100. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_mc_rm.py +0 -0
  101. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_mc_up.py +0 -0
  102. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_treecompare_no_cache.py +0 -0
  103. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_treecompare_with_cache.py +0 -0
  104. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_treedb.py +0 -0
  105. {materials_commons_cli-2.3.0b7 → materials_commons_cli-2.3.0b8}/test/test_user_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: materials_commons_cli
3
- Version: 2.3.0b7
3
+ Version: 2.3.0b8
4
4
  Summary: Materials Commons CLI
5
5
  Home-page: https://materials-commons.github.io/materials-commons-cli/html/index.html
6
6
  Author: Materials Commons development team
@@ -0,0 +1 @@
1
+ __version__ = '2.3.0b8'
@@ -17,12 +17,14 @@ class AsyncReconciler:
17
17
  db: FileIndexDB,
18
18
  reconcile_mode: ReconcileMode,
19
19
  # recompute_checksum: bool = True,
20
- max_concurrent: int = 10):
20
+ max_concurrent: int = 10,
21
+ batch_size: Optional[int] = None):
21
22
  self.proj = proj
22
23
  self.db = db
23
24
  # self.recompute_checksum = recompute_checksum
24
25
  self.max_concurrent = max_concurrent
25
26
  self.reconcile_mode = reconcile_mode
27
+ self.batch_size = batch_size or max_concurrent
26
28
  self.reconciler = SingleFileReconciler(proj=self.proj, mode=reconcile_mode)
27
29
 
28
30
  async def walk(self, path: str | Path, listdir_fn: ListDirFunc, recursive: bool = False,
@@ -35,36 +37,39 @@ class AsyncReconciler:
35
37
 
36
38
  async for current_path, observations in async_walk(path, recursive=recursive, listdir_fn=listdir_fn,
37
39
  ignore_fn=ignore_fn):
38
- path_states: dict[str, FileState] = {}
39
40
  remote_dir = projects.local_to_remote_project_path(Path(self.proj.local_path), Path(current_path))
40
41
 
41
42
  # Create a map of file_records to name
42
43
  file_records = await self.db.get_files_by_dir(remote_dir.as_posix())
43
44
  file_records_map = {file_record.name: file_record for file_record in file_records}
44
45
 
45
- # Go through all the observations and match to the file records
46
- for obs in observations:
47
- obs.file_record = file_records_map.get(obs.name, None)
48
- obs.remote_path = remote_dir / obs.name
49
- path_states[obs.name] = FileState(observation=obs)
46
+ # Handle a batch of records rather than the entire directory
47
+ for start in range(0, len(observations), self.batch_size):
48
+ batch_observations = observations[start:start + self.batch_size]
49
+ path_states: dict[str, FileState] = {}
50
50
 
51
- results = await asyncio.gather(
52
- *[single_entry_reconcile(state.observation) for state in path_states.values()],
53
- return_exceptions=True)
51
+ # Go through all the observations and match to the file records
52
+ for obs in batch_observations:
53
+ obs.file_record = file_records_map.get(obs.name, None)
54
+ obs.remote_path = remote_dir / obs.name
55
+ path_states[obs.name] = FileState(observation=obs)
54
56
 
55
- # At this point path_entries contains entries in one of 4 states:
56
- # 1. Both remote and local entries exist
57
- # 2. Only remote entry exists
58
- # 3. Only local entry exists
59
- # 4. Lookup failed, and we got an exception
57
+ results = await asyncio.gather(
58
+ *[single_entry_reconcile(state.observation) for state in path_states.values()],
59
+ return_exceptions=True)
60
60
 
61
- for state, result in zip(path_states.values(), results):
62
- if isinstance(result, Exception):
63
- state.exception = result
64
- else:
65
- state.file_decision = result
61
+ # At this point path_entries contains entries in one of 4 states:
62
+ # 1. Both remote and local entries exist
63
+ # 2. Only remote entry exists
64
+ # 3. Only local entry exists
65
+ # 4. Lookup failed, and we got an exception
66
+ for state, result in zip(path_states.values(), results):
67
+ if isinstance(result, Exception):
68
+ state.exception = result
69
+ else:
70
+ state.file_decision = result
66
71
 
67
- yield current_path, path_states
72
+ yield current_path, path_states
68
73
 
69
74
  async def reconcile_file(self, path: str | Path) -> FileState:
70
75
  remote_project_path = projects.local_to_remote_project_path(Path(self.proj.local_path), Path(path))
@@ -116,3 +116,5 @@ class Downloader:
116
116
  print(f"Downloading {entry_name} to {current_path / entry_name}...")
117
117
  transfer_id = await self.container.file_download_manager.download_file(download_request)
118
118
  self.transfer_ids.append(transfer_id)
119
+ else:
120
+ print(f"Skipping download of {entry_name} because {file_state.file_decision.reason}")
@@ -25,6 +25,7 @@ from materials_commons.cli.subcommands.globus import globus_subcommand
25
25
  from materials_commons.cli.subcommands.init import init_subcommand
26
26
  from materials_commons.cli.subcommands.ls import ls_subcommand
27
27
  from materials_commons.cli.subcommands.ls2 import ls2_subcommand
28
+ from materials_commons.cli.subcommands.mcp import mcp_subcommand
28
29
  from materials_commons.cli.subcommands.mkdir import mkdir_subcommand
29
30
  from materials_commons.cli.subcommands.mv import mv_subcommand
30
31
  # from materials_commons.cli.subcommands.proc import ProcSubcommand
@@ -58,7 +59,8 @@ standard_usage = [
58
59
  # {'name': 'ls2', 'desc': 'List directory contents (experimental)', 'subcommand': ls2_subcommand},
59
60
  # {'name': 'down2', 'desc': 'Donwload files (experimental)', 'subcommand': down2_subcommand},
60
61
  {'name': 'config', 'desc': 'Configure `mc`', 'subcommand': config_subcommand},
61
- {'name': 'server', 'desc': 'Run MC Server', 'subcommand': server_subcommand}
62
+ {'name': 'server', 'desc': 'Run MC Server', 'subcommand': server_subcommand},
63
+ {'name': 'mcp', 'desc': 'Run MCP Server', 'subcommand': mcp_subcommand},
62
64
  ]
63
65
  standard_interfaces = {d['name']: d for d in standard_usage}
64
66
 
@@ -25,6 +25,9 @@ class FileDownloadManager:
25
25
 
26
26
  async def start_workers(self) -> None:
27
27
  """Start background workers to process download queue"""
28
+ if self._workers_running:
29
+ logger.info("Download workers already running")
30
+ return
28
31
  self._workers_running = True
29
32
  self._worker_tasks = [
30
33
  asyncio.create_task(self._download_worker(i))
@@ -0,0 +1,86 @@
1
+ import argparse
2
+ import functools
3
+ import inspect
4
+
5
+ from mcp.server.fastmcp import FastMCP
6
+ from materials_commons.cli.config import Config
7
+ from materials_commons.api.client import Client
8
+
9
+
10
+ mcp = FastMCP(
11
+ name="mcmcp",
12
+ instructions=""
13
+ )
14
+
15
+
16
+ def make_parser():
17
+ parser = argparse.ArgumentParser(
18
+ description="MCP Server for Materials Commons",
19
+ usage="mc mcp",
20
+ )
21
+ parser.add_argument("--port", type=int, default=8000)
22
+ parser.add_argument("--mc-url", type=str, default="https://materialscommons.org/api")
23
+ return parser
24
+
25
+ def mcp_subcommand(argv, working_dir=None):
26
+ parser = make_parser()
27
+ args = parser.parse_args(argv)
28
+ config = Config.load()
29
+ client = config.default_remote.make_client()
30
+ register_mcapi_tools(client)
31
+ mcp.run()
32
+ return args
33
+
34
+ def register_mcapi_tools(client: Client):
35
+ for method_name, method in inspect.getmembers(client, predicate=callable):
36
+ if method_name.startswith("_"):
37
+ continue
38
+ if not is_get_or_list_method(method_name):
39
+ continue
40
+
41
+ doc = inspect.getdoc(method)
42
+ if doc is None:
43
+ continue
44
+
45
+ signature = inspect.signature(method)
46
+
47
+ @functools.wraps(method)
48
+ def tool_wrapper(*args, __method=method, **kwargs):
49
+ result = __method(*args, **kwargs)
50
+ return to_jsonable(result)
51
+
52
+ tool_wrapper.__name__ = method_name
53
+ tool_wrapper.__doc__ = doc
54
+ tool_wrapper.__signature__ = signature
55
+
56
+ mcp.tool(name=method_name)(tool_wrapper)
57
+
58
+ def is_get_or_list_method(method_name: str):
59
+ return method_name.startswith("get_") or method_name.startswith("list_")
60
+
61
+ def to_jsonable(value):
62
+ if value is None:
63
+ return None
64
+
65
+ if isinstance(value, (str, int, float, bool)):
66
+ return value
67
+
68
+ if isinstance(value, list):
69
+ return [to_jsonable(item) for item in value]
70
+
71
+ if isinstance(value, tuple):
72
+ return [to_jsonable(item) for item in value]
73
+
74
+ if isinstance(value, dict):
75
+ return {
76
+ str(key): to_jsonable(item)
77
+ for key, item in value.items()
78
+ }
79
+
80
+ if hasattr(value, "to_dict"):
81
+ return to_jsonable(value.to_dict())
82
+
83
+ if hasattr(value, "__dict__"):
84
+ return to_jsonable(value.__dict__)
85
+
86
+ return str(value)
@@ -208,6 +208,7 @@ async def ws_upload(args, working_dir):
208
208
  file_state = path_entries[entry_name]
209
209
  if file_state.exception:
210
210
  logger.error(f"Error encountered while processing {entry_name}: {file_state.exception}")
211
+ # print(f"Error encountered while processing {entry_name}: {file_state.exception}")
211
212
  continue
212
213
  if file_state.file_decision.action == "upload":
213
214
  upload_request = UploadRequest(observation=file_state.observation,
@@ -219,7 +220,7 @@ async def ws_upload(args, working_dir):
219
220
  file_state = await async_reconciler.reconcile_file(p)
220
221
  if file_state.exception:
221
222
  logger.error(f"Error encountered while processing {p}: {file_state.exception}")
222
- print(f"Error encountered while processing {p}: {file_state.exception}")
223
+ # print(f"Error encountered while processing {p}: {file_state.exception}")
223
224
  continue
224
225
  if file_state.file_decision.action == "upload":
225
226
  upload_request = UploadRequest(observation=file_state.observation,
@@ -141,7 +141,6 @@ async def local_listdir(path: str | Path) -> list[Observation]:
141
141
 
142
142
  def mcapi_file_to_remote_file_entry(entry: mcmodel.File) -> RemoteFileEntry:
143
143
  kind: EntryKind = "dir" if entry.mime_type == "directory" else "file"
144
- print(f"mcapi_file_to_remote_file_entry called for entry: {entry.mime_type}, {entry.name}, {entry.directory.path}")
145
144
  remote_entry = RemoteFileEntry(
146
145
  path=Path(entry.directory.path) / entry.name,
147
146
  name=entry.name,
@@ -163,7 +162,6 @@ async def remote_listdir(project_path: str | Path, proj: OldLocalProject) -> lis
163
162
  project_path: The path within the project to list directory contents of.
164
163
  proj: The local project object representing the remote project.
165
164
  """
166
- print(f"remote_listdir called for project_path: {project_path}, proj: {proj}")
167
165
  entries = await asyncio.to_thread(proj.remote.list_directory_by_path, proj.id, project_path.as_posix())
168
166
  items: list[Observation] = []
169
167
  for entry in entries:
@@ -206,7 +204,6 @@ async def merged_local_remote_listdir(
206
204
  """
207
205
  Merge local and remote directory listings, prioritizing local entries.
208
206
  """
209
- print(f"merged_local_remote_listdir {proj.local_path}, {path}")
210
207
  local_entries = await local_listdir_fn(path)
211
208
 
212
209
  project_path = projects.local_to_remote_project_path(Path(proj.local_path), path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: materials-commons-cli
3
- Version: 2.3.0b7
3
+ Version: 2.3.0b8
4
4
  Summary: Materials Commons CLI
5
5
  Home-page: https://materials-commons.github.io/materials-commons-cli/html/index.html
6
6
  Author: Materials Commons development team
@@ -68,6 +68,7 @@ materials_commons/cli/subcommands/globus.py
68
68
  materials_commons/cli/subcommands/init.py
69
69
  materials_commons/cli/subcommands/ls.py
70
70
  materials_commons/cli/subcommands/ls2.py
71
+ materials_commons/cli/subcommands/mcp.py
71
72
  materials_commons/cli/subcommands/mkdir.py
72
73
  materials_commons/cli/subcommands/mv.py
73
74
  materials_commons/cli/subcommands/proj.py
@@ -11,3 +11,4 @@ setuptools
11
11
  sortedcontainers
12
12
  tabulate
13
13
  aiosqlite
14
+ fastmcp
@@ -72,5 +72,6 @@ setup(
72
72
  "sortedcontainers",
73
73
  "tabulate",
74
74
  "aiosqlite",
75
+ "fastmcp",
75
76
  ]
76
77
  )
@@ -1 +0,0 @@
1
- __version__ = '2.3.0b7'