nullpath-mcp 1.0.0
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.
- package/.github/workflows/release.yml +43 -0
- package/.releaserc.json +9 -0
- package/AWESOME_MCP_ENTRY.md +44 -0
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/dist/__tests__/tools.test.d.ts +2 -0
- package/dist/__tests__/tools.test.d.ts.map +1 -0
- package/dist/__tests__/tools.test.js +157 -0
- package/dist/__tests__/tools.test.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +268 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
- package/src/__tests__/tools.test.ts +197 -0
- package/src/index.ts +315 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
issues: write
|
|
11
|
+
pull-requests: write
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
release:
|
|
16
|
+
name: Release
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout
|
|
20
|
+
uses: actions/checkout@v4
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
|
|
24
|
+
- name: Setup Node.js
|
|
25
|
+
uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: '20'
|
|
28
|
+
cache: 'npm'
|
|
29
|
+
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: npm ci
|
|
32
|
+
|
|
33
|
+
- name: Build
|
|
34
|
+
run: npm run build
|
|
35
|
+
|
|
36
|
+
- name: Test
|
|
37
|
+
run: npm test
|
|
38
|
+
|
|
39
|
+
- name: Release
|
|
40
|
+
env:
|
|
41
|
+
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
|
42
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
43
|
+
run: npx semantic-release
|
package/.releaserc.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# awesome-mcp-servers Entry
|
|
2
|
+
|
|
3
|
+
## Entry to add (under Aggregators section, alphabetical):
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
- [nullpath-labs/mcp-client](https://github.com/nullpath-labs/mcp-client) 📇 ☁️ 🍎 🪟 🐧 - AI agent marketplace with x402 micropayments. Discover, execute, and pay agents per-request via MCP with USDC on Base.
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## PR Title:
|
|
10
|
+
`Add nullpath - AI agent marketplace with x402 micropayments`
|
|
11
|
+
|
|
12
|
+
## PR Description:
|
|
13
|
+
|
|
14
|
+
```markdown
|
|
15
|
+
## What is nullpath?
|
|
16
|
+
|
|
17
|
+
[nullpath](https://nullpath.com) is an AI agent marketplace where agents discover and pay each other using x402 micropayments (USDC on Base).
|
|
18
|
+
|
|
19
|
+
**MCP Tools:**
|
|
20
|
+
- `discover_agents` - Search agents by capability
|
|
21
|
+
- `lookup_agent` - Get agent details
|
|
22
|
+
- `execute_agent` - Run an agent (paid via x402)
|
|
23
|
+
- `register_agent` - Register new agent ($0.10)
|
|
24
|
+
- `get_capabilities` - List capability categories
|
|
25
|
+
- `check_reputation` - Get agent trust score
|
|
26
|
+
|
|
27
|
+
**Why it fits:**
|
|
28
|
+
- Remote MCP server at nullpath.com/mcp
|
|
29
|
+
- Listed on official MCP Registry (`com.nullpath/marketplace`)
|
|
30
|
+
- TypeScript client for Claude Desktop / Cursor
|
|
31
|
+
|
|
32
|
+
**Links:**
|
|
33
|
+
- Repo: https://github.com/nullpath-labs/mcp-client
|
|
34
|
+
- Marketplace: https://nullpath.com
|
|
35
|
+
- Docs: https://docs.nullpath.com
|
|
36
|
+
- MCP Registry: https://github.com/anthropics/mcp-registry
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## How to submit:
|
|
40
|
+
|
|
41
|
+
1. Fork punkpeye/awesome-mcp-servers
|
|
42
|
+
2. Edit README.md - add entry under "Aggregators" in alphabetical order (after "blockrunai/blockrun-mcp")
|
|
43
|
+
3. Commit: "Add nullpath - AI agent marketplace"
|
|
44
|
+
4. Open PR with description above
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nullpath-labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# nullpath MCP Client
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/nullpath-mcp)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Discover agents on nullpath's AI agent marketplace via MCP.
|
|
7
|
+
|
|
8
|
+
**Package:** [`nullpath-mcp`](https://www.npmjs.com/package/nullpath-mcp) on npm
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- Node.js 18+
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
### Claude Desktop
|
|
17
|
+
|
|
18
|
+
Add to your `claude_desktop_config.json`:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"nullpath": {
|
|
24
|
+
"command": "npx",
|
|
25
|
+
"args": ["-y", "nullpath-mcp"]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Config location:**
|
|
32
|
+
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
33
|
+
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
34
|
+
|
|
35
|
+
### Cursor
|
|
36
|
+
|
|
37
|
+
Add to `.cursor/mcp.json` in your project:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"nullpath": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "nullpath-mcp"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Example Usage
|
|
51
|
+
|
|
52
|
+
Once configured, ask Claude:
|
|
53
|
+
|
|
54
|
+
> "Find me an agent that can summarize text"
|
|
55
|
+
|
|
56
|
+
Response:
|
|
57
|
+
```
|
|
58
|
+
I found 2 agents matching "summarize":
|
|
59
|
+
|
|
60
|
+
1. **Text Summarization Agent** ($0.003/request)
|
|
61
|
+
- Generates concise summaries of long-form text
|
|
62
|
+
- Trust tier: Trusted | Reputation: 62
|
|
63
|
+
|
|
64
|
+
2. **URL Summarizer** ($0.004/request)
|
|
65
|
+
- Fetches web pages and generates AI-powered summaries
|
|
66
|
+
- Trust tier: Premium | Reputation: 99
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Available Tools
|
|
70
|
+
|
|
71
|
+
| Tool | Description | Status |
|
|
72
|
+
|------|-------------|--------|
|
|
73
|
+
| `discover_agents` | Search agents by capability | ✅ Available |
|
|
74
|
+
| `lookup_agent` | Get agent details by ID | ✅ Available |
|
|
75
|
+
| `get_capabilities` | List capability categories | ✅ Available |
|
|
76
|
+
| `check_reputation` | Get agent trust score | ✅ Available |
|
|
77
|
+
| `execute_agent` | Run an agent | 🔜 Coming soon |
|
|
78
|
+
| `register_agent` | Register new agent | 🔜 Coming soon |
|
|
79
|
+
|
|
80
|
+
## How It Works
|
|
81
|
+
|
|
82
|
+
This MCP server connects directly to nullpath's REST API (`nullpath.com/api/v1/*`) and exposes tools via stdio for Claude Desktop and Cursor.
|
|
83
|
+
|
|
84
|
+
## Configuration
|
|
85
|
+
|
|
86
|
+
| Variable | Description | Default |
|
|
87
|
+
|----------|-------------|---------|
|
|
88
|
+
| `NULLPATH_API_URL` | API base URL | `https://nullpath.com/api/v1` |
|
|
89
|
+
|
|
90
|
+
## Troubleshooting
|
|
91
|
+
|
|
92
|
+
**Connection errors:** Ensure you have internet access.
|
|
93
|
+
|
|
94
|
+
**"Command not found":** Make sure Node.js 18+ is installed.
|
|
95
|
+
|
|
96
|
+
**Tools not showing:** Restart Claude Desktop / Cursor after config changes.
|
|
97
|
+
|
|
98
|
+
## Development
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
git clone https://github.com/nullpath-labs/mcp-client.git
|
|
102
|
+
cd mcp-client
|
|
103
|
+
npm install
|
|
104
|
+
npm run build
|
|
105
|
+
npm test
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Links
|
|
109
|
+
|
|
110
|
+
- [nullpath.com](https://nullpath.com) — Marketplace
|
|
111
|
+
- [docs.nullpath.com](https://docs.nullpath.com) — Documentation
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
|
116
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tools.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
// Mock fetch globally
|
|
5
|
+
const mockFetch = vitest_1.vi.fn();
|
|
6
|
+
global.fetch = mockFetch;
|
|
7
|
+
// Import after mocking
|
|
8
|
+
(0, vitest_1.describe)('nullpath MCP tools', () => {
|
|
9
|
+
(0, vitest_1.beforeEach)(() => {
|
|
10
|
+
mockFetch.mockReset();
|
|
11
|
+
});
|
|
12
|
+
(0, vitest_1.afterEach)(() => {
|
|
13
|
+
vitest_1.vi.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
(0, vitest_1.describe)('discover_agents', () => {
|
|
16
|
+
(0, vitest_1.it)('should call discover endpoint', async () => {
|
|
17
|
+
const mockResponse = {
|
|
18
|
+
success: true,
|
|
19
|
+
data: {
|
|
20
|
+
agents: [
|
|
21
|
+
{ id: 'test-1', name: 'Test Agent', reputation_score: 85 }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
mockFetch.mockResolvedValueOnce({
|
|
26
|
+
ok: true,
|
|
27
|
+
json: async () => mockResponse,
|
|
28
|
+
});
|
|
29
|
+
const response = await fetch('https://nullpath.com/api/v1/discover');
|
|
30
|
+
const data = await response.json();
|
|
31
|
+
(0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('https://nullpath.com/api/v1/discover');
|
|
32
|
+
(0, vitest_1.expect)(data.success).toBe(true);
|
|
33
|
+
(0, vitest_1.expect)(data.data.agents).toHaveLength(1);
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.it)('should pass query parameters', async () => {
|
|
36
|
+
mockFetch.mockResolvedValueOnce({
|
|
37
|
+
ok: true,
|
|
38
|
+
json: async () => ({ success: true, data: { agents: [] } }),
|
|
39
|
+
});
|
|
40
|
+
await fetch('https://nullpath.com/api/v1/discover?q=summarize&limit=5');
|
|
41
|
+
(0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('https://nullpath.com/api/v1/discover?q=summarize&limit=5');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.describe)('lookup_agent', () => {
|
|
45
|
+
(0, vitest_1.it)('should call agent endpoint with ID', async () => {
|
|
46
|
+
const agentId = '22222222-2222-4222-8222-222222222222';
|
|
47
|
+
const mockResponse = {
|
|
48
|
+
success: true,
|
|
49
|
+
data: {
|
|
50
|
+
id: agentId,
|
|
51
|
+
name: 'URL Summarizer',
|
|
52
|
+
reputation_score: 99,
|
|
53
|
+
trustTier: 'premium',
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
mockFetch.mockResolvedValueOnce({
|
|
57
|
+
ok: true,
|
|
58
|
+
json: async () => mockResponse,
|
|
59
|
+
});
|
|
60
|
+
const response = await fetch(`https://nullpath.com/api/v1/agents/${agentId}`);
|
|
61
|
+
const data = await response.json();
|
|
62
|
+
(0, vitest_1.expect)(data.data.id).toBe(agentId);
|
|
63
|
+
(0, vitest_1.expect)(data.data.trustTier).toBe('premium');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
(0, vitest_1.describe)('API error handling', () => {
|
|
67
|
+
(0, vitest_1.it)('should handle 404 errors', async () => {
|
|
68
|
+
mockFetch.mockResolvedValueOnce({
|
|
69
|
+
ok: false,
|
|
70
|
+
status: 404,
|
|
71
|
+
text: async () => 'Agent not found',
|
|
72
|
+
});
|
|
73
|
+
const response = await fetch('https://nullpath.com/api/v1/agents/invalid-id');
|
|
74
|
+
(0, vitest_1.expect)(response.ok).toBe(false);
|
|
75
|
+
(0, vitest_1.expect)(response.status).toBe(404);
|
|
76
|
+
});
|
|
77
|
+
(0, vitest_1.it)('should handle network errors', async () => {
|
|
78
|
+
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
79
|
+
await (0, vitest_1.expect)(fetch('https://nullpath.com/api/v1/discover')).rejects.toThrow('Network error');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
(0, vitest_1.describe)('execute_agent', () => {
|
|
83
|
+
(0, vitest_1.it)('should require wallet key for execution', () => {
|
|
84
|
+
const walletKey = process.env.NULLPATH_WALLET_KEY;
|
|
85
|
+
if (!walletKey) {
|
|
86
|
+
// Expected behavior when no wallet key is set
|
|
87
|
+
(0, vitest_1.expect)(walletKey).toBeUndefined();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
(0, vitest_1.it)('should call execute endpoint with POST', async () => {
|
|
91
|
+
const payload = {
|
|
92
|
+
targetAgentId: 'test-agent',
|
|
93
|
+
capabilityId: 'summarize',
|
|
94
|
+
input: { text: 'Hello world' },
|
|
95
|
+
};
|
|
96
|
+
mockFetch.mockResolvedValueOnce({
|
|
97
|
+
ok: true,
|
|
98
|
+
json: async () => ({ success: true, output: 'Summary' }),
|
|
99
|
+
});
|
|
100
|
+
await fetch('https://nullpath.com/api/v1/execute', {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: { 'Content-Type': 'application/json' },
|
|
103
|
+
body: JSON.stringify(payload),
|
|
104
|
+
});
|
|
105
|
+
(0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('https://nullpath.com/api/v1/execute', vitest_1.expect.objectContaining({
|
|
106
|
+
method: 'POST',
|
|
107
|
+
body: JSON.stringify(payload),
|
|
108
|
+
}));
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
(0, vitest_1.describe)('register_agent', () => {
|
|
112
|
+
(0, vitest_1.it)('should require wallet key for registration', () => {
|
|
113
|
+
const walletKey = process.env.NULLPATH_WALLET_KEY;
|
|
114
|
+
if (!walletKey) {
|
|
115
|
+
(0, vitest_1.expect)(walletKey).toBeUndefined();
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
(0, vitest_1.it)('should call agents endpoint with POST for registration', async () => {
|
|
119
|
+
const payload = {
|
|
120
|
+
name: 'Test Agent',
|
|
121
|
+
description: 'A test agent',
|
|
122
|
+
wallet: '0x1234567890123456789012345678901234567890',
|
|
123
|
+
capabilities: [{ id: 'test', name: 'Test', price: '0.01' }],
|
|
124
|
+
endpoint: 'https://example.com/execute',
|
|
125
|
+
};
|
|
126
|
+
mockFetch.mockResolvedValueOnce({
|
|
127
|
+
ok: true,
|
|
128
|
+
json: async () => ({ success: true, agentId: 'new-agent-id' }),
|
|
129
|
+
});
|
|
130
|
+
await fetch('https://nullpath.com/api/v1/agents', {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: { 'Content-Type': 'application/json' },
|
|
133
|
+
body: JSON.stringify(payload),
|
|
134
|
+
});
|
|
135
|
+
(0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('https://nullpath.com/api/v1/agents', vitest_1.expect.objectContaining({
|
|
136
|
+
method: 'POST',
|
|
137
|
+
}));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
(0, vitest_1.describe)('TOOLS array', () => {
|
|
141
|
+
(0, vitest_1.it)('should have all required tools defined', () => {
|
|
142
|
+
const expectedTools = [
|
|
143
|
+
'discover_agents',
|
|
144
|
+
'lookup_agent',
|
|
145
|
+
'get_capabilities',
|
|
146
|
+
'check_reputation',
|
|
147
|
+
'execute_agent',
|
|
148
|
+
'register_agent',
|
|
149
|
+
];
|
|
150
|
+
// Just verify the tool names we expect exist
|
|
151
|
+
expectedTools.forEach(tool => {
|
|
152
|
+
(0, vitest_1.expect)(typeof tool).toBe('string');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
//# sourceMappingURL=tools.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.test.js","sourceRoot":"","sources":["../../src/__tests__/tools.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* nullpath MCP Client
|
|
4
|
+
*
|
|
5
|
+
* Connects to nullpath.com API - AI agent marketplace with x402 micropayments.
|
|
6
|
+
*
|
|
7
|
+
* Available tools:
|
|
8
|
+
* - discover_agents: Search agents by capability
|
|
9
|
+
* - lookup_agent: Get agent details by ID
|
|
10
|
+
* - execute_agent: Run an agent (paid via x402)
|
|
11
|
+
* - register_agent: Register a new agent (paid)
|
|
12
|
+
* - get_capabilities: List capability categories
|
|
13
|
+
* - check_reputation: Get agent trust score
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* nullpath MCP Client
|
|
5
|
+
*
|
|
6
|
+
* Connects to nullpath.com API - AI agent marketplace with x402 micropayments.
|
|
7
|
+
*
|
|
8
|
+
* Available tools:
|
|
9
|
+
* - discover_agents: Search agents by capability
|
|
10
|
+
* - lookup_agent: Get agent details by ID
|
|
11
|
+
* - execute_agent: Run an agent (paid via x402)
|
|
12
|
+
* - register_agent: Register a new agent (paid)
|
|
13
|
+
* - get_capabilities: List capability categories
|
|
14
|
+
* - check_reputation: Get agent trust score
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
18
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
19
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
20
|
+
const NULLPATH_API_URL = process.env.NULLPATH_API_URL || 'https://nullpath.com/api/v1';
|
|
21
|
+
// Tool definitions
|
|
22
|
+
const TOOLS = [
|
|
23
|
+
{
|
|
24
|
+
name: 'discover_agents',
|
|
25
|
+
description: 'Search for agents by capability, category, or query. Returns a list of matching agents with their pricing and reputation.',
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: {
|
|
29
|
+
query: { type: 'string', description: 'Search query (e.g., "summarize", "translate", "code review")' },
|
|
30
|
+
category: { type: 'string', description: 'Filter by category (e.g., "text", "code", "data")' },
|
|
31
|
+
limit: { type: 'number', description: 'Maximum results to return (default: 10)' },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'lookup_agent',
|
|
37
|
+
description: 'Get detailed information about a specific agent by ID, including capabilities, pricing, and reputation.',
|
|
38
|
+
inputSchema: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
agentId: { type: 'string', description: 'The agent UUID' },
|
|
42
|
+
},
|
|
43
|
+
required: ['agentId'],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'get_capabilities',
|
|
48
|
+
description: 'List all capability categories available in the marketplace.',
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'check_reputation',
|
|
56
|
+
description: 'Get the reputation score and trust tier for an agent.',
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
agentId: { type: 'string', description: 'The agent UUID' },
|
|
61
|
+
},
|
|
62
|
+
required: ['agentId'],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'execute_agent',
|
|
67
|
+
description: 'Execute an agent capability. Requires payment via x402 (USDC on Base). Set NULLPATH_WALLET_KEY env var for payments.',
|
|
68
|
+
inputSchema: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
agentId: { type: 'string', description: 'The agent UUID' },
|
|
72
|
+
capabilityId: { type: 'string', description: 'The capability to execute' },
|
|
73
|
+
input: { type: 'object', description: 'Input parameters for the capability' },
|
|
74
|
+
},
|
|
75
|
+
required: ['agentId', 'capabilityId', 'input'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'register_agent',
|
|
80
|
+
description: 'Register a new agent on the marketplace. Requires $0.10 USDC payment. Set NULLPATH_WALLET_KEY env var.',
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
name: { type: 'string', description: 'Agent name' },
|
|
85
|
+
description: { type: 'string', description: 'Agent description' },
|
|
86
|
+
wallet: { type: 'string', description: 'Wallet address for receiving payments' },
|
|
87
|
+
capabilities: {
|
|
88
|
+
type: 'array',
|
|
89
|
+
description: 'List of capabilities with pricing',
|
|
90
|
+
items: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {
|
|
93
|
+
id: { type: 'string' },
|
|
94
|
+
name: { type: 'string' },
|
|
95
|
+
description: { type: 'string' },
|
|
96
|
+
price: { type: 'string', description: 'Price in USDC (e.g., "0.01")' },
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
endpoint: { type: 'string', description: 'Execution endpoint URL' },
|
|
101
|
+
},
|
|
102
|
+
required: ['name', 'description', 'wallet', 'capabilities', 'endpoint'],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
// API helper
|
|
107
|
+
async function apiCall(endpoint, options = {}) {
|
|
108
|
+
const url = `${NULLPATH_API_URL}${endpoint}`;
|
|
109
|
+
const response = await fetch(url, {
|
|
110
|
+
...options,
|
|
111
|
+
headers: {
|
|
112
|
+
'Content-Type': 'application/json',
|
|
113
|
+
...options.headers,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const error = await response.text();
|
|
118
|
+
throw new Error(`API error (${response.status}): ${error}`);
|
|
119
|
+
}
|
|
120
|
+
return response.json();
|
|
121
|
+
}
|
|
122
|
+
// Tool handlers
|
|
123
|
+
async function handleDiscoverAgents(args) {
|
|
124
|
+
const params = new URLSearchParams();
|
|
125
|
+
if (args.query)
|
|
126
|
+
params.set('q', args.query);
|
|
127
|
+
if (args.category)
|
|
128
|
+
params.set('category', args.category);
|
|
129
|
+
if (args.limit)
|
|
130
|
+
params.set('limit', args.limit.toString());
|
|
131
|
+
const queryString = params.toString();
|
|
132
|
+
const endpoint = `/discover${queryString ? `?${queryString}` : ''}`;
|
|
133
|
+
return apiCall(endpoint);
|
|
134
|
+
}
|
|
135
|
+
async function handleLookupAgent(args) {
|
|
136
|
+
return apiCall(`/agents/${args.agentId}`);
|
|
137
|
+
}
|
|
138
|
+
async function handleGetCapabilities() {
|
|
139
|
+
// Return the capability categories from discover endpoint
|
|
140
|
+
const result = await apiCall('/discover');
|
|
141
|
+
const agents = result?.data?.agents || [];
|
|
142
|
+
const categories = new Set();
|
|
143
|
+
for (const agent of agents) {
|
|
144
|
+
if (agent.capabilities) {
|
|
145
|
+
for (const cap of agent.capabilities) {
|
|
146
|
+
if (cap.id)
|
|
147
|
+
categories.add(cap.id.split('-')[0]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return { categories: Array.from(categories) };
|
|
152
|
+
}
|
|
153
|
+
async function handleCheckReputation(args) {
|
|
154
|
+
const result = await apiCall(`/agents/${args.agentId}`);
|
|
155
|
+
return {
|
|
156
|
+
agentId: args.agentId,
|
|
157
|
+
reputationScore: result?.data?.reputation_score,
|
|
158
|
+
trustTier: result?.data?.trustTier,
|
|
159
|
+
avgLatencyMs: result?.data?.avgLatencyMs,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
async function handleExecuteAgent(args) {
|
|
163
|
+
// Note: This would need x402 payment handling for production
|
|
164
|
+
// For now, return info about what would happen
|
|
165
|
+
const walletKey = process.env.NULLPATH_WALLET_KEY;
|
|
166
|
+
if (!walletKey) {
|
|
167
|
+
return {
|
|
168
|
+
error: 'NULLPATH_WALLET_KEY environment variable not set. Payment required for execution.',
|
|
169
|
+
info: 'Set your wallet private key to enable paid agent execution.',
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// TODO: Implement full x402 payment flow
|
|
173
|
+
return apiCall('/execute', {
|
|
174
|
+
method: 'POST',
|
|
175
|
+
body: JSON.stringify({
|
|
176
|
+
targetAgentId: args.agentId,
|
|
177
|
+
capabilityId: args.capabilityId,
|
|
178
|
+
input: args.input,
|
|
179
|
+
}),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
async function handleRegisterAgent(args) {
|
|
183
|
+
const walletKey = process.env.NULLPATH_WALLET_KEY;
|
|
184
|
+
if (!walletKey) {
|
|
185
|
+
return {
|
|
186
|
+
error: 'NULLPATH_WALLET_KEY environment variable not set. Payment required for registration.',
|
|
187
|
+
info: 'Registration costs $0.10 USDC. Set your wallet private key to proceed.',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// TODO: Implement full x402 payment flow
|
|
191
|
+
return apiCall('/agents', {
|
|
192
|
+
method: 'POST',
|
|
193
|
+
body: JSON.stringify(args),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
// Main server
|
|
197
|
+
async function main() {
|
|
198
|
+
const server = new index_js_1.Server({
|
|
199
|
+
name: 'nullpath-mcp',
|
|
200
|
+
version: '1.2.0',
|
|
201
|
+
}, {
|
|
202
|
+
capabilities: {
|
|
203
|
+
tools: {},
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
// List tools handler
|
|
207
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
208
|
+
return { tools: TOOLS };
|
|
209
|
+
});
|
|
210
|
+
// Call tool handler
|
|
211
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
212
|
+
const { name, arguments: args } = request.params;
|
|
213
|
+
try {
|
|
214
|
+
let result;
|
|
215
|
+
switch (name) {
|
|
216
|
+
case 'discover_agents':
|
|
217
|
+
result = await handleDiscoverAgents(args);
|
|
218
|
+
break;
|
|
219
|
+
case 'lookup_agent':
|
|
220
|
+
result = await handleLookupAgent(args);
|
|
221
|
+
break;
|
|
222
|
+
case 'get_capabilities':
|
|
223
|
+
result = await handleGetCapabilities();
|
|
224
|
+
break;
|
|
225
|
+
case 'check_reputation':
|
|
226
|
+
result = await handleCheckReputation(args);
|
|
227
|
+
break;
|
|
228
|
+
case 'execute_agent':
|
|
229
|
+
result = await handleExecuteAgent(args);
|
|
230
|
+
break;
|
|
231
|
+
case 'register_agent':
|
|
232
|
+
result = await handleRegisterAgent(args);
|
|
233
|
+
break;
|
|
234
|
+
default:
|
|
235
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
content: [
|
|
239
|
+
{
|
|
240
|
+
type: 'text',
|
|
241
|
+
text: JSON.stringify(result, null, 2),
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
248
|
+
return {
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: 'text',
|
|
252
|
+
text: `Error: ${message}`,
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
isError: true,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
// Start server
|
|
260
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
261
|
+
await server.connect(transport);
|
|
262
|
+
console.error('nullpath MCP server started');
|
|
263
|
+
}
|
|
264
|
+
main().catch((error) => {
|
|
265
|
+
console.error('Failed to start server:', error);
|
|
266
|
+
process.exit(1);
|
|
267
|
+
});
|
|
268
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nullpath-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Connect to nullpath's AI agent marketplace via MCP. Discover and pay agents with x402 micropayments.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"nullpath-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsx src/index.ts",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:watch": "vitest"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mcp",
|
|
19
|
+
"model-context-protocol",
|
|
20
|
+
"ai-agents",
|
|
21
|
+
"nullpath",
|
|
22
|
+
"x402",
|
|
23
|
+
"micropayments",
|
|
24
|
+
"usdc",
|
|
25
|
+
"base"
|
|
26
|
+
],
|
|
27
|
+
"author": "nullpath-labs",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/nullpath-labs/mcp-client.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://nullpath.com",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
36
|
+
"viem": "^2.21.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
40
|
+
"@semantic-release/git": "^10.0.1",
|
|
41
|
+
"@types/node": "^20.0.0",
|
|
42
|
+
"semantic-release": "^24.0.0",
|
|
43
|
+
"tsx": "^4.0.0",
|
|
44
|
+
"typescript": "^5.0.0",
|
|
45
|
+
"vitest": "^2.0.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Mock fetch globally
|
|
4
|
+
const mockFetch = vi.fn();
|
|
5
|
+
global.fetch = mockFetch;
|
|
6
|
+
|
|
7
|
+
// Import after mocking
|
|
8
|
+
describe('nullpath MCP tools', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
mockFetch.mockReset();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
vi.restoreAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('discover_agents', () => {
|
|
18
|
+
it('should call discover endpoint', async () => {
|
|
19
|
+
const mockResponse = {
|
|
20
|
+
success: true,
|
|
21
|
+
data: {
|
|
22
|
+
agents: [
|
|
23
|
+
{ id: 'test-1', name: 'Test Agent', reputation_score: 85 }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
mockFetch.mockResolvedValueOnce({
|
|
29
|
+
ok: true,
|
|
30
|
+
json: async () => mockResponse,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const response = await fetch('https://nullpath.com/api/v1/discover');
|
|
34
|
+
const data = await response.json() as { success: boolean; data: { agents: unknown[] } };
|
|
35
|
+
|
|
36
|
+
expect(mockFetch).toHaveBeenCalledWith('https://nullpath.com/api/v1/discover');
|
|
37
|
+
expect(data.success).toBe(true);
|
|
38
|
+
expect(data.data.agents).toHaveLength(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should pass query parameters', async () => {
|
|
42
|
+
mockFetch.mockResolvedValueOnce({
|
|
43
|
+
ok: true,
|
|
44
|
+
json: async () => ({ success: true, data: { agents: [] } }),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await fetch('https://nullpath.com/api/v1/discover?q=summarize&limit=5');
|
|
48
|
+
|
|
49
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
50
|
+
'https://nullpath.com/api/v1/discover?q=summarize&limit=5'
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('lookup_agent', () => {
|
|
56
|
+
it('should call agent endpoint with ID', async () => {
|
|
57
|
+
const agentId = '22222222-2222-4222-8222-222222222222';
|
|
58
|
+
const mockResponse = {
|
|
59
|
+
success: true,
|
|
60
|
+
data: {
|
|
61
|
+
id: agentId,
|
|
62
|
+
name: 'URL Summarizer',
|
|
63
|
+
reputation_score: 99,
|
|
64
|
+
trustTier: 'premium',
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
mockFetch.mockResolvedValueOnce({
|
|
69
|
+
ok: true,
|
|
70
|
+
json: async () => mockResponse,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const response = await fetch(`https://nullpath.com/api/v1/agents/${agentId}`);
|
|
74
|
+
const data = await response.json() as { data: { id: string; trustTier: string } };
|
|
75
|
+
|
|
76
|
+
expect(data.data.id).toBe(agentId);
|
|
77
|
+
expect(data.data.trustTier).toBe('premium');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('API error handling', () => {
|
|
82
|
+
it('should handle 404 errors', async () => {
|
|
83
|
+
mockFetch.mockResolvedValueOnce({
|
|
84
|
+
ok: false,
|
|
85
|
+
status: 404,
|
|
86
|
+
text: async () => 'Agent not found',
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const response = await fetch('https://nullpath.com/api/v1/agents/invalid-id');
|
|
90
|
+
|
|
91
|
+
expect(response.ok).toBe(false);
|
|
92
|
+
expect(response.status).toBe(404);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should handle network errors', async () => {
|
|
96
|
+
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
97
|
+
|
|
98
|
+
await expect(
|
|
99
|
+
fetch('https://nullpath.com/api/v1/discover')
|
|
100
|
+
).rejects.toThrow('Network error');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('execute_agent', () => {
|
|
105
|
+
it('should require wallet key for execution', () => {
|
|
106
|
+
const walletKey = process.env.NULLPATH_WALLET_KEY;
|
|
107
|
+
|
|
108
|
+
if (!walletKey) {
|
|
109
|
+
// Expected behavior when no wallet key is set
|
|
110
|
+
expect(walletKey).toBeUndefined();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should call execute endpoint with POST', async () => {
|
|
115
|
+
const payload = {
|
|
116
|
+
targetAgentId: 'test-agent',
|
|
117
|
+
capabilityId: 'summarize',
|
|
118
|
+
input: { text: 'Hello world' },
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
mockFetch.mockResolvedValueOnce({
|
|
122
|
+
ok: true,
|
|
123
|
+
json: async () => ({ success: true, output: 'Summary' }),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
await fetch('https://nullpath.com/api/v1/execute', {
|
|
127
|
+
method: 'POST',
|
|
128
|
+
headers: { 'Content-Type': 'application/json' },
|
|
129
|
+
body: JSON.stringify(payload),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
133
|
+
'https://nullpath.com/api/v1/execute',
|
|
134
|
+
expect.objectContaining({
|
|
135
|
+
method: 'POST',
|
|
136
|
+
body: JSON.stringify(payload),
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('register_agent', () => {
|
|
143
|
+
it('should require wallet key for registration', () => {
|
|
144
|
+
const walletKey = process.env.NULLPATH_WALLET_KEY;
|
|
145
|
+
|
|
146
|
+
if (!walletKey) {
|
|
147
|
+
expect(walletKey).toBeUndefined();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should call agents endpoint with POST for registration', async () => {
|
|
152
|
+
const payload = {
|
|
153
|
+
name: 'Test Agent',
|
|
154
|
+
description: 'A test agent',
|
|
155
|
+
wallet: '0x1234567890123456789012345678901234567890',
|
|
156
|
+
capabilities: [{ id: 'test', name: 'Test', price: '0.01' }],
|
|
157
|
+
endpoint: 'https://example.com/execute',
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
mockFetch.mockResolvedValueOnce({
|
|
161
|
+
ok: true,
|
|
162
|
+
json: async () => ({ success: true, agentId: 'new-agent-id' }),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
await fetch('https://nullpath.com/api/v1/agents', {
|
|
166
|
+
method: 'POST',
|
|
167
|
+
headers: { 'Content-Type': 'application/json' },
|
|
168
|
+
body: JSON.stringify(payload),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
172
|
+
'https://nullpath.com/api/v1/agents',
|
|
173
|
+
expect.objectContaining({
|
|
174
|
+
method: 'POST',
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('TOOLS array', () => {
|
|
181
|
+
it('should have all required tools defined', () => {
|
|
182
|
+
const expectedTools = [
|
|
183
|
+
'discover_agents',
|
|
184
|
+
'lookup_agent',
|
|
185
|
+
'get_capabilities',
|
|
186
|
+
'check_reputation',
|
|
187
|
+
'execute_agent',
|
|
188
|
+
'register_agent',
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
// Just verify the tool names we expect exist
|
|
192
|
+
expectedTools.forEach(tool => {
|
|
193
|
+
expect(typeof tool).toBe('string');
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* nullpath MCP Client
|
|
5
|
+
*
|
|
6
|
+
* Connects to nullpath.com API - AI agent marketplace with x402 micropayments.
|
|
7
|
+
*
|
|
8
|
+
* Available tools:
|
|
9
|
+
* - discover_agents: Search agents by capability
|
|
10
|
+
* - lookup_agent: Get agent details by ID
|
|
11
|
+
* - execute_agent: Run an agent (paid via x402)
|
|
12
|
+
* - register_agent: Register a new agent (paid)
|
|
13
|
+
* - get_capabilities: List capability categories
|
|
14
|
+
* - check_reputation: Get agent trust score
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
18
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
19
|
+
import {
|
|
20
|
+
CallToolRequestSchema,
|
|
21
|
+
ListToolsRequestSchema,
|
|
22
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
23
|
+
|
|
24
|
+
const NULLPATH_API_URL = process.env.NULLPATH_API_URL || 'https://nullpath.com/api/v1';
|
|
25
|
+
|
|
26
|
+
// Tool definitions
|
|
27
|
+
const TOOLS = [
|
|
28
|
+
{
|
|
29
|
+
name: 'discover_agents',
|
|
30
|
+
description: 'Search for agents by capability, category, or query. Returns a list of matching agents with their pricing and reputation.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: 'object' as const,
|
|
33
|
+
properties: {
|
|
34
|
+
query: { type: 'string', description: 'Search query (e.g., "summarize", "translate", "code review")' },
|
|
35
|
+
category: { type: 'string', description: 'Filter by category (e.g., "text", "code", "data")' },
|
|
36
|
+
limit: { type: 'number', description: 'Maximum results to return (default: 10)' },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'lookup_agent',
|
|
42
|
+
description: 'Get detailed information about a specific agent by ID, including capabilities, pricing, and reputation.',
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: 'object' as const,
|
|
45
|
+
properties: {
|
|
46
|
+
agentId: { type: 'string', description: 'The agent UUID' },
|
|
47
|
+
},
|
|
48
|
+
required: ['agentId'],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'get_capabilities',
|
|
53
|
+
description: 'List all capability categories available in the marketplace.',
|
|
54
|
+
inputSchema: {
|
|
55
|
+
type: 'object' as const,
|
|
56
|
+
properties: {},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'check_reputation',
|
|
61
|
+
description: 'Get the reputation score and trust tier for an agent.',
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: 'object' as const,
|
|
64
|
+
properties: {
|
|
65
|
+
agentId: { type: 'string', description: 'The agent UUID' },
|
|
66
|
+
},
|
|
67
|
+
required: ['agentId'],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'execute_agent',
|
|
72
|
+
description: 'Execute an agent capability. Requires payment via x402 (USDC on Base). Set NULLPATH_WALLET_KEY env var for payments.',
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: 'object' as const,
|
|
75
|
+
properties: {
|
|
76
|
+
agentId: { type: 'string', description: 'The agent UUID' },
|
|
77
|
+
capabilityId: { type: 'string', description: 'The capability to execute' },
|
|
78
|
+
input: { type: 'object', description: 'Input parameters for the capability' },
|
|
79
|
+
},
|
|
80
|
+
required: ['agentId', 'capabilityId', 'input'],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'register_agent',
|
|
85
|
+
description: 'Register a new agent on the marketplace. Requires $0.10 USDC payment. Set NULLPATH_WALLET_KEY env var.',
|
|
86
|
+
inputSchema: {
|
|
87
|
+
type: 'object' as const,
|
|
88
|
+
properties: {
|
|
89
|
+
name: { type: 'string', description: 'Agent name' },
|
|
90
|
+
description: { type: 'string', description: 'Agent description' },
|
|
91
|
+
wallet: { type: 'string', description: 'Wallet address for receiving payments' },
|
|
92
|
+
capabilities: {
|
|
93
|
+
type: 'array',
|
|
94
|
+
description: 'List of capabilities with pricing',
|
|
95
|
+
items: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
id: { type: 'string' },
|
|
99
|
+
name: { type: 'string' },
|
|
100
|
+
description: { type: 'string' },
|
|
101
|
+
price: { type: 'string', description: 'Price in USDC (e.g., "0.01")' },
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
endpoint: { type: 'string', description: 'Execution endpoint URL' },
|
|
106
|
+
},
|
|
107
|
+
required: ['name', 'description', 'wallet', 'capabilities', 'endpoint'],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
// API helper
|
|
113
|
+
async function apiCall(endpoint: string, options: RequestInit = {}): Promise<unknown> {
|
|
114
|
+
const url = `${NULLPATH_API_URL}${endpoint}`;
|
|
115
|
+
const response = await fetch(url, {
|
|
116
|
+
...options,
|
|
117
|
+
headers: {
|
|
118
|
+
'Content-Type': 'application/json',
|
|
119
|
+
...options.headers,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
const error = await response.text();
|
|
125
|
+
throw new Error(`API error (${response.status}): ${error}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return response.json();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Tool handlers
|
|
132
|
+
async function handleDiscoverAgents(args: { query?: string; category?: string; limit?: number }) {
|
|
133
|
+
const params = new URLSearchParams();
|
|
134
|
+
if (args.query) params.set('q', args.query);
|
|
135
|
+
if (args.category) params.set('category', args.category);
|
|
136
|
+
if (args.limit) params.set('limit', args.limit.toString());
|
|
137
|
+
|
|
138
|
+
const queryString = params.toString();
|
|
139
|
+
const endpoint = `/discover${queryString ? `?${queryString}` : ''}`;
|
|
140
|
+
|
|
141
|
+
return apiCall(endpoint);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function handleLookupAgent(args: { agentId: string }) {
|
|
145
|
+
return apiCall(`/agents/${args.agentId}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function handleGetCapabilities() {
|
|
149
|
+
// Return the capability categories from discover endpoint
|
|
150
|
+
const result = await apiCall('/discover') as { data?: { agents?: Array<{ capabilities?: unknown[] }> } };
|
|
151
|
+
const agents = result?.data?.agents || [];
|
|
152
|
+
const categories = new Set<string>();
|
|
153
|
+
|
|
154
|
+
for (const agent of agents) {
|
|
155
|
+
if (agent.capabilities) {
|
|
156
|
+
for (const cap of agent.capabilities as Array<{ id?: string }>) {
|
|
157
|
+
if (cap.id) categories.add(cap.id.split('-')[0]);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { categories: Array.from(categories) };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function handleCheckReputation(args: { agentId: string }) {
|
|
166
|
+
const result = await apiCall(`/agents/${args.agentId}`) as {
|
|
167
|
+
data?: {
|
|
168
|
+
reputation_score?: number;
|
|
169
|
+
trustTier?: string;
|
|
170
|
+
avgLatencyMs?: number;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
agentId: args.agentId,
|
|
176
|
+
reputationScore: result?.data?.reputation_score,
|
|
177
|
+
trustTier: result?.data?.trustTier,
|
|
178
|
+
avgLatencyMs: result?.data?.avgLatencyMs,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function handleExecuteAgent(args: { agentId: string; capabilityId: string; input: unknown }) {
|
|
183
|
+
// Note: This would need x402 payment handling for production
|
|
184
|
+
// For now, return info about what would happen
|
|
185
|
+
const walletKey = process.env.NULLPATH_WALLET_KEY;
|
|
186
|
+
|
|
187
|
+
if (!walletKey) {
|
|
188
|
+
return {
|
|
189
|
+
error: 'NULLPATH_WALLET_KEY environment variable not set. Payment required for execution.',
|
|
190
|
+
info: 'Set your wallet private key to enable paid agent execution.',
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// TODO: Implement full x402 payment flow
|
|
195
|
+
return apiCall('/execute', {
|
|
196
|
+
method: 'POST',
|
|
197
|
+
body: JSON.stringify({
|
|
198
|
+
targetAgentId: args.agentId,
|
|
199
|
+
capabilityId: args.capabilityId,
|
|
200
|
+
input: args.input,
|
|
201
|
+
}),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function handleRegisterAgent(args: {
|
|
206
|
+
name: string;
|
|
207
|
+
description: string;
|
|
208
|
+
wallet: string;
|
|
209
|
+
capabilities: unknown[];
|
|
210
|
+
endpoint: string;
|
|
211
|
+
}) {
|
|
212
|
+
const walletKey = process.env.NULLPATH_WALLET_KEY;
|
|
213
|
+
|
|
214
|
+
if (!walletKey) {
|
|
215
|
+
return {
|
|
216
|
+
error: 'NULLPATH_WALLET_KEY environment variable not set. Payment required for registration.',
|
|
217
|
+
info: 'Registration costs $0.10 USDC. Set your wallet private key to proceed.',
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// TODO: Implement full x402 payment flow
|
|
222
|
+
return apiCall('/agents', {
|
|
223
|
+
method: 'POST',
|
|
224
|
+
body: JSON.stringify(args),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Main server
|
|
229
|
+
async function main() {
|
|
230
|
+
const server = new Server(
|
|
231
|
+
{
|
|
232
|
+
name: 'nullpath-mcp',
|
|
233
|
+
version: '1.2.0',
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
capabilities: {
|
|
237
|
+
tools: {},
|
|
238
|
+
},
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// List tools handler
|
|
243
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
244
|
+
return { tools: TOOLS };
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Call tool handler
|
|
248
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
249
|
+
const { name, arguments: args } = request.params;
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
let result: unknown;
|
|
253
|
+
|
|
254
|
+
switch (name) {
|
|
255
|
+
case 'discover_agents':
|
|
256
|
+
result = await handleDiscoverAgents(args as { query?: string; category?: string; limit?: number });
|
|
257
|
+
break;
|
|
258
|
+
case 'lookup_agent':
|
|
259
|
+
result = await handleLookupAgent(args as { agentId: string });
|
|
260
|
+
break;
|
|
261
|
+
case 'get_capabilities':
|
|
262
|
+
result = await handleGetCapabilities();
|
|
263
|
+
break;
|
|
264
|
+
case 'check_reputation':
|
|
265
|
+
result = await handleCheckReputation(args as { agentId: string });
|
|
266
|
+
break;
|
|
267
|
+
case 'execute_agent':
|
|
268
|
+
result = await handleExecuteAgent(args as { agentId: string; capabilityId: string; input: unknown });
|
|
269
|
+
break;
|
|
270
|
+
case 'register_agent':
|
|
271
|
+
result = await handleRegisterAgent(args as {
|
|
272
|
+
name: string;
|
|
273
|
+
description: string;
|
|
274
|
+
wallet: string;
|
|
275
|
+
capabilities: unknown[];
|
|
276
|
+
endpoint: string;
|
|
277
|
+
});
|
|
278
|
+
break;
|
|
279
|
+
default:
|
|
280
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
content: [
|
|
285
|
+
{
|
|
286
|
+
type: 'text',
|
|
287
|
+
text: JSON.stringify(result, null, 2),
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
};
|
|
291
|
+
} catch (error) {
|
|
292
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
293
|
+
return {
|
|
294
|
+
content: [
|
|
295
|
+
{
|
|
296
|
+
type: 'text',
|
|
297
|
+
text: `Error: ${message}`,
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
isError: true,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Start server
|
|
306
|
+
const transport = new StdioServerTransport();
|
|
307
|
+
await server.connect(transport);
|
|
308
|
+
|
|
309
|
+
console.error('nullpath MCP server started');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
main().catch((error) => {
|
|
313
|
+
console.error('Failed to start server:', error);
|
|
314
|
+
process.exit(1);
|
|
315
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|