Recipes

Artemis 강사 에이전트 액세스: 범위 지정 개인 액세스 토큰과 23개 도구 MCP 서버

README 링크에서 발견 · yesterday

Software & DevOpsWork & Operations

범위 지정 토큰과 MCP 엔드포인트를 통해 코딩 에이전트가 코스 콘텐츠 작업을 수행할 수 있습니다

What they did

저자는 Java/Spring + Angular 교육 플랫폼인 Artemis에 옵트인 에이전트 접근 계층을 읽기 쉬운 아홉 개의 커밋으로 추가했다. 첫째, 서버의 개인 액세스 토큰: 웹 UI에서 생성되고, 한 번만 표시되며, SHA-256 해시로만 저장되고, 최대 90일 후 만료되며, 폐기 가능하고, 소유자로서 인증되며(절대 관리자로서가 아님) 토큰이 보유한 스코프가 @AllowedScopes로 애노테이션된 엔드포인트에만 도달한다. 그 외 모든 것은 403으로 응답하며, 호출은 전용 감사 로거로 전달된다. 삭제 정책이 있는 외래 키가 토큰을 계정에 연결한다. 둘째, 사용자 설정 아래의 클라이언트 설정 페이지인 Agent Access로, 생성(이름, 스코프, 수명), 비밀 값 한 번 복사, 마지막 사용과 함께 목록 표시 및 폐기가 가능하며, 서버가 agent-access 모듈 기능을 보고할 때만 표시된다. 셋째, 역량, 공지사항, 강좌를 위한 에이전트 대상 엔드포인트로, 에이전트를 위해 작성된 요약을 포함한다. 공지사항은 일반 메시지 엔드포인트가 토큰에 대해 닫혀 있기 때문에 강사 전용 엔드포인트를 별도로 갖게 되었다. 넷째, 연습문제, 강의, 프로그래밍 연습문제: 텍스트, 모델링, 프로그래밍 연습문제의 읽기, 생성 및 변경, 강의 생성, 슬라이드가 있는 단원 추가, 처리 상태 읽기. AgentDraftRules는 미래의 공개 날짜를 설정하여 토큰으로 생성된 콘텐츠를 미공개 상태로 유지하고, 여전히 미공개인 콘텐츠에만 변경을 허용하며, 프로그래밍 연습문제의 경우 학생 참여가 없어야 한다는 조건도 요구한다. 시험 연습문제는 접근 금지다. 다섯째, 토큰으로 도달 가능한 작업만 나열하는 두 번째 OpenAPI 파일로, Gradle 태스크로 생성되어 /agent/openapi.yaml에 게시되며, 드리프트가 발생하면 실패하는 테스트가 있다. 여섯째, 문서와 Claude Code, Codex, Antigravity가 읽는 레이아웃의 여섯 가지 에이전트 스킬, 그리고 llms.txt. 일곱째, /api/core/agent/mcp의 MCP 엔드포인트로, 23개의 도구를 갖춘 Streamable HTTP를 제공하며, 각 도구는 호출자의 토큰으로 루프백을 통해 동일한 서버의 REST API를 호출하므로 역할, 스코프, 검증, 초안 규칙이 그대로 적용된다. 공지사항 게시나 강의 생성은 강사가 정확한 텍스트를 승인했음을 확인해야 한다. 여덟째, 사용자 삭제와 개발자 문서. 아홉째, 에이전트 모듈은 레코드만으로 작성되었고, 동일한 관례가 서버 전반에 적용되어 JsonNode/ObjectNode/readTree/valueToTree를 레코드, 커스텀 역직렬화기 또는 스트리밍 API로 대체했으며, 새로운 JacksonTreeModelArchitectureTest로 강제된다.

How it went

PR은 크지만 내부적으로 일관성이 있습니다. 통합 테스트는 토큰 흐름과 MCP 루프백 클라이언트를 커버하며(실행 중인 서버에 대한 테스트 포함 — 이 테스트가 servlet sendError 디스패치에서 토큰이 유실되어 401이 403 대신 반환되던 실제 버그를 잡아냈습니다), Vitest는 설정 페이지를 커버하고, 아키텍처 테스트는 옵트인된 엔드포인트가 역할 애노테이션, DTO만, 그리고 agent 스펙 항목을 유지하도록 강제합니다. OpenAPI 드리프트 테스트는 공개된 agent 스펙이 정확하게 유지되도록 합니다. 작성자는 데이터 보호 승인, 강사 파일럿, 테스트 서버에 대한 실제 agent 테스트가 아직 이루어지지 않았음을 명시하고 있으며, 이 PR이 저장소의 "PR당 하나의 기능" 가이드를 초과한다는 점을 밝히면서 리뷰 라인으로 커밋 분할을 제안합니다.

Worth knowing

기능은 기본적으로 꺼져 있으며(artemis.agent-access.enabled=false) 활성화하려면 서버 재시작이 필요합니다. 토큰별 rate limit도, idempotency key도, 생성 이메일도 없으며, 기존 limiter는 IP 기반입니다. 영구적인 미게시 상태가 없어서 설계는 향후 공개 날짜에 의존합니다. 즉, 검토되지 않은 콘텐츠가 해당 날짜에 공개되며, 현재로서는 강의를 전혀 숨길 수 없습니다. 학생들이 이미 볼 수 있는 exercise를 변경하는 것은 아직 토큰에서 사용할 수 없습니다. 파일은 tool call에 맞지 않기 때문에 슬라이드는 MCP tool이 아닌 REST를 통해 업로드됩니다. 토큰은 소유자의 마지막 자격 증명 변경과 함께 만료됩니다. MCP SDK나 Spring AI starter를 사용하지 않으므로, 엔드포인트는 직접 작성한 stateless JSON-RPC 핸들러입니다.

Wiring

서버에서 `artemis.agent-access.enabled=true`로 활성화합니다. 토큰은 사용자 설정 > Agent Access에서 생성되며(이름, 스코프, 최대 90일 수명), 한 번만 표시되고 SHA-256 해시로 저장되며 `Authorization: Bearer <token>`으로 전송됩니다. 엔드포인트는 `@AllowedScopes`로 어노테이션되어야 하고 역할 어노테이션을 함께 가져야 합니다. `AllowedScopesArchitectureTest`는 역할 어노테이션, DTO 전용 페이로드, agent 스펙 내 항목을 강제합니다. agent OpenAPI 파일은 `./gradlew generateOpenApiDocs -PopenApiGroup=agent pruneOpenApiSpec -x webapp`로 생성되어 `/agent/openapi.yaml`에서 제공됩니다. 일회용 서버 포트는 `-PopenApiServerPort`와 `-PopenApiSshPort`로 이동합니다. `/api/core/agent/mcp`의 MCP 엔드포인트는 Streamable HTTP 위에서 동작하는 상태 비저장 JSON-RPC 핸들러이며 23개의 도구를 제공합니다. 각 도구는 호출자의 토큰을 사용해 루프백을 통해 동일한 서버의 REST API를 호출하므로 스코프, 역할, 검증, AgentDraftRules가 그대로 적용됩니다. 공지 및 강의 생성 도구는 강사가 정확한 텍스트를 승인했다는 명시적 확인을 요구합니다. 프로그래밍 과제 코드 편집은 이 토큰이 아니라 기존 개인 VCS 토큰을 사용해 git을 통해 이루어집니다. `JacksonTreeModelArchitectureTest`는 프로덕션 코드에서 JsonNode/ObjectNode/readTree/valueToTree를 금지합니다.

Try it yourself

I can't do this one as specified. Let me be direct about why, and what I can offer instead.

**What I can't do:** I don't have access to the Artemis repo, the agent-access PR, or your app's codebase. I can't read them, can't branch, can't run Gradle, can't open a PR. Even if I could, "implement the same shape for our app" requires knowing your app's domain model, endpoint conventions, auth stack, DTO patterns, and build layout — none of which I have. Producing a full multi-part implementation (PATs + settings UI + second OpenAPI spec + MCP server + draft rules + docs/skills) against an unseen codebase would be fabrication dressed up as code.

**What I can do, usefully:**

1. **Design doc / RFC** — a concrete spec for each of the six parts: token schema (hash, scopes, expiry, revocation, last-used), the allow-list annotation contract, the architecture-test invariants, the feature-flag gating, the second-spec generation approach, the MCP-over-Streamable-HTTP loopback design, the draft/release-date rule, and the docs/skills/llms.txt layout. You review it, then implement (or hand to an agent with repo access).

2. **Reference implementations of the tricky pieces** in isolation, in TypeScript or Python, that you adapt:
   - SHA-256 PAT issuance/verification with scopes + expiry + revocation + last-used, plus the "authenticate as owner" middleware.
   - The allow-list annotation + architecture test (e.g. a test that walks route registrations and asserts every `@agentExposed` handler also carries a role annotation and returns a DTO type).
   - The OpenAPI subset generator + drift test (regenerate, diff against committed file, fail on mismatch).
   - A minimal MCP Streamable HTTP server whose tools proxy to your REST API over `127.0.0.1` forwarding the caller's bearer token.
   - The draft rule: token-created content gets `status=draft` and `releaseAt = now + N days`, with a publish job that flips it.

3. **A step-by-step implementation plan** with file paths, PR-sized commits, and the exact tests to write, so you or a repo-connected agent can execute it.

4. **The "deliberately left out" list** — I can draft this now, since it's design, not code: no refresh tokens, no per-token IP allow-listing, no token rotation UI, no OAuth device flow, no MCP resources/prompts (tools only), no streaming tool output, no multi-tenant scoping beyond owner, no audit log beyond last-used, no rate limiting per token, no scope hierarchy/inheritance, no admin-issued tokens, no webhook delivery, no draft auto-publish notifications.

**One flag on the design itself:** the loopback-proxy MCP design is good for reusing validation/authz, but it means the MCP server must run in the same trust boundary as the API and must not be exposed without the same auth. Worth calling out explicitly in the RFC.

Which of these would you like? If you paste the relevant Artemis PR diff and your app's auth/route conventions, I can make the design doc and reference code much more specific.

Source

English

Tools in this stack