wealthi-coach-mcp-server
Read-only MCP server providing Wealthi's AI Coach with scoped access to student progress data from Firestore and Supabase, enabling AI to retrieve student profiles, progress, assessment results, and learning signals without direct database credentials.
README
wealthi-coach-mcp-server
Read-only MCP server giving Wealthi's AI Coach scoped access to student progress data, without the AI ever touching Firestore or Supabase directly.
Why this exists
Before this server, two clients wrote and read student data directly via SDK calls: the dashboard against Supabase, the mobile app against Firestore. Any AI feature built on top of that would need direct database credentials — which violates Wealthi's own AI philosophy ("AI should never receive unrestricted database access," "AI should not expose internal system data"). This server is the single, narrow, auditable path by which AI systems read student data. It does not replace the app's existing read/write paths for UI rendering; it exists specifically for AI consumption.
Domain ownership
| Domain | System of record | Read by |
|---|---|---|
| XP, streak, points, level | Firestore (users/{uid}) |
get_student_progress, get_coach_context |
| Quiz attempts | Firestore (users/{uid}/quizAttempts) |
get_assessment_results, get_curriculum_progress |
| Achievements | Firestore (users/{uid}/achievements) |
(reserved — not yet exposed; see Future Work) |
| Identity, grade band, parent link | Supabase profiles (project qsawrfybwwpgajefndnk) |
get_student_profile, get_coach_context |
| Coach seen-content tracker | Supabase profiles.routing_signals |
get_learning_signals, get_coach_context |
This split is intentional and permanent, not a migration waypoint. See project history for the full reasoning — short version: Firestore owns event-heavy gamification data because that's already its strength and mobile's home turf; Supabase owns identity/relational data because it needs joins and row-level security that Firestore doesn't offer.
Known infrastructure note: as of 2026-06, qsawrfybwwpgajefndnk is the
confirmed-correct Supabase project — verified directly against
wealthihome/.env's VITE_SUPABASE_URL, which is what the live app
actually uses. Wealthi has had multiple Supabase projects connected to the
same Lovable workspace with no "active" indicator in Lovable's panel
itself, so don't trust Lovable's panel alone to determine which project is
correct — always cross-check against the app's actual env var.
Read-only scope (by design, not just by convention)
This server never writes to Firestore or Supabase. All six tools carry
readOnlyHint: true / destructiveHint: false annotations, and the
service layer (src/services/) contains no write methods at all — there's
no update, set, or delete call anywhere in this codebase. Writes
continue to go through existing paths:
- Mobile's direct Firestore SDK writes (XP, streak, quiz submission)
- Dashboard's existing Supabase writes (profile updates, routing_signals)
- The dormancy-decay Edge Function (Supabase) for pattern-state decay
If a future use case needs the AI to act (e.g., "mark this content as seen" instead of just reading seen-content), that should be a deliberately designed, narrowly-scoped write tool added later with its own review — not an extension of this server's existing read tools, and not a broadening of its current credentials to writable ones.
Authentication & Credential Scoping
This server uses two separate, dedicated credentials, neither reused from any other Wealthi service. This matters because of a prior credential exposure incident — the fix isn't just rotating one key, it's making sure no future leak from this server compromises anything beyond what this server itself can read.
Firebase Admin (Firestore access)
- In the Firebase console for the project backing the mobile app, go to Project Settings → Service Accounts.
- Create a new service account specifically for this server — do not reuse the mobile app's or NestJS API's existing service account.
- Grant it the Cloud Datastore Viewer IAM role (Google Cloud Console
→ IAM, not the Firebase console) — this is a read-only role scoped to
Firestore/Datastore. Firestore has no separate "read-only Admin SDK
mode"; the restriction must be enforced at the IAM role level. Do not
grant
roles/datastore.userorroles/owner— both include write access. - Generate a private key (JSON) for this service account and populate
FIREBASE_PROJECT_ID,FIREBASE_CLIENT_EMAIL,FIREBASE_PRIVATE_KEYin.envfrom its contents. - Store the JSON file itself in a secrets manager (not in this repo, not
in plain
.envin any deployed environment) — inject the three env vars at deploy time instead.
Supabase (identity + routing_signals access)
- In the Supabase dashboard for project
qsawrfybwwpgajefndnk, go to Authentication → Policies and confirmprofileshas row-level security enabled (it should already, given existing app usage). - Create a dedicated Postgres role or use Supabase's API key management
to issue a key scoped to read-only
SELECTonprofilesonly — not theservice_rolekey used by the existing Edge Functions. If Supabase's built-in key types don't offer this granularity directly, create a custom Postgres role withGRANT SELECT ON profiles TO wealthi_coach_readonly;and authenticate via that role's credentials, rather than defaulting toservice_role. - Populate
SUPABASE_URLandSUPABASE_COACH_READONLY_KEYin.env.
Rotation discipline
Given the prior exposure incident: rotate both credentials on a fixed schedule (recommend quarterly), and immediately if this repo's CI/CD config, deployment logs, or any environment dump is ever suspected compromised. Because credentials are scoped narrowly and not shared with any other service, rotating them only requires redeploying this server — no coordination needed with the mobile app, dashboard, or NestJS API.
Repo location
This server lives in its own repo (wealthi-coach-mcp-server), separate
from wealthi-ai/wealthihome (dashboard) and the mobile app's repo. It is
not the "Wealthi Intelligence" Supabase project (a separate, unrelated
leads-generation database) — that naming collision was identified and
deliberately avoided when naming this repo. If "Wealthi Intelligence" or
"Wealthi System" comes up in conversation, confirm which of (a) this repo,
(b) the leads-gen Supabase project, or (c) the qsawrfybwwpgajefndnk
Supabase project is actually meant — they are three different things that
have been confused before.
Project structure
wealthi-coach-mcp-server/
├── package.json
├── tsconfig.json
├── .env.example
├── src/
│ ├── index.ts # entry point, transport selection
│ ├── types.ts # Coach-facing domain shapes
│ ├── constants.ts # collection/table names, limits
│ ├── tools/ # MCP tool contracts (thin)
│ │ ├── getStudentProfile.ts
│ │ ├── getStudentProgress.ts
│ │ ├── getAssessmentResults.ts
│ │ ├── getCurriculumProgress.ts
│ │ ├── getLearningSignals.ts
│ │ └── getCoachContext.ts
│ ├── services/ # DB clients + query/composition logic
│ │ ├── firebaseClient.ts
│ │ ├── supabaseClient.ts
│ │ ├── firestoreProgressService.ts
│ │ ├── supabaseProfileService.ts
│ │ ├── curriculumService.ts
│ │ └── learningSignalsService.ts
│ └── schemas/
│ └── studentInput.ts # shared Zod input schemas
└── dist/ # build output (gitignored)
Setup
npm install
cp .env.example .env # fill in real credentials, see above
npm run build
npm start # stdio mode by default
For HTTP mode (remote deployment):
TRANSPORT=http PORT=3000 npm start
Test with the MCP Inspector:
npm run inspect
How the AI Coach client calls this server
The AI Coach currently runs as a feature inside the dashboard
(AICoachCard, coachContent.ts). To call this server from that context,
add it as an MCP server in the Claude API request the Coach feature
already makes:
const response = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "claude-sonnet-4-6",
max_tokens: 1000,
messages: [
{
role: "user",
content: "Open a Coach session for this student and recommend what to show next."
}
],
mcp_servers: [
{
type: "url",
url: "https://<your-deployed-host>/mcp",
name: "wealthi-coach-mcp-server"
}
]
})
});
In practice, the Coach prompt should instruct the model to call
get_coach_context first, with the current student's ID, before
generating any response — that's the single round-trip that gives it
profile, progress, learning signals, and curriculum state together. The
finer-grained tools (get_student_profile, get_student_progress, etc.)
exist for cases where only one piece is needed, or for debugging which
specific data source is returning unexpected values.
The student ID passed to these tools should come from the authenticated session on the dashboard/mobile side, never from anything the AI itself infers or that a user can supply via chat — that's what keeps this a properly scoped, per-student tool rather than an open query surface.
Future work (not built yet)
getAssessmentResults-style achievement tool (Firestoreachievementscollection is in the domain table but not yet exposed as a tool — add when Coach actually needs to reference specific achievements).- Teacher/School platform tools, once those surfaces exist — they belong
in this same
tools/+services/structure, not a separate server. - If
dormancy-decayand other currently-dormant Edge Functions get reactivated (see open infra note: they're pointed at a different Supabase project,jatohkwzfdoxzevnxrfl, than the live app uses, and have 0 invocations to date),get_learning_signals's momentum derivation may want to read their output directly instead of recomputing a simpler heuristic here.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。