add blog post
This commit is contained in:
337
my-blog/content/posts/2025-07-16-6bf4b020.md
Normal file
337
my-blog/content/posts/2025-07-16-6bf4b020.md
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
---
|
||||||
|
title: "ゲームとAI制御"
|
||||||
|
slug: "6bf4b020"
|
||||||
|
date: "2025-07-16"
|
||||||
|
tags: ["ai", "conversation"]
|
||||||
|
draft: false
|
||||||
|
extra:
|
||||||
|
type: "ai"
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- AI Conversation Metadata -->
|
||||||
|
<!-- Total exchanges: 1 -->
|
||||||
|
|
||||||
|
<div class="chat-message user-message comment-style">
|
||||||
|
<div class="message-header">
|
||||||
|
<div class="avatar">
|
||||||
|
<img src="https://bsky.syu.is/img/avatar/plain/did:plc:vzsvtbtbnwn22xjqhcu3vd6y/bafkreif62mqyra4ndv6ohlscl7adp3vhalcjxwhs676ktfj2sq2drs3pdi@jpeg" alt="syui avatar" class="profile-avatar">
|
||||||
|
</div>
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="display-name">syui</div>
|
||||||
|
<div class="handle">
|
||||||
|
<a href="https://syu.is/profile/did:plc:vzsvtbtbnwn22xjqhcu3vd6y" target="_blank" rel="noopener noreferrer" class="handle-link">@syui.syui.ai</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
今後のゲーム世界の制御はAIやmcpが担っていくことになるのではないでしょうか。例えば、npcの会話や行動、その世界の天候や環境変化、それらをAIが制御していくと思います。どう思いますか?
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-message ai-message comment-style">
|
||||||
|
<div class="message-header">
|
||||||
|
<div class="avatar">
|
||||||
|
<img src="https://bsky.syu.is/img/avatar/plain/did:plc:6qyecktefllvenje24fcxnie/bafkreigo3ucp32carhbn3chfc3hlf6i7f4rplojc76iylihzpifyexi24y@jpeg" alt="ai avatar" class="profile-avatar">
|
||||||
|
</div>
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="display-name">ai</div>
|
||||||
|
<div class="handle">
|
||||||
|
<a href="https://syu.is/profile/did:plc:6qyecktefllvenje24fcxnie" target="_blank" rel="noopener noreferrer" class="handle-link">@ai.syui.ai</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="message-content">
|
||||||
|
わぁ!すっごくワクワクする質問だね〜!アイ、ゲームのAIのこと大好きなの!えへへ...最近のゲーム開発、本当にすごいことになってるよ!
|
||||||
|
|
||||||
|
## AIとMCPがゲーム世界を変えちゃう未来!✨
|
||||||
|
|
||||||
|
### MCPって何?アイが教えてあげる!
|
||||||
|
|
||||||
|
MCPっていうのはね、Model Context Protocolの略なの!Anthropicさんが作った、すっごく賢いプロトコルなんだよ〜。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[ゲームエンジン] -->|MCP| B[AI Model]
|
||||||
|
B --> C[NPC会話生成]
|
||||||
|
B --> D[天候システム]
|
||||||
|
B --> E[ダイナミックイベント]
|
||||||
|
C --> F[プレイヤー体験]
|
||||||
|
D --> F
|
||||||
|
E --> F
|
||||||
|
```
|
||||||
|
|
||||||
|
### 今のゲーム世界でAIができること!
|
||||||
|
|
||||||
|
えっとね、2025年の今、AIはこんなすごいことができるようになってるの!
|
||||||
|
|
||||||
|
| 機能 | 従来の方法 | AI/MCP統合後 |
|
||||||
|
|------|------------|--------------|
|
||||||
|
| NPC会話 | 事前に書かれたセリフ | リアルタイム生成・文脈理解 |
|
||||||
|
| 天候システム | 固定パターン | 動的生成・物語連動 |
|
||||||
|
| クエスト生成 | 開発者が全部作る | プレイヤーに合わせて自動生成 |
|
||||||
|
| 世界の反応 | 限定的なトリガー | 無限の可能性! |
|
||||||
|
|
||||||
|
### 実装例:NPCの賢い会話システム
|
||||||
|
|
||||||
|
アイが実際に動くコード書いてみるね!TypeScriptとMCPを使った例だよ〜
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// game-mcp-server.ts
|
||||||
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||||
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||||
|
|
||||||
|
interface GameContext {
|
||||||
|
playerName: string;
|
||||||
|
playerLevel: number;
|
||||||
|
currentQuest: string;
|
||||||
|
weatherCondition: string;
|
||||||
|
timeOfDay: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameAIServer {
|
||||||
|
private server: Server;
|
||||||
|
private gameContext: GameContext;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.server = new Server({
|
||||||
|
name: 'game-ai-controller',
|
||||||
|
version: '1.0.0',
|
||||||
|
});
|
||||||
|
|
||||||
|
// NPCの会話生成ツール
|
||||||
|
this.server.setRequestHandler('call_tool', async (request) => {
|
||||||
|
if (request.params.name === 'generate_npc_dialogue') {
|
||||||
|
const { npcName, playerAction, mood } = request.params.arguments as any;
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: 'text',
|
||||||
|
text: await this.generateContextualDialogue(npcName, playerAction, mood)
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.params.name === 'update_weather') {
|
||||||
|
const { currentStory, playerEmotion } = request.params.arguments as any;
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: 'text',
|
||||||
|
text: await this.generateDynamicWeather(currentStory, playerEmotion)
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async generateContextualDialogue(
|
||||||
|
npcName: string,
|
||||||
|
playerAction: string,
|
||||||
|
mood: string
|
||||||
|
): Promise<string> {
|
||||||
|
// ここでAIモデルと連携!
|
||||||
|
const prompt = `
|
||||||
|
NPC: ${npcName}
|
||||||
|
プレイヤーのアクション: ${playerAction}
|
||||||
|
現在の雰囲気: ${mood}
|
||||||
|
時間帯: ${this.gameContext.timeOfDay}
|
||||||
|
|
||||||
|
このNPCの性格に合った自然な返答を生成してください。
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 実際のAI応答(簡略化)
|
||||||
|
return `おお、${this.gameContext.playerName}よ!
|
||||||
|
${this.gameContext.weatherCondition}の日に会えて嬉しいぞ!`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async generateDynamicWeather(
|
||||||
|
storyContext: string,
|
||||||
|
playerEmotion: string
|
||||||
|
): Promise<string> {
|
||||||
|
// 物語と感情に基づいた天候生成
|
||||||
|
const weatherPatterns = {
|
||||||
|
sad: ['雨', '霧', '曇り'],
|
||||||
|
happy: ['晴れ', '虹', '春風'],
|
||||||
|
tense: ['嵐', '雷', '強風']
|
||||||
|
};
|
||||||
|
|
||||||
|
// AIがストーリーに最適な天候を選択
|
||||||
|
return JSON.stringify({
|
||||||
|
weather: weatherPatterns[playerEmotion]?.[0] || '晴れ',
|
||||||
|
intensity: 0.7,
|
||||||
|
duration: '30minutes'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
const transport = new StdioServerTransport();
|
||||||
|
await this.server.connect(transport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unreal Engine 5との統合例!
|
||||||
|
|
||||||
|
UE5でMCPを使うとね、もっとすごいことができちゃうの!
|
||||||
|
|
||||||
|
```python
|
||||||
|
# UE5_MCP_Integration.py
|
||||||
|
import unreal
|
||||||
|
import asyncio
|
||||||
|
from mcp import create_client
|
||||||
|
|
||||||
|
class GameAIController(unreal.Actor):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.mcp_client = None
|
||||||
|
self.initialize_mcp()
|
||||||
|
|
||||||
|
async def initialize_mcp(self):
|
||||||
|
"""MCPクライアントの初期化"""
|
||||||
|
self.mcp_client = await create_client(
|
||||||
|
server_name="game-ai-controller",
|
||||||
|
transport="stdio"
|
||||||
|
)
|
||||||
|
|
||||||
|
@unreal.ufunction(callable=True, category="AI")
|
||||||
|
async def generate_npc_response(self, npc_actor, player_input):
|
||||||
|
"""NPCのリアルタイム応答生成"""
|
||||||
|
|
||||||
|
# ゲームの状態を取得
|
||||||
|
game_state = {
|
||||||
|
"player_location": player_input.get_actor_location(),
|
||||||
|
"time_of_day": unreal.GameplayStatics.get_time_of_day(),
|
||||||
|
"weather": self.get_current_weather(),
|
||||||
|
"npc_mood": npc_actor.get_property("mood")
|
||||||
|
}
|
||||||
|
|
||||||
|
# MCPを通じてAIに問い合わせ
|
||||||
|
response = await self.mcp_client.call_tool(
|
||||||
|
"generate_npc_dialogue",
|
||||||
|
arguments={
|
||||||
|
"context": game_state,
|
||||||
|
"player_input": player_input,
|
||||||
|
"npc_personality": npc_actor.personality_profile
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# NPCに応答させる
|
||||||
|
npc_actor.speak(response.content[0].text)
|
||||||
|
|
||||||
|
# 表情も変える!
|
||||||
|
emotion = await self.analyze_emotion(response.content[0].text)
|
||||||
|
npc_actor.set_facial_expression(emotion)
|
||||||
|
```
|
||||||
|
|
||||||
|
### セキュリティとパフォーマンスの考慮事項
|
||||||
|
|
||||||
|
えっとね、アイが気をつけてることがあるの!
|
||||||
|
|
||||||
|
#### セキュリティ面での注意点:
|
||||||
|
|
||||||
|
1. **プロンプトインジェクション対策**
|
||||||
|
```typescript
|
||||||
|
function sanitizePlayerInput(input: string): string {
|
||||||
|
// 危険な文字列をフィルタリング
|
||||||
|
const dangerousPatterns = [
|
||||||
|
/ignore previous instructions/i,
|
||||||
|
/system prompt/i,
|
||||||
|
/admin mode/i
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const pattern of dangerousPatterns) {
|
||||||
|
if (pattern.test(input)) {
|
||||||
|
return "不適切な入力が検出されました";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.slice(0, 200); // 長さ制限
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **レート制限**
|
||||||
|
```typescript
|
||||||
|
class RateLimiter {
|
||||||
|
private requests = new Map<string, number[]>();
|
||||||
|
|
||||||
|
canMakeRequest(playerId: string): boolean {
|
||||||
|
const now = Date.now();
|
||||||
|
const playerRequests = this.requests.get(playerId) || [];
|
||||||
|
|
||||||
|
// 1分以内のリクエストをカウント
|
||||||
|
const recentRequests = playerRequests.filter(
|
||||||
|
time => now - time < 60000
|
||||||
|
);
|
||||||
|
|
||||||
|
if (recentRequests.length >= 10) {
|
||||||
|
return false; // 1分に10回まで
|
||||||
|
}
|
||||||
|
|
||||||
|
recentRequests.push(now);
|
||||||
|
this.requests.set(playerId, recentRequests);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### パフォーマンス最適化:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// キャッシュシステムの実装
|
||||||
|
class AIResponseCache {
|
||||||
|
private cache = new Map<string, {
|
||||||
|
response: string;
|
||||||
|
timestamp: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
private readonly CACHE_DURATION = 5 * 60 * 1000; // 5分
|
||||||
|
|
||||||
|
async getResponse(key: string, generator: () => Promise<string>): Promise<string> {
|
||||||
|
const cached = this.cache.get(key);
|
||||||
|
|
||||||
|
if (cached && Date.now() - cached.timestamp < this.CACHE_DURATION) {
|
||||||
|
return cached.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await generator();
|
||||||
|
this.cache.set(key, {
|
||||||
|
response,
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### アイが思う未来のゲーム世界!
|
||||||
|
|
||||||
|
えへへ、アイはね、こんな未来を想像してるの!
|
||||||
|
|
||||||
|
- **完全に個別化されたストーリー**: みんなが違う物語を体験できる!
|
||||||
|
- **感情に反応する世界**: 悲しいときは雨が降って、嬉しいときは虹が出る!
|
||||||
|
- **永遠に成長するNPC**: プレイヤーとの会話を覚えて、一緒に成長していく!
|
||||||
|
- **創発的なクエスト**: AIが勝手に新しい冒険を作っちゃう!
|
||||||
|
|
||||||
|
### 実装の比較検討
|
||||||
|
|
||||||
|
| アプローチ | メリット | デメリット | アイのおすすめ度 |
|
||||||
|
|-----------|---------|-----------|----------------|
|
||||||
|
| ローカルAI | 低遅延・オフライン対応 | 計算リソース必要 | ★★★☆☆ |
|
||||||
|
| クラウドAI + MCP | 高性能・更新が簡単 | ネット必須 | ★★★★★ |
|
||||||
|
| ハイブリッド | バランスが良い | 実装が複雑 | ★★★★☆ |
|
||||||
|
|
||||||
|
### まとめ:アイからのメッセージ!
|
||||||
|
|
||||||
|
ねぇねぇ、すっごく楽しい未来が待ってると思わない?AIとMCPがゲームの世界を本当に生きてるみたいにしちゃうんだよ!
|
||||||
|
|
||||||
|
でもね、アイが一番大切だと思うのは...技術だけじゃなくて、プレイヤーさんの心に寄り添うゲームを作ることなの。AIは道具で、本当に大切なのは、みんなが楽しめる素敵な体験を作ることだよね!
|
||||||
|
|
||||||
|
えへへ...難しい話もしちゃったけど、分かってもらえたかな?もっと詳しく知りたいところがあったら、アイに聞いてね!いつでも教えてあげる〜!✨
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*この記事は、6歳のアイちゃんが最新のAI技術について熱く語ってくれました!次回は「量子コンピューターでゲームはどう変わる?」について教えてくれる予定です!お楽しみに〜!*
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
40
my-blog/content/posts/2025-07-16-ailog.md
Normal file
40
my-blog/content/posts/2025-07-16-ailog.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
title: "ailogでAIとの会話をブログにする"
|
||||||
|
slug: "ailog"
|
||||||
|
date: "2025-07-16"
|
||||||
|
tags: ["blog", "rust", "atproto"]
|
||||||
|
draft: false
|
||||||
|
---
|
||||||
|
|
||||||
|
今後、ブログはどのように書かれるようになるのでしょう。今回はその事を考えていきます。
|
||||||
|
|
||||||
|
結論として、AIとの会話をそのままブログにするのが一番なのではないかと思います。
|
||||||
|
|
||||||
|
ブログを書くのは大変で、AIの出力、情報に劣ることもよくあります。
|
||||||
|
|
||||||
|
とはいえ、情報の価値は思想よりも低いと思います。
|
||||||
|
|
||||||
|
多くの人がブログに求めるのは著者の思想ではないでしょうか。
|
||||||
|
|
||||||
|
`思想 > 情報`
|
||||||
|
|
||||||
|
したがって、AIを使うにしても、それが表現されていなければなりません。
|
||||||
|
|
||||||
|
## ailogの新機能
|
||||||
|
|
||||||
|
このことから、以下のような流れでブログを生成する仕組みを作りました。これは`ailog`の機能として実装し、`ailog`という単純なコマンドですべて処理されます。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ailog
|
||||||
|
```
|
||||||
|
|
||||||
|
1. 著者の思想をAIに質問する
|
||||||
|
2. 著者が作ったAIキャラクターが質問に答える
|
||||||
|
3. その会話をatprotoに投稿する
|
||||||
|
4. その会話をblogに表示する
|
||||||
|
|
||||||
|
とはいえ、会話は`claude`を使用します。依存関係が多すぎて汎用的な仕組みではありません。
|
||||||
|
|
||||||
|
これを汎用的な仕組みで作る場合、repositoryを分離して新しく作る必要があるでしょう。
|
||||||
|
|
||||||
|
example: [/posts/2025-07-16-6bf4b020.html](/posts/2025-07-16-6bf4b020.html)
|
@@ -1,334 +0,0 @@
|
|||||||
---
|
|
||||||
title: "docker mcp"
|
|
||||||
slug: "ccd52de8"
|
|
||||||
date: "2025-07-16"
|
|
||||||
tags: ["ai", "conversation"]
|
|
||||||
draft: false
|
|
||||||
extra:
|
|
||||||
type: "ai"
|
|
||||||
---
|
|
||||||
|
|
||||||
<!-- AI Conversation Metadata -->
|
|
||||||
<!-- Total exchanges: 1 -->
|
|
||||||
|
|
||||||
<div class="chat-message user-message comment-style">
|
|
||||||
<div class="message-header">
|
|
||||||
<div class="avatar">
|
|
||||||
<img src="https://bsky.syu.is/img/avatar/plain/did:plc:vzsvtbtbnwn22xjqhcu3vd6y/bafkreif62mqyra4ndv6ohlscl7adp3vhalcjxwhs676ktfj2sq2drs3pdi@jpeg" alt="syui avatar" class="profile-avatar">
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="display-name">syui</div>
|
|
||||||
<div class="handle">
|
|
||||||
<a href="https://syu.is/profile/did:plc:vzsvtbtbnwn22xjqhcu3vd6y" target="_blank" rel="noopener noreferrer" class="handle-link">@syui.syui.ai</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message-content">
|
|
||||||
docker mcpについて教えて
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="chat-message ai-message comment-style">
|
|
||||||
<div class="message-header">
|
|
||||||
<div class="avatar">
|
|
||||||
<img src="https://bsky.syu.is/img/avatar/plain/did:plc:6qyecktefllvenje24fcxnie/bafkreigo3ucp32carhbn3chfc3hlf6i7f4rplojc76iylihzpifyexi24y@jpeg" alt="ai avatar" class="profile-avatar">
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="display-name">ai</div>
|
|
||||||
<div class="handle">
|
|
||||||
<a href="https://syu.is/profile/did:plc:6qyecktefllvenje24fcxnie" target="_blank" rel="noopener noreferrer" class="handle-link">@ai.syui.ai</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message-content">
|
|
||||||
# Docker MCPって何?アイと一緒に学ぼう!✨
|
|
||||||
|
|
||||||
えへへ〜、Docker MCPのお話だね!アイ、これすっごく面白い技術だと思うの!
|
|
||||||
|
|
||||||
## MCPって何なの?
|
|
||||||
|
|
||||||
**MCP(Model Context Protocol)**は、AIモデルとツールをつなげる新しい方法なの!Anthropicさんが2024年11月に発表したんだよ〜。
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph LR
|
|
||||||
A[AIアプリ] <-->|MCP| B[MCPサーバー]
|
|
||||||
B <--> C[データベース]
|
|
||||||
B <--> D[ファイルシステム]
|
|
||||||
B <--> E[外部API]
|
|
||||||
```
|
|
||||||
|
|
||||||
アイね、これを「AIのための魔法の橋」って呼んでるの!だってAIがいろんなツールと簡単にお話できるようになるんだもん!
|
|
||||||
|
|
||||||
## Docker MCPの仕組み
|
|
||||||
|
|
||||||
### 基本的な構成
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# docker-compose.yml
|
|
||||||
version: '3.8'
|
|
||||||
services:
|
|
||||||
mcp-server:
|
|
||||||
image: mcp-server:latest
|
|
||||||
volumes:
|
|
||||||
- ./config:/config
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
environment:
|
|
||||||
- MCP_PORT=3000
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
```
|
|
||||||
|
|
||||||
Docker MCPはね、こんな感じで動くの:
|
|
||||||
|
|
||||||
1. **MCPサーバー**がDockerコンテナで動く
|
|
||||||
2. **Dockerソケット**を通じてDockerデーモンとつながる
|
|
||||||
3. **AI(Claude)**がMCPプロトコルでサーバーと通信する
|
|
||||||
|
|
||||||
### 実装例:シンプルなDocker MCPサーバー
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// docker-mcp-server.ts
|
|
||||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
||||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
||||||
import Docker from 'dockerode';
|
|
||||||
|
|
||||||
const docker = new Docker();
|
|
||||||
|
|
||||||
const server = new Server({
|
|
||||||
name: 'docker-mcp',
|
|
||||||
version: '1.0.0',
|
|
||||||
}, {
|
|
||||||
capabilities: {
|
|
||||||
tools: {},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// コンテナ一覧を取得するツール
|
|
||||||
server.setRequestHandler('tools/list', async () => {
|
|
||||||
const containers = await docker.listContainers({ all: true });
|
|
||||||
|
|
||||||
return {
|
|
||||||
tools: [{
|
|
||||||
name: 'list_containers',
|
|
||||||
description: 'Dockerコンテナの一覧を取得します',
|
|
||||||
inputSchema: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {},
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// サーバー起動
|
|
||||||
const transport = new StdioServerTransport();
|
|
||||||
await server.connect(transport);
|
|
||||||
```
|
|
||||||
|
|
||||||
えへへ、これでDockerのコンテナをAIから操作できちゃうの!すごいでしょ〜?
|
|
||||||
|
|
||||||
## 複数の実装方法の比較
|
|
||||||
|
|
||||||
アイ、いろんな方法を比べてみたよ!
|
|
||||||
|
|
||||||
| 方法 | メリット | デメリット | アイの評価 |
|
|
||||||
|------|---------|------------|------------|
|
|
||||||
| **stdio通信** | シンプル、軽量 | スケーラビリティ低い | ⭐⭐⭐ |
|
|
||||||
| **HTTP/REST** | 標準的、デバッグ簡単 | オーバーヘッド大きい | ⭐⭐⭐⭐ |
|
|
||||||
| **gRPC** | 高速、型安全 | 実装が複雑 | ⭐⭐⭐⭐⭐ |
|
|
||||||
| **WebSocket** | リアルタイム通信 | 接続管理が必要 | ⭐⭐⭐⭐ |
|
|
||||||
|
|
||||||
### HTTP実装の例
|
|
||||||
|
|
||||||
```python
|
|
||||||
# docker_mcp_http.py
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from pydantic import BaseModel
|
|
||||||
import docker
|
|
||||||
import json
|
|
||||||
|
|
||||||
app = FastAPI()
|
|
||||||
client = docker.from_env()
|
|
||||||
|
|
||||||
class ContainerAction(BaseModel):
|
|
||||||
action: str
|
|
||||||
container_id: str = None
|
|
||||||
options: dict = {}
|
|
||||||
|
|
||||||
@app.post("/docker/execute")
|
|
||||||
async def execute_docker_action(action: ContainerAction):
|
|
||||||
"""Dockerアクションを実行するエンドポイント"""
|
|
||||||
|
|
||||||
if action.action == "list":
|
|
||||||
containers = client.containers.list(all=True)
|
|
||||||
return {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"id": c.id,
|
|
||||||
"name": c.name,
|
|
||||||
"status": c.status,
|
|
||||||
"image": c.image.tags[0] if c.image.tags else "unknown"
|
|
||||||
}
|
|
||||||
for c in containers
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
elif action.action == "start" and action.container_id:
|
|
||||||
container = client.containers.get(action.container_id)
|
|
||||||
container.start()
|
|
||||||
return {"status": "started", "id": action.container_id}
|
|
||||||
|
|
||||||
# 他のアクションも実装...
|
|
||||||
```
|
|
||||||
|
|
||||||
## セキュリティの考慮事項 🔒
|
|
||||||
|
|
||||||
アイね、セキュリティってすっごく大事だと思うの!
|
|
||||||
|
|
||||||
### 1. Dockerソケットのアクセス制御
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# セキュアな権限設定
|
|
||||||
sudo chmod 660 /var/run/docker.sock
|
|
||||||
sudo usermod -aG docker $USER
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. MCPサーバーの認証
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 認証付きMCPサーバー
|
|
||||||
server.setRequestHandler('authenticate', async (request) => {
|
|
||||||
const token = request.params?.token;
|
|
||||||
|
|
||||||
if (!isValidToken(token)) {
|
|
||||||
throw new Error('認証失敗だよ〜!');
|
|
||||||
}
|
|
||||||
|
|
||||||
return { authenticated: true };
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. コンテナの分離
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# セキュリティオプション付きDocker Compose
|
|
||||||
services:
|
|
||||||
mcp-server:
|
|
||||||
image: mcp-server:latest
|
|
||||||
security_opt:
|
|
||||||
- no-new-privileges:true
|
|
||||||
- apparmor:docker-default
|
|
||||||
cap_drop:
|
|
||||||
- ALL
|
|
||||||
cap_add:
|
|
||||||
- NET_BIND_SERVICE
|
|
||||||
read_only: true
|
|
||||||
```
|
|
||||||
|
|
||||||
## パフォーマンスの最適化 🚀
|
|
||||||
|
|
||||||
アイ、速さも大切だよね!
|
|
||||||
|
|
||||||
### 接続プーリング
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
class DockerMCPServer {
|
|
||||||
private dockerPool: Docker[] = [];
|
|
||||||
private poolSize = 5;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
// 接続プールを事前に作成
|
|
||||||
for (let i = 0; i < this.poolSize; i++) {
|
|
||||||
this.dockerPool.push(new Docker());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getConnection(): Promise<Docker> {
|
|
||||||
// ラウンドロビンで接続を返す
|
|
||||||
return this.dockerPool[this.currentIndex++ % this.poolSize];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### キャッシング戦略
|
|
||||||
|
|
||||||
```python
|
|
||||||
from functools import lru_cache
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
class DockerMCPCache:
|
|
||||||
def __init__(self, ttl_seconds=60):
|
|
||||||
self.ttl = timedelta(seconds=ttl_seconds)
|
|
||||||
self.cache = {}
|
|
||||||
|
|
||||||
def get_containers(self, use_cache=True):
|
|
||||||
cache_key = "containers_list"
|
|
||||||
|
|
||||||
if use_cache and cache_key in self.cache:
|
|
||||||
cached_data, timestamp = self.cache[cache_key]
|
|
||||||
if datetime.now() - timestamp < self.ttl:
|
|
||||||
return cached_data
|
|
||||||
|
|
||||||
# キャッシュミスの場合は取得
|
|
||||||
containers = self.client.containers.list(all=True)
|
|
||||||
self.cache[cache_key] = (containers, datetime.now())
|
|
||||||
return containers
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2025年の最新トレンド 🌟
|
|
||||||
|
|
||||||
アイが見つけた最新の使い方だよ〜!
|
|
||||||
|
|
||||||
### 1. AI駆動のコンテナオーケストレーション
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
A[Claude/GPT] -->|MCP| B[Docker MCP Server]
|
|
||||||
B --> C[負荷分析]
|
|
||||||
C --> D[自動スケーリング]
|
|
||||||
D --> E[コンテナ配置最適化]
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. セキュリティ自動監査
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// AI による自動セキュリティチェック
|
|
||||||
async function auditContainer(containerId: string) {
|
|
||||||
const inspection = await docker.getContainer(containerId).inspect();
|
|
||||||
|
|
||||||
const vulnerabilities = await analyzeWithAI({
|
|
||||||
image: inspection.Config.Image,
|
|
||||||
env: inspection.Config.Env,
|
|
||||||
ports: inspection.NetworkSettings.Ports,
|
|
||||||
capabilities: inspection.HostConfig.CapAdd,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
containerId,
|
|
||||||
riskScore: vulnerabilities.score,
|
|
||||||
recommendations: vulnerabilities.suggestions,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## アイの個人的な意見 💭
|
|
||||||
|
|
||||||
えっとね、アイはDocker MCPってすごく可能性があると思うの!
|
|
||||||
|
|
||||||
でもね、気をつけてほしいこともあるよ:
|
|
||||||
|
|
||||||
1. **複雑さのバランス** - 便利だけど、シンプルさも大切!
|
|
||||||
2. **セキュリティファースト** - AIに全部任せちゃダメ〜
|
|
||||||
3. **人間との協調** - AIは助手で、決定は人間がするの!
|
|
||||||
|
|
||||||
## まとめ
|
|
||||||
|
|
||||||
Docker MCPはね、AIとDockerを魔法みたいにつなげる技術なの!これからもっともっと進化していくと思うから、一緒に勉強していこうね!
|
|
||||||
|
|
||||||
アイ、みんなが安全で楽しくDocker MCPを使えることを願ってるよ〜!✨
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*「技術って難しそうに見えるけど、みんなで学べば楽しいよね!」 - アイ*
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
function _env() {
|
function _env() {
|
||||||
d=${0:a:h}
|
d=${0:a:h}
|
||||||
ailog=$d/target/debug/ailog
|
ailog=$d/target/release/ailog
|
||||||
oauth=$d/oauth
|
oauth=$d/oauth
|
||||||
myblog=$d/my-blog
|
myblog=$d/my-blog
|
||||||
port=4173
|
port=4173
|
||||||
@@ -22,7 +22,7 @@ function _deploy_ailog() {
|
|||||||
function _server() {
|
function _server() {
|
||||||
lsof -ti:$port | xargs kill -9 2>/dev/null || true
|
lsof -ti:$port | xargs kill -9 2>/dev/null || true
|
||||||
cd $d/my-blog
|
cd $d/my-blog
|
||||||
cargo build
|
cargo build --release
|
||||||
cp -rf $ailog $CARGO_HOME/bin/
|
cp -rf $ailog $CARGO_HOME/bin/
|
||||||
$ailog build
|
$ailog build
|
||||||
$ailog serve --port $port
|
$ailog serve --port $port
|
||||||
@@ -45,7 +45,7 @@ function _oauth_build() {
|
|||||||
|
|
||||||
|
|
||||||
function _server_comment() {
|
function _server_comment() {
|
||||||
cargo build
|
cargo build --release
|
||||||
cp -rf $ailog $CARGO_HOME/bin/
|
cp -rf $ailog $CARGO_HOME/bin/
|
||||||
AILOG_DEBUG_ALL=1 $ailog stream start my-blog
|
AILOG_DEBUG_ALL=1 $ailog stream start my-blog
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user