mcp-http-webhook 1.0.29 β 1.0.30
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/package.json +1 -5
- package/ARCHITECTURE.md +0 -269
- package/BLOG_POST.md +0 -738
- package/COMPLETION_IMPLEMENTATION.md +0 -280
- package/CONTRIBUTING.md +0 -136
- package/GETTING_STARTED.md +0 -310
- package/IMPLEMENTATION.md +0 -294
- package/MIGRATION_TO_SDK.md +0 -263
- package/PAGINATION_IMPLEMENTATION.md +0 -221
- package/SDK_INTEGRATION_COMPLETE.md +0 -300
- package/STANDARD_SUBSCRIPTIONS.md +0 -268
- package/STANDARD_SUBSCRIPTIONS_COMPLETE.md +0 -309
- package/SUMMARY.md +0 -272
- package/examples/GITHUB_LIVE_EXAMPLE.md +0 -308
- package/examples/GITHUB_LIVE_SETUP.md +0 -253
- package/examples/QUICKSTART.md +0 -130
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
# Standard MCP Subscriptions with Webhook Support
|
|
2
|
-
|
|
3
|
-
This library now supports **standard MCP `resources/subscribe`** with webhook callbacks, eliminating the need for custom endpoints!
|
|
4
|
-
|
|
5
|
-
## π― Two Ways to Subscribe
|
|
6
|
-
|
|
7
|
-
### Method 1: Standard MCP Subscribe (Recommended) β
|
|
8
|
-
|
|
9
|
-
Use the standard `resources/subscribe` method with webhook URL in `_meta`:
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
curl -X POST http://localhost:3000/mcp \
|
|
13
|
-
-H "Content-Type: application/json" \
|
|
14
|
-
-d '{
|
|
15
|
-
"jsonrpc": "2.0",
|
|
16
|
-
"id": 1,
|
|
17
|
-
"method": "resources/subscribe",
|
|
18
|
-
"params": {
|
|
19
|
-
"uri": "github://repo/owner/repo/issues",
|
|
20
|
-
"_meta": {
|
|
21
|
-
"webhookUrl": "https://your-app.com/webhooks/mcp",
|
|
22
|
-
"webhookSecret": "your-secret-123"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}'
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**Response:**
|
|
29
|
-
```json
|
|
30
|
-
{
|
|
31
|
-
"jsonrpc": "2.0",
|
|
32
|
-
"id": 1,
|
|
33
|
-
"result": {
|
|
34
|
-
"subscriptionId": "sub_abc123xyz",
|
|
35
|
-
"_meta": {
|
|
36
|
-
"subscriptionId": "sub_abc123xyz",
|
|
37
|
-
"webhookEnabled": true
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Method 2: Legacy Custom Endpoint (Still Supported)
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
curl -X POST http://localhost:3000/mcp/resources/subscribe \
|
|
47
|
-
-H "Content-Type: application/json" \
|
|
48
|
-
-d '{
|
|
49
|
-
"uri": "github://repo/owner/repo/issues",
|
|
50
|
-
"callbackUrl": "https://your-app.com/webhooks/mcp",
|
|
51
|
-
"callbackSecret": "your-secret-123"
|
|
52
|
-
}'
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## π¬ Webhook Notifications (Standard MCP Format)
|
|
56
|
-
|
|
57
|
-
When a resource changes, your webhook URL receives a **standard MCP notification**:
|
|
58
|
-
|
|
59
|
-
```json
|
|
60
|
-
{
|
|
61
|
-
"jsonrpc": "2.0",
|
|
62
|
-
"method": "notifications/resources/updated",
|
|
63
|
-
"params": {
|
|
64
|
-
"uri": "github://repo/owner/repo/issues",
|
|
65
|
-
"title": "Repository Issues Updated",
|
|
66
|
-
"_meta": {
|
|
67
|
-
"changeType": "created",
|
|
68
|
-
"subscriptionId": "sub_abc123xyz",
|
|
69
|
-
"timestamp": "2025-10-14T13:30:00Z",
|
|
70
|
-
"issue": {
|
|
71
|
-
"number": 42,
|
|
72
|
-
"title": "New feature request",
|
|
73
|
-
"state": "open"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## π Full Workflow Example
|
|
81
|
-
|
|
82
|
-
### 1. Subscribe to Resource
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
// Using standard MCP client
|
|
86
|
-
const response = await mcpClient.request({
|
|
87
|
-
method: 'resources/subscribe',
|
|
88
|
-
params: {
|
|
89
|
-
uri: 'github://repo/surajbhan/test/issues',
|
|
90
|
-
_meta: {
|
|
91
|
-
webhookUrl: 'https://my-app.com/mcp/notifications',
|
|
92
|
-
webhookSecret: 'my-secret-key'
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
console.log('Subscription ID:', response._meta.subscriptionId);
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### 2. Receive Notifications
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// Your webhook endpoint
|
|
104
|
-
app.post('/mcp/notifications', (req, res) => {
|
|
105
|
-
const notification = req.body;
|
|
106
|
-
|
|
107
|
-
if (notification.method === 'notifications/resources/updated') {
|
|
108
|
-
const { uri, title, _meta } = notification.params;
|
|
109
|
-
|
|
110
|
-
console.log('Resource updated:', uri);
|
|
111
|
-
console.log('Change type:', _meta.changeType); // 'created', 'updated', or 'deleted'
|
|
112
|
-
console.log('Details:', _meta);
|
|
113
|
-
|
|
114
|
-
// Handle the update
|
|
115
|
-
handleResourceUpdate(uri, _meta);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
res.status(200).send('OK');
|
|
119
|
-
});
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### 3. Unsubscribe
|
|
123
|
-
|
|
124
|
-
```typescript
|
|
125
|
-
// Standard MCP unsubscribe
|
|
126
|
-
await mcpClient.request({
|
|
127
|
-
method: 'resources/unsubscribe',
|
|
128
|
-
params: {
|
|
129
|
-
uri: 'github://repo/surajbhan/test/issues',
|
|
130
|
-
_meta: {
|
|
131
|
-
subscriptionId: 'sub_abc123xyz'
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## π Webhook Security
|
|
138
|
-
|
|
139
|
-
### Signature Verification
|
|
140
|
-
|
|
141
|
-
All webhook notifications include a signature header for verification:
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
import crypto from 'crypto';
|
|
145
|
-
|
|
146
|
-
function verifyWebhookSignature(
|
|
147
|
-
payload: any,
|
|
148
|
-
signature: string,
|
|
149
|
-
secret: string
|
|
150
|
-
): boolean {
|
|
151
|
-
const hmac = crypto.createHmac('sha256', secret);
|
|
152
|
-
hmac.update(JSON.stringify(payload));
|
|
153
|
-
const expected = `sha256=${hmac.digest('hex')}`;
|
|
154
|
-
|
|
155
|
-
return crypto.timingSafeEqual(
|
|
156
|
-
Buffer.from(signature),
|
|
157
|
-
Buffer.from(expected)
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// In your webhook handler
|
|
162
|
-
app.post('/mcp/notifications', (req, res) => {
|
|
163
|
-
const signature = req.headers['x-webhook-signature'];
|
|
164
|
-
const isValid = verifyWebhookSignature(
|
|
165
|
-
req.body,
|
|
166
|
-
signature,
|
|
167
|
-
'my-secret-key'
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
if (!isValid) {
|
|
171
|
-
return res.status(401).send('Invalid signature');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Process notification...
|
|
175
|
-
});
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## π¨ MCP Inspector Integration
|
|
179
|
-
|
|
180
|
-
The standard subscribe method works seamlessly with MCP Inspector:
|
|
181
|
-
|
|
182
|
-
1. Open MCP Inspector: `npx @modelcontextprotocol/inspector http://localhost:3000/mcp`
|
|
183
|
-
2. List resources
|
|
184
|
-
3. Click "Subscribe" on a resource
|
|
185
|
-
4. **NEW**: Inspector can pass webhook URL via `_meta`
|
|
186
|
-
|
|
187
|
-
## π Comparison
|
|
188
|
-
|
|
189
|
-
| Feature | Standard MCP Subscribe | Legacy Endpoint |
|
|
190
|
-
|---------|----------------------|-----------------|
|
|
191
|
-
| **Endpoint** | `POST /mcp` | `POST /mcp/resources/subscribe` |
|
|
192
|
-
| **Method** | `resources/subscribe` | N/A (direct POST) |
|
|
193
|
-
| **Webhook URL** | `params._meta.webhookUrl` | `params.callbackUrl` |
|
|
194
|
-
| **MCP Compliant** | β
Yes | β No (custom extension) |
|
|
195
|
-
| **Inspector Compatible** | β
Yes | β οΈ Partial |
|
|
196
|
-
| **Notification Format** | `notifications/resources/updated` | Custom |
|
|
197
|
-
| **Recommended** | β
**Use this** | β οΈ Legacy support |
|
|
198
|
-
|
|
199
|
-
## π Quick Start
|
|
200
|
-
|
|
201
|
-
### For MCP Clients
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
205
|
-
|
|
206
|
-
const client = new Client({
|
|
207
|
-
name: 'my-app',
|
|
208
|
-
version: '1.0.0'
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
// Connect to MCP server
|
|
212
|
-
await client.connect(transport);
|
|
213
|
-
|
|
214
|
-
// Subscribe with webhook
|
|
215
|
-
const subscription = await client.request({
|
|
216
|
-
method: 'resources/subscribe',
|
|
217
|
-
params: {
|
|
218
|
-
uri: 'github://repo/owner/repo/issues',
|
|
219
|
-
_meta: {
|
|
220
|
-
webhookUrl: 'https://my-app.com/webhooks/mcp',
|
|
221
|
-
webhookSecret: 'secret123'
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
console.log('Subscribed:', subscription._meta.subscriptionId);
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### For HTTP Clients
|
|
230
|
-
|
|
231
|
-
```bash
|
|
232
|
-
# Subscribe
|
|
233
|
-
curl -X POST http://localhost:3000/mcp \
|
|
234
|
-
-H "Content-Type: application/json" \
|
|
235
|
-
-d '{
|
|
236
|
-
"jsonrpc": "2.0",
|
|
237
|
-
"id": 1,
|
|
238
|
-
"method": "resources/subscribe",
|
|
239
|
-
"params": {
|
|
240
|
-
"uri": "github://repo/owner/repo/issues",
|
|
241
|
-
"_meta": {
|
|
242
|
-
"webhookUrl": "https://webhook.site/your-unique-url",
|
|
243
|
-
"webhookSecret": "test123"
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}'
|
|
247
|
-
|
|
248
|
-
# Watch webhook.site for notifications!
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## π― Benefits
|
|
252
|
-
|
|
253
|
-
1. **β
Standard Compliant**: Works with all MCP clients
|
|
254
|
-
2. **π Universal**: No custom endpoints needed
|
|
255
|
-
3. **π‘ Webhook-based**: No SSE connection required
|
|
256
|
-
4. **π Secure**: Built-in signature verification
|
|
257
|
-
5. **π¨ Inspector Ready**: Full MCP Inspector support
|
|
258
|
-
6. **π Spec Aligned**: Follows MCP 2025-06-18 specification
|
|
259
|
-
|
|
260
|
-
## π Learn More
|
|
261
|
-
|
|
262
|
-
- **MCP Spec**: https://modelcontextprotocol.io/specification/2025-06-18/server/resources#subscriptions
|
|
263
|
-
- **Full Example**: See `examples/github-server-live.ts`
|
|
264
|
-
- **Architecture**: See `ARCHITECTURE.md`
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
|
-
**π Now you have standard MCP subscriptions with webhook support!**
|
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
# β
Standard MCP Subscriptions Implementation Complete
|
|
2
|
-
|
|
3
|
-
## π― What Was Implemented
|
|
4
|
-
|
|
5
|
-
Successfully integrated **standard MCP `resources/subscribe`** with webhook callback support, making the library fully MCP-compliant while preserving all webhook functionality.
|
|
6
|
-
|
|
7
|
-
## π How It Works
|
|
8
|
-
|
|
9
|
-
### Before (Custom Endpoint)
|
|
10
|
-
```bash
|
|
11
|
-
POST /mcp/resources/subscribe
|
|
12
|
-
{
|
|
13
|
-
"uri": "github://repo/owner/repo/issues",
|
|
14
|
-
"callbackUrl": "https://client.com/webhook",
|
|
15
|
-
"callbackSecret": "secret"
|
|
16
|
-
}
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### After (Standard MCP) β
|
|
20
|
-
```bash
|
|
21
|
-
POST /mcp
|
|
22
|
-
{
|
|
23
|
-
"jsonrpc": "2.0",
|
|
24
|
-
"method": "resources/subscribe",
|
|
25
|
-
"params": {
|
|
26
|
-
"uri": "github://repo/owner/repo/issues",
|
|
27
|
-
"_meta": {
|
|
28
|
-
"webhookUrl": "https://client.com/webhook",
|
|
29
|
-
"webhookSecret": "secret"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## π Key Changes
|
|
36
|
-
|
|
37
|
-
### 1. Server Intercepts Standard MCP Subscribe
|
|
38
|
-
|
|
39
|
-
In `src/server.ts`, the main `/mcp` endpoint now intercepts `resources/subscribe`:
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
// Intercept resources/subscribe to support webhook callbacks
|
|
43
|
-
if (req.body.method === 'resources/subscribe') {
|
|
44
|
-
const webhookUrl = req.body.params?._meta?.webhookUrl;
|
|
45
|
-
|
|
46
|
-
if (webhookUrl) {
|
|
47
|
-
// Handle webhook-based subscription
|
|
48
|
-
const result = await subscriptionManager.createSubscription({
|
|
49
|
-
uri,
|
|
50
|
-
clientCallbackUrl: webhookUrl,
|
|
51
|
-
clientCallbackSecret: webhookSecret,
|
|
52
|
-
context,
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// Return standard MCP response
|
|
56
|
-
return res.json({
|
|
57
|
-
jsonrpc: '2.0',
|
|
58
|
-
id: req.body.id,
|
|
59
|
-
result: {
|
|
60
|
-
...result,
|
|
61
|
-
_meta: { subscriptionId: result.subscriptionId, webhookEnabled: true }
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### 2. Standard MCP Notification Format
|
|
69
|
-
|
|
70
|
-
Updated `src/webhooks/WebhookManager.ts` to send notifications in standard MCP format:
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
// Standard MCP notification
|
|
74
|
-
const payload = {
|
|
75
|
-
jsonrpc: '2.0',
|
|
76
|
-
method: 'notifications/resources/updated',
|
|
77
|
-
params: {
|
|
78
|
-
uri: changeInfo.resourceUri,
|
|
79
|
-
title: changeInfo.data?.title,
|
|
80
|
-
_meta: {
|
|
81
|
-
changeType: changeInfo.changeType,
|
|
82
|
-
subscriptionId: subscription.uri,
|
|
83
|
-
timestamp: new Date().toISOString(),
|
|
84
|
-
...changeInfo.data
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### 3. Both Methods Supported
|
|
91
|
-
|
|
92
|
-
- β
**Standard MCP**: `POST /mcp` with `resources/subscribe` method
|
|
93
|
-
- β
**Legacy Custom**: `POST /mcp/resources/subscribe` (backward compatible)
|
|
94
|
-
|
|
95
|
-
## π Benefits
|
|
96
|
-
|
|
97
|
-
### 1. MCP Compliance
|
|
98
|
-
- β
Follows MCP specification 2025-06-18
|
|
99
|
-
- β
Works with all standard MCP clients
|
|
100
|
-
- β
Compatible with MCP Inspector
|
|
101
|
-
- β
Uses `notifications/resources/updated` format
|
|
102
|
-
|
|
103
|
-
### 2. Webhook-Based (Not SSE)
|
|
104
|
-
- β
No persistent connection required
|
|
105
|
-
- β
Client provides webhook URL in `_meta`
|
|
106
|
-
- β
Server sends HTTP POST to client webhook
|
|
107
|
-
- β
Fully stateless and scalable
|
|
108
|
-
|
|
109
|
-
### 3. Backward Compatible
|
|
110
|
-
- β
Custom endpoints still work (`/mcp/resources/subscribe`)
|
|
111
|
-
- β
Existing integrations unaffected
|
|
112
|
-
- β
Gradual migration path
|
|
113
|
-
|
|
114
|
-
## π Usage Examples
|
|
115
|
-
|
|
116
|
-
### Example 1: Subscribe via Standard MCP
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
// MCP Client
|
|
120
|
-
const response = await client.request({
|
|
121
|
-
method: 'resources/subscribe',
|
|
122
|
-
params: {
|
|
123
|
-
uri: 'github://repo/owner/repo/issues',
|
|
124
|
-
_meta: {
|
|
125
|
-
webhookUrl: 'https://my-app.com/mcp/notifications',
|
|
126
|
-
webhookSecret: 'secret123'
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// Response
|
|
132
|
-
{
|
|
133
|
-
subscriptionId: 'sub_abc123',
|
|
134
|
-
_meta: {
|
|
135
|
-
subscriptionId: 'sub_abc123',
|
|
136
|
-
webhookEnabled: true
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Example 2: Receive Notifications
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
// Your webhook endpoint
|
|
145
|
-
app.post('/mcp/notifications', (req, res) => {
|
|
146
|
-
const notification = req.body;
|
|
147
|
-
|
|
148
|
-
// Standard MCP notification
|
|
149
|
-
if (notification.method === 'notifications/resources/updated') {
|
|
150
|
-
console.log('Resource:', notification.params.uri);
|
|
151
|
-
console.log('Change:', notification.params._meta.changeType);
|
|
152
|
-
console.log('Data:', notification.params._meta);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
res.send('OK');
|
|
156
|
-
});
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Example 3: Unsubscribe
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
await client.request({
|
|
163
|
-
method: 'resources/unsubscribe',
|
|
164
|
-
params: {
|
|
165
|
-
uri: 'github://repo/owner/repo/issues',
|
|
166
|
-
_meta: {
|
|
167
|
-
subscriptionId: 'sub_abc123'
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
## π§ͺ Testing
|
|
174
|
-
|
|
175
|
-
### Test with curl
|
|
176
|
-
|
|
177
|
-
```bash
|
|
178
|
-
# 1. Subscribe
|
|
179
|
-
curl -X POST http://localhost:3000/mcp \
|
|
180
|
-
-H "Content-Type: application/json" \
|
|
181
|
-
-d '{
|
|
182
|
-
"jsonrpc": "2.0",
|
|
183
|
-
"id": 1,
|
|
184
|
-
"method": "resources/subscribe",
|
|
185
|
-
"params": {
|
|
186
|
-
"uri": "github://repo/surajbhan/test/issues",
|
|
187
|
-
"_meta": {
|
|
188
|
-
"webhookUrl": "https://webhook.site/unique-url",
|
|
189
|
-
"webhookSecret": "test123"
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}'
|
|
193
|
-
|
|
194
|
-
# 2. Create issue (triggers webhook)
|
|
195
|
-
# Go to GitHub and create an issue
|
|
196
|
-
|
|
197
|
-
# 3. Check webhook.site for notification!
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Test with MCP Inspector
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
npx @modelcontextprotocol/inspector http://localhost:3000/mcp
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
1. List resources
|
|
207
|
-
2. Subscribe to a resource
|
|
208
|
-
3. Provide webhook URL in metadata
|
|
209
|
-
4. Trigger resource change
|
|
210
|
-
5. See notification arrive!
|
|
211
|
-
|
|
212
|
-
## π Notification Flow
|
|
213
|
-
|
|
214
|
-
```
|
|
215
|
-
βββββββββββββββ
|
|
216
|
-
β Client β
|
|
217
|
-
β (Your App) β
|
|
218
|
-
ββββββββ¬βββββββ
|
|
219
|
-
β
|
|
220
|
-
β 1. POST /mcp
|
|
221
|
-
β method: resources/subscribe
|
|
222
|
-
β params._meta.webhookUrl: "https://client.com/webhook"
|
|
223
|
-
β
|
|
224
|
-
βΌ
|
|
225
|
-
βββββββββββββββββββ
|
|
226
|
-
β MCP Server β
|
|
227
|
-
β (This Library) β
|
|
228
|
-
ββββββββββ¬βββββββββ
|
|
229
|
-
β
|
|
230
|
-
β 2. Create subscription
|
|
231
|
-
β Setup GitHub webhook
|
|
232
|
-
β
|
|
233
|
-
βΌ
|
|
234
|
-
βββββββββββββββββββ
|
|
235
|
-
β GitHub β
|
|
236
|
-
β (3rd Party) β
|
|
237
|
-
ββββββββββ¬βββββββββ
|
|
238
|
-
β
|
|
239
|
-
β 3. Issue created
|
|
240
|
-
β POST /webhooks/incoming/sub_123
|
|
241
|
-
β
|
|
242
|
-
βΌ
|
|
243
|
-
βββββββββββββββββββ
|
|
244
|
-
β MCP Server β
|
|
245
|
-
ββββββββββ¬βββββββββ
|
|
246
|
-
β
|
|
247
|
-
β 4. Send MCP notification
|
|
248
|
-
β POST https://client.com/webhook
|
|
249
|
-
β {
|
|
250
|
-
β "jsonrpc": "2.0",
|
|
251
|
-
β "method": "notifications/resources/updated",
|
|
252
|
-
β "params": { ... }
|
|
253
|
-
β }
|
|
254
|
-
β
|
|
255
|
-
βΌ
|
|
256
|
-
βββββββββββββββ
|
|
257
|
-
β Client β
|
|
258
|
-
β Receives β
|
|
259
|
-
βNotification β
|
|
260
|
-
βββββββββββββββ
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
## π Security
|
|
264
|
-
|
|
265
|
-
### Signature Verification
|
|
266
|
-
|
|
267
|
-
All notifications include HMAC signature:
|
|
268
|
-
|
|
269
|
-
```typescript
|
|
270
|
-
const signature = headers['x-webhook-signature'];
|
|
271
|
-
// Format: "sha256=<hmac_hex>"
|
|
272
|
-
|
|
273
|
-
const hmac = crypto.createHmac('sha256', secret);
|
|
274
|
-
hmac.update(JSON.stringify(payload));
|
|
275
|
-
const expected = `sha256=${hmac.digest('hex')}`;
|
|
276
|
-
|
|
277
|
-
if (signature !== expected) {
|
|
278
|
-
throw new Error('Invalid signature');
|
|
279
|
-
}
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
## π Documentation
|
|
283
|
-
|
|
284
|
-
- **Standard Subscriptions Guide**: `STANDARD_SUBSCRIPTIONS.md`
|
|
285
|
-
- **GitHub Live Example**: `examples/github-server-live.ts`
|
|
286
|
-
- **MCP Specification**: https://modelcontextprotocol.io/specification/2025-06-18/server/resources#subscriptions
|
|
287
|
-
|
|
288
|
-
## β
Checklist
|
|
289
|
-
|
|
290
|
-
- [x] Standard `resources/subscribe` intercept
|
|
291
|
-
- [x] Webhook URL via `_meta` parameter
|
|
292
|
-
- [x] Standard MCP notification format (`notifications/resources/updated`)
|
|
293
|
-
- [x] Backward compatible with custom endpoints
|
|
294
|
-
- [x] Signature verification
|
|
295
|
-
- [x] Retry logic with exponential backoff
|
|
296
|
-
- [x] MCP Inspector compatible
|
|
297
|
-
- [x] Documentation and examples
|
|
298
|
-
- [x] Live GitHub integration tested
|
|
299
|
-
|
|
300
|
-
## π Result
|
|
301
|
-
|
|
302
|
-
You now have:
|
|
303
|
-
1. β
**Standard MCP compliance** - works with all MCP clients
|
|
304
|
-
2. β
**Webhook-based subscriptions** - no SSE needed
|
|
305
|
-
3. β
**Third-party integration** - GitHub, Slack, etc.
|
|
306
|
-
4. β
**Backward compatible** - existing code still works
|
|
307
|
-
5. β
**Production ready** - retry, security, monitoring
|
|
308
|
-
|
|
309
|
-
**The best of both worlds: Standard MCP + Webhook Power! π**
|