
ツールアクセスとエージェント連携のための、統合的でセキュリティ優先のワイヤープロトコル。UAPは、Ed25519署名付きCapabilityCards、必須のmTLS、Keycloak IdP認証、および呼び出しごとの一時的なDockerサンドボックスを使用して、CVE-2025-49596とMCPツールポイズニングの脆弱性を排除します。
██╗ ██╗ █████╗ ██████╗
██║ ██║██╔══██╗██╔══██╗
██║ ██║███████║██████╔╝
██║ ██║██╔══██║██╔═══╝
╚██████╔╝██║ ██║██║
╚═════╝ ╚═╝ ╚═╝╚═╝
Universal Agent Protocol
ツールアクセス、エージェント連携、構造化 RPC のための、セキュリティ最優先の統合ワイヤープロトコル。 CVE-2025-49596 と、MCP が構造的に残していたツールポイズニングおよびサンドボックスエスケープの脆弱性クラスを塞ぐために構築されました。
git clone https://github.com/RajSidwadkar/UAP-protocol
cd UAP-protocol
npm install
npx tsx scripts/generate-keypair.ts
docker compose -f docker-compose.dev.yml up -d
curl http://localhost:3000/health
# {"status":"ok","version":"1.0.0"}
これにより Keycloak が :8080 で、UAP ゲートウェイが :3000 で起動します。ゲートウェイは mTLS を強制し、Ed25519 署名付き CapabilityCard を検証し、すべてのツール呼び出しを一時的な Docker コンテナ内で実行します。生成したキーペア以外に設定は不要です。
graph TD
A[Client / Agent SDK] -->|mTLS + JWT + card_sig| B[UAP Gateway<br/>Fastify · port 3000]
B --> C{8-Stage Pipeline}
C --> C1[1 · Frame parse<br/>UapMessageFactory]
C1 --> C2[2 · Schema validate<br/>AJV against schema_ref]
C2 --> C3[3 · Token verify<br/>Keycloak JWKS · max 15 min]
C3 --> C4[4 · Scope enforce<br/>PermissionEnforcer]
C4 --> C5[5 · Card verify<br/>Ed25519 signature check]
C5 --> C6[6 · Sandbox execute<br/>Docker · CapDrop ALL · 128 MB]
C6 --> C7[7 · Audit emit<br/>AuditEventBus · non-blocking]
C7 --> C8[8 · Response<br/>UapResponseEnvelope]
B --> R[(Service Registry<br/>InMemory · Redis)]
B --> KC[(Keycloak IdP<br/>OAuth 2.1 · PKCE)]
B --> OT[(OpenTelemetry<br/>W3C TraceContext)]
B --> AU[(Audit Log<br/>append-only NDJSON)]ヘキサゴナルレイヤー — ドメインは I/O 依存がゼロです。すべてのインフラストラクチャ上の関心事は型付きポートインターフェースの背後に置かれます。Docker を WASM に、Keycloak を Auth0 に、Pino を SIEM エクスポーターに置き換えても、ドメインへの影響はゼロです。
CVE-2025-49596(署名なしメタデータによるツールポイズニング)。 MCP のツール説明は公開後に変更可能です。攻撃者はデプロイ後にツール名や説明へ悪意のある指示を注入できますが、クライアントには改ざんを検知する手段がありません。UAP はすべてのツールメタデータを Ed25519 署名付き CapabilityCard ペイロード内に置きます。署名後のあらゆる変更は署名を無効化し、ゲートウェイは何かを実行する前にカードを拒否します。
CWE-284 / サンドボックスエスケープのクラス。 MCP はサーバープロセスレベルでツールを実行します。いずれかのツールでのパストラバーサルまたはプロセスインジェクションは、ホストのファイルシステムとネットワークに到達します。UAP は呼び出しごとに新しい Docker コンテナを作成します — 読み取り専用の rootfs、CapDrop: ALL、128 MB の RAM 上限、ネットワークはデフォルトで無効。コンテナはレスポンス後に破棄されます。呼び出し間に持続する攻撃対象領域はありません。
CWE-287 / confused-deputy 認証。 MCP は自身が OAuth プロバイダーとして機能するため、リソースサーバーと認可サーバーの両方の役割を持ちます。これは典型的な confused-deputy パターンです。UAP はこれらの役割を分離します:ゲートウェイは純粋なリソースサーバーです。Keycloak(または任意の外部 IdP)が唯一の権威です。JWT はリモートの JWKS エンドポイントに対して検証され、15 分でハードキャップされます。
すべての UAP メッセージは同じエンベロープを使用します。auth ブロックにはスコープ付き JWT と、エージェントの署名付き CapabilityCard への参照が含まれます。ゲートウェイはリクエストがアプリケーションコードに到達する前に両方を検証します。
{
"uap": {
"version": "1.0",
"type": "tool_call",
"id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
"trace": {
"traceparent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
},
"auth": {
"token": "eyJhbGciOiJSUzI1NiJ9...",
"scope": ["tool:read"],
"card_sig": "ed25519:a1b2c3d4..."
}
},
"method": "tools/invoke",
"schema_ref": "uap:tool.invoke/v1",
"params": {
"tool_id": "db:query",
"input": { "sql": "SELECT 1" }
},
"ack": true
}
UAP-protocol/
├── packages/
│ ├── gateway/ @uap/gateway — Fastify-based UAP Gateway
│ ├── sdk-ts/ @uap/sdk-ts — TypeScript client + server SDK
│ └── sdk-py/ uap-sdk — Python async SDK (httpx + FastAPI)
├── scripts/
│ ├── generate-keypair.ts — Ed25519 keypair for local dev
│ └── keycloak-bootstrap.ts — Idempotent Keycloak realm setup
└── docker/
└── sandbox/ — Base image for zero-trust tool execution
import { UapClient, ClientCredentialsTokenProvider } from "@uap/sdk-ts";
const client = new UapClient({
gatewayUrl: "https://gateway.example.com",
tokenProvider: new ClientCredentialsTokenProvider({
tokenUrl: process.env.TOKEN_URL!,
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
}),
});
const result = await client.invokeTool(
"db:query",
{ sql: "SELECT * FROM users LIMIT 10" },
["tool:read"]
);
const task = await client.delegateTask(
"summarizer",
{ text: "..." },
["task:submit"]
);
from uap_sdk.client import UapClient, UapClientOptions
from uap_sdk.token import ClientCredentialsTokenProvider
async with UapClient(UapClientOptions(
gateway_url="https://gateway.example.com",
token_provider=ClientCredentialsTokenProvider(
token_url=os.environ["TOKEN_URL"],
client_id=os.environ["CLIENT_ID"],
client_secret=os.environ["CLIENT_SECRET"],
)
)) as client:
result = await client.invoke_tool("db:query", {"sql": "SELECT 1"}, ["tool:read"])
FastAPI ミドルウェア
from uap_sdk.middleware import uap_auth
@app.post("/summarize")
@uap_auth(scope=["task:submit"])
async def summarize(request: Request):
claims = request.state.uap_claims # typed AuthClaims
...
uap-migrate CLI は、あらゆる MCP サーバーを 5 分以内に署名付き UAP CapabilityCard としてラップします。冪等です — 移行済みサーバーで再実行しても no-op となります。
node dist/cli/migrate.js mcp http://localhost:3001 \
--issuer did:uap:my-org \
--key config/dev.privkey.hex \
--out ./uap-cards
# → ./uap-cards/did:uap:my-org.card.json
ツール名、説明、パラメータスキーマは Ed25519 署名付きペイロードの一部です。署名後に任意のフィールドを変更すると署名が無効化され、構造的にツールポイズニングを防ぎます。
const signed = await signer.sign({
issuer: "did:uap:my-agent",
version: "1.0.0",
tools: [{
id: "db:query",
description: "Run a read-only SQL query",
inputSchema: { type: "object", required: ["sql"] },
scopes: ["tool:read"]
}],
scopes: ["tool:read"],
issuedAt: Date.now(),
expiresAt: Date.now() + 86_400_000 * 30
});
// signed.signature === "ed25519:a1b2c3..."
ブランチ命名規則:feat/<sprint>-<task>-<slug> — 例:feat/s2-2.1-mtls-keycloak
すべての変更は次の流れに従います:ブランチ → ローカルで npx tsc --noEmit + npx vitest run → コミット → PR → squash merge → ブランチ削除。ローカル開発で CI への依存はありません。
# Run all tests before committing
cd packages/gateway && npx vitest run
cd packages/sdk-ts && npx vitest run
cd packages/sdk-py && python -m pytest tests/ -v
ロードマップ: Sprint 0(スキャフォールド)→ Sprint 1(スキーマ + 署名 + RPC)→ Sprint 2(セキュリティコア)→ Sprint 3(ゲートウェイ + レジストリ)→ Sprint 4(ブリッジアダプター)→ Sprint 5(SDK + Docker イメージ)。
UAP · Universal Agent Protocol · 2026
SPDX-License-Identifier: Apache-2.0
| レイヤー | 内容 | 依存関係 |
|---|
| Domain | UapEnvelope, CapabilityCard, AuditEvent, Task | なし — 標準ライブラリのみ |
| Application | InvokeToolUseCase, DelegateTaskUseCase, ValidateCardUseCase | ドメインポートのみ |
| Infrastructure | KeycloakAuthAdapter, DockerSandboxAdapter, Ed25519SignerAdapter, PinoAuditAdapter | アプリケーションポート + 外部ライブラリ |
| Transport | UAP-RPC フレームパーサー、Fastify ゲートウェイ、SSE/WebSocket ハンドラー | インフラストラクチャ + ドメインシリアライザ |
| 機能 | UAP | MCP | A2A | JSON-RPC 2.0 |
|---|
| 必須認証 | ✅ 常に mTLS + JWT | ❌ オプション | ⚠️ API キーのみ | ❌ なし |
| ツールメタデータの整合性 | ✅ Ed25519 署名付きペイロード | ❌ 公開後の改変が可能 | ❌ 署名なし | ❌ 署名なし |
| サンドボックスモデル | ✅ 呼び出しごとの一時 Docker | ⚠️ サーバーレベルのみ | ❌ なし | ❌ なし |
| エージェントディスカバリ | ✅ ハブ&スポーク · N 接続 | ❌ N² 直接 HTTP | ⚠️ DNS ベース | ❌ なし |
| 監査証跡 | ✅ プロトコルネイティブな追記専用ログ | ❌ なし | ❌ なし | ❌ なし |
| 分散トレーシング | ✅ W3C TraceContext 必須 | ❌ なし | ❌ なし | ❌ なし |
| スキーマ検証 | ✅ トランスポート層で AJV | ⚠️ 任意の Zod | ❌ なし | ❌ なし |
| トークン有効期限の上限 | ✅ 15 分を強制 | ❌ 強制なし | ❌ 強制なし | ❌ N/A |
| バッチセマンティクス | ✅ 直列 · 並列 · トランザクション | ❌ 未定義 | ❌ なし | ⚠️ 曖昧 |
| バイナリペイロード | ✅ ネイティブフレーム | ❌ Base64 のみ | ❌ Base64 のみ | ❌ Base64 のみ |
| IdP モデル | ✅ 外部 IdP のみ | ❌ サーバー自身が OAuth プロバイダー | ⚠️ 場合による | ❌ なし |
| ブリッジアダプター | ✅ MCP + A2A ブリッジは Phase 2 で提供 | ❌ ブリッジなし | ❌ ブリッジなし | ❌ ブリッジなし |
| 水平スケーリング | ✅ ステートレス · 任意のロードバランサー | ❌ スティッキーセッション | ⚠️ 場合による | ❌ なし |
| 変数 | 説明 | デフォルト |
|---|
KEYCLOAK_URL | Keycloak のベース URL | http://localhost:8080 |
KEYCLOAK_REALM | レルム名 | uap |
UAP_AUDIENCE | JWT の audience クレーム | uap-gateway |
UAP_SIGNING_KEY_PATH | Ed25519 秘密鍵(16 進数)へのパス | config/dev.privkey.hex |
UAP_DOCKER_SOCKET | Docker ソケットのパス | /var/run/docker.sock |
UAP_AUDIT_LOG_DIR | 追記専用の監査 NDJSON ログディレクトリ | /var/log/uap |
UAP_GATEWAY_PORT | ゲートウェイの待ち受けポート | 3000 |
UAP_MTLS_CERT | サーバー TLS 証明書(PEM) | certs/server.crt |
UAP_MTLS_KEY | サーバー TLS 秘密鍵(PEM) | certs/server.key |
UAP_MTLS_CA | クライアント証明書検証用の CA 証明書 | certs/ca.crt |
OTEL_EXPORTER_OTLP_ENDPOINT | OpenTelemetry コレクターエンドポイント | http://localhost:4318 |
REDIS_URL | マルチインスタンスレジストリ用 Redis(オプション) | — |
| パッケージ | バージョン | 目的 |
|---|
fastify | ^4.27 | ゲートウェイ HTTP サーバー |
zod | ^3.23 | エンベロープスキーマと型推論 |
@noble/curves | ^1.4 | Ed25519 署名 |
jose | ^5.4 | JWT 検証、JWKS クライアント |
ajv | ^8.16 | トランスポートレベルのパラメータ検証 |
dockerode | ^4.0 | ゼロトラストサンドボックスアダプター |
pino | ^9.2 | 追記専用の構造化監査ログ |
ulid | ^2.3 | ソート可能な一意 ID |
@opentelemetry/sdk-node | ^0.52 | 分散トレーシング |
ioredis | ^5.3 | マルチインスタンスサービスレジストリ |
@modelcontextprotocol/sdk | ^1.0 | MCP ブリッジアダプター |
httpx (Python) | ^0.27 | Python SDK 用の非同期 HTTP クライアント |
pydantic (Python) | ^2.7 | Python の型検証 |