sunholo 0.143.16__py3-none-any.whl → 0.144.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.
- sunholo/agents/dispatch_to_qa.py +16 -2
- sunholo/agents/fastapi/__init__.py +2 -1
- sunholo/agents/fastapi/vac_routes.py +1017 -0
- sunholo/mcp/cli.py +22 -338
- sunholo/mcp/cli_fastmcp.py +201 -0
- sunholo/mcp/vac_mcp_server.py +4 -247
- sunholo/mcp/vac_mcp_server_fastmcp.py +193 -0
- sunholo/streaming/streaming.py +26 -6
- {sunholo-0.143.16.dist-info → sunholo-0.144.0.dist-info}/METADATA +12 -10
- {sunholo-0.143.16.dist-info → sunholo-0.144.0.dist-info}/RECORD +14 -11
- {sunholo-0.143.16.dist-info → sunholo-0.144.0.dist-info}/WHEEL +0 -0
- {sunholo-0.143.16.dist-info → sunholo-0.144.0.dist-info}/entry_points.txt +0 -0
- {sunholo-0.143.16.dist-info → sunholo-0.144.0.dist-info}/licenses/LICENSE.txt +0 -0
- {sunholo-0.143.16.dist-info → sunholo-0.144.0.dist-info}/top_level.txt +0 -0
sunholo/mcp/cli.py
CHANGED
@@ -1,338 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
from pydantic import AnyUrl
|
25
|
-
|
26
|
-
# Configure logging
|
27
|
-
from ..custom_logging import setup_logging
|
28
|
-
logger = setup_logging("sunholo-mcp")
|
29
|
-
|
30
|
-
class SunholoMCPServer:
|
31
|
-
def __init__(self):
|
32
|
-
logger.info("Initializing Sunholo MCP Server")
|
33
|
-
|
34
|
-
if Server is None:
|
35
|
-
raise ImportError("SunholoMCPServer requires `sunholo[anthropic]` to be installed")
|
36
|
-
|
37
|
-
self.server = Server("sunholo-mcp-server")
|
38
|
-
self.server.onerror = self.handle_error
|
39
|
-
|
40
|
-
self.setup_handlers()
|
41
|
-
|
42
|
-
def handle_error(self, error: Exception):
|
43
|
-
"""Handle server errors"""
|
44
|
-
logger.error(f"MCP Server error: {error}", exc_info=True)
|
45
|
-
|
46
|
-
def setup_handlers(self):
|
47
|
-
"""Set up all the MCP protocol handlers"""
|
48
|
-
self.setup_resource_handlers()
|
49
|
-
self.setup_tool_handlers()
|
50
|
-
|
51
|
-
def setup_resource_handlers(self):
|
52
|
-
"""Configure resource-related handlers"""
|
53
|
-
|
54
|
-
@self.server.list_resources()
|
55
|
-
async def list_resources() -> list[Resource]:
|
56
|
-
"""List available Sunholo resources"""
|
57
|
-
return [
|
58
|
-
Resource(
|
59
|
-
uri="sunholo://vacs/list",
|
60
|
-
name="Available Sunholo VACs",
|
61
|
-
mimeType="application/json",
|
62
|
-
description="List of available Virtual Agent Computers"
|
63
|
-
)
|
64
|
-
]
|
65
|
-
|
66
|
-
@self.server.read_resource()
|
67
|
-
async def read_resource(uri: AnyUrl) -> str:
|
68
|
-
"""Read Sunholo resources based on URI"""
|
69
|
-
logger.info(f"{uri} available")
|
70
|
-
if str(uri) == "sunholo://vacs/list":
|
71
|
-
try:
|
72
|
-
# Execute sunholo vac list command
|
73
|
-
result = subprocess.run(
|
74
|
-
["sunholo", "vac", "list"],
|
75
|
-
capture_output=True,
|
76
|
-
text=True
|
77
|
-
)
|
78
|
-
return result.stdout
|
79
|
-
except subprocess.CalledProcessError as e:
|
80
|
-
raise RuntimeError(f"Failed to list VACs: {str(e)}")
|
81
|
-
except Exception as e:
|
82
|
-
raise RuntimeError(f"Error accessing Sunholo: {str(e)}")
|
83
|
-
|
84
|
-
raise ValueError(f"Unknown resource: {uri}")
|
85
|
-
|
86
|
-
def setup_tool_handlers(self):
|
87
|
-
"""Configure tool-related handlers"""
|
88
|
-
|
89
|
-
@self.server.list_tools()
|
90
|
-
async def list_tools() -> list[Tool]:
|
91
|
-
"""List available Sunholo tools"""
|
92
|
-
return [
|
93
|
-
Tool(
|
94
|
-
name="chat_with_vac",
|
95
|
-
description="Chat with a specific Sunholo VAC",
|
96
|
-
inputSchema={
|
97
|
-
"type": "object",
|
98
|
-
"properties": {
|
99
|
-
"vac_name": {
|
100
|
-
"type": "string",
|
101
|
-
"description": "Name of the VAC to chat with"
|
102
|
-
},
|
103
|
-
"message": {
|
104
|
-
"type": "string",
|
105
|
-
"description": "Message to send to the VAC"
|
106
|
-
},
|
107
|
-
},
|
108
|
-
"required": ["vac_name", "message"]
|
109
|
-
}
|
110
|
-
),
|
111
|
-
Tool(
|
112
|
-
name="list_configs",
|
113
|
-
description="List Sunholo configurations",
|
114
|
-
inputSchema={
|
115
|
-
"type": "object",
|
116
|
-
"properties": {
|
117
|
-
"kind": {
|
118
|
-
"type": "string",
|
119
|
-
"description": "Filter configurations by kind e.g. vacConfig"
|
120
|
-
},
|
121
|
-
"vac": {
|
122
|
-
"type": "string",
|
123
|
-
"description": "Filter configurations by VAC name"
|
124
|
-
},
|
125
|
-
"validate": {
|
126
|
-
"type": "boolean",
|
127
|
-
"description": "Validate the configuration files"
|
128
|
-
}
|
129
|
-
}
|
130
|
-
}
|
131
|
-
),
|
132
|
-
Tool(
|
133
|
-
name="embed_content",
|
134
|
-
description="Embed content in a VAC's vector store",
|
135
|
-
inputSchema={
|
136
|
-
"type": "object",
|
137
|
-
"properties": {
|
138
|
-
"vac_name": {
|
139
|
-
"type": "string",
|
140
|
-
"description": "Name of the VAC to embed content for"
|
141
|
-
},
|
142
|
-
"content": {
|
143
|
-
"type": "string",
|
144
|
-
"description": "Content to embed"
|
145
|
-
},
|
146
|
-
"local_chunks": {
|
147
|
-
"type": "boolean",
|
148
|
-
"description": "Whether to process chunks locally",
|
149
|
-
"default": False
|
150
|
-
}
|
151
|
-
},
|
152
|
-
"required": ["vac_name", "content"]
|
153
|
-
}
|
154
|
-
)
|
155
|
-
]
|
156
|
-
|
157
|
-
@self.server.call_tool()
|
158
|
-
async def call_tool(
|
159
|
-
name: str,
|
160
|
-
arguments: Any
|
161
|
-
) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
|
162
|
-
"""Handle tool calls for Sunholo interactions"""
|
163
|
-
|
164
|
-
if name == "chat_with_vac":
|
165
|
-
if not isinstance(arguments, dict):
|
166
|
-
raise ValueError("Invalid arguments format")
|
167
|
-
|
168
|
-
vac_name = arguments.get("vac_name")
|
169
|
-
message = arguments.get("message")
|
170
|
-
|
171
|
-
if not vac_name or not message:
|
172
|
-
raise ValueError("Missing required arguments")
|
173
|
-
|
174
|
-
try:
|
175
|
-
cmd = ["sunholo", "vac", "chat", vac_name, message]
|
176
|
-
cmd.append("--headless")
|
177
|
-
|
178
|
-
result = subprocess.run(
|
179
|
-
cmd,
|
180
|
-
capture_output=True,
|
181
|
-
text=True
|
182
|
-
)
|
183
|
-
|
184
|
-
return [
|
185
|
-
TextContent(
|
186
|
-
type="text",
|
187
|
-
text=result.stdout
|
188
|
-
)
|
189
|
-
]
|
190
|
-
except subprocess.CalledProcessError as e:
|
191
|
-
return [
|
192
|
-
TextContent(
|
193
|
-
type="text",
|
194
|
-
text=f"Error chatting with VAC: {e.stderr}"
|
195
|
-
)
|
196
|
-
]
|
197
|
-
|
198
|
-
elif name == "embed_content":
|
199
|
-
if not isinstance(arguments, dict):
|
200
|
-
raise ValueError("Invalid arguments format")
|
201
|
-
|
202
|
-
vac_name = arguments.get("vac_name")
|
203
|
-
content = arguments.get("content")
|
204
|
-
local_chunks = arguments.get("local_chunks", False)
|
205
|
-
|
206
|
-
if not vac_name or not content:
|
207
|
-
raise ValueError("Missing required arguments")
|
208
|
-
|
209
|
-
try:
|
210
|
-
cmd = ["sunholo", "embed", vac_name, content]
|
211
|
-
if local_chunks:
|
212
|
-
cmd.append("--local-chunks")
|
213
|
-
|
214
|
-
result = subprocess.run(
|
215
|
-
cmd,
|
216
|
-
capture_output=True,
|
217
|
-
text=True
|
218
|
-
)
|
219
|
-
|
220
|
-
return [
|
221
|
-
TextContent(
|
222
|
-
type="text",
|
223
|
-
text=result.stdout
|
224
|
-
)
|
225
|
-
]
|
226
|
-
except subprocess.CalledProcessError as e:
|
227
|
-
return [
|
228
|
-
TextContent(
|
229
|
-
type="text",
|
230
|
-
text=f"Error embedding content: {e.stderr}"
|
231
|
-
)
|
232
|
-
]
|
233
|
-
elif name == "list_configs":
|
234
|
-
|
235
|
-
# Build command
|
236
|
-
cmd = ["sunholo", "list-configs"]
|
237
|
-
|
238
|
-
if arguments.get("kind"):
|
239
|
-
cmd.extend(["--kind", arguments["kind"]])
|
240
|
-
if arguments.get("vac"):
|
241
|
-
cmd.extend(["--vac", arguments["vac"]])
|
242
|
-
if arguments.get("validate"):
|
243
|
-
cmd.append("--validate")
|
244
|
-
|
245
|
-
# Execute sunholo command
|
246
|
-
try:
|
247
|
-
result = subprocess.run(cmd, capture_output=True, text=True)
|
248
|
-
return [TextContent(type="text", text=result.stdout)]
|
249
|
-
except subprocess.CalledProcessError as e:
|
250
|
-
return [TextContent(type="text", text=f"Error: {e.stderr}")]
|
251
|
-
|
252
|
-
|
253
|
-
raise ValueError(f"Unknown tool: {name}")
|
254
|
-
|
255
|
-
async def run(self):
|
256
|
-
"""Run the MCP server"""
|
257
|
-
async with stdio_server() as (read_stream, write_stream):
|
258
|
-
await self.server.run(
|
259
|
-
read_stream,
|
260
|
-
write_stream,
|
261
|
-
self.server.create_initialization_options()
|
262
|
-
)
|
263
|
-
|
264
|
-
def cli_mcp(args):
|
265
|
-
"""CLI handler for the MCP server command"""
|
266
|
-
try:
|
267
|
-
|
268
|
-
if not os.getenv("VAC_CONFIG_FOLDER"):
|
269
|
-
raise ValueError("sunholo configuration folder must be present in config/ or via VAC_CONFIG_FOLDER")
|
270
|
-
|
271
|
-
# Create and run the MCP server
|
272
|
-
server = SunholoMCPServer()
|
273
|
-
msg = {"message": "Starting Sunholo MCP server..."}
|
274
|
-
|
275
|
-
logger.info(msg)
|
276
|
-
console.print(msg)
|
277
|
-
|
278
|
-
asyncio.run(server.run())
|
279
|
-
|
280
|
-
except Exception as e:
|
281
|
-
logger.error(f"Error running MCP server: {str(e)}")
|
282
|
-
raise
|
283
|
-
|
284
|
-
def cli_mcp_bridge(args):
|
285
|
-
"""CLI handler for the MCP bridge command"""
|
286
|
-
try:
|
287
|
-
from .stdio_http_bridge import run_bridge
|
288
|
-
|
289
|
-
http_url = args.url
|
290
|
-
logger.info(f"Starting MCP stdio-to-HTTP bridge for {http_url}")
|
291
|
-
|
292
|
-
if console:
|
293
|
-
console.print(f"Starting MCP bridge to {http_url}...")
|
294
|
-
|
295
|
-
asyncio.run(run_bridge(http_url))
|
296
|
-
|
297
|
-
except KeyboardInterrupt:
|
298
|
-
logger.info("Bridge stopped by user")
|
299
|
-
except Exception as e:
|
300
|
-
logger.error(f"Error running MCP bridge: {str(e)}")
|
301
|
-
raise
|
302
|
-
|
303
|
-
def setup_mcp_subparser(subparsers):
|
304
|
-
"""
|
305
|
-
Sets up an argparse subparser for the 'mcp' command 3.
|
306
|
-
|
307
|
-
By default will use configurations within the folder specified by 'VAC_CONFIG_FOLDER'
|
308
|
-
|
309
|
-
Example command:
|
310
|
-
```bash
|
311
|
-
sunholo mcp
|
312
|
-
```
|
313
|
-
"""
|
314
|
-
mcp_parser = subparsers.add_parser('mcp',
|
315
|
-
help='MCP (Model Context Protocol) commands')
|
316
|
-
|
317
|
-
# Create subcommands for mcp
|
318
|
-
mcp_subparsers = mcp_parser.add_subparsers(title='mcp commands',
|
319
|
-
description='MCP subcommands',
|
320
|
-
help='MCP subcommands',
|
321
|
-
dest='mcp_command')
|
322
|
-
|
323
|
-
# mcp server command (default)
|
324
|
-
server_parser = mcp_subparsers.add_parser('server',
|
325
|
-
help='Start an Anthropic MCP server that wraps sunholo functionality')
|
326
|
-
server_parser.set_defaults(func=cli_mcp)
|
327
|
-
|
328
|
-
# mcp bridge command
|
329
|
-
bridge_parser = mcp_subparsers.add_parser('bridge',
|
330
|
-
help='Start a stdio-to-HTTP bridge for MCP servers')
|
331
|
-
bridge_parser.add_argument('url',
|
332
|
-
nargs='?',
|
333
|
-
default='http://127.0.0.1:1956/mcp',
|
334
|
-
help='HTTP URL of the MCP server (default: http://127.0.0.1:1956/mcp)')
|
335
|
-
bridge_parser.set_defaults(func=cli_mcp_bridge)
|
336
|
-
|
337
|
-
# Set default behavior when no subcommand is provided
|
338
|
-
mcp_parser.set_defaults(func=cli_mcp)
|
1
|
+
# Copyright [2024] [Holosun ApS]
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
"""
|
16
|
+
CLI for MCP server commands using FastMCP.
|
17
|
+
"""
|
18
|
+
|
19
|
+
# Import the FastMCP implementation
|
20
|
+
from .cli_fastmcp import cli_mcp, cli_mcp_bridge, setup_mcp_subparser
|
21
|
+
|
22
|
+
__all__ = ['cli_mcp', 'cli_mcp_bridge', 'setup_mcp_subparser']
|
@@ -0,0 +1,201 @@
|
|
1
|
+
import os
|
2
|
+
import asyncio
|
3
|
+
import subprocess
|
4
|
+
from typing import List, Optional
|
5
|
+
|
6
|
+
from fastmcp import FastMCP
|
7
|
+
|
8
|
+
# Configure logging
|
9
|
+
from ..custom_logging import setup_logging
|
10
|
+
logger = setup_logging("sunholo-mcp")
|
11
|
+
|
12
|
+
# Initialize FastMCP server
|
13
|
+
mcp = FastMCP("sunholo-mcp-server")
|
14
|
+
|
15
|
+
@mcp.resource("sunholo://vacs/list")
|
16
|
+
async def list_vacs() -> str:
|
17
|
+
"""
|
18
|
+
List of available Virtual Agent Computers.
|
19
|
+
|
20
|
+
Returns the list of configured VACs in the system.
|
21
|
+
"""
|
22
|
+
try:
|
23
|
+
result = subprocess.run(
|
24
|
+
["sunholo", "vac", "list"],
|
25
|
+
capture_output=True,
|
26
|
+
text=True,
|
27
|
+
check=True
|
28
|
+
)
|
29
|
+
return result.stdout
|
30
|
+
except subprocess.CalledProcessError as e:
|
31
|
+
raise RuntimeError(f"Failed to list VACs: {str(e)}")
|
32
|
+
except Exception as e:
|
33
|
+
raise RuntimeError(f"Error accessing Sunholo: {str(e)}")
|
34
|
+
|
35
|
+
@mcp.tool
|
36
|
+
async def chat_with_vac(vac_name: str, message: str, headless: bool = True) -> str:
|
37
|
+
"""
|
38
|
+
Chat with a specific Sunholo VAC.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
vac_name: Name of the VAC to chat with
|
42
|
+
message: Message to send to the VAC
|
43
|
+
headless: Run in headless mode (default: True)
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
Response from the VAC
|
47
|
+
"""
|
48
|
+
try:
|
49
|
+
cmd = ["sunholo", "vac", "chat", vac_name, message]
|
50
|
+
if headless:
|
51
|
+
cmd.append("--headless")
|
52
|
+
|
53
|
+
result = subprocess.run(
|
54
|
+
cmd,
|
55
|
+
capture_output=True,
|
56
|
+
text=True,
|
57
|
+
check=True
|
58
|
+
)
|
59
|
+
return result.stdout
|
60
|
+
except subprocess.CalledProcessError as e:
|
61
|
+
return f"Error chatting with VAC: {e.stderr}"
|
62
|
+
|
63
|
+
@mcp.tool
|
64
|
+
async def list_configs(
|
65
|
+
kind: Optional[str] = None,
|
66
|
+
vac: Optional[str] = None,
|
67
|
+
validate: bool = False
|
68
|
+
) -> str:
|
69
|
+
"""
|
70
|
+
List Sunholo configurations.
|
71
|
+
|
72
|
+
Args:
|
73
|
+
kind: Filter configurations by kind (e.g., 'vacConfig')
|
74
|
+
vac: Filter configurations by VAC name
|
75
|
+
validate: Validate the configuration files
|
76
|
+
|
77
|
+
Returns:
|
78
|
+
Configuration listing output
|
79
|
+
"""
|
80
|
+
cmd = ["sunholo", "list-configs"]
|
81
|
+
|
82
|
+
if kind:
|
83
|
+
cmd.extend(["--kind", kind])
|
84
|
+
if vac:
|
85
|
+
cmd.extend(["--vac", vac])
|
86
|
+
if validate:
|
87
|
+
cmd.append("--validate")
|
88
|
+
|
89
|
+
try:
|
90
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
91
|
+
return result.stdout
|
92
|
+
except subprocess.CalledProcessError as e:
|
93
|
+
return f"Error: {e.stderr}"
|
94
|
+
|
95
|
+
@mcp.tool
|
96
|
+
async def embed_content(
|
97
|
+
vac_name: str,
|
98
|
+
content: str,
|
99
|
+
local_chunks: bool = False
|
100
|
+
) -> str:
|
101
|
+
"""
|
102
|
+
Embed content in a VAC's vector store.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
vac_name: Name of the VAC to embed content for
|
106
|
+
content: Content to embed
|
107
|
+
local_chunks: Whether to process chunks locally
|
108
|
+
|
109
|
+
Returns:
|
110
|
+
Embedding operation result
|
111
|
+
"""
|
112
|
+
try:
|
113
|
+
cmd = ["sunholo", "embed", vac_name, content]
|
114
|
+
if local_chunks:
|
115
|
+
cmd.append("--local-chunks")
|
116
|
+
|
117
|
+
result = subprocess.run(
|
118
|
+
cmd,
|
119
|
+
capture_output=True,
|
120
|
+
text=True,
|
121
|
+
check=True
|
122
|
+
)
|
123
|
+
return result.stdout
|
124
|
+
except subprocess.CalledProcessError as e:
|
125
|
+
return f"Error embedding content: {e.stderr}"
|
126
|
+
|
127
|
+
def cli_mcp(args):
|
128
|
+
"""CLI handler for the MCP server command using FastMCP."""
|
129
|
+
try:
|
130
|
+
if not os.getenv("VAC_CONFIG_FOLDER"):
|
131
|
+
raise ValueError("sunholo configuration folder must be present in config/ or via VAC_CONFIG_FOLDER")
|
132
|
+
|
133
|
+
logger.info("Starting Sunholo MCP server with FastMCP...")
|
134
|
+
|
135
|
+
# Run the FastMCP server in stdio mode (default for Claude Desktop)
|
136
|
+
mcp.run()
|
137
|
+
|
138
|
+
except Exception as e:
|
139
|
+
logger.error(f"Error running MCP server: {str(e)}")
|
140
|
+
raise
|
141
|
+
|
142
|
+
def cli_mcp_bridge(args):
|
143
|
+
"""
|
144
|
+
CLI handler for the MCP bridge command.
|
145
|
+
FastMCP handles HTTP transport natively, so this can be simplified.
|
146
|
+
"""
|
147
|
+
try:
|
148
|
+
http_url = args.url
|
149
|
+
|
150
|
+
# Parse port from URL if provided
|
151
|
+
import urllib.parse
|
152
|
+
parsed = urllib.parse.urlparse(http_url)
|
153
|
+
port = parsed.port or 8000
|
154
|
+
|
155
|
+
logger.info(f"Starting FastMCP HTTP server on port {port}")
|
156
|
+
|
157
|
+
# Run FastMCP in HTTP mode
|
158
|
+
mcp.run(transport="http", port=port)
|
159
|
+
|
160
|
+
except KeyboardInterrupt:
|
161
|
+
logger.info("Server stopped by user")
|
162
|
+
except Exception as e:
|
163
|
+
logger.error(f"Error running MCP server: {str(e)}")
|
164
|
+
raise
|
165
|
+
|
166
|
+
def setup_mcp_subparser(subparsers):
|
167
|
+
"""
|
168
|
+
Sets up an argparse subparser for the 'mcp' command.
|
169
|
+
|
170
|
+
By default will use configurations within the folder specified by 'VAC_CONFIG_FOLDER'
|
171
|
+
|
172
|
+
Example command:
|
173
|
+
```bash
|
174
|
+
sunholo mcp
|
175
|
+
```
|
176
|
+
"""
|
177
|
+
mcp_parser = subparsers.add_parser('mcp',
|
178
|
+
help='MCP (Model Context Protocol) commands')
|
179
|
+
|
180
|
+
# Create subcommands for mcp
|
181
|
+
mcp_subparsers = mcp_parser.add_subparsers(title='mcp commands',
|
182
|
+
description='MCP subcommands',
|
183
|
+
help='MCP subcommands',
|
184
|
+
dest='mcp_command')
|
185
|
+
|
186
|
+
# mcp server command (default)
|
187
|
+
server_parser = mcp_subparsers.add_parser('server',
|
188
|
+
help='Start an Anthropic MCP server that wraps sunholo functionality')
|
189
|
+
server_parser.set_defaults(func=cli_mcp)
|
190
|
+
|
191
|
+
# mcp bridge command - now simplified with FastMCP
|
192
|
+
bridge_parser = mcp_subparsers.add_parser('bridge',
|
193
|
+
help='Start an HTTP MCP server (FastMCP handles transport)')
|
194
|
+
bridge_parser.add_argument('url',
|
195
|
+
nargs='?',
|
196
|
+
default='http://127.0.0.1:8000/mcp',
|
197
|
+
help='HTTP URL for the MCP server (default: http://127.0.0.1:8000/mcp)')
|
198
|
+
bridge_parser.set_defaults(func=cli_mcp_bridge)
|
199
|
+
|
200
|
+
# Set default behavior when no subcommand is provided
|
201
|
+
mcp_parser.set_defaults(func=cli_mcp)
|