Skip to main content
Glama
@dinko/adonis-mcp

@dinko/adonis-mcp

by Dyoma3

adonis-oauth-mcp

두 개의 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에서 import할 수 없습니다.

구조

각 패키지는 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 애플리케이션이 제3자 클라이언트에게 액세스 토큰을 전달해야 할 때 사용하는, PKCE를 지원하는 OAuth 2.1 인가 서버입니다.

이 패키지는 프로토콜을 소유합니다. 애플리케이션은 위임할 수 없는 세 가지를 소유합니다: 동의 화면, 발급할 토큰, 그리고 라우트.

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

approve와 deny는 반드시 인증되어야 합니다: 인가 코드는 액세스를 허용한 사용자에게 바인딩됩니다. 토큰 엔드포인트는 사양상 공개이며, 인가 코드가 교환되는 곳이므로 스로틀을 두기에 좋은 위치입니다.

리다이렉트 처리

approve와 deny는 기본적으로 200 { redirect_to }로 응답하며, 동의 화면이 스스로 탐색합니다:

window.location.assign(response.redirect_to)

이것이 fetch나 axios로 결정을 POST하는 화면에 필요한 것입니다. 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