mcp-as-code 0.1.0__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.
maco/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """maco Python interface generator and MCP code-execution server."""
2
+
3
+ __version__ = "0.1.0"
maco/_build_info.py ADDED
@@ -0,0 +1,4 @@
1
+ """Build metadata embedded during release builds."""
2
+
3
+ COMMIT_SHA = "08491b148578850fa5db449fb473cceb63841359"
4
+ RELEASE_DATE = "2026-06-14"
maco/cli.py ADDED
@@ -0,0 +1,258 @@
1
+ """Command line interface for maco."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import os
7
+ import sys
8
+
9
+ from .codegen import generate, generate_sandbox_sdk_from_gateway
10
+ from .config import ConfigError, load_config
11
+ from .gateway import ServeOptions, serve
12
+ from .runner import RunnerError, exit_with_error, run_code
13
+ from .sandbox import DEFAULT_SANDBOX_IMAGE, SANDBOX_SDK_ROOT
14
+ from .serve_mcp import ServeMcpOptions, serve_mcp
15
+ from .version import get_version_info
16
+
17
+
18
+ def build_parser() -> argparse.ArgumentParser:
19
+ parser = argparse.ArgumentParser(
20
+ prog="maco",
21
+ description="Generate and execute Python code interfaces for MCP tools.",
22
+ )
23
+ subparsers = parser.add_subparsers(dest="command", required=True)
24
+
25
+ version_parser = subparsers.add_parser("version", help="print maco version and release metadata")
26
+ version_parser.set_defaults(func=_cmd_version)
27
+
28
+ gen = subparsers.add_parser("gen", help="generate Python wrappers for configured MCP tools")
29
+ gen.add_argument("--config", default="mcp.json", help="MCP config path (default: mcp.json)")
30
+ gen.add_argument("--workspace", default=".maco", help="generated workspace directory (default: .maco)")
31
+ gen.add_argument("--server", help="only generate wrappers for one configured server")
32
+ gen.add_argument("--clean", action="store_true", help="remove the workspace before generating")
33
+ gen.set_defaults(func=_cmd_gen)
34
+
35
+ serve_parser = subparsers.add_parser("serve", help="run the local maco gateway server")
36
+ serve_parser.add_argument("--config", default="mcp.json", help="MCP config path (default: mcp.json)")
37
+ serve_parser.add_argument("--workspace", default=".maco", help="generated workspace directory (default: .maco)")
38
+ serve_parser.add_argument("--clean", action="store_true", help="remove the workspace before generating")
39
+ serve_parser.add_argument("--host", default="127.0.0.1", help="host to bind (default: 127.0.0.1)")
40
+ serve_parser.add_argument("--port", default=0, type=int, help="port to bind (default: 0, an ephemeral port)")
41
+ serve_parser.add_argument("--token", help="explicit bearer token for generated code")
42
+ serve_parser.add_argument("--no-token", action="store_true", help="disable gateway bearer-token protection")
43
+ serve_parser.set_defaults(func=_cmd_serve)
44
+
45
+ run = subparsers.add_parser("run", help="run a Python file with generated wrappers available")
46
+ run.add_argument("--workspace", help="generated workspace directory (default: auto-detect)")
47
+ run.add_argument("--cwd", help="working directory for the script")
48
+ run.add_argument("--python", help="Python version/interpreter to pass to uv run")
49
+ run.add_argument("code_path", help="Python file to execute")
50
+ run.add_argument("script_args", nargs=argparse.REMAINDER, help="arguments passed to the Python file")
51
+ run.set_defaults(func=_cmd_run)
52
+
53
+ serve_mcp = subparsers.add_parser(
54
+ "serve-mcp",
55
+ help="run an HTTP MCP server exposing sandboxed bash and code execution",
56
+ )
57
+ _add_serve_mcp_options(serve_mcp)
58
+ serve_mcp.set_defaults(func=_cmd_serve_mcp)
59
+
60
+ sandbox_bootstrap = subparsers.add_parser(
61
+ "sandbox-bootstrap",
62
+ help=argparse.SUPPRESS,
63
+ )
64
+ sandbox_bootstrap.add_argument("--gateway-url", help=argparse.SUPPRESS)
65
+ sandbox_bootstrap.add_argument("--gateway-token", help=argparse.SUPPRESS)
66
+ sandbox_bootstrap.add_argument("--workspace", default=SANDBOX_SDK_ROOT, help=argparse.SUPPRESS)
67
+ sandbox_bootstrap.add_argument("--no-clean", action="store_true", help=argparse.SUPPRESS)
68
+ sandbox_bootstrap.set_defaults(func=_cmd_sandbox_bootstrap)
69
+
70
+ return parser
71
+
72
+
73
+ def _add_serve_mcp_options(command: argparse.ArgumentParser) -> None:
74
+ command.add_argument("--config", default="mcp.json", help="MCP config path (default: mcp.json)")
75
+ command.add_argument(
76
+ "--provider",
77
+ choices=["local", "docker", "matchlock"],
78
+ default="local",
79
+ help="sandbox provider to use (default: local)",
80
+ )
81
+ command.add_argument("--workspace", default=".maco", help="generated workspace directory")
82
+ command.add_argument("--clean", action="store_true", help="remove the workspace before generating")
83
+ command.add_argument("--scratch", help="writable scratch directory for sandbox code")
84
+ command.add_argument(
85
+ "--gateway-file",
86
+ help="connect to an existing gateway.json instead of starting a managed gateway",
87
+ )
88
+ command.add_argument(
89
+ "--gateway-host",
90
+ help="host for the managed gateway started by serve-mcp",
91
+ )
92
+ command.add_argument(
93
+ "--gateway-port",
94
+ default=0,
95
+ type=int,
96
+ help="port for the managed gateway started by serve-mcp (default: 0)",
97
+ )
98
+ command.add_argument("--gateway-token", help="explicit bearer token for the managed gateway")
99
+ command.add_argument(
100
+ "--no-gateway-token",
101
+ action="store_true",
102
+ help="disable bearer-token protection for the managed gateway",
103
+ )
104
+ command.add_argument("--host", default="127.0.0.1", help="HTTP MCP bind host")
105
+ command.add_argument("--port", default=8789, type=int, help="HTTP MCP bind port")
106
+ command.add_argument("--timeout", default=60, type=int, help="default command timeout in seconds")
107
+ command.add_argument(
108
+ "--debug",
109
+ action="store_true",
110
+ help="log provider command summaries to server stderr",
111
+ )
112
+ command.add_argument(
113
+ "--image",
114
+ help=f"container image for docker/matchlock providers (default: {DEFAULT_SANDBOX_IMAGE})",
115
+ )
116
+ command.add_argument("--python-command", help="guest command prefix used by code_execute")
117
+ command.add_argument("--docker-binary", default="docker", help="docker binary path/name")
118
+ command.add_argument("--docker-network", help="docker network passed to `docker run --network`")
119
+ command.add_argument(
120
+ "--docker-gateway-host",
121
+ default="host.docker.internal",
122
+ help="hostname inside docker that reaches the host gateway",
123
+ )
124
+ command.add_argument(
125
+ "--docker-gateway-ip",
126
+ help="explicit host gateway IP to map inside Docker; usually auto-detected",
127
+ )
128
+ command.add_argument("--matchlock-binary", default="matchlock", help="matchlock binary path/name")
129
+ command.add_argument(
130
+ "--matchlock-gateway-host",
131
+ default="maco-gateway.internal",
132
+ help="hostname inside matchlock that reaches the host gateway",
133
+ )
134
+ command.add_argument(
135
+ "--matchlock-gateway-ip",
136
+ help="IP for --add-host <gateway-host>:<ip> inside matchlock (default: 192.168.100.1 for managed gateways)",
137
+ )
138
+ command.add_argument(
139
+ "--matchlock-allow-host",
140
+ action="append",
141
+ default=[],
142
+ help="extra host to allow from the matchlock sandbox (repeatable)",
143
+ )
144
+
145
+
146
+ def main(argv: list[str] | None = None) -> int:
147
+ parser = build_parser()
148
+ args = parser.parse_args(argv)
149
+ try:
150
+ return args.func(args)
151
+ except (ConfigError, RunnerError, OSError, ValueError) as exc:
152
+ exit_with_error(exc)
153
+ return 0
154
+
155
+
156
+ def _cmd_version(args: argparse.Namespace) -> int:
157
+ info = get_version_info()
158
+ print(f"version: {info.version}")
159
+ print(f"commit: {info.commit_sha}")
160
+ print(f"release date: {info.release_date}")
161
+ return 0
162
+
163
+
164
+ def _cmd_gen(args: argparse.Namespace) -> int:
165
+ config = load_config(args.config)
166
+ stats = generate(
167
+ config,
168
+ workspace=args.workspace,
169
+ server_filter=args.server,
170
+ clean=args.clean,
171
+ )
172
+ print(f"Generated {stats.tool_count} tools from {stats.server_count} servers")
173
+ print(f"Workspace: {stats.workspace}")
174
+ print("Explore: rg --files {}/maco_generated/servers".format(stats.workspace))
175
+ return 0
176
+
177
+
178
+ def _cmd_serve(args: argparse.Namespace) -> int:
179
+ config = load_config(args.config)
180
+ stats = generate(config, workspace=args.workspace, clean=args.clean)
181
+ print(f"Generated {stats.tool_count} tools from {stats.server_count} servers")
182
+ print(f"Workspace: {stats.workspace}")
183
+ serve(
184
+ config,
185
+ ServeOptions(
186
+ host=args.host,
187
+ port=args.port,
188
+ workspace=args.workspace,
189
+ token=args.token,
190
+ use_token=not args.no_token,
191
+ ),
192
+ )
193
+ return 0
194
+
195
+
196
+ def _cmd_run(args: argparse.Namespace) -> int:
197
+ script_args = list(args.script_args or [])
198
+ if script_args and script_args[0] == "--":
199
+ script_args = script_args[1:]
200
+ return run_code(
201
+ args.code_path,
202
+ script_args,
203
+ workspace=args.workspace,
204
+ cwd=args.cwd,
205
+ python=args.python,
206
+ )
207
+
208
+
209
+ def _cmd_serve_mcp(args: argparse.Namespace) -> int:
210
+ serve_mcp(
211
+ ServeMcpOptions(
212
+ config=args.config,
213
+ provider=args.provider,
214
+ workspace=args.workspace,
215
+ clean=args.clean,
216
+ scratch=args.scratch,
217
+ gateway_file=args.gateway_file,
218
+ gateway_host=args.gateway_host,
219
+ gateway_port=args.gateway_port,
220
+ gateway_token=args.gateway_token,
221
+ gateway_use_token=not args.no_gateway_token,
222
+ host=args.host,
223
+ port=args.port,
224
+ timeout=args.timeout,
225
+ debug=args.debug,
226
+ image=args.image,
227
+ python_command=args.python_command,
228
+ docker_binary=args.docker_binary,
229
+ docker_network=args.docker_network,
230
+ docker_gateway_host=args.docker_gateway_host,
231
+ docker_gateway_ip=args.docker_gateway_ip,
232
+ matchlock_binary=args.matchlock_binary,
233
+ matchlock_gateway_host=args.matchlock_gateway_host,
234
+ matchlock_gateway_ip=args.matchlock_gateway_ip,
235
+ matchlock_allow_host=tuple(args.matchlock_allow_host or []),
236
+ )
237
+ )
238
+ return 0
239
+
240
+
241
+ def _cmd_sandbox_bootstrap(args: argparse.Namespace) -> int:
242
+ gateway_url = args.gateway_url or os.environ.get("MACO_GATEWAY_URL")
243
+ if not gateway_url:
244
+ raise ValueError("sandbox bootstrap requires --gateway-url or MACO_GATEWAY_URL")
245
+ stats = generate_sandbox_sdk_from_gateway(
246
+ gateway_url,
247
+ token=args.gateway_token or os.environ.get("MACO_GATEWAY_TOKEN"),
248
+ workspace=args.workspace,
249
+ clean=not args.no_clean,
250
+ )
251
+ print(f"Generated sandbox SDK with {stats.tool_count} tools from {stats.server_count} servers")
252
+ print(f"Workspace: {stats.workspace}")
253
+ print(f"Explore: rg --files {stats.workspace}/tools")
254
+ return 0
255
+
256
+
257
+ if __name__ == "__main__": # pragma: no cover
258
+ raise SystemExit(main(sys.argv[1:]))