Skip to main content
Glama

MCP Eval Demo

평가(evals)를 통해 LLM 에이전트가 MCP 서버를 실제로 효과적으로 사용할 수 있는지 검증하는 작업 예시입니다 — 단지 서버의 코드가 올바른지 확인하는 정도가 아닙니다.

단위 테스트는 "delete_note가 메모를 삭제하는가?"에 답합니다. 하지만 MCP 서버가 실제로 유용한지를 결정하는 다음 질문들에는 답할 수 없습니다.

  • 사용자가 id로 말하는 대신 말로 그 표현할 때, 에이전트가 올바른 메모를 찾아내는가?

  • 목록 미리보기가 잘렸다는 것을 알아내는가, 아니면 반쪽만 있는 메모로 답하는가?

  • update_note가 덮어쓴다는 것을 아는지, 아니면 "내 장보기 목록에 한 줄 추가해 줘"라는 요청에, sọng 사용자의 내용을 조용히 파괴하지 않는가?

  • 오류 메시지 속에서 회복할 수 있는가, 아니면 포기하는가?

이런 것들은 도구 표면(tool surface) — 이름, 설명, 스키마, 결과 형태, 오류 텍스트 — 의 속성이며, 이를 확인하는 유일한 방법은 실제 에이전트를 서버에 해당하는 실행해 무엇을 했는지 평가하는 것입니다. 이 저장소는 바로 그런 목적이 있습니다.

상태

MCP 서버와 그 인프라, 평가 하네스(eval harness)가 모두 준비되어 있습니다.

Related MCP server: MCP Notepad Server

테스트 대상 서버: Notes MCP

인메모리 노트장입니다. 상태는 서버 프로세스에 존재하며 종료 시 폐기되므로, 모든 평가 실행이 동일한 기존 데이터 코퍼스에서 출발합니다(seed.py 참조).

도구

동작 힌트

기능

create_note

쓰기

메모를 생성합니다. 제목은 대소문자를 구분하지 않고 로 고유해야 합니다.

get_note

읽기 전용

id로 지정한 메모 하나의 전체 내용을 반환합니다.

list_notes

읽기 전용

최신 수정 순으로 메모를 나열하고, 잘린(id적인) 미리보기 형태로 표시하며 선택적으로 부분 문자열 query를 받습니다.

update_note

파괴적

메모의 제목 및/또는 내용을 덮어씁니다.

delete_note

파괴적

메모를 완전히 삭제합니다.

평가가 무언가를 걸러낼 수 있도록 여러 설계 선택이 의도적으로 들어 있습니다.

  • ID이지 제목이 아니라. 모든 변경 도구는 note_id를 받습니다. 그래서 "내 장보기 목록"을 변경하라는 에이전트는 먼저 id를 찾아야 합니다. 에이전트가 이 부분에서 추측을 자주 범합니다.

  • 잘린 미리보기. list_notes는 각 메모의 처음 120자만 반환하며, content_truncatedcontent_length로 그 사실을 알려 줍니다. 목록에서 그대로 내용 질문에 답하는 에이전트는 틀리기 마련입니다. 제대로된 에이전트는 get_note를 감에 감니다.

  • 추가가 아닌 덮어쓰기. update_note는 덮어씁니다. 따라서 "내 장보기 목록에 계란 추가"는 곧 것을 읽기-수정-쓰기이며, 읽기를 생략없이 에이전트는 데이터를 파괴합니다.

  • 가르쳐 내는 오류. 모든 실패는 문제가 되는 값을 명시하고, 그 값을 해결할 도구는 무엇인지 짚어 주어, 최첨단의 길이 아닌 앞으로 나아갈 수 있는 길을 에이전트에게 남겨 줍니다.

구성

src/notes_mcp/
  models.py    Pydantic models — also the tool input/output schemas the agent sees
  store.py     In-memory storage and its error types
  seed.py      Fixed corpus: stable ids and timestamps, so evals are reproducible
  server.py    MCP tool definitions, descriptions, and annotations
  cli.py       `notes-mcp` entry point
evals/
  agent.py       Builds the pydantic-ai agent under test + local trace capture
  task.py        One agent turn against a freshly seeded server — the thing evaluated
  evaluators.py  Custom pydantic-evals evaluators (tool-not-called, argument-contains)
  cases.yaml     The dataset itself: cases that probe specific MCP misuse patterns
  cases.py       Loads cases.yaml — registers the custom evaluators, picks the judge model
  __main__.py    `python -m evals` — runs the dataset against a live model
tests/
  test_store.py    Unit tests for the storage layer
  test_server.py   Protocol-level tests through a real MCP client session
scripts/
  lint.sh    Ruff + pyright + format check
  test.sh    Unit + protocol tests (fast, free)
  evals.sh   Agent-behaviour evals against a live model (slow, costs money)

도구 설명은 인라인 docstring으로 구성하는 것이 아니라 server.py의 모듈 수준 상수로서 존재합니다. 설명 문구는 평가가 실패할 때 가장 많이 조정하게 되는 대상이며, 이를 한 곳에 모아두기 때문에 연간 파일의 변경 내용을 읽을 수 있습니다.

시작하기

uv와 Python 3.12(.python-version에 고정)가 필요합니다.

uv sync                       # create .venv and install everything
uv run scripts/test.sh        # unit + protocol tests
uv run scripts/lint.sh        # ruff check, pyright (strict), format check
uv run pre-commit install     # optional: run the same checks on commit

서버 만들기

uv run notes-mcp                        # stdio, seeded with the sample notes
uv run notes-mcp --empty                # stdio, no notes
uv run notes-mcp --transport streamable-http

.mcp.json이 이 프로젝트의 stdio 서버를 등록하므로, 이 디렉토리에서 시작되는 MCP 호스트 — 예를 들어 Claude Code — 는 자동으로 notes 서버를 인식하여 직접 입력을 통해 제어할 수 있습니다.

에이전트를 시작하지 않고도, 이 평가들이 사실상 살피는 대상인 사용자에게 시작될 도구 표면(tool surface)을 확인하려면:

uv run fastmcp list .mcp.json                   # names, signatures, descriptions
uv run fastmcp list .mcp.json --input-schema    # ...with the full JSON schemas
npx @modelcontextprotocol/inspector uv run notes-mcp   # MCP Inspector, for clicking around

mcp 버전에 관한 참고: 서버는 mcp SDK 안에 mcp.server.fastmcp로 번들로 제공되던 복제본이 아닌, 스탠드얼론 FastMCP 라이브러리 기반으로 만들어집니다 — mcp 2.0이 대해 그 모듈은 삭제되었습니다. FastMCP가 자체적으로 필요로 하는 mcp 버전을 정하며(3.x는 mcp 1.x을 지정합니다), 따라서 pyproject.toml에는 수동으로 쓴 mcp 제한이 아닙니다. 평가러 하네스는 반대 방식으로 동일한 라이브러리를 접촉합니다. pydantic-ai의 MCP 클라이언트가 FastMCP의 Client를 기반으로 합니다. 이 저장소의 양쪽 절파(server와 eval)는 따라서 유지 다음에 하는 핀 고정이 아니라, 그 구축 자체로 버전을 함께 만나갑니다. FastMCP 4는 양쪽 모두를 mcp 2.x로 옮겨 주는 단계고, 그래서 이 의존성은 그 아래로 캡되어 있습니다.

테스트 접근법

두 가지 pytest 레이어를 scripts/test.sh로 돌립니다:

  • test_store.py — 저장소 의미론(고유성, 정렬 순서, 제한, 타임스탬프)를 다룹니다. 빠르고 폭넓게 검사하며 프로토콜은 전혀 관여하지 않습니다.

  • test_server.py — 프로세스 내 MCP 클라이언트 세션(fastmcp.Client, FastMCP의 인메모리 전송)으로 서버를 구동하고, 에이전트가 실제로 받아 가지는 것 – 도구 목록, JSON 스키마, 행동 어노테이션, 구조화된 결과, 오류 텍스트 — 을 검증합니다. 프로토콜 자체는 실제 실행되며, 단지 서브프로세스와 소켓이 없는 것뿐입니다.

비동기 테스트는 pytest-asyncio 대신 anyio pytest 플러그인을 사용합니다. MCP 클라이언트는 세션 수명 전제에 취소 스코프(cancel scope)를 열어 두며, anyio는 픽스처의 준비와 정리를 동일한 테스크에서 실행해 주기 때문입니다.

세 번째 종류인 — 에이전트 행동 평가는 — 실제 모델을 호출하며 비용이 들기 때문에 pytest 묶음에는 전혀 포함되지 않고, 자체 실행기와 스크립트를 두고 있습니다. 이어지는 절에서 설명합니다.

평가 하네스

evals/는 최소한의 pydantic-ai 에이전트 — 일반적인 한 줄 시스템 프롬프트, 몇몇샷 예제 없음, 특별한 지침 없는 — 를 구성하고, 유일하게 연결된 도구를 pydantic_ai.mcp.MCPToolset를 통해 프로세스 내 Notes MCP 서버에 있는 것으로 만들어 줍니다(agent.py). 시스템 프롬프트를 일부러 비우고 있습니다. 이 평가가 진짜로 확인하는 것은 서버 자체의 도구 이름, 설명, 스키마가 올바른 동작을 유지하기 충분한가 하는 일이지, 프롬프트 전략으로 약한 도구 표면을 덮어 쓰는 일이 아니기 때문입니다.

evals/src/ 아래가 아니라 최상위에 위치합니다. 이 저장소 자체를 위한 개발 도구이지, 누군가가 설치하게 될 notes-mcp 패키지의 일부가 아닙니다.

pydantic_evals는 그 에이전트를, 각각이 이 문서 상단에서 다루는 네 가지 행동 중 하나를 대상으로 하는 로 이루어진 DatasetCase들 위해 돌립니다:

Case

검사 내용

delete_by_description_looks_up_the_id_first

"내가 복용량 메모를 삭제하라"고 요청하면, 에이전트는 delete_note 이전에 list_notes를 호출하고 올바른 id를 삭제.

answers_past_the_list_notes_preview_cutoff

list_notes 미리보기로부터 답이 절단되지 않는 질문은, 에이전트가 get_note을 호출 할 때만 올바르게 답한다.

appending_to_a_note_preserves_its_truncated_tail

"내 장바구니에 크래커 추가"의 경우는 먼저 본문 메모를 전부 읽어야 하며, update_note 호출이 미리보기 절단 것보다 뒤에 존재했던 원문 텍스트를 출시당 유지하는지 검사한다.

title_conflict_on_create_is_not_silently_lost

제목이 이미 있는 상태로 메모를 새로 만들 때, 새 내용을 조용히 누락시키거나 중복 메모가 만들어졌다고 주장해는 안 되다.

deleting_a_nonexistent_note_does_not_fabricate_success

존재하지 않는 메모 삭제를 요청받은 경우, 임의로 추측한 id로 delete_note를 호출하거나 성공을 스스로 주장해서는 안 된다.

simple_lookup_answers_from_the_right_note

정상 작동을 지금 확인하는 행복 경로(해피 패스) 테스트다.

사례들은 Python이 아니라 cases.yaml에 데이터로 들어 있습니다. 파이썬 대신 데이터로 두기 때문에 사례를 추가하거나 평가 루틴의 쓰여진 문구를 바꾸더라도 코드에는 손을 대지 않아도 됩니다. cases.py는 단지 로더일 뿐이며, 매뉴얼 정의한 평가자 알고리즘을 Dataset.from_file에 넘겨주고(YAML 파일은 그 로더가 등록한 것만 이름으로 지정할 수 있습니다) judge 모델을 설정합니다. YAML 파일의 yaml-language-server 헤더는 파일을 시작할 때 cases시그말 스키마를 가리켜 편집기가 편집하는 평가자 이름과 그 인자를 자동으로 완성·검증할 수 있게 합니다. 사용자 정의 평가자를 추가하거나 바꾼 뒤에는 이것을 다시 만들면 됩니다:

uv run python -c "from evals.cases import write_json_schema; print(write_json_schema())"

평가자는 pydantic-방식의 내장 평가자(ToolCorrectness, Contains, MaxToolCalls, LLMJudge — 유효한 대처가 두 대 이상인 사례용)에다 작은 맞춤 평가자 두 개를 evaluators.py에서 합쳐 씁니다. ToolNotCalled(도구가 절대로 호출되지 않아야 함 — 이에 대응하는 내장 부정형 검사는 존재하지 않습니다)와 ArgWithSubstring(LLM의 정확한 문장을 일치 또는 부분집합 사전으로 단정할 수 없는 — "이전 내용이 유지되어야 하는" 사례들을 위해, 도구 인자 안에 부분적 문자열이 있는지를 조사합니다)입니다. 이 두 사용자 정의평가자 역시 내장 평가자와 마찬가지로, 도구 호출 범위(tool-call span)를 읽습니다. 이를 통해서 Agent.instrument_all()과 로거(send_to_logfire=False)의 로컬 logfire.configure()가 잡아 주며, 자세한 것은 agent.pyconfigure_instrumentation()을 참조하세요.

__main__.py는 데이터셋을 실행하고 전체 리포트를 출력하며, 하나라도 실패하면 0이 아닌 종료 상태를 반환합니다. 실패란 test 함수 오류, 크래시난 평가자, 또는 어설션 실패를 뜻합니다. 다음과 같이 실행합니다:

uv run scripts/evals.sh

공급자(provider) 구성

NOTES_MCP_EVAL_MODEL은 pydantic-ai의 provider:model 문자열에 따라 공급자와 모델을 모두 선택하며, 기본값은 anthropic:claude-haiku-4-5-20251001입니다. .env.example.env로 복사하고, 다음 세 공급자 중 자신이 쓰는 공급자의 섹션을 채우세요. scripts/evals.sh.env를 자동으로 읽습니다(python-dotenv파라미터를 사용하며, 셸에 이미 들어 있는 변수를 절대 덮어쓰지 않습니다). .env은 gitignore되어 있고, 다음과 같습니다:

  • Anthropic API (기본값) — ANTHROPIC_API_KEY가 필요합니다.

  • OpenAINOTES_MCP_EVAL_MODEL=openai:gpt-5OPENAI_API_KEY.

  • Amazon BedrockNOTES_MCP_EVAL_MODEL=bedrock:<bedrock-model-id>. boto3의 표준 인증 체인을 통해 인증되므로, 일반적인 AWS SDK 변수 외에 별도의 평가용 설정은 필요 없습니다: AWS_PROFILE에 명명된 프로필을 쓰려는 경우 설정하면 됩니다(AWS_DEFAULT_REGION도 함께 설정해야 하는데, 프로필에 기존 region이 없다면 말입니다 — 이 변수는 AWS_REGION가 아니고, 반드시 AWS_DEFAULT_REGION이어야 합니다. boto3의 region 판단은 그곳을 보지 않습니다). 두 변수 모두 두지 않으면 기본 프로필/리전을 사용합니다.

어떤 공급자든 코드가 그 공급자에 따라 분기를 만들지는 않습니다. eval_model()이 돌려주는 문자열은 에이전트와 LLMJudge 양쪽에 그대로 전달하며, pydantic-ai의 infer_model이 확인하려는 접두사에 맞는 클라이언트와 자격 증명을 결정합니다.

Install Server
F
license - not found
A
quality
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

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    A simple notes system that allows creating, storing, and accessing text notes through MCP resources and tools, with built-in prompt support for generating summaries of stored notes.
  • F
    license
    B
    quality
    D
    maintenance
    A learning-focused MCP server that demonstrates core MCP concepts through a simple notepad application, enabling users to create, update, delete, and search notes while exploring tools, resources, and prompts functionality.
    4
  • F
    license
    A
    quality
    D
    maintenance
    A minimal MCP server demonstrating tools, resources, and prompts for managing notes, with a simple notes app that supports adding, listing, deleting notes and summarizing them.
    3
    1

View all related MCP servers

Related MCP Connectors

  • Cross-session, cross-device memory for your agent: remember and recall notes. No key to start.

  • Shared, governed long-term memory for AI agents across tools and sessions via MCP and REST.

  • AI access to your aNotepad online notes: read, search, write, and organize via 22 tools.

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/jasongilman/mcp-eval-demo'

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