Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
# Security Policy
# セキュリティポリシー

## Supported Versions
## サポート対象バージョン

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.
本プロジェクト(aws-lambda-mcp-server)は現在アクティブに開発されています。
Comment thread
poad marked this conversation as resolved.
セキュリティアップデートは最新版(0.x.x系)のみ提供しています。

| Version | Supported |
| ------- | ------------------ |
| 0.x.x | :white_check_mark: |
| バージョン | サポート状況 |
| ---------- | ------------------- |
| 0.x.x | ✅ |

## Reporting a Vulnerability
## セキュリティに関するご注意

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

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

We will respond to security reports within 48 hours and provide regular updates on the remediation process.
脆弱性を発見された場合は、GitHub の Security Advisories 機能を利用してご報告ください。

1. このリポジトリの「セキュリティ」タブに移動
2. 「脆弱性の報告」をクリック
3. フォームに詳細を記入し、送信

ご報告いただいた内容には48時間以内に初回対応し、修正状況について随時ご連絡いたします。
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- 依存関係の更新はdependabotで行われるが、`pnpm up -r`での更新は可
- `pnpm audit` による依存パッケージの脆弱性チェック実施は必須
- 変数の破壊的再代入は禁止
- TypeScript のドキュメンテーションコメントは TSDoc で記述する

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

Expand Down
44 changes: 24 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,33 @@ TypeScriptでの利用例です。

```typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { handler } from 'aws-lambda-mcp-server';
import { createHonoApp } from 'aws-lambda-mcp-server';
Comment thread
poad marked this conversation as resolved.
Comment thread
poad marked this conversation as resolved.
Comment thread
poad marked this conversation as resolved.
import { handle } from 'hono/aws-lambda';

// MCPサーバーのインスタンスを作成
const server = new McpServer({
name: 'my-mcp-server',
version: '1.0.0',
});

// MCPサーバーのインスタンスにToolsやResourcesなどを設定する
server.tool(
"say_hello",
{ who: z.string() },
async ({ who }) => ({
content: [{
type: "text",
text: `${who} さん、こんにちは!`
}]
})
);
import { z } from 'zod';
Comment thread
poad marked this conversation as resolved.
Comment thread
poad marked this conversation as resolved.
Comment thread
poad marked this conversation as resolved.

// MCPサーバーのファクトリ関数を用意
const createMcpServer = () => {
const server = new McpServer({
name: 'my-mcp-server',
version: '1.0.0',
});

// MCPサーバーのインスタンスにToolsやResourcesなどを設定する
server.tool(
'say_hello',
{ who: z.string() },
async ({ who }) => ({
content: [{
type: 'text',
text: `${who} さん、こんにちは!`
}]
})
);
return server;
Comment thread
poad marked this conversation as resolved.
};

// Hono アプリケーションを作成
const app = createHonoApp(server);
const app = createHonoApp(createMcpServer);

// AWS Lambdaのエントリポイントとして利用
export const handler = handle(app);
Expand Down
28 changes: 0 additions & 28 deletions SECURITY.md

This file was deleted.

34 changes: 18 additions & 16 deletions example/lambda/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,25 @@ import { createHonoApp } from 'aws-lambda-mcp-server';

const logger = new Logger();

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

server.tool(
'say_hello',
{ who: z.string() },
async ({ who }) => ({
content: [{
type: 'text',
text: `${who} さん、こんにちは!`,
}],
}),
);
const createMcpServer = () => {
const server = new McpServer({
name: 'hello-server',
version: '1.0.0',
});

const app = createHonoApp(server);
server.tool(
'say_hello',
{ who: z.string() },
async ({ who }) => ({
content: [{
type: 'text',
text: `${who} さん、こんにちは!`,
}],
}),
);
return server;
};
const app = createHonoApp(createMcpServer);

// Lambda handler
export const handler = handle(app);
Expand Down
44 changes: 24 additions & 20 deletions package/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,33 @@ TypeScriptでの利用例です。

```typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { handler } from 'aws-lambda-mcp-server';
import { createHonoApp } from 'aws-lambda-mcp-server';
Comment thread
poad marked this conversation as resolved.
import { handle } from 'hono/aws-lambda';

// MCPサーバーのインスタンスを作成
const server = new McpServer({
name: 'my-mcp-server',
version: '1.0.0',
});

// MCPサーバーのインスタンスにToolsやResourcesなどを設定する
server.tool(
"say_hello",
{ who: z.string() },
async ({ who }) => ({
content: [{
type: "text",
text: `${who} さん、こんにちは!`
}]
})
);
import { z } from 'zod';

// MCPサーバーのファクトリ関数を用意
Comment thread
poad marked this conversation as resolved.
const createMcpServer = () => {
const server = new McpServer({
name: 'my-mcp-server',
version: '1.0.0',
});

// MCPサーバーのインスタンスにToolsやResourcesなどを設定する
server.tool(
'say_hello',
{ who: z.string() },
async ({ who }) => ({
content: [{
type: 'text',
text: `${who} さん、こんにちは!`
}]
})
);
return server;
};

// Hono アプリケーションを作成
const app = createHonoApp(server);
const app = createHonoApp(createMcpServer);

// AWS Lambdaのエントリポイントとして利用
export const handler = handle(app);
Expand Down
94 changes: 87 additions & 7 deletions package/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
/**
* Model Context Protocol (MCP) サーバーを Hono フレームワーク上で動作させるエントリーポイント。
*
* @remarks
* `createHonoApp` 関数を通じて、/mcp エンドポイントでMCPサーバーを提供します。
* - POST/GET /mcp: MCPリクエストの受信・処理
* - その他のHTTPメソッド: 405 Method Not Allowed
*
* 内部的にエラーハンドリングやリソースクローズ処理も行います。
*/

import { Logger } from '@aws-lambda-powertools/logger';
import { StreamableHTTPTransport } from '@hono/mcp';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { Context, Hono } from 'hono';
import { BlankEnv, BlankInput } from 'hono/types';

/**
* ロガーインスタンス(AWS Lambda Powertools)。
*
* @private
*/
const logger = new Logger();

/**
* 許可されていないHTTPメソッドに対するハンドラーです。
*
* @remarks
* 405エラーのJSONレスポンスを返します。
*
* @param c Honoのコンテキスト
* @returns 405エラーのJSONレスポンス
* @private
*/
const methodNotAllowedHandler = async (
c: Context<BlankEnv, '/mcp', BlankInput>,
) => {
Expand All @@ -22,6 +48,18 @@ const methodNotAllowedHandler = async (
);
};

/**
* サーバーエラー発生時の共通エラーハンドラーです。
*
* @remarks
* エラー内容をロギングし、500エラーのJSONレスポンスを返します。
*
* @param c Honoのコンテキスト
* @param reason エラー理由
* @param logMessage ログ出力用メッセージ
* @returns 500エラーのJSONレスポンス
* @private
*/
const handleError = (
c: Context<BlankEnv, '/mcp', BlankInput>,
reason: unknown,
Expand All @@ -44,6 +82,17 @@ const handleError = (
);
};

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

const handleRequest = async (server: McpServer, c: Context<BlankEnv, '/mcp', BlankInput>) => {
/**
* MCPリクエストを処理します。
*
* @remarks
Comment thread
poad marked this conversation as resolved.
* サーバーとトランスポートの接続・リクエスト処理・エラーハンドリングを行います。
*
* @param createMcpServer MCPサーバーインスタンスを生成するファクトリ関数
* @param c Honoのコンテキスト
* @returns MCPレスポンス
* @private
*/
const handleRequest = async (createMcpServer: () => McpServer, c: Context<BlankEnv, '/mcp', BlankInput>) => {
Comment thread
poad marked this conversation as resolved.
const transport = new StreamableHTTPTransport({
sessionIdGenerator: undefined, // セッションIDを生成しない(ステートレスモード)
enableJsonResponse: true,
Comment thread
poad marked this conversation as resolved.
Comment thread
poad marked this conversation as resolved.
});
Comment thread
poad marked this conversation as resolved.
const server = createMcpServer();
try {
await server.connect(transport);
logger.trace('MCP リクエストを受信');
return await transport.handleRequest(c);
} catch (error) {
return handleError(c, error, 'MCP 接続中のエラー:');
} finally {
// エラーの有無に関わらず必ずリソースをクローズ
try {
await closeResources(server, transport);
} catch (closeError) {
// クローズエラーは既にcloseResources内でログ出力されているため、
// ここでは追加のエラーハンドリングは不要だが、エラーの詳細を記録
const errorDetails = closeError instanceof Error
? { message: closeError.message, stack: closeError.stack }
: closeError;
logger.error('Transport close failed after connection error:', { closeError: errorDetails });
logger.error('リソースクローズ中に追加エラーが発生しましたが、処理を継続します', { closeError: errorDetails });
}
return handleError(c, error, 'MCP 接続中のエラー:');
}

};

export const createHonoApp = (server: McpServer) => {
/**
* Honoアプリケーションを生成し、/mcpエンドポイントでMCPサーバーを提供します。
*
* @remarks
* POST/GET /mcp でMCPリクエストを受け付け、他のHTTPメソッドは405を返します。
*
* @param createMcpServer MCPサーバーインスタンスを生成するファクトリ関数
* @returns Honoアプリケーションインスタンス
*
Comment thread
poad marked this conversation as resolved.
* @example
* ```ts
* import { createHonoApp } from '...';
* import { createMcpServer } from './your-mcp-server';
* const app = createHonoApp(createMcpServer);
Comment thread
poad marked this conversation as resolved.
* ```
*/
export const createHonoApp = (createMcpServer: () => McpServer) => {
const app = new Hono();

app.post('/mcp', async (c) => {
return await handleRequest(server, c);
return await handleRequest(createMcpServer, c);
});

app.get('/mcp', async (c) => {
return await handleRequest(server, c);
return await handleRequest(createMcpServer, c);
});

app.put('/mcp', methodNotAllowedHandler);
Expand Down
Loading