@jrmc/adonis-mcp 1.0.0-alpha.3 → 1.0.0-alpha.8
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 +282 -0
- package/build/commands/commands.json +1 -1
- package/build/commands/make/tool.d.ts +2 -0
- package/build/commands/make/tool.d.ts.map +1 -1
- package/build/commands/make/tool.js +6 -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 +2 -4
- package/build/providers/mcp_provider.d.ts.map +1 -1
- package/build/providers/mcp_provider.js +18 -34
- package/build/src/Transport/http_transport.d.ts +16 -0
- package/build/src/Transport/http_transport.d.ts.map +1 -0
- package/build/src/Transport/http_transport.js +24 -0
- package/build/src/context.d.ts +27 -0
- package/build/src/context.d.ts.map +1 -0
- package/build/src/context.js +32 -0
- package/build/src/controllers/mcp_controller.d.ts +1 -3
- package/build/src/controllers/mcp_controller.d.ts.map +1 -1
- package/build/src/controllers/mcp_controller.js +6 -59
- package/build/src/define_config.d.ts +1 -1
- package/build/src/define_config.d.ts.map +1 -1
- package/build/src/enums/error.d.ts +16 -0
- package/build/src/enums/error.d.ts.map +1 -0
- package/build/src/enums/error.js +18 -0
- package/build/src/enums/role.d.ts +12 -0
- package/build/src/enums/role.d.ts.map +1 -0
- package/build/src/enums/role.js +12 -0
- package/build/src/request.d.ts +9 -0
- package/build/src/request.d.ts.map +1 -0
- package/build/src/request.js +8 -0
- package/build/src/response.d.ts +32 -0
- package/build/src/response.d.ts.map +1 -0
- package/build/src/response.js +33 -0
- package/build/src/server/methods/call_tool.d.ts +12 -0
- package/build/src/server/methods/call_tool.d.ts.map +1 -0
- package/build/src/server/methods/call_tool.js +39 -0
- package/build/src/server/methods/get_prompt.d.ts +12 -0
- package/build/src/server/methods/get_prompt.d.ts.map +1 -0
- package/build/src/server/methods/get_prompt.js +12 -0
- package/build/src/server/methods/initialize.d.ts +12 -0
- package/build/src/server/methods/initialize.d.ts.map +1 -0
- package/build/src/server/methods/initialize.js +30 -0
- package/build/src/server/methods/list_prompts.d.ts +12 -0
- package/build/src/server/methods/list_prompts.d.ts.map +1 -0
- package/build/src/server/methods/list_prompts.js +12 -0
- package/build/src/server/methods/list_resources.d.ts +12 -0
- package/build/src/server/methods/list_resources.d.ts.map +1 -0
- package/build/src/server/methods/list_resources.js +12 -0
- package/build/src/server/methods/list_tools.d.ts +12 -0
- package/build/src/server/methods/list_tools.d.ts.map +1 -0
- package/build/src/server/methods/list_tools.js +54 -0
- package/build/src/server/methods/ping.d.ts +12 -0
- package/build/src/server/methods/ping.d.ts.map +1 -0
- package/build/src/server/methods/ping.js +12 -0
- package/build/src/server/methods/read_resource.d.ts +12 -0
- package/build/src/server/methods/read_resource.d.ts.map +1 -0
- package/build/src/server/methods/read_resource.js +12 -0
- package/build/src/server/pagination/cursor_paginator.d.ts +12 -0
- package/build/src/server/pagination/cursor_paginator.d.ts.map +1 -0
- package/build/src/server/pagination/cursor_paginator.js +48 -0
- package/build/src/server/tool.d.ts +18 -0
- package/build/src/server/tool.d.ts.map +1 -0
- package/build/src/server/tool.js +8 -0
- package/build/src/server.d.ts +43 -0
- package/build/src/server.d.ts.map +1 -0
- package/build/src/server.js +115 -0
- package/build/src/types/config.d.ts +15 -0
- package/build/src/types/config.d.ts.map +1 -0
- package/build/src/types/config.js +7 -0
- package/build/src/types/context.d.ts +26 -0
- package/build/src/types/context.d.ts.map +1 -0
- package/build/src/types/context.js +7 -0
- package/build/src/types/method.d.ts +37 -0
- package/build/src/types/method.d.ts.map +1 -0
- package/build/src/types/method.js +7 -0
- package/build/src/types/notification.d.ts +14 -0
- package/build/src/types/notification.d.ts.map +1 -0
- package/build/src/types/notification.js +7 -0
- package/build/src/types/request.d.ts +44 -0
- package/build/src/types/request.d.ts.map +1 -0
- package/build/src/types/request.js +7 -0
- package/build/src/types/response.d.ts +46 -0
- package/build/src/types/response.d.ts.map +1 -0
- package/build/src/types/response.js +7 -0
- package/build/src/types/transport.d.ts +12 -0
- package/build/src/types/transport.d.ts.map +1 -0
- package/build/src/types/transport.js +7 -0
- package/build/stubs/config.ts.stub +3 -1
- package/build/stubs/make/mcp/tools/main.ts.stub +31 -9
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -6
- package/build/commands/make/prompt.d.ts +0 -14
- package/build/commands/make/prompt.d.ts.map +0 -1
- package/build/commands/make/prompt.js +0 -30
- package/build/commands/make/resource.d.ts +0 -14
- package/build/commands/make/resource.d.ts.map +0 -1
- package/build/commands/make/resource.js +0 -30
- package/build/src/mcp.d.ts +0 -22
- package/build/src/mcp.d.ts.map +0 -1
- package/build/src/mcp.js +0 -32
- package/build/src/types.d.ts +0 -49
- package/build/src/types.d.ts.map +0 -1
- package/build/src/types.js +0 -8
package/README.md
CHANGED
|
@@ -5,3 +5,285 @@
|
|
|
5
5
|
|
|
6
6
|
AdonisJS MCP - Server MCP for your AdonisJS applications.
|
|
7
7
|
|
|
8
|
+
## Roadmap
|
|
9
|
+
|
|
10
|
+
- [x] MCP prompts support
|
|
11
|
+
- [ ] MCP resources support
|
|
12
|
+
- [ ] MCP prompts support
|
|
13
|
+
- [ ] Alternative transports support (SSE, stdio)
|
|
14
|
+
- [x] Advanced pagination support
|
|
15
|
+
- [ ] Automatic schema validation with Vine ??
|
|
16
|
+
|
|
17
|
+
## Installation & Configuration
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
node ace add @jrmc/adonis-mcp
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This will create a configuration file `config/mcp.ts`:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { defineConfig } from '@jrmc/adonis-mcp'
|
|
27
|
+
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
name: 'adonis-mcp-server',
|
|
30
|
+
version: '1.0.0',
|
|
31
|
+
path: 'app/mcp', // Path where your tools will be stored
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
### Creating a Tool
|
|
38
|
+
|
|
39
|
+
To create a new tool, use the Ace command:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
node ace make:mcp-tool my_tool
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This command will create a file in `app/mcp/tools/my_tool.ts` with a base template:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import type { McpContext } from '@jrmc/adonis-mcp/types/context'
|
|
49
|
+
import type { BaseSchema, InferJSONSchema } from '@jrmc/adonis-mcp/types/method'
|
|
50
|
+
|
|
51
|
+
import { Tool } from '@jrmc/adonis-mcp'
|
|
52
|
+
|
|
53
|
+
type Schema = BaseSchema<{
|
|
54
|
+
text: { type: "string" }
|
|
55
|
+
}>
|
|
56
|
+
|
|
57
|
+
type Context = McpContext & { args: InferJSONSchema<Schema> }
|
|
58
|
+
|
|
59
|
+
export default class MyToolTool implements Tool<Schema> {
|
|
60
|
+
name = 'tool_name'
|
|
61
|
+
title = 'Tool title'
|
|
62
|
+
description = 'Tool description'
|
|
63
|
+
|
|
64
|
+
async handle({ args }: Context) {
|
|
65
|
+
console.log(args.text)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
schema() {
|
|
69
|
+
return {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
text: {
|
|
73
|
+
type: "string",
|
|
74
|
+
description: "Description text argument"
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
required: ["text"]
|
|
78
|
+
} as Schema
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Schema Definition
|
|
84
|
+
|
|
85
|
+
The schema defines the input parameters of your tool. It follows the [JSON Schema](https://json-schema.org/) specification:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
schema() {
|
|
89
|
+
return {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: {
|
|
92
|
+
title: {
|
|
93
|
+
type: "string",
|
|
94
|
+
description: "Bookmark title"
|
|
95
|
+
},
|
|
96
|
+
url: {
|
|
97
|
+
type: "string",
|
|
98
|
+
description: "Bookmark URL"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
required: ["title", "url"]
|
|
102
|
+
} as Schema
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
You can also use Zod to define your schema:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import * as z from 'zod'
|
|
110
|
+
|
|
111
|
+
const zodSchema = z.object({
|
|
112
|
+
page: z.number().optional(),
|
|
113
|
+
perPage: z.number().optional()
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
schema() {
|
|
117
|
+
return z.toJSONSchema(
|
|
118
|
+
zodSchema,
|
|
119
|
+
{ io: "input" }
|
|
120
|
+
) as Schema
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Handler Implementation
|
|
125
|
+
|
|
126
|
+
The `handle` method contains your tool's logic. It receives a typed context with validated arguments:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
async handle({ args, response, auth, bouncer }: Context) {
|
|
130
|
+
// Your logic here
|
|
131
|
+
const result = await SomeModel.query().where('id', args.id)
|
|
132
|
+
|
|
133
|
+
return response.text(JSON.stringify({ result }))
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Setting up Authentication and Bouncer
|
|
138
|
+
|
|
139
|
+
To use `auth` and `bouncer` in your MCP tools, add the following TypeScript declaration in your middleware (e.g., in your Bouncer initialization middleware):
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
declare module '@jrmc/adonis-mcp/types/context' {
|
|
143
|
+
export interface McpContext {
|
|
144
|
+
auth?: {
|
|
145
|
+
user?: HttpContext['auth']['user']
|
|
146
|
+
}
|
|
147
|
+
bouncer?: Bouncer<
|
|
148
|
+
Exclude<HttpContext['auth']['user'], undefined>,
|
|
149
|
+
typeof abilities,
|
|
150
|
+
typeof policies
|
|
151
|
+
>
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The MCP context automatically binds `auth` and `bouncer` from the `HttpContext` if they are available, so make sure your middleware initializes them on the `HttpContext` first.
|
|
157
|
+
|
|
158
|
+
#### Registering the MCP Route
|
|
159
|
+
|
|
160
|
+
In your `start/routes.ts` file, register the MCP route and apply middleware:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { middleware } from '#start/kernel'
|
|
164
|
+
import router from '@adonisjs/core/services/router'
|
|
165
|
+
|
|
166
|
+
// Register MCP route (defaults to /mcp, or specify a custom path)
|
|
167
|
+
router.mcp().use(middleware.auth())
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
You can also specify a custom path:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
router.mcp('/custom-mcp-path').use(middleware.auth())
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Using Authentication
|
|
177
|
+
|
|
178
|
+
The MCP context automatically includes the `auth` instance from the `HttpContext` if available. You can use it to access the authenticated user:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
async handle({ args, auth }: Context) {
|
|
182
|
+
const user = auth?.user
|
|
183
|
+
|
|
184
|
+
if (!user) {
|
|
185
|
+
throw new Error('User not authenticated')
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Use the authenticated user
|
|
189
|
+
const bookmark = await Bookmark.create({
|
|
190
|
+
title: args.title,
|
|
191
|
+
userId: user.id,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
return response.text(JSON.stringify({ bookmark }))
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Using Bouncer
|
|
199
|
+
|
|
200
|
+
The MCP context automatically includes the `bouncer` instance from the `HttpContext` if available. You can use it to check permissions:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
async handle({ args, bouncer }: Context) {
|
|
204
|
+
// Check a permission
|
|
205
|
+
await bouncer.authorize('viewUsers')
|
|
206
|
+
|
|
207
|
+
// Or use a policy
|
|
208
|
+
const user = await User.findOrFail(args.userId)
|
|
209
|
+
await bouncer.with(UserPolicy).authorize('view', user)
|
|
210
|
+
|
|
211
|
+
return response.text(JSON.stringify({ user }))
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Response Return
|
|
216
|
+
|
|
217
|
+
The context includes a `response` instance to format your responses. The most common method is `text()`:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
async handle({ args, response }: Context) {
|
|
221
|
+
const data = { success: true, message: 'Operation completed' }
|
|
222
|
+
|
|
223
|
+
return response.text(JSON.stringify(data))
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Complete Example
|
|
228
|
+
|
|
229
|
+
Here is a complete example of a tool that creates a bookmark:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import type { McpContext } from '@jrmc/adonis-mcp/types/context'
|
|
233
|
+
import type { BaseSchema, InferJSONSchema } from '@jrmc/adonis-mcp/types/method'
|
|
234
|
+
|
|
235
|
+
import { Tool } from '@jrmc/adonis-mcp'
|
|
236
|
+
import Bookmark from '#models/bookmark'
|
|
237
|
+
|
|
238
|
+
type Schema = BaseSchema<{
|
|
239
|
+
title: { type: "string" }
|
|
240
|
+
url: { type: "string" }
|
|
241
|
+
}>
|
|
242
|
+
|
|
243
|
+
type Context = McpContext & { args: InferJSONSchema<Schema> }
|
|
244
|
+
|
|
245
|
+
export default class AddBookmarkTool implements Tool<Schema> {
|
|
246
|
+
name = 'create_bookmark'
|
|
247
|
+
title = 'Create Bookmark'
|
|
248
|
+
description = 'Create a new bookmark'
|
|
249
|
+
|
|
250
|
+
async handle({ args, response, auth }: Context) {
|
|
251
|
+
const bookmark = await Bookmark.create({
|
|
252
|
+
title: args.title,
|
|
253
|
+
text: args.url,
|
|
254
|
+
userId: auth?.user?.id,
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
return response.text(JSON.stringify({ bookmark }))
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
schema() {
|
|
261
|
+
return {
|
|
262
|
+
type: "object",
|
|
263
|
+
properties: {
|
|
264
|
+
title: {
|
|
265
|
+
type: "string",
|
|
266
|
+
description: "Bookmark title"
|
|
267
|
+
},
|
|
268
|
+
url: {
|
|
269
|
+
type: "string",
|
|
270
|
+
description: "Bookmark URL"
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
required: ["title", "url"]
|
|
274
|
+
} as Schema
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Pagination
|
|
280
|
+
|
|
281
|
+
The `tools/list` method supports cursor-based pagination to handle large numbers of tools efficiently. This is particularly useful when you have many tools registered in your application. [More information](https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/pagination)
|
|
282
|
+
|
|
283
|
+
## Support
|
|
284
|
+
|
|
285
|
+
For any questions or issues, please open an issue on the [GitHub repository](https://github.com/batosai/adonis-mcp).
|
|
286
|
+
|
|
287
|
+
## Inspiration
|
|
288
|
+
|
|
289
|
+
This package is inspired by [laravel/mcp](https://github.com/laravel/mcp).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"commands":[{"commandName":"make:mcp-
|
|
1
|
+
{"commands":[{"commandName":"make:mcp-tool","description":"Create a new MCP tool","help":"","namespace":"make","aliases":[],"flags":[],"args":[{"name":"name","argumentName":"name","required":true,"description":"Name of the tool","type":"string"}],"options":{"startApp":true},"filePath":"make/tool.js"}],"version":1}
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
|
|
6
6
|
*/
|
|
7
|
+
import type { CommandOptions } from '@adonisjs/core/types/ace';
|
|
7
8
|
import { BaseCommand } from '@adonisjs/core/ace';
|
|
8
9
|
export default class MakeTool extends BaseCommand {
|
|
9
10
|
static commandName: string;
|
|
10
11
|
static description: string;
|
|
12
|
+
static options: CommandOptions;
|
|
11
13
|
name: string;
|
|
12
14
|
run(): Promise<void>;
|
|
13
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../commands/make/tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAQ,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAItD,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,WAAW;IAC/C,MAAM,CAAC,WAAW,SAAkB;IACpC,MAAM,CAAC,WAAW,SAA0B;
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../commands/make/tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAG9D,OAAO,EAAQ,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAItD,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,WAAW;IAC/C,MAAM,CAAC,WAAW,SAAkB;IACpC,MAAM,CAAC,WAAW,SAA0B;IAE5C,MAAM,CAAC,OAAO,EAAE,cAAc,CAE7B;IAGO,IAAI,EAAE,MAAM,CAAA;IAEd,GAAG;CAYV"}
|
|
@@ -16,11 +16,16 @@ import { stubsRoot } from '../../stubs/main.js';
|
|
|
16
16
|
export default class MakeTool extends BaseCommand {
|
|
17
17
|
static commandName = 'make:mcp-tool';
|
|
18
18
|
static description = 'Create a new MCP tool';
|
|
19
|
+
static options = {
|
|
20
|
+
startApp: true,
|
|
21
|
+
};
|
|
19
22
|
async run() {
|
|
23
|
+
const config = this.app.config.get('mcp', { path: 'app/mcp' });
|
|
20
24
|
const codemods = await this.createCodemods();
|
|
21
25
|
const stubPath = `make/mcp/tools/main.ts.stub`;
|
|
22
26
|
await codemods.makeUsingStub(stubsRoot, stubPath, {
|
|
23
|
-
|
|
27
|
+
name: string.pascalCase(this.name),
|
|
28
|
+
basePath: config.path,
|
|
24
29
|
});
|
|
25
30
|
this.logger.success(`Tool created successfully for: ${this.name}`);
|
|
26
31
|
}
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC3C,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA"}
|
package/build/index.js
CHANGED
|
@@ -6,15 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { ApplicationService } from '@adonisjs/core/types';
|
|
8
8
|
import type { RouteGroup } from '@adonisjs/core/http';
|
|
9
|
-
import
|
|
9
|
+
import McpServer from '../src/server.js';
|
|
10
10
|
export default class McpProvider {
|
|
11
11
|
protected app: ApplicationService;
|
|
12
12
|
constructor(app: ApplicationService);
|
|
13
13
|
register(): void;
|
|
14
14
|
start(): Promise<void>;
|
|
15
15
|
registerTools(): Promise<void>;
|
|
16
|
-
registerResources(): Promise<void>;
|
|
17
|
-
registerPrompts(): Promise<void>;
|
|
18
16
|
}
|
|
19
17
|
declare module '@adonisjs/core/http' {
|
|
20
18
|
interface Router {
|
|
@@ -23,7 +21,7 @@ declare module '@adonisjs/core/http' {
|
|
|
23
21
|
}
|
|
24
22
|
declare module '@adonisjs/core/types' {
|
|
25
23
|
interface ContainerBindings {
|
|
26
|
-
'jrmc.mcp':
|
|
24
|
+
'jrmc.mcp': McpServer;
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
27
|
//# sourceMappingURL=mcp_provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp_provider.d.ts","sourceRoot":"","sources":["../../providers/mcp_provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"mcp_provider.d.ts","sourceRoot":"","sources":["../../providers/mcp_provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAKrD,OAAO,SAAS,MAAM,kBAAkB,CAAA;AAExC,MAAM,CAAC,OAAO,OAAO,WAAW;IAClB,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,QAAQ;IAQF,KAAK;IAeL,aAAa;CA4CpB;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,UAAU,CAAA;KACtC;CACF;AAED,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,iBAAiB;QACzB,UAAU,EAAE,SAAS,CAAA;KACtB;CACF"}
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
7
|
+
// import type { Tool } from '../src/types.js'
|
|
8
|
+
import { fsReadAll } from '@adonisjs/core/helpers';
|
|
9
|
+
import McpServer from '../src/server.js';
|
|
9
10
|
export default class McpProvider {
|
|
10
11
|
app;
|
|
11
12
|
constructor(app) {
|
|
@@ -14,7 +15,7 @@ export default class McpProvider {
|
|
|
14
15
|
register() {
|
|
15
16
|
this.app.container.singleton('jrmc.mcp', async () => {
|
|
16
17
|
const config = this.app.config.get('mcp', {});
|
|
17
|
-
return new
|
|
18
|
+
return new McpServer(config);
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
21
|
async start() {
|
|
@@ -22,43 +23,26 @@ export default class McpProvider {
|
|
|
22
23
|
const McpController = () => import('../src/controllers/mcp_controller.js');
|
|
23
24
|
router.mcp = (pattern = '/mcp') => {
|
|
24
25
|
return router.group(() => {
|
|
25
|
-
router.get(pattern, [McpController, 'get']);
|
|
26
26
|
router.post(pattern, [McpController, 'post']);
|
|
27
|
-
router.delete(pattern, [McpController, 'delete']);
|
|
28
27
|
});
|
|
29
28
|
};
|
|
30
29
|
await this.registerTools();
|
|
31
|
-
await this.registerResources()
|
|
32
|
-
await this.registerPrompts()
|
|
30
|
+
// await this.registerResources()
|
|
31
|
+
// await this.registerPrompts()
|
|
33
32
|
}
|
|
34
33
|
async registerTools() {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Object.values(collection).map((item) => {
|
|
40
|
-
const toolMcp = new item();
|
|
41
|
-
mcp.getServer().registerTool(toolMcp.name, toolMcp.config, toolMcp.handle);
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
async registerResources() {
|
|
45
|
-
const mcp = await this.app.container.make('jrmc.mcp');
|
|
46
|
-
const collection = await fsImportAll(new URL(this.app.makePath(mcp.config.path), import.meta.url), {
|
|
47
|
-
filter: (filePath) => filePath.includes('_resource.ts')
|
|
48
|
-
});
|
|
49
|
-
Object.values(collection).map((item) => {
|
|
50
|
-
const resourceMcp = new item();
|
|
51
|
-
mcp.getServer().registerResource(resourceMcp.name, resourceMcp.uriOrTemplate, resourceMcp.config, resourceMcp.handle);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
async registerPrompts() {
|
|
55
|
-
const mcp = await this.app.container.make('jrmc.mcp');
|
|
56
|
-
const collection = await fsImportAll(new URL(this.app.makePath(mcp.config.path), import.meta.url), {
|
|
57
|
-
filter: (filePath) => filePath.includes('_prompt.ts')
|
|
58
|
-
});
|
|
59
|
-
Object.values(collection).map((item) => {
|
|
60
|
-
const promptMcp = new item();
|
|
61
|
-
mcp.getServer().registerPrompt(promptMcp.name, promptMcp.config, promptMcp.handle);
|
|
34
|
+
const server = await this.app.container.make('jrmc.mcp');
|
|
35
|
+
const path = this.app.makePath(server.config.path);
|
|
36
|
+
const files = await fsReadAll(path, {
|
|
37
|
+
filter: (filePath) => filePath.includes('_tool.ts'),
|
|
62
38
|
});
|
|
39
|
+
await Promise.all(files.map(async (file) => {
|
|
40
|
+
const path = this.app.makePath(server.config.path, file);
|
|
41
|
+
const { default: tool } = await import(path);
|
|
42
|
+
const toolInstance = new tool();
|
|
43
|
+
server.addTool({
|
|
44
|
+
[toolInstance.name]: path,
|
|
45
|
+
});
|
|
46
|
+
}));
|
|
63
47
|
}
|
|
64
48
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jrmc/adonis-mcp
|
|
3
|
+
*
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
|
|
6
|
+
*/
|
|
7
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
8
|
+
import type { McpContext } from '../types/context.js';
|
|
9
|
+
import type { Transport } from '../types/transport.js';
|
|
10
|
+
export default class HttpTransport implements Transport {
|
|
11
|
+
protected ctx: HttpContext;
|
|
12
|
+
constructor(ctx: HttpContext);
|
|
13
|
+
bindBouncer(mcpContext: McpContext): void;
|
|
14
|
+
bindAuth(mcpContext: McpContext): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=http_transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http_transport.d.ts","sourceRoot":"","sources":["../../../src/Transport/http_transport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AAEtD,MAAM,CAAC,OAAO,OAAO,aAAc,YAAW,SAAS;IACzC,SAAS,CAAC,GAAG,EAAE,WAAW;gBAAhB,GAAG,EAAE,WAAW;IAEtC,WAAW,CAAC,UAAU,EAAE,UAAU;IAMlC,QAAQ,CAAC,UAAU,EAAE,UAAU;CAKhC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jrmc/adonis-mcp
|
|
3
|
+
*
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
|
|
6
|
+
*/
|
|
7
|
+
export default class HttpTransport {
|
|
8
|
+
ctx;
|
|
9
|
+
constructor(ctx) {
|
|
10
|
+
this.ctx = ctx;
|
|
11
|
+
}
|
|
12
|
+
bindBouncer(mcpContext) {
|
|
13
|
+
if ('bouncer' in this.ctx) {
|
|
14
|
+
;
|
|
15
|
+
mcpContext.bouncer = this.ctx.bouncer;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
bindAuth(mcpContext) {
|
|
19
|
+
if ('auth' in this.ctx) {
|
|
20
|
+
;
|
|
21
|
+
mcpContext.auth = this.ctx.auth;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jrmc/adonis-mcp
|
|
3
|
+
*
|
|
4
|
+
* @license MIT
|
|
5
|
+
* @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
|
|
6
|
+
*/
|
|
7
|
+
import type { McpContext, ServerContextOptions } from './types/context.js';
|
|
8
|
+
import type { McpRequest } from './types/request.js';
|
|
9
|
+
import type { ToolList, ResourceList, PromptList } from './types/method.js';
|
|
10
|
+
import McpResponse from './response.js';
|
|
11
|
+
export default class ServerContext implements McpContext {
|
|
12
|
+
supportedProtocolVersions: string[];
|
|
13
|
+
serverCapabilities: Record<string, any>;
|
|
14
|
+
serverName: string;
|
|
15
|
+
serverVersion: string;
|
|
16
|
+
instructions: string;
|
|
17
|
+
maxPaginationLength: number;
|
|
18
|
+
defaultPaginationLength: number;
|
|
19
|
+
tools: ToolList;
|
|
20
|
+
resources: ResourceList;
|
|
21
|
+
prompts: PromptList;
|
|
22
|
+
request: McpRequest;
|
|
23
|
+
response: McpResponse;
|
|
24
|
+
constructor(options: ServerContextOptions);
|
|
25
|
+
getPerPage(requestedPerPage?: number): number;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE3E,OAAO,WAAW,MAAM,eAAe,CAAA;AAEvC,MAAM,CAAC,OAAO,OAAO,aAAc,YAAW,UAAU;IACtD,yBAAyB,EAAE,MAAM,EAAE,CAAA;IACnC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,uBAAuB,EAAE,MAAM,CAAA;IAC/B,KAAK,EAAE,QAAQ,CAAA;IACf,SAAS,EAAE,YAAY,CAAA;IACvB,OAAO,EAAE,UAAU,CAAA;IACnB,OAAO,EAAE,UAAU,CAAA;IACnB,QAAQ,EAAE,WAAW,CAAA;gBAET,OAAO,EAAE,oBAAoB;IAelC,UAAU,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM;CAGrD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import McpResponse from './response.js';
|
|
2
|
+
export default class ServerContext {
|
|
3
|
+
supportedProtocolVersions;
|
|
4
|
+
serverCapabilities;
|
|
5
|
+
serverName;
|
|
6
|
+
serverVersion;
|
|
7
|
+
instructions;
|
|
8
|
+
maxPaginationLength;
|
|
9
|
+
defaultPaginationLength;
|
|
10
|
+
tools;
|
|
11
|
+
resources;
|
|
12
|
+
prompts;
|
|
13
|
+
request;
|
|
14
|
+
response;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.supportedProtocolVersions = options.supportedProtocolVersions;
|
|
17
|
+
this.serverCapabilities = options.serverCapabilities;
|
|
18
|
+
this.serverName = options.serverName;
|
|
19
|
+
this.serverVersion = options.serverVersion;
|
|
20
|
+
this.instructions = options.instructions;
|
|
21
|
+
this.maxPaginationLength = options.maxPaginationLength;
|
|
22
|
+
this.defaultPaginationLength = options.defaultPaginationLength;
|
|
23
|
+
this.tools = options.tools;
|
|
24
|
+
this.resources = options.resources;
|
|
25
|
+
this.prompts = options.prompts;
|
|
26
|
+
this.request = options.request;
|
|
27
|
+
this.response = new McpResponse();
|
|
28
|
+
}
|
|
29
|
+
getPerPage(requestedPerPage) {
|
|
30
|
+
return Math.min(requestedPerPage ?? this.defaultPaginationLength, this.maxPaginationLength);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { HttpContext } from '@adonisjs/core/http';
|
|
8
8
|
export default class McpController {
|
|
9
|
-
post(ctx: HttpContext): Promise<
|
|
10
|
-
get(ctx: HttpContext): Promise<void>;
|
|
11
|
-
delete(ctx: HttpContext): Promise<void>;
|
|
9
|
+
post(ctx: HttpContext): Promise<any>;
|
|
12
10
|
}
|
|
13
11
|
//# sourceMappingURL=mcp_controller.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp_controller.d.ts","sourceRoot":"","sources":["../../../src/controllers/mcp_controller.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"mcp_controller.d.ts","sourceRoot":"","sources":["../../../src/controllers/mcp_controller.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAGtD,MAAM,CAAC,OAAO,OAAO,aAAa;IAC1B,IAAI,CAAC,GAAG,EAAE,WAAW;CAU5B"}
|
|
@@ -4,67 +4,14 @@
|
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
8
|
-
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
-
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import HttpTransport from '../Transport/http_transport.js';
|
|
10
8
|
export default class McpController {
|
|
11
9
|
async post(ctx) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
10
|
+
const body = ctx.request.body();
|
|
11
|
+
const method = body.method;
|
|
12
|
+
console.log('body', body);
|
|
13
|
+
console.log('method:', method);
|
|
14
14
|
const mcp = await ctx.containerResolver.make('jrmc.mcp');
|
|
15
|
-
|
|
16
|
-
let transport;
|
|
17
|
-
const server = mcp.getServer();
|
|
18
|
-
if (sessionId && mcp.get(sessionId)) {
|
|
19
|
-
transport = mcp.get(sessionId);
|
|
20
|
-
}
|
|
21
|
-
else if (!sessionId && isInitializeRequest(ctx.request.body())) {
|
|
22
|
-
transport = new StreamableHTTPServerTransport({
|
|
23
|
-
sessionIdGenerator: () => randomUUID(),
|
|
24
|
-
onsessioninitialized: (sId) => {
|
|
25
|
-
mcp.add(sId, transport);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
transport.onclose = () => {
|
|
29
|
-
if (transport.sessionId) {
|
|
30
|
-
mcp.delete(transport.sessionId);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
await server.connect(transport);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
return ctx.response.status(400).json({
|
|
37
|
-
jsonrpc: '2.0',
|
|
38
|
-
error: {
|
|
39
|
-
code: -32000,
|
|
40
|
-
message: 'Bad Request: No valid session ID provided',
|
|
41
|
-
},
|
|
42
|
-
id: null,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
await transport.handleRequest(req, res, ctx.request.body());
|
|
46
|
-
}
|
|
47
|
-
async get(ctx) {
|
|
48
|
-
const req = ctx.request.request;
|
|
49
|
-
const res = ctx.response.response;
|
|
50
|
-
const mcp = await ctx.containerResolver.make('jrmc.mcp');
|
|
51
|
-
const sessionId = req.headers['mcp-session-id'];
|
|
52
|
-
req.headers['Authorization'] = req.headers['Authorization'];
|
|
53
|
-
if (!sessionId || !mcp.get(sessionId)) {
|
|
54
|
-
return ctx.response.status(400).send('Invalid or missing session ID');
|
|
55
|
-
}
|
|
56
|
-
const transport = mcp.get(sessionId);
|
|
57
|
-
await transport.handleRequest(req, res);
|
|
58
|
-
}
|
|
59
|
-
async delete(ctx) {
|
|
60
|
-
const req = ctx.request.request;
|
|
61
|
-
const res = ctx.response.response;
|
|
62
|
-
const mcp = await ctx.containerResolver.make('jrmc.mcp');
|
|
63
|
-
const sessionId = req.headers['mcp-session-id'];
|
|
64
|
-
if (!sessionId || !mcp.get(sessionId)) {
|
|
65
|
-
return ctx.response.status(400).send('Invalid or missing session ID');
|
|
66
|
-
}
|
|
67
|
-
const transport = mcp.get(sessionId);
|
|
68
|
-
await transport.handleRequest(req, res);
|
|
15
|
+
return await mcp.handle(body, new HttpTransport(ctx));
|
|
69
16
|
}
|
|
70
17
|
}
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
|
|
6
6
|
*/
|
|
7
|
-
import type { McpConfig } from './types.js';
|
|
7
|
+
import type { McpConfig } from './types/config.js';
|
|
8
8
|
export declare function defineConfig<T extends McpConfig>(config: T): T;
|
|
9
9
|
//# sourceMappingURL=define_config.d.ts.map
|