Skip to main content
Glama
@dinko/adonis-mcp

@dinko/adonis-mcp

by Dyoma3

adonis-oauth-mcp

2つのAdonisJSパッケージのためのモノレポです。これらは一緒にバージョン管理・リリースされるため、リソース登録コントラクトの変更にクロスリポジトリの調整は不要です。

パッケージ

担当

packages/oauth (@dinko/adonis-oauth)

OAuth 2.1認可サーバー: token / approve / deny、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

サードパーティのクライアントにアクセストークンを渡す必要があるAdonisJSアプリケーション向けの、PKCE対応OAuth 2.1認可サーバー。

パッケージはプロトコルを所有します。アプリケーションは委任できない3つのものを所有します: 同意画面、発行するトークン、ルート。

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

設定すると3つのファイルが生成され、既存のファイルを上書きすることはありません:

ファイル

対処方法

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')

approveとdenyは必ず認証されている必要があります: 認可コードはアクセスを許可するユーザーに紐づいています。トークンエンドポイントは仕様上公開されており、認可コードが引き換えられる場所なので、スロットルを設定するのに適した場所です。

リダイレクトの返却

approveとdenyはデフォルトで200 { redirect_to }を返し、同意画面が自分でナビゲートします:

window.location.assign(response.redirect_to)

これはfetchやaxiosで決定を送信する画面が必要とするものです。XHRはリクエストを再発行して302に従うため、ページはナビゲートされません: リクエストがクロスオリジンでクライアントのコールバックに到達してCORSに失敗する間、ユーザーは同意画面に留まります。

同意画面がプレーンなHTMLフォームの場合は、redirectMode: 'http'を設定してください。その場合ブラウザはドキュメントをナビゲートするため、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
})

任意: 画面を別の場所でレンダリングするアプリケーションはこれをスキップできます。approveとdenyがリクエストを独自に再度検証するためです。

設定

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

アクセストークンを発行します。

ループバックリダイレクトURI(http://localhost/callback)はRFC 8252に従い任意のポートで一致し、redirectUriPatternsはコールバックにidを含むクライアントのために単一の: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.
    12 npm
    1
    MIT
  • A
    license
    B
    quality
    D
    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