axmp-openapi-fastmcp-server 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,577 @@
1
+ Metadata-Version: 2.3
2
+ Name: axmp-openapi-fastmcp-server
3
+ Version: 1.1.0
4
+ Summary: Add your description here
5
+ Author: Kilsoo Kang
6
+ Author-email: Kilsoo Kang <kilsoo75@gmail.com>
7
+ Requires-Dist: diskcache>=5.6.3
8
+ Requires-Dist: fastmcp>=3.0.0
9
+ Requires-Dist: pathvalidate>=3.3.1
10
+ Requires-Dist: py-key-value-aio[redis]>=0.4.4
11
+ Requires-Dist: pydantic>=2.12.5
12
+ Requires-Dist: pydantic-settings>=2.12.0
13
+ Requires-Dist: python-dotenv>=1.2.1
14
+ Requires-Python: >=3.12
15
+ Description-Content-Type: text/markdown
16
+
17
+ # AXMP OpenAPI FastMCP Server
18
+
19
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
20
+ [![FastMCP](https://img.shields.io/badge/FastMCP-3.0.0b1+-green.svg)](https://github.com/jlowin/fastmcp)
21
+ [![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](LICENSE)
22
+
23
+ > **Multiple OpenAPI backends to a single MCP server** — Profile-based configuration with multi-provider OAuth support.
24
+
25
+ AXMP OpenAPI FastMCP Server는 여러 OpenAPI 호환 백엔드 서비스를 하나의 통합 MCP(Model Context Protocol) 서버로 노출하는 래퍼입니다. [FastMCP](https://github.com/jlowin/fastmcp) 프레임워크를 기반으로 OpenAPI 스펙의 각 operation을 MCP Tool로 자동 변환하며, Keycloak/Google/GitHub/Azure OAuth 인증을 지원합니다.
26
+
27
+ ---
28
+
29
+ ## Table of Contents
30
+
31
+ - [Architecture](#architecture)
32
+ - [Features](#features)
33
+ - [Project Structure](#project-structure)
34
+ - [Installation](#installation)
35
+ - [Configuration](#configuration)
36
+ - [Environment Variables](#environment-variables)
37
+ - [MCP Profile](#mcp-profile)
38
+ - [Backend Auth Config](#backend-auth-config)
39
+ - [Usage](#usage)
40
+ - [CLI Mode (HTTP)](#cli-mode-http)
41
+ - [CLI Mode (stdio)](#cli-mode-stdio)
42
+ - [Container Mode](#container-mode)
43
+ - [MCP Host Configuration](#mcp-host-configuration)
44
+ - [Authentication](#authentication)
45
+ - [Tool Configuration](#tool-configuration)
46
+ - [Docker](#docker)
47
+ - [Development](#development)
48
+ - [CI/CD](#cicd)
49
+
50
+ ---
51
+
52
+ ## Architecture
53
+
54
+ ```
55
+ ┌─────────────────────────────────────────────────────────────────┐
56
+ │ MCP Host │
57
+ │ (Claude Desktop, Cursor, etc.) │
58
+ └──────────────────────┬──────────────────────────────────────────┘
59
+ │ MCP Protocol (stdio / HTTP)
60
+
61
+ ┌─────────────────────────────────────────────────────────────────┐
62
+ │ AXMP OpenAPI FastMCP Server │
63
+ │ ┌───────────────────────────────────────────────────────────┐ │
64
+ │ │ OAuth Provider (Keycloak / Google / GitHub / Azure) │ │
65
+ │ └───────────────────────────────────────────────────────────┘ │
66
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
67
+ │ │ OpenAPI │ │ OpenAPI │ │ OpenAPI │ ... │
68
+ │ │ Provider A │ │ Provider B │ │ Provider C │ │
69
+ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
70
+ │ │ │ │ │
71
+ │ ┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐ │
72
+ │ │ httpx Client│ │ httpx Client│ │ httpx Client│ │
73
+ │ │ (API Key) │ │ (Bearer) │ │ (Basic) │ │
74
+ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
75
+ └─────────┼────────────────┼────────────────┼─────────────────────┘
76
+ ▼ ▼ ▼
77
+ ┌──────────┐ ┌──────────┐ ┌──────────┐
78
+ │ Backend │ │ Backend │ │ Backend │
79
+ │ Server A │ │ Server B │ │ Server C │
80
+ └──────────┘ └──────────┘ └──────────┘
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Features
86
+
87
+ - **Multi-Backend 통합** — 여러 OpenAPI 백엔드를 하나의 MCP 서버로 통합
88
+ - **Profile 기반 설정** — JSON 프로필로 백엔드 구성을 관리
89
+ - **Multi-Provider OAuth** — Keycloak, Google, GitHub, Azure 지원
90
+ - **Token Forwarding** — 업스트림 OAuth 토큰을 백엔드에 자동 전달
91
+ - **유연한 인증** — None / Basic / BearerToken / ApiKey 백엔드별 개별 인증
92
+ - **Tool Filtering** — `api_maps` (명시적) / `route_maps` (패턴) 기반 Tool 선택
93
+ - **Custom Tool Naming** — 기본 `operationId` 대신 사용자 정의 Tool 이름 지정
94
+ - **Tool Description Override** — Tool 설명을 프로필에서 직접 재정의
95
+ - **Dual Transport** — `stdio` (로컬) / `http` (원격) 전송 모드
96
+ - **Dual Entry Point** — CLI (인자 기반) / Container (환경변수 기반)
97
+ - **Multi-Arch Docker** — `linux/amd64`, `linux/arm64` 지원
98
+
99
+ ---
100
+
101
+ ## Project Structure
102
+
103
+ ```
104
+ axmp-openapi-fastmcp-server/
105
+ ├── src/axmp_openapi_fastmcp_server/
106
+ │ ├── __init__.py # Logging configuration
107
+ │ ├── __main__.py # python -m entry point
108
+ │ ├── settings.py # Pydantic Settings (MCP + OAuth)
109
+ │ ├── types.py # Enums (TransportType, OAuthProvider, AuthHeaderKey)
110
+ │ ├── multi_openapi_spec.py # Multi-backend configuration models
111
+ │ ├── openapi_fastmcp_server.py # Core wrapper (FastMCP + OpenAPI providers)
112
+ │ ├── runner/
113
+ │ │ ├── cli.py # CLI entry point (Click)
114
+ │ │ └── container.py # Container entry point (env-based)
115
+ │ └── auth/providers/
116
+ │ └── keycloak.py # Keycloak OAuth provider
117
+ ├── mcp_profiles/ # MCP profile & OpenAPI spec files
118
+ │ ├── mcp_profile_<id>.json # Backend configuration profiles
119
+ │ └── backend_server_<id>.json # OpenAPI spec files
120
+ ├── .env # Environment variables
121
+ ├── Dockerfile # Container image definition
122
+ ├── pyproject.toml # Project metadata & dependencies
123
+ ├── .github/workflows/
124
+ │ └── cicd-for-tag.yml # CI/CD pipeline (Docker build & push)
125
+ └── .pre-commit-config.yaml # Pre-commit hooks (ruff)
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Installation
131
+
132
+ ### Requirements
133
+
134
+ - Python >= 3.12
135
+ - [uv](https://docs.astral.sh/uv/) (recommended package manager)
136
+
137
+ ### Install from source
138
+
139
+ ```bash
140
+ # Clone repository
141
+ git clone <repository-url>
142
+ cd axmp-openapi-fastmcp-server
143
+
144
+ # Install dependencies
145
+ uv sync
146
+
147
+ # Or with pip
148
+ pip install -e .
149
+ ```
150
+
151
+ ### Install from package
152
+
153
+ ```bash
154
+ pip install axmp-openapi-fastmcp-server
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Configuration
160
+
161
+ ### Environment Variables
162
+
163
+ `.env` 파일 또는 시스템 환경변수로 설정합니다.
164
+
165
+ #### MCP Server Settings (`AXMP_MCP_` prefix)
166
+
167
+ | Variable | Description | Default | Required |
168
+ |----------|-------------|---------|----------|
169
+ | `AXMP_MCP_SERVER_NAME` | MCP 서버 이름 | - | Yes |
170
+ | `AXMP_MCP_PORT` | HTTP 리스닝 포트 | `21000` | No |
171
+ | `AXMP_MCP_TRANSPORT_TYPE` | 전송 방식 (`http` / `stdio`) | `http` | No |
172
+ | `AXMP_MCP_PROFILE_BASE_PATH` | MCP 프로필 디렉토리 경로 | - | Yes |
173
+ | `AXMP_MCP_PROFILE_ID` | 사용할 프로필 ID | - | Yes |
174
+ | `AXMP_MCP_USE_AUTHORIZATION` | OAuth 인증 활성화 | `False` | No |
175
+ | `AXMP_MCP_FORWARD_TOKEN_TO_BACKEND` | 업스트림 토큰을 백엔드에 전달 | `False` | No |
176
+ | `AXMP_MCP_REDIS_URL` | Redis 접속 URL. 설정 시 OAuth 스토리지가 Redis로 전환됨 (미설정 시 디스크). 형식: `redis://[user[:password]@]host[:port][/db]` 또는 TLS는 `rediss://...` | - | No |
177
+ | `AXMP_MCP_REDIS_KEY_PREFIX` | Redis 키 격리 prefix | `axmp-mcp:{SERVER_NAME}` | No |
178
+ | `AXMP_MCP_REDIS_CLIENT_TTL_DAYS` | DCR 클라이언트 등록 sliding TTL (일). 미사용 클라이언트 자동 청소 기간 | `14` | No |
179
+
180
+ > Redis 모드는 `AXMP_MCP_REDIS_URL` 존재 여부만으로 활성화됩니다. 서버 시작 시 ping으로 연결을 검증하며, 실패 시 서버가 시작되지 않습니다 (silent fallback 없음). URL에 password가 포함될 수 있어 내부적으로 `SecretStr`로 다루며, 로그에는 host:port만 노출됩니다.
181
+
182
+ #### OAuth Settings (`AXMP_OAUTH_` prefix)
183
+
184
+ | Variable | Description | Default | Required |
185
+ |----------|-------------|---------|----------|
186
+ | `AXMP_OAUTH_PROVIDER` | OAuth 제공자 (`keycloak` / `google` / `github` / `azure`) | `keycloak` | No |
187
+ | `AXMP_OAUTH_ISSUER_URL` | OAuth Issuer URL (Keycloak realm URL 등) | - | Yes* |
188
+ | `AXMP_OAUTH_CLIENT_ID` | OAuth Client ID | - | Yes* |
189
+ | `AXMP_OAUTH_CLIENT_SECRET` | OAuth Client Secret | - | Yes* |
190
+ | `AXMP_OAUTH_BASE_URL` | MCP 서버 base URL (callback용) | - | Yes* |
191
+ | `AXMP_OAUTH_REQUIRED_SCOPES` | 필요 OAuth 스코프 | `openid,profile,email` | No |
192
+ | `AXMP_OAUTH_STORAGE_PATH` | 토큰 저장 경로 | `~/.fastmcp/server/oauth-proxy` | No |
193
+
194
+ > \* `AXMP_MCP_USE_AUTHORIZATION=True`인 경우 필수
195
+
196
+ #### Example `.env`
197
+
198
+ ```bash
199
+ # MCP Server
200
+ AXMP_MCP_SERVER_NAME="axmp-openapi-fastmcp-server"
201
+ AXMP_MCP_PORT=8000
202
+ AXMP_MCP_TRANSPORT_TYPE="http"
203
+ AXMP_MCP_USE_AUTHORIZATION="True"
204
+ AXMP_MCP_FORWARD_TOKEN_TO_BACKEND="True"
205
+ AXMP_MCP_PROFILE_BASE_PATH="/path/to/mcp_profiles"
206
+ AXMP_MCP_PROFILE_ID="1234567890"
207
+
208
+ # OAuth (Keycloak)
209
+ AXMP_OAUTH_PROVIDER="keycloak"
210
+ AXMP_OAUTH_ISSUER_URL="https://keycloak.example.com/auth/realms/your-realm"
211
+ AXMP_OAUTH_CLIENT_ID="studio-client"
212
+ AXMP_OAUTH_CLIENT_SECRET="your-client-secret"
213
+ AXMP_OAUTH_BASE_URL="http://127.0.0.1:8000"
214
+ AXMP_OAUTH_STORAGE_PATH="/path/to/.fastmcp/server/oauth-proxy"
215
+
216
+ # Redis OAuth storage (optional — enables shared storage across instances)
217
+ # AXMP_MCP_REDIS_URL="redis://:redis-password@redis.example.com:6379/0"
218
+ ```
219
+
220
+ ### MCP Profile
221
+
222
+ MCP 프로필은 백엔드 서버 구성을 정의하는 JSON 파일입니다. 파일 이름은 `mcp_profile_<profile-id>.json` 형식을 따릅니다.
223
+
224
+ ```json
225
+ {
226
+ "backends": [
227
+ {
228
+ "server_name": "studio-backend",
229
+ "endpoint": "https://api.example.com",
230
+ "base_path": "/api/v1",
231
+ "timeout": 10,
232
+ "tls_verify": true,
233
+ "spec_file_path": "studio-api.json",
234
+ "auth_config": {
235
+ "type": "ApiKey",
236
+ "api_key_name": "X-Access-Key",
237
+ "api_key_value": "your-api-key"
238
+ },
239
+ "tool_config": {
240
+ "api_maps": [
241
+ {
242
+ "path": "/api/v1/agents",
243
+ "methods": ["get", "post"]
244
+ },
245
+ {
246
+ "path": "/api/v1/agents/{agent_id}",
247
+ "methods": [
248
+ {
249
+ "method": "get",
250
+ "tool_name": "get_agent_by_id",
251
+ "description": "Get agent details by ID"
252
+ }
253
+ ]
254
+ }
255
+ ]
256
+ }
257
+ }
258
+ ]
259
+ }
260
+ ```
261
+
262
+ #### Backend Configuration Fields
263
+
264
+ | Field | Type | Description | Required |
265
+ |-------|------|-------------|----------|
266
+ | `server_name` | `string` | 백엔드 식별 이름 | Yes |
267
+ | `endpoint` | `string` | 백엔드 서버 URL | Yes |
268
+ | `base_path` | `string` | API base path | No |
269
+ | `timeout` | `float` | 요청 타임아웃 (초) | No (`10`) |
270
+ | `tls_verify` | `bool` | TLS 인증서 검증 | No (`true`) |
271
+ | `spec_file_path` | `string` | OpenAPI spec JSON 파일 (프로필 디렉토리 기준 상대경로) | Yes |
272
+ | `auth_config` | `object` | 백엔드 인증 설정 | Yes |
273
+ | `tool_config` | `object` | Tool 필터링 및 커스터마이징 설정 | Yes |
274
+
275
+ ### Backend Auth Config
276
+
277
+ | Auth Type | Fields | Description |
278
+ |-----------|--------|-------------|
279
+ | `None` | - | 인증 없음 |
280
+ | `Basic` | `username`, `password` | HTTP Basic 인증 |
281
+ | `BearerToken` | `bearer_token` | Bearer 토큰 인증 |
282
+ | `ApiKey` | `api_key_name`, `api_key_value` | 커스텀 헤더 API 키 |
283
+
284
+ ---
285
+
286
+ ## Usage
287
+
288
+ ### CLI Mode (HTTP)
289
+
290
+ ```bash
291
+ axmp-openapi-fastmcp-server \
292
+ --port 21000 \
293
+ --transport http \
294
+ --server-name axmp-mixed-openapi-mcp-server \
295
+ --profile-base-path /path/to/mcp_profiles \
296
+ --profile-id 1234567890 \
297
+ --backend-server-auth-configs "studio-backend:X-Access-Key=your-api-key,workspace-backend:X-Access-Key=your-api-key"
298
+ ```
299
+
300
+ ### CLI Mode (stdio)
301
+
302
+ ```bash
303
+ axmp-openapi-fastmcp-server \
304
+ --transport stdio \
305
+ --profile-base-path /path/to/mcp_profiles \
306
+ --profile-id 1234567890 \
307
+ --backend-server-auth-configs "studio-backend:X-Access-Key=your-api-key"
308
+ ```
309
+
310
+ #### CLI Options
311
+
312
+ | Option | Description | Default |
313
+ |--------|-------------|---------|
314
+ | `--transport` | 전송 방식 (`stdio` / `http` / `sse` / `streamable-http`) | `streamable-http` |
315
+ | `--port` | HTTP 리스닝 포트 | `21000` |
316
+ | `--server-name` | MCP 서버 이름 | `axmp-openapi-fastmcp-server-<profile-id>` |
317
+ | `--profile-base-path` | MCP 프로필 디렉토리 경로 | - (필수) |
318
+ | `--profile-id` | 프로필 ID | - (필수) |
319
+ | `--backend-server-auth-configs` | 런타임 인증 오버라이드 | - |
320
+
321
+ #### `--backend-server-auth-configs` Format
322
+
323
+ 프로필의 auth 설정을 런타임에 오버라이드합니다:
324
+
325
+ ```
326
+ <server-name>:<key-name>=<value>,<server-name>:<key-name>=<value>
327
+ ```
328
+
329
+ - **ApiKey**: `studio-backend:X-Access-Key=zmp-xxxxx`
330
+ - **BearerToken**: `studio-backend:bearer_token=eyJhbGci...`
331
+ - **Basic**: `studio-backend:username=admin,studio-backend:password=secret`
332
+
333
+ ### Container Mode
334
+
335
+ 환경변수 기반으로 실행됩니다. `.env` 파일 또는 시스템 환경변수를 설정한 후:
336
+
337
+ ```bash
338
+ uv run axmp-container-fastmcp-server
339
+ ```
340
+
341
+ ### MCP Host Configuration
342
+
343
+ #### Claude Desktop / Cursor
344
+
345
+ `claude_desktop_config.json` 또는 MCP 호스트 설정에 추가:
346
+
347
+ ```json
348
+ {
349
+ "mcpServers": {
350
+ "axmp-openapi-fastmcp-server": {
351
+ "command": "python3",
352
+ "args": [
353
+ "-m",
354
+ "axmp_openapi_fastmcp_server",
355
+ "--transport", "stdio",
356
+ "--profile-base-path", "/path/to/mcp_profiles",
357
+ "--profile-id", "1234567890",
358
+ "--backend-server-auth-configs",
359
+ "studio-backend:X-Access-Key=your-api-key"
360
+ ]
361
+ }
362
+ }
363
+ }
364
+ ```
365
+
366
+ ---
367
+
368
+ ## Authentication
369
+
370
+ ### OAuth Flow (HTTP transport)
371
+
372
+ `AXMP_MCP_USE_AUTHORIZATION=True`이고 transport가 `http`인 경우 OAuth 인증이 활성화됩니다.
373
+
374
+ ```
375
+ MCP Client → MCP Server → OAuth Provider (Keycloak/Google/GitHub/Azure)
376
+
377
+ ├─ Token Introspection (검증)
378
+ ├─ User Info Extraction (사용자 정보)
379
+ └─ Scope Validation (스코프 확인)
380
+ ```
381
+
382
+ ### Token Forwarding
383
+
384
+ `AXMP_MCP_FORWARD_TOKEN_TO_BACKEND=True`이고 백엔드 auth type이 `BearerToken`인 경우, 업스트림 OAuth 토큰이 자동으로 백엔드 요청에 주입됩니다.
385
+
386
+ ### Supported OAuth Providers
387
+
388
+ | Provider | Class | Description |
389
+ |----------|-------|-------------|
390
+ | `keycloak` | `KeyCloakProvider` | Custom implementation with token introspection |
391
+ | `google` | `GoogleProvider` | FastMCP built-in |
392
+ | `github` | `GitHubProvider` | FastMCP built-in |
393
+ | `azure` | `AzureProvider` | FastMCP built-in |
394
+
395
+ ---
396
+
397
+ ## Tool Configuration
398
+
399
+ ### api_maps (Explicit)
400
+
401
+ 특정 경로와 메서드를 명시적으로 MCP Tool로 등록합니다:
402
+
403
+ ```json
404
+ {
405
+ "api_maps": [
406
+ {
407
+ "path": "/api/v1/agents",
408
+ "methods": ["get", "post"]
409
+ },
410
+ {
411
+ "path": "/api/v1/agents/{agent_id}",
412
+ "methods": [
413
+ {
414
+ "method": "get",
415
+ "tool_name": "get_agent_detail",
416
+ "description": "Get agent details"
417
+ }
418
+ ]
419
+ }
420
+ ]
421
+ }
422
+ ```
423
+
424
+ - 문자열 메서드: OpenAPI `operationId`를 Tool 이름으로 사용
425
+ - 객체 메서드: `tool_name`과 `description` 커스터마이징 가능
426
+ - `api_maps`만 사용 시 명시되지 않은 경로는 자동 제외 (`MCPType.EXCLUDE`)
427
+
428
+ ### route_maps (Pattern)
429
+
430
+ 정규식 패턴으로 Tool을 필터링합니다:
431
+
432
+ ```json
433
+ {
434
+ "route_maps": [
435
+ {
436
+ "pattern": "^/api/alert/v1/channels/.*",
437
+ "methods": ["get"],
438
+ "tags": []
439
+ },
440
+ {
441
+ "pattern": "^/api/alert/v1/admin/.*",
442
+ "methods": ["post"],
443
+ "tags": ["alerts"]
444
+ }
445
+ ]
446
+ }
447
+ ```
448
+
449
+ ---
450
+
451
+ ## Docker
452
+
453
+ ### Build
454
+
455
+ ```bash
456
+ docker build -t axmp-openapi-fastmcp-server .
457
+ ```
458
+
459
+ ### Run
460
+
461
+ ```bash
462
+ docker run -d \
463
+ --env-file .env \
464
+ -p 8000:8000 \
465
+ -v /path/to/mcp_profiles:/application/mcp_profiles \
466
+ axmp-openapi-fastmcp-server
467
+ ```
468
+
469
+ ### Dockerfile Overview
470
+
471
+ ```dockerfile
472
+ FROM python:3.12.10-slim
473
+ WORKDIR /application
474
+
475
+ # Virtual env + uv install
476
+ RUN python -m venv /application/.venv && \
477
+ /application/.venv/bin/pip install uv
478
+
479
+ # Install dependencies (production only)
480
+ COPY . .
481
+ RUN /application/.venv/bin/uv sync --no-cache --no-dev
482
+
483
+ # Container entry point (env-based)
484
+ CMD ["/application/.venv/bin/axmp-container-fastmcp-server"]
485
+ ```
486
+
487
+ ---
488
+
489
+ ## Development
490
+
491
+ ### Setup
492
+
493
+ ```bash
494
+ # Install dev dependencies
495
+ uv sync
496
+
497
+ # Install pre-commit hooks
498
+ pre-commit install
499
+ ```
500
+
501
+ ### Linting & Formatting
502
+
503
+ ```bash
504
+ # Lint
505
+ uv run ruff check .
506
+
507
+ # Format
508
+ uv run ruff format .
509
+ ```
510
+
511
+ ### Testing
512
+
513
+ ```bash
514
+ # Run tests
515
+ uv run pytest
516
+
517
+ # Watch mode
518
+ uv run ptw
519
+ ```
520
+
521
+ ### Pre-commit Hooks
522
+
523
+ | Hook | Description |
524
+ |------|-------------|
525
+ | `trailing-whitespace` | 후행 공백 제거 |
526
+ | `end-of-file-fixer` | 파일 끝 개행 보장 |
527
+ | `debug-statements` | `pdb` import 감지 |
528
+ | `ruff` | Lint & auto-fix |
529
+ | `ruff-format` | 코드 포맷팅 |
530
+
531
+ ---
532
+
533
+ ## CI/CD
534
+
535
+ GitHub Actions를 통해 semantic versioning 태그(`v*.*.*`) 푸시 시 자동 빌드 & 배포됩니다.
536
+
537
+ ### Pipeline
538
+
539
+ ```
540
+ git tag v1.0.0 → push → GitHub Actions
541
+ ├─ Checkout
542
+ ├─ Setup QEMU (multi-arch)
543
+ ├─ Setup Docker Buildx
544
+ ├─ Login to Private Registry
545
+ ├─ Extract metadata (semver tags)
546
+ └─ Build & Push (linux/amd64, linux/arm64)
547
+ ```
548
+
549
+ ### Registry
550
+
551
+ - **Registry**: `zcr.cloudzcp.net`
552
+ - **Image**: `zcr.cloudzcp.net/cloudzcp/axmp-openapi-fastmcp-server`
553
+ - **Platforms**: `linux/amd64`, `linux/arm64`
554
+
555
+ ---
556
+
557
+ ## Tech Stack
558
+
559
+ | Category | Technology |
560
+ |----------|------------|
561
+ | Language | Python 3.12+ |
562
+ | MCP Framework | [FastMCP](https://github.com/jlowin/fastmcp) >= 3.0.0b1 |
563
+ | Settings | Pydantic Settings |
564
+ | HTTP Client | httpx (async) |
565
+ | CLI | Click |
566
+ | OAuth | Keycloak / Google / GitHub / Azure |
567
+ | Encryption | Fernet (cryptography) |
568
+ | Build | uv |
569
+ | Linting | Ruff |
570
+ | Container | Docker (multi-arch) |
571
+ | CI/CD | GitHub Actions |
572
+
573
+ ---
574
+
575
+ ## Author
576
+
577
+ **Kilsoo Kang** — kilsoo75@gmail.com