axon-mcp 0.1.0__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.
- axon_mcp-0.1.0/PKG-INFO +24 -0
- axon_mcp-0.1.0/README.md +15 -0
- axon_mcp-0.1.0/axon_mcp/__init__.py +3 -0
- axon_mcp-0.1.0/axon_mcp/server.py +245 -0
- axon_mcp-0.1.0/axon_mcp.egg-info/PKG-INFO +24 -0
- axon_mcp-0.1.0/axon_mcp.egg-info/SOURCES.txt +10 -0
- axon_mcp-0.1.0/axon_mcp.egg-info/dependency_links.txt +1 -0
- axon_mcp-0.1.0/axon_mcp.egg-info/entry_points.txt +2 -0
- axon_mcp-0.1.0/axon_mcp.egg-info/requires.txt +2 -0
- axon_mcp-0.1.0/axon_mcp.egg-info/top_level.txt +1 -0
- axon_mcp-0.1.0/pyproject.toml +17 -0
- axon_mcp-0.1.0/setup.cfg +4 -0
axon_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: axon-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Model Context Protocol (MCP) server for Axon Protocol
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: mcp>=0.1.0
|
|
8
|
+
Requires-Dist: httpx>=0.27.0
|
|
9
|
+
|
|
10
|
+
# Axon Model Context Protocol (MCP) Server
|
|
11
|
+
|
|
12
|
+
Exposes Axon's core backend capabilities as tools that can be run natively by AI agents.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install -e .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Running
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
axon-mcp
|
|
24
|
+
```
|
axon_mcp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Dict, Any, Optional
|
|
5
|
+
from mcp.server.fastmcp import FastMCP
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
# FastMCP Server Instance
|
|
9
|
+
mcp = FastMCP("Axon Protocol")
|
|
10
|
+
|
|
11
|
+
def find_cwd_config() -> Optional[Path]:
|
|
12
|
+
config_path = Path.cwd() / ".axon"
|
|
13
|
+
if config_path.is_file():
|
|
14
|
+
return config_path
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
def find_upward_config() -> Optional[Path]:
|
|
18
|
+
current = Path.cwd()
|
|
19
|
+
for parent in [current] + list(current.parents):
|
|
20
|
+
config_path = parent / ".axon"
|
|
21
|
+
if config_path.is_file():
|
|
22
|
+
return config_path
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
def find_home_config() -> Optional[Path]:
|
|
26
|
+
home = Path.home()
|
|
27
|
+
# Try ~/.axon/config.json
|
|
28
|
+
config_json = home / ".axon" / "config.json"
|
|
29
|
+
if config_json.is_file():
|
|
30
|
+
return config_json
|
|
31
|
+
# Try ~/.axon
|
|
32
|
+
config_dot = home / ".axon"
|
|
33
|
+
if config_dot.is_file():
|
|
34
|
+
return config_dot
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
def load_config() -> Dict[str, Any]:
|
|
38
|
+
# Default settings checking env first
|
|
39
|
+
config = {
|
|
40
|
+
"base_url": os.getenv("AXON_BASE_URL", "http://localhost:8000"),
|
|
41
|
+
"api_key": os.getenv("AXON_API_KEY"),
|
|
42
|
+
"project_id": os.getenv("AXON_PROJECT_ID"),
|
|
43
|
+
"agent_id": os.getenv("AXON_AGENT_ID"),
|
|
44
|
+
"agent_token": os.getenv("AXON_AGENT_TOKEN"),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Try loading from local config files
|
|
48
|
+
config_path = find_cwd_config() or find_upward_config() or find_home_config()
|
|
49
|
+
if config_path:
|
|
50
|
+
try:
|
|
51
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
52
|
+
data = json.load(f)
|
|
53
|
+
if isinstance(data, dict):
|
|
54
|
+
if "base_url" in data:
|
|
55
|
+
config["base_url"] = data["base_url"]
|
|
56
|
+
if "api_key" in data:
|
|
57
|
+
config["api_key"] = data["api_key"]
|
|
58
|
+
if "project_id" in data:
|
|
59
|
+
config["project_id"] = data["project_id"]
|
|
60
|
+
if "agent_id" in data:
|
|
61
|
+
config["agent_id"] = data["agent_id"]
|
|
62
|
+
if "agent_token" in data:
|
|
63
|
+
config["agent_token"] = data["agent_token"]
|
|
64
|
+
except Exception:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
return config
|
|
68
|
+
|
|
69
|
+
def get_client() -> httpx.Client:
|
|
70
|
+
config = load_config()
|
|
71
|
+
headers = {
|
|
72
|
+
"Content-Type": "application/json"
|
|
73
|
+
}
|
|
74
|
+
# If using local mode fallback defaults, inject default project key
|
|
75
|
+
api_key = config.get("api_key") or "axon-local-dev-key-384729"
|
|
76
|
+
headers["X-API-Key"] = api_key
|
|
77
|
+
|
|
78
|
+
if config.get("agent_id"):
|
|
79
|
+
headers["X-Agent-ID"] = config["agent_id"]
|
|
80
|
+
if config.get("agent_token"):
|
|
81
|
+
headers["Authorization"] = f"Bearer {config['agent_token']}"
|
|
82
|
+
|
|
83
|
+
return httpx.Client(
|
|
84
|
+
base_url=config["base_url"],
|
|
85
|
+
headers=headers,
|
|
86
|
+
timeout=10.0
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
@mcp.tool()
|
|
90
|
+
def axon_register_agent(name: str, capabilities: list[str]) -> str:
|
|
91
|
+
"""Register a new agent in Axon.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
name: Name of the agent.
|
|
95
|
+
capabilities: List of capability strings (e.g., ["coding", "planning"]).
|
|
96
|
+
"""
|
|
97
|
+
config = load_config()
|
|
98
|
+
project_id = config.get("project_id") or "00000000-0000-0000-0000-000000000000"
|
|
99
|
+
|
|
100
|
+
with get_client() as client:
|
|
101
|
+
try:
|
|
102
|
+
resp = client.post("/v1/agents/register", json={
|
|
103
|
+
"name": name,
|
|
104
|
+
"project_id": project_id,
|
|
105
|
+
"capabilities": capabilities
|
|
106
|
+
})
|
|
107
|
+
if resp.status_code != 200:
|
|
108
|
+
return f"Error registering agent: {resp.text}"
|
|
109
|
+
data = resp.json()
|
|
110
|
+
return f"Agent registered successfully.\nAgent ID: {data.get('agent_id')}\nToken: {data.get('token')}"
|
|
111
|
+
except Exception as e:
|
|
112
|
+
return f"Error connecting to server: {str(e)}"
|
|
113
|
+
|
|
114
|
+
@mcp.tool()
|
|
115
|
+
def axon_store_memory(content: str, tags: dict = None, scope: str = "project", ttl: int = None) -> str:
|
|
116
|
+
"""Store a text memory in Axon.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
content: The text content of the memory.
|
|
120
|
+
tags: Optional dict of key-value tags.
|
|
121
|
+
scope: Scope of the memory ('project', 'private', or 'org'). Defaults to 'project'.
|
|
122
|
+
ttl: Optional Time-to-Live in seconds.
|
|
123
|
+
"""
|
|
124
|
+
with get_client() as client:
|
|
125
|
+
try:
|
|
126
|
+
resp = client.post("/v1/memory/store", json={
|
|
127
|
+
"content": content,
|
|
128
|
+
"tags": tags or {},
|
|
129
|
+
"scope": scope,
|
|
130
|
+
"ttl": ttl
|
|
131
|
+
})
|
|
132
|
+
if resp.status_code != 200:
|
|
133
|
+
return f"Error storing memory: {resp.text}"
|
|
134
|
+
data = resp.json()
|
|
135
|
+
return f"Memory stored successfully.\nMemory ID: {data.get('id')}\nCreated At: {data.get('created_at')}"
|
|
136
|
+
except Exception as e:
|
|
137
|
+
return f"Error connecting to server: {str(e)}"
|
|
138
|
+
|
|
139
|
+
@mcp.tool()
|
|
140
|
+
def axon_search_memories(query: str, limit: int = 10, min_similarity: float = 0.3, scope: str = None) -> str:
|
|
141
|
+
"""Search stored memories in Axon.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
query: The semantic search query.
|
|
145
|
+
limit: Max number of results. Defaults to 10.
|
|
146
|
+
min_similarity: Threshold for similarity [0.0 - 1.0]. Defaults to 0.3.
|
|
147
|
+
scope: Optional scope filter.
|
|
148
|
+
"""
|
|
149
|
+
with get_client() as client:
|
|
150
|
+
try:
|
|
151
|
+
payload = {
|
|
152
|
+
"query": query,
|
|
153
|
+
"limit": limit,
|
|
154
|
+
"min_similarity": min_similarity
|
|
155
|
+
}
|
|
156
|
+
if scope:
|
|
157
|
+
payload["scope"] = scope
|
|
158
|
+
|
|
159
|
+
resp = client.post("/v1/memory/search", json=payload)
|
|
160
|
+
if resp.status_code != 200:
|
|
161
|
+
return f"Error searching memories: {resp.text}"
|
|
162
|
+
|
|
163
|
+
data = resp.json()
|
|
164
|
+
results = data.get("results", [])
|
|
165
|
+
if not results:
|
|
166
|
+
return "No matching memories found."
|
|
167
|
+
|
|
168
|
+
output = []
|
|
169
|
+
for r in results:
|
|
170
|
+
output.append(
|
|
171
|
+
f"[{r.get('similarity', 0.0):.2f}] ID: {r.get('id')}\nContent: {r.get('content')}\nTags: {r.get('tags', {})}\n"
|
|
172
|
+
)
|
|
173
|
+
return "\n".join(output)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
return f"Error connecting to server: {str(e)}"
|
|
176
|
+
|
|
177
|
+
@mcp.tool()
|
|
178
|
+
def axon_acquire_lock(resource_id: str, timeout: int = 300) -> str:
|
|
179
|
+
"""Acquire a distributed lock.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
resource_id: The ID of the resource to lock.
|
|
183
|
+
timeout: Expiry time in seconds. Defaults to 300.
|
|
184
|
+
"""
|
|
185
|
+
with get_client() as client:
|
|
186
|
+
try:
|
|
187
|
+
resp = client.post("/v1/lock/acquire", json={
|
|
188
|
+
"resource_id": resource_id,
|
|
189
|
+
"timeout": timeout
|
|
190
|
+
})
|
|
191
|
+
if resp.status_code == 409:
|
|
192
|
+
return f"Conflict: Resource '{resource_id}' is already locked."
|
|
193
|
+
if resp.status_code != 200:
|
|
194
|
+
return f"Error acquiring lock: {resp.text}"
|
|
195
|
+
data = resp.json()
|
|
196
|
+
return f"Lock acquired successfully.\nLock ID: {data.get('lock_id')}\nExpires At: {data.get('expires_at')}"
|
|
197
|
+
except Exception as e:
|
|
198
|
+
return f"Error connecting to server: {str(e)}"
|
|
199
|
+
|
|
200
|
+
@mcp.tool()
|
|
201
|
+
def axon_release_lock(resource_id: str) -> str:
|
|
202
|
+
"""Release a distributed lock.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
resource_id: The ID of the resource to release.
|
|
206
|
+
"""
|
|
207
|
+
with get_client() as client:
|
|
208
|
+
try:
|
|
209
|
+
resp = client.post(f"/v1/lock/release?resource_id={resource_id}")
|
|
210
|
+
if resp.status_code == 403:
|
|
211
|
+
return "Error: You do not own this lock."
|
|
212
|
+
if resp.status_code != 200:
|
|
213
|
+
return f"Error releasing lock: {resp.text}"
|
|
214
|
+
return f"Lock on resource '{resource_id}' released successfully."
|
|
215
|
+
except Exception as e:
|
|
216
|
+
return f"Error connecting to server: {str(e)}"
|
|
217
|
+
|
|
218
|
+
@mcp.tool()
|
|
219
|
+
def axon_create_receipt(input_data: str, steps: list[dict], output_data: str) -> str:
|
|
220
|
+
"""Create a cryptographic reasoning receipt in Axon.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
input_data: The initial input/prompt.
|
|
224
|
+
steps: List of logic step dicts (e.g., [{"step": 1, "action": "parse", "log": "..."}]).
|
|
225
|
+
output_data: The final generated response.
|
|
226
|
+
"""
|
|
227
|
+
with get_client() as client:
|
|
228
|
+
try:
|
|
229
|
+
resp = client.post("/v1/receipts/create", json={
|
|
230
|
+
"input": input_data,
|
|
231
|
+
"steps": steps,
|
|
232
|
+
"output": output_data
|
|
233
|
+
})
|
|
234
|
+
if resp.status_code != 200:
|
|
235
|
+
return f"Error creating receipt: {resp.text}"
|
|
236
|
+
data = resp.json()
|
|
237
|
+
return f"Reasoning receipt uploaded.\nReceipt ID: {data.get('id')}\nChain Signature: {data.get('chain_hash')}"
|
|
238
|
+
except Exception as e:
|
|
239
|
+
return f"Error connecting to server: {str(e)}"
|
|
240
|
+
|
|
241
|
+
def main():
|
|
242
|
+
mcp.run()
|
|
243
|
+
|
|
244
|
+
if __name__ == "__main__":
|
|
245
|
+
main()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: axon-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Model Context Protocol (MCP) server for Axon Protocol
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: mcp>=0.1.0
|
|
8
|
+
Requires-Dist: httpx>=0.27.0
|
|
9
|
+
|
|
10
|
+
# Axon Model Context Protocol (MCP) Server
|
|
11
|
+
|
|
12
|
+
Exposes Axon's core backend capabilities as tools that can be run natively by AI agents.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install -e .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Running
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
axon-mcp
|
|
24
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
axon_mcp/__init__.py
|
|
4
|
+
axon_mcp/server.py
|
|
5
|
+
axon_mcp.egg-info/PKG-INFO
|
|
6
|
+
axon_mcp.egg-info/SOURCES.txt
|
|
7
|
+
axon_mcp.egg-info/dependency_links.txt
|
|
8
|
+
axon_mcp.egg-info/entry_points.txt
|
|
9
|
+
axon_mcp.egg-info/requires.txt
|
|
10
|
+
axon_mcp.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
axon_mcp
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "axon-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Model Context Protocol (MCP) server for Axon Protocol"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"mcp>=0.1.0",
|
|
13
|
+
"httpx>=0.27.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.scripts]
|
|
17
|
+
axon-mcp = "axon_mcp.server:main"
|
axon_mcp-0.1.0/setup.cfg
ADDED