Skip to main content
Glama
wealthi-ai

wealthi-coach-mcp-server

Official
by wealthi-ai

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.

Related MCP server: OfficeRnD MCP Server

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)

  1. In the Firebase console for the project backing the mobile app, go to Project Settings → Service Accounts.

  2. Create a new service account specifically for this server — do not reuse the mobile app's or NestJS API's existing service account.

  3. 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.user or roles/owner — both include write access.

  4. Generate a private key (JSON) for this service account and populate FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, FIREBASE_PRIVATE_KEY in .env from its contents.

  5. Store the JSON file itself in a secrets manager (not in this repo, not in plain .env in any deployed environment) — inject the three env vars at deploy time instead.

Supabase (identity + routing_signals access)

  1. In the Supabase dashboard for project qsawrfybwwpgajefndnk, go to Authentication → Policies and confirm profiles has row-level security enabled (it should already, given existing app usage).

  2. Create a dedicated Postgres role or use Supabase's API key management to issue a key scoped to read-only SELECT on profiles only — not the service_role key used by the existing Edge Functions. If Supabase's built-in key types don't offer this granularity directly, create a custom Postgres role with GRANT SELECT ON profiles TO wealthi_coach_readonly; and authenticate via that role's credentials, rather than defaulting to service_role.

  3. Populate SUPABASE_URL and SUPABASE_COACH_READONLY_KEY in .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 (Firestore achievements collection 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-decay and 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.

Available Tools

6 tools
get_assessment_resultsGet Assessment ResultsA
Read-onlyIdempotent

Retrieve a student's recent quiz/assessment attempts, most recent first.

Reads from Firestore (users/{studentId}/quizAttempts). Paginated since this collection grows unbounded over a student's tenure — always check has_more.

Args:

  • student_id (string): The student's unique identifier.

  • limit (number): Max results to return, 1-50 (default 20).

  • cursor (string, optional): Pagination cursor from a previous call's next_cursor.

Returns: JSON object with schema: { "studentId": string, "results": [ { "attemptId": string, "topic": string, "score": number, // 0-100 "completedAt": string, // ISO 8601 "attemptNumber": number } ], "hasMore": boolean, "nextCursor": string // present only if hasMore is true }

Examples:

  • Use when: "How did this student do on their last few quizzes?" -> default limit

  • Use when: "Show me everything" -> paginate using next_cursor until has_more is false

Error Handling:

  • Returns an empty results array (not an error) if the student has no attempts yet.

ParametersJSON Schema
NameRequiredDescriptionDefault
student_idYesThe student's unique identifier (Firebase Auth UID / Supabase user_id — these are the same value across both systems).
limitNoMaximum number of assessment results to return (1-50, default 20).
cursorNoPagination cursor from a previous call's next_cursor field.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, idempotentHint=true. The description adds that it reads from Firestore, is paginated, and always check has_more. It also discloses error handling (empty array for no attempts). This significantly enriches the behavioral understanding beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections: main action, data source, pagination notes, args, returns, examples, and error handling. No fluff, every sentence adds value. Front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 3 parameters (1 required) and no output schema, the description provides a complete picture: data source, pagination mechanism, return schema, examples, and error handling. It covers all necessary context for an agent to use it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description's Args section repeats parameters but adds useful context: default for limit, optional cursor, and why cursor is used (pagination). It also includes a full return schema, which is not in the structured schema. This adds value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it retrieves a student's recent quiz/assessment attempts, sorted most recent first. The verb 'Retrieve' and resource 'quiz/assessment attempts' are specific, and it's distinct from sibling tools like get_student_progress or get_coach_context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides concrete examples of when to use ('How did this student do on their last few quizzes?') and how to paginate for full history. Does not explicitly mention when not to use, but the context is clear enough for an agent to decide.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_coach_contextGet Coach ContextA
Read-onlyIdempotent

Retrieve everything Coach needs to open a session with a student, in one call.

This is the primary entry point for AI Coach sessions — composes profile, progress, learning signals, and curriculum progress into a single object, so the Coach client doesn't need to know that two separate databases (Firestore and Supabase) are involved. Use the individual tools (get_student_profile, get_student_progress, get_learning_signals, get_curriculum_progress) only when you need just one piece, or for debugging a specific data source.

Args:

  • student_id (string): The student's unique identifier.

Returns: JSON object with schema: { "profile": { studentId, displayName, gradeBand, hasLinkedParent, enrolledAt }, "progress": { studentId, xp, level, streakCount, streakStatus, pointsBalance }, "signals": { studentId, momentumState, seenContentIds, daysSinceLastSession, recommendedInteractionType }, "curriculum": { studentId, topics: [...] } }

Examples:

  • Use when: "Start a Coach session for this student" -> call this first, every time, before generating any Coach response

  • Don't use when: you only need one field (e.g. just streak count) and want to minimize Firestore/Supabase reads -> use the specific tool instead

Error Handling:

  • Returns "Student not found" if get_student_profile finds no record. Progress/signals/curriculum default to safe empty states for new students who have a profile but haven't started any activity yet.

ParametersJSON Schema
NameRequiredDescriptionDefault
student_idYesThe student's unique identifier (Firebase Auth UID / Supabase user_id — these are the same value across both systems).

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true. The description adds behavioral context beyond annotations: it composes data from two databases, defaults to safe empty states for new students, and specifies error handling ('Student not found'). No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and concise: it starts with a clear summary, then sections for motivation, args, returns, examples, and error handling. Every sentence adds value with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple input schema (1 param), rich annotations, and detailed return schema documentation in the description, the tool definition is fully complete. Sibling tools are referenced, and context signals confirm high coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the description restates the parameter in the Args section without adding new meaning beyond the schema's description. Baseline score 3 is appropriate as the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Retrieve everything Coach needs to open a session with a student, in one call.' It specifies the verb, resource, and distinguishes itself from siblings by labeling it as the primary entry point and listing alternative tools for individual data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly provides usage guidance: 'Use when: Start a Coach session for this student' and 'Don't use when: you only need one field.' It names sibling tools as alternatives and gives examples, making it easy for the agent to decide.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_curriculum_progressGet Curriculum ProgressA
Read-onlyIdempotent

Retrieve a student's completion status across Wealthi's financial literacy topics (saving, budgeting, tradeoffs, delayed gratification, goal setting, decision making, financial confidence, future thinking, credit basics).

Derives completion from passing quiz attempts (score >= 70) grouped by topic and module, mapped against the same topic taxonomy used by Coach's content library (coachContent.ts) — so results align with what's shown in-app.

Args:

  • student_id (string): The student's unique identifier.

Returns: JSON object with schema: { "studentId": string, "topics": [ { "topicId": string, "topicLabel": string, "status": "not_started" | "in_progress" | "completed", "completedModules": number, "totalModules": number } ] }

Error Handling:

  • Always returns all 9 topics, even if the student hasn't started any (status will be "not_started" with completedModules: 0).

ParametersJSON Schema
NameRequiredDescriptionDefault
student_idYesThe student's unique identifier (Firebase Auth UID / Supabase user_id — these are the same value across both systems).

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond annotations: it explains the derivation logic (passing quiz scores >=70), grouping by topic/module, and guarantees it always returns all 9 topics even if unstarted. This complements the readOnlyHint and idempotentHint annotations without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured: it opens with a clear purpose, then explains derivation, parameters, return schema, and error handling. Every sentence adds value, and the length is appropriate for the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having no output schema, the description provides a complete return schema and explains guaranteed behavior (all topics returned). With good annotations and a simple parameter, the description fully enables correct agent invocation without gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter `student_id` is well-documented in the schema (100% coverage) with a detailed description of its format (Firebase Auth UID / Supabase user_id). The description's Args section merely repeats this, adding no new meaning, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool retrieves completion status across specific financial literacy topics, using a specific verb ('Retrieve') and resource ('student's completion status'). It implicitly distinguishes from siblings like `get_assessment_results` and `get_student_progress` by focusing on topic-level completion derived from quiz attempts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives like `get_student_progress` or `get_assessment_results`. The description does not provide when-to-use or when-not-to-use context, leaving the agent to infer usage from purpose alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_learning_signalsGet Learning SignalsA
Read-onlyIdempotent

Retrieve behavioral signals that inform what Coach should show a student next.

Composes data from two sources: Supabase (profiles.routing_signals, for already-seen content) and Firestore (last activity timestamp, for momentum). Returns translated behavioral labels only — never raw dormancy-decay scores or internal routing fields. This mirrors the translation Coach already does internally via behaviorLabels.ts.

Args:

  • student_id (string): The student's unique identifier.

Returns: JSON object with schema: { "studentId": string, "momentumState": "building" | "steady" | "dormant" | "returning", "seenContentIds": string[], // content already shown, for dedup "daysSinceLastSession": number, "recommendedInteractionType": "read" | "decide" | "reflect" }

Examples:

  • Use when: "What should Coach show this student right now?" -> check recommendedInteractionType and filter coachContent.ts by seenContentIds

  • Use when: deciding whether to show comeback/re-engagement copy -> check momentumState === "returning"

Error Handling:

  • A student with no activity history returns momentumState: "dormant" and daysSinceLastSession: 999 (sentinel for "never active"), not an error.

ParametersJSON Schema
NameRequiredDescriptionDefault
student_idYesThe student's unique identifier (Firebase Auth UID / Supabase user_id — these are the same value across both systems).

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=true and idempotentHint=true, but the description adds detail: it never returns raw internal fields, explains data sources (Supabase and Firestore), and documents error handling for inactive students (sentinel values). No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with paragraphs and bullet points for Args, Returns, Examples, and Error Handling. The first sentence clearly states purpose. Slightly verbose (Args redundant with schema), but overall efficient for the level of detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, the description provides a detailed output schema with types, examples, and error handling. Covers all scenarios (inactive student, sentinel values). Fully complete for a single-parameter tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single parameter student_id, with a clear explanation of its meaning. The tool description's Args section merely repeats the schema, adding no additional meaning, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it retrieves behavioral signals for Coach to decide what to show a student next. It specifies the verb 'retrieve' and resource 'learning signals', and distinguishes from sibling tools by focusing on behavioral signals for next action, not assessments or progress.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit examples of when to use this tool (e.g., 'What should Coach show this student right now?' and deciding on re-engagement copy). It also notes what it never returns (raw dormancy-decay scores), giving clear context. However, it does not explicitly name alternative tools for when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_student_profileGet Student ProfileA
Read-onlyIdempotent

Retrieve a student's basic identity and enrollment information.

This tool does NOT return parent contact details, raw assessment data, or any internal scoring/routing fields — only what's needed to personalize Coach's tone and respect age-appropriate framing.

Args:

  • student_id (string): The student's unique identifier.

Returns: JSON object with schema: { "studentId": string, "displayName": string, // safe display name only "gradeBand": "elementary" | "middle" | "high" | "young_adult", "hasLinkedParent": boolean, // presence only, never parent identity "enrolledAt": string // ISO 8601 date }

Error Handling:

  • Returns "Student not found" if no profile exists for the given student_id.

ParametersJSON Schema
NameRequiredDescriptionDefault
student_idYesThe student's unique identifier (Firebase Auth UID / Supabase user_id — these are the same value across both systems).

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and idempotentHint; the description adds context about excluding sensitive fields and error handling ('Student not found'), enhancing transparency without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Description is concise, front-loaded with purpose, followed by exclusions, param/returns/errors in a clear structure with no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple retrieval tool with no output schema, the description provides a complete return schema, error handling, and clear boundaries, making it adequately complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with a detailed schema description for student_id. The description adds minimal extra ('student's unique identifier'), meeting baseline for high coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states 'Retrieve a student's basic identity and enrollment information' with a specific verb and resource, clearly distinguishing from siblings like get_assessment_results by specifying what it returns and what it excludes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says what the tool does NOT return (parent contact, raw assessment data) and implies usage for personalizing coach tone, but does not name alternative tools for other purposes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_student_progressGet Student ProgressA
Read-onlyIdempotent

Retrieve a student's current XP, level, streak, and points balance.

Reads from Firestore (users/{studentId}), which is the system of record for gamification/progress data. Does NOT include quiz-level detail — use get_assessment_results for that.

Args:

  • student_id (string): The student's unique identifier.

Returns: JSON object with schema: { "studentId": string, "xp": number, "level": number, "streakCount": number, "streakStatus": "active" | "at_risk" | "broken", "pointsBalance": number }

Error Handling:

  • Returns "Student not found" if no Firestore user document exists for student_id.

ParametersJSON Schema
NameRequiredDescriptionDefault
student_idYesThe student's unique identifier (Firebase Auth UID / Supabase user_id — these are the same value across both systems).

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only, idempotent, non-destructive. The description adds valuable behavioral context: reads from Firestore, lists exact fields returned, specifies error handling ('Student not found'). This supplements the annotations well.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured with sections for Args, Returns, and Error Handling. It front-loads the main purpose. Slightly verbose with the full return schema, but overall concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite no output schema, the description provides a complete return type spec. It includes error handling and data source. Input schema is fully described. The tool is simple (1 param), and the description covers all necessary information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, providing a detailed description of student_id. The description's Args section repeats a truncated version of the schema description, adding no new meaning. Baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Retrieve a student's current XP, level, streak, and points balance.' It explicitly distinguishes from a sibling tool: 'Does NOT include quiz-level detail — use get_assessment_results for that.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: it reads from Firestore and is for gamification/progress data. It explicitly directs to an alternative for quiz detail. However, no explicit when-not-to-use beyond quiz-level.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedget_assessment_results
    • First observedget_coach_context
    • First observedget_curriculum_progress
    • First observedget_learning_signals
    • First observedget_student_profile
    • First observedget_student_progress

TDQS

A4.5/5.0

Scored across 6 tools

Disambiguation5/5

Each tool serves a distinct function: assessment results, composite coach context, curriculum progress, learning signals, student profile, and student progress. No overlap in purpose; descriptions clearly differentiate them.

Naming Consistency5/5

All tools follow the 'get_' prefix with descriptive noun phrases (e.g., get_student_profile, get_learning_signals). The naming pattern is perfectly consistent.

Tool Count5/5

Six tools cover the essential data retrieval needs for an AI coach session: profile, progress, curriculum, learning signals, assessment results, and a composite tool. This is a well-scoped set that doesn't feel too few or too many.

Completeness5/5

The tools provide comprehensive coverage of student data: identity, progress metrics, curriculum status, behavioral signals, and quiz results. The composite tool (get_coach_context) further enhances completeness by bundling the most commonly needed data in one call. No obvious gaps for the stated coaching purpose.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers