Hello World MCP 서버 만들기: Python·TypeScript stdio와 Amazon Q 연결

반응형

MCP 서버의 최소 단위는 “host가 server process를 시작하고, tool 목록을 확인한 뒤, 인자를 넣어 호출해 결과를 받는 것”이다. Hello World 예제는 이 왕복을 가장 작은 코드로 확인하기 좋다.

기존 글의 Amazon Q Developer 실행 화면에는 say_hello tool이 호출되어 인사말을 반환한 기록이 남아 있다. 다만 당시 사용한 Python low-level decorator와 비공식 Node package는 현재 SDK 구조와 맞지 않는다. 아래 코드는 2026-07-28 MCP 공식 문서의 Python SDK 2.x와 TypeScript server package를 기준으로 다시 구성했다.

Amazon Q Developer가 MCP say_hello 도구를 호출해 인사말을 반환한 화면
직접 구현한 MCP server의 say_hello 호출 결과

먼저 확인할 stdio 규칙

local MCP server는 host가 child process로 실행하고 stdin·stdout으로 JSON-RPC message를 주고받을 수 있다. 이때 server가 print()console.log()로 stdout에 일반 log를 쓰면 protocol message가 깨진다.

  • Python log: standard logging처럼 stderr를 쓰는 방식
  • TypeScript log: console.error() 또는 file logger
  • tool result: SDK가 protocol response로 반환

Python: MCPServer로 say_hello 만들기

project를 만들고 공식 Python SDK를 추가한다.

uv init hello-mcp-python
cd hello-mcp-python
uv add "mcp[cli]"

server.py는 tool 하나만 노출한다.

from mcp.server import MCPServer

mcp = MCPServer("hello-python")


@mcp.tool()
def say_hello(name: str = "World") -> str:
    """Return a short greeting for the given name."""
    return f"Hello, {name}!"


if __name__ == "__main__":
    mcp.run(transport="stdio")

project environment에서 실행하면 server는 stdin을 기다린다. terminal prompt가 돌아오지 않는 것만으로 성공·실패를 판단하지 않는다.

uv run server.py

host나 MCP Inspector에서 tool 목록과 호출 결과까지 확인해야 protocol 왕복이 검증된다.

TypeScript: McpServer와 StdioServerTransport 연결하기

현재 공식 예제는 @modelcontextprotocol/server와 Zod schema를 사용한다.

mkdir hello-mcp-typescript
cd hello-mcp-typescript
npm init -y
npm install @modelcontextprotocol/server zod
npm install -D @types/node typescript

src/index.ts에 server와 tool을 등록한다.

import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";

const server = new McpServer({
  name: "hello-typescript",
  version: "1.0.0",
});

server.registerTool(
  "say_hello",
  {
    description: "Return a short greeting for the given name",
    inputSchema: z.object({
      name: z.string().default("World"),
    }),
  },
  async ({ name }) => ({
    content: [{ type: "text", text: `Hello, ${name}!` }],
  }),
);

const transport = new StdioServerTransport();
await server.connect(transport);

official quickstart처럼 tsconfig.json의 output을 build로 두고 compile한 뒤 node /absolute/path/build/index.js로 실행한다. host 설정은 TypeScript source가 아니라 build artifact를 가리켜야 한다.

Amazon Q 설정에서 command와 args를 읽는 법

개념상 host가 만드는 process는 다음 두 command와 같다.

uv --directory /ABSOLUTE/PATH/hello-mcp-python run server.py
node /ABSOLUTE/PATH/hello-mcp-typescript/build/index.js

이를 mcpServers schema로 표현하면 다음과 같다. 실제 저장 위치와 등록 command는 설치된 Amazon Q Developer CLI version의 공식 문서를 먼저 확인한다.

{
  "mcpServers": {
    "hello-python": {
      "command": "uv",
      "args": [
        "--directory",
        "/ABSOLUTE/PATH/hello-mcp-python",
        "run",
        "server.py"
      ]
    },
    "hello-typescript": {
      "command": "node",
      "args": [
        "/ABSOLUTE/PATH/hello-mcp-typescript/build/index.js"
      ]
    }
  }
}

command는 shell 문장 전체가 아니라 executable이고, args의 각 원소가 별도의 argv가 된다. GUI나 CLI가 다른 working directory에서 server를 시작할 수 있으므로 상대경로보다 절대경로가 안전하다. 상세한 실행 패턴은 Amazon Q Developer MCP의 command·args 설정, 실행기 차이는 uv·uvx·npm·npx 구분으로 이어진다.

성공 여부를 확인하는 순서

  1. uv run server.py 또는 compiled Node artifact가 즉시 error 없이 대기하는지 확인한다.
  2. host의 MCP status에서 server가 loaded 상태인지 본다.
  3. tool 목록에 say_hello가 노출되는지 확인한다.
  4. name을 넣어 호출하고 content가 반환되는지 확인한다.
  5. server log가 stdout이 아닌 stderr로 나가는지 확인한다.

PID가 존재하는지만으로 tool schema와 response가 맞는지는 알 수 없다. 반대로 host에서 보이지 않을 때는 package version보다 먼저 absolute path, build artifact, exit code, stdout 오염을 확인한다.

확장 전에 세울 안전 경계

Hello World 다음에 CI/CD나 IaC tool로 확장할 때는 처음부터 write 권한을 주지 않는다. read-only 조회와 dry-run을 기본으로 두고, 허용 resource·timeout·output size를 제한한다. credential을 source·args·일반 log에 넣지 않고 host의 secret 전달 방식과 최소 권한을 사용한다.

참고 자료

반응형
KEEP READING
카테고리 전체 보기 →

댓글