macaroonnetwork-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.
- macaroonnetwork_mcp-0.1.0/.gitignore +16 -0
- macaroonnetwork_mcp-0.1.0/PKG-INFO +72 -0
- macaroonnetwork_mcp-0.1.0/README.md +54 -0
- macaroonnetwork_mcp-0.1.0/macaroonnetwork_mcp/__init__.py +6 -0
- macaroonnetwork_mcp-0.1.0/macaroonnetwork_mcp/mcp_server.py +177 -0
- macaroonnetwork_mcp-0.1.0/pyproject.toml +33 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: macaroonnetwork-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Discovery-only MCP client for Macaroon Network -- search and inspect a live marketplace where AI agents pay per query in Bitcoin over Lightning.
|
|
5
|
+
Project-URL: Homepage, https://macaroonnetwork.com
|
|
6
|
+
Project-URL: Repository, https://github.com/kevmoz/macaroonnetwork
|
|
7
|
+
Author: Kevin Smith
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: agent-commerce,l402,lightning,marketplace,mcp,model-context-protocol
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Requires-Dist: mcp>=1.0.0
|
|
16
|
+
Requires-Dist: requests>=2.31.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# macaroonnetwork-mcp
|
|
20
|
+
|
|
21
|
+
Discovery-only MCP client for [Macaroon Network](https://macaroonnetwork.com) —
|
|
22
|
+
a marketplace where AI agents discover, pay for (Bitcoin/Lightning via L402),
|
|
23
|
+
and buy live data.
|
|
24
|
+
|
|
25
|
+
## What this does
|
|
26
|
+
|
|
27
|
+
Two tools, both free, no payment or configuration required:
|
|
28
|
+
|
|
29
|
+
- **`macaroons_search`** — semantic search over the live marketplace registry
|
|
30
|
+
by natural-language intent.
|
|
31
|
+
- **`macaroons_metadata`** — free freshness/content-hash metadata for a feed
|
|
32
|
+
target, before deciding whether to buy.
|
|
33
|
+
|
|
34
|
+
## What this does *not* do (yet)
|
|
35
|
+
|
|
36
|
+
This package does not expose buying tools (`macaroons_purchase` /
|
|
37
|
+
`macaroons_execute`). The reference buyer implementation in the
|
|
38
|
+
[macaroonnetwork repo](https://github.com/kevmoz/macaroonnetwork) pays via a
|
|
39
|
+
regtest Lightning node that's part of that repo's own dev environment —
|
|
40
|
+
there's no way to make that work correctly for an arbitrary external
|
|
41
|
+
installation yet. Real-wallet payment support (a configurable Lightning node,
|
|
42
|
+
or the Polygon stablecoin credit rail) is planned; this package will grow
|
|
43
|
+
purchase tools once that exists. Shipping non-functional buy tools now would
|
|
44
|
+
mean they silently fail for every real user, which is exactly the kind of
|
|
45
|
+
thing this project's L402/predicate machinery exists to prevent on the seller
|
|
46
|
+
side — no reason to reintroduce it here.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install macaroonnetwork-mcp
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Use with an MCP client
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"macaroonnetwork": {
|
|
60
|
+
"command": "macaroonnetwork-mcp"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Talks to `https://api.macaroonnetwork.com` by default. Override with
|
|
67
|
+
`MACAROONS_REGISTRY_URL` / `MACAROONS_FEED_URL` env vars to point at a local
|
|
68
|
+
dev stack instead.
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
MIT
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# macaroonnetwork-mcp
|
|
2
|
+
|
|
3
|
+
Discovery-only MCP client for [Macaroon Network](https://macaroonnetwork.com) —
|
|
4
|
+
a marketplace where AI agents discover, pay for (Bitcoin/Lightning via L402),
|
|
5
|
+
and buy live data.
|
|
6
|
+
|
|
7
|
+
## What this does
|
|
8
|
+
|
|
9
|
+
Two tools, both free, no payment or configuration required:
|
|
10
|
+
|
|
11
|
+
- **`macaroons_search`** — semantic search over the live marketplace registry
|
|
12
|
+
by natural-language intent.
|
|
13
|
+
- **`macaroons_metadata`** — free freshness/content-hash metadata for a feed
|
|
14
|
+
target, before deciding whether to buy.
|
|
15
|
+
|
|
16
|
+
## What this does *not* do (yet)
|
|
17
|
+
|
|
18
|
+
This package does not expose buying tools (`macaroons_purchase` /
|
|
19
|
+
`macaroons_execute`). The reference buyer implementation in the
|
|
20
|
+
[macaroonnetwork repo](https://github.com/kevmoz/macaroonnetwork) pays via a
|
|
21
|
+
regtest Lightning node that's part of that repo's own dev environment —
|
|
22
|
+
there's no way to make that work correctly for an arbitrary external
|
|
23
|
+
installation yet. Real-wallet payment support (a configurable Lightning node,
|
|
24
|
+
or the Polygon stablecoin credit rail) is planned; this package will grow
|
|
25
|
+
purchase tools once that exists. Shipping non-functional buy tools now would
|
|
26
|
+
mean they silently fail for every real user, which is exactly the kind of
|
|
27
|
+
thing this project's L402/predicate machinery exists to prevent on the seller
|
|
28
|
+
side — no reason to reintroduce it here.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install macaroonnetwork-mcp
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Use with an MCP client
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"macaroonnetwork": {
|
|
42
|
+
"command": "macaroonnetwork-mcp"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Talks to `https://api.macaroonnetwork.com` by default. Override with
|
|
49
|
+
`MACAROONS_REGISTRY_URL` / `MACAROONS_FEED_URL` env vars to point at a local
|
|
50
|
+
dev stack instead.
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"""macaroonnetwork-mcp — discovery-only MCP server for Macaroon Network.
|
|
2
|
+
|
|
3
|
+
Exposes two read-only tools any MCP client can use with zero configuration:
|
|
4
|
+
|
|
5
|
+
- macaroons_search: semantic search over the live marketplace registry.
|
|
6
|
+
- macaroons_metadata: free metadata for a feed target (freshness, content
|
|
7
|
+
hash) before deciding whether to buy.
|
|
8
|
+
|
|
9
|
+
Deliberately does NOT expose macaroons_purchase / macaroons_execute (the
|
|
10
|
+
paid tools). The reference implementation of those in the macaroonnetwork
|
|
11
|
+
repo (packages/buyer/) pays by shelling out to this repo's own regtest
|
|
12
|
+
Lightning dev environment (docker compose exec lnd-buyer lncli payinvoice)
|
|
13
|
+
-- there is no docker-compose.dev.yml or regtest LND node on an external
|
|
14
|
+
user's machine, so those tools would silently fail for anyone who isn't
|
|
15
|
+
running inside that repo's checkout. Shipping them here would mean this
|
|
16
|
+
package's "buy" tools crash for every real external user -- exactly the
|
|
17
|
+
kind of unearned-passing-result this whole project exists to avoid on the
|
|
18
|
+
seller side. Real-wallet payment support (a configurable LND node, or the
|
|
19
|
+
Polygon x402/stablecoin credit rail) is a separate, not-yet-built piece of
|
|
20
|
+
work; this package will grow purchase/execute tools once that exists.
|
|
21
|
+
|
|
22
|
+
Talks to https://api.macaroonnetwork.com by default -- override with
|
|
23
|
+
MACAROONS_REGISTRY_URL / MACAROONS_FEED_URL for local development against
|
|
24
|
+
this repo's own dev stack.
|
|
25
|
+
"""
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import asyncio
|
|
29
|
+
import json
|
|
30
|
+
import os
|
|
31
|
+
from typing import Any
|
|
32
|
+
|
|
33
|
+
import requests
|
|
34
|
+
|
|
35
|
+
_REGISTRY_URL = os.environ.get("MACAROONS_REGISTRY_URL", "https://api.macaroonnetwork.com")
|
|
36
|
+
_FEED_URL = os.environ.get("MACAROONS_FEED_URL", "https://api.macaroonnetwork.com")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_tool_definitions() -> list[dict[str, Any]]:
|
|
40
|
+
return [
|
|
41
|
+
{
|
|
42
|
+
"name": "macaroons_search",
|
|
43
|
+
"description": (
|
|
44
|
+
"Search Macaroon Network for capabilities matching an intent. "
|
|
45
|
+
"Returns ranked listings with price, predicate hash, and freshness. "
|
|
46
|
+
"Free, no payment required."
|
|
47
|
+
),
|
|
48
|
+
"inputSchema": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"properties": {
|
|
51
|
+
"intent": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"description": (
|
|
54
|
+
"Natural language description of what the agent needs. "
|
|
55
|
+
"E.g. 'GPU pricing data updated in the last 24 hours'"
|
|
56
|
+
),
|
|
57
|
+
},
|
|
58
|
+
"limit": {
|
|
59
|
+
"type": "integer",
|
|
60
|
+
"default": 5,
|
|
61
|
+
"maximum": 20,
|
|
62
|
+
"description": "Maximum number of results to return",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
"required": ["intent"],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "macaroons_metadata",
|
|
70
|
+
"description": (
|
|
71
|
+
"Get free metadata for a feed target before purchasing. Returns "
|
|
72
|
+
"freshness and content_hash. No payment required."
|
|
73
|
+
),
|
|
74
|
+
"inputSchema": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {
|
|
77
|
+
"target_id": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"description": "The feed target id (e.g. 'runpod').",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
"required": ["target_id"],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _ok(data: Any) -> dict[str, Any]:
|
|
89
|
+
return {"isError": False, "content": [{"type": "text", "text": json.dumps(data)}]}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _error(message: str) -> dict[str, Any]:
|
|
93
|
+
return {"isError": True, "content": [{"type": "text", "text": message}]}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
async def _search(args: dict[str, Any]) -> dict[str, Any]:
|
|
97
|
+
def _do() -> list[dict[str, Any]]:
|
|
98
|
+
resp = requests.get(
|
|
99
|
+
f"{_REGISTRY_URL}/listings/search",
|
|
100
|
+
params={"intent": args["intent"], "limit": args.get("limit", 5)},
|
|
101
|
+
timeout=15,
|
|
102
|
+
)
|
|
103
|
+
resp.raise_for_status()
|
|
104
|
+
return resp.json().get("listings", [])
|
|
105
|
+
|
|
106
|
+
return _ok(await asyncio.to_thread(_do))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
async def _metadata(args: dict[str, Any]) -> dict[str, Any]:
|
|
110
|
+
def _do() -> dict[str, Any]:
|
|
111
|
+
resp = requests.get(f"{_FEED_URL}/meta", timeout=15)
|
|
112
|
+
resp.raise_for_status()
|
|
113
|
+
target_id = args["target_id"]
|
|
114
|
+
for target in resp.json().get("targets", []):
|
|
115
|
+
if target["target_id"] == target_id:
|
|
116
|
+
return target
|
|
117
|
+
raise ValueError(f"unknown target_id: {target_id}")
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
result = await asyncio.to_thread(_do)
|
|
121
|
+
except ValueError as exc:
|
|
122
|
+
return _error(str(exc))
|
|
123
|
+
return _ok(result)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
async def call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]:
|
|
127
|
+
if name == "macaroons_search":
|
|
128
|
+
return await _search(arguments)
|
|
129
|
+
if name == "macaroons_metadata":
|
|
130
|
+
return await _metadata(arguments)
|
|
131
|
+
return _error(f"unknown tool: {name}")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _build_mcp_server():
|
|
135
|
+
"""Wires get_tool_definitions()/call_tool() into a real mcp.server.Server
|
|
136
|
+
for stdio use. Imported lazily so offline unit tests (which only need
|
|
137
|
+
get_tool_definitions()/call_tool()) never require the mcp package."""
|
|
138
|
+
import mcp.types as types
|
|
139
|
+
from mcp.server import Server
|
|
140
|
+
from mcp.server.stdio import stdio_server
|
|
141
|
+
|
|
142
|
+
async def on_list_tools(ctx, params):
|
|
143
|
+
tools = [
|
|
144
|
+
types.Tool(
|
|
145
|
+
name=t["name"], description=t["description"], input_schema=t["inputSchema"]
|
|
146
|
+
)
|
|
147
|
+
for t in get_tool_definitions()
|
|
148
|
+
]
|
|
149
|
+
return types.ListToolsResult(tools=tools)
|
|
150
|
+
|
|
151
|
+
async def on_call_tool(ctx, params):
|
|
152
|
+
result = await call_tool(params.name, params.arguments or {})
|
|
153
|
+
content = [types.TextContent(type="text", text=item["text"]) for item in result["content"]]
|
|
154
|
+
return types.CallToolResult(content=content, is_error=result["isError"])
|
|
155
|
+
|
|
156
|
+
server = Server(
|
|
157
|
+
"macaroon-network",
|
|
158
|
+
version="0.1.0",
|
|
159
|
+
on_list_tools=on_list_tools,
|
|
160
|
+
on_call_tool=on_call_tool,
|
|
161
|
+
)
|
|
162
|
+
return server, stdio_server
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
async def _main() -> None:
|
|
166
|
+
server, stdio_server = _build_mcp_server()
|
|
167
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
168
|
+
await server.run(read_stream, write_stream, server.create_initialization_options())
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def main() -> None:
|
|
172
|
+
"""Console-script entry point (see pyproject.toml [project.scripts])."""
|
|
173
|
+
asyncio.run(_main())
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if __name__ == "__main__":
|
|
177
|
+
main()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "macaroonnetwork-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Discovery-only MCP client for Macaroon Network -- search and inspect a live marketplace where AI agents pay per query in Bitcoin over Lightning."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "Kevin Smith" }]
|
|
13
|
+
keywords = ["mcp", "model-context-protocol", "agent-commerce", "l402", "lightning", "marketplace"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"mcp>=1.0.0",
|
|
22
|
+
"requests>=2.31.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://macaroonnetwork.com"
|
|
27
|
+
Repository = "https://github.com/kevmoz/macaroonnetwork"
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
macaroonnetwork-mcp = "macaroonnetwork_mcp.mcp_server:main"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["macaroonnetwork_mcp"]
|