大家One 開発者向けドキュメント
いつもの AI チャットが、
そのまま管理画面になる
大家One はMCP サーバーとREST APIを公開しています。お使いの AI アシスタントを大家One につないでおけば、画面を開いてメニューをたどらなくても、話しかけるだけで物件のことがわかります。
「先月の滞納を教えて」
未入金の部屋と金額を、その場で一覧にして答えます。
「201号室の退去処理をして」
退去日を伝えるだけ。空室化と、以降の請求取り消しまで行います。
「今月の資金繰りは?」
日ごとの入出金予定と、手元残高がいちばん減る日を教えます。
実際にどんな答えが返るのかを、会話例で見たい場合はAI チャットから大家One を使うをご覧ください。滞納・空室・資金繰りの 3 例を、実際の回答の形で掲載しています。
そして大事なのはここです。入居者の氏名・電話番号・住所は、AI には一切渡りません。AI から見える入居者は「さくらハイツ 201号室さん」です。詳しくは「なぜ個人情報を AI に渡さずに済むのか」をご覧ください。
1. 何ができるか
公開しているのは、大家One の日々の運営データです。参照だけでなく、入金の記録や退去処理といった実際の操作まで AI 経由で行えます。
空室
- 部屋ごとの入居中/空室の別、空室になった日、空室日数
- 入居率サマリー(総戸数・入居戸数・空室戸数・入居率)
- 空室メモ(募集状況の覚え書き)の閲覧と更新
契約
- 契約の一覧・詳細(家賃・管理費・敷金・契約期間・契約状態)
- 家賃改定や契約期間延長などの条件更新
- 退去処理(退去日を指定すると空室化し、以降の請求が取り消される)
- 新規入居受付の開始(氏名の入力は AI ではなく大家ご本人がブラウザで行います)
請求・入金
- 月次の請求一覧(請求額・入金額・未収額・入金状態・滞納フラグ
is_overdue) - 入金の記録(入金日・金額・支払方法)
- 入金状態の一括切替(入金済にする/未入金に戻す)
運営コスト
- 修繕費・保険料・固定資産税・水道光熱費・管理組合費などの一覧
- コストの登録・編集(毎月/毎年の定期計上にも対応)
資金繰り
- 日繰り表(日ごとの入出金予定と手元現金残高の推移)
- 入出金予定の追加・編集・削除、実績化
- 手元現金残高の更新
- 預り金(敷金)サマリー
- 月別の収支集計(収入・支出・純収益・空室戸数)
資金繰り関連は、家族アカウントのfamily_memberロールで発行したトークンからは参照も操作もできません(ブラウザ画面での権限と揃えてあります)。
2. なぜ個人情報を AI に渡さずに済むのか
賃貸管理のデータには、氏名・電話番号・住所・生年月日・勤務先といった、外に出したくない情報が詰まっています。大家One の公開API と MCP は、それらを「マスクして返す」のではなく、そもそも取得経路を持たない設計にしています。
入居者は「201号室さん」として扱われる
AI から見た入居者は、氏名ではなく部屋のラベルです。物件名がわかる場合は物件名込みで"さくらハイツ 201号室さん"、物件名が取れない場合のみ"201号室さん"となります。誰の話をしているかは大家さんには一目でわかり、AI にとっては匿名のままです。
歴代の入居者の区別も、氏名ではなく契約のstatus(有効/退去予定/解約/満了)と、契約どうしをつなぐparent_contract_idのチェーンで行います。「前の入居者」を指すのに氏名は必要ありません。
3 層で守っています
- そもそも DB から読まない(コンパイル時ガード)
契約の参照は、氏名系の暗号化カラム(*_enc)を SELECT しない専用の読み取り関数(listContractsForPublicApi/getContractForPublicApi)を使います。レスポンスを組み立てる関数の入力型に個人情報のフィールドが存在しないため、「うっかり氏名を混ぜる」コードは型エラーになって書けません。復号関数を import することも禁止しています。 - 返す項目は許可リストで明示的に組み立てる
「これは除外する」という denylist 方式は、項目が増えたときに漏れます。大家One は逆に、返してよい項目だけを 1 つずつ書き並べて出力を作ります。DB に新しいカラムが増えても、自動的に外へ出ることはありません。 - 返す直前にもう一度検査する
すべてのレスポンスは、送出直前にassertNoPiiを通ります。*_encで終わるキーや、tenant_name/phone/address/guarantor/account_numberといった禁止キーが 1 つでも含まれていたら、レスポンスを返さずエラーにします。MCP 経由の場合は、委譲先の公開API と MCP 層で計 2 回この検査を通ります。
書き込む側も止めます
入居受付ドラフト作成(POST /move-in-drafts / start_move_in_draft)は、AI が気を利かせて氏名を送ってきても受け付けません。氏名・フリガナ・電話・メール・住所・生年月日・保証人・同居人・勤務先などを思わせるキーが含まれていると、422 PII_NOT_ALLOWEDで拒否します。
このときのエラーメッセージにはキー名しか載せません。値をそのまま返すと、拒否したはずの個人情報がエラーレスポンスやログに残ってしまうためです。
取得できないもの・取得できるもの
| 取得できないもの | 取得できるもの |
|---|---|
氏名・フリガナ/電話番号/メールアドレス/住所・郵便番号/生年月日/性別/緊急連絡先/保証人の情報/同居人の氏名/勤務先・収入/国籍/口座名義・口座番号/仲介担当者名/tenant_id そのもの | 物件名/部屋番号・階/契約の金額条件(家賃・管理費・敷金・礼金)/契約期間・支払方法・支払期日/num_occupants(同居人を含む人数のみ)/請求・入金・滞納/運営コスト/日繰り・預り金・月別収支 |
なお金額は一切マスクしていません。家賃も残高も実額で返ります。守っているのは「誰か」であって「いくらか」ではない、という割り切りです。
入居受付だけは個人情報をまたぎます — その渡し方
新しい入居者の登録だけは、どうしても氏名が要ります。ここは AI に氏名を渡さずに済むよう、署名付きの短命リンクを大家さんに手渡す方式にしています。
- AI が
start_move_in_draftを呼ぶ。渡すのは部屋ID・家賃・契約期間など、個人情報でない項目だけ。 - サーバーが
draft_id/url/expires_atを返す。 - AI はその URL を大家さんに案内する。大家さんが自分のブラウザで開いて氏名などを入力する。
URL は <サイトURL>/move-ins/new?draft=<署名付きトークン> の形で、有効期限は 30 分です。署名は HMAC-SHA256、署名対象に含まれるのはdraft_id / owner_id / exp の3 値だけで、個人情報は含まれません。改ざん検知のための署名であり、リンクを開いても中に氏名は入っていません。
3. 5分クイックスタート
トークンを発行し、クライアントに設定し、疎通を確認する。この 3 ステップです。
ステップ 1: アクセストークン(PAT)を発行する
トークンの発行は、大家One にログインして[設定]→[API連携]タブから行います。ここが唯一の発行経路です。トークン発行 API 自体はブラウザのセッション認証専用なので、PAT を使ってさらに PAT を発行することはできません(トークンが漏れても増殖しない設計です)。
発行画面では次を選びます。
- 有効期限: 無期限 / 30日 / 90日 / 180日 / 1年
- スコープ: そのトークンに許す操作の範囲(下表)。必要最小限を選んでください。
発行すると平文のトークンが表示されます。表示されるのは発行直後の 1 回だけで、あとから再表示はできません。サーバー側には bcrypt ハッシュしか残らないため、運営側でも復元できません。控え忘れたら、失効させて発行し直してください。
トークンの形式
ooya_pat_<lookup 12桁><secret 32桁> ← 全長 53 文字
例: ooya_pat_a1B2c3D4e5F6gHiJkLmNoPqRsTuVwXyZ0123456789ab先頭 ooya_pat_ は固定の目印、続く 12 桁は検索キー、残る 32 桁が秘密部分です。GitHub の ghp_ と同じ発想で、誤ってリポジトリに混入したときに grep で見つけられるようにしています。
スコープ一覧
| 参照系スコープ | 内容 |
|---|---|
| read:properties | 物件・部屋の参照 |
| read:vacancies | 空室状況・入居率の参照 |
| read:contracts | 契約の参照 |
| read:invoices | 請求・入金・滞納の参照 |
| read:costs | 運営コストの参照 |
| read:cashflow | 日繰り表・預り金の参照(family_member には発行できない) |
| read:timeline | 月別収支集計の参照 |
| 操作系スコープ | 内容 |
|---|---|
| write:invoices | 入金の記録・入金状態の切替 |
| write:costs | 運営コストの登録・編集 |
| write:cashflow | 日繰り予定の追加・編集・削除、残高更新 |
| write:vacancies | 空室メモの更新 |
| write:contracts | 契約条件の更新・退去処理 |
| write:move_in | 入居受付ドラフトの作成 |
まとめて指定したい場合は、ワイルドカードread:*(参照系すべて)とwrite:*(操作系すべて)も選べます。スコープが足りないエンドポイントを呼ぶと403 INSUFFICIENT_SCOPE が返ります。
発行者のロールもトークンに焼き込まれます。家族アカウントのfamily_memberロールで発行したトークンは参照専用で、さらに資金繰り系の 6 エンドポイントは実行時にも403 ROLE_FORBIDDENで遮断されます(read:cashflow はそもそも発行時に選べません)。
ステップ 2: クライアントを設定する
大家One の MCP サーバーはStreamable HTTP のみで提供しています(stdio 方式・SSE 方式には対応していません)。エンドポイントと認証は次のとおりです。
POST https://www.ooyaone.com/api/mcp
Authorization: Bearer ooya_pat_...
Content-Type: application/jsonリモート MCP に対応しているクライアントの場合
URL と HTTP ヘッダを指定できるクライアントであれば、次の形の設定で接続できます。設定ファイルの場所やキー名はクライアントごとに異なりますので、お使いの製品のドキュメントを必ずご確認ください。
{
"mcpServers": {
"ooya-one": {
"type": "http",
"url": "https://www.ooyaone.com/api/mcp",
"headers": {
"Authorization": "Bearer ooya_pat_あなたのトークン"
}
}
}
}リモート MCP に対応していないクライアントの場合
ローカルプロセス(stdio)しか起動できないクライアントでは、mcp-remote のようなブリッジを間に挟む形になります。ブリッジ側がリモートの Streamable HTTP エンドポイントへ中継します。
{
"mcpServers": {
"ooya-one": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://www.ooyaone.com/api/mcp",
"--header", "Authorization: Bearer ooya_pat_あなたのトークン"
]
}
}
}ご注意:上の 2 つの設定例は、大家One 側の実装事実(Streamable HTTP + Bearer 認証)から書き起こしたものです。特定のクライアント製品での動作を確認したものではありません。キー名・引数の形式はクライアントの仕様に合わせて読み替えてください。うまくつながらない場合は、まず次のステップ 3 の curl で疎通を切り分けると原因を絞り込めます。
ステップ 3: 動作を確認する
MCP は initialize / ping / tools/list もすべて PAT が必須です(未認証ではツール一覧すら取得できません)。まずはtools/list で 23 件返ってくるかを見るのが確実です。
curl -X POST https://www.ooyaone.com/api/mcp \
-H "Authorization: Bearer $OOYA_PAT" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'REST API 側の疎通は次のとおりです。
curl "https://www.ooyaone.com/api/public/v1/properties" \
-H "Authorization: Bearer $OOYA_PAT"
# => {"data":[{"id":"...","name":"さくらハイツ","room_count":8}]}401 が返る場合はトークンの綴り・失効・期限切れを確認してください。403 が返る場合は、レスポンスの code で原因を切り分けます。
INSUFFICIENT_SCOPE… そのエンドポイントに必要なスコープをトークンが持っていないROLE_FORBIDDEN…family_memberロールで資金繰り系を呼んだACCOUNT_SUSPENDED/ACCOUNT_CANCELLED/OWNER_SETUP_REQUIRED… アカウント側の状態が原因です。スコープの設定を見直しても解決しません
特に ACCOUNT_SUSPENDED(一時停止)と ACCOUNT_CANCELLED(退会済み)は、認証の直後・スコープ判定より前に検査されるため、スコープの内容にかかわらずすべてのエンドポイントが 403 になります。支払いの遅延などでアカウントが停止していないか、まず大家One にログインしてご確認ください。
4. MCP ツール リファレンス(23 ツール)
参照 11 ツール、操作 12 ツールの計 23 ツールです。公開API の 1 エンドポイントに MCP ツール 1 個が対応します。
サーバー情報
| 項目 | 値 |
|---|---|
| エンドポイント | POST https://www.ooyaone.com/api/mcp |
| トランスポート | Streamable HTTP のみ(stdio 非対応・SSE 非対応。GET / DELETE は 405) |
| 対応メソッド | initialize / ping / tools/list / tools/call(通知は受理して 202) |
| プロトコルバージョン | 2025-06-18 / 2025-03-26 / 2024-11-05 をネゴシエート |
| serverInfo | { name: "ooya-one", title: "大家One", version: "1.0.0" } |
| セッション | ステートレス。Mcp-Session-Id を発行しない |
| バッチ | JSON-RPC バッチ(配列)は非対応(400) |
サーバーが AI に伝えている利用指針
initialize の instructions として、次の内容をそのまま返しています。個人情報を渡さないよう、接続直後に AI へ明示するためのものです。
大家One(賃貸物件管理)の運営データを操作するツール群です。
物件・部屋・空室・契約・請求(家賃入金)・運営コスト・資金繰りを参照し、入金記録や退去処理などの日々の運営操作を行えます。
入居者は「201号室さん」のように部屋番号で表され、氏名・電話番号・住所などの個人情報はこのサーバーでは一切取得も更新もできません。
ユーザーから個人情報を含む依頼(氏名の登録・変更など)を受けた場合は、ツールに個人情報を渡さず、start_move_in_draft が返す入力リンクを案内するか、大家本人が画面で操作するよう伝えてください。
操作の前にまず一覧系ツール(list_properties / list_rooms / list_contracts / list_invoices)で対象の ID を特定してください。参照ツール(11)
| ツール名 | 用途 | 主な引数(* は必須) | 必要スコープ |
|---|---|---|---|
list_properties | 所有物件の一覧(物件ID・名称・総戸数) | — | read:properties |
list_rooms | 部屋の一覧(部屋番号・階・入居状況) | property_id | read:properties |
list_vacancies | 空室状況(空室になった日・空室日数・空室メモ) | property_id | read:vacancies |
get_occupancy | 入居率サマリー(総戸数・入居戸数・空室戸数・入居率) | property_id | read:vacancies |
list_contracts | 契約一覧(家賃・敷金・契約期間・契約状態・derived_state)※ページング対応。いま有効な契約は active_on で絞る | property_id / status / active_on / page / per_page | read:contracts |
get_contract | 契約 1 件の詳細 | contract_id* | read:contracts |
list_invoices | 請求・入金状況(未収額・入金状態・滞納フラグ)※ページング対応 | property_id / month / status / page / per_page | read:invoices |
list_costs | 運営コスト一覧(発生日・費目・金額・備考) | property_id / year | read:costs |
get_cashflow | 日繰り表(日次の入出金予定と手元現金残高の推移)※ family_member ロールの PAT では 403 | from / to / property_id | read:cashflow |
get_deposits | 預り金(敷金)サマリー※ family_member ロールの PAT では 403 | property_id | read:cashflow |
get_timeline | 月別の収支集計(収入・支出・純収益・空室戸数) | from / to / property_id | read:timeline |
操作ツール(12)
| ツール名 | 用途 | 主な引数(* は必須) | 必要スコープ |
|---|---|---|---|
record_payment | 請求に入金を 1 件記録する | invoice_id* / paid_at* / amount* / method* | write:invoices |
toggle_payment | 入金状態をまとめて切り替える(入金済 ⇄ 未入金) | invoice_id* / action* | write:invoices |
add_cost | 運営コストを 1 件登録する(定期計上にも対応) | property_id* / category* / amount* / incurred_on* / is_recurring / recurrence_interval / recurrence_end_date / memo | write:costs |
update_cost | 登録済み運営コストを編集する | cost_id* / category / amount / incurred_on / is_recurring / memo ほか | write:costs |
add_cashflow_entry | 日繰り表に入出金予定を 1 件追加する※ family_member ロールの PAT では 403 | date* / direction* / amount* / label* | write:cashflow |
update_cashflow_entry | 日繰り予定を編集する(is_actual=true で実績化)※ family_member ロールの PAT では 403 | entry_id* / date / direction / amount / label / is_actual | write:cashflow |
delete_cashflow_entry | 日繰り予定を削除する(取り消し不可)※ family_member ロールの PAT では 403 | entry_id* | write:cashflow |
update_current_balance | 現在の手元現金残高を更新する(基準日は自動で当日)※ family_member ロールの PAT では 403 | balance* | write:cashflow |
update_vacancy_memo | 空室メモ(募集状況の覚え書き)を更新する | room_id* / vacancy_memo* | write:vacancies |
move_out_contract | 契約を退去処理する(空室化+退去日以降の請求取消) | contract_id* / move_out_date* | write:contracts |
update_contract | 契約の金額条件・期間・支払方法を更新する | contract_id* / rent / management_fee / deposit / end_date / payment_method / payment_due_day / tenancy_type | write:contracts |
start_move_in_draft | 入居受付を開始し、大家本人が氏名を入力する短命リンクを発行する | room_id* / rent / management_fee / deposit / key_money / start_date / end_date / contract_date / tenancy_type / payment_method / payment_due_day | write:move_in |
ツール実行の結果と JSON-RPC エラー
tools/call が成功すると、公開API と同じ{ "data": ... }(ページングがある場合は meta 付き)を JSON 文字列にしたテキストが content に入り、isError: false になります。ツール実行時のエラーはisError: true のテキスト(エラー: メッセージ(code: CODE))として返り、JSON-RPC としては成功扱いです。
なお MCP 経由と REST 直叩きでは、レート制限の消費(tools/call は IP 枠を 2 消費)と 422 の返り方だけが異なります。認証・スコープ認可・ロールガード・PII 非送出ガードは同じコードを通ります。
一方、プロトコル層で失敗した場合は JSON-RPC エラーになります。独自コードは次のとおりです。
| JSON-RPC code | HTTP | 意味 |
|---|---|---|
-32001 | 401 | 認証エラー(PAT 不正・失効・期限切れ) |
-32002 | 429 | レート制限超過 |
-32003 | 503 | 基盤が利用できない(fail-closed) |
-32004 | 403 | 認可エラー(スコープ不足・ロール制限) |
5. REST API リファレンス(23 ルート)
MCP を使わず直接叩くこともできます。MCP ツールはこの REST 実装をそのまま内部で呼ぶため、認証・スコープ認可・ロールガード・PII 非送出ガードはまったく同じコードを通ります。ただしレート制限の消費とバリデーションエラーの返り方だけは差があります(後述)。
共通事項
| 項目 | 内容 |
|---|---|
| ベース URL | https://www.ooyaone.com/api/public/v1 |
| 認証 | Authorization: Bearer ooya_pat_...(MCP と同じ PAT) |
| 成功レスポンス | { "data": ... }。ページング対応ルートのみ { "data": [...], "meta": { total, page, per_page, total_pages } } |
| エラーレスポンス | { "error": "日本語メッセージ", "code": "CODE" } |
| オーナーの指定 | リクエストで owner_id / tenant_id を指定する余地はありません。対象は必ず PAT から解決されます |
| CORS | 既定で閉じています。PUBLIC_API_ALLOWED_ORIGINS に完全一致したオリジンにのみ許可(ワイルドカード不可・credentials 不可) |
ページネーション
ページングに対応しているのは /contracts と /invoices の 2 つだけです。それ以外のエンドポイントは全件を返し、meta も付きません。小規模(1〜3 棟・数十契約)を想定した割り切りです。
page: 1 始まり。既定は 1per_page: 既定 20、上限 100(範囲外は丸められます)
GET https://www.ooyaone.com/api/public/v1/invoices?month=2026-07&page=1&per_page=20
{
"data": [ ... ],
"meta": { "total": 42, "page": 1, "per_page": 20, "total_pages": 3 }
}レート制限
3 つの枠が同時に効きます。いずれも 1 分のウィンドウです。書き込み系は、トークン単位 60 req/min に加えて書き込み専用枠が追加で適用されます。
| 枠 | 既定値 | 適用対象 |
|---|---|---|
| トークン単位 | 60 req/min | 認証成功後、そのトークンのすべてのリクエスト |
| IP 単位 | 120 req/min | 認証前にチェック(総当たり・列挙対策) |
| 書き込み別枠 | 20 req/min | write: スコープを要求するルートに追加適用 |
超過時のレスポンスは次のとおりです。
HTTP/1.1 429 Too Many Requests
Retry-After: 37
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1784620800
{"error":"レート制限を超過しました","code":"RATE_LIMITED"}MCP 経由は IP 枠を 2 つ消費します(重要)
tools/call を 1 回実行すると、IP 単位の枠が 2 消費されます。MCP 層が委譲前に 1 回チェックし(未認証のまま有効なツール名や必須引数を列挙されるのを防ぐため)、委譲先の公開API が同じキーでもう 1 回チェックするためです。両者は同一のキー空間(クライアント IP + User-Agent のハッシュ)を使うので、MCP 経由の実効スループットは IP 枠の上では REST 直叩きの半分(既定 120 req/min → 実質 60 回/分の tools/call)になります。
トークン単位(60 req/min)と書き込み別枠(20 req/min)は二重に消費されません。また initialize / ping / tools/list は IP・トークンとも 1 回ずつの消費です。大量に呼び出す予定がある場合は、この差を見込んでください。
エラー形式
エラーは { "error", "code" } で統一しています。スキーマ検証(Zod)で弾かれた 422 の場合のみ、原因を特定できるようdetails に issue の配列が付きます。
HTTP/1.1 422 Unprocessable Entity
{
"error": "バリデーションエラー",
"code": "VALIDATION_ERROR",
"details": [
{
"code": "too_small",
"minimum": 1,
"path": ["amount"],
"message": "..."
}
]
}| HTTP | code | 発生条件 |
|---|---|---|
| 401 | (理由は区別しない) | Authorization 欠落・形式不正・トークン不一致・失効・期限切れ・発行元アクセスキー失効。列挙を防ぐためすべて同じ応答 |
| 403 | INSUFFICIENT_SCOPE | PAT がそのエンドポイントの必要スコープを持っていない |
| 403 | ROLE_FORBIDDEN | family_member ロールの PAT が資金繰り系エンドポイントを呼んだ |
| 403 | ACCOUNT_SUSPENDED | アカウントが一時停止中(支払い遅延など)。スコープに関係なく全エンドポイントが弾かれる |
| 403 | ACCOUNT_CANCELLED | アカウントが退会済み。スコープに関係なく全エンドポイントが弾かれる |
| 403 | OWNER_SETUP_REQUIRED | オーナー情報の初期設定が完了していない(通常フローでは発生しない) |
| 404 | NOT_FOUND | 指定 ID のリソースが存在しない(他オーナーのデータも 404 になる) |
| 409 | CONFLICT 系 | 状態が操作と矛盾する(例: 一部入金済みの請求に mark_paid) |
| 422 | VALIDATION_ERROR | Zod バリデーション違反・未知キー(.strict())。details に Zod issue が入る |
| 422 | PII_NOT_ALLOWED | POST /move-in-drafts に個人情報のキーが含まれていた |
| 429 | RATE_LIMITED | レート制限超過。Retry-After / X-RateLimit-* ヘッダを併せて返す |
| 503 | PUBLIC_API_UNAVAILABLE | レート制限基盤が未設定(fail-closed。制限なしで公開しない設計) |
正直に書いておきます:想定外の例外に起因する 500 は { "error": "サーバーエラーが発生しました" } のみで、code が付きません。クライアント側では code が常に存在する前提のコードを書かないでください。
MCP 経由では 422 の details が構造化されません
REST は details に issue の配列をそのまま返しますが、MCP 経由ではpath と message だけを抜き出した日本語テキストになり、配列としては返りません(先頭 10 件まで)。上の例と同じ状況なら、MCP では次のように届きます。
エラー: バリデーションエラー(amount: ...)(code: VALIDATION_ERROR)これは意図的な仕様です。issue の received / input にはクライアントが送った値そのものが入り得るため、そのまま返すと AI が誤って渡した氏名などがエラーメッセージ経由で外へ出てしまいます。項目名と理由だけなら AI が自己修正でき、かつ値は漏れません。
エンドポイント一覧
| メソッド | パス | 概要 | 必要スコープ | 対応 MCP ツール |
|---|---|---|---|---|
| GET | /properties | 物件一覧 | read:properties | list_properties |
| GET | /rooms | 部屋一覧 | read:properties | list_rooms |
| GET | /vacancies | 空室一覧 | read:vacancies | list_vacancies |
| GET | /occupancy | 入居率サマリー | read:vacancies | get_occupancy |
| GET | /contracts | 契約一覧※ ページング対応(meta あり) | read:contracts | list_contracts |
| GET | /contracts/{id} | 契約詳細 | read:contracts | get_contract |
| PATCH | /contracts/{id} | 契約条件の更新 | write:contracts | update_contract |
| POST | /contracts/{id}/move-out | 退去処理 | write:contracts | move_out_contract |
| GET | /invoices | 請求・入金一覧※ ページング対応(meta あり) | read:invoices | list_invoices |
| POST | /invoices/{id}/payments | 入金記録 | write:invoices | record_payment |
| POST | /invoices/{id}/payment-status | 入金状態の一括切替 | write:invoices | toggle_payment |
| GET | /costs | 運営コスト一覧 | read:costs | list_costs |
| POST | /costs | 運営コスト登録 | write:costs | add_cost |
| PATCH | /costs/{id} | 運営コスト編集 | write:costs | update_cost |
| GET | /cashflow | 日繰り表(資金繰り予測)※ family_member は 403 | read:cashflow | get_cashflow |
| POST | /cashflow/entries | 日繰り予定の追加※ family_member は 403 | write:cashflow | add_cashflow_entry |
| PATCH | /cashflow/entries/{id} | 日繰り予定の編集・実績化※ family_member は 403 | write:cashflow | update_cashflow_entry |
| DELETE | /cashflow/entries/{id} | 日繰り予定の削除※ family_member は 403 | write:cashflow | delete_cashflow_entry |
| PUT | /cashflow/current-balance | 手元現金残高の更新※ family_member は 403 | write:cashflow | update_current_balance |
| GET | /deposits | 預り金(敷金)サマリー※ family_member は 403 | read:cashflow | get_deposits |
| GET | /timeline | 月別収支集計 | read:timeline | get_timeline |
| PUT | /rooms/{id}/vacancy-memo | 空室メモの更新 | write:vacancies | update_vacancy_memo |
| POST | /move-in-drafts | 入居受付ドラフト作成(短命リンク発行) | write:move_in | start_move_in_draft |
パスはすべて https://www.ooyaone.com/api/public/v1 からの相対です。{id} は各リソースの UUID で、一覧系エンドポイントのレスポンスから取得します。
6. 設計思想の深掘り
なぜこの形にしたのか。実装を読む前提で、判断の理由を残しておきます。
PII 非送出は「フィルタ」ではなく「経路の不在」で担保する
個人情報の流出を防ぐ方法として真っ先に思いつくのは、レスポンス直前でマスクをかけることです。しかしその方式は「フィルタを書き忘れた新しいエンドポイント」で必ず破れます。
そこで大家One は、防御の重心を実行時から型システムに移しました。公開API 用の読み取り関数は氏名系カラムを SELECT せず、その戻り型を受け取るシリアライザは構造的に個人情報のフィールドを持ちません。氏名を返そうとするコードは、実行される前にコンパイルが通りません。
その上に、allowlist によるレスポンス構築(第 2 層)と、送出直前の assertNoPii(第 3 層)を重ねています。3 層とも独立していて、どれか 1 つが破れても他が止めます。
MCP は SDK を使わず、公開API へ内部委譲する
MCP サーバーの実装には SDK を使う選択肢もありましたが、採用しませんでした。理由は認証と PII ガードの地点を 1 つに保ちたかったからです。
大家One の MCP は独自の DB アクセスもビジネスロジックも持ちません。各ツールは、対応する公開API のルートハンドラを関数として直接呼びます(HTTP で自分自身を叩き直すことはしません)。その結果、PAT 認証・スコープ認可・レート制限・監査ログ・PII ガードは、MCP 経由でも REST 直叩きでもまったく同じコードを通ります。
SDK を挟むと、この「経路を増やさない」という性質を保つのが難しくなります。ツールが 23 個ある以上、認証を書き忘れる箇所が 23 個生まれる設計は避けたい、という判断です。
tools/call の前段だけは例外的に MCP 層で IP レート制限を先に通しています。ツール名の解決や引数の整形が無制限に実行できると、400 と 401 の応答差から有効なツール名や必須引数を列挙できてしまうためです。
ステートレス設計 — トークンを失効させたら次の 1 コールで効く
MCP サーバーは Mcp-Session-Id を発行しません。セッションを持たないので、すべてのリクエストが毎回フルの認証を通ります。
これは性能面では不利です(毎回 bcrypt が走ります)。それでも選んだのは、トークンを失効させた瞬間から、次の 1 コールで確実に遮断されるという性質を優先したからです。セッションをキャッシュすると、失効させたはずのトークンがセッションの生存期間だけ生き延びます。個人情報を扱うシステムで、その猶予は受け入れられないと考えました。
同じ理由で、トークンの失効・期限切れの判定は一切キャッシュせず毎回 DB を見ています。また、家族メンバーを除名してアクセスキーを失効させると、そのメンバーが発行済みの PAT も連鎖的に無効になります。
失敗するときは、開いたままにせず閉じる
レート制限の基盤(Redis)が設定されていない環境では、レート制限なしで公開API を動かすのではなく、503 を返します(PUBLIC_API_UNAVAILABLE)。「制限が効かないまま外に開いている」状態を作らないための fail-closed です。
認証エラーの理由を区別しないのも同じ考え方です。トークンが存在しないのか、期限切れなのか、失効済みなのかを返し分けると、それ自体が攻撃者への情報になります。すべて同じ401です。存在しないトークンでも、実在するトークンと同じだけの bcrypt 計算を行い、応答時間の差からトークンを推測されないようにしています。
7. 制約と既知の限界
できないこと、気をつけていただきたいことを、隠さず書いておきます。
自由記述欄の中身までは検査していません
assertNoPii が検査しているのはキー名だけで、値の中身は見ていません。したがって、大家さんご自身が
- 空室メモ(
vacancy_memo) - 運営コストの備考(
memo) - 日繰り予定の摘要(
label)
に入居者や関係者の氏名・連絡先を書き込んでいた場合、それはそのまま API/MCP のレスポンスに含まれて返ります。仕組みで防ぎきれない部分なので、自由記述欄には個人が特定できる情報を書かない運用をお願いします。各ツールの説明文でも AI に対して同じ注意を伝えています。
個人情報の登録・変更は API からはできません
氏名・連絡先・保証人・同居人などの登録と変更は、公開API にも MCP にも経路がありません。update_contract で変更できるのは金額条件・期間・支払方法などに限られ、氏名系を渡すと422 になります。これらの変更は、大家さんご本人がブラウザ画面で行ってください。
トークンの発行は API からはできません
PAT の発行はブラウザの設定画面からのみです。CI などから自動でトークンを発行・ローテーションする使い方はできません。
MCP のトランスポートは 1 種類だけです
Streamable HTTP のみで、stdio 直結にも SSE にも対応していません。GET / DELETE は 405 を返します。サーバー起点の通知(listChanged 等)も送りません。JSON-RPC のバッチ(配列)も未対応です。
ページングがあるのは 2 エンドポイントだけです
/contracts と /invoices 以外は全件を返します。件数が多い場合の分割取得はできません。
入居率は 0〜1 の比率です
get_occupancy / GET /occupancy が返す occupancy_rate は、入居戸数 ÷ 総戸数 で計算した 0〜1 の小数です(8 戸中 6 戸入居なら 0.75)。パーセント値ではないので、表示する際は 100 倍してください。総戸数が 0 のときは 0 を返します。
CORS は既定で閉じています
ブラウザから直接呼び出す用途は想定していません。許可オリジンを明示設定しない限り、フロントエンドの JavaScript からは呼べません。そもそも PAT をブラウザに置く運用は避けてください。
本ページの設定例は動作保証ではありません
クイックスタートに掲載した MCP クライアントの設定例は、大家One 側の実装(Streamable HTTP + Bearer 認証)から書き起こしたものであり、個別のクライアント製品での動作を検証したものではありません。接続がうまくいかない場合は、curl でサーバー側の疎通を確認したうえで、クライアント側の設定仕様をご確認ください。
AI に話しかけるだけの賃貸管理を、試してみませんか
API/MCP は大家One のすべてのプランでお使いいただけます。
まずは 30 日間の無料期間で、実際のデータをつないでお確かめください。
大家One の機能全体については機能紹介をご覧ください。