Skip to main content
Glama
Dyoma3

@dinko/adonis-mcp

by Dyoma3

adonis-oauth-mcp

Монорепозиторий для двух пакетов AdonisJS. Они версионируются и выпускаются вместе, поэтому изменения в контракте регистрации ресурсов никогда не требуют координации между репозиториями.

Пакет

Владение

packages/oauth (@dinko/adonis-oauth)

Сервер авторизации OAuth 2.1: токен / одобрение / отказ, проверка redirect-URI, хранение кодов авторизации, метаданные сервера авторизации и универсальная конечная точка метаданных защищённого ресурса, управляемая реестром ресурсов. Ничего не знает о MCP.

packages/mcp (@dinko/adonis-mcp)

MCP-сервер: обработчик запросов, контроллер, контракт инструментов, промежуточное ПО аутентификации. Регистрирует себя как защищённый ресурс OAuth, объявляя свой URL ресурса, области, клиентов, resource_name и поставщика токенов. Пока не запущен.

Зависимость работает в одну сторону: mcp → oauth. Ничто в oauth не может импортировать из mcp.

Структура

Каждый пакет следует соглашению о пакетах AdonisJS:

index.ts       re-exports `configure` and `stubsRoot` (what `node ace configure` imports)
configure.ts   the configure hook, driving codemods and stubs
stubs/         .stub templates rendered into the target app
src/           runtime code the app imports
providers/     service providers registered by the configure hook
services/      container services, for code that cannot use dependency injection

Related MCP server: mcpauth

Разработка

npm install     # links the workspaces
npm run build   # tsc + copy stubs, per package
npm run typecheck
npm test        # runs against build/, so build first

При разработке устанавливайте в приложение из этого репозитория (npm link, file: или git-зависимость), а не из реестра.

@dinko/adonis-oauth

Сервер авторизации OAuth 2.1 с PKCE для приложений AdonisJS, которым необходимо выдавать токены доступа сторонним клиентам.

Пакет владеет протоколом. Приложение владеет тремя вещами, которые оно не может делегировать: экран согласия, какой токен выдавать и маршруты.

npm i @dinko/adonis-oauth
node ace configure @dinko/adonis-oauth

Настройка генерирует три файла и никогда не перезаписывает существующий:

Файл

Что с ним делать

config/oauth.ts

Объявите свои ресурсы, их клиентов и issueToken.

database/migrations/..._create_oauth_authorization_codes_table.ts

Настройте столбец user_id под вашу таблицу пользователей, затем выполните миграцию.

app/controllers/oauth_controller.ts

Ваш отсюда: делегирует пакету и является местом, где вы добавляете всё, что он не покрывает.

Маршруты

Не регистрируются автоматически — где они находятся и какое промежуточное ПО их защищает, решаете вы. Добавьте их в start/routes.ts:

router.get('.well-known/oauth-authorization-server', [OauthController, 'getAuthorizationServer'])
router.get('.well-known/oauth-protected-resource/:resource', [OauthController, 'getProtectedResource'])

router
  .group(() => {
    router.post('token', [OauthController, 'token'])
    router
      .group(() => {
        router.post('authorize/approve', [OauthController, 'approveAuthorization'])
        router.post('authorize/deny', [OauthController, 'denyAuthorization'])
      })
      .use(middleware.auth())
  })
  .prefix('oauth')

Одобрение и отказ должны быть аутентифицированы: код авторизации привязан к пользователю, предоставляющему доступ. Конечная точка токена является публичной по спецификации, и именно там погашаются коды авторизации, поэтому это хорошее место для ограничения частоты запросов.

Возврат перенаправления

Одобрение и отказ по умолчанию отвечают 200 { redirect_to }, и экран согласия сам выполняет навигацию:

window.location.assign(response.redirect_to)

Это то, что нужно экрану, отправляющему своё решение через fetch или axios. XHR следует за 302, повторно отправляя запрос, поэтому страница никогда не перенаправляется: пользователь остаётся на экране согласия, а запрос попадает на обратный вызов клиента с другого источника и не проходит CORS.

Установите redirectMode: 'http', когда экран согласия — это простая HTML-форма. В этом случае браузер выполняет навигацию по документу, поэтому он следует за 302 нативно, и пользователь попадает на клиента.

Выдача токенов

Тип токена зависит от запрашиваемого ресурса, поэтому это решение живёт в каждом ресурсе, а не в контроллере. После того как пакет проверил запрос, использовал код авторизации и проверил верификатор PKCE, он вызывает:

issueToken: async ({ userId, scopes, client, resource, ctx }) => {
  const user = await User.find(userId)
  if (!user) return null // rejects the exchange with invalid_grant

  const expiresIn = 30 * 24 * 60 * 60
  const token = await User.accessTokens.create(user, scopes, {
    name: `oauth:${client.id}`,
    expiresIn,
  })

  return { accessToken: token.value!.release(), expiresIn }
}

userId — это то, что было сохранено вместе с кодом авторизации: пакет не знает о вашей модели пользователя и никогда не загружает её.

Экран согласия

Страница GET /oauth/authorize — ваша: Edge, Inertia или отдельный фронтенд. Пакет только проверяет запрос за ней:

const validation = server.validateAuthorizationRequest(request.qs())

if (!validation.valid) {
  return view.render('oauth/authorize', { error: validation.error })
}

return view.render('oauth/authorize', {
  client: validation.client,
  requestedScopes: validation.scopes,
  authorizationFields: validation.fields, // post these back to approve
})

Необязательно: приложения, отображающие экран в другом месте, могут пропустить его, поскольку одобрение и отказ снова проверяют запрос самостоятельно.

Конфигурация

export default defineConfig({
  issuer: env.get('APP_URL'),
  authorizationEndpoint: `${env.get('APP_URL')}/oauth/authorize`,
  tokenEndpoint: `${env.get('APP_URL')}/oauth/token`,

  // optional
  redirectMode: 'json', // or 'http'
  tokenEndpointAuthMethods: ['none'],
  authorizationCodeTtlSeconds: 10 * 60,
  authorizationCodesTable: 'oauth_authorization_codes',
  authenticatedUserId: (ctx) => ctx.auth.user?.id, // defaults to this

  resources: [mcpResource],
})

Каждый ресурс объявляет:

Поле

id

Слаг, используемый в /.well-known/oauth-protected-resource/<id>.

resource

Канонический индикатор ресурса, который клиенты отправляют в параметре resource.

resourceName

Человекочитаемое имя, объявляемое через обнаружение.

scopes

Все области, которые понимает ресурс.

clients

id, redirectUris, redirectUriPatterns, allowedScopes.

issueToken

Выпускает токен доступа.

Loopback redirect URIs (http://localhost/callback) совпадают на любом порту согласно RFC 8252, а redirectUriPatterns допускает один сегмент :param для клиентов, чей обратный вызов содержит идентификатор.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A complete OAuth 2.1 server implementation for FastMCP with PKCE support, enabling secure authentication and authorization flows. Provides authorization code exchange, token management, and refresh capabilities for building authenticated MCP applications.
    -
  • A
    license
    Not graded
    quality
    F
    maintenance
    Drop-in OAuth 2.1 + Dynamic Client Registration for MCP servers, providing authentication middleware and token verification.
    8 npm
    1
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    A production-grade Model Context Protocol (MCP) resource server with OAuth 2.1 authorization, provider-agnostic and supporting multiple MCP specification versions.
    18
    MIT