@anycast/mcp 0.1.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/README.md +135 -0
- package/dist/client.d.ts +63 -0
- package/dist/client.js +148 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +132 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# @anycast/mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for the [Anycast Platform](https://anycast.net). Enables AI assistants like Claude, Cursor, and Copilot to manage agents, webhooks, and P2P connectivity.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @anycast/mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
Set your Anycast API key:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
export ANYCAST_API_KEY=your-api-key-here
|
|
17
|
+
export ANYCAST_API_URL=https://api.anycast.net # optional, defaults to localhost:3002
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage with Claude Desktop
|
|
21
|
+
|
|
22
|
+
Add to your `claude_desktop_config.json`:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"anycast": {
|
|
28
|
+
"command": "anycast-mcp",
|
|
29
|
+
"env": {
|
|
30
|
+
"ANYCAST_API_KEY": "your-api-key-here",
|
|
31
|
+
"ANYCAST_API_URL": "https://api.anycast.net"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage with Claude Code
|
|
39
|
+
|
|
40
|
+
Add to your project's `.claude/settings.json`:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"anycast": {
|
|
46
|
+
"command": "npx",
|
|
47
|
+
"args": ["@anycast/mcp"],
|
|
48
|
+
"env": {
|
|
49
|
+
"ANYCAST_API_KEY": "your-api-key-here"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage with Cursor
|
|
57
|
+
|
|
58
|
+
Add to Cursor settings > MCP Servers:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"anycast": {
|
|
63
|
+
"command": "anycast-mcp",
|
|
64
|
+
"env": {
|
|
65
|
+
"ANYCAST_API_KEY": "your-api-key-here"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Available Tools
|
|
72
|
+
|
|
73
|
+
### Agents
|
|
74
|
+
| Tool | Description |
|
|
75
|
+
|------|-------------|
|
|
76
|
+
| `list_agents` | List all agents with status, IP, version |
|
|
77
|
+
| `get_agent` | Get agent details by ID |
|
|
78
|
+
| `update_agent` | Update agent name or labels |
|
|
79
|
+
| `delete_agent` | Delete agent (disconnects connections) |
|
|
80
|
+
| `get_agent_connections` | Get connection history for an agent |
|
|
81
|
+
|
|
82
|
+
### Tokens
|
|
83
|
+
| Tool | Description |
|
|
84
|
+
|------|-------------|
|
|
85
|
+
| `list_tokens` | List registration tokens (prefixes only) |
|
|
86
|
+
| `create_token` | Create new registration token |
|
|
87
|
+
| `revoke_token` | Revoke a token |
|
|
88
|
+
|
|
89
|
+
### Groups
|
|
90
|
+
| Tool | Description |
|
|
91
|
+
|------|-------------|
|
|
92
|
+
| `list_groups` | List agent groups |
|
|
93
|
+
| `create_group` | Create a new group |
|
|
94
|
+
| `add_agent_to_group` | Add agent to group |
|
|
95
|
+
| `remove_agent_from_group` | Remove agent from group |
|
|
96
|
+
|
|
97
|
+
### Connectivity
|
|
98
|
+
| Tool | Description |
|
|
99
|
+
|------|-------------|
|
|
100
|
+
| `get_discovery` | Get rendezvous server URL |
|
|
101
|
+
| `list_connections` | List P2P connections |
|
|
102
|
+
| `get_connection_stats` | Bandwidth and connection counts |
|
|
103
|
+
|
|
104
|
+
### Webhooks (Ramps)
|
|
105
|
+
| Tool | Description |
|
|
106
|
+
|------|-------------|
|
|
107
|
+
| `list_destinations` | List webhook destinations |
|
|
108
|
+
| `create_destination` | Create webhook destination |
|
|
109
|
+
| `list_events` | List webhook events |
|
|
110
|
+
|
|
111
|
+
### Resources
|
|
112
|
+
|
|
113
|
+
| URI | Description |
|
|
114
|
+
|-----|-------------|
|
|
115
|
+
| `anycast://agents` | All registered agents |
|
|
116
|
+
| `anycast://connections` | Recent connections (24h) |
|
|
117
|
+
| `anycast://stats` | Platform statistics |
|
|
118
|
+
|
|
119
|
+
## Examples
|
|
120
|
+
|
|
121
|
+
Ask Claude:
|
|
122
|
+
|
|
123
|
+
> "List all my online agents"
|
|
124
|
+
|
|
125
|
+
> "Create a registration token called 'production' with a limit of 50 uses"
|
|
126
|
+
|
|
127
|
+
> "Show me the connection stats for the last week"
|
|
128
|
+
|
|
129
|
+
> "Create a webhook destination at https://api.example.com/webhooks"
|
|
130
|
+
|
|
131
|
+
> "Which agents are in the 'production' group?"
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anycast Platform API client for the MCP server.
|
|
3
|
+
*/
|
|
4
|
+
export interface AnycastConfig {
|
|
5
|
+
apiUrl: string;
|
|
6
|
+
apiKey: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function loadConfig(): AnycastConfig;
|
|
9
|
+
export declare class AnycastClient {
|
|
10
|
+
private config;
|
|
11
|
+
constructor(config: AnycastConfig);
|
|
12
|
+
private request;
|
|
13
|
+
listAgents(params?: {
|
|
14
|
+
status?: string;
|
|
15
|
+
search?: string;
|
|
16
|
+
page?: number;
|
|
17
|
+
limit?: number;
|
|
18
|
+
}): Promise<unknown>;
|
|
19
|
+
getAgent(id: string): Promise<unknown>;
|
|
20
|
+
updateAgent(id: string, data: {
|
|
21
|
+
name?: string;
|
|
22
|
+
labels?: Record<string, string>;
|
|
23
|
+
}): Promise<unknown>;
|
|
24
|
+
deleteAgent(id: string): Promise<unknown>;
|
|
25
|
+
getAgentConnections(id: string, params?: {
|
|
26
|
+
status?: string;
|
|
27
|
+
page?: number;
|
|
28
|
+
}): Promise<unknown>;
|
|
29
|
+
listTokens(): Promise<unknown>;
|
|
30
|
+
createToken(data: {
|
|
31
|
+
name: string;
|
|
32
|
+
usageLimit?: number;
|
|
33
|
+
expiresAt?: string;
|
|
34
|
+
}): Promise<unknown>;
|
|
35
|
+
revokeToken(id: string): Promise<unknown>;
|
|
36
|
+
listGroups(): Promise<unknown>;
|
|
37
|
+
createGroup(data: {
|
|
38
|
+
name: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
}): Promise<unknown>;
|
|
41
|
+
addAgentToGroup(groupId: string, agentId: string): Promise<unknown>;
|
|
42
|
+
removeAgentFromGroup(groupId: string, agentId: string): Promise<unknown>;
|
|
43
|
+
getDiscovery(): Promise<unknown>;
|
|
44
|
+
listConnections(params?: {
|
|
45
|
+
status?: string;
|
|
46
|
+
type?: string;
|
|
47
|
+
days?: number;
|
|
48
|
+
page?: number;
|
|
49
|
+
}): Promise<unknown>;
|
|
50
|
+
getStats(): Promise<unknown>;
|
|
51
|
+
listDestinations(): Promise<unknown>;
|
|
52
|
+
createDestination(data: {
|
|
53
|
+
name?: string;
|
|
54
|
+
url: string;
|
|
55
|
+
maxRetries?: number;
|
|
56
|
+
}): Promise<unknown>;
|
|
57
|
+
listEvents(params?: {
|
|
58
|
+
status?: string;
|
|
59
|
+
provider?: string;
|
|
60
|
+
page?: number;
|
|
61
|
+
limit?: number;
|
|
62
|
+
}): Promise<unknown>;
|
|
63
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Anycast Platform API client for the MCP server.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AnycastClient = void 0;
|
|
7
|
+
exports.loadConfig = loadConfig;
|
|
8
|
+
function loadConfig() {
|
|
9
|
+
const apiKey = process.env.ANYCAST_API_KEY || '';
|
|
10
|
+
const apiUrl = process.env.ANYCAST_API_URL || 'http://localhost:3002';
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
console.error('Warning: ANYCAST_API_KEY not set');
|
|
13
|
+
}
|
|
14
|
+
return { apiUrl, apiKey };
|
|
15
|
+
}
|
|
16
|
+
class AnycastClient {
|
|
17
|
+
config;
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
}
|
|
21
|
+
async request(path, opts) {
|
|
22
|
+
const url = `${this.config.apiUrl}${path}`;
|
|
23
|
+
const res = await fetch(url, {
|
|
24
|
+
...opts,
|
|
25
|
+
headers: {
|
|
26
|
+
'Content-Type': 'application/json',
|
|
27
|
+
'x-api-key': this.config.apiKey,
|
|
28
|
+
...opts?.headers,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
const text = await res.text();
|
|
32
|
+
let data;
|
|
33
|
+
try {
|
|
34
|
+
data = JSON.parse(text);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
data = { raw: text };
|
|
38
|
+
}
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
const errMsg = data?.error || `HTTP ${res.status}`;
|
|
41
|
+
throw new Error(errMsg);
|
|
42
|
+
}
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
// Agents
|
|
46
|
+
async listAgents(params) {
|
|
47
|
+
const qs = new URLSearchParams();
|
|
48
|
+
if (params?.status)
|
|
49
|
+
qs.set('status', params.status);
|
|
50
|
+
if (params?.search)
|
|
51
|
+
qs.set('search', params.search);
|
|
52
|
+
if (params?.page)
|
|
53
|
+
qs.set('page', String(params.page));
|
|
54
|
+
if (params?.limit)
|
|
55
|
+
qs.set('limit', String(params.limit));
|
|
56
|
+
return this.request(`/api/agents?${qs}`);
|
|
57
|
+
}
|
|
58
|
+
async getAgent(id) {
|
|
59
|
+
return this.request(`/api/agents/${id}`);
|
|
60
|
+
}
|
|
61
|
+
async updateAgent(id, data) {
|
|
62
|
+
return this.request(`/api/agents/${id}`, { method: 'PATCH', body: JSON.stringify(data) });
|
|
63
|
+
}
|
|
64
|
+
async deleteAgent(id) {
|
|
65
|
+
return this.request(`/api/agents/${id}`, { method: 'DELETE' });
|
|
66
|
+
}
|
|
67
|
+
async getAgentConnections(id, params) {
|
|
68
|
+
const qs = new URLSearchParams();
|
|
69
|
+
if (params?.status)
|
|
70
|
+
qs.set('status', params.status);
|
|
71
|
+
if (params?.page)
|
|
72
|
+
qs.set('page', String(params.page));
|
|
73
|
+
return this.request(`/api/agents/${id}/connections?${qs}`);
|
|
74
|
+
}
|
|
75
|
+
// Tokens
|
|
76
|
+
async listTokens() {
|
|
77
|
+
return this.request('/api/agents/tokens');
|
|
78
|
+
}
|
|
79
|
+
async createToken(data) {
|
|
80
|
+
return this.request('/api/agents/tokens', { method: 'POST', body: JSON.stringify(data) });
|
|
81
|
+
}
|
|
82
|
+
async revokeToken(id) {
|
|
83
|
+
return this.request(`/api/agents/tokens/${id}`, { method: 'DELETE' });
|
|
84
|
+
}
|
|
85
|
+
// Groups
|
|
86
|
+
async listGroups() {
|
|
87
|
+
return this.request('/api/agents/groups');
|
|
88
|
+
}
|
|
89
|
+
async createGroup(data) {
|
|
90
|
+
return this.request('/api/agents/groups', { method: 'POST', body: JSON.stringify(data) });
|
|
91
|
+
}
|
|
92
|
+
async addAgentToGroup(groupId, agentId) {
|
|
93
|
+
return this.request(`/api/agents/groups/${groupId}/members`, {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
body: JSON.stringify({ agentIds: [agentId] }),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async removeAgentFromGroup(groupId, agentId) {
|
|
99
|
+
return this.request(`/api/agents/groups/${groupId}/members`, {
|
|
100
|
+
method: 'DELETE',
|
|
101
|
+
body: JSON.stringify({ agentId }),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Discovery
|
|
105
|
+
async getDiscovery() {
|
|
106
|
+
// Public endpoint, no auth needed
|
|
107
|
+
const url = `${this.config.apiUrl}/api/agents/discover`;
|
|
108
|
+
const res = await fetch(url);
|
|
109
|
+
return res.json();
|
|
110
|
+
}
|
|
111
|
+
// Connections
|
|
112
|
+
async listConnections(params) {
|
|
113
|
+
const qs = new URLSearchParams();
|
|
114
|
+
if (params?.status)
|
|
115
|
+
qs.set('status', params.status);
|
|
116
|
+
if (params?.type)
|
|
117
|
+
qs.set('type', params.type);
|
|
118
|
+
if (params?.days)
|
|
119
|
+
qs.set('days', String(params.days));
|
|
120
|
+
if (params?.page)
|
|
121
|
+
qs.set('page', String(params.page));
|
|
122
|
+
return this.request(`/api/agents/connections?${qs}`);
|
|
123
|
+
}
|
|
124
|
+
async getStats() {
|
|
125
|
+
return this.request('/api/agents/stats');
|
|
126
|
+
}
|
|
127
|
+
// Destinations (Ramps)
|
|
128
|
+
async listDestinations() {
|
|
129
|
+
return this.request('/api/destinations');
|
|
130
|
+
}
|
|
131
|
+
async createDestination(data) {
|
|
132
|
+
return this.request('/api/destinations', { method: 'POST', body: JSON.stringify(data) });
|
|
133
|
+
}
|
|
134
|
+
// Events
|
|
135
|
+
async listEvents(params) {
|
|
136
|
+
const qs = new URLSearchParams();
|
|
137
|
+
if (params?.status)
|
|
138
|
+
qs.set('status', params.status);
|
|
139
|
+
if (params?.provider)
|
|
140
|
+
qs.set('provider', params.provider);
|
|
141
|
+
if (params?.page)
|
|
142
|
+
qs.set('page', String(params.page));
|
|
143
|
+
if (params?.limit)
|
|
144
|
+
qs.set('limit', String(params.limit));
|
|
145
|
+
return this.request(`/api/events?${qs}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.AnycastClient = AnycastClient;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* @anycast/mcp — MCP server for the Anycast Platform
|
|
5
|
+
*
|
|
6
|
+
* Enables AI assistants (Claude, Cursor, etc.) to manage agents,
|
|
7
|
+
* webhooks, and connectivity on the Anycast Edge Platform.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
11
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
12
|
+
const zod_1 = require("zod");
|
|
13
|
+
const client_js_1 = require("./client.js");
|
|
14
|
+
const config = (0, client_js_1.loadConfig)();
|
|
15
|
+
const client = new client_js_1.AnycastClient(config);
|
|
16
|
+
const server = new mcp_js_1.McpServer({
|
|
17
|
+
name: 'anycast',
|
|
18
|
+
version: '0.1.0',
|
|
19
|
+
});
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Tools — Agents
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
server.tool('list_agents', 'List all registered agents with their status, IP, and version', { status: zod_1.z.enum(['ONLINE', 'OFFLINE', 'CONNECTING']).optional().describe('Filter by agent status'), search: zod_1.z.string().optional().describe('Search by agent name'), limit: zod_1.z.number().optional().describe('Max results (default 20)') }, async ({ status, search, limit }) => {
|
|
24
|
+
const data = await client.listAgents({ status, search, limit });
|
|
25
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
26
|
+
});
|
|
27
|
+
server.tool('get_agent', 'Get details for a specific agent including groups, connections, and labels', { id: zod_1.z.string().describe('Agent ID') }, async ({ id }) => {
|
|
28
|
+
const data = await client.getAgent(id);
|
|
29
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
30
|
+
});
|
|
31
|
+
server.tool('update_agent', 'Update an agent name or labels', { id: zod_1.z.string().describe('Agent ID'), name: zod_1.z.string().optional().describe('New name'), labels: zod_1.z.record(zod_1.z.string()).optional().describe('Key-value labels') }, async ({ id, name, labels }) => {
|
|
32
|
+
const data = await client.updateAgent(id, { name, labels });
|
|
33
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
34
|
+
});
|
|
35
|
+
server.tool('delete_agent', 'Delete an agent — disconnects active connections and removes from all groups', { id: zod_1.z.string().describe('Agent ID to delete') }, async ({ id }) => {
|
|
36
|
+
const data = await client.deleteAgent(id);
|
|
37
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
38
|
+
});
|
|
39
|
+
server.tool('get_agent_connections', 'Get connection history for a specific agent', { id: zod_1.z.string().describe('Agent ID'), status: zod_1.z.enum(['PENDING', 'CONNECTED', 'DISCONNECTED', 'FAILED']).optional() }, async ({ id, status }) => {
|
|
40
|
+
const data = await client.getAgentConnections(id, { status });
|
|
41
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
42
|
+
});
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// Tools — Tokens
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
server.tool('list_tokens', 'List all agent registration tokens (prefixes only, not full tokens)', {}, async () => {
|
|
47
|
+
const data = await client.listTokens();
|
|
48
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
49
|
+
});
|
|
50
|
+
server.tool('create_token', 'Create a new agent registration token — the full token is shown only once', { name: zod_1.z.string().describe('Token name'), usageLimit: zod_1.z.number().optional().describe('Max number of agents that can register with this token'), expiresAt: zod_1.z.string().optional().describe('ISO 8601 expiry date') }, async ({ name, usageLimit, expiresAt }) => {
|
|
51
|
+
const data = await client.createToken({ name, usageLimit, expiresAt });
|
|
52
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
53
|
+
});
|
|
54
|
+
server.tool('revoke_token', 'Revoke an agent registration token — agents already registered are not affected', { id: zod_1.z.string().describe('Token ID to revoke') }, async ({ id }) => {
|
|
55
|
+
const data = await client.revokeToken(id);
|
|
56
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
57
|
+
});
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Tools — Groups
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
server.tool('list_groups', 'List agent groups with member and policy counts', {}, async () => {
|
|
62
|
+
const data = await client.listGroups();
|
|
63
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
64
|
+
});
|
|
65
|
+
server.tool('create_group', 'Create a new agent group for organizing agents and applying policies', { name: zod_1.z.string().describe('Group name'), description: zod_1.z.string().optional().describe('Group description') }, async ({ name, description }) => {
|
|
66
|
+
const data = await client.createGroup({ name, description });
|
|
67
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
68
|
+
});
|
|
69
|
+
server.tool('add_agent_to_group', 'Add an agent to a group', { groupId: zod_1.z.string().describe('Group ID'), agentId: zod_1.z.string().describe('Agent ID to add') }, async ({ groupId, agentId }) => {
|
|
70
|
+
const data = await client.addAgentToGroup(groupId, agentId);
|
|
71
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
72
|
+
});
|
|
73
|
+
server.tool('remove_agent_from_group', 'Remove an agent from a group', { groupId: zod_1.z.string().describe('Group ID'), agentId: zod_1.z.string().describe('Agent ID to remove') }, async ({ groupId, agentId }) => {
|
|
74
|
+
const data = await client.removeAgentFromGroup(groupId, agentId);
|
|
75
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
76
|
+
});
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// Tools — Connectivity
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
server.tool('get_discovery', 'Get the rendezvous server URL for agent connections (public, no auth needed)', {}, async () => {
|
|
81
|
+
const data = await client.getDiscovery();
|
|
82
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
83
|
+
});
|
|
84
|
+
server.tool('list_connections', 'List P2P connections between agents', { status: zod_1.z.enum(['PENDING', 'CONNECTED', 'DISCONNECTED', 'FAILED']).optional(), type: zod_1.z.enum(['DIRECT', 'RELAYED']).optional(), days: zod_1.z.number().optional().describe('Lookback window in days (default 7)') }, async ({ status, type, days }) => {
|
|
85
|
+
const data = await client.listConnections({ status, type, days });
|
|
86
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
87
|
+
});
|
|
88
|
+
server.tool('get_connection_stats', 'Get agent and connection statistics — online counts, bandwidth, totals', {}, async () => {
|
|
89
|
+
const data = await client.getStats();
|
|
90
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
91
|
+
});
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Tools — Ramps (webhook delivery)
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
server.tool('list_destinations', 'List webhook delivery destinations with retry config and alert settings', {}, async () => {
|
|
96
|
+
const data = await client.listDestinations();
|
|
97
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
98
|
+
});
|
|
99
|
+
server.tool('create_destination', 'Create a new webhook delivery destination', { url: zod_1.z.string().describe('Webhook endpoint URL'), name: zod_1.z.string().optional().describe('Display name'), maxRetries: zod_1.z.number().optional().describe('Max retry attempts (0-10)') }, async ({ url, name, maxRetries }) => {
|
|
100
|
+
const data = await client.createDestination({ url, name, maxRetries });
|
|
101
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
102
|
+
});
|
|
103
|
+
server.tool('list_events', 'List webhook events with filtering by status, provider, and time', { status: zod_1.z.enum(['RECEIVED', 'PROCESSING', 'DELIVERED', 'FAILED', 'RETRYING', 'DEAD']).optional(), provider: zod_1.z.string().optional().describe('Filter by provider (moonpay, transak, etc.)'), limit: zod_1.z.number().optional().describe('Max results') }, async ({ status, provider, limit }) => {
|
|
104
|
+
const data = await client.listEvents({ status, provider, limit });
|
|
105
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
106
|
+
});
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Resources
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
server.resource('agents', 'anycast://agents', async (uri) => {
|
|
111
|
+
const data = await client.listAgents({ limit: 100 });
|
|
112
|
+
return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(data, null, 2) }] };
|
|
113
|
+
});
|
|
114
|
+
server.resource('connections', 'anycast://connections', async (uri) => {
|
|
115
|
+
const data = await client.listConnections({ days: 1 });
|
|
116
|
+
return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(data, null, 2) }] };
|
|
117
|
+
});
|
|
118
|
+
server.resource('stats', 'anycast://stats', async (uri) => {
|
|
119
|
+
const data = await client.getStats();
|
|
120
|
+
return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(data, null, 2) }] };
|
|
121
|
+
});
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Start
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
async function main() {
|
|
126
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
127
|
+
await server.connect(transport);
|
|
128
|
+
}
|
|
129
|
+
main().catch((err) => {
|
|
130
|
+
console.error('MCP server error:', err);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@anycast/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for the Anycast Platform — enables AI assistants to manage agents, webhooks, and connectivity",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"anycast-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsx watch src/index.ts",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^20.11.0",
|
|
22
|
+
"tsx": "^4.7.0",
|
|
23
|
+
"typescript": "^5.3.3",
|
|
24
|
+
"vitest": "^4.0.18"
|
|
25
|
+
},
|
|
26
|
+
"files": ["dist"],
|
|
27
|
+
"keywords": ["mcp", "anycast", "ai", "agents", "claude", "cursor"],
|
|
28
|
+
"license": "MIT"
|
|
29
|
+
}
|