Skip to main content
Glama
darrenjrobinson

entra-scim-mcp

entra-scim-mcp

Microsoft Entra SCIM 2.0 프로비저닝 API(2026년 4월 GA)용 Model Context Protocol 서버입니다. https://graph.microsoft.com/rp/scim 엔드포인트에 대한 사용자 및 그룹 수명 주기 작업을 Claude와 같은 에이전트를 위한 MCP 도구로 노출합니다.

무엇을 할 수 있나

  • 테넌트의 SCIM 기능 살펴보기(get_service_provider_config, list_resource_types, list_schemas)

  • Custom Security Attributes 및 수명 주기 속성을 포함한 사용자 프로비저닝, 읽기, 업데이트, 프로비저닝 해제

  • 그룹 생성, 업데이트, 삭제 및 API의 엄격한 PATCH 규칙을 자동으로 준수하는 멤버십 관리

Related MCP server: mcp-m365-mgmt

사전 요구 사항

이 서버가 테넌트와 통신하려면 Microsoft 문서에 있는 일회성 설정을 완료하세요.

  1. Entra ID P1(또는 P1이 포함된 모든 SKU)과 청구 연결에 사용할 Azure 구독.

  2. ID 거버넌스 → 대시보드에서 SCIM 프로비저닝 API를 활성화하고 청구 리소스 그룹을 연결하세요.

  3. 필요한 애플리케이션 권한을 가진 앱을 등록하세요.

    • User.ReadWrite.All, Group.ReadWrite.All(핵심 수명 주기)

    • CustomSecAttributeAssignment.ReadWrite.All, CustomSecAttributeDefinition.Read.All(CSA 도구)

    • User-LifeCycleInfo.ReadWrite.All(수명 주기 도구)

    • User-Mail.ReadWrite.All, User-Phone.ReadWrite.All, User.EnableDisableAccount.All(최소 권한 대안)

    • 관리자 동의를 부여하세요.

  4. 클라이언트 비밀 또는 PEM 클라이언트 인증서 중 하나를 생성·업로드하세요.

모든 SCIM API 호출은 과금됩니다. 이 서버는 API가 요구하는 범위만큼만 배치를 수행하며 그 이상은 하지 않습니다.

Entra 테넌트 없이 사용해 보기

패키지에는 Entra SCIM API의 로컬 mock(entra-scim-mock-server)이 포함되어 있어, Azure 설정 없이 또는 API 비용 없이 모든 도구를 실행해 볼 수 있습니다.

# shell 1 — start the mock (seeds a small demo tenant)
npx -y --package entra-scim-mcp entra-scim-mock-server

그런 다음 MCP 서버가 이 mock을 가리키도록 설정합니다.

{
  "mcpServers": {
    "entra-scim-mock": {
      "command": "npx",
      "args": ["-y", "entra-scim-mcp"],
      "env": {
        "ENTRA_SCIM_BASE_URL": "http://127.0.0.1:8990",
        "ENTRA_SCIM_STATIC_TOKEN": "dev-token"
      }
    }
  }
}

목 플래그: --port, --token, --seed <file.json>, --no-seed, --capture <file.jsonl>(모든 요청/응답 기록), --validator-compat(Microsoft SCIM Validator의 RFC 표준 동작 — docs/scim-validator.md 참고).

설치 및 실행

이 서버는 stdio MCP 서버이며, MCP 클라이언트(Claude Desktop, Claude Code 등)가 실행하도록 설계되었습니다.

npx -y entra-scim-mcp

필수 환경 변수:

| 변수 | 필수 | 설명 | | ----------------- -------- | -------- | ------------------------------------------------- | | ENTRA_TENANT_ID | 예 | 디렉터리(테넌트) GUID | | ENTRA_CLIENT_ID | 예 | 앱 등록(클라이언트) GUID | | ENTRA_CLIENT_SECRET | 둘 중 하나 | 클라이언트 비밀 값(개발 환경용) | | ENTRA_CLIENT_CERT_PATH | 둘 중 하나 | 인증서 개인 키가 포함된 PEM 파일 경로 | | ENTRA_CLIENT_CERT_PASSWORD | 선택 | PEM이 암호화된 경우의 암호 |

ENTRA_CLIENT_SECRET 또는 ENTRA_CLIENT_CERT_PATH 중 정확히 하나만 설정하세요.

개발/테스트 환경 변수

변수

설명

ENTRA_SCIM_BASE_URL

SCIM 기본 URL을 재정의합니다(기본값 https://graph.microsoft.com/rp/scim). 로컬 mock을 가리킬 수 있습니다.

ENTRA_SCIM_STATIC_TOKEN

Azure AD 대신 고정 bearer 토큰을 사용합니다. 가이드라인: ENTRA_SCIM_BASE_URL을 반드시 지정해야 하며, 모든 *.microsoft.com / *.microsoft.us 호스트를 거부하고, 루프백(loopback)이 아닌 호스트에 대해 경고합니다. 실제 자격 증명과 함께 사용할 수 없습니다. 이 모드에서는 테넌트/클라이언트 ID가 필요 없습니다.

ENTRA_SCIM_DRY_RUN

1로 설정: 모든 도구는 클라이언트 측 검증을 모두 수행한 뒤, 전송하는 대신 전송되었을 정확한 요청을 반환합니다. 토큰을 획득하지 않으므로 자격 증명 구성 없이도 동작합니다.

dry-run 결과는 성공적인 페이로드로 반환됩니다.

{
  "dryRun": true,
  "request": {
    "method": "DELETE",
    "url": "https://graph.microsoft.com/rp/scim/users/u-1",
    "headers": {}
  }
}

(DELETE는 Accept 헤더를 갖지 않습니다. 해당 위치에서 API가 특정 JSON 미디어 타입을 거부하기 때문입니다. 그 외 모든 메서드는 Accept: application/json을 전송합니다.)

여러 요청으로 나뉘는 도구(예: 20개를 초과하는 ID에 대한 add_group_members)는 dry-run에서 첫 번째 분할된 요청만 보여줍니다.

Claude Desktop 설정

~/Library/Application Support/Claude/claude_desktop_config.json(macOS) 또는 %APPDATA%\Claude\claude_desktop_config.json(Windows):

{
  "mcpServers": {
    "entra-scim": {
      "command": "npx",
      "args": ["-y", "entra-scim-mcp"],
      "env": {
        "ENTRA_TENANT_ID": "00000000-0000-0000-0000-000000000000",
        "ENTRA_CLIENT_ID": "11111111-1111-1111-1111-111111111111",
        "ENTRA_CLIENT_SECRET": "..."
      }
    }
  }
}

프로덕션 환경에서는 클라이언트 비밀 대신 인증서를 사용하세요.

{
  "env": {
    "ENTRA_TENANT_ID": "...",
    "ENTRA_CLIENT_ID": "...",
    "ENTRA_CLIENT_CERT_PATH": "/secure/path/entra-scim-mcp.pem"
  }
}

도구

도구

목적

get_service_provider_config

SCIM 기능을 한 번에 조회합니다.

list_resource_types

SCIM 리소스 유형(사용자, 그룹)을 열거합니다.

list_schemas

SCIM 스키마와 Entra 확장을 나열합니다.

list_users

사용자를 나열합니다. API의 제한된 필터(eq/ew, and-only) 및 커서 페이지네이션을 지원합니다.

get_user

ID를 이용해 단일 사용자를 읽습니다. 선택적으로 반환할 속성을 지정할 수 있습니다.

provision_user

필요 속성 집합(userName, password, displayName, name.givenName, name.familyName, mailNickname)을 적용하여 사용자를 생성합니다.

update_user

사용자 PATCH입니다. mailNicknameremove를 차단하고, 주소 경로에 [type eq "work"]을 강제합니다.

deprovision_user

사용자 DELETE.

update_user_lifecycle

수명 주기 속성(예: employeeLeaveDateTime)을 설정합니다. User-LifeCycleInfo.ReadWrite.All 권한이 필요합니다.

get_user_custom_security_attributes

속성 집합 단위로 사용자의 CSAs를 읽습니다. attributeSets필수입니다. API는 확장 URN만으로는 요청을 거부하며, get_user만으로는 CSA가 절대 반환되지 않습니다.

update_user_custom_security_attributes

사용자의 CSA를 PATCH합니다.

list_groups

API의 제한된 필터 집합으로 그룹을 나열합니다.

get_group

단일 그룹을 읽습니다(멤버는 반환되을 수 없습니다 — members.value 필터와 함께 list_groups를 사용하세요).

create_group

그룹을 POST합니다. mailEnabled, securityEnabled, mailNickname, description을 Entra 확장을 통해 설정합니다.

update_group

그룹 속성만 PATCH합니다(멤버십 작업은 여기서 거부됩니다).

add_group_members

그룹에 한 명 이상의 사용자를 추가합니다 — PATCH당 20개 ID(API 한도)로 자동 분할되며, 각 PATCH에는 하나의 Operation만 실행합니다. 시퀀스 중간 실패가 발생하면 addedMemberIds / failedMemberIds / notAttemptedMemberIds를 보고하여 부분 쓰기가 조용히 무시되지 않게 합니다.

remove_group_member

그룹에서 단일 사용자를 제거합니다(API는 PATCH당 다른 연산과 함께 최대 하나의 제거만 허용합니다).

delete_group

그룹 DELETE.

이 서버가 강제로 지켜 주는 규칙

Entra SCIM API에는 놓치기 쉬운 제약이 있습니다. 이 서버는 요청을 전송하기 전에 잘못된 입력을 거부합니다.

  • 필터 허용 목록: 리소스별문서화된 속성 및 연산자만 허용하며, or는 거부되고, externalId는 다른 절과 결합할 수 없습니다.

  • 쿼리 문자열: = 주변에 공백을 허용하지 않습니다(공백이 있으면 API가 400을 반환함).

  • 사용자 PATCH: mailNicknameremove를 차단하고, 주소 경로 필터는 정확히 [type eq "work"]인지 확인합니다.

  • 그룹 PATCH: 멤버십 연산은 전용 도구를 통해서만 수행되므로, 20명 추가 상한 및 단일 제거 규칙이 보장됩니다.

  • 멱등 멤버 추가: API는 같은 멤버를 다시 추가해도 성공으로 취급합니다. add_group_members는 입력에서 중복을 제거합니다.

오류는 status, scimType, detail을 포함하는 구조화된 페이로드로 에이전트에게 반환됩니다.

알아 두면 좋은 API 동작

실제 API가 절차에 모호하게나 전혀 언급하지 않은 동작입니다. 각 항목은 실제 테넌트 또는 Microsoft SCIM Validator를 대상으로 발견되었으며 이미 처리되어 있습니다. 응답을 읽는 방식이 달라지기 때문에 여기에 정리했습니다.

DELETE는 Accept 헤더를 보내면 안 됩니다. API는 400 Accept header application/json 같은 오류로 응답합니다. 네 가지 변형을 모두 실제로 시도했습니다: 헤더 없음 → 204, */* → 204, application/json → 400, application/scim+json → 400. 규칙을 뒤집는 메서드는 DELETE뿐입니다 — 다른 모든 메서드는 JSON Accept필수이고, 이를 생략하면 문서에 명시된 400이 됩니다. 이 한 가지 때문에 deprovision_userdelete_group은 첫 라이브 실행 전까지 조용히 깨져 있었습니다.

Custom Security Attributes는 일반 읽기로는 결코 반환되지 않습니다. /Schemas에서 속성-집합 수준 속성은 returned: "request"로 정의되어 있어서, get_user는 아무것도 요청해도 CSA를 포함하지 않습니다. CSA는 명시적으로 이름을 지정할 때만 나타나며, 프로젝션은 집합 단위로 동작합니다: urn:...:CustomSecurityAttributes:<Set>. 확장 URN만 단독으로 주면 아예 거부됩니다(400 ... not supported in the "attributes" or "excludedAttributes" query parameter). 이 때문에 attributeSets는 선택 입력이 아니라 필수 입력입니다.

CSA 값에는 타입이 있고, 그 타입이 강제됩니다. Boolean, Integer, String 및 다중 값 String은 모두 일치하는 JSON 타입으로 보내면 온전하게 왕복됩니다. PATCH 하나로 여러 속성을 동시에 전달할 수도 있습니다. Microsoft가 문서화하지 않은 제거 동작이 두 가지 있습니다.

  • CSA 경로에 "remove"를 쓰면 해당 할당 하나만 지워지고 나머지는 그대로 남습니다.

  • 다중 값 속성에 [] 을 사용하면 할당이 제거됩니다. 이후 읽기에서는 빈 배열을 반환하는 대신 해당 속성 자체가 빠져나옵니다.

password는 생성 시 필수이지만 읽을 수는 없습니다. writeOnly / returned: never이며 어떤 응답도 그것을 되돌려 주지 않습니다. 생성에 필요한 전체 필수 집합은 userName, password, displayName, name.givenName, name.familyName, mailNickname입니다 — RFC 7643이 userName만 요구하는 것보다 훨씬 엄격합니다.

그룹 displayName은 고유하지 않습니다. Entra는 중복된 그룹 이름을 수락하고 201을 반환합니다. RFC 지향 도구는 여기서 409를 가정하는 경우가 많으므로, 기존 그룹을 찾는 용도로 생성 실패에 의존하지 마십시오 — 먼저 필터링하십시오.

그룹 멤버 제거의 핵심은 멤버십이지 사용자가 아닙니다. 일치하는 항목이 없는 members[value eq "<id>"]에 대한 remove404입니다. 그 id가 누구의 것이든 관계없습니다 — 그룹에 없던 실제 라이브 사용자는 사용자가 아닌 GUID와 똑같이 거부됩니다. 전체 과정에서 실제 테넌트에 유지용(ballast) 멤버가 계속 존재하도록 두고 검증했으므로, 그룹이 비워진 것과 무관합니다.

Case

Result

실제 멤버

204

멤버가 아니었던 라이브 사용자

404

사용자가 아니었던 정상 GUID

404

먼저 삭제된 멤버

404

알아둘 만한 두 가지 결과가 있습니다. 사용자를 삭제하면 멤버십이 제거되므로, 먼저 삭제하고 나서 멤버십 제거를 시도하는 순서는 다른 비멤버와 같은 지점에 이릅니다. 이는 삭제 전후로 members.value 필터를 붙여 list_groups를 조회해 확인했습니다. 또한 오류 메시지는 멤버가 아니라 그룹을 지칭합니다(Resource '<groupId>' does not exist or one of its queried reference-property objects are not present). 그룹이 분명히 존재하는데도 그렇게 읽히는 것이 어색합니다. 의도적으로 틀린 그룹 id로 시도해도 그 id를 말하는 같은 문장이 반환되었으므로, 이 텍스트는 단지 PATCH 대상을 그대로 반영한 것입니다. 모의 서버는 이것을 개선하지 않고 그대로 재현합니다. npx tsx scripts/probe-member-removal.ts --confirm로 다시 실행하세요(~17회 청구 호출).

그룹 읽기에는 멤버가 포함되지 않습니다. get_group은 페이지 크기와 관계없이 members 배열을 반환하지 않습니다. 사용자의 그룹을 찾으려면 반대 방향으로 필터하세요: members.value eq "<userId>" 조건으로 list_groups를 호출하면 됩니다.

오류는 구조화되어 있고, 그대로 보여줄 충분한 가치가 있습니다. 실패에는 status, scimType, detail이 담겨 있으며, detail 텍스트는 특이할 만큼 구체적입니다(문제가 되는 조작 인덱스와 제약 조건까지 지정합니다. 도구는 그것을 메시지로 평탄화하지 않고 그대로 전달합니다.

모든 호출은 비용이 청구됩니다. API 자체가 요구하는 것 외에는 일괄 처리가 없으므로 수다스러운 에이전트는 실제 비용이 듭니다. add_group_members는 API의 20명 상한에 맞춰 청크로 나뉘며, 그 부분이 유일한 배치 지점입니다.

실제 테넌트에 대한 테스트

이 테스트 스위트는 실제 테넌트를 다루지 않습니다. 라이브 Entra에 대해 도구를 검증하려면 gitignore된 .env에 자격 증명을 넣고 스모크 스크립트를 실행하세요.

cd node
cp .env.example .env      # then fill in tenant id, client id, and the secret VALUE

.env오직 scripts/ 안의 스크립트만 읽습니다. 공개된 서버는 항상 process.env를 읽기 때문에, MCP 클라이언트가 서버를 실행하는 어떤 디렉토리에 .env가 남아 있어도 그 파일을 우연히 읽을 수 없습니다. 환경에 이미 설정된 변수는 항상 파일보다 우선합니다.

Var

Purpose

ENTRA_SCIM_SMOKE_DFINIT

검증된 도메인. 일회용 scim-smoke-* ID를 만드는 곳입니다

ENTRA_SCIM_SMOKE_CSA_SET

속성 집합 이름. 두 Custom Security Attribute 도구를 다루도록 설정합니다

ENTRA_SCIM_SMOKE_CSA_ATTR

해당 집합 안의 속성 이름

ENTRA_SCIM_SMOKE_CSA_VALUE

속성에 할당할 값. CSA는 타입이 있고, API는 타입 불일치를 거부합니다: true/false는 JSON 불리언으로, 정수는 숫자로, 그 외는 숫자로 보냅니다. 기본값은 문자열이므로 Boolean이나 Integer 속성은 이 값을 설정하세요.

스모크 스크립트

ENTRA_SCIM_LIVE=1 npm run smoke:live              # bash
$env:ENTRA_SCIM_LIVE=1; npm run smoke:live        # PowerShell

플래그를 전달할 때는 스크립트를 직접 호출하세요 — npm run x -- --flag는 Windows에서 신뢰할 수 있게 전달되지 않습니다.

npx tsx scripts/live-smoke.ts --confirm

약 21번의 청구 호출에 걸쳐 18개 도구를 한 번의 정돈된 순서로 실행합니다. 두 명의 사용자와 하나의 그룹을 만들고, 모든 읽기·패치·삭제를 실행한 뒤 다시 삭제합니다. 주요 특징:

  • 실수로 실행되지 않습니다. 마찬가지로 확인 없이 실행하면 테넌트, 엔드포인트, 비용을 출력하고 종료합니다. ENTRA_SCIM_DRY_RUN이나 ENTRA_SCIM_STATIC_TOKEN이 설정된 경우에는 --rehearse를 넘기지 않으면 완전히 거부합니다. 그런 실행은 라이브 API에 대해 아무것도 증명하지 않기 때문입니다.

  • 첫 실패에서 멈추지 않습니다. 실패한 단계는 그 단계에서 파생된 단계들만 skip로 표시하고, 그와 무관한 모든 단계는 계속 실행되므로 한 번의 실행으로 라이브가 어떤 도구를 수용하는지 알 수 있습니다. 실패가 하나라도 있으면 종료 코드는 0이 아닙니다.

  • 테스트 ID는 명백합니다. scim-smoke-<runId>-1@<domain> 그리고 SCIM Smoke <runId> 그룹.

  • 정리는 보장됩니다. 생성된 모든 것은 finally 블록에서 삭제되며, 남은 항목은 id와 함께 출력됩니다. 실행이 중단됐다면 npx tsx scripts/live-smoke.ts --sweep로 남겨진 scim-smoke-* 사용자를 찾아낸 다음, 삭제하려면 --confirm을 추가하세요. 스윕은 scim-smoke- 접두사가 없는 계정은 절대 건드리지 않습니다.

두 Custom Security Attribute 도구는 테넌트에 속성 집합이 존재하고(Entra 포털 -> Protection -> Custom security attrs) ENTRA_SCIM_SMOKE_CSA_SET / ENTRA_SCIM_SMOKE_CSA_ATTR이 그것을 가리킬 때까지 skip을 보고합니다. 나머지는 모두 자동으로 실행됩니다.

집합이 만들어지면, 그 두 도구만 약 9번의 호출로 검증하세요(21번이 아닙니다). 이 검증은 모든 값을 다시 읽습니다 (API가 받아들이지만 저장하지 않는 PATCH는 그렇지 않으면 통과처럼 보입니다). 각 선언된 자료형을 고려하고 제거 동작도 테스트합니다:

npx tsx scripts/live-smoke.ts --csa-only --confirm

집합의 구조를 한 번 선언하면 그 결과에 따라 데이터 타입별 테스트 값이 파생됩니다:

ENTRA_SCIM_SMOKE_CSA_ATTRS=isManaged:bool,accountType:string,trustLevel:int,locations:string[]

네 가지 타입 모두에 대해 라이브로 확인했습니다: 값은 온전한 상태로 왕복되고, "remove"는 하나의 할당만 지우고 나머지 부분을 유지하며, 여러 값 속성을 []로 교체하면 속성을 제거합니다 — 이후 읽기에서는 빈 배열이 아니라 속성 자체가 생략됩니다.

무언가를 쓰기 전에 저렴한 비용으로 먼저 리허설해 보세요. 이는 API가 아니라 스크립트를 검증합니다:

# no network at all
ENTRA_SCIM_DRY_RUN=1 npx tsx scripts/live-smoke.ts --rehearse

# or against the local mock: start it in one shell...
npm run mock
# ...and in another, aim the script at it
export ENTRA_SCIM_BASE_URL=http://127.0.0.1:8990
export ENTRA_SCIM_STATIC_TOKEN=dev-token
npx tsx scripts/live-smoke.ts --rehearse

모의 리허설이 실제로 할 가치가 있는 부분입니다. 실제 HTTP, 실제 ID, 전체 생성/패치/삭제 순서를 실행하므로 시퀀싱과 정리 버그를 실제 비용을 쓰기 전에 잡아냅니다. 하지만 라이브 실행의 대체재는 아닙니다 — 첫 라이브 패스에서 mock이 잡지 못한 버그가 두 개 발견되었습니다(test legs의 실제 발견 참조).

테스트 레그들이 실제로 잡은 것

각각 서로가 잡을 수 없는 것을 찾아낸 세 개의 독립적인 테스트 레그가 있습니다. 그래서 세 개가 모두 존재합니다:

Leg

비용

발견

Mock + 단위 테스트

무료

시퀀싱, 검증, 정리 버그. 빠르지만, 자신의 가정을 공유하므로 잘못된가정을 찾을 수는 없다.

Live 테넌트 (smoke:live)

~21 calls

DELETE Accept 버그(두 도구가 한 번도 작동하지 않았던 것), 유효하지 않은 CSA URL, CSA 타입/제거 의미론.

SCIM Validator

무료

7개의 mock 정확성 gap — mock이 실제 SCIM 클라이언트가 요구하는 것보다 더 관대했던 곳과, 각각이 실제 동작을 숨기고 있었던 곳.

가져갈 교훈: mock의 관대함은 실제 API 동작을 숨긴다. 라이브 실행이 발견한 모든 결함은 먼저 전체 mock 슈트를 통과했습니다. mock가 클라이언트와 동일한 설명서를 읽고 만들어졌기 때문입니다. 그 순환을 깨뜨릴 수 있는 것은 외부 클라이언트(검증자)와 실제 테넌트뿐입니다.

라이브 테넌트를 대화식으로 구동하기

Always root .mcp.json은 Claude Code에 scripts/dev-server.mjs를 사용해 서버를 등록합니다. 이 스크립트는 node/.env를 불러오고 빌드된 서버를 시작합니다 — 따라서 커밋된 설정 파일에 비밀이 들어가지 않습니다.

이 스크립트는 빌드된 서버를 실행하므로, MCP 클라이언트가 실행하기 전에 node/dist가 존재해야 합니다. 새 클론에서 그 상태로 만드는 방법은 다음과 같습니다.

cd node && npm install     # the "prepare" script builds as part of install

소스를 변경한 후에는 재빌드하고 클라이언트를 다시 시작해서 명령을 다시 실행하세요.

cd node && npm run build

개발

cd node
npm install             # installs, then builds via "prepare"
npm test
npm run lint            # ESLint, type-aware
npm run format:check    # Prettier
npm run typecheck       # strict tsc over src, test and scripts
npm run test:coverage   # vitest with the coverage gate
npm run build           # rebuild after a source change
npm run mock            # run the local mock server (tsx, no build needed)
npm run mock:capture    # mock in validator-compat mode, capturing traffic to captures/

npm run lint, format:check, typecheck, test는 CI가 모든 푸시와 pull 요청에서 실행하는 네 가지 검문이며, npm audit --audit-level=high도 함께 실시합니다.

서버는 실제 테넌트에 테스트 의존성이 없습니다. 단위 테스트는 필터, 패치, 쿼리, 클라이언트 레이어를 다루고, 통합 테스트는 프로세스 내 모의 서버를 시작하고 실제 HTTP를 통해 모든 MCP 도구를 종단간으로 구동합니다(node/test/integration/). 캡처된 SCIM Validator 세션은 npm run fixtures:convert로 재현 픽처로 변환합니다. 아무것도 증명할 수 없는 단 하나의 일, 즉 라이브 API가 페이로드를 수용하는지에 대해서는 실제 테넌트에 대한 테스트를 참조하세요.

릴리스

버전은 네 곳에 있습니다 — node/package.json, node/package-lock.json (두 번), 그리고 server.json (두 번, 한 번은 레지스트리 레코드용, 한 번은 그것이 가리키는 npm 패키지용). 하나의 명령이 그것들을 모두 작성합니다:

cd node
npm version minor          # or patch / major — writes all four, stages three
cd ..
git commit -m "v0.2.0"     # the version npm just printed
git tag -a v0.2.0 -m v0.2.0
git push --follow-tags

-a가 중요합니다. --follow-tags주석(annotated) 태그만 푸시하므로, 경량(lightweight) git tag v0.2.0은 로컬에 그대로 남고 푸시는 태그를 전혀 보내지 않았는데도 성공으로 보고합니다. 즉 릴리스는 그저 실행되지 않습니다.

npm version은 package.json과 lockfile을 올리고, 그 다음 version 수명 주기 스크립트가 이 값을 server.json에 반영한 후 그 결과를 스테이징합니다. npm version은 일반적으로 커밋과 태그를 모두 만들지만, 여기서는 커밋이나 태그를 만들지 않습니다. npm은 버전을 올리는 패키지 옆에서 .git을 찾습니다. 그런데 이 패키지는 node/에 있고 저장소의 .git은 한 단계 위에 있으므로, npm은 git 저장소가 아니라고 판단하고 그 단계를 아무 말 없이 건너뜁니다. 그래서 위에서 명시적으로 커밋과 태그를 수행하는 것입니다. 이 부분을 잘못 설정하면 git push --follow-tags는 조용히 아무것도 푸시하지 않습니다. 따라가야 할 태그가 만들어지지 않았기 때문입니다.

npm run check:version은 네 곳이 모두 일치하는지 확인하고, CI는 모든 푸시에 대해 실행하며, 릴리스 워크플로우는 태그 자체를 대상으로 다시 실행합니다. 따라서 package.json과 일치하지 않는 태그는 아무것도 게시되기 전에 실패합니다. 서버가 MCP 핸드셰이크에서 보고하는 버전은 런타임에 package.json에서 읽히므로 자동으로 그 값을 따릅니다.

v* 태그를 푸시하면 .github/workflows/release.yml이 실행됩니다.

  1. 검증(verify) — 린트, 포맷, 타입체크, 커버리지를 포함한 테스트, 버전/태그 검사, 그리고 라이브 레지스트리에 대한 mcp-publisher validate.

  2. Windows에서 검증(verify on Windows)windows-latest에서 동일한 테스트를 다시 수행합니다. mock이 실제 소켓을 바인딩하고 캡처 싱크가 실제 경로에 쓰기 때문입니다. 이 단계가 없으면 릴리스 게이트가 일반 커밋에 적용되는 게이트(CI도 Windows에서 실행)보다 약해집니다.

  3. 게시(publish)npm publish를 실행하고, 새 버전이 npm에 표시될 때까지 기다린 다음 server.jsonMCP Registry에 게시합니다.

이 세 단계가 모두 통과하기 전에는 아무것도 게시되지 않습니다.

두 게시 과정 모두 GitHub OIDC로 인증하므로, 저장소에는 비밀이 전혀 없습니다. 유출하거나 회전시키거나 만료된 것을 발견해야 하는 게시 토큰이 없습니다.

Registry

이 워크플로우를 인증하는 방식

npm

이 패키지의 trusted publisher입니다. 이 저장소와 워크플로우 파일 release.yml을 빈 환경으로 지정하고, npm은 OIDC 클레임을 그와 대조하며 같은 토큰에서 생성된 출처 증명(provenance attestation)을 함께 기록합니다. npm >= 11.5.1이 필요하기 때문에 잡이 게시 전에 npm을 업그레이드합니다.

MCP Registry

mcp-publisher login github-oidc. darrenjrobinson/entra-scim-mcp에서 실행하는 것이 io.github.darrenjrobinson/* 네임스페이스를 인증합니다.

이 두 가지 때문에 게시 작업이 id-token: write를 요청하는 것입니다.

MCP Registry는 package.json을 가져와 그 안의 mcpNameserver.jsonname과 비교합니다. 두 값 모두 시스템과 같은 io.github.darrenjrobinson/entra-scim-mcp이고, check:version은 여전히 이 값들이 일치하는지 확인합니다.

워크플로우의 파일명을 바꾸거나 게시 작업에 environment:를 추가하면, npmjs.com의 구성이 그에 맞게 갱신될 때까지 npm trusted publisher를 설정됩니다. OIDC 클레임이 정확히 비교되기 때문입니다.

라이선스

MIT — LICENSE를 참조하세요.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Create and manage AI agents that collaborate and solve problems through natural language interacti…

  • Runtime permission, approval, and audit layer for AI agent tool execution.

  • Give AI agents the LinkedIn tools to find, qualify, engage, and follow up with prospects.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/darrenjrobinson/entra-scim-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server