@ampless/mcp-server 1.0.0-alpha.16 → 1.0.0-alpha.18

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.
package/README.ja.md CHANGED
@@ -3,151 +3,73 @@
3
3
 
4
4
  # @ampless/mcp-server
5
5
 
6
- [ampless](https://github.com/heavymoons/ampless) 向け MCP(Model Context Protocol)サーバー。Claude Desktop、Cursor、Claude Code、その他 MCP 対応ツールから AI エージェントが CMS インスタンスの投稿を読み書きしたり、メディアをアップロードしたりできます。
6
+ [ampless](https://github.com/heavymoons/ampless) 向け MCP ツールレジストリ。
7
7
 
8
- > **プレリリース / アルファ版。** v1.0 まではマイナーバージョンでも破壊的変更が入る可能性があります。
8
+ **直接インストールする必要はありません。** `@ampless/backend` の `mcp-handler` Lambda が `./tools` サブパスエクスポート経由で使い、`@ampless/admin` / `@ampless/backend` を入れると推移的に付いてきます。
9
9
 
10
- ## ツール一覧
11
-
12
- | ツール | 機能 |
13
- |---|---|
14
- | `list_posts` | オプションの `status` フィルターとページネーション付きで投稿一覧を取得 |
15
- | `get_post` | `slug` または `postId` で単一の投稿を取得 |
16
- | `create_post` | 新しい投稿を作成(下書きまたは公開済み) |
17
- | `update_post` | 既存の投稿のフィールドをパッチ更新 |
18
- | `delete_post` | 投稿を削除しタグインデックスをクリーンアップ |
19
- | `upload_media` | Base64 エンコードされたバイト列を S3 にアップロードし `Media` レコードを作成 |
20
- | `get_schema` | CMS コンテンツスキーマ(Post / Page / Media のフィールド形状)を返す |
21
-
22
- サーバーは指定した認証情報(環境変数)で Cognito ユーザープールにサインインするため、各ツールはそのユーザーのロール(`ampless-admin` または `ampless-editor`)で動作します。下書きや編集内容は認証済みユーザーにのみ表示されます。リゾルバー側の `status === 'published'` フィルターにより、未公開コンテンツはパブリック読み取りからは見えません。
23
-
24
- ## インストール
25
-
26
- サーバーは Node CLI として公開されています。グローバルインストールは通常不要です — MCP クライアントから `npx -y @ampless/mcp-server@alpha` を指定してください。
27
-
28
- ## 設定
29
-
30
- 以下が必要です:
31
-
32
- 1. **`amplify_outputs.json`** — `npx ampx sandbox` または `npx ampx pipeline-deploy` で生成されます。パスは `--outputs` で渡します。
33
- 2. **Cognito ユーザーアカウント** — ユーザープールのメールアドレスとパスワード。管理 UI から最初に作成したユーザーは自動的に `ampless-admin` に登録されます。
34
- 3. **AWS 認証情報** — `upload_media` を使用する場合にのみ必要です。デフォルトの認証情報チェーン(`AWS_PROFILE`、環境変数、インスタンスロール)が使用されます。読み取り専用ツールは AWS 認証情報なしで動作します。
35
-
36
- ### Claude Desktop
37
-
38
- `~/Library/Application Support/Claude/claude_desktop_config.json`(macOS)またはプラットフォームに応じた同等のパスを編集します:
10
+ ## 全体の構成
39
11
 
40
- ```json
41
- {
42
- "mcpServers": {
43
- "ampless": {
44
- "command": "npx",
45
- "args": [
46
- "-y",
47
- "@ampless/mcp-server",
48
- "--outputs",
49
- "/absolute/path/to/your-site/amplify_outputs.json"
50
- ],
51
- "env": {
52
- "AMPLESS_MCP_EMAIL": "you@example.com",
53
- "AMPLESS_MCP_PASSWORD": "your-password"
54
- }
55
- }
56
- }
57
- }
12
+ ```
13
+ MCP クライアント (.mcp.json)
14
+ └── HTTP Bearer トークン (amk_...)
15
+ └── mcp-handler Lambda (packages/backend/src/functions/mcp-handler.ts)
16
+ └── @ampless/mcp-server/tools ← このパッケージ
17
+ └── ToolDefinition[], dispatchToolCall
58
18
  ```
59
19
 
60
- Claude Desktop を再起動すると、7 つのツールが `/mcp` の下に表示されます。
20
+ `mcp-handler` Lambda Bearer トークンを `McpToken` AppSync モデル(admin 専用)に照合し、`ToolContext`(GraphQL クライアント + S3 クライアント + サイトコンテキスト)を構築して、各ツール呼び出しをこのパッケージの `dispatchToolCall` に委譲します。
61
21
 
62
- ### Cursor
22
+ エンドユーザーは管理画面経由で MCP を設定します:
63
23
 
64
- `~/.cursor/mcp.json` を編集するか、**Cursor Settings → MCP** を使用します。設定の形式は Claude Desktop と同じです:
24
+ 1. `/admin/mcp-tokens` にアクセスし、Bearer トークン(`amk_...`)を発行する。
25
+ 2. Amplify コンソールまたは `amplify_outputs.json` で `mcp-handler` Lambda の Function URL を確認する。
26
+ 3. MCP クライアントの設定ファイル(`.mcp.json`、`claude_desktop_config.json` など)にエントリを追加する:
65
27
 
66
28
  ```json
67
29
  {
68
30
  "mcpServers": {
69
31
  "ampless": {
70
- "command": "npx",
71
- "args": ["-y", "@ampless/mcp-server", "--outputs", "/path/to/amplify_outputs.json"],
72
- "env": {
73
- "AMPLESS_MCP_EMAIL": "you@example.com",
74
- "AMPLESS_MCP_PASSWORD": "your-password"
32
+ "url": "https://<function-url-id>.lambda-url.<region>.on.aws/",
33
+ "transport": "http",
34
+ "headers": {
35
+ "Authorization": "Bearer amk_..."
75
36
  }
76
37
  }
77
38
  }
78
39
  }
79
40
  ```
80
41
 
81
- ### Claude Code
42
+ HTTP MCP のアーキテクチャ全体については `docs/architecture/04-access-layer-mcp.md` を参照してください。
82
43
 
83
- プロジェクトレベルの MCP サーバーを追加します:
44
+ ## エクスポート
84
45
 
85
- ```bash
86
- claude mcp add ampless \
87
- --env AMPLESS_MCP_EMAIL=you@example.com \
88
- --env AMPLESS_MCP_PASSWORD=your-password \
89
- -- npx -y @ampless/mcp-server --outputs /path/to/amplify_outputs.json
90
- ```
91
-
92
- ## 使用例
93
-
94
- 登録後、AI エージェントに次のように指示できます:
95
-
96
- - 「最新の投稿を 5 件表示して。」
97
- - 「スラッグ `welcome` の投稿を見せて。」
98
- - 「タイトル '2 記事目' の下書きを markdown 形式で、本文 'Hello world.' で作成して。」
99
- - 「投稿 `post-1234` を公開して。」
100
- - 「スラッグ `bad-draft` の投稿を削除して。」
101
-
102
- エージェントが自動的に適切なツールを選択します。
103
-
104
- ### `format` ごとの `body` の形式
105
-
106
- - `format: 'markdown'` → body は markdown ソース文字列
107
- - `format: 'html'` → body は生の HTML 文字列(そのままレンダリングされます — 下記のエディタートラストモデルを参照)
108
- - `format: 'tiptap'` → body は tiptap ドキュメント JSON、例:
109
-
110
- ```json
111
- {
112
- "type": "doc",
113
- "content": [
114
- { "type": "paragraph", "content": [{ "type": "text", "text": "Hello" }] }
115
- ]
116
- }
117
- ```
118
-
119
- AI に投稿本文を生成させる場合は、markdown を指定するのが最も簡単です。
120
-
121
- ## セキュリティに関する注意
122
-
123
- - **エディタートラストモデル。** ampless は `editor` と `admin` を同一のトラストクラスとして扱います — どちらも投稿本文に任意の HTML / JS を格納できます(`docs/architecture/04-access-layer-mcp.md` 参照)。MCP サーバーが書き込める内容は、そのユーザーアカウントが管理 UI から書き込める内容と同じです。
124
- - **設定ファイル内の認証情報。** `AMPLESS_MCP_PASSWORD` は Claude Desktop / Cursor の設定ファイル内にプレーンテキストで保存されます。SSH 秘密鍵と同様に扱ってください。OS キーチェーン連携はロードマップで対応予定です。
125
- - **AWS 認証情報。** `upload_media` のみ必要です。サイトの S3 バケットへの書き込み権限のみを持つ専用の IAM ユーザー / ロールを使用してください。
126
-
127
- ## CLI フラグ
46
+ ### `./tools`
128
47
 
48
+ ```typescript
49
+ import { getTools, dispatchToolCall } from '@ampless/mcp-server/tools'
50
+ import type { ToolDefinition, ToolContext, ResolvedSite } from '@ampless/mcp-server/tools'
129
51
  ```
130
- ampless-mcp [options]
131
-
132
- --outputs <path> amplify_outputs.json へのパス(AMPLESS_MCP_OUTPUTS でも指定可)
133
- --site-name <name> コンテキスト用のサイト表示名(AMPLESS_MCP_SITE_NAME でも指定可、例: "mysite.net")
134
- --site-url <url> ツール結果に含めるサイト URL(AMPLESS_MCP_SITE_URL でも指定可、省略可)
135
- --environment <env> デプロイ環境: prod | stg | dev(AMPLESS_MCP_ENVIRONMENT でも指定可、デフォルト "dev")
136
- --site-id <id> クエリのデフォルト siteId(AMPLESS_MCP_SITE_ID でも指定可、デフォルト "default")
137
- ```
138
-
139
- `--site-name` を設定すると、MCP クライアントに表示されるサーバー名にサイトと環境が含まれ(例: `@ampless/mcp-server [mysite.net/prod]`)、ツールの description に `[mysite.net / prod]` が前置され、結果が `{ site, result }` でラップされます。`--environment prod` 設定時、破壊的ツール(`delete_post`、`delete_static_file`、`upload_static_bundle`)の呼び出しにはサイト名と一致する `confirmSite` 引数が必要です。
140
52
 
141
- 必須の環境変数:
142
-
143
- ```
144
- AMPLESS_MCP_EMAIL Cognito ユーザーのメールアドレス
145
- AMPLESS_MCP_PASSWORD Cognito ユーザーのパスワード
146
- ```
53
+ | エクスポート | 説明 |
54
+ |---|---|
55
+ | `getTools()` | `ToolDefinition` オブジェクトのリスト(name、description、inputSchema)を返す |
56
+ | `dispatchToolCall(name, args, ctx)` | 名前でツール呼び出しをディスパッチする。不明なツール名の場合は例外をスロー |
57
+ | `ToolDefinition` | 単一ツールのインターフェース(name、description、inputSchema、handler) |
58
+ | `ToolContext` | ランタイムコンテキストのインターフェース(graphql、storage、site) |
59
+ | `ResolvedSite` | 解決済みサイトコンテキストのインターフェース(name、url、environment、siteId) |
147
60
 
148
- ## トラブルシューティング
61
+ ## ツール一覧
149
62
 
150
- - **`NotAuthorizedException: Incorrect username or password.`** — 認証情報が誤っているか、メールアドレスが未確認です。まず Web の `/login` から一度サインインしてください。
151
- - **`InvalidPasswordException`** — ユーザーが `FORCE_CHANGE_PASSWORD` 状態です。Web UI からサインインして永続パスワードを設定してください。
152
- - **`AppSync 401`** ID トークンが拒否された可能性があります。サーバーは次の呼び出し時に自動更新します。繰り返し 401 が発生する場合は、ユーザープールが再デプロイされている可能性があるため認証情報を更新してください。
153
- - **`upload_media` AWS 認証情報なしで失敗する** MCP サーバーの環境に `AWS_PROFILE` または `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` を設定してください。
63
+ | ツール | role | 説明 |
64
+ |---|---|---|
65
+ | `list_posts` | reader | オプションの status フィルターとページネーション付きで投稿一覧を取得 |
66
+ | `get_post` | reader | slug または postId で単一の投稿を取得 |
67
+ | `create_post` | editor | 新しい投稿を作成(下書きまたは公開済み) |
68
+ | `update_post` | editor | 既存の投稿のフィールドをパッチ更新 |
69
+ | `delete_post` | editor | 投稿を削除しタグインデックスをクリーンアップ |
70
+ | `upload_media` | editor | Base64 エンコードされたバイト列を S3 にアップロードし Media レコードを作成 |
71
+ | `get_schema` | reader | CMS コンテンツスキーマを返す |
72
+ | `upload_static_bundle` | editor | ビルド済み静的バンドルを S3 にアップロード |
73
+ | `list_static_files` | reader | 静的バンドルファイルを一覧表示 |
74
+ | `delete_static_file` | editor | 静的ファイルを S3 から削除 |
75
+ | `get_site_context` | reader | 現在のサイトコンテキスト(name、url、environment)を返す |
package/README.md CHANGED
@@ -3,151 +3,73 @@
3
3
 
4
4
  # @ampless/mcp-server
5
5
 
6
- MCP (Model Context Protocol) server for [ampless](https://github.com/heavymoons/ampless). Lets AI agents — Claude Desktop, Cursor, Claude Code, and anything else that speaks MCP — read and write posts and upload media on your CMS instance.
6
+ MCP tool registry for [ampless](https://github.com/heavymoons/ampless).
7
7
 
8
- > **Pre-release / alpha.** Breaking changes possible in any minor version until v1.0.
8
+ **No direct install needed.** This package is consumed by `@ampless/backend`'s `mcp-handler` Lambda via the `./tools` subpath export, and arrives transitively when you install `@ampless/admin` or `@ampless/backend`.
9
9
 
10
- ## Tools
11
-
12
- | Tool | What it does |
13
- |---|---|
14
- | `list_posts` | List posts with optional `status` filter and pagination |
15
- | `get_post` | Fetch a single post by `slug` or `postId` |
16
- | `create_post` | Create a new post (draft or published) |
17
- | `update_post` | Patch fields on an existing post |
18
- | `delete_post` | Delete a post and clean up its tag index |
19
- | `upload_media` | Upload base64-encoded bytes to S3 and create a `Media` record |
20
- | `get_schema` | Return the CMS content schema (Post / Page / Media field shapes) |
21
-
22
- The server signs in to your Cognito User Pool with the credentials you provide (env vars), so each tool runs with the role of that user (`ampless-admin` or `ampless-editor`). Drafts and editing surface only to authenticated users; the resolver-side `status === 'published'` filter still keeps unpublished content invisible to public reads.
23
-
24
- ## Install
25
-
26
- The server is published as a Node CLI; you typically don't install it globally — point your MCP client at `npx -y @ampless/mcp-server@alpha` instead.
27
-
28
- ## Configure
29
-
30
- You need:
31
-
32
- 1. **`amplify_outputs.json`** — generated by `npx ampx sandbox` or `npx ampx pipeline-deploy`. The path is passed via `--outputs`.
33
- 2. **A Cognito user account** — email + password from your User Pool. The first user created via the admin UI is automatically in `ampless-admin`.
34
- 3. **AWS credentials** — only required if you intend to use `upload_media`. The default credential chain (`AWS_PROFILE`, env vars, instance role) is used. Read-only tools work without AWS credentials.
35
-
36
- ### Claude Desktop
37
-
38
- Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or the equivalent path on your platform:
10
+ ## How it fits together
39
11
 
40
- ```json
41
- {
42
- "mcpServers": {
43
- "ampless": {
44
- "command": "npx",
45
- "args": [
46
- "-y",
47
- "@ampless/mcp-server",
48
- "--outputs",
49
- "/absolute/path/to/your-site/amplify_outputs.json"
50
- ],
51
- "env": {
52
- "AMPLESS_MCP_EMAIL": "you@example.com",
53
- "AMPLESS_MCP_PASSWORD": "your-password"
54
- }
55
- }
56
- }
57
- }
12
+ ```
13
+ MCP client (.mcp.json)
14
+ └── HTTP Bearer token (amk_...)
15
+ └── mcp-handler Lambda (packages/backend/src/functions/mcp-handler.ts)
16
+ └── @ampless/mcp-server/tools ← this package
17
+ └── ToolDefinition[], dispatchToolCall
58
18
  ```
59
19
 
60
- Restart Claude Desktop. The 7 tools should appear under `/mcp`.
20
+ The `mcp-handler` Lambda resolves the Bearer token against the `McpToken` AppSync model (admin-only), builds a `ToolContext` (GraphQL client + S3 client + site context), and delegates each incoming tool call to `dispatchToolCall` from this package.
61
21
 
62
- ### Cursor
22
+ End users configure MCP via the admin UI:
63
23
 
64
- Edit `~/.cursor/mcp.json` (or use **Cursor Settings MCP**). The config shape is the same as Claude Desktop:
24
+ 1. Go to `/admin/mcp-tokens` and issue a Bearer token (`amk_...`).
25
+ 2. Find the `mcp-handler` Lambda Function URL in the Amplify console or `amplify_outputs.json`.
26
+ 3. Add an entry to your MCP client's config (`.mcp.json`, `claude_desktop_config.json`, etc.):
65
27
 
66
28
  ```json
67
29
  {
68
30
  "mcpServers": {
69
31
  "ampless": {
70
- "command": "npx",
71
- "args": ["-y", "@ampless/mcp-server", "--outputs", "/path/to/amplify_outputs.json"],
72
- "env": {
73
- "AMPLESS_MCP_EMAIL": "you@example.com",
74
- "AMPLESS_MCP_PASSWORD": "your-password"
32
+ "url": "https://<function-url-id>.lambda-url.<region>.on.aws/",
33
+ "transport": "http",
34
+ "headers": {
35
+ "Authorization": "Bearer amk_..."
75
36
  }
76
37
  }
77
38
  }
78
39
  }
79
40
  ```
80
41
 
81
- ### Claude Code
42
+ See `docs/architecture/04-access-layer-mcp.md` for the full HTTP MCP architecture.
82
43
 
83
- Add a project-level MCP server:
44
+ ## Exports
84
45
 
85
- ```bash
86
- claude mcp add ampless \
87
- --env AMPLESS_MCP_EMAIL=you@example.com \
88
- --env AMPLESS_MCP_PASSWORD=your-password \
89
- -- npx -y @ampless/mcp-server --outputs /path/to/amplify_outputs.json
90
- ```
91
-
92
- ## Usage examples
93
-
94
- Once registered, prompt your AI agent:
95
-
96
- - "List the latest 5 posts."
97
- - "Show me the post with slug `welcome`."
98
- - "Create a draft titled 'My second post' with format markdown and body 'Hello world.'"
99
- - "Publish post `post-1234`."
100
- - "Delete the post with slug `bad-draft`."
101
-
102
- The agent will pick the right tool automatically.
103
-
104
- ### `body` shape per `format`
105
-
106
- - `format: 'markdown'` → body is a markdown source string
107
- - `format: 'html'` → body is a raw HTML string (rendered verbatim — see editor trust model below)
108
- - `format: 'tiptap'` → body is the tiptap document JSON, e.g.
109
-
110
- ```json
111
- {
112
- "type": "doc",
113
- "content": [
114
- { "type": "paragraph", "content": [{ "type": "text", "text": "Hello" }] }
115
- ]
116
- }
117
- ```
118
-
119
- If you're letting the AI generate post bodies, asking for markdown is usually easiest.
120
-
121
- ## Security notes
122
-
123
- - **Editor trust model.** ampless treats `editor` and `admin` as a single trust class — both can store arbitrary HTML/JS in post bodies (see `docs/architecture/04-access-layer-mcp.md`). Whatever the MCP server can write, that user account could already write through the admin UI.
124
- - **Credentials in the config file.** `AMPLESS_MCP_PASSWORD` lives in plaintext inside Claude Desktop / Cursor's config file. Treat that file like an SSH private key. OS keychain integration is on the roadmap.
125
- - **AWS credentials.** Only `upload_media` requires them. Use a dedicated IAM user / role with write access only to your site's S3 bucket.
126
-
127
- ## CLI flags
46
+ ### `./tools`
128
47
 
48
+ ```typescript
49
+ import { getTools, dispatchToolCall } from '@ampless/mcp-server/tools'
50
+ import type { ToolDefinition, ToolContext, ResolvedSite } from '@ampless/mcp-server/tools'
129
51
  ```
130
- ampless-mcp [options]
131
-
132
- --outputs <path> Path to amplify_outputs.json (also AMPLESS_MCP_OUTPUTS)
133
- --site-name <name> Site display name for context (also AMPLESS_MCP_SITE_NAME; e.g. "mysite.net")
134
- --site-url <url> Site URL included in tool results (also AMPLESS_MCP_SITE_URL; optional)
135
- --environment <env> Deployment environment: prod | stg | dev (also AMPLESS_MCP_ENVIRONMENT; default "dev")
136
- --site-id <id> Default siteId for queries (also AMPLESS_MCP_SITE_ID; default "default")
137
- ```
138
-
139
- When `--site-name` is set, the server name shown in MCP clients includes the site and environment (e.g. `@ampless/mcp-server [mysite.net/prod]`), tool descriptions are prefixed with `[mysite.net / prod]`, and results are wrapped in `{ site, result }`. Destructive tools (`delete_post`, `delete_static_file`, `upload_static_bundle`) require a `confirmSite` argument equal to the site name when `--environment prod` is set.
140
52
 
141
- Required env:
142
-
143
- ```
144
- AMPLESS_MCP_EMAIL Cognito user email
145
- AMPLESS_MCP_PASSWORD Cognito user password
146
- ```
53
+ | Export | Description |
54
+ |---|---|
55
+ | `getTools()` | Returns the list of `ToolDefinition` objects (name, description, inputSchema) |
56
+ | `dispatchToolCall(name, args, ctx)` | Dispatches a tool call by name; throws if unknown |
57
+ | `ToolDefinition` | Interface for a single tool (name, description, inputSchema, handler) |
58
+ | `ToolContext` | Interface for the runtime context (graphql, storage, site) |
59
+ | `ResolvedSite` | Interface for the resolved site context (name, url, environment, siteId) |
147
60
 
148
- ## Troubleshooting
61
+ ## Tools
149
62
 
150
- - **`NotAuthorizedException: Incorrect username or password.`** — Wrong creds, or the user hasn't confirmed their email. Sign in via the web `/login` once first.
151
- - **`InvalidPasswordException`** — The user is in `FORCE_CHANGE_PASSWORD` state. Sign in via the web UI to set a permanent password.
152
- - **`AppSync 401`** id token may have been rejected; the server auto-refreshes on the next call. Repeated 401s usually mean the User Pool was redeployed and your creds need updating.
153
- - **`upload_media` fails with no AWS credentials** set `AWS_PROFILE` or `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` in the MCP server's environment.
63
+ | Tool | Role | Description |
64
+ |---|---|---|
65
+ | `list_posts` | reader | List posts with optional status filter and pagination |
66
+ | `get_post` | reader | Fetch a single post by slug or postId |
67
+ | `create_post` | editor | Create a new post (draft or published) |
68
+ | `update_post` | editor | Patch fields on an existing post |
69
+ | `delete_post` | editor | Delete a post and clean up its tag index |
70
+ | `upload_media` | editor | Upload base64-encoded bytes to S3 and create a Media record |
71
+ | `get_schema` | reader | Return the CMS content schema |
72
+ | `upload_static_bundle` | editor | Upload a pre-built static bundle to S3 |
73
+ | `list_static_files` | reader | List static bundle files |
74
+ | `delete_static_file` | editor | Delete a static file from S3 |
75
+ | `get_site_context` | reader | Return current site context (name, url, environment) |
package/dist/index.d.ts CHANGED
@@ -1,2 +1,128 @@
1
+ import { BundleExtractResult } from 'ampless';
1
2
 
2
- export { }
3
+ /**
4
+ * Site context passed from the HTTP transport into each tool call.
5
+ * The mcp-handler Lambda resolves this from the MCP access token.
6
+ */
7
+ interface ResolvedSite {
8
+ name: string;
9
+ url?: string;
10
+ environment: 'prod' | 'stg' | 'dev';
11
+ siteId: string;
12
+ }
13
+ /**
14
+ * Abstract contracts each tool handler depends on. Concrete
15
+ * implementations live in `@ampless/backend`'s mcp-handler Lambda:
16
+ *
17
+ * - `mcp-graphql-client.ts` — AppSync GraphQL client (Bearer token)
18
+ * - `mcp-storage-client.ts` — S3 client for media operations
19
+ *
20
+ * Both satisfy these interfaces structurally (no `implements` needed)
21
+ * — TypeScript's structural typing checks the shape on the call site.
22
+ * Tools never instantiate these themselves; the caller passes a ready
23
+ * `ToolContext` into `dispatchToolCall`.
24
+ */
25
+ interface GraphqlClient {
26
+ query<T>(operation: string, variables?: Record<string, unknown>): Promise<T>;
27
+ }
28
+ interface StorageObject {
29
+ /** Full S3 key including any prefix. */
30
+ key: string;
31
+ /** Object size in bytes (0 when the backend can't supply it). */
32
+ size: number;
33
+ /** ISO 8601 timestamp of the last write, when the backend supplies it. */
34
+ lastModified?: string;
35
+ }
36
+ interface StorageClient {
37
+ /**
38
+ * Upload `body` to the bucket at `key` with `contentType`. Returns
39
+ * the public URL of the stored object (same format both routes use:
40
+ * https://{bucket}.s3.{region}.amazonaws.com/{key}).
41
+ */
42
+ putObject(key: string, body: Uint8Array, contentType: string): Promise<string>;
43
+ /**
44
+ * Remove the object at `key`. Implementations should treat a missing
45
+ * key as success (S3 DeleteObject is idempotent by default).
46
+ */
47
+ deleteObject(key: string): Promise<void>;
48
+ /**
49
+ * List every object under `prefix`. Implementations are expected to
50
+ * paginate internally so the caller gets the full set in a single
51
+ * resolved promise — the static-bundle tools never expect more than
52
+ * a few hundred entries per bundle in practice.
53
+ */
54
+ listObjects(prefix: string): Promise<StorageObject[]>;
55
+ }
56
+ interface ToolContext {
57
+ graphql: GraphqlClient;
58
+ storage: () => StorageClient;
59
+ site?: ResolvedSite;
60
+ }
61
+
62
+ /**
63
+ * Server-side zip extractor used by the static-bundle MCP tools. Both
64
+ * the stdio CLI and the Lambda HTTP transport run this — `fflate` is
65
+ * a workspace dependency of `@ampless/mcp-server`, so the import
66
+ * resolves identically in both. The browser-side admin uploader has
67
+ * its own `extractZip(File)` based on JSZip (works on a `File`, not a
68
+ * `Buffer`).
69
+ *
70
+ * Behaviour parity with the admin extractor:
71
+ * - Skip directory entries (fflate gives byte arrays only, so this
72
+ * is naturally satisfied unless the zip has empty-byte directory
73
+ * placeholders — those still get filtered out by validateBundlePath
74
+ * returning "directory entry" for any path ending with `/`).
75
+ * - Silently drop OS-specific junk (`__MACOSX/*`, `.DS_Store`,
76
+ * `Thumbs.db`) so callers don't see them as bundle entries.
77
+ * - Surface structural issues (absolute paths, parent traversal, null
78
+ * bytes) so the tool can reject the upload.
79
+ * - Strip a common single top-level directory (macOS Finder zips
80
+ * wrap their contents in a folder).
81
+ */
82
+
83
+ interface ExtractZipOptions {
84
+ /**
85
+ * Hard ceiling on uncompressed bundle bytes. Defaults to 50 MB,
86
+ * matching the browser uploader's MAX_BUNDLE_BYTES. Callers running
87
+ * inside a tight Lambda envelope (Function URL payload cap ~6 MB
88
+ * post-base64) can tighten this; setting it lower than the bundle
89
+ * causes `extractZipFromBuffer` to throw before fully populating
90
+ * `files`.
91
+ */
92
+ maxBytes?: number;
93
+ }
94
+ /**
95
+ * Unzip `buffer` in memory and return the same shape the browser
96
+ * `extractZip(File)` helper returns. Throws if the unzip itself fails
97
+ * (corrupt archive) or if the uncompressed size exceeds `maxBytes`.
98
+ */
99
+ declare function extractZipFromBuffer(buffer: Uint8Array, opts?: ExtractZipOptions): BundleExtractResult;
100
+ /**
101
+ * Decode an extracted file's bytes as UTF-8 text. Used by the tool
102
+ * handler before running cross-file `validateBundle` so we don't
103
+ * instantiate a TextDecoder per entry. fflate provides a fast helper.
104
+ */
105
+ declare function decodeUtf8(data: Uint8Array): string;
106
+
107
+ interface ToolDefinition {
108
+ name: string;
109
+ description: string;
110
+ inputSchema: Record<string, unknown>;
111
+ handler: (args: Record<string, unknown>, ctx: ToolContext) => Promise<unknown>;
112
+ destructive?: boolean;
113
+ }
114
+ declare const tools: ToolDefinition[];
115
+ /**
116
+ * Look up a tool definition by name and invoke its handler. Returns
117
+ * `null` when no tool with that name is registered — callers should
118
+ * surface that as a JSON-RPC "method not found" error.
119
+ */
120
+ declare function dispatchToolCall(name: string, args: Record<string, unknown>, ctx: ToolContext): Promise<unknown>;
121
+ /**
122
+ * `tools` is the canonical registry; `getTools()` returns it for
123
+ * callers that prefer a function over a top-level constant (admin's
124
+ * HTTP factory exposes this through its options shape).
125
+ */
126
+ declare function getTools(): readonly ToolDefinition[];
127
+
128
+ export { type ExtractZipOptions, type GraphqlClient, type StorageClient, type StorageObject, type ToolContext, type ToolDefinition, decodeUtf8, dispatchToolCall, extractZipFromBuffer, getTools, tools };