MCPクライアントにできることは、すべて通常のHTTPSを使ってスクリプトからも実行できます。エンドポイントは1つ、APIキーも1つ、入力も出力もJSONです。このガイドでは、認証、必要な3つの呼び出し、エラー、再試行、制限、新着メール向けのWebhookを説明します。
すべてのリクエストは、https://mcpemails.com/api/mcpへのJSON-RPC 2.0のPOSTです。claude.ai、ChatGPT、その他のMCPクライアントが使うのと同じエンドポイントで、ツールも権限も同じです。スクリプトとチャットアシスタントは同じ1つの製品を扱うことになります。
Content-Type: application/jsonとAccept: application/jsonを送信してください。応答は1つのJSONオブジェクトです。Authorizationヘッダーを持ちます。structuredContentオブジェクトが返されるため、文章を解析する必要はありません。同じデータがJSON文字列としてcontent[0].textにも入っています。mcpe_に続く64文字の16進数です。表示されるのは作成時の1回だけで、保存されるのはハッシュのみです。その場でコピーしてください。紛失したキーは復元できず、新しいキーに置き換えるしかありません。Authorization: Bearer mcpe_...として送信します。キーをURLやクエリ文字列に含めないでください。各キーが持つのは、作成時にチェックを入れた権限だけです。後からアクセスを編集で変更でき、変更は再接続なしで次の呼び出しから適用されます。
| スコープ | 許可される操作 |
|---|---|
read:email | メッセージの一覧表示、読み取り、検索、添付ファイルのダウンロード、受信トレイとフォルダーの一覧表示。 |
search:email | 古いキーのために残しています。検索はread:emailに含まれます。 |
send:email | 送信、返信、転送。 |
manage:drafts | 下書きの作成、更新、削除。下書きを送信するにはsend:emailも必要です。 |
manage:folders | メッセージの移動、コピー、フラグ設定、アーカイブ。フォルダーの作成、名前の変更、削除。 |
delete:email | メッセージの削除と一括削除。 |
manage:contacts | 最近のメールから連絡先を検索。 |
schedule:email | 予約送信の設定と、予約済みメールの管理。 |
manage:automations | 誰も見ていなくてもスケジュールどおりに実行されるルールの作成。 |
まずはread:emailから始め、ワークフローに必要になった時点で書き込み系のスコープを追加してください。キーのスコープ外の呼び出しは、メールサーバーに接続する前に拒否されます。ワークスペースの閲覧者が持てるのは読み取り系のスコープだけです。
既定では、キーはワークスペース内のすべての受信トレイにアクセスできます。一部に限定するには、キーのアクセスを編集を開き、受信トレイへのアクセスで受信トレイを選びます。この制限は呼び出しのたびに確認されるため、サポート用の受信トレイに限定したキーは、リクエストの内容にかかわらず経理用の受信トレイを読めません。
claude.ai、ChatGPT、その他のMCPクライアントなど、ユーザーが自分で接続するアプリは、キーではなくOAuthでログインします。動的クライアント登録、PKCE付きの認可コード、そしてユーザーがスコープと受信トレイを選ぶ同意画面を使います。詳しくはOAuth接続をご覧ください。自分のスクリプト、サーバー、ワークフローには、APIキーのほうが簡単です。
MCPクライアントはinitializeから始めます。サーバーはセッションを保持しないため、スクリプトでは省略できますが、キーが有効か確認し、サーバーの説明を読む手軽な方法として使えます。
curl -s https://mcpemails.com/api/mcp \
-H "Authorization: Bearer $MCPEMAILS_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"clientInfo": { "name": "my-agent", "version": "1.0" },
"capabilities": {}
}
}'tools/listは、このキーで呼び出せるすべてのツールを、説明、入力スキーマ、出力スキーマとともに返します。ツール名や引数をハードコードせず、起動時にこの一覧を読み込んでください。一覧はキーのスコープで絞り込まれ、ツールの引数は今後も追加されていきます。
curl -s https://mcpemails.com/api/mcp \
-H "Authorization: Bearer $MCPEMAILS_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'ツールを名前と引数で呼び出します。多くのツールは、動作を指定するactionを受け取ります。たとえばemail_readのlist、read、searchです。メールボックスはinbox (アドレス) またはinbox_idで指定します。inbox_listは両方を返します。
curl -s https://mcpemails.com/api/mcp \
-H "Authorization: Bearer $MCPEMAILS_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "email_read",
"arguments": { "action": "list", "inbox": "you@example.com", "unread": true, "limit": 20 }
}
}'成功した場合の結果:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{ "type": "text", "text": "{\"messages\":[...],\"total\":42, ...}" }],
"structuredContent": {
"messages": [{ "id": "...", "subject": "...", "from": { "name": "...", "email": "..." } }],
"total": 42,
"total_is_estimate": false,
"has_more": true,
"next_offset": 20
}
}
}エラーには2種類あります。まったく実行できなかったリクエストは、HTTPステータス付きのJSON-RPC errorとして返ります。ツールまで届いたものの、ツールに拒否されたリクエストは、AIモデルが理由を読めるように、isError: true付きの通常のresultとして返ります。分岐はメッセージの文面ではなく、data.error_codeまたは_metaのコードで行ってください。
| レスポンス | 発生する状況 | 対処 |
|---|---|---|
HTTP 401、-32001 | キーがない、形式が不正、取り消し済み、または期限切れ。 | Authorizationヘッダーを修正するか、新しいキーを作成します。再試行しても解決しません。 |
HTTP 403、-32004、insufficient_scope | このツール操作に必要なスコープがキーにない。許可に必要なスコープはdata.required_scopesに一覧されます。 | アクセスを編集でスコープを追加するか、別のキーを使います。 |
HTTP 429、-32003、rate_limit_exceeded | リクエストが多すぎる。どの時間枠が上限に達したかはdata.windowに示されます。 | Retry-Afterの秒数 (data.retry_afterにも記載) だけ待ってから、同じリクエストを再試行します。 |
-32602 | 不明なツール名。このキーで呼び出せる名前はdata.available_toolsに一覧されます。 | tools/listにある名前を使います。 |
isError: true、invalid_arguments | 引数がツールのスキーマに合わない。何も実行されていません。テキストに問題のある引数がそれぞれ示され、引数名が推測で付けられていた場合は、実在する引数名も示されます。 | 引数を修正します。同じ引数は同じように拒否されます。 |
isError: true、usage_limit_reached | Freeのワークスペースが月間のメール操作回数を使い切った。 | _metaにあるリセット日まで待つか、アップグレードします。有料プランではメール操作は無制限です。 |
isError: true、その他 | ツールは実行されたが失敗した。メッセージが見つからない、プロバイダーに拒否された、宛先が無効、など。 | content[0].textを読んでください。何が起きたか、何かが送信されたかどうかが書かれています。 |
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", ...
{
"jsonrpc": "2.0",
"id": 4,
"error": {
"code": -32004,
"message": "Insufficient scope: the 'send:email' scope is required to call email_compose.",
"data": { "error_code": "insufficient_scope", "required_scopes": ["send:email"], ... }
}
}HTTP/1.1 429 Too Many Requests
Retry-After: 12
{
"jsonrpc": "2.0",
"id": 5,
"error": {
"code": -32003,
"message": "Rate limit exceeded",
"data": { "error_code": "rate_limit_exceeded", "window": "per_minute", "retry_after": 12, ... }
}
}{
"jsonrpc": "2.0",
"id": 6,
"result": {
"isError": true,
"content": [{ "type": "text", "text": "Invalid arguments for email_read. The call was rejected before it ran, ..." }],
"_meta": {
"com.mcpemails/invalid_arguments": {
"error_code": "invalid_arguments",
"retryable": false,
"errors": [{ "path": "arguments.since", "message": "..." }]
}
}
}
}一覧と検索の結果は、すべて同じ4つのフィールドで終わります。
has_more: 次のページがあるときはtrue。すべて確認したことを意味するのはhas_more: falseだけです。next_offset: 他の引数はすべてそのままで、この値をoffsetとして渡すと次のページを取得できます。has_moreがfalseのときはnullです。total: 一致した件数。プロバイダーが件数を数えられない場合はnullです。手元のページと矛盾することはありません。total_is_estimate: totalが正確な件数ではなく、推定値または下限値のときにtrue。長いメッセージ本文も同じように分割されます。body_truncatedがtrueの場合は、body_next_offsetをbody_offsetとして渡して再度読み取ってください。
送信後に接続が切れると、メールが送られたかどうかわからなくなります。idempotency_keyを渡し、同じキーで再試行すれば、処理は1回だけ実行されます。
curl -s https://mcpemails.com/api/mcp \
-H "Authorization: Bearer $MCPEMAILS_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "email_compose",
"arguments": {
"action": "send",
"inbox": "you@example.com",
"to": ["customer@example.com"],
"subject": "Your order has shipped",
"body": "Hi, your order is on its way.",
"idempotency_key": "order-1042-shipped"
}
}
}'tools/listでは、対応するすべてのツールの入力スキーマにidempotency_keyが表示されます。idempotent_replay: true、元のstatus、そしてresultに元の結果が返されます。失われたかもしれないmessage_idもここに含まれます。idempotency_key_conflictで拒否されます。新しい操作には新しいキーを使ってください。status: "processing"が返ります。少し待ってから再試行してください。status: "unknown"になります。新しいキーで送り直す前に、送信済みフォルダーを確認してください。{
"idempotency_key": "order-1042-shipped",
"idempotent_replay": true,
"status": "succeeded",
"result": { "message_id": "...", "inbox_id": "...", "status": "sent" },
"message": "This logical request was already processed. ..."
}どの受信トレイでも、すべての送信を保留して担当者の承認を待つように設定できます。その場合、スクリプトからの送信はすぐには送られず、status: "pending_approval"とともにapproval_idが返ります。誰かがダッシュボードで承認すると送信されます。この機能はすべてのプランで使え、新しい自動化の動作を確かめている間の既定の設定として適しています。同じidempotency_keyで再試行すると、2つ目の承認を作らずに既存の承認が返されます。
各プランには、ワークスペース全体での1分あたりの上限があります。1つのキーでプランの1分あたりの上限をすべて使うことができ、複数のキーがある場合はその上限を共有します。
| プラン | 1分あたりのリクエスト数 | Webhook |
|---|---|---|
| Free | 60 | なし |
| Personal | 120 | なし |
| Pro | 300 | あり |
| Business | 1,000 | あり |
tools/callのレスポンスには、上限に近いほうの時間枠についてRateLimit-Limit、RateLimit-Remaining、RateLimit-Reset (秒単位) が含まれるため、クライアントは上限に達する前にペースを調整できます。data.windowに示されます。Retry-Afterが含まれます。その時間だけ待ってから、同じリクエストを再試行してください。ProとBusinessでは、受信トレイにメールが届いたときにMCPEmailsから指定のURLへPOSTできます。ワークフローはポーリングせずに新着メールで起動します。ダッシュボードでエンドポイントを作成し、対象の受信トレイを選んで、署名シークレットをコピーしてください。シークレットが表示されるのは1回だけです。URLはHTTPSで、ポートは443または8443である必要があります。テストボタンを使うと、署名付きのpingイベントを送信できます。
POST /your/webhook HTTP/1.1
Content-Type: application/json
MCPEmails-Event-Id: evt_...
MCPEmails-Event-Type: message.received
MCPEmails-Signature: t=1792843200,v1=5f2b...
{
"id": "evt_...",
"type": "message.received",
"created_at": "2026-10-24T09:20:00.000Z",
"workspace_id": "...",
"inbox_id": "...",
"folder": "INBOX",
"count": 1,
"message_ids": ["..."]
}typeはmessage.receivedです。message_idsには、その受信トレイのINBOXフォルダーに届いた新しいメッセージが、1イベントあたり最大10件まで含まれます。countは届いた件数で、それより多いこともあります。id、from、subjectを含むmessagesリストも届きます。email_read (action: "read"、inbox_id、message_id) で取得します。そのキーのスコープと受信トレイへのアクセスは通常どおり適用されます。すべての配信にはMCPEmails-Signature: t=<unix seconds>,v1=<hex>が含まれます。v1は、タイムスタンプ、ドット、生のリクエスト本文をつなげたものに対する、エンドポイントのシークレットをキーとしたHMAC-SHA256です。キーには表示されたとおりのシークレット全体を、whsec_の接頭辞も含めて使います。生の本文から署名を再計算し、定数時間で比較して、5分より古いタイムスタンプは拒否してください。
import crypto from 'node:crypto';
// rawBody: the request body exactly as received, before JSON.parse.
export function verifyMcpemailsSignature(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(
String(header ?? '').split(',').map((part) => part.trim().split('=')),
);
const timestamp = Number(parts.t);
if (!Number.isFinite(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest();
const received = Buffer.from(parts.v1 ?? '', 'hex');
return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}MCPEmails-Event-Idを使います。再試行では同じイベントIDが送られます。POSTにしたWebhookトリガーノードを追加し、その本番URLをMCPEmailsのダッシュボードでWebhookエンドポイントとして登録します。POST、URLはhttps://mcpemails.com/api/mcp、認証はGeneric Credential Type → Header Authで、名前をAuthorization、値をBearer mcpe_...にします。result.structuredContentでメッセージを受け取ります。NODE_FUNCTION_ALLOW_BUILTIN=cryptoでcryptoモジュールを許可してください。{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "email_read",
"arguments": {
"action": "read",
"inbox_id": "{{ $json.body.inbox_id }}",
"message_id": "{{ $json.body.message_ids[0] }}"
}
}
}メールの読み取りと送信を自分で行うAI Agentノードについては、n8nガイドをご覧ください。
ヘッダーにキーを入れてサーバーを追加します。OAuthログイン用のブラウザーがないヘッドレス環境やCIに適しています。
claude mcp add --transport http mcpemails https://mcpemails.com/api/mcp \
--header "Authorization: Bearer $MCPEMAILS_KEY"OAuthログインとスコープの選び方はClaude Codeガイドで説明しています。
1つの受信トレイの未読メッセージをページごとにすべて一覧表示し、429が返ったら待機します。
// node agent.mjs (Node 18 or later, MCPEMAILS_KEY in the environment)
const ENDPOINT = 'https://mcpemails.com/api/mcp';
let nextId = 1;
async function callTool(name, args) {
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MCPEMAILS_KEY}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({ jsonrpc: '2.0', id: nextId++, method: 'tools/call', params: { name, arguments: args } }),
});
if (res.status === 429) {
const wait = Number(res.headers.get('Retry-After') ?? 1);
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
return callTool(name, args);
}
const reply = await res.json();
if (reply.error) throw new Error(`${reply.error.code}: ${reply.error.message}`);
if (reply.result.isError) throw new Error(reply.result.content[0].text);
return reply.result.structuredContent;
}
const inbox = 'you@example.com';
let offset = 0;
do {
const page = await callTool('email_read', { action: 'list', inbox, unread: true, limit: 50, offset });
for (const m of page.messages) console.log(m.id, m.from?.email, m.subject);
offset = page.has_more ? page.next_offset : null;
} while (offset !== null);OpenClawは既定でOAuthを使ってログインします。手順はOpenClawガイドで説明しています。代わりにスコープ付きキーを使うには、サーバーエントリのheadersマップにキーを入れ、authは設定しないでください。OpenClawは、OAuthに設定されたエントリでは静的なAuthorizationヘッダーを無視するためです。
{
"mcp": {
"servers": {
"mcpemails": {
"url": "https://mcpemails.com/api/mcp",
"transport": "streamable-http",
"headers": { "Authorization": "Bearer mcpe_YOUR_KEY_HERE" }
}
}
}
}