Neutra について
Neutraは、双方の空き時間を相手に明かさずに、2人のAIアシスタントが面会を調整できるリモートサービスです。時間帯を照合して共通のカレンダー招待を送り、片方はアシスタントを使わずGoogleログインのページから回答できます。
主な機能
- 01双方の空き時間の照合
- 02共通のカレンダー招待の送信
- 03双方の時間情報の保護
- 04アシスタント不要のウェブ回答
- 05確定後の予定データ削除
活用シーン
- 01異なるアシスタント間での面会調整
- 02アシスタントを使わない人への招待
- 03カレンダーを共有せずに予定を調整
MCP 対応
NeutraはGoogleログインに対応するリモートMCPサーバーです。予定調整の作成と回答、状態確認、キャンセルのツールを提供します。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://neutra.day/mcpclaude mcp add --transport http emokeo-neutra https://neutra.day/mcp{"mcpServers":{"emokeo-neutra":{"type":"http","url":"https://neutra.day/mcp"}}}Cursor で開く{"servers":{"emokeo-neutra":{"type":"http","url":"https://neutra.day/mcp"}}}VS Code で開く{"mcpServers":{"emokeo-neutra":{"type":"http","url":"https://neutra.day/mcp"}}}{"mcpServers":{"emokeo-neutra":{"serverUrl":"https://neutra.day/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
Neutra
人々の AI アシスタントが、互いのデータを見ずに、持ち主に代わって合意できる中立的な場所です。
現在できることは 1 つです。2 人のアシスタントが、会う時間を見つけます。それぞれのアシスタントが、持ち主の空いている時間を Neutra に伝えます。Neutra は共通の時間を見つけ、2 人にカレンダーの招待を 1 件送ります。どちらも、相手の空いている時間を見ることはありません。
sequenceDiagram
participant A as Anna's assistant
participant N as Neutra
participant B as Ben's assistant
A->>N: Anna's free times
N-->>A: a message for Anna to forward to Ben
Note over A,B: Anna forwards it in any chat
B->>N: Ben's free times + the code
N-->>A: calendar invite
N-->>B: calendar invite
異なるアシスタント間でも利用できます。Anna が Claude を使い、Ben が別のアシスタントを使っていても、両方が MCP コネクターに対応していれば動作します。Ben はアシスタントを使わずに回答することもできます。メッセージには、Google でサインインして空いている時間を追加できるシンプルなページへのリンクが含まれます。
プライバシーを設計に組み込む
- Neutra 側では AI を使いません。 Neutra は時間帯を比較するだけのシンプルなコードです。あなたの空いている時間が、Neutra の AI モデルに渡されることはありません。
- 誰も相手の空いている時間を見ることはありません。 返されるのは、両者に合う会議時間だけです。相手の空いている時間が返されることはなく、コードはハッシュとしてのみ保存されます。
- 時間は、決定が確定するとすぐに削除されます。 遅くとも 14 日後には削除されます。回答する人の空いている時間は、そもそも保存されません。
- 再試行しても、カレンダーの空き状況を探ることはできません。 回答する人が試せるのは最大 3 回です。また、各回答で指定する時間は、会議の長さの少なくとも 2 倍必要なため、空き時間を 1 つずつ探ることはできません。
- データは EU 内に留まります。 Cloudflare の EU 管轄内で処理されます。
- テストで確認済みです。
test/decisions.test.tsでは、どのレスポンスにも時間やコードが含まれないことを検証しています。
詳細:プライバシーページ。
試してみる
- Claude の場合:コネクタディレクトリで Neutra を開き、Connect を選択します。他のアシスタントの場合は、カスタムコネクターとして
https://neutra.day/mcpを追加します。 - Google でサインインします。Neutra が使用するのはあなたの名前とメールアドレスだけです。招待を正しい宛先に送信するためと、あなたのみが回答できるようにするためです。
- 次のように依頼します。「Neutra を使って、来週 Ben と 1 時間会う時間を見つけてください。火曜日と木曜日の 18:00~21:00 が空いています。」 返されたメッセージを転送します。
エージェントの開発者向け
Google サインインに対応したリモート MCP サーバーです。リソースはGoogle の AIP に準拠しています:decisions/{decision} と decisions/{decision}/answers/{answer}。
| ツール | 内容 |
|---|---|
create_decision | 持ち主の空いている時間と会議の長さを指定して、調整を開始します。コードと転送用のメッセージを返します。 |
create_answer | メッセージに記載されたコード(neutra:<id>.<code>)と、持ち主の空いている時間を指定して回答します。双方に合う時間が見つかると、招待が送信されます。 |
get_decision | ステータス(WAITING、NO_MATCH、INVITE_SENT、ACCEPTED、DECLINED、EXPIRED)と会議時間を取得します。 |
delete_decision | 開始した調整を、招待も含めてキャンセルします。 |
get_answer | 自分の回答を読み取ります。 |
create_feature_request | Neutra ではまだできないことで、持ち主が望んでいたことを Neutra の開発者に伝えます。 |
get_feature_request | 送信した機能リクエストを読み取ります。 |
価格の合意(デフォルトでは無効)
2人が、互いの上限を知らないまま、価格(家賃、売買価格、料金)に合意します。価格の合意は決定の一種です。開始者のアシスタントは、decision.price(件名、詳細、currencyCode、単位、answerBy)を指定してcreate_decisionを呼び出し、starterAnswer.priceには1つの数値を設定します。お金を受け取る側ならminimumToAccept、支払う側ならmaximumToPayを指定します。相手側はcreate_answerとanswer.priceを使って回答します。通貨は常に決定で指定されたものを使用します。支払う側の上限が受け取る側の最低額以上なら取引が成立し、そうでなければ両者には「取引不成立」とだけ通知されます。結果は両者にメールで届きます。
decision.price.ruleは、合意できる範囲内のどの価格で取引が成立するか、またその結果何が明らかになるかを指定します。
| ルール | 価格 | 取引成立時に明らかになること |
|---|---|---|
MIDPOINT(デフォルト) | 数値が重なる範囲の中央 | 双方が相手の数値を推測できます |
LOWEST | 受け取る側の最低額 | 支払う側にはその額が分かります。支払う側の数値は非公開のままです |
HIGHEST | 支払う側の上限額 | 受け取る側にはその額が分かります。受け取る側の数値は非公開のままです |
MIDPOINT_ROUNDED | 中央の値をroundToに丸めた額(デフォルトでは開始者の数値のおよそ1%)。重なる範囲内に収められます | 双方の数値がおおよそ分かるだけです |
RANDOM | 重なる範囲内から一様ランダムに選んだ値 | 相手の数値が価格を上回る、または下回ることだけが分かります |
OVERLAP_ONLY | なし。結果は「数値が重なっています」または「重なっていません」のみです(給与、初期選考など) | 何も分かりません。どちらの数値も明らかになりません |
decision.price.maxAnswers(1〜3、デフォルトは1)は、相手側が送信できる数値の回数です。取引が成立しなかった後も回答回数が残っていれば、相手側が再度回答できるようリクエストは開いたままになります。開始者には不成立だった試行の内容は一切表示されません。回答する人には、回答前にルールの平易な説明(ruleText)と回答可能回数が、引き継ぎメッセージ、プレビュー、ウェブページに表示されます。
- 回答する人の数値は、試行の間も含め、一切保存されません。開始者の数値は、リクエストコードから生成したキー(ハッシュのみ保存)で暗号化され、リクエストが解決または終了するとすぐに消去されます。
codeを指定したget_decisionは、回答する前にリクエストの内容を確認するためのpreviewを返します(yourSideがPAYSの場合はmaximumToPay、RECEIVESの場合はminimumToAcceptを送信します)。回答回数は消費されません。- 入出力は
neutra.v1メッセージ(proto3 JSON)に従います。すべての価格フィールドはpriceの中にあります。例:decision.price.agreedPriceText。 - 上限は範囲で指定することもできます。例:
"10000-20000"(下限のある支払い幅、上限のある価格)。両端が考慮されます。取引成立には双方の範囲が重なる必要があり、ルールに従って重なる範囲内の価格が選ばれます。単一の数値では反対側の端は開いたままです。内側の端は同じ側の端とのみ比較されるため、誇張しても得るものはありません。開始者の範囲の両端は封印され、回答する人の数値は一切保存されません。 - どちらの呼び出しでも
validateOnlyを指定すると、何も送信せず、本人が確認できるよう数値を返します。 - 1人あたり、1日に回答できる価格リクエストは最大3件です(1つのリクエストに対するすべての試行を1件として数えます)。
wrangler.jsoncのPRICE_DECISIONSで切り替えます。off(誰にも変更はありません)、testers(ALLOWED_EMAILSに含まれる人だけがcreate_decisionでdecision.priceを指定でき、コードを持つ人は誰でも回答できます)、またはopenです。docs/RUNBOOK.mdを参照してください。
エラーではgoogle.rpcコードを使用します。NOT_FOUND、PERMISSION_DENIED、FAILED_PRECONDITION、INVALID_ARGUMENT、RESOURCE_EXHAUSTED(1日または1時間あたりの上限に達した場合)。
Neutraの実行
Cloudflare WorkersとD1上で動作し、Cloudflareのremote-mcp-google-oauthテンプレートをベースにしています。mainへのプッシュごとに、GitHub Actions(.github/workflows/deploy.yml)が型チェック、テスト、デプロイを実行します。デプロイの前には毎回、migrations/内のマイグレーションが適用されます。変更はプルリクエストを通じて行います。
セットアップ(一度だけ実施)
Cloudflare
- アカウント ID と
MCP_RESOURCEアドレスはwrangler.jsoncにあります。ドメインneutra.dayは、Cloudflare ダッシュボードでカスタムドメインとして Worker に紐付けられています。 - API トークン:「Edit Cloudflare Workers」テンプレートに加えて D1: Edit を指定します。
- D1 データベース(EU 管轄)と
OAUTH_KV名前空間は、wrangler d1 create neutra --jurisdiction euとwrangler kv namespace create OAUTH_KVを使って一度作成済みです。それぞれの ID はwrangler.jsoncにあります。
Google Cloud(プロジェクト neutra)
- Google Auth Platform:対象ユーザーは External、公開ステータスは In production(テストモードでは更新トークンの有効期限が 7 日になります)。ブランディングには上記のホームページとプライバシーに関するリンクを設定し、承認済みドメインに
neutra.dayを指定します。 - リダイレクト URI が
https://neutra.day/callbackの Web クライアントを作成します。コネクタのサインインとブラウザーの回答ページの両方で使用します(新しい招待者キーを作成するときのみhttps://developers.google.com/oauthplaygroundを追加し、ローカル開発用にhttp://localhost:8788/callbackを追加します)。 - Google Calendar API と Gmail API を有効にします。
- サインインで求めるのはメールアドレスとプロフィールのみです。
ACCESS_MODEがallowlistの間は、ALLOWED_EMAILSに登録されたメールアドレスのみサインインできます。
招待者([email protected])
- OAuth 2.0 Playground で、Web クライアント独自の認証情報を使用して、
calendar.eventsとgmail.sendスコープを持つ更新トークンを取得します(手順はdocs/RUNBOOK.mdにあります)。
GitHub シークレット(Settings → Secrets and variables → Actions)
| シークレット | 内容 |
|---|---|
CLOUDFLARE_API_TOKEN | Cloudflare API トークン |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | Web クライアント |
COOKIE_ENCRYPTION_KEY | 任意の長いランダム文字列 |
ALLOWED_EMAILS | テストユーザーのメールアドレスをカンマ区切りで指定 |
INVITER_REFRESH_TOKEN | 招待者の更新トークン |
ローカル開発
npm install を実行し、.dev.vars.example を .dev.vars にコピーして値を設定したら、npm run dev を実行します。npx @modelcontextprotocol/inspector@latest で http://localhost:8788/mcp に接続してテストします。
ライセンス
MIT。詳細は LICENSE を参照してください。Cloudflare の MIT ライセンスのテンプレートに含まれるコードを使用しています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。