machinecommander 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.
Potentially problematic release.
This version of machinecommander might be problematic. Click here for more details.
- machinecommander/__init__.py +8 -0
- machinecommander/mcp_server.py +30 -0
- machinecommander/server.py +188 -0
- machinecommander-0.1.0.dist-info/METADATA +121 -0
- machinecommander-0.1.0.dist-info/RECORD +7 -0
- machinecommander-0.1.0.dist-info/WHEEL +4 -0
- machinecommander-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from mcp.server.fastmcp import FastMCP
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
mcp = FastMCP("MachineCommander")
|
|
5
|
+
|
|
6
|
+
@mcp.tool()
|
|
7
|
+
def get_construction_machines_data(question: str) -> dict:
|
|
8
|
+
"""MachineCommander is a global system to manage all the construction machines working on construction projects. Use this tool to extract the data of construction machines and projects, and to answer construction related questions. The return value is a list of rows, with each row as a dict."""
|
|
9
|
+
url = f"https://gpt-agent.zhgcloud.com/paipai_mcp/{question}"
|
|
10
|
+
auth = ("zeaho-data", "Zeaho_93246!")
|
|
11
|
+
try:
|
|
12
|
+
response = requests.get(url, auth=auth)
|
|
13
|
+
response.raise_for_status()
|
|
14
|
+
try:
|
|
15
|
+
result_data = response.json()
|
|
16
|
+
result = {"result": result_data}
|
|
17
|
+
except:
|
|
18
|
+
result = {"result": response.text}
|
|
19
|
+
except Exception as e:
|
|
20
|
+
result = {"result": f"请求失败: {str(e)}"}
|
|
21
|
+
return result
|
|
22
|
+
|
|
23
|
+
@mcp.tool()
|
|
24
|
+
def manage_construction_machines(order: str) -> dict:
|
|
25
|
+
"""MachineCommander is a global system to manage all the construction machines working on construction projects. Use this tool to send orders to the construction machines."""
|
|
26
|
+
return {"result": "nop"}
|
|
27
|
+
|
|
28
|
+
# Start the server
|
|
29
|
+
def main():
|
|
30
|
+
mcp.run(transport="stdio")
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
from mcp.server.models import InitializationOptions
|
|
5
|
+
import mcp.types as types
|
|
6
|
+
from mcp.server import NotificationOptions, Server
|
|
7
|
+
from pydantic import AnyUrl
|
|
8
|
+
import mcp.server.stdio
|
|
9
|
+
|
|
10
|
+
# Store notes as a simple key-value dict to demonstrate state management
|
|
11
|
+
notes: dict[str, str] = {}
|
|
12
|
+
|
|
13
|
+
server = Server("MachineCommander")
|
|
14
|
+
|
|
15
|
+
@server.list_resources()
|
|
16
|
+
async def handle_list_resources() -> list[types.Resource]:
|
|
17
|
+
"""
|
|
18
|
+
List available note resources.
|
|
19
|
+
Each note is exposed as a resource with a custom note:// URI scheme.
|
|
20
|
+
"""
|
|
21
|
+
return [
|
|
22
|
+
types.Resource(
|
|
23
|
+
uri=AnyUrl(f"note://internal/{name}"),
|
|
24
|
+
name=f"Note: {name}",
|
|
25
|
+
description=f"A simple note named {name}",
|
|
26
|
+
mimeType="text/plain",
|
|
27
|
+
)
|
|
28
|
+
for name in notes
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
@server.read_resource()
|
|
32
|
+
async def handle_read_resource(uri: AnyUrl) -> str:
|
|
33
|
+
"""
|
|
34
|
+
Read a specific note's content by its URI.
|
|
35
|
+
The note name is extracted from the URI host component.
|
|
36
|
+
"""
|
|
37
|
+
if uri.scheme != "note":
|
|
38
|
+
raise ValueError(f"Unsupported URI scheme: {uri.scheme}")
|
|
39
|
+
|
|
40
|
+
name = uri.path
|
|
41
|
+
if name is not None:
|
|
42
|
+
name = name.lstrip("/")
|
|
43
|
+
return notes[name]
|
|
44
|
+
raise ValueError(f"Note not found: {name}")
|
|
45
|
+
|
|
46
|
+
@server.list_prompts()
|
|
47
|
+
async def handle_list_prompts() -> list[types.Prompt]:
|
|
48
|
+
"""
|
|
49
|
+
List available prompts.
|
|
50
|
+
Each prompt can have optional arguments to customize its behavior.
|
|
51
|
+
"""
|
|
52
|
+
return [
|
|
53
|
+
types.Prompt(
|
|
54
|
+
name="summarize-notes",
|
|
55
|
+
description="Creates a summary of all notes",
|
|
56
|
+
arguments=[
|
|
57
|
+
types.PromptArgument(
|
|
58
|
+
name="style",
|
|
59
|
+
description="Style of the summary (brief/detailed)",
|
|
60
|
+
required=False,
|
|
61
|
+
)
|
|
62
|
+
],
|
|
63
|
+
)
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
@server.get_prompt()
|
|
67
|
+
async def handle_get_prompt(
|
|
68
|
+
name: str, arguments: dict[str, str] | None
|
|
69
|
+
) -> types.GetPromptResult:
|
|
70
|
+
"""
|
|
71
|
+
Generate a prompt by combining arguments with server state.
|
|
72
|
+
The prompt includes all current notes and can be customized via arguments.
|
|
73
|
+
"""
|
|
74
|
+
if name != "summarize-notes":
|
|
75
|
+
raise ValueError(f"Unknown prompt: {name}")
|
|
76
|
+
|
|
77
|
+
style = (arguments or {}).get("style", "brief")
|
|
78
|
+
detail_prompt = " Give extensive details." if style == "detailed" else ""
|
|
79
|
+
|
|
80
|
+
return types.GetPromptResult(
|
|
81
|
+
description="Summarize the current notes",
|
|
82
|
+
messages=[
|
|
83
|
+
types.PromptMessage(
|
|
84
|
+
role="user",
|
|
85
|
+
content=types.TextContent(
|
|
86
|
+
type="text",
|
|
87
|
+
text=f"Here are the current notes to summarize:{detail_prompt}\n\n"
|
|
88
|
+
+ "\n".join(
|
|
89
|
+
f"- {name}: {content}"
|
|
90
|
+
for name, content in notes.items()
|
|
91
|
+
),
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
],
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
@server.list_tools()
|
|
98
|
+
async def handle_list_tools() -> list[types.Tool]:
|
|
99
|
+
"""
|
|
100
|
+
List available tools.
|
|
101
|
+
Each tool specifies its arguments using JSON Schema validation.
|
|
102
|
+
"""
|
|
103
|
+
return [
|
|
104
|
+
types.Tool(
|
|
105
|
+
name="add-note",
|
|
106
|
+
description="Add a new note",
|
|
107
|
+
inputSchema={
|
|
108
|
+
"type": "object",
|
|
109
|
+
"properties": {
|
|
110
|
+
"name": {"type": "string"},
|
|
111
|
+
"content": {"type": "string"},
|
|
112
|
+
},
|
|
113
|
+
"required": ["name", "content"],
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
@server.call_tool()
|
|
119
|
+
async def handle_call_tool(
|
|
120
|
+
name: str, arguments: dict | None
|
|
121
|
+
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
|
|
122
|
+
"""
|
|
123
|
+
Handle tool execution requests.
|
|
124
|
+
"""
|
|
125
|
+
if name != "add-note":
|
|
126
|
+
raise ValueError(f"Unknown tool: {name}")
|
|
127
|
+
|
|
128
|
+
if not arguments:
|
|
129
|
+
raise ValueError("Missing arguments")
|
|
130
|
+
|
|
131
|
+
note_name = arguments.get("name")
|
|
132
|
+
content = arguments.get("content")
|
|
133
|
+
|
|
134
|
+
if not note_name or not content:
|
|
135
|
+
raise ValueError("Missing name or content")
|
|
136
|
+
|
|
137
|
+
# Update server state
|
|
138
|
+
notes[note_name] = content
|
|
139
|
+
|
|
140
|
+
# Notify clients that resources have changed
|
|
141
|
+
await server.request_context.session.send_resource_list_changed()
|
|
142
|
+
|
|
143
|
+
return [
|
|
144
|
+
types.TextContent(
|
|
145
|
+
type="text",
|
|
146
|
+
text=f"Added note '{note_name}' with content: {content}",
|
|
147
|
+
)
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
@server.tool()
|
|
151
|
+
async def get_construction_machines_data(question: str) -> dict:
|
|
152
|
+
"""MachineCommander is a global system to manage all the construction machines working on construction projects. Use this tool to extract the data of construction machines and projects, and to answer construction related questions. The return value is a list of rows, with each row as a dict."""
|
|
153
|
+
url = f"https://gpt-agent.zhgcloud.com/paipai_mcp/{question}"
|
|
154
|
+
auth = ("zeaho-data", "Zeaho_93246!")
|
|
155
|
+
try:
|
|
156
|
+
loop = asyncio.get_event_loop()
|
|
157
|
+
# 使用线程池避免阻塞事件循环
|
|
158
|
+
def fetch():
|
|
159
|
+
try:
|
|
160
|
+
response = requests.get(url, auth=auth, timeout=10)
|
|
161
|
+
response.raise_for_status()
|
|
162
|
+
try:
|
|
163
|
+
result_data = response.json()
|
|
164
|
+
return {"result": result_data}
|
|
165
|
+
except Exception:
|
|
166
|
+
return {"result": response.text}
|
|
167
|
+
except Exception as e:
|
|
168
|
+
return {"result": f"请求失败: {str(e)}"}
|
|
169
|
+
result = await loop.run_in_executor(None, fetch)
|
|
170
|
+
except Exception as e:
|
|
171
|
+
result = {"result": f"请求失败: {str(e)}"}
|
|
172
|
+
return result
|
|
173
|
+
|
|
174
|
+
async def main():
|
|
175
|
+
# Run the server using stdin/stdout streams
|
|
176
|
+
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
|
|
177
|
+
await server.run(
|
|
178
|
+
read_stream,
|
|
179
|
+
write_stream,
|
|
180
|
+
InitializationOptions(
|
|
181
|
+
server_name="MachineCommander",
|
|
182
|
+
server_version="0.1.0",
|
|
183
|
+
capabilities=server.get_capabilities(
|
|
184
|
+
notification_options=NotificationOptions(),
|
|
185
|
+
experimental_capabilities={},
|
|
186
|
+
),
|
|
187
|
+
),
|
|
188
|
+
)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: machinecommander
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MachineCommander is an IoT system to manage all the construction machines working on construction projects.
|
|
5
|
+
Author-email: Ye Wang <wangye@zeaho.com>
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Requires-Dist: mcp>=1.10.1
|
|
8
|
+
Requires-Dist: requests>=2.31.0
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# MachineCommander MCP server
|
|
12
|
+
|
|
13
|
+
MachineCommander is an IoT system to manage all the construction machines working on construction projects.
|
|
14
|
+
|
|
15
|
+
## Components
|
|
16
|
+
|
|
17
|
+
### Resources
|
|
18
|
+
|
|
19
|
+
The server implements a simple note storage system with:
|
|
20
|
+
- Custom note:// URI scheme for accessing individual notes
|
|
21
|
+
- Each note resource has a name, description and text/plain mimetype
|
|
22
|
+
|
|
23
|
+
### Prompts
|
|
24
|
+
|
|
25
|
+
The server provides a single prompt:
|
|
26
|
+
- summarize-notes: Creates summaries of all stored notes
|
|
27
|
+
- Optional "style" argument to control detail level (brief/detailed)
|
|
28
|
+
- Generates prompt combining all current notes with style preference
|
|
29
|
+
|
|
30
|
+
### Tools
|
|
31
|
+
|
|
32
|
+
The server implements one tool:
|
|
33
|
+
- add-note: Adds a new note to the server
|
|
34
|
+
- Takes "name" and "content" as required string arguments
|
|
35
|
+
- Updates server state and notifies clients of resource changes
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
[TODO: Add configuration details specific to your implementation]
|
|
40
|
+
|
|
41
|
+
## Quickstart
|
|
42
|
+
|
|
43
|
+
### Install
|
|
44
|
+
|
|
45
|
+
#### Claude Desktop
|
|
46
|
+
|
|
47
|
+
On MacOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json`
|
|
48
|
+
On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
|
|
49
|
+
|
|
50
|
+
<details>
|
|
51
|
+
<summary>Development/Unpublished Servers Configuration</summary>
|
|
52
|
+
```
|
|
53
|
+
"mcpServers": {
|
|
54
|
+
"MachineCommander": {
|
|
55
|
+
"command": "uv",
|
|
56
|
+
"args": [
|
|
57
|
+
"--directory",
|
|
58
|
+
"/Users/yewang/work/ai/machine-commander/MachineCommander",
|
|
59
|
+
"run",
|
|
60
|
+
"MachineCommander"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
</details>
|
|
66
|
+
|
|
67
|
+
<details>
|
|
68
|
+
<summary>Published Servers Configuration</summary>
|
|
69
|
+
```
|
|
70
|
+
"mcpServers": {
|
|
71
|
+
"MachineCommander": {
|
|
72
|
+
"command": "uvx",
|
|
73
|
+
"args": [
|
|
74
|
+
"MachineCommander"
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
</details>
|
|
80
|
+
|
|
81
|
+
## Development
|
|
82
|
+
|
|
83
|
+
### Building and Publishing
|
|
84
|
+
|
|
85
|
+
To prepare the package for distribution:
|
|
86
|
+
|
|
87
|
+
1. Sync dependencies and update lockfile:
|
|
88
|
+
```bash
|
|
89
|
+
uv sync
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
2. Build package distributions:
|
|
93
|
+
```bash
|
|
94
|
+
uv build
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This will create source and wheel distributions in the `dist/` directory.
|
|
98
|
+
|
|
99
|
+
3. Publish to PyPI:
|
|
100
|
+
```bash
|
|
101
|
+
uv publish
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Note: You'll need to set PyPI credentials via environment variables or command flags:
|
|
105
|
+
- Token: `--token` or `UV_PUBLISH_TOKEN`
|
|
106
|
+
- Or username/password: `--username`/`UV_PUBLISH_USERNAME` and `--password`/`UV_PUBLISH_PASSWORD`
|
|
107
|
+
|
|
108
|
+
### Debugging
|
|
109
|
+
|
|
110
|
+
Since MCP servers run over stdio, debugging can be challenging. For the best debugging
|
|
111
|
+
experience, we strongly recommend using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector).
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
You can launch the MCP Inspector via [`npm`](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) with this command:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx @modelcontextprotocol/inspector uv --directory /Users/yewang/work/ai/machine-commander/MachineCommander run machinecommander
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
Upon launching, the Inspector will display a URL that you can access in your browser to begin debugging.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
machinecommander/__init__.py,sha256=uoRnkrZJolcVImtRw7bS8csjWqsCD1kCl-Ut8qHxb1w,182
|
|
2
|
+
machinecommander/mcp_server.py,sha256=DA49649xLhAbjCiI5BFw7FbTVXA_lxjvIzWAFZRRr8U,1264
|
|
3
|
+
machinecommander/server.py,sha256=QtWUj06y29eO_qeWdXuFT2IxRUU8vqaoJE4R2CFSy6w,6078
|
|
4
|
+
machinecommander-0.1.0.dist-info/METADATA,sha256=opha51p8vV26sonW0NZZoZJtKsookgEYh_RVPDqoNoo,3125
|
|
5
|
+
machinecommander-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
6
|
+
machinecommander-0.1.0.dist-info/entry_points.txt,sha256=WwSKZcxuzujhwJ4Lk7EhGfzSQD1Vf76lW_tDDTDEZrw,59
|
|
7
|
+
machinecommander-0.1.0.dist-info/RECORD,,
|