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.
- package/COMPLETION_IMPLEMENTATION.md +280 -0
- package/PAGINATION_IMPLEMENTATION.md +221 -0
- package/README.md +194 -6
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +81 -9
- package/dist/server.js.map +1 -1
- package/dist/types/index.d.ts +57 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/examples/completion-example.ts +339 -0
- package/examples/pagination-example.ts +261 -0
- package/package.json +5 -4
- package/src/__tests__/pagination.test.ts +323 -0
- package/src/server.ts +97 -14
- package/src/types/index.ts +74 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
188
|
-
|
|
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
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"
|
|
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"}
|