AdonisJS MCP - 适用于您的 AdonisJS 应用程序的 MCP 服务器。
node ace add @jrmc/adonis-mcp
这将创建一个配置文件 config/mcp.ts:
import { defineConfig } from '@jrmc/adonis-mcp'
export default defineConfig({
name: 'adonis-mcp-server',
version: '1.0.0',
path: 'app/mcp', // 存储工具的位置
})
要创建一个新的工具,请使用 Ace 命令:
node ace make:mcp-tool my_tool
此命令将在 app/mcp/tools/my_tool.ts 中创建一个带有基础模板的文件:
import type { McpContext } from '@jrmc/adonis-mcp/types/context'
import type { BaseSchema, InferJSONSchema } from '@jrmc/adonis-mcp/types/method'
import { Tool } from '@jrmc/adonis-mcp'
type Schema = BaseSchema<{
text: { type: "string" }
}>
type Context = McpContext & { args: InferJSONSchema<Schema> }
export default class MyToolTool implements Tool<Schema> {
name = 'tool_name'
title = 'Tool title'
description = 'Tool description'
async handle({ args }: Context) {
console.log(args.text)
}
schema() {
return {
type: "object",
properties: {
text: {
type: "string",
description: "描述文本参数"
},
},
required: ["text"]
} as Schema
}
}
模式定义了工具的输入参数。它遵循 JSON Schema 规范:
schema() {
return {
type: "object",
properties: {
title: {
type: "string",
description: "书签标题"
},
url: {
type: "string",
description: "书签 URL"
}
},
required: ["title", "url"]
} as Schema
}
您也可以使用 Zod 来定义模式:
import * as z from 'zod'
const zodSchema = z.object({
page: z.number().optional(),
perPage: z.number().optional()
})
schema() {
return z.toJSONSchema(
zodSchema,
{ io: "input" }
) as Schema
}
handle 方法包含工具的逻辑。它接收一个带有已验证参数的类型化上下文:
async handle({ args, response, auth, bouncer }: Context) {
// 您的逻辑在这里
const result = await SomeModel.query().where('id', args.id)
return response.text(JSON.stringify({ result }))
}
要在您的 MCP 工具中使用 auth 和 bouncer,请在中间件(例如,在您的 Bouncer 初始化中间件中)添加以下 TypeScript 声明:
declare module '@jrmc/adonis-mcp/types/context' {
export interface McpContext {
auth?: {
user?: HttpContext['auth']['user']
}
bouncer?: Bouncer<
Exclude<HttpContext['auth']['user'], undefined>,
typeof abilities,
typeof policies
>
}
}
MCP 上下文会自动绑定 auth 和 bouncer 从 HttpContext,如果它们可用的话,因此请确保您的中间件首先在 HttpContext 上初始化它们。
在您的 start/routes.ts 文件中,注册 MCP 路由并应用中间件:
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
// 注册 MCP 路由(默认为 /mcp,或指定自定义路径)
router.mcp().use(middleware.auth())
您还可以指定自定义路径:
router.mcp('/custom-mcp-path').use(middleware.auth())
MCP 上下文会自动包含来自 HttpContext 的 auth 实例(如果可用)。您可以使用它来访问经过身份验证的用户:
async handle({ args, auth }: Context) {
const user = auth?.user
if (!user) {
throw new Error('用户未经过身份验证')
}
// 使用经过身份验证的用户
const bookmark = await Bookmark.create({
title: args.title,
userId: user.id,
})
return response.text(JSON.stringify({ bookmark }))
}
MCP 上下文会自动包含来自 HttpContext 的 bouncer 实例(如果可用)。您可以使用它来检查权限:
async handle({ args, bouncer }: Context) {
// 检查权限
await bouncer.authorize('viewUsers')
// 或使用策略
const user = await User.findOrFail(args.userId)
await bouncer.with(UserPolicy).authorize('view', user)
return response.text(JSON.stringify({ user }))
}
上下文包括一个 response 实例来格式化您的响应。最常用的方法是 text():
async handle({ args, response }: Context) {
const data = { success: true, message: '操作完成' }
return response.text(JSON.stringify(data))
}
这是一个创建书签的工具的完整示例:
import type { McpContext } from '@jrmc/adonis-mcp/types/context'
import type { BaseSchema, InferJSONSchema } from '@jrmc/adonis-mcp/types/method'
import { Tool } from '@jrmc/adonis-mcp'
import Bookmark from '#models/bookmark'
type Schema = BaseSchema<{
title: { type: "string" }
url: { type: "string" }
}>
type Context = McpContext & { args: InferJSONSchema<Schema> }
export default class AddBookmarkTool implements Tool<Schema> {
name = 'create_bookmark'
title = '创建书签'
description = '创建新的书签'
async handle({ args, response, auth }: Context) {
const bookmark = await Bookmark.create({
title: args.title,
text: args.url,
userId: auth?.user?.id,
})
return response.text(JSON.stringify({ bookmark }))
}
schema() {
return {
type: "object",
properties: {
title: {
type: "string",
description: "书签标题"
},
url: {
type: "string",
description: "书签 URL"
}
},
required: ["title", "url"]
} as Schema
}
}
tools/list 方法支持基于游标的分页,以高效处理大量工具。当您在应用程序中注册了许多工具时,这一点特别有用。更多信息
对于任何问题或问题,请在 GitHub 仓库 上打开一个问题。
此包受到 laravel/mcp 的启发。