mcp-http-webhook 1.0.6 → 1.0.7

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.
@@ -0,0 +1,280 @@
1
+ # MCP Completion Support Implementation
2
+
3
+ ## Summary
4
+
5
+ Implemented comprehensive completion (autocomplete) support for MCP resources and prompts. Completions provide intelligent suggestions for prompt arguments and resource URI parameters, enabling better user experience in MCP clients.
6
+
7
+ ## Changes Made
8
+
9
+ ### 1. Type Definitions (`src/types/index.ts`)
10
+
11
+ #### Added New Types:
12
+
13
+ - **`CompletionItem`**: Individual completion suggestion
14
+ - `value`: The actual value to use
15
+ - `label`: Optional display label
16
+ - `description`: Optional description
17
+ - `type`: Type hint (value, function, variable, constant, other)
18
+
19
+ - **`CompletionRef`**: Reference to what's being completed
20
+ - Prompt reference: `{ type: 'ref/prompt', name, arguments }`
21
+ - Resource reference: `{ type: 'ref/resource', uri }`
22
+
23
+ - **`CompletionHandler`**: Function signature for completion handlers
24
+ ```typescript
25
+ (ref: CompletionRef, argument: string, context: AuthContext) => Promise<CompletionItem[]>
26
+ ```
27
+
28
+ #### Updated Types:
29
+
30
+ - **`PromptDefinition`**: Added optional `completion` handler
31
+ - **`ResourceDefinition`**: Added optional `completion` handler
32
+ - **`MCPServerConfig`**: Added optional global `completions` handler
33
+
34
+ ### 2. Server Implementation (`src/server.ts`)
35
+
36
+ #### Imports:
37
+ - Added `completable` from `@modelcontextprotocol/sdk/server/completable.js`
38
+
39
+ #### Prompt Registration:
40
+ - Wraps prompt argument schemas with `completable()` when completion handler is provided
41
+ - Completion callback receives:
42
+ - Current argument value
43
+ - Context with other argument values (for context-aware suggestions)
44
+ - Returns array of completion values
45
+
46
+ #### Completion Flow:
47
+ 1. Client requests completions for a specific argument
48
+ 2. Server identifies the relevant completion handler:
49
+ - Prompt-specific handler
50
+ - Resource-specific handler
51
+ - Global fallback handler
52
+ 3. Handler returns suggestions based on:
53
+ - Current partial value
54
+ - Other argument values (context)
55
+ - User authentication context
56
+ 4. Server formats and returns completion items
57
+
58
+ ### 3. Documentation
59
+
60
+ #### Updated README.md:
61
+ - Added **Completions** section with:
62
+ - Prompt completion example (context-aware)
63
+ - Resource URI completion example (hierarchical)
64
+ - Global completion handler example
65
+ - Reference to example file
66
+
67
+ ### 4. Examples
68
+
69
+ Created `examples/completion-example.ts` demonstrating:
70
+
71
+ 1. **Prompt Argument Completion**:
72
+ - Language selection → suggests: python, javascript, typescript, etc.
73
+ - Framework selection → context-aware based on language
74
+ - Feature selection → common features
75
+
76
+ 2. **Resource URI Completion**:
77
+ - Owner parameter → suggests GitHub organizations
78
+ - Repo parameter → filtered by selected owner
79
+ - Hierarchical completion
80
+
81
+ 3. **Global Completion Handler**:
82
+ - Fallback for arguments without specific handlers
83
+ - Provides default suggestions
84
+
85
+ ## Usage
86
+
87
+ ### Prompt with Completion
88
+
89
+ ```typescript
90
+ const promptDef: PromptDefinition = {
91
+ name: 'generate-code',
92
+ arguments: [
93
+ { name: 'language', required: true },
94
+ { name: 'framework', required: false }
95
+ ],
96
+
97
+ handler: async (args, context) => {
98
+ // Generate code based on args
99
+ return { messages: [...] };
100
+ },
101
+
102
+ completion: async (ref, argument, context) => {
103
+ if (argument === 'language') {
104
+ return [
105
+ { value: 'python', label: 'Python' },
106
+ { value: 'javascript', label: 'JavaScript' }
107
+ ];
108
+ }
109
+
110
+ // Context-aware: framework based on language
111
+ if (argument === 'framework' && ref.arguments?.language) {
112
+ const lang = ref.arguments.language;
113
+ return getFrameworksForLanguage(lang);
114
+ }
115
+
116
+ return [];
117
+ }
118
+ };
119
+ ```
120
+
121
+ ### Resource with Completion
122
+
123
+ ```typescript
124
+ const resourceDef: ResourceDefinition = {
125
+ uri: 'github://repos/{owner}/{repo}',
126
+ name: 'github-repos',
127
+
128
+ read: async (uri, context) => { /* ... */ },
129
+
130
+ completion: async (ref, argument, context) => {
131
+ if (argument === 'owner') {
132
+ return await fetchGitHubOrganizations();
133
+ }
134
+
135
+ if (argument === 'repo') {
136
+ // Extract owner from current URI
137
+ const owner = ref.uri.match(/repos\/([^/]+)/)?.[1];
138
+ return await fetchReposForOwner(owner);
139
+ }
140
+
141
+ return [];
142
+ }
143
+ };
144
+ ```
145
+
146
+ ### Global Completion Handler
147
+
148
+ ```typescript
149
+ createMCPServer({
150
+ // ... other config
151
+ completions: async (ref, argument, context) => {
152
+ // Fallback for any argument without specific handler
153
+ if (ref.type === 'ref/prompt') {
154
+ return getPromptCompletions(ref.name, argument);
155
+ }
156
+ if (ref.type === 'ref/resource') {
157
+ return getResourceCompletions(ref.uri, argument);
158
+ }
159
+ return [];
160
+ }
161
+ });
162
+ ```
163
+
164
+ ## Client Request/Response
165
+
166
+ ### Request Completions
167
+
168
+ ```json
169
+ {
170
+ "jsonrpc": "2.0",
171
+ "method": "completion/complete",
172
+ "params": {
173
+ "ref": {
174
+ "type": "ref/prompt",
175
+ "name": "generate-code",
176
+ "arguments": {
177
+ "language": "python"
178
+ }
179
+ },
180
+ "argument": {
181
+ "name": "framework",
182
+ "value": "fla"
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ ### Response
189
+
190
+ ```json
191
+ {
192
+ "jsonrpc": "2.0",
193
+ "result": {
194
+ "completion": {
195
+ "values": ["flask", "fastapi"],
196
+ "total": 2,
197
+ "hasMore": false
198
+ }
199
+ }
200
+ }
201
+ ```
202
+
203
+ ## Key Features
204
+
205
+ ### 1. Context-Aware Completions
206
+ - Suggestions based on other argument values
207
+ - Example: Framework suggestions filtered by selected language
208
+
209
+ ### 2. Hierarchical Completions
210
+ - Step-by-step suggestions for complex URIs
211
+ - Example: Owner → Repo → Branch
212
+
213
+ ### 3. Async Data Sources
214
+ - Completion handlers can fetch from databases/APIs
215
+ - Supports dynamic, real-time suggestions
216
+
217
+ ### 4. Type Safety
218
+ - Full TypeScript support
219
+ - Strongly typed completion items and handlers
220
+
221
+ ### 5. Fallback Support
222
+ - Global handler for arguments without specific handlers
223
+ - Prevents empty completion lists
224
+
225
+ ### 6. Performance Optimized
226
+ - Completions use Zod's completable wrapper
227
+ - Efficient MCP SDK integration
228
+
229
+ ## Best Practices
230
+
231
+ 1. **Fast Handlers**: Keep completion handlers under 100ms for good UX
232
+ 2. **Context-Aware**: Use `ref.arguments` to provide relevant suggestions
233
+ 3. **Caching**: Cache frequent completions (e.g., language lists)
234
+ 4. **Fuzzy Matching**: Implement fuzzy search for better matches
235
+ 5. **Async Loading**: Fetch suggestions from APIs/databases as needed
236
+ 6. **Graceful Fallback**: Always return empty array instead of throwing errors
237
+ 7. **Rich Metadata**: Include labels and descriptions for better UX
238
+ 8. **Hierarchical Flow**: For nested parameters, complete in logical order
239
+
240
+ ## Examples of Use Cases
241
+
242
+ 1. **Code Generation**: Language → Framework → Library completions
243
+ 2. **File Browsers**: Drive → Folder → File hierarchical completion
244
+ 3. **Database Queries**: Database → Schema → Table → Column completion
245
+ 4. **API Endpoints**: Service → Resource → Method completion
246
+ 5. **Git Operations**: Remote → Branch → Commit completion
247
+ 6. **Cloud Resources**: Provider → Region → Resource type completion
248
+
249
+ ## Integration with MCP SDK
250
+
251
+ - Uses `completable()` wrapper from `@modelcontextprotocol/sdk`
252
+ - Integrates seamlessly with Zod schemas
253
+ - Compatible with all MCP clients that support completions capability
254
+ - Follows official MCP completion protocol
255
+
256
+ ## Files Modified
257
+
258
+ - `src/types/index.ts` - Type definitions for completions
259
+ - `src/server.ts` - Server-side completion implementation
260
+ - `README.md` - Documentation
261
+ - `examples/completion-example.ts` - Comprehensive examples (NEW)
262
+
263
+ ## Testing
264
+
265
+ Build successful:
266
+ ```bash
267
+ cd packages/plugins/mcp-proxy
268
+ npm run build # ✓ No errors
269
+ ```
270
+
271
+ ## Next Steps
272
+
273
+ Consider:
274
+ 1. Add fuzzy matching library for better user experience
275
+ 2. Implement completion result caching
276
+ 3. Add completion metrics/analytics
277
+ 4. Support for completion pagination (for large result sets)
278
+ 5. Add completion templates/presets
279
+ 6. Integration tests with MCP clients
280
+ 7. Performance benchmarks for completion handlers
@@ -0,0 +1,221 @@
1
+ # MCP Resources Pagination Implementation
2
+
3
+ ## Summary
4
+
5
+ Implemented comprehensive pagination support for MCP (Model Context Protocol) resources in the `mcp-proxy` package. Both `list()` and `read()` operations now support offset-based and cursor-based pagination.
6
+
7
+ ## Changes Made
8
+
9
+ ### 1. Type Definitions (`src/types/index.ts`)
10
+
11
+ #### Added New Types:
12
+ - **`PaginationMetadata`**: Response metadata for paginated results
13
+ - `page`: Current page number
14
+ - `limit`: Items per page
15
+ - `total`: Total number of items (optional)
16
+ - `hasMore`: Whether more items exist
17
+ - `nextCursor`: Token for next page (cursor-based)
18
+ - `prevCursor`: Token for previous page (cursor-based)
19
+
20
+ - **`ResourceListResult`**: New return type for paginated list operations
21
+ - `resources`: Array of resource items
22
+ - `pagination`: Optional pagination metadata
23
+
24
+ #### Updated Types:
25
+ - **`ResourceReadOptions`**: Added `cursor` field to pagination options
26
+ ```typescript
27
+ pagination?: {
28
+ page?: number;
29
+ limit?: number;
30
+ cursor?: string; // NEW
31
+ }
32
+ ```
33
+
34
+ - **`ResourceReadResult`**: Added optional pagination metadata
35
+ ```typescript
36
+ pagination?: PaginationMetadata; // NEW
37
+ ```
38
+
39
+ - **`ResourceDefinition`**: Updated signatures
40
+ - `list()`: Now accepts `options?: ResourceReadOptions` parameter
41
+ - `list()`: Can return `ResourceListResult` (with pagination) or `ResourceListItem[]` (backward compatible)
42
+
43
+ ### 2. Server Implementation (`src/server.ts`)
44
+
45
+ #### Templated Resources (line ~258):
46
+ - Extract pagination params from `extra?._meta`
47
+ - Pass options to `list()` handler
48
+ - Handle both array and paginated responses
49
+ - Add `_meta.pagination` to response when present
50
+
51
+ #### Resource Read Handlers (lines ~311, ~370):
52
+ - Extract pagination params from `_extra?._meta`
53
+ - Pass options to `read()` handler
54
+ - Include pagination metadata in response via `_meta.pagination`
55
+
56
+ ### 3. Documentation
57
+
58
+ #### Updated README.md:
59
+ - Added dedicated **Pagination** section with:
60
+ - Client request format
61
+ - Server implementation examples
62
+ - Response format
63
+ - Reference to examples
64
+
65
+ #### Updated Resource Examples:
66
+ - Modified basic resource example to show pagination usage
67
+ - Demonstrated both `list()` and `read()` pagination
68
+
69
+ ### 4. Examples
70
+
71
+ Created `examples/pagination-example.ts` demonstrating:
72
+ 1. **Offset-based pagination** in `list()`:
73
+ - Page/limit parameters
74
+ - Total count and hasMore flags
75
+
76
+ 2. **Paginated read** for large content:
77
+ - Useful for logs, large documents
78
+ - Same pagination approach as list
79
+
80
+ 3. **Cursor-based pagination**:
81
+ - Next/previous cursor tokens
82
+ - Better for real-time/streaming data
83
+ - Handles dynamic datasets
84
+
85
+ ### 5. Tests
86
+
87
+ Created `src/__tests__/pagination.test.ts` covering:
88
+ - Default pagination behavior
89
+ - Custom page/limit parameters
90
+ - Last page detection (hasMore: false)
91
+ - Cursor-based navigation
92
+ - Backward compatibility (non-paginated resources)
93
+
94
+ ## Usage
95
+
96
+ ### Client Request Format
97
+
98
+ ```typescript
99
+ {
100
+ "jsonrpc": "2.0",
101
+ "method": "resources/list",
102
+ "params": {},
103
+ "_meta": {
104
+ "page": 1,
105
+ "limit": 10,
106
+ "cursor": "optional-token"
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Server Implementation
112
+
113
+ ```typescript
114
+ const resource: ResourceDefinition = {
115
+ uri: 'items://list',
116
+ name: 'items',
117
+ description: 'Items with pagination',
118
+
119
+ list: async (context, options) => {
120
+ const page = options?.pagination?.page || 1;
121
+ const limit = options?.pagination?.limit || 10;
122
+
123
+ // Fetch paginated data
124
+ const items = await fetchItems(page, limit);
125
+ const total = await countItems();
126
+
127
+ return {
128
+ resources: items.map(toResource),
129
+ pagination: {
130
+ page,
131
+ limit,
132
+ total,
133
+ hasMore: page * limit < total,
134
+ }
135
+ };
136
+ },
137
+
138
+ read: async (uri, context, options) => {
139
+ const cursor = options?.pagination?.cursor;
140
+ const limit = options?.pagination?.limit || 50;
141
+
142
+ const data = await fetchWithCursor(cursor, limit);
143
+
144
+ return {
145
+ contents: data.items,
146
+ pagination: {
147
+ page: 1,
148
+ limit,
149
+ hasMore: data.hasMore,
150
+ nextCursor: data.nextCursor,
151
+ }
152
+ };
153
+ }
154
+ };
155
+ ```
156
+
157
+ ### Response Format
158
+
159
+ ```json
160
+ {
161
+ "jsonrpc": "2.0",
162
+ "result": {
163
+ "resources": [...],
164
+ "_meta": {
165
+ "pagination": {
166
+ "page": 1,
167
+ "limit": 10,
168
+ "total": 100,
169
+ "hasMore": true,
170
+ "nextCursor": "token-123",
171
+ "prevCursor": "token-122"
172
+ }
173
+ }
174
+ }
175
+ }
176
+ ```
177
+
178
+ ## Backward Compatibility
179
+
180
+ ✅ **Fully backward compatible**:
181
+ - Pagination is optional - resources can omit it
182
+ - `list()` can return array or paginated result
183
+ - `read()` can omit pagination metadata
184
+ - Old resources continue to work without changes
185
+
186
+ ## Best Practices
187
+
188
+ 1. **Default Values**: Always provide sensible defaults (e.g., page=1, limit=10)
189
+ 2. **Maximum Limits**: Set upper bounds to prevent abuse (e.g., max 100 items)
190
+ 3. **Total Count**: Include when feasible for better UX
191
+ 4. **hasMore Flag**: Always indicate if more data exists
192
+ 5. **Cursor vs Offset**: Use cursors for real-time/dynamic data, offsets for stable datasets
193
+ 6. **Caching**: Consider caching frequently accessed pages
194
+ 7. **Documentation**: Document pagination support in resource descriptions
195
+
196
+ ## Files Modified
197
+
198
+ - `src/types/index.ts` - Type definitions
199
+ - `src/server.ts` - Server implementation
200
+ - `README.md` - Documentation
201
+ - `examples/pagination-example.ts` - Comprehensive examples (NEW)
202
+ - `src/__tests__/pagination.test.ts` - Test suite (NEW)
203
+
204
+ ## Testing
205
+
206
+ Build successful:
207
+ ```bash
208
+ cd packages/plugins/mcp-proxy
209
+ npm run build # ✓ No errors
210
+ ```
211
+
212
+ All type checking passes with no compilation errors.
213
+
214
+ ## Next Steps
215
+
216
+ Consider:
217
+ 1. Add integration tests with real MCP clients
218
+ 2. Add metrics/monitoring for pagination usage
219
+ 3. Implement page size limits per resource
220
+ 4. Add pagination presets (small/medium/large)
221
+ 5. Support for GraphQL-style pagination (edges/nodes)
package/README.md CHANGED
@@ -179,14 +179,38 @@ Resources represent data that can be read and subscribed to:
179
179
  name: 'GitHub Issues',
180
180
  description: 'Repository issues',
181
181
 
182
- read: async (uri, context) => {
183
- return { contents: [...] };
182
+ read: async (uri, context, options) => {
183
+ // Access pagination options
184
+ const page = options?.pagination?.page || 1;
185
+ const limit = options?.pagination?.limit || 10;
186
+
187
+ return {
188
+ contents: [...],
189
+ pagination: {
190
+ page,
191
+ limit,
192
+ total: 100,
193
+ hasMore: true
194
+ }
195
+ };
184
196
  },
185
197
 
186
- list: async (context) => {
187
- return [
188
- { uri: '...', name: '...' }
189
- ];
198
+ list: async (context, options) => {
199
+ // Pagination support in list
200
+ const page = options?.pagination?.page || 1;
201
+ const limit = options?.pagination?.limit || 10;
202
+
203
+ return {
204
+ resources: [
205
+ { uri: '...', name: '...' }
206
+ ],
207
+ pagination: {
208
+ page,
209
+ limit,
210
+ total: 50,
211
+ hasMore: true
212
+ }
213
+ };
190
214
  },
191
215
 
192
216
  subscription: {
@@ -242,6 +266,170 @@ class MyStore implements KeyValueStore {
242
266
  }
243
267
  ```
244
268
 
269
+ ### Pagination
270
+
271
+ Resources support pagination for both `list()` and `read()` operations:
272
+
273
+ **Client Request:**
274
+ ```typescript
275
+ // Send pagination params in _meta
276
+ {
277
+ "jsonrpc": "2.0",
278
+ "method": "resources/list",
279
+ "params": {},
280
+ "_meta": {
281
+ "page": 1,
282
+ "limit": 10,
283
+ "cursor": "optional-cursor"
284
+ }
285
+ }
286
+ ```
287
+
288
+ **Server Implementation:**
289
+ ```typescript
290
+ {
291
+ list: async (context, options) => {
292
+ const page = options?.pagination?.page || 1;
293
+ const limit = options?.pagination?.limit || 10;
294
+
295
+ // Fetch paginated data
296
+ const { items, total } = await fetchItems(page, limit);
297
+
298
+ return {
299
+ resources: items,
300
+ pagination: {
301
+ page,
302
+ limit,
303
+ total,
304
+ hasMore: page * limit < total,
305
+ nextCursor: 'next-page-token', // Optional
306
+ }
307
+ };
308
+ },
309
+
310
+ read: async (uri, context, options) => {
311
+ // Pagination also works for large content in read()
312
+ const cursor = options?.pagination?.cursor;
313
+ const limit = options?.pagination?.limit || 50;
314
+
315
+ return {
316
+ contents: paginatedData,
317
+ pagination: {
318
+ page: 1,
319
+ limit,
320
+ hasMore: true,
321
+ nextCursor: 'token-for-next-page',
322
+ }
323
+ };
324
+ }
325
+ }
326
+ ```
327
+
328
+ **Response Format:**
329
+ ```json
330
+ {
331
+ "resources": [...],
332
+ "_meta": {
333
+ "pagination": {
334
+ "page": 1,
335
+ "limit": 10,
336
+ "total": 100,
337
+ "hasMore": true,
338
+ "nextCursor": "...",
339
+ "prevCursor": "..."
340
+ }
341
+ }
342
+ }
343
+ ```
344
+
345
+ See [examples/pagination-example.ts](./examples/pagination-example.ts) for complete examples including cursor-based pagination.
346
+
347
+ ### Completions
348
+
349
+ Completions provide autocomplete suggestions for prompt arguments and resource URI parameters:
350
+
351
+ **Prompt with Completion:**
352
+
353
+ ```typescript
354
+ {
355
+ name: 'generate-code',
356
+ arguments: [
357
+ { name: 'language', required: true },
358
+ { name: 'framework', required: false }
359
+ ],
360
+ handler: async (args, context) => { /* ... */ },
361
+
362
+ // Completion handler for arguments
363
+ completion: async (ref, argument, context) => {
364
+ if (argument === 'language') {
365
+ return [
366
+ { value: 'python', label: 'Python' },
367
+ { value: 'javascript', label: 'JavaScript' },
368
+ { value: 'typescript', label: 'TypeScript' }
369
+ ];
370
+ }
371
+
372
+ // Context-aware: suggest frameworks based on language
373
+ if (argument === 'framework') {
374
+ const lang = ref.arguments?.language;
375
+ if (lang === 'python') {
376
+ return [
377
+ { value: 'django', label: 'Django' },
378
+ { value: 'flask', label: 'Flask' }
379
+ ];
380
+ }
381
+ }
382
+
383
+ return [];
384
+ }
385
+ }
386
+ ```
387
+
388
+ **Resource with Completion:**
389
+
390
+ ```typescript
391
+ {
392
+ uri: 'github://repos/{owner}/{repo}',
393
+ name: 'github-repos',
394
+ /* ... */
395
+
396
+ // Completion for URI parameters
397
+ completion: async (ref, argument, context) => {
398
+ if (argument === 'owner') {
399
+ return [
400
+ { value: 'facebook', label: 'Facebook' },
401
+ { value: 'microsoft', label: 'Microsoft' }
402
+ ];
403
+ }
404
+
405
+ if (argument === 'repo') {
406
+ // Get owner from current URI
407
+ const owner = ref.uri.match(/repos\/([^/]+)/)?.[1];
408
+ // Return repos for that owner
409
+ return fetchReposForOwner(owner);
410
+ }
411
+
412
+ return [];
413
+ }
414
+ }
415
+ ```
416
+
417
+ **Global Completion Handler:**
418
+
419
+ ```typescript
420
+ createMCPServer({
421
+ // ...
422
+ completions: async (ref, argument, context) => {
423
+ // Fallback for any prompt/resource without specific handler
424
+ return [
425
+ { value: 'default', label: 'Default Value' }
426
+ ];
427
+ }
428
+ });
429
+ ```
430
+
431
+ See [examples/completion-example.ts](./examples/completion-example.ts) for comprehensive completion examples.
432
+
245
433
  ### Authentication
246
434
 
247
435
  ```typescript
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAiD,MAAM,SAAS,CAAC;AAkKpG;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAogBlE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAiD,MAAM,SAAS,CAAC;AAkKpG;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAslBlE"}