mirror of
https://github.com/aljazceru/dvmcp.git
synced 2025-12-17 05:14:24 +01:00
refactor: kind number, readme, license, spec
This commit is contained in:
21
LICENSE
21
LICENSE
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|||||||
111
README.md
111
README.md
@@ -1,15 +1,116 @@
|
|||||||
# dvmcp
|
# DVMCP: Data Vending Machine Context Protocol
|
||||||
|
|
||||||
To install dependencies:
|
DVMCP is a bridge implementation that connects Model Context Protocol (MCP) servers to Nostr's Data Vending Machine (DVM) ecosystem. This bridge enables AI and computational tools exposed through MCP to be discovered and utilized via Nostr's decentralized network.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The Model Context Protocol provides a standardized way for applications to expose AI capabilities and tools, while Nostr's Data Vending Machines offer a decentralized marketplace for computational services. This bridge brings these two worlds together, allowing:
|
||||||
|
|
||||||
|
- MCP servers to announce their capabilities on the Nostr network
|
||||||
|
- Nostr clients to discover available MCP tools
|
||||||
|
- Seamless execution of MCP tools through Nostr's DVM protocol
|
||||||
|
- Standardized payment handling
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Service Discovery**: Automatically announces MCP services using NIP-89
|
||||||
|
- **Tool Discovery**: Exposes MCP tools through DVM kind:5600/6600 events
|
||||||
|
- **Tool Execution**: Handles tool execution requests via kind:5601/6601 events
|
||||||
|
- **Status Updates**: Provides job status and payment handling via kind:7000 events
|
||||||
|
- **Error Handling**: Comprehensive error handling and status reporting
|
||||||
|
- **Payment Flow**: Built-in support for Lightning payment processing
|
||||||
|
|
||||||
|
## Protocol Specification
|
||||||
|
|
||||||
|
For detailed information about the DVMCP, see the [specification document](docs/dvmcp-spec.md).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- [Bun](https://bun.sh) runtime (v1.2.2 or later)
|
||||||
|
- A running MCP server
|
||||||
|
- Access to Nostr relays
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
1. Clone the repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/gzuuus/dvmcp.git
|
||||||
|
cd dvmcp
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun install
|
bun install
|
||||||
```
|
```
|
||||||
|
|
||||||
To run:
|
3. Create your configuration:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun run index.ts
|
cp .env.example .env
|
||||||
```
|
```
|
||||||
|
|
||||||
This project was created using `bun init` in bun v1.2.2. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
4. Edit `.env` with your settings:
|
||||||
|
|
||||||
|
### Running the Bridge
|
||||||
|
|
||||||
|
Development mode with auto-reload:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Production mode:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run start
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
The bridge operates in several stages:
|
||||||
|
|
||||||
|
1. **Initialization**:
|
||||||
|
|
||||||
|
- Connects to the specified MCP server
|
||||||
|
- Announces service availability on Nostr network
|
||||||
|
- Begins listening for DVM requests
|
||||||
|
|
||||||
|
2. **Tool Discovery**:
|
||||||
|
|
||||||
|
- Receives kind:5600 requests from clients
|
||||||
|
- Queries available tools from MCP server
|
||||||
|
- Responds with kind:6600 tool catalog
|
||||||
|
|
||||||
|
3. **Tool Execution**:
|
||||||
|
|
||||||
|
- Receives kind:5601 execution requests
|
||||||
|
- Validates parameters against tool schema
|
||||||
|
- Executes tool via MCP server
|
||||||
|
- Returns results via kind:6601 events
|
||||||
|
- Provides status updates via kind:7000 events
|
||||||
|
|
||||||
|
4. **Payment Processing**:
|
||||||
|
- Handles payment requirements through kind:7000 events
|
||||||
|
- Supports Lightning Network payments
|
||||||
|
- Provides execution status updates
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please feel free to submit pull requests, or issues. For major changes, please open an issue first to discuss what you would like to change.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT License](LICENSE)
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
This project builds on several excellent open-source projects:
|
||||||
|
|
||||||
|
- [Model Context Protocol](https://modelcontextprotocol.io)
|
||||||
|
- [Nostr Protocol](https://github.com/nostr-protocol/nips)
|
||||||
|
- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
|
||||||
|
- [Nostr Tools](https://github.com/nbd-wtf/nostr-tools)
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ The protocol consists of four main phases:
|
|||||||
|
|
||||||
## Event Kinds
|
## Event Kinds
|
||||||
|
|
||||||
This specification defines how to use existing DVM event kinds (5000-7000) for MCP integration:
|
This specification defines how to use existing DVM event kinds (5600-7000) for MCP integration:
|
||||||
|
|
||||||
| Kind | Description |
|
| Kind | Description |
|
||||||
| ---- | ------------------------------- |
|
| ---- | ------------------------------- |
|
||||||
| 5000 | Tool discovery request |
|
| 5600 | Tool discovery request |
|
||||||
| 6000 | Tool catalog response |
|
| 6600 | Tool catalog response |
|
||||||
| 5001 | Tool execution request |
|
| 5601 | Tool execution request |
|
||||||
| 6001 | Tool execution response |
|
| 6601 | Tool execution response |
|
||||||
| 7000 | Job feedback and payment status |
|
| 7000 | Job feedback and payment status |
|
||||||
|
|
||||||
## Service Discovery
|
## Service Discovery
|
||||||
@@ -62,8 +62,8 @@ Service providers SHOULD announce their DVM capabilities using NIP-89 handler in
|
|||||||
},
|
},
|
||||||
"tags": [
|
"tags": [
|
||||||
["d", "<dvm-announcement/random-id>"],
|
["d", "<dvm-announcement/random-id>"],
|
||||||
["k", "5000"], // Tool discovery
|
["k", "5600"], // Tool discovery
|
||||||
["k", "5001"], // Tool execution
|
["k", "5601"], // Tool execution
|
||||||
["capabilities", "mcp-1.0"],
|
["capabilities", "mcp-1.0"],
|
||||||
["t", "mcp"]
|
["t", "mcp"]
|
||||||
]
|
]
|
||||||
@@ -73,17 +73,17 @@ Service providers SHOULD announce their DVM capabilities using NIP-89 handler in
|
|||||||
### Required Tags
|
### Required Tags
|
||||||
|
|
||||||
- `d`: A unique identifier for this announcement that should be maintained consistently for announcement updates
|
- `d`: A unique identifier for this announcement that should be maintained consistently for announcement updates
|
||||||
- `k`: The event kinds this DVM supports (must include 5000 and 5001 for MCP support)
|
- `k`: The event kinds this DVM supports (must include 5600 and 5601 for MCP support)
|
||||||
- `capabilities`: Must include "mcp-1.0" to indicate MCP protocol support
|
- `capabilities`: Must include "mcp-1.0" to indicate MCP protocol support
|
||||||
- `t`: Should include "mcp" to aid in discovery
|
- `t`: Should include "mcp" to aid in discovery
|
||||||
|
|
||||||
### Tool Discovery Request (kind: 5000)
|
### Tool Discovery Request (kind: 5600)
|
||||||
|
|
||||||
Clients discover available tools by sending a kind 5000 event. This initiates the tool discovery process.
|
Clients discover available tools by sending a kind 5600 event. This initiates the tool discovery process.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"kind": 5000,
|
"kind": 5600,
|
||||||
"content": "",
|
"content": "",
|
||||||
"tags": [
|
"tags": [
|
||||||
["output", "application/json"],
|
["output", "application/json"],
|
||||||
@@ -98,13 +98,13 @@ The `p` tag MAY be included to target a specific provider:
|
|||||||
["p", "<provider-pubkey>"]
|
["p", "<provider-pubkey>"]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tool Catalog Response (kind: 6000)
|
### Tool Catalog Response (kind: 6600)
|
||||||
|
|
||||||
The DVM MUST respond with a kind 6000 event that lists all available tools and their specifications:
|
The DVM MUST respond with a kind 6600 event that lists all available tools and their specifications:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"kind": 6000,
|
"kind": 6600,
|
||||||
"content": {
|
"content": {
|
||||||
"tools": [
|
"tools": [
|
||||||
{
|
{
|
||||||
@@ -162,13 +162,13 @@ Common parameter and properties types include:
|
|||||||
|
|
||||||
Tools are executed through a request/response pair of events.
|
Tools are executed through a request/response pair of events.
|
||||||
|
|
||||||
### Job Request (kind: 5001)
|
### Job Request (kind: 5601)
|
||||||
|
|
||||||
Tools are executed using a kind 5001 event:
|
Tools are executed using a kind 5601 event:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"kind": 5001,
|
"kind": 5601,
|
||||||
"content": {
|
"content": {
|
||||||
"name": "<tool-name>",
|
"name": "<tool-name>",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
@@ -191,11 +191,11 @@ The content object MAY include:
|
|||||||
- `timeout`: Maximum execution time in milliseconds
|
- `timeout`: Maximum execution time in milliseconds
|
||||||
- `metadata`: Additional execution context
|
- `metadata`: Additional execution context
|
||||||
|
|
||||||
### Job Response (kind: 6001)
|
### Job Response (kind: 6601)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"kind": 6001,
|
"kind": 6601,
|
||||||
"content": {
|
"content": {
|
||||||
"content": [
|
"content": [
|
||||||
{
|
{
|
||||||
@@ -297,7 +297,7 @@ For any error, DVMs MUST:
|
|||||||
|
|
||||||
1. Send a kind 7000 event with status "error"
|
1. Send a kind 7000 event with status "error"
|
||||||
2. Include relevant error details in the content
|
2. Include relevant error details in the content
|
||||||
3. Set isError=true in any kind 6001 response
|
3. Set isError=true in any kind 6601 response
|
||||||
|
|
||||||
## Implementation Requirements
|
## Implementation Requirements
|
||||||
|
|
||||||
@@ -324,17 +324,17 @@ sequenceDiagram
|
|||||||
Client->>Relay: Query kind:31990
|
Client->>Relay: Query kind:31990
|
||||||
Relay-->>Client: DVM handler info
|
Relay-->>Client: DVM handler info
|
||||||
|
|
||||||
Client->>DVM: kind:5000 (List Tools)
|
Client->>DVM: kind:5600 (List Tools)
|
||||||
DVM->>Server: Initialize + Get Tools
|
DVM->>Server: Initialize + Get Tools
|
||||||
Server-->>DVM: Tool Definitions
|
Server-->>DVM: Tool Definitions
|
||||||
DVM-->>Client: kind:6000 (Tool Catalog)
|
DVM-->>Client: kind:6600 (Tool Catalog)
|
||||||
|
|
||||||
Client->>DVM: kind:5001 (Execute Tool)
|
Client->>DVM: kind:5601 (Execute Tool)
|
||||||
DVM-->>Client: (Optional)kind:7000 (payment-required)
|
DVM-->>Client: (Optional)kind:7000 (payment-required)
|
||||||
Client->>DVM: Payment
|
Client->>DVM: Payment
|
||||||
DVM-->>Client: kind:7000 (processing)
|
DVM-->>Client: kind:7000 (processing)
|
||||||
DVM->>Server: Execute Tool
|
DVM->>Server: Execute Tool
|
||||||
Server-->>DVM: Results
|
Server-->>DVM: Results
|
||||||
DVM-->>Client: kind:7000 (success)
|
DVM-->>Client: kind:7000 (success)
|
||||||
DVM-->>Client: kind:6001 (Results)
|
DVM-->>Client: kind:6601 (Results)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"name": "dvmcp",
|
"name": "dvmcp",
|
||||||
"module": "src/dvm-bridge.ts",
|
"module": "src/dvm-bridge.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
|
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
|
||||||
"dev": "bun --watch src/dvm-bridge.ts",
|
"dev": "bun --watch src/dvm-bridge.ts",
|
||||||
|
|||||||
@@ -65,11 +65,11 @@ export class DVMBridge {
|
|||||||
|
|
||||||
private async handleRequest(event: Event) {
|
private async handleRequest(event: Event) {
|
||||||
try {
|
try {
|
||||||
if (event.kind === 5000) {
|
if (event.kind === 5600) {
|
||||||
const tools = await this.mcpClient.listTools();
|
const tools = await this.mcpClient.listTools();
|
||||||
|
|
||||||
const response = keyManager.signEvent({
|
const response = keyManager.signEvent({
|
||||||
...keyManager.createEventTemplate(6000),
|
...keyManager.createEventTemplate(6600),
|
||||||
content: JSON.stringify({
|
content: JSON.stringify({
|
||||||
schema_version: '1.0',
|
schema_version: '1.0',
|
||||||
tools,
|
tools,
|
||||||
@@ -81,7 +81,7 @@ export class DVMBridge {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await this.relayHandler.publishEvent(response);
|
await this.relayHandler.publishEvent(response);
|
||||||
} else if (event.kind === 5001) {
|
} else if (event.kind === 5601) {
|
||||||
const { name, parameters } = JSON.parse(event.content);
|
const { name, parameters } = JSON.parse(event.content);
|
||||||
|
|
||||||
const processingStatus = keyManager.signEvent({
|
const processingStatus = keyManager.signEvent({
|
||||||
@@ -108,7 +108,7 @@ export class DVMBridge {
|
|||||||
await this.relayHandler.publishEvent(successStatus);
|
await this.relayHandler.publishEvent(successStatus);
|
||||||
|
|
||||||
const response = keyManager.signEvent({
|
const response = keyManager.signEvent({
|
||||||
...keyManager.createEventTemplate(6001),
|
...keyManager.createEventTemplate(6601),
|
||||||
content: JSON.stringify(result),
|
content: JSON.stringify(result),
|
||||||
tags: [
|
tags: [
|
||||||
['e', event.id],
|
['e', event.id],
|
||||||
@@ -153,11 +153,9 @@ if (import.meta.main) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle termination signals
|
|
||||||
process.on('SIGINT', shutdown);
|
process.on('SIGINT', shutdown);
|
||||||
process.on('SIGTERM', shutdown);
|
process.on('SIGTERM', shutdown);
|
||||||
|
|
||||||
// Start the bridge
|
|
||||||
try {
|
try {
|
||||||
await bridge.start();
|
await bridge.start();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ export class NostrAnnouncer {
|
|||||||
}),
|
}),
|
||||||
tags: [
|
tags: [
|
||||||
['d', 'dvm-announcement'],
|
['d', 'dvm-announcement'],
|
||||||
['k', '5000'],
|
['k', '5600'],
|
||||||
['k', '5001'],
|
['k', '5601'],
|
||||||
['capabilities', 'mcp-1.0'],
|
['capabilities', 'mcp-1.0'],
|
||||||
['t', 'mcp'],
|
['t', 'mcp'],
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export class RelayHandler {
|
|||||||
subscribeToRequests(onRequest: (event: Event) => void): SubCloser {
|
subscribeToRequests(onRequest: (event: Event) => void): SubCloser {
|
||||||
const filters: Filter[] = [
|
const filters: Filter[] = [
|
||||||
{
|
{
|
||||||
kinds: [5000, 5001],
|
kinds: [5600, 5601],
|
||||||
since: Math.floor(Date.now() / 1000),
|
since: Math.floor(Date.now() / 1000),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user