@jrmc/adonis-mcp 1.0.0-alpha.9 → 1.0.0-beta.10
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 +835 -29
- package/build/commands/commands.json +1 -1
- package/build/commands/inspector.d.ts +17 -0
- package/build/commands/inspector.d.ts.map +1 -0
- package/build/commands/inspector.js +55 -0
- package/build/commands/make/prompt.d.ts +16 -0
- package/build/commands/make/prompt.d.ts.map +1 -0
- package/build/commands/make/prompt.js +36 -0
- package/build/commands/make/resource.d.ts +16 -0
- package/build/commands/make/resource.d.ts.map +1 -0
- package/build/commands/make/resource.js +33 -0
- package/build/commands/make/tool.d.ts.map +1 -1
- package/build/commands/make/tool.js +4 -3
- package/build/configure.d.ts.map +1 -1
- package/build/configure.js +22 -1
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -0
- package/build/providers/mcp_provider.d.ts +3 -0
- package/build/providers/mcp_provider.d.ts.map +1 -1
- package/build/providers/mcp_provider.js +45 -12
- package/build/providers/vinejs_provider.d.ts +13 -0
- package/build/providers/vinejs_provider.d.ts.map +1 -0
- package/build/providers/vinejs_provider.js +10 -0
- package/build/src/define_config.d.ts.map +1 -1
- package/build/src/define_config.js +0 -3
- package/build/src/enums/error.d.ts.map +1 -1
- package/build/src/enums/error.js +0 -1
- package/build/src/request.d.ts +7 -3
- package/build/src/request.d.ts.map +1 -1
- package/build/src/request.js +6 -2
- package/build/src/response.d.ts +24 -23
- package/build/src/response.d.ts.map +1 -1
- package/build/src/response.js +49 -13
- package/build/src/server/annotations/annotations.d.ts +10 -0
- package/build/src/server/annotations/annotations.d.ts.map +1 -0
- package/build/src/server/annotations/annotations.js +9 -0
- package/build/src/server/annotations/audience.d.ts +22 -0
- package/build/src/server/annotations/audience.d.ts.map +1 -0
- package/build/src/server/annotations/audience.js +28 -0
- package/build/src/server/annotations/is_destructive.d.ts +17 -0
- package/build/src/server/annotations/is_destructive.d.ts.map +1 -0
- package/build/src/server/annotations/is_destructive.js +24 -0
- package/build/src/server/annotations/is_idempotent.d.ts +17 -0
- package/build/src/server/annotations/is_idempotent.d.ts.map +1 -0
- package/build/src/server/annotations/is_idempotent.js +24 -0
- package/build/src/server/annotations/is_open_world.d.ts +17 -0
- package/build/src/server/annotations/is_open_world.d.ts.map +1 -0
- package/build/src/server/annotations/is_open_world.js +24 -0
- package/build/src/server/annotations/is_read_only.d.ts +17 -0
- package/build/src/server/annotations/is_read_only.d.ts.map +1 -0
- package/build/src/server/annotations/is_read_only.js +24 -0
- package/build/src/server/annotations/last_modified.d.ts +21 -0
- package/build/src/server/annotations/last_modified.d.ts.map +1 -0
- package/build/src/server/annotations/last_modified.js +28 -0
- package/build/src/server/annotations/priority.d.ts +21 -0
- package/build/src/server/annotations/priority.d.ts.map +1 -0
- package/build/src/server/annotations/priority.js +31 -0
- package/build/src/server/annotations/tool_annotations.d.ts +11 -0
- package/build/src/server/annotations/tool_annotations.d.ts.map +1 -0
- package/build/src/server/annotations/tool_annotations.js +10 -0
- package/build/src/server/contents/audio.d.ts +24 -0
- package/build/src/server/contents/audio.d.ts.map +1 -0
- package/build/src/server/contents/audio.js +57 -0
- package/build/src/server/contents/blob.d.ts +20 -0
- package/build/src/server/contents/blob.d.ts.map +1 -0
- package/build/src/server/contents/blob.js +42 -0
- package/build/src/server/contents/embedded_resource.d.ts +26 -0
- package/build/src/server/contents/embedded_resource.d.ts.map +1 -0
- package/build/src/server/contents/embedded_resource.js +76 -0
- package/build/src/server/contents/error.d.ts +20 -0
- package/build/src/server/contents/error.d.ts.map +1 -0
- package/build/src/server/contents/error.js +25 -0
- package/build/src/server/contents/image.d.ts +24 -0
- package/build/src/server/contents/image.d.ts.map +1 -0
- package/build/src/server/contents/image.js +57 -0
- package/build/src/server/contents/resource_link.d.ts +23 -0
- package/build/src/server/contents/resource_link.d.ts.map +1 -0
- package/build/src/server/contents/resource_link.js +59 -0
- package/build/src/server/contents/structured.d.ts +20 -0
- package/build/src/server/contents/structured.d.ts.map +1 -0
- package/build/src/server/contents/structured.js +26 -0
- package/build/src/server/contents/text.d.ts +24 -0
- package/build/src/server/contents/text.d.ts.map +1 -0
- package/build/src/server/contents/text.js +61 -0
- package/build/src/server/context.d.ts +9 -6
- package/build/src/server/context.d.ts.map +1 -1
- package/build/src/server/context.js +13 -3
- package/build/src/server/contracts/content.d.ts +16 -0
- package/build/src/server/contracts/content.d.ts.map +1 -0
- package/build/src/server/contracts/content.js +8 -0
- package/build/src/server/contracts/context.d.ts +28 -0
- package/build/src/server/contracts/context.d.ts.map +1 -0
- package/build/src/server/contracts/request.d.ts +12 -0
- package/build/src/server/contracts/request.d.ts.map +1 -0
- package/build/src/server/contracts/request.js +1 -0
- package/build/src/server/contracts/response.d.ts +26 -0
- package/build/src/server/contracts/response.d.ts.map +1 -0
- package/build/src/{types → server/contracts}/transport.d.ts +2 -2
- package/build/src/server/contracts/transport.d.ts.map +1 -0
- package/build/src/server/contracts/transport.js +7 -0
- package/build/src/server/controllers/mcp_controller.d.ts.map +1 -1
- package/build/src/server/controllers/mcp_controller.js +0 -3
- package/build/src/server/exceptions/jsonrpc_error.d.ts +7 -0
- package/build/src/server/exceptions/jsonrpc_error.d.ts.map +1 -0
- package/build/src/server/exceptions/jsonrpc_error.js +10 -0
- package/build/src/server/exceptions/jsonrpc_exception.d.ts +6 -5
- package/build/src/server/exceptions/jsonrpc_exception.d.ts.map +1 -1
- package/build/src/server/exceptions/jsonrpc_exception.js +18 -9
- package/build/src/server/mcp_bouncer.d.ts +115 -0
- package/build/src/server/mcp_bouncer.d.ts.map +1 -0
- package/build/src/server/mcp_bouncer.js +123 -0
- package/build/src/server/methods/call_tool.d.ts +2 -2
- package/build/src/server/methods/call_tool.d.ts.map +1 -1
- package/build/src/server/methods/call_tool.js +53 -18
- package/build/src/server/methods/completion.d.ts +12 -0
- package/build/src/server/methods/completion.d.ts.map +1 -0
- package/build/src/server/methods/completion.js +46 -0
- package/build/src/server/methods/get_prompt.d.ts +2 -2
- package/build/src/server/methods/get_prompt.d.ts.map +1 -1
- package/build/src/server/methods/get_prompt.js +56 -2
- package/build/src/server/methods/initialize.d.ts +2 -2
- package/build/src/server/methods/initialize.d.ts.map +1 -1
- package/build/src/server/methods/initialize.js +4 -1
- package/build/src/server/methods/list_prompts.d.ts +2 -2
- package/build/src/server/methods/list_prompts.d.ts.map +1 -1
- package/build/src/server/methods/list_prompts.js +13 -3
- package/build/src/server/methods/list_resource_templates.d.ts +12 -0
- package/build/src/server/methods/list_resource_templates.d.ts.map +1 -0
- package/build/src/server/methods/list_resource_templates.js +23 -0
- package/build/src/server/methods/list_resources.d.ts +2 -2
- package/build/src/server/methods/list_resources.d.ts.map +1 -1
- package/build/src/server/methods/list_resources.js +13 -3
- package/build/src/server/methods/list_tools.d.ts +2 -2
- package/build/src/server/methods/list_tools.d.ts.map +1 -1
- package/build/src/server/methods/list_tools.js +5 -28
- package/build/src/server/methods/ping.d.ts +2 -2
- package/build/src/server/methods/ping.d.ts.map +1 -1
- package/build/src/server/methods/ping.js +1 -1
- package/build/src/server/methods/read_resource.d.ts +2 -2
- package/build/src/server/methods/read_resource.d.ts.map +1 -1
- package/build/src/server/methods/read_resource.js +29 -2
- package/build/src/server/pagination/cursor_paginator.d.ts +7 -7
- package/build/src/server/pagination/cursor_paginator.d.ts.map +1 -1
- package/build/src/server/pagination/cursor_paginator.js +15 -15
- package/build/src/server/prompt.d.ts +28 -0
- package/build/src/server/prompt.d.ts.map +1 -0
- package/build/src/server/prompt.js +32 -0
- package/build/src/server/requests/request_validator.d.ts +15 -0
- package/build/src/server/requests/request_validator.d.ts.map +1 -0
- package/build/src/server/requests/request_validator.js +25 -0
- package/build/src/server/resource.d.ts +23 -0
- package/build/src/server/resource.d.ts.map +1 -0
- package/build/src/server/resource.js +40 -0
- package/build/src/server/tool.d.ts +19 -9
- package/build/src/server/tool.d.ts.map +1 -1
- package/build/src/server/tool.js +21 -0
- package/build/src/server/transports/fake_transport.d.ts +19 -1
- package/build/src/server/transports/fake_transport.d.ts.map +1 -1
- package/build/src/server/transports/fake_transport.js +28 -1
- package/build/src/server/transports/http_transport.d.ts +4 -3
- package/build/src/server/transports/http_transport.d.ts.map +1 -1
- package/build/src/server/transports/http_transport.js +14 -8
- package/build/src/server/transports/stdio_transport.d.ts +2 -2
- package/build/src/server/transports/stdio_transport.d.ts.map +1 -1
- package/build/src/server/transports/stdio_transport.js +0 -3
- package/build/src/server.d.ts +6 -3
- package/build/src/server.d.ts.map +1 -1
- package/build/src/server.js +24 -11
- package/build/src/types/config.d.ts +1 -0
- package/build/src/types/config.d.ts.map +1 -1
- package/build/src/types/content.d.ts +35 -0
- package/build/src/types/content.d.ts.map +1 -0
- package/build/src/types/content.js +7 -0
- package/build/src/types/context.d.ts +31 -18
- package/build/src/types/context.d.ts.map +1 -1
- package/build/src/types/jsonrpc.d.ts +406 -0
- package/build/src/types/jsonrpc.d.ts.map +1 -0
- package/build/src/types/jsonrpc.js +7 -0
- package/build/src/types/method.d.ts +22 -12
- package/build/src/types/method.d.ts.map +1 -1
- package/build/src/types/request.d.ts +24 -35
- package/build/src/types/request.d.ts.map +1 -1
- package/build/src/types/response.d.ts +16 -38
- package/build/src/types/response.d.ts.map +1 -1
- package/build/src/utils/find_resource_pattern.d.ts +21 -0
- package/build/src/utils/find_resource_pattern.d.ts.map +1 -0
- package/build/src/utils/find_resource_pattern.js +35 -0
- package/build/src/utils/stdio.d.ts +2 -3
- package/build/src/utils/stdio.d.ts.map +1 -1
- package/build/src/utils/stdio.js +7 -7
- package/build/src/utils/uri_template.d.ts +25 -0
- package/build/src/utils/uri_template.d.ts.map +1 -0
- package/build/src/utils/uri_template.js +241 -0
- package/build/stubs/config.ts.stub +1 -1
- package/build/stubs/main.d.ts.map +1 -1
- package/build/stubs/main.js +1 -2
- package/build/stubs/make/mcp/prompts/main.ts.stub +32 -16
- package/build/stubs/make/mcp/prompts/with_vine.ts.stub +40 -0
- package/build/stubs/make/mcp/resources/main.ts.stub +13 -19
- package/build/stubs/make/mcp/tools/main.ts.stub +11 -13
- package/build/stubs/make/mcp/tools/with_vine.ts.stub +37 -0
- package/build/stubs/make/middleware/mcp_middleware.ts.stub +49 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +37 -7
- package/build/src/types/notification.d.ts +0 -14
- package/build/src/types/notification.d.ts.map +0 -1
- package/build/src/types/transport.d.ts.map +0 -1
- /package/build/src/{types/notification.js → server/contracts/context.js} +0 -0
- /package/build/src/{types/transport.js → server/contracts/response.js} +0 -0
package/README.md
CHANGED
|
@@ -5,14 +5,38 @@
|
|
|
5
5
|
|
|
6
6
|
AdonisJS MCP - Server MCP for your AdonisJS applications.
|
|
7
7
|
|
|
8
|
+
> **Note:** This documentation has been generated by AI and has not been fully verified yet. Please report any inaccuracies or issues you encounter.
|
|
9
|
+
|
|
10
|
+
## Links
|
|
11
|
+
|
|
12
|
+
[View documentation](https://adonis-mcp.jrmc.dev/)
|
|
13
|
+
|
|
8
14
|
## Roadmap
|
|
9
15
|
|
|
16
|
+
- [x] MCP tools support
|
|
17
|
+
- [x] MCP resources support
|
|
10
18
|
- [x] MCP prompts support
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
19
|
+
- [x] HTTP transport
|
|
20
|
+
- [x] Stdio transport
|
|
21
|
+
- [x] Fake transport (for testing)
|
|
14
22
|
- [x] Advanced pagination support
|
|
15
|
-
- [
|
|
23
|
+
- [x] Meta support
|
|
24
|
+
- [x] Annotations
|
|
25
|
+
- [x] Completion
|
|
26
|
+
- [x] Inspector
|
|
27
|
+
- [x] Session
|
|
28
|
+
- [x] Documentation
|
|
29
|
+
- [x] Inject support
|
|
30
|
+
- [x] VineJs integration
|
|
31
|
+
- [x] JSON Schema with VineJs
|
|
32
|
+
- [x] Bounce integration
|
|
33
|
+
- [x] Auth helpers
|
|
34
|
+
- [x] Starter kit
|
|
35
|
+
- [x] Demo applications
|
|
36
|
+
- [ ] Events
|
|
37
|
+
- [ ] Logger
|
|
38
|
+
- [ ] Alternative transports (SSE)
|
|
39
|
+
- [ ] Output tool
|
|
16
40
|
|
|
17
41
|
## Installation & Configuration
|
|
18
42
|
|
|
@@ -28,10 +52,17 @@ import { defineConfig } from '@jrmc/adonis-mcp'
|
|
|
28
52
|
export default defineConfig({
|
|
29
53
|
name: 'adonis-mcp-server',
|
|
30
54
|
version: '1.0.0',
|
|
31
|
-
path: 'app/mcp', // Path where your tools will be stored
|
|
32
55
|
})
|
|
33
56
|
```
|
|
34
57
|
|
|
58
|
+
By default, your MCP tools, resources, and prompts will be stored in `app/mcp`. If you want to use a different path, you need to configure it in your `adonisrc.ts` file:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
directories: {
|
|
62
|
+
mcp: 'app/custom/mcp', // Optional: custom path for MCP files (defaults to 'app/mcp')
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
35
66
|
## Usage
|
|
36
67
|
|
|
37
68
|
### Creating a Tool
|
|
@@ -45,8 +76,8 @@ node ace make:mcp-tool my_tool
|
|
|
45
76
|
This command will create a file in `app/mcp/tools/my_tool.ts` with a base template:
|
|
46
77
|
|
|
47
78
|
```typescript
|
|
48
|
-
import type {
|
|
49
|
-
import type { BaseSchema
|
|
79
|
+
import type { ToolContext } from '@jrmc/adonis-mcp/types/context'
|
|
80
|
+
import type { BaseSchema } from '@jrmc/adonis-mcp/types/method'
|
|
50
81
|
|
|
51
82
|
import { Tool } from '@jrmc/adonis-mcp'
|
|
52
83
|
|
|
@@ -54,15 +85,13 @@ type Schema = BaseSchema<{
|
|
|
54
85
|
text: { type: "string" }
|
|
55
86
|
}>
|
|
56
87
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
export default class MyToolTool implements Tool<Schema> {
|
|
88
|
+
export default class MyToolTool extends Tool<Schema> {
|
|
60
89
|
name = 'tool_name'
|
|
61
90
|
title = 'Tool title'
|
|
62
91
|
description = 'Tool description'
|
|
63
92
|
|
|
64
|
-
async handle({ args }:
|
|
65
|
-
|
|
93
|
+
async handle({ args, response }: ToolContext<Schema>) {
|
|
94
|
+
return response.text('Hello, world!')
|
|
66
95
|
}
|
|
67
96
|
|
|
68
97
|
schema() {
|
|
@@ -121,12 +150,33 @@ schema() {
|
|
|
121
150
|
}
|
|
122
151
|
```
|
|
123
152
|
|
|
153
|
+
You can also use VineJS(>= [v4](https://vinejs.dev/docs/json-schema-generation)) to define your schema:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import vine from '@vinejs/vine'
|
|
157
|
+
|
|
158
|
+
const vineSchema = vine.object({
|
|
159
|
+
page: vine.number().meta({
|
|
160
|
+
description: 'page number for pagination',
|
|
161
|
+
}),
|
|
162
|
+
perPage: vine.number().optional().meta({
|
|
163
|
+
description: 'per page limit for pagination',
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
schema() {
|
|
168
|
+
return vine.create(
|
|
169
|
+
vineSchema
|
|
170
|
+
).toJSONSchema() as Schema
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
124
174
|
### Handler Implementation
|
|
125
175
|
|
|
126
176
|
The `handle` method contains your tool's logic. It receives a typed context with validated arguments:
|
|
127
177
|
|
|
128
178
|
```typescript
|
|
129
|
-
async handle({ args, response, auth, bouncer }:
|
|
179
|
+
async handle({ args, response, auth, bouncer }: ToolContext<Schema>) {
|
|
130
180
|
// Your logic here
|
|
131
181
|
const result = await SomeModel.query().where('id', args.id)
|
|
132
182
|
|
|
@@ -136,15 +186,15 @@ async handle({ args, response, auth, bouncer }: Context) {
|
|
|
136
186
|
|
|
137
187
|
### Setting up Authentication and Bouncer
|
|
138
188
|
|
|
139
|
-
To use `auth` and `bouncer` in your MCP tools, add the following TypeScript declaration in your middleware (e.g., in your
|
|
189
|
+
To use `auth` and `bouncer` in your MCP tools, prompts, and resources, add the following TypeScript declaration in your middleware (e.g., in your MCP middleware):
|
|
140
190
|
|
|
141
191
|
```typescript
|
|
142
192
|
declare module '@jrmc/adonis-mcp/types/context' {
|
|
143
193
|
export interface McpContext {
|
|
144
|
-
auth
|
|
194
|
+
auth: {
|
|
145
195
|
user?: HttpContext['auth']['user']
|
|
146
196
|
}
|
|
147
|
-
bouncer
|
|
197
|
+
bouncer: McpBouncer<
|
|
148
198
|
Exclude<HttpContext['auth']['user'], undefined>,
|
|
149
199
|
typeof abilities,
|
|
150
200
|
typeof policies
|
|
@@ -173,12 +223,29 @@ You can also specify a custom path:
|
|
|
173
223
|
router.mcp('/custom-mcp-path').use(middleware.auth())
|
|
174
224
|
```
|
|
175
225
|
|
|
226
|
+
> **⚠️ Important: CSRF Protection**
|
|
227
|
+
>
|
|
228
|
+
> If you have CSRF protection enabled in your application, you **must** exclude the MCP route from CSRF validation. MCP clients typically don't include CSRF tokens in their requests.
|
|
229
|
+
>
|
|
230
|
+
> In your `config/shield.ts` file, add the MCP route to the CSRF exceptions:
|
|
231
|
+
>
|
|
232
|
+
> ```typescript
|
|
233
|
+
> export const shieldConfig = defineConfig({
|
|
234
|
+
> csrf: {
|
|
235
|
+
> enabled: true,
|
|
236
|
+
> exceptRoutes: [
|
|
237
|
+
> '/mcp', // Or your custom MCP path
|
|
238
|
+
> ],
|
|
239
|
+
> },
|
|
240
|
+
> })
|
|
241
|
+
> ```
|
|
242
|
+
|
|
176
243
|
### Using Authentication
|
|
177
244
|
|
|
178
245
|
The MCP context automatically includes the `auth` instance from the `HttpContext` if available. You can use it to access the authenticated user:
|
|
179
246
|
|
|
180
247
|
```typescript
|
|
181
|
-
async handle({ args, auth }:
|
|
248
|
+
async handle({ args, auth, response }: ToolContext<Schema>) {
|
|
182
249
|
const user = auth?.user
|
|
183
250
|
|
|
184
251
|
if (!user) {
|
|
@@ -200,7 +267,7 @@ async handle({ args, auth }: Context) {
|
|
|
200
267
|
The MCP context automatically includes the `bouncer` instance from the `HttpContext` if available. You can use it to check permissions:
|
|
201
268
|
|
|
202
269
|
```typescript
|
|
203
|
-
async handle({ args, bouncer }:
|
|
270
|
+
async handle({ args, bouncer, response }: ToolContext<Schema>) {
|
|
204
271
|
// Check a permission
|
|
205
272
|
await bouncer.authorize('viewUsers')
|
|
206
273
|
|
|
@@ -214,13 +281,55 @@ async handle({ args, bouncer }: Context) {
|
|
|
214
281
|
|
|
215
282
|
### Response Return
|
|
216
283
|
|
|
217
|
-
The context includes a `response` instance to format your responses. The
|
|
284
|
+
The context includes a `response` instance to format your responses. The available methods depend on the context type:
|
|
285
|
+
|
|
286
|
+
#### Tool Responses
|
|
287
|
+
|
|
288
|
+
For tools, you can use:
|
|
289
|
+
|
|
290
|
+
- `response.text(text: string)`: Return plain text content
|
|
291
|
+
- `response.image(data: string, mimeType: string)`: Return image content (base64 encoded)
|
|
292
|
+
- `response.audio(data: string, mimeType: string)`: Return audio content (base64 encoded)
|
|
293
|
+
- `response.structured(object: Record<string, unknown>)`: Return structured JSON data
|
|
294
|
+
- `response.resourceLink(uri: string)`: Return a link to a resource
|
|
295
|
+
- `response.error(message: string)`: Return an error message
|
|
296
|
+
- `response.send(content: Content | Content[])`: Send custom content objects
|
|
218
297
|
|
|
219
298
|
```typescript
|
|
220
|
-
async handle({ args, response }:
|
|
221
|
-
|
|
299
|
+
async handle({ args, response }: ToolContext<Schema>) {
|
|
300
|
+
// Return text
|
|
301
|
+
return response.text(JSON.stringify({ success: true }))
|
|
302
|
+
|
|
303
|
+
// Return structured data
|
|
304
|
+
return response.structured({
|
|
305
|
+
temperature: 22.5,
|
|
306
|
+
conditions: 'Partly cloudy',
|
|
307
|
+
humidity: 65
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
// Return image
|
|
311
|
+
const imageData = await fs.readFile('path/to/image.png', 'base64')
|
|
312
|
+
return response.image(imageData, 'image/png')
|
|
313
|
+
|
|
314
|
+
// Return a resource link
|
|
315
|
+
return response.resourceLink('file:///path/to/resource.txt')
|
|
222
316
|
|
|
223
|
-
|
|
317
|
+
// Return error
|
|
318
|
+
return response.error('Something went wrong')
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Resource Responses
|
|
323
|
+
|
|
324
|
+
For resources, you can use:
|
|
325
|
+
|
|
326
|
+
- `response.text(text: string)`: Return text content
|
|
327
|
+
- `response.blob(text: string)`: Return binary content (base64 encoded)
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
async handle({ response }: ResourceContext) {
|
|
331
|
+
const content = await fs.readFile('path/to/file.txt', 'utf-8')
|
|
332
|
+
return response.text(content)
|
|
224
333
|
}
|
|
225
334
|
```
|
|
226
335
|
|
|
@@ -229,8 +338,8 @@ async handle({ args, response }: Context) {
|
|
|
229
338
|
Here is a complete example of a tool that creates a bookmark:
|
|
230
339
|
|
|
231
340
|
```typescript
|
|
232
|
-
import type {
|
|
233
|
-
import type { BaseSchema
|
|
341
|
+
import type { ToolContext } from '@jrmc/adonis-mcp/types/context'
|
|
342
|
+
import type { BaseSchema } from '@jrmc/adonis-mcp/types/method'
|
|
234
343
|
|
|
235
344
|
import { Tool } from '@jrmc/adonis-mcp'
|
|
236
345
|
import Bookmark from '#models/bookmark'
|
|
@@ -240,14 +349,12 @@ type Schema = BaseSchema<{
|
|
|
240
349
|
url: { type: "string" }
|
|
241
350
|
}>
|
|
242
351
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
export default class AddBookmarkTool implements Tool<Schema> {
|
|
352
|
+
export default class AddBookmarkTool extends Tool<Schema> {
|
|
246
353
|
name = 'create_bookmark'
|
|
247
354
|
title = 'Create Bookmark'
|
|
248
355
|
description = 'Create a new bookmark'
|
|
249
356
|
|
|
250
|
-
async handle({ args, response, auth }:
|
|
357
|
+
async handle({ args, response, auth }: ToolContext<Schema>) {
|
|
251
358
|
const bookmark = await Bookmark.create({
|
|
252
359
|
title: args.title,
|
|
253
360
|
text: args.url,
|
|
@@ -276,9 +383,708 @@ export default class AddBookmarkTool implements Tool<Schema> {
|
|
|
276
383
|
}
|
|
277
384
|
```
|
|
278
385
|
|
|
386
|
+
## Advanced Features
|
|
387
|
+
|
|
388
|
+
### Structured Output
|
|
389
|
+
|
|
390
|
+
The `response.structured()` method allows you to return JSON data in a structured format. This is particularly useful when you want to return data that can be easily parsed and used by the MCP client without additional processing:
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
import type { ToolContext } from '@jrmc/adonis-mcp/types/context'
|
|
394
|
+
import { Tool } from '@jrmc/adonis-mcp'
|
|
395
|
+
|
|
396
|
+
export default class GetWeatherTool extends Tool {
|
|
397
|
+
name = 'get_weather'
|
|
398
|
+
title = 'Get Weather'
|
|
399
|
+
description = 'Get current weather data'
|
|
400
|
+
|
|
401
|
+
async handle({ args, response }: ToolContext) {
|
|
402
|
+
const weatherData = {
|
|
403
|
+
temperature: 22.5,
|
|
404
|
+
conditions: 'Partly cloudy',
|
|
405
|
+
humidity: 65,
|
|
406
|
+
windSpeed: 12,
|
|
407
|
+
location: args.location
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return response.structured(weatherData)
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Note:** Structured content can only be used in tools, not in prompts or resources.
|
|
416
|
+
|
|
417
|
+
### Resource Links
|
|
418
|
+
|
|
419
|
+
Resource links allow you to reference other resources in your tool responses. This is useful when you want to point to additional information without embedding the entire resource content:
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
import type { ToolContext } from '@jrmc/adonis-mcp/types/context'
|
|
423
|
+
import { Tool } from '@jrmc/adonis-mcp'
|
|
424
|
+
|
|
425
|
+
export default class GetDocumentationTool extends Tool {
|
|
426
|
+
name = 'get_documentation'
|
|
427
|
+
title = 'Get Documentation'
|
|
428
|
+
description = 'Get documentation for a specific topic'
|
|
429
|
+
|
|
430
|
+
async handle({ args, response }: ToolContext) {
|
|
431
|
+
return [
|
|
432
|
+
response.text('Here is the documentation for your topic:'),
|
|
433
|
+
response.resourceLink(`file:///docs/${args.topic}.md`)
|
|
434
|
+
]
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
The resource link will include metadata about the resource (name, mimeType, title, description, size) without fetching the actual content. The MCP client can then decide whether to fetch the resource content separately.
|
|
440
|
+
|
|
441
|
+
**Note:** Resource links can only be used in tools, not in prompts or resources.
|
|
442
|
+
|
|
443
|
+
### Metadata with `withMeta()`
|
|
444
|
+
|
|
445
|
+
The `withMeta()` method is available on all content types and allows you to attach custom metadata to your responses. This metadata can be used by MCP clients for various purposes such as logging, analytics, or custom processing:
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
async handle({ args, response }: ToolContext<Schema>) {
|
|
449
|
+
const users = await User.all()
|
|
450
|
+
|
|
451
|
+
return response.text(JSON.stringify(users)).withMeta({
|
|
452
|
+
source: 'database',
|
|
453
|
+
queryTime: Date.now(),
|
|
454
|
+
count: users.length,
|
|
455
|
+
cacheHit: false
|
|
456
|
+
})
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Metadata is particularly useful when:
|
|
461
|
+
- You want to provide debugging information
|
|
462
|
+
- You need to track the source of data
|
|
463
|
+
- You want to include performance metrics
|
|
464
|
+
- You need to pass additional context to the client
|
|
465
|
+
|
|
466
|
+
### Annotations
|
|
467
|
+
|
|
468
|
+
Annotations allow you to provide additional metadata about your tools and resources to help MCP clients better understand their behavior and characteristics.
|
|
469
|
+
|
|
470
|
+
#### Tool Annotations
|
|
471
|
+
|
|
472
|
+
Tools support the following annotations that describe their operational characteristics:
|
|
473
|
+
|
|
474
|
+
##### `@isReadOnly()`
|
|
475
|
+
|
|
476
|
+
Indicates that a tool only reads data and does not modify any state:
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
import { Tool } from '@jrmc/adonis-mcp'
|
|
480
|
+
import { isReadOnly } from '@jrmc/adonis-mcp/tool_annotations'
|
|
481
|
+
|
|
482
|
+
@isReadOnly()
|
|
483
|
+
export default class GetUserTool extends Tool {
|
|
484
|
+
name = 'get_user'
|
|
485
|
+
|
|
486
|
+
async handle({ args, response }: ToolContext) {
|
|
487
|
+
const user = await User.find(args.id)
|
|
488
|
+
return response.text(JSON.stringify(user))
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
You can also explicitly set it to false:
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
@isReadOnly(false)
|
|
497
|
+
export default class UpdateUserTool extends Tool {
|
|
498
|
+
// ...
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
##### `@isOpenWorld()`
|
|
503
|
+
|
|
504
|
+
Indicates that a tool can access information from the internet or external sources:
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
import { isOpenWorld } from '@jrmc/adonis-mcp/tool_annotations'
|
|
508
|
+
|
|
509
|
+
@isOpenWorld()
|
|
510
|
+
export default class FetchWeatherTool extends Tool {
|
|
511
|
+
name = 'fetch_weather'
|
|
512
|
+
|
|
513
|
+
async handle({ args, response }: ToolContext) {
|
|
514
|
+
const weather = await externalApi.getWeather(args.city)
|
|
515
|
+
return response.text(JSON.stringify(weather))
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
##### `@isDestructive()`
|
|
521
|
+
|
|
522
|
+
Indicates that a tool performs destructive operations like deleting data:
|
|
523
|
+
|
|
524
|
+
```typescript
|
|
525
|
+
import { isDestructive } from '@jrmc/adonis-mcp/tool_annotations'
|
|
526
|
+
|
|
527
|
+
@isDestructive()
|
|
528
|
+
export default class DeleteUserTool extends Tool {
|
|
529
|
+
name = 'delete_user'
|
|
530
|
+
|
|
531
|
+
async handle({ args, response }: ToolContext) {
|
|
532
|
+
await User.query().where('id', args.id).delete()
|
|
533
|
+
return response.text('User deleted successfully')
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
##### `@isIdempotent()`
|
|
539
|
+
|
|
540
|
+
Indicates that a tool can be safely called multiple times with the same arguments without causing different effects:
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
import { isIdempotent } from '@jrmc/adonis-mcp/tool_annotations'
|
|
544
|
+
|
|
545
|
+
@isIdempotent()
|
|
546
|
+
export default class SetUserStatusTool extends Tool {
|
|
547
|
+
name = 'set_user_status'
|
|
548
|
+
|
|
549
|
+
async handle({ args, response }: ToolContext) {
|
|
550
|
+
await User.query().where('id', args.id).update({ status: args.status })
|
|
551
|
+
return response.text('Status updated')
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
##### Combining Multiple Annotations
|
|
557
|
+
|
|
558
|
+
You can use multiple annotations on the same tool:
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
import { isReadOnly, isOpenWorld, isIdempotent } from '@jrmc/adonis-mcp/tool_annotations'
|
|
562
|
+
|
|
563
|
+
@isReadOnly()
|
|
564
|
+
@isOpenWorld()
|
|
565
|
+
@isIdempotent()
|
|
566
|
+
export default class SearchOnlineTool extends Tool {
|
|
567
|
+
name = 'search_online'
|
|
568
|
+
|
|
569
|
+
async handle({ args, response }: ToolContext) {
|
|
570
|
+
const results = await searchEngine.search(args.query)
|
|
571
|
+
return response.text(JSON.stringify(results))
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
#### Resource Annotations
|
|
577
|
+
|
|
578
|
+
Resources support the following annotations to provide additional context:
|
|
579
|
+
|
|
580
|
+
##### `@priority()`
|
|
581
|
+
|
|
582
|
+
Specifies the importance of a resource as a number between 0.0 and 1.0:
|
|
583
|
+
|
|
584
|
+
```typescript
|
|
585
|
+
import { Resource } from '@jrmc/adonis-mcp'
|
|
586
|
+
import { priority } from '@jrmc/adonis-mcp/annotations'
|
|
587
|
+
|
|
588
|
+
@priority(0.9)
|
|
589
|
+
export default class ImportantDocResource extends Resource {
|
|
590
|
+
name = 'important_doc.txt'
|
|
591
|
+
uri = 'file:///important_doc.txt'
|
|
592
|
+
|
|
593
|
+
async handle({ response }: ResourceContext) {
|
|
594
|
+
return response.text('Critical documentation content')
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
##### `@audience()`
|
|
600
|
+
|
|
601
|
+
Specifies the intended audience for a resource (user, assistant, or both):
|
|
602
|
+
|
|
603
|
+
```typescript
|
|
604
|
+
import { Resource } from '@jrmc/adonis-mcp'
|
|
605
|
+
import { audience } from '@jrmc/adonis-mcp/annotations'
|
|
606
|
+
import Role from '@jrmc/adonis-mcp/enums/role'
|
|
607
|
+
|
|
608
|
+
@audience(Role.USER)
|
|
609
|
+
export default class UserManualResource extends Resource {
|
|
610
|
+
name = 'user_manual.txt'
|
|
611
|
+
uri = 'file:///user_manual.txt'
|
|
612
|
+
|
|
613
|
+
async handle({ response }: ResourceContext) {
|
|
614
|
+
return response.text('User manual content')
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
You can also specify multiple audiences:
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
@audience([Role.USER, Role.ASSISTANT])
|
|
623
|
+
export default class SharedDocResource extends Resource {
|
|
624
|
+
// ...
|
|
625
|
+
}
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
##### `@lastModified()`
|
|
629
|
+
|
|
630
|
+
Indicates when a resource was last updated (ISO 8601 timestamp):
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
import { Resource } from '@jrmc/adonis-mcp'
|
|
634
|
+
import { lastModified } from '@jrmc/adonis-mcp/annotations'
|
|
635
|
+
|
|
636
|
+
@lastModified('2024-12-12T10:00:00Z')
|
|
637
|
+
export default class DocumentResource extends Resource {
|
|
638
|
+
name = 'document.txt'
|
|
639
|
+
uri = 'file:///document.txt'
|
|
640
|
+
|
|
641
|
+
async handle({ response }: ResourceContext) {
|
|
642
|
+
return response.text('Document content')
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
##### Combining Resource Annotations
|
|
648
|
+
|
|
649
|
+
You can use multiple annotations on the same resource:
|
|
650
|
+
|
|
651
|
+
```typescript
|
|
652
|
+
import { Resource } from '@jrmc/adonis-mcp'
|
|
653
|
+
import { priority, audience, lastModified } from '@jrmc/adonis-mcp/annotations'
|
|
654
|
+
import Role from '@jrmc/adonis-mcp/enums/role'
|
|
655
|
+
|
|
656
|
+
@priority(0.8)
|
|
657
|
+
@audience([Role.USER, Role.ASSISTANT])
|
|
658
|
+
@lastModified('2024-12-12T10:00:00Z')
|
|
659
|
+
export default class ApiDocResource extends Resource {
|
|
660
|
+
name = 'api_docs.txt'
|
|
661
|
+
uri = 'file:///api_docs.txt'
|
|
662
|
+
|
|
663
|
+
async handle({ response }: ResourceContext) {
|
|
664
|
+
return response.text('API documentation content')
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### Creating a Resource
|
|
670
|
+
|
|
671
|
+
To create a new resource, use the Ace command:
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
node ace make:mcp-resource my_resource
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
This command will create a file in `app/mcp/resources/my_resource.ts` with a base template:
|
|
678
|
+
|
|
679
|
+
```typescript
|
|
680
|
+
import type { ResourceContext } from '@jrmc/adonis-mcp/types/context'
|
|
681
|
+
|
|
682
|
+
import { Resource } from '@jrmc/adonis-mcp'
|
|
683
|
+
|
|
684
|
+
export default class MyResourceResource extends Resource {
|
|
685
|
+
name = 'example.txt'
|
|
686
|
+
uri = 'file:///example.txt'
|
|
687
|
+
mimeType = 'text/plain'
|
|
688
|
+
title = 'Resource title'
|
|
689
|
+
description = 'Resource description'
|
|
690
|
+
size = 0
|
|
691
|
+
|
|
692
|
+
async handle({ response }: ResourceContext) {
|
|
693
|
+
this.size = 1000
|
|
694
|
+
return response.text('Hello World')
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
### Resource Properties
|
|
700
|
+
|
|
701
|
+
Resources have the following properties:
|
|
702
|
+
|
|
703
|
+
- `name` (optional): The name of the resource
|
|
704
|
+
- `uri` (required): The unique identifier for the resource (must be unique)
|
|
705
|
+
- `mimeType` (optional): The MIME type of the resource
|
|
706
|
+
- `title` (optional): A human-readable title
|
|
707
|
+
- `description` (optional): A description of the resource
|
|
708
|
+
- `size` (optional): The size of the resource in bytes
|
|
709
|
+
|
|
710
|
+
### Resource Handler
|
|
711
|
+
|
|
712
|
+
The `handle` method returns the content of the resource. You can use `response.text()` for text content or `response.blob()` for binary content:
|
|
713
|
+
|
|
714
|
+
```typescript
|
|
715
|
+
async handle({ response }: ResourceContext) {
|
|
716
|
+
const content = await fs.readFile('path/to/file.txt', 'utf-8')
|
|
717
|
+
this.size = content.length
|
|
718
|
+
return response.text(content)
|
|
719
|
+
}
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### URI Templates
|
|
723
|
+
|
|
724
|
+
Resources support URI templates (RFC 6570) to create dynamic resources. This allows you to define resources with variable parts in their URIs:
|
|
725
|
+
|
|
726
|
+
```typescript
|
|
727
|
+
import type { ResourceContext } from '@jrmc/adonis-mcp/types/context'
|
|
728
|
+
import { Resource } from '@jrmc/adonis-mcp'
|
|
729
|
+
|
|
730
|
+
type Args = {
|
|
731
|
+
name: string
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
export default class RobotsResource extends Resource<Args> {
|
|
735
|
+
name = 'robots.txt'
|
|
736
|
+
uri = 'file:///{name}.txt'
|
|
737
|
+
mimeType = 'text/plain'
|
|
738
|
+
title = 'Robots file'
|
|
739
|
+
description = 'Dynamic robots.txt file'
|
|
740
|
+
|
|
741
|
+
async handle({ args, response }: ResourceContext<Args>) {
|
|
742
|
+
this.size = 1000
|
|
743
|
+
return response.text(`Hello World ${args?.name}`)
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
When a client requests `file:///robots.txt`, the template `file:///{name}.txt` will match and extract `name: "robots"` as an argument, which will be available in the `handle` method via `args.name`.
|
|
749
|
+
|
|
750
|
+
URI templates support various operators:
|
|
751
|
+
- `{name}` - Simple variable substitution
|
|
752
|
+
- `{/name}` - Path segment
|
|
753
|
+
- `{?name}` - Query parameter
|
|
754
|
+
- `{&name}` - Additional query parameter
|
|
755
|
+
- `{#name}` - Fragment identifier
|
|
756
|
+
- `{+name}` - Reserved characters allowed
|
|
757
|
+
- `{.name}` - Dot-prefixed segment
|
|
758
|
+
|
|
759
|
+
For more information, see [RFC 6570](https://www.rfc-editor.org/rfc/rfc6570).
|
|
760
|
+
|
|
761
|
+
### Creating a Prompt
|
|
762
|
+
|
|
763
|
+
To create a new prompt, use the Ace command:
|
|
764
|
+
|
|
765
|
+
```bash
|
|
766
|
+
node ace make:mcp-prompt my_prompt
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
This command will create a file in `app/mcp/prompts/my_prompt.ts` with a base template:
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
import type { PromptContext } from '@jrmc/adonis-mcp/types/context'
|
|
773
|
+
import type { BaseSchema } from '@jrmc/adonis-mcp/types/method'
|
|
774
|
+
|
|
775
|
+
import { Prompt } from '@jrmc/adonis-mcp'
|
|
776
|
+
|
|
777
|
+
type Schema = BaseSchema<{
|
|
778
|
+
text: { type: "string" }
|
|
779
|
+
}>
|
|
780
|
+
|
|
781
|
+
export default class MyPromptPrompt extends Prompt<Schema> {
|
|
782
|
+
name = 'my_prompt'
|
|
783
|
+
title = 'Prompt title'
|
|
784
|
+
description = 'Prompt description'
|
|
785
|
+
|
|
786
|
+
async handle({ args, response }: PromptContext<Schema>) {
|
|
787
|
+
return [
|
|
788
|
+
response.text('Hello, world!')
|
|
789
|
+
]
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
schema() {
|
|
793
|
+
return {
|
|
794
|
+
type: "object",
|
|
795
|
+
properties: {
|
|
796
|
+
text: {
|
|
797
|
+
type: "string",
|
|
798
|
+
description: "Description text argument"
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
required: ["text"]
|
|
802
|
+
} as Schema
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
### Prompt Schema
|
|
808
|
+
|
|
809
|
+
Prompts use the same schema definition system as tools, following the [JSON Schema](https://json-schema.org/) specification. You can also use Zod to define your schema:
|
|
810
|
+
|
|
811
|
+
```typescript
|
|
812
|
+
import * as z from 'zod'
|
|
813
|
+
|
|
814
|
+
const zodSchema = z.object({
|
|
815
|
+
code: z.string(),
|
|
816
|
+
language: z.string().optional()
|
|
817
|
+
})
|
|
818
|
+
|
|
819
|
+
schema() {
|
|
820
|
+
return z.toJSONSchema(
|
|
821
|
+
zodSchema,
|
|
822
|
+
{ io: "input" }
|
|
823
|
+
) as Schema
|
|
824
|
+
}
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
### Prompt Handler
|
|
828
|
+
|
|
829
|
+
The `handle` method for prompts returns an array of content objects. This allows you to return multiple pieces of content, including embedded resources:
|
|
830
|
+
|
|
831
|
+
```typescript
|
|
832
|
+
async handle({ args, response }: PromptContext<Schema>) {
|
|
833
|
+
return [
|
|
834
|
+
response.text(`Please review this code:\n\n${args.code}`),
|
|
835
|
+
response.embeddedResource('file:///example.txt')
|
|
836
|
+
]
|
|
837
|
+
}
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
### Prompt Response Methods
|
|
841
|
+
|
|
842
|
+
For prompts, you can use the same response methods as tools, but you must return an array:
|
|
843
|
+
|
|
844
|
+
- `response.text(text: string)`: Return plain text content
|
|
845
|
+
- `response.image(data: string, mimeType: string)`: Return image content (base64 encoded)
|
|
846
|
+
- `response.audio(data: string, mimeType: string)`: Return audio content (base64 encoded)
|
|
847
|
+
- `response.embeddedResource(uri: string)`: Embed another resource in the prompt response
|
|
848
|
+
|
|
849
|
+
All response methods also support the `withMeta()` method to add metadata:
|
|
850
|
+
|
|
851
|
+
```typescript
|
|
852
|
+
async handle({ args, response }: PromptContext<Schema>) {
|
|
853
|
+
return [
|
|
854
|
+
response.text('Here is the code to review:').withMeta({
|
|
855
|
+
language: args.language
|
|
856
|
+
}),
|
|
857
|
+
response.embeddedResource('file:///code.py'),
|
|
858
|
+
response.text('Please provide feedback.')
|
|
859
|
+
]
|
|
860
|
+
}
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
### Complete Prompt Example
|
|
864
|
+
|
|
865
|
+
Here is a complete example of a prompt for code review:
|
|
866
|
+
|
|
867
|
+
```typescript
|
|
868
|
+
import type { PromptContext } from '@jrmc/adonis-mcp/types/context'
|
|
869
|
+
import type { BaseSchema } from '@jrmc/adonis-mcp/types/method'
|
|
870
|
+
|
|
871
|
+
import { Prompt } from '@jrmc/adonis-mcp'
|
|
872
|
+
|
|
873
|
+
type Schema = BaseSchema<{
|
|
874
|
+
code: { type: "string" }
|
|
875
|
+
language: { type: "string" }
|
|
876
|
+
}>
|
|
877
|
+
|
|
878
|
+
export default class CodeReviewPrompt extends Prompt<Schema> {
|
|
879
|
+
name = 'code_review'
|
|
880
|
+
title = 'Code Review'
|
|
881
|
+
description = 'Review code and provide feedback'
|
|
882
|
+
|
|
883
|
+
async handle({ args, response }: PromptContext<Schema>) {
|
|
884
|
+
return [
|
|
885
|
+
response.text(`Please review this ${args.language} code:\n\n${args.code}`),
|
|
886
|
+
response.text('Provide feedback on code quality, potential bugs, and improvements.')
|
|
887
|
+
]
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
schema() {
|
|
891
|
+
return {
|
|
892
|
+
type: "object",
|
|
893
|
+
properties: {
|
|
894
|
+
code: {
|
|
895
|
+
type: "string",
|
|
896
|
+
description: "The code to review"
|
|
897
|
+
},
|
|
898
|
+
language: {
|
|
899
|
+
type: "string",
|
|
900
|
+
description: "Programming language"
|
|
901
|
+
}
|
|
902
|
+
},
|
|
903
|
+
required: ["code", "language"]
|
|
904
|
+
} as Schema
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
## Completions
|
|
910
|
+
|
|
911
|
+
Completions provide argument suggestions for prompts and resources, helping users fill in parameters interactively. This feature must be enabled in your configuration and can be implemented for both prompts and resources.
|
|
912
|
+
|
|
913
|
+
### Enabling Completions
|
|
914
|
+
|
|
915
|
+
First, enable completions in your `config/mcp.ts`:
|
|
916
|
+
|
|
917
|
+
```typescript
|
|
918
|
+
import { defineConfig } from '@jrmc/adonis-mcp'
|
|
919
|
+
|
|
920
|
+
export default defineConfig({
|
|
921
|
+
name: 'adonis-mcp-server',
|
|
922
|
+
version: '1.0.0',
|
|
923
|
+
completions: true, // Enable completions
|
|
924
|
+
})
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
### Implementing Completions in Prompts
|
|
928
|
+
|
|
929
|
+
Add a `complete()` method to your prompt to provide argument suggestions:
|
|
930
|
+
|
|
931
|
+
```typescript
|
|
932
|
+
import type { PromptContext, CompleteContext } from '@jrmc/adonis-mcp/types/context'
|
|
933
|
+
import type { BaseSchema } from '@jrmc/adonis-mcp/types/method'
|
|
934
|
+
|
|
935
|
+
import { Prompt } from '@jrmc/adonis-mcp'
|
|
936
|
+
|
|
937
|
+
type Schema = BaseSchema<{
|
|
938
|
+
language: { type: "string" }
|
|
939
|
+
code: { type: "string" }
|
|
940
|
+
}>
|
|
941
|
+
|
|
942
|
+
export default class CodeReviewPrompt extends Prompt<Schema> {
|
|
943
|
+
name = 'code_review'
|
|
944
|
+
title = 'Code Review'
|
|
945
|
+
description = 'Review code and provide feedback'
|
|
946
|
+
|
|
947
|
+
async handle({ args, response }: PromptContext<Schema>) {
|
|
948
|
+
return [
|
|
949
|
+
response.text(`Please review this ${args.language} code:\n\n${args.code}`)
|
|
950
|
+
]
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
async complete({ args, response }: CompleteContext<Schema>) {
|
|
954
|
+
// Provide language suggestions when the user types
|
|
955
|
+
if (args?.language !== undefined) {
|
|
956
|
+
return response.complete({
|
|
957
|
+
values: ['python', 'javascript', 'typescript', 'java', 'go', 'rust']
|
|
958
|
+
})
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
return response.complete({ values: [] })
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
schema() {
|
|
965
|
+
return {
|
|
966
|
+
type: "object",
|
|
967
|
+
properties: {
|
|
968
|
+
language: {
|
|
969
|
+
type: "string",
|
|
970
|
+
description: "Programming language"
|
|
971
|
+
},
|
|
972
|
+
code: {
|
|
973
|
+
type: "string",
|
|
974
|
+
description: "Code to review"
|
|
975
|
+
}
|
|
976
|
+
},
|
|
977
|
+
required: ["language", "code"]
|
|
978
|
+
} as Schema
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
### Implementing Completions in Resources
|
|
984
|
+
|
|
985
|
+
Resources with URI templates can also provide completions for their path parameters:
|
|
986
|
+
|
|
987
|
+
```typescript
|
|
988
|
+
import type { ResourceContext, CompleteContext } from '@jrmc/adonis-mcp/types/context'
|
|
989
|
+
import { Resource } from '@jrmc/adonis-mcp'
|
|
990
|
+
|
|
991
|
+
type Args = {
|
|
992
|
+
directory: string
|
|
993
|
+
name: string
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
export default class ConfigFileResource extends Resource<Args> {
|
|
997
|
+
name = 'config_file'
|
|
998
|
+
uri = 'file://{directory}/{name}.txt'
|
|
999
|
+
mimeType = 'text/plain'
|
|
1000
|
+
title = 'Configuration File'
|
|
1001
|
+
description = 'Access configuration files'
|
|
1002
|
+
|
|
1003
|
+
async handle({ args, response }: ResourceContext<Args>) {
|
|
1004
|
+
const content = await readConfigFile(args.directory, args.name)
|
|
1005
|
+
return response.text(content)
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
async complete({ args, response }: CompleteContext<Args>) {
|
|
1009
|
+
// Provide suggestions based on available directories and files
|
|
1010
|
+
if (args?.name !== undefined) {
|
|
1011
|
+
return response.complete({
|
|
1012
|
+
values: ['config', 'settings', 'environment', 'database']
|
|
1013
|
+
})
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
if (args?.directory !== undefined) {
|
|
1017
|
+
return response.complete({
|
|
1018
|
+
values: ['production', 'staging', 'development']
|
|
1019
|
+
})
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
return response.complete({ values: [] })
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
### Completion Context
|
|
1028
|
+
|
|
1029
|
+
The `complete()` method receives a `CompleteContext` that includes:
|
|
1030
|
+
|
|
1031
|
+
- `args`: The current argument values (partial or complete)
|
|
1032
|
+
- `response`: The response object with a `complete()` method
|
|
1033
|
+
|
|
1034
|
+
The response format includes:
|
|
1035
|
+
|
|
1036
|
+
```typescript
|
|
1037
|
+
response.complete({
|
|
1038
|
+
values: string[], // Array of suggested values
|
|
1039
|
+
hasMore?: boolean, // Optional: indicates if more values are available
|
|
1040
|
+
total?: number // Optional: total number of available values
|
|
1041
|
+
})
|
|
1042
|
+
```
|
|
1043
|
+
|
|
1044
|
+
### Transports
|
|
1045
|
+
|
|
1046
|
+
The package supports multiple transport mechanisms:
|
|
1047
|
+
|
|
1048
|
+
- **HTTP Transport**: Default transport for HTTP-based MCP servers (used when accessing via HTTP routes)
|
|
1049
|
+
- **Stdio Transport**: For command-line MCP servers that communicate via standard input/output
|
|
1050
|
+
- **Fake Transport**: For testing purposes, allows you to capture and inspect MCP messages
|
|
1051
|
+
|
|
279
1052
|
### Pagination
|
|
280
1053
|
|
|
281
|
-
The `tools/list`
|
|
1054
|
+
The `tools/list` and `resources/list` methods support cursor-based pagination to handle large numbers of tools and resources efficiently. This is particularly useful when you have many tools or resources registered in your application. [More information](https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/pagination)
|
|
1055
|
+
|
|
1056
|
+
## Testing & Debugging
|
|
1057
|
+
|
|
1058
|
+
### MCP Inspector
|
|
1059
|
+
|
|
1060
|
+
The MCP Inspector is a powerful tool for debugging and testing your MCP server. It provides a graphical interface to interact with your tools, resources, and prompts.
|
|
1061
|
+
|
|
1062
|
+
To open the MCP Inspector, use the following command:
|
|
1063
|
+
|
|
1064
|
+
```bash
|
|
1065
|
+
node ace mcp:inspector
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
By default, this command uses HTTP transport. You can specify a different transport type:
|
|
1069
|
+
|
|
1070
|
+
```bash
|
|
1071
|
+
# Use HTTP transport (default)
|
|
1072
|
+
node ace mcp:inspector http
|
|
1073
|
+
|
|
1074
|
+
# Use stdio transport
|
|
1075
|
+
node ace mcp:inspector stdio
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
**Important notes:**
|
|
1079
|
+
|
|
1080
|
+
- The inspector can only be used in development environment (not in production)
|
|
1081
|
+
- For HTTP transport, make sure your server is running and the MCP route is configured
|
|
1082
|
+
- The inspector will automatically connect to your MCP server and allow you to:
|
|
1083
|
+
- List and test all available tools
|
|
1084
|
+
- Browse and read resources
|
|
1085
|
+
- Execute prompts with different arguments
|
|
1086
|
+
- Inspect request/response payloads
|
|
1087
|
+
- Debug any issues with your MCP implementation
|
|
282
1088
|
|
|
283
1089
|
## Support
|
|
284
1090
|
|