Skip to content

Commit 60cd1a1

Browse files
authored
API仕様変更・セキュリティポリシー見直し・ドキュメント整備 (#9)
* API仕様変更に伴い、READMEの使い方例とパッケージのTSDocコメントを修正 - createHonoAppの利用方法をファクトリ関数渡しに統一 - 使い方サンプルを現行APIに合わせて修正 - package/src/index.tsのドキュメントコメントをTSDoc形式に変更 * リポジトリの内容に合わせてSECURITY.mdを修正 - AWS Lambda用MCPサーバー向けのセキュリティ運用に更新 - Secrets管理、依存性脆弱性管理、CI/CDチェック、バリデーション等の注意事項を明記 - 脆弱性報告手順も明確化 * リソースリークの修正 * リソースリークの修正
1 parent f9f7e84 commit 60cd1a1

8 files changed

Lines changed: 189 additions & 113 deletions

File tree

.github/SECURITY.md

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
1-
# Security Policy
1+
# セキュリティポリシー
22

3-
## Supported Versions
3+
## サポート対象バージョン
44

5-
This project is currently in active development (version 0.x.x). Security updates are provided for the latest version only. As this is an AWS Bedrock application, we prioritize security issues related to AWS credentials, data handling, and API interactions.
5+
本プロジェクト(aws-lambda-mcp-server)は現在アクティブに開発されています。
6+
セキュリティアップデートは最新版(0.x.x系)のみ提供しています。
67

7-
| Version | Supported |
8-
| ------- | ------------------ |
9-
| 0.x.x | :white_check_mark: |
8+
| バージョン | サポート状況 |
9+
| ---------- | ------------------- |
10+
| 0.x.x | |
1011

11-
## Reporting a Vulnerability
12+
## セキュリティに関するご注意
1213

13-
Please report security vulnerabilities through GitHub's Security Advisories feature:
14+
- 本リポジトリは AWS Lambda 上で動作する MCP(Model Context Protocol)サーバー用ライブラリです。
15+
- APIキー、シークレット、パスワード等のハードコーディングは禁止です。開発時は `.env` ファイル(.gitignore対象)、本番では環境変数や AWS Secrets Manager / Parameter Store をご利用ください。
16+
- 依存パッケージの脆弱性は `pnpm audit` や dependabot で定期的にチェックし、脆弱性が報告された場合は速やかにアップデートしてください。
17+
- CI/CD では静的解析(SAST)や依存性チェックを自動実行しています。
18+
- 外部から受け取るデータは型チェック・バリデーション(zod等)を必ず行ってください。
19+
- ログやエラーメッセージに認証情報・個人情報・シークレット等を出力しないでください。
20+
- クライアントへ返すデータは適切にエスケープし、XSS等の攻撃を防止してください。
21+
- IAMロール・ポリシーは最小権限の原則で設計してください。
22+
- セキュリティ上の懸念やインシデントが発生した場合は、速やかにご報告ください。
1423

15-
1. Go to the Security tab of this repository
16-
2. Click "Report a vulnerability"
17-
3. Fill out the private vulnerability report form
24+
## 脆弱性の報告方法
1825

19-
We will respond to security reports within 48 hours and provide regular updates on the remediation process.
26+
脆弱性を発見された場合は、GitHub の Security Advisories 機能を利用してご報告ください。
27+
28+
1. このリポジトリの「セキュリティ」タブに移動
29+
2. 「脆弱性の報告」をクリック
30+
3. フォームに詳細を記入し、送信
31+
32+
ご報告いただいた内容には48時間以内に初回対応し、修正状況について随時ご連絡いたします。

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
- 依存関係の更新はdependabotで行われるが、`pnpm up -r`での更新は可
2828
- `pnpm audit` による依存パッケージの脆弱性チェック実施は必須
2929
- 変数の破壊的再代入は禁止
30+
- TypeScript のドキュメンテーションコメントは TSDoc で記述する
3031

3132
## セキュリティベストプラクティス
3233

README.md

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,33 @@ TypeScriptでの利用例です。
2525

2626
```typescript
2727
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
28-
import { handler } from 'aws-lambda-mcp-server';
28+
import { createHonoApp } from 'aws-lambda-mcp-server';
2929
import { handle } from 'hono/aws-lambda';
30-
31-
// MCPサーバーのインスタンスを作成
32-
const server = new McpServer({
33-
name: 'my-mcp-server',
34-
version: '1.0.0',
35-
});
36-
37-
// MCPサーバーのインスタンスにToolsやResourcesなどを設定する
38-
server.tool(
39-
"say_hello",
40-
{ who: z.string() },
41-
async ({ who }) => ({
42-
content: [{
43-
type: "text",
44-
text: `${who} さん、こんにちは!`
45-
}]
46-
})
47-
);
30+
import { z } from 'zod';
31+
32+
// MCPサーバーのファクトリ関数を用意
33+
const createMcpServer = () => {
34+
const server = new McpServer({
35+
name: 'my-mcp-server',
36+
version: '1.0.0',
37+
});
38+
39+
// MCPサーバーのインスタンスにToolsやResourcesなどを設定する
40+
server.tool(
41+
'say_hello',
42+
{ who: z.string() },
43+
async ({ who }) => ({
44+
content: [{
45+
type: 'text',
46+
text: `${who} さん、こんにちは!`
47+
}]
48+
})
49+
);
50+
return server;
51+
};
4852

4953
// Hono アプリケーションを作成
50-
const app = createHonoApp(server);
54+
const app = createHonoApp(createMcpServer);
5155

5256
// AWS Lambdaのエントリポイントとして利用
5357
export const handler = handle(app);

SECURITY.md

Lines changed: 0 additions & 28 deletions
This file was deleted.

example/lambda/index.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,25 @@ import { createHonoApp } from 'aws-lambda-mcp-server';
66

77
const logger = new Logger();
88

9-
const server = new McpServer({
10-
name: 'hello-server',
11-
version: '1.0.0',
12-
});
13-
14-
server.tool(
15-
'say_hello',
16-
{ who: z.string() },
17-
async ({ who }) => ({
18-
content: [{
19-
type: 'text',
20-
text: `${who} さん、こんにちは!`,
21-
}],
22-
}),
23-
);
9+
const createMcpServer = () => {
10+
const server = new McpServer({
11+
name: 'hello-server',
12+
version: '1.0.0',
13+
});
2414

25-
const app = createHonoApp(server);
15+
server.tool(
16+
'say_hello',
17+
{ who: z.string() },
18+
async ({ who }) => ({
19+
content: [{
20+
type: 'text',
21+
text: `${who} さん、こんにちは!`,
22+
}],
23+
}),
24+
);
25+
return server;
26+
};
27+
const app = createHonoApp(createMcpServer);
2628

2729
// Lambda handler
2830
export const handler = handle(app);

package/README.md

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,33 @@ TypeScriptでの利用例です。
2121

2222
```typescript
2323
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
24-
import { handler } from 'aws-lambda-mcp-server';
24+
import { createHonoApp } from 'aws-lambda-mcp-server';
2525
import { handle } from 'hono/aws-lambda';
26-
27-
// MCPサーバーのインスタンスを作成
28-
const server = new McpServer({
29-
name: 'my-mcp-server',
30-
version: '1.0.0',
31-
});
32-
33-
// MCPサーバーのインスタンスにToolsやResourcesなどを設定する
34-
server.tool(
35-
"say_hello",
36-
{ who: z.string() },
37-
async ({ who }) => ({
38-
content: [{
39-
type: "text",
40-
text: `${who} さん、こんにちは!`
41-
}]
42-
})
43-
);
26+
import { z } from 'zod';
27+
28+
// MCPサーバーのファクトリ関数を用意
29+
const createMcpServer = () => {
30+
const server = new McpServer({
31+
name: 'my-mcp-server',
32+
version: '1.0.0',
33+
});
34+
35+
// MCPサーバーのインスタンスにToolsやResourcesなどを設定する
36+
server.tool(
37+
'say_hello',
38+
{ who: z.string() },
39+
async ({ who }) => ({
40+
content: [{
41+
type: 'text',
42+
text: `${who} さん、こんにちは!`
43+
}]
44+
})
45+
);
46+
return server;
47+
};
4448

4549
// Hono アプリケーションを作成
46-
const app = createHonoApp(server);
50+
const app = createHonoApp(createMcpServer);
4751

4852
// AWS Lambdaのエントリポイントとして利用
4953
export const handler = handle(app);

package/src/index.ts

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,37 @@
1+
/**
2+
* Model Context Protocol (MCP) サーバーを Hono フレームワーク上で動作させるエントリーポイント。
3+
*
4+
* @remarks
5+
* `createHonoApp` 関数を通じて、/mcp エンドポイントでMCPサーバーを提供します。
6+
* - POST/GET /mcp: MCPリクエストの受信・処理
7+
* - その他のHTTPメソッド: 405 Method Not Allowed
8+
*
9+
* 内部的にエラーハンドリングやリソースクローズ処理も行います。
10+
*/
11+
112
import { Logger } from '@aws-lambda-powertools/logger';
213
import { StreamableHTTPTransport } from '@hono/mcp';
314
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
415
import { Context, Hono } from 'hono';
516
import { BlankEnv, BlankInput } from 'hono/types';
617

18+
/**
19+
* ロガーインスタンス(AWS Lambda Powertools)。
20+
*
21+
* @private
22+
*/
723
const logger = new Logger();
824

25+
/**
26+
* 許可されていないHTTPメソッドに対するハンドラーです。
27+
*
28+
* @remarks
29+
* 405エラーのJSONレスポンスを返します。
30+
*
31+
* @param c Honoのコンテキスト
32+
* @returns 405エラーのJSONレスポンス
33+
* @private
34+
*/
935
const methodNotAllowedHandler = async (
1036
c: Context<BlankEnv, '/mcp', BlankInput>,
1137
) => {
@@ -22,6 +48,18 @@ const methodNotAllowedHandler = async (
2248
);
2349
};
2450

51+
/**
52+
* サーバーエラー発生時の共通エラーハンドラーです。
53+
*
54+
* @remarks
55+
* エラー内容をロギングし、500エラーのJSONレスポンスを返します。
56+
*
57+
* @param c Honoのコンテキスト
58+
* @param reason エラー理由
59+
* @param logMessage ログ出力用メッセージ
60+
* @returns 500エラーのJSONレスポンス
61+
* @private
62+
*/
2563
const handleError = (
2664
c: Context<BlankEnv, '/mcp', BlankInput>,
2765
reason: unknown,
@@ -44,6 +82,17 @@ const handleError = (
4482
);
4583
};
4684

85+
/**
86+
* MCPサーバーおよびトランスポートのリソースをクローズします。
87+
*
88+
* @remarks
89+
* どちらか一方のクローズに失敗しても、もう一方は必ず実行されます。
90+
*
91+
* @param server MCPサーバーインスタンス
92+
* @param transport トランスポートインスタンス
93+
* @returns void
94+
* @private
95+
*/
4796
const closeResources = async (server: McpServer, transport: StreamableHTTPTransport) => {
4897
// 両方のクローズを確実に実行(片方が失敗してももう片方を実行)
4998
const closeResults = await Promise.allSettled([
@@ -64,38 +113,69 @@ const closeResources = async (server: McpServer, transport: StreamableHTTPTransp
64113
});
65114
};
66115

67-
const handleRequest = async (server: McpServer, c: Context<BlankEnv, '/mcp', BlankInput>) => {
116+
/**
117+
* MCPリクエストを処理します。
118+
*
119+
* @remarks
120+
* サーバーとトランスポートの接続・リクエスト処理・エラーハンドリングを行います。
121+
*
122+
* @param createMcpServer MCPサーバーインスタンスを生成するファクトリ関数
123+
* @param c Honoのコンテキスト
124+
* @returns MCPレスポンス
125+
* @private
126+
*/
127+
const handleRequest = async (createMcpServer: () => McpServer, c: Context<BlankEnv, '/mcp', BlankInput>) => {
68128
const transport = new StreamableHTTPTransport({
69129
sessionIdGenerator: undefined, // セッションIDを生成しない(ステートレスモード)
70130
enableJsonResponse: true,
71131
});
132+
const server = createMcpServer();
72133
try {
73134
await server.connect(transport);
74135
logger.trace('MCP リクエストを受信');
75136
return await transport.handleRequest(c);
76137
} catch (error) {
138+
return handleError(c, error, 'MCP 接続中のエラー:');
139+
} finally {
140+
// エラーの有無に関わらず必ずリソースをクローズ
77141
try {
78142
await closeResources(server, transport);
79143
} catch (closeError) {
144+
// クローズエラーは既にcloseResources内でログ出力されているため、
145+
// ここでは追加のエラーハンドリングは不要だが、エラーの詳細を記録
80146
const errorDetails = closeError instanceof Error
81147
? { message: closeError.message, stack: closeError.stack }
82148
: closeError;
83-
logger.error('Transport close failed after connection error:', { closeError: errorDetails });
149+
logger.error('リソースクローズ中に追加エラーが発生しましたが、処理を継続します', { closeError: errorDetails });
84150
}
85-
return handleError(c, error, 'MCP 接続中のエラー:');
86151
}
87-
88152
};
89153

90-
export const createHonoApp = (server: McpServer) => {
154+
/**
155+
* Honoアプリケーションを生成し、/mcpエンドポイントでMCPサーバーを提供します。
156+
*
157+
* @remarks
158+
* POST/GET /mcp でMCPリクエストを受け付け、他のHTTPメソッドは405を返します。
159+
*
160+
* @param createMcpServer MCPサーバーインスタンスを生成するファクトリ関数
161+
* @returns Honoアプリケーションインスタンス
162+
*
163+
* @example
164+
* ```ts
165+
* import { createHonoApp } from '...';
166+
* import { createMcpServer } from './your-mcp-server';
167+
* const app = createHonoApp(createMcpServer);
168+
* ```
169+
*/
170+
export const createHonoApp = (createMcpServer: () => McpServer) => {
91171
const app = new Hono();
92172

93173
app.post('/mcp', async (c) => {
94-
return await handleRequest(server, c);
174+
return await handleRequest(createMcpServer, c);
95175
});
96176

97177
app.get('/mcp', async (c) => {
98-
return await handleRequest(server, c);
178+
return await handleRequest(createMcpServer, c);
99179
});
100180

101181
app.put('/mcp', methodNotAllowedHandler);

0 commit comments

Comments
 (0)