@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.
Files changed (104) hide show
  1. package/README.md +282 -0
  2. package/build/commands/commands.json +1 -1
  3. package/build/commands/make/tool.d.ts +2 -0
  4. package/build/commands/make/tool.d.ts.map +1 -1
  5. package/build/commands/make/tool.js +6 -1
  6. package/build/index.d.ts +3 -0
  7. package/build/index.d.ts.map +1 -1
  8. package/build/index.js +3 -0
  9. package/build/providers/mcp_provider.d.ts +2 -4
  10. package/build/providers/mcp_provider.d.ts.map +1 -1
  11. package/build/providers/mcp_provider.js +18 -34
  12. package/build/src/Transport/http_transport.d.ts +16 -0
  13. package/build/src/Transport/http_transport.d.ts.map +1 -0
  14. package/build/src/Transport/http_transport.js +24 -0
  15. package/build/src/context.d.ts +27 -0
  16. package/build/src/context.d.ts.map +1 -0
  17. package/build/src/context.js +32 -0
  18. package/build/src/controllers/mcp_controller.d.ts +1 -3
  19. package/build/src/controllers/mcp_controller.d.ts.map +1 -1
  20. package/build/src/controllers/mcp_controller.js +6 -59
  21. package/build/src/define_config.d.ts +1 -1
  22. package/build/src/define_config.d.ts.map +1 -1
  23. package/build/src/enums/error.d.ts +16 -0
  24. package/build/src/enums/error.d.ts.map +1 -0
  25. package/build/src/enums/error.js +18 -0
  26. package/build/src/enums/role.d.ts +12 -0
  27. package/build/src/enums/role.d.ts.map +1 -0
  28. package/build/src/enums/role.js +12 -0
  29. package/build/src/request.d.ts +9 -0
  30. package/build/src/request.d.ts.map +1 -0
  31. package/build/src/request.js +8 -0
  32. package/build/src/response.d.ts +32 -0
  33. package/build/src/response.d.ts.map +1 -0
  34. package/build/src/response.js +33 -0
  35. package/build/src/server/methods/call_tool.d.ts +12 -0
  36. package/build/src/server/methods/call_tool.d.ts.map +1 -0
  37. package/build/src/server/methods/call_tool.js +39 -0
  38. package/build/src/server/methods/get_prompt.d.ts +12 -0
  39. package/build/src/server/methods/get_prompt.d.ts.map +1 -0
  40. package/build/src/server/methods/get_prompt.js +12 -0
  41. package/build/src/server/methods/initialize.d.ts +12 -0
  42. package/build/src/server/methods/initialize.d.ts.map +1 -0
  43. package/build/src/server/methods/initialize.js +30 -0
  44. package/build/src/server/methods/list_prompts.d.ts +12 -0
  45. package/build/src/server/methods/list_prompts.d.ts.map +1 -0
  46. package/build/src/server/methods/list_prompts.js +12 -0
  47. package/build/src/server/methods/list_resources.d.ts +12 -0
  48. package/build/src/server/methods/list_resources.d.ts.map +1 -0
  49. package/build/src/server/methods/list_resources.js +12 -0
  50. package/build/src/server/methods/list_tools.d.ts +12 -0
  51. package/build/src/server/methods/list_tools.d.ts.map +1 -0
  52. package/build/src/server/methods/list_tools.js +54 -0
  53. package/build/src/server/methods/ping.d.ts +12 -0
  54. package/build/src/server/methods/ping.d.ts.map +1 -0
  55. package/build/src/server/methods/ping.js +12 -0
  56. package/build/src/server/methods/read_resource.d.ts +12 -0
  57. package/build/src/server/methods/read_resource.d.ts.map +1 -0
  58. package/build/src/server/methods/read_resource.js +12 -0
  59. package/build/src/server/pagination/cursor_paginator.d.ts +12 -0
  60. package/build/src/server/pagination/cursor_paginator.d.ts.map +1 -0
  61. package/build/src/server/pagination/cursor_paginator.js +48 -0
  62. package/build/src/server/tool.d.ts +18 -0
  63. package/build/src/server/tool.d.ts.map +1 -0
  64. package/build/src/server/tool.js +8 -0
  65. package/build/src/server.d.ts +43 -0
  66. package/build/src/server.d.ts.map +1 -0
  67. package/build/src/server.js +115 -0
  68. package/build/src/types/config.d.ts +15 -0
  69. package/build/src/types/config.d.ts.map +1 -0
  70. package/build/src/types/config.js +7 -0
  71. package/build/src/types/context.d.ts +26 -0
  72. package/build/src/types/context.d.ts.map +1 -0
  73. package/build/src/types/context.js +7 -0
  74. package/build/src/types/method.d.ts +37 -0
  75. package/build/src/types/method.d.ts.map +1 -0
  76. package/build/src/types/method.js +7 -0
  77. package/build/src/types/notification.d.ts +14 -0
  78. package/build/src/types/notification.d.ts.map +1 -0
  79. package/build/src/types/notification.js +7 -0
  80. package/build/src/types/request.d.ts +44 -0
  81. package/build/src/types/request.d.ts.map +1 -0
  82. package/build/src/types/request.js +7 -0
  83. package/build/src/types/response.d.ts +46 -0
  84. package/build/src/types/response.d.ts.map +1 -0
  85. package/build/src/types/response.js +7 -0
  86. package/build/src/types/transport.d.ts +12 -0
  87. package/build/src/types/transport.d.ts.map +1 -0
  88. package/build/src/types/transport.js +7 -0
  89. package/build/stubs/config.ts.stub +3 -1
  90. package/build/stubs/make/mcp/tools/main.ts.stub +31 -9
  91. package/build/tsconfig.tsbuildinfo +1 -1
  92. package/package.json +3 -6
  93. package/build/commands/make/prompt.d.ts +0 -14
  94. package/build/commands/make/prompt.d.ts.map +0 -1
  95. package/build/commands/make/prompt.js +0 -30
  96. package/build/commands/make/resource.d.ts +0 -14
  97. package/build/commands/make/resource.d.ts.map +0 -1
  98. package/build/commands/make/resource.js +0 -30
  99. package/build/src/mcp.d.ts +0 -22
  100. package/build/src/mcp.d.ts.map +0 -1
  101. package/build/src/mcp.js +0 -32
  102. package/build/src/types.d.ts +0 -49
  103. package/build/src/types.d.ts.map +0 -1
  104. 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-prompt","description":"Create a new MCP prompt","help":"","namespace":"make","aliases":[],"flags":[],"args":[{"name":"name","argumentName":"name","required":true,"description":"Name of the prompt","type":"string"}],"options":{},"filePath":"make/prompt.js"},{"commandName":"make:mcp-resource","description":"Create a new MCP resource","help":"","namespace":"make","aliases":[],"flags":[],"args":[{"name":"name","argumentName":"name","required":true,"description":"Name of the resource","type":"string"}],"options":{},"filePath":"make/resource.js"},{"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":{},"filePath":"make/tool.js"}],"version":1}
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;IAGpC,IAAI,EAAE,MAAM,CAAA;IAEd,GAAG;CAUV"}
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
- className: `${string.pascalCase(this.name)}Tool`
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
@@ -1,2 +1,5 @@
1
1
  export { configure } from './configure.js';
2
+ export { Tool } from './src/server/tool.js';
3
+ export * as McpResponse from './src/response.js';
4
+ export { defineConfig } from './src/define_config.js';
2
5
  //# sourceMappingURL=index.d.ts.map
@@ -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
@@ -1 +1,4 @@
1
1
  export { configure } from './configure.js';
2
+ export { Tool } from './src/server/tool.js';
3
+ export * as McpResponse from './src/response.js';
4
+ export { defineConfig } from './src/define_config.js';
@@ -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 Mcp from '../src/mcp.js';
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': 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;AAIrD,OAAO,GAAG,MAAM,eAAe,CAAA;AAE/B,MAAM,CAAC,OAAO,OAAO,WAAW;IAClB,SAAS,CAAC,GAAG,EAAE,kBAAkB;gBAAvB,GAAG,EAAE,kBAAkB;IAE7C,QAAQ;IAOF,KAAK;IAiBL,aAAa;IAab,iBAAiB;IAajB,eAAe;CAYtB;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,GAAG,CAAA;KAChB;CACF"}
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 { fsImportAll } from '@adonisjs/core/helpers';
8
- import Mcp from '../src/mcp.js';
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 Mcp(config);
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 mcp = await this.app.container.make('jrmc.mcp');
36
- const collection = await fsImportAll(new URL(this.app.makePath(mcp.config.path), import.meta.url), {
37
- filter: (filePath) => filePath.includes('_tool.ts')
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<void>;
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;AAKtD,MAAM,CAAC,OAAO,OAAO,aAAa;IAC1B,IAAI,CAAC,GAAG,EAAE,WAAW;IAuCrB,GAAG,CAAC,GAAG,EAAE,WAAW;IAepB,MAAM,CAAC,GAAG,EAAE,WAAW;CAa9B"}
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 { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
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 req = ctx.request.request;
13
- const res = ctx.response.response;
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
- const sessionId = req.headers['mcp-session-id'];
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