Skip to content

Commit abe387c

Browse files
Copilot0xrinegade
andcommitted
Implement MCP Server API for web service capability
Co-authored-by: 0xrinegade <[email protected]>
1 parent 7ea76ba commit abe387c

File tree

7 files changed

+687
-20
lines changed

7 files changed

+687
-20
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ reqwest = { version = "0.11", features = ["json"] }
3030
prometheus = "0.13"
3131
axum = "0.7"
3232
tower = "0.5"
33+
clap = { version = "4.0", features = ["derive"] }

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,33 @@
22

33
A Model Context Protocol (MCP) server that provides comprehensive access to Solana blockchain data through Cline. This server implements a wide range of Solana RPC methods, making it easy to query blockchain information directly through natural language conversations.
44

5+
## 🚀 Usage Modes
6+
7+
The Solana MCP Server supports two modes of operation:
8+
9+
### 📡 Stdio Mode (Default)
10+
For integration with Claude Desktop and other MCP clients:
11+
```bash
12+
solana-mcp-server stdio # or just: solana-mcp-server
13+
```
14+
15+
### 🌐 Web Service Mode
16+
For HTTP API access and integration with web applications:
17+
```bash
18+
# Run on default port 3000
19+
solana-mcp-server web
20+
21+
# Run on custom port
22+
solana-mcp-server web --port 8080
23+
```
24+
25+
**Web Service Endpoints:**
26+
- `POST /api/mcp` - MCP JSON-RPC API
27+
- `GET /health` - Health check
28+
- `GET /metrics` - Prometheus metrics
29+
30+
📖 **[Complete Web Service Documentation](./docs/web-service.md)**
31+
532
## Installation
633

734
### Using Pre-built Binaries

docs/web-service.md

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
# Solana MCP Server - Web Service Mode
2+
3+
The Solana MCP Server can run in web service mode, providing HTTP endpoints for MCP JSON-RPC communication alongside the traditional stdio transport.
4+
5+
## Running as Web Service
6+
7+
### Basic Usage
8+
9+
```bash
10+
# Run on default port 3000
11+
solana-mcp-server web
12+
13+
# Run on custom port
14+
solana-mcp-server web --port 8000
15+
```
16+
17+
### Available Endpoints
18+
19+
When running in web service mode, the server provides:
20+
21+
#### POST /api/mcp
22+
- **Purpose**: MCP JSON-RPC API endpoint
23+
- **Content-Type**: `application/json`
24+
- **Description**: Accepts MCP JSON-RPC requests and returns responses
25+
26+
#### GET /health
27+
- **Purpose**: Health check endpoint
28+
- **Response**: `{"status":"ok","service":"solana-mcp-server"}`
29+
- **Description**: Returns server health status
30+
31+
#### GET /metrics
32+
- **Purpose**: Prometheus metrics endpoint
33+
- **Content-Type**: `text/plain; version=0.0.4`
34+
- **Description**: Exposes Prometheus-format metrics for monitoring
35+
36+
## API Usage Examples
37+
38+
### Initialize MCP Session
39+
40+
```bash
41+
curl -X POST http://localhost:3000/api/mcp \
42+
-H "Content-Type: application/json" \
43+
-d '{
44+
"jsonrpc": "2.0",
45+
"id": 1,
46+
"method": "initialize",
47+
"params": {
48+
"protocolVersion": "2024-11-05",
49+
"capabilities": {},
50+
"clientInfo": {
51+
"name": "my-client",
52+
"version": "1.0.0"
53+
}
54+
}
55+
}'
56+
```
57+
58+
### List Available Tools
59+
60+
```bash
61+
curl -X POST http://localhost:3000/api/mcp \
62+
-H "Content-Type: application/json" \
63+
-d '{
64+
"jsonrpc": "2.0",
65+
"id": 2,
66+
"method": "tools/list",
67+
"params": {}
68+
}'
69+
```
70+
71+
### Call a Tool (Get Account Balance)
72+
73+
```bash
74+
curl -X POST http://localhost:3000/api/mcp \
75+
-H "Content-Type: application/json" \
76+
-d '{
77+
"jsonrpc": "2.0",
78+
"id": 3,
79+
"method": "tools/call",
80+
"params": {
81+
"name": "getBalance",
82+
"arguments": {
83+
"pubkey": "11111111111111111111111111111112"
84+
}
85+
}
86+
}'
87+
```
88+
89+
## Differences from Stdio Mode
90+
91+
### Initialization
92+
- In stdio mode, the server waits for an `initialize` request
93+
- In web service mode, the server is automatically initialized and ready to accept requests
94+
95+
### Session Management
96+
- Stdio mode maintains a single persistent session
97+
- Web service mode handles stateless HTTP requests (each request is independent)
98+
99+
### Error Handling
100+
- Stdio mode can terminate on critical errors
101+
- Web service mode returns HTTP error codes and continues serving requests
102+
103+
## Integration Examples
104+
105+
### Using with curl
106+
107+
```bash
108+
#!/bin/bash
109+
# Simple script to get account info via web API
110+
111+
ACCOUNT_PUBKEY="$1"
112+
SERVER_URL="http://localhost:3000/api/mcp"
113+
114+
curl -X POST "$SERVER_URL" \
115+
-H "Content-Type: application/json" \
116+
-d "{
117+
\"jsonrpc\": \"2.0\",
118+
\"id\": 1,
119+
\"method\": \"tools/call\",
120+
\"params\": {
121+
\"name\": \"getAccountInfo\",
122+
\"arguments\": {
123+
\"pubkey\": \"$ACCOUNT_PUBKEY\"
124+
}
125+
}
126+
}" | jq .
127+
```
128+
129+
### Using with Python
130+
131+
```python
132+
import requests
133+
import json
134+
135+
class SolanaMcpClient:
136+
def __init__(self, base_url="http://localhost:3000"):
137+
self.base_url = base_url
138+
self.api_url = f"{base_url}/api/mcp"
139+
self.request_id = 0
140+
141+
def call_tool(self, tool_name, arguments=None):
142+
self.request_id += 1
143+
payload = {
144+
"jsonrpc": "2.0",
145+
"id": self.request_id,
146+
"method": "tools/call",
147+
"params": {
148+
"name": tool_name,
149+
"arguments": arguments or {}
150+
}
151+
}
152+
153+
response = requests.post(
154+
self.api_url,
155+
headers={"Content-Type": "application/json"},
156+
json=payload
157+
)
158+
159+
return response.json()
160+
161+
def get_balance(self, pubkey):
162+
return self.call_tool("getBalance", {"pubkey": pubkey})
163+
164+
def get_health(self):
165+
response = requests.get(f"{self.base_url}/health")
166+
return response.json()
167+
168+
# Usage
169+
client = SolanaMcpClient()
170+
balance = client.get_balance("11111111111111111111111111111112")
171+
print(json.dumps(balance, indent=2))
172+
```
173+
174+
### Using with JavaScript/Node.js
175+
176+
```javascript
177+
class SolanaMcpClient {
178+
constructor(baseUrl = 'http://localhost:3000') {
179+
this.baseUrl = baseUrl;
180+
this.apiUrl = `${baseUrl}/api/mcp`;
181+
this.requestId = 0;
182+
}
183+
184+
async callTool(toolName, arguments = {}) {
185+
this.requestId++;
186+
const payload = {
187+
jsonrpc: '2.0',
188+
id: this.requestId,
189+
method: 'tools/call',
190+
params: {
191+
name: toolName,
192+
arguments: arguments
193+
}
194+
};
195+
196+
const response = await fetch(this.apiUrl, {
197+
method: 'POST',
198+
headers: {
199+
'Content-Type': 'application/json'
200+
},
201+
body: JSON.stringify(payload)
202+
});
203+
204+
return await response.json();
205+
}
206+
207+
async getBalance(pubkey) {
208+
return await this.callTool('getBalance', { pubkey });
209+
}
210+
211+
async getHealth() {
212+
const response = await fetch(`${this.baseUrl}/health`);
213+
return await response.json();
214+
}
215+
}
216+
217+
// Usage
218+
const client = new SolanaMcpClient();
219+
client.getBalance('11111111111111111111111111111112')
220+
.then(result => console.log(JSON.stringify(result, null, 2)));
221+
```
222+
223+
## Monitoring and Observability
224+
225+
### Health Checks
226+
Use the `/health` endpoint for liveness and readiness probes:
227+
228+
```bash
229+
# Simple health check
230+
curl -f http://localhost:3000/health
231+
232+
# In Kubernetes
233+
livenessProbe:
234+
httpGet:
235+
path: /health
236+
port: 3000
237+
initialDelaySeconds: 30
238+
periodSeconds: 10
239+
```
240+
241+
### Metrics Collection
242+
The `/metrics` endpoint provides Prometheus-compatible metrics:
243+
244+
```bash
245+
# View metrics
246+
curl http://localhost:3000/metrics
247+
248+
# Prometheus scrape config
249+
scrape_configs:
250+
- job_name: 'solana-mcp-server'
251+
static_configs:
252+
- targets: ['localhost:3000']
253+
metrics_path: '/metrics'
254+
```
255+
256+
## Production Deployment
257+
258+
### Docker Compose Example
259+
260+
```yaml
261+
version: '3.8'
262+
services:
263+
solana-mcp-server:
264+
image: solana-mcp-server:latest
265+
command: ["web", "--port", "3000"]
266+
ports:
267+
- "3000:3000"
268+
environment:
269+
- RUST_LOG=info
270+
volumes:
271+
- ./config.json:/app/config.json:ro
272+
healthcheck:
273+
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
274+
interval: 30s
275+
timeout: 10s
276+
retries: 3
277+
```
278+
279+
### Kubernetes Deployment
280+
281+
```yaml
282+
apiVersion: apps/v1
283+
kind: Deployment
284+
metadata:
285+
name: solana-mcp-server
286+
spec:
287+
replicas: 3
288+
selector:
289+
matchLabels:
290+
app: solana-mcp-server
291+
template:
292+
metadata:
293+
labels:
294+
app: solana-mcp-server
295+
spec:
296+
containers:
297+
- name: solana-mcp-server
298+
image: solana-mcp-server:latest
299+
args: ["web", "--port", "3000"]
300+
ports:
301+
- containerPort: 3000
302+
livenessProbe:
303+
httpGet:
304+
path: /health
305+
port: 3000
306+
initialDelaySeconds: 30
307+
periodSeconds: 10
308+
readinessProbe:
309+
httpGet:
310+
path: /health
311+
port: 3000
312+
initialDelaySeconds: 5
313+
periodSeconds: 5
314+
resources:
315+
requests:
316+
memory: "512Mi"
317+
cpu: "250m"
318+
limits:
319+
memory: "1Gi"
320+
cpu: "500m"
321+
322+
---
323+
apiVersion: v1
324+
kind: Service
325+
metadata:
326+
name: solana-mcp-server-service
327+
spec:
328+
selector:
329+
app: solana-mcp-server
330+
ports:
331+
- port: 80
332+
targetPort: 3000
333+
type: LoadBalancer
334+
```
335+
336+
## Security Considerations
337+
338+
- The web service mode exposes the MCP server over HTTP
339+
- Consider implementing authentication/authorization for production use
340+
- Use HTTPS in production environments
341+
- Configure appropriate CORS headers if needed for browser access
342+
- Monitor and rate-limit API usage to prevent abuse
343+
344+
## Limitations
345+
346+
- Web service mode does not support streaming or persistent connections
347+
- Each HTTP request is independent (no session state)
348+
- Large responses may be subject to HTTP timeout limits
349+
- No built-in authentication (implement at reverse proxy level)

0 commit comments

Comments
 (0)