|
| 1 | +# ============================================================================= |
| 2 | +# MCP Toolbox for Databases — LOCAL config (AlloyDB Omni via docker-compose) |
| 3 | +# ============================================================================= |
| 4 | +# Why this file exists |
| 5 | +# -------------------- |
| 6 | +# `tools.yaml` (sibling file) targets cloud AlloyDB and uses SQL features that |
| 7 | +# do NOT exist in AlloyDB Omni: `kind: alloydb-postgres`, secret-manager |
| 8 | +# password lookup, `google_ml.embedding(...)`, and `hybrid_lore_search()`. |
| 9 | +# Trying to run the toolbox against Omni with that file fails immediately. |
| 10 | +# |
| 11 | +# This file is the Phase 4 dev counterpart: |
| 12 | +# 1. Source switched to `kind: postgres` pointing at the Omni container |
| 13 | +# (127.0.0.1:5432) with credentials sourced from the project `.env`. |
| 14 | +# 2. Queries rewritten against the v_* views in db/retrieval_views.sql: |
| 15 | +# v_character_dossier, v_active_debts, v_current_scene, |
| 16 | +# v_pending_missions, v_timeline |
| 17 | +# (plus a few direct table reads for things without a view). |
| 18 | +# 3. The two embedding-dependent tools are dropped here because Omni has no |
| 19 | +# `google_ml.embedding` function. A keyword-only `search-lore-keyword` |
| 20 | +# stands in so the Archivist toolset still has a search verb during |
| 21 | +# Phase 4 smoke tests; the real hybrid search returns in Phase 5. |
| 22 | +# |
| 23 | +# Run with |
| 24 | +# -------- |
| 25 | +# set -a && source .env && set +a |
| 26 | +# ./toolbox --tools_file mcp/alloydb_toolbox_config/tools.local.yaml |
| 27 | +# |
| 28 | +# Required env vars (already in .env.template): |
| 29 | +# ALLOYDB_HOST, ALLOYDB_PORT, ALLOYDB_DATABASE, |
| 30 | +# ALLOYDB_USER, ALLOYDB_PASSWORD |
| 31 | +# |
| 32 | +# DO NOT deploy this file to Cloud Run. It is dev-only. The cloud config |
| 33 | +# (`tools.yaml`) is the production source of truth for Phase 5–7. |
| 34 | +# ============================================================================= |
| 35 | + |
| 36 | +version: "1" |
| 37 | + |
| 38 | +sources: |
| 39 | + continental-db: |
| 40 | + kind: postgres |
| 41 | + host: ${ALLOYDB_HOST} |
| 42 | + port: ${ALLOYDB_PORT} |
| 43 | + database: ${ALLOYDB_DATABASE} |
| 44 | + user: ${ALLOYDB_USER} |
| 45 | + password: ${ALLOYDB_PASSWORD} |
| 46 | + |
| 47 | +tools: |
| 48 | + # ── Archivist ──────────────────────────────────────────────────────────── |
| 49 | + |
| 50 | + get-character: |
| 51 | + kind: postgres-sql |
| 52 | + source: continental-db |
| 53 | + description: > |
| 54 | + Full character dossier — faction, current location, reputation, |
| 55 | + traits, backstory, and last-seen day/phase. Matches on either the |
| 56 | + character's primary name or alias (case-insensitive). |
| 57 | + parameters: |
| 58 | + - name: name |
| 59 | + type: string |
| 60 | + description: "Character name or alias" |
| 61 | + statement: > |
| 62 | + SELECT * |
| 63 | + FROM v_character_dossier |
| 64 | + WHERE LOWER(name) = LOWER($1) |
| 65 | + OR LOWER(alias) = LOWER($1) |
| 66 | + LIMIT 1 |
| 67 | +
|
| 68 | + get-rules: |
| 69 | + kind: postgres-sql |
| 70 | + source: continental-db |
| 71 | + description: > |
| 72 | + Active hotel rules. Pass a rule_number to fetch one rule; |
| 73 | + omit the parameter to list every active rule in number order. |
| 74 | + parameters: |
| 75 | + - name: rule_number |
| 76 | + type: integer |
| 77 | + description: "Specific rule number (optional — omit to list all active rules)" |
| 78 | + statement: > |
| 79 | + SELECT rule_number, title, description, penalty, |
| 80 | + exceptions, source, added_day |
| 81 | + FROM hotel_rules |
| 82 | + WHERE is_active = true |
| 83 | + AND rule_number = COALESCE($1, rule_number) |
| 84 | + ORDER BY rule_number |
| 85 | +
|
| 86 | + get-faction: |
| 87 | + kind: postgres-sql |
| 88 | + source: continental-db |
| 89 | + description: "Faction details with the roster of characters tied to it." |
| 90 | + parameters: |
| 91 | + - name: faction_name |
| 92 | + type: string |
| 93 | + description: "Faction name" |
| 94 | + statement: > |
| 95 | + SELECT |
| 96 | + f.id, f.name, f.type, f.influence, f.territory, |
| 97 | + f.status, f.description, |
| 98 | + json_agg( |
| 99 | + json_build_object( |
| 100 | + 'name', c.name, |
| 101 | + 'alias', c.alias, |
| 102 | + 'status', c.status, |
| 103 | + 'reputation', c.reputation |
| 104 | + ) |
| 105 | + ) FILTER (WHERE c.id IS NOT NULL) AS members |
| 106 | + FROM factions f |
| 107 | + LEFT JOIN characters c ON c.faction_id = f.id |
| 108 | + WHERE LOWER(f.name) = LOWER($1) |
| 109 | + GROUP BY f.id, f.name, f.type, f.influence, |
| 110 | + f.territory, f.status, f.description |
| 111 | +
|
| 112 | + search-lore-keyword: |
| 113 | + kind: postgres-sql |
| 114 | + source: continental-db |
| 115 | + description: > |
| 116 | + Keyword-only lore search — local Phase 4 fallback because Omni has |
| 117 | + no `google_ml.embedding`. Matches title, content, and tags |
| 118 | + (case-insensitive). The cloud `search-lore` tool replaces this with |
| 119 | + a real hybrid (vector + RRF) search in Phase 5+. |
| 120 | + parameters: |
| 121 | + - name: query |
| 122 | + type: string |
| 123 | + description: "Search text" |
| 124 | + - name: limit |
| 125 | + type: integer |
| 126 | + description: "Maximum rows to return (default 5)" |
| 127 | + statement: > |
| 128 | + SELECT id, title, content, category, canon_level, tags |
| 129 | + FROM lore_chunks |
| 130 | + WHERE title ILIKE '%' || $1 || '%' |
| 131 | + OR content ILIKE '%' || $1 || '%' |
| 132 | + OR EXISTS ( |
| 133 | + SELECT 1 FROM unnest(tags) t |
| 134 | + WHERE t ILIKE '%' || $1 || '%' |
| 135 | + ) |
| 136 | + ORDER BY |
| 137 | + (CASE WHEN title ILIKE '%' || $1 || '%' THEN 2 ELSE 0 END) |
| 138 | + + (CASE WHEN EXISTS ( |
| 139 | + SELECT 1 FROM unnest(tags) t |
| 140 | + WHERE t ILIKE '%' || $1 || '%' |
| 141 | + ) THEN 1 ELSE 0 END) |
| 142 | + DESC, |
| 143 | + id DESC |
| 144 | + LIMIT COALESCE($2, 5) |
| 145 | +
|
| 146 | + # ── Ledger ─────────────────────────────────────────────────────────────── |
| 147 | + |
| 148 | + get-debts: |
| 149 | + kind: postgres-sql |
| 150 | + source: continental-db |
| 151 | + description: > |
| 152 | + Outstanding debts and markers involving a character — either side |
| 153 | + of the ledger. Ordered by value (highest stakes first). |
| 154 | + parameters: |
| 155 | + - name: character_name |
| 156 | + type: string |
| 157 | + description: "Character name (matches creditor or debtor)" |
| 158 | + statement: > |
| 159 | + SELECT * |
| 160 | + FROM v_active_debts |
| 161 | + WHERE LOWER(creditor_name) = LOWER($1) |
| 162 | + OR LOWER(debtor_name) = LOWER($1) |
| 163 | + ORDER BY value DESC |
| 164 | +
|
| 165 | + get-reputation: |
| 166 | + kind: postgres-sql |
| 167 | + source: continental-db |
| 168 | + description: "Reputation score, status and traits for one character." |
| 169 | + parameters: |
| 170 | + - name: character_name |
| 171 | + type: string |
| 172 | + description: "Character name or alias" |
| 173 | + statement: > |
| 174 | + SELECT name, alias, title, status, reputation, traits |
| 175 | + FROM characters |
| 176 | + WHERE LOWER(name) = LOWER($1) |
| 177 | + OR LOWER(alias) = LOWER($1) |
| 178 | +
|
| 179 | + # ── Timeline ───────────────────────────────────────────────────────────── |
| 180 | + |
| 181 | + get-schedule: |
| 182 | + kind: postgres-sql |
| 183 | + source: continental-db |
| 184 | + description: > |
| 185 | + Every event scheduled on a given story day, with participants and |
| 186 | + location. The view orders them by phase descending (latest first). |
| 187 | + parameters: |
| 188 | + - name: story_day |
| 189 | + type: integer |
| 190 | + description: "Story day number" |
| 191 | + statement: > |
| 192 | + SELECT * |
| 193 | + FROM v_timeline |
| 194 | + WHERE day = $1 |
| 195 | +
|
| 196 | + list-pending-missions: |
| 197 | + kind: postgres-sql |
| 198 | + source: continental-db |
| 199 | + description: > |
| 200 | + All pending or active missions, ordered by priority (5 = highest). |
| 201 | + Includes who requested the mission and who it is assigned to. |
| 202 | + statement: > |
| 203 | + SELECT * FROM v_pending_missions |
| 204 | +
|
| 205 | + who-is-where: |
| 206 | + kind: postgres-sql |
| 207 | + source: continental-db |
| 208 | + description: > |
| 209 | + Current scene snapshot — every location with active occupants and |
| 210 | + who is in it. Empty rooms are filtered out. |
| 211 | + statement: > |
| 212 | + SELECT location_id, location_name, location_type, district, |
| 213 | + is_continental, current_status, characters_present |
| 214 | + FROM v_current_scene |
| 215 | + WHERE characters_present IS NOT NULL |
| 216 | + ORDER BY location_name |
| 217 | +
|
| 218 | + # ── World clock ────────────────────────────────────────────────────────── |
| 219 | + |
| 220 | + get-world-clock: |
| 221 | + kind: postgres-sql |
| 222 | + source: continental-db |
| 223 | + description: > |
| 224 | + Current story day, phase, crisis level, hotel status, and any |
| 225 | + standing High Table edict. Use this to ground any agent response |
| 226 | + in the right temporal and geopolitical context. |
| 227 | + statement: > |
| 228 | + SELECT current_day, current_phase, crisis_level, crisis_name, |
| 229 | + high_table_edict, hotel_status, updated_at |
| 230 | + FROM story_state |
| 231 | + WHERE id = 1 |
| 232 | +
|
| 233 | +# ============================================================================= |
| 234 | +# Toolsets — kept intentionally parallel to tools.yaml so agent code that |
| 235 | +# binds to a toolset name (e.g. "archivist-tools") works with either config. |
| 236 | +# `smoke-test` is local-only and exists for Phase 4c MCP Inspector runs. |
| 237 | +# ============================================================================= |
| 238 | +toolsets: |
| 239 | + archivist-tools: |
| 240 | + - get-character |
| 241 | + - get-rules |
| 242 | + - get-faction |
| 243 | + - search-lore-keyword |
| 244 | + |
| 245 | + ledger-tools: |
| 246 | + - get-debts |
| 247 | + - get-reputation |
| 248 | + |
| 249 | + timeline-tools: |
| 250 | + - get-schedule |
| 251 | + - list-pending-missions |
| 252 | + - who-is-where |
| 253 | + - get-world-clock |
| 254 | + |
| 255 | + # Six-tool sampler for Phase 4c MCP Inspector smoke tests |
| 256 | + smoke-test: |
| 257 | + - get-world-clock |
| 258 | + - get-character |
| 259 | + - get-debts |
| 260 | + - get-schedule |
| 261 | + - who-is-where |
| 262 | + - search-lore-keyword |
0 commit comments