Skip to main content
Glama
dantalan

baatjie-mcp-server

by dantalan

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
PORTNoPort for HTTP transport.3000
TANOS_URLYesThe URL of the tanOS Supabase project.
TRANSPORTNoTransport mode: 'stdio' or 'http'.stdio
SIGSCHE_URLYesThe URL of the sigscheCore Supabase project.
TANOS_SERVICE_KEYYesThe service role key for tanOS.
SIGSCHE_SERVICE_KEYYesThe service role key for sigscheCore.

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
baatjie_describe_schemaA

List every table reachable through this server, with row counts and column names.

Call this first when you are unsure which table or column to use. It is the cheapest way to orient before querying.

Args:

  • project ('tanos' | 'sigsche' | omit for both): Which system to describe

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: { "projects": { "tanos": { "tables": [{ "name": string, "columns": string[] }] }, "sigsche": { "tables": [...] } } }

tanOS tables: Property: landlords, properties, rooms, tenants, foreign_nationals, leases, lease_agreements, payments, maintenance, notices Commercial: locare_accounts, brms, agents, employers, policies, daily_activity Internal: todos, ai_agents, audit_log

sigscheCore tables: profiles, queue_items, library_items, brand_cards, registration_status

baatjie_queryA

Read rows from any table in tanOS or sigscheCore, with filtering, column selection, ordering and pagination.

This is the general-purpose read. For sequencing work prefer baatjie_next_actions, and for the ops snapshot prefer baatjie_dashboard — both are cheaper and better shaped.

Personal identifiers (ID numbers, passport numbers, phone, email, banking details) are withheld unless include_pii is true, and the response reports which fields were withheld.

Args:

  • project ('tanos' | 'sigsche'): Which system

  • table (string): Table name — must be in the allowlist

  • columns (string[], optional): Specific columns; omit for all

  • filters (Filter[]): AND-combined filters

  • order_by (string, optional): Column to sort on

  • ascending (boolean): Sort direction (default: true)

  • limit (number): Max rows, 1-200 (default: 25)

  • offset (number): Rows to skip (default: 0)

  • include_pii (boolean): Include personal identifiers (default: false)

  • response_format ('markdown' | 'json'): Output format

Returns: { "total": number, "count": number, "offset": number, "items": object[], "has_more": boolean, "next_offset"?: number, "redacted_fields": string[] }

Examples:

  • "Which todos are still open?" -> project='tanos', table='todos', filters=[{"column":"status","op":"neq","value":"done"}]

  • "Show agencies signed this month" -> table='locare_accounts', filters=[{"column":"signed_date","op":"gte","value":"2026-08-01"}]

  • "Biggest BRM books" -> table='brms', order_by='inherited_book_size', ascending=false

Error Handling:

  • "Unknown table" lists the valid table names for that project

  • Column errors suggest calling baatjie_describe_schema

tanOS tables: Property: landlords, properties, rooms, tenants, foreign_nationals, leases, lease_agreements, payments, maintenance, notices Commercial: locare_accounts, brms, agents, employers, policies, daily_activity Internal: todos, ai_agents, audit_log

sigscheCore tables: profiles, queue_items, library_items, brand_cards, registration_status

baatjie_insertA

Insert one or more rows into any table in tanOS or sigscheCore. Every insert is recorded in tanOS audit_log with the actor you supply.

Args:

  • project ('tanos' | 'sigsche'): Which system

  • table (string): Target table

  • rows (object[]): Rows to insert, 1-100. Omit columns with database defaults.

  • actor (string): Who is writing, for the audit trail (default: 'mcp')

  • response_format ('markdown' | 'json'): Output format

Returns: { "ok": true, "table": string, "action": "insert", "affected": number, "rows": object[], "audit_logged": boolean, "note"?: string }

Examples:

  • Log a signed agency -> table='locare_accounts', rows=[{"agency_name":"Cape Letting","brm_id":"...","tier":"Growth","status":"active"}]

  • Record a payment -> table='payments', rows=[{"lease_id":"...","amount":3400,"payment_date":"2026-08-08","method":"payroll"}]

Note: writes to occupant-facing tables (tenants, leases, notices, payments) are flagged in the response, because a row there corresponds to a real person's tenancy or money. A 'notices' row in particular represents a notice served on an occupant — South African arrears and eviction notices carry statutory requirements, so route the wording through your legal-exposure-check skill before sending rather than after.

Error Handling:

  • Foreign key failures name the missing parent record

  • CHECK constraint failures point at columns with restricted values

baatjie_updateA

Update rows matching a filter, in any table in either system. At least one filter is required — an unfiltered update is refused rather than rewriting the whole table. Recorded in tanOS audit_log.

Args:

  • project ('tanos' | 'sigsche'): Which system

  • table (string): Target table

  • patch (object): Columns and new values

  • filters (Filter[]): Which rows to change — must not be empty

  • actor (string): Who is writing, for the audit trail

  • response_format ('markdown' | 'json'): Output format

Returns: { "ok": true, "table": string, "action": "update", "affected": number, "rows": object[], "audit_logged": boolean }

Examples:

  • Mark a todo done -> table='todos', patch={"status":"done"}, filters=[{"column":"id","op":"eq","value":""}]

  • Close a maintenance ticket -> table='maintenance', patch={"status":"resolved","resolved_at":"2026-08-08T12:00:00Z"}, filters=[{"column":"ticket_id","op":"eq","value":""}]

Error Handling:

  • Empty filters are rejected with an explanation

  • Unknown columns in the patch are reported by name

baatjie_deleteA

Permanently delete rows matching a filter. Requires confirm=true and at least one filter. Recorded in tanOS audit_log.

Deletes are irreversible and there is no soft-delete on these tables. Prefer a status change (baatjie_update) over deletion wherever the schema has a status column — the ledger is append-only by design, and payment corrections belong as compensating rows rather than deletions.

Args:

  • project ('tanos' | 'sigsche'): Which system

  • table (string): Target table

  • filters (Filter[]): Which rows to delete — must not be empty

  • confirm (boolean): Must be true; guards against accidental invocation

  • actor (string): Who is deleting, for the audit trail

  • response_format ('markdown' | 'json'): Output format

Returns: { "ok": true, "table": string, "action": "delete", "affected": number, "audit_logged": boolean }

Error Handling:

  • confirm=false returns an explanation without deleting anything

  • Foreign key violations name the dependent rows blocking the delete

baatjie_next_actionsA

Return the todos that are genuinely startable right now — every blocker done — ranked by how much each one unblocks downstream.

This is the tool to reach for when asked "what should I do next", "what's the priority", or "what's blocking us". A raw todo list hides the fact that most items cannot be started; this one answers the question the list is standing in for.

Args:

  • track ('A' | 'B' | 'SPINE' | 'TODAY', optional): Restrict to one workstream. A = agency business, B = payroll housing rail, SPINE = shared infrastructure, TODAY = time-boxed launch-day items

  • priority ('critical' | 'high' | 'medium' | 'low', optional): Minimum priority

  • include_blocked (boolean): Also list blocked items with their blocker counts (default: false)

  • limit (number): Max items (default: 25)

  • response_format ('markdown' | 'json'): Output format

Returns: { "startable": [{ "id","title","priority","track","wave","effort","unblocks" }], "blocked_count": number, "roots": [...], // startable items that unblock the most "summary": { "total","startable","blocked","by_priority": {...} } }

Examples:

  • "What should I work on?" -> no args

  • "What's next on the housing rail?" -> track='B'

  • "Show me everything including what's stuck" -> include_blocked=true

Error Handling:

  • Returns an empty startable list with an explanation if every open item is blocked, which itself signals the roots need attention first

baatjie_list_todosA

List todos with their wave, track, effort, blocker count and unblock count.

Use this for a full picture of the board. For "what do I do next", baatjie_next_actions is the better tool because it filters to what is actually actionable.

Args:

  • status ('open' | 'in_progress' | 'done' | 'blocked', optional): Filter by status. Omit to return everything except done.

  • track ('A' | 'B' | 'SPINE' | 'TODAY', optional): Filter by workstream

  • wave (number, optional): Filter by wave (0=today, 1=roots, 2..4=later)

  • priority ('critical' | 'high' | 'medium' | 'low', optional): Filter by priority

  • limit (number): Max items (default: 25)

  • offset (number): Pagination offset (default: 0)

  • response_format ('markdown' | 'json'): Output format

Returns: { "total","count","offset","items":[...],"has_more","next_offset"? } where each item carries id, title, priority, status, wave, track, effort, open_blockers, startable and unblocks.

Examples:

  • "Show the critical list" -> priority='critical'

  • "What's in wave 1?" -> wave=1

  • "Everything on the housing rail" -> track='B'

baatjie_create_todoA

Add a todo to the tanOS action plan, optionally with sequencing metadata.

Args:

  • title (string): Short imperative summary

  • detail (string, optional): Context, why it matters, what "done" looks like

  • category (string): Grouping label, e.g. 'security', 'legal', 'pricing' (default: 'general')

  • product (string): 'locare' | 'tanos' | 'sigschecore' | 'brand' | 'cross-cutting' (default: 'cross-cutting')

  • priority ('critical' | 'high' | 'medium' | 'low'): Default 'medium'

  • wave (number, optional): 0=today, 1=root, 2=near, 3=downstream, 4=later

  • track ('A' | 'B' | 'SPINE' | 'TODAY', optional): Which workstream owns it

  • blocked_by (string[], optional): Todo ids that must complete first

  • effort (string, optional): Rough size, e.g. '1 hour', '2-3 days'

  • actor (string): Who is creating it, for the audit trail

  • response_format ('markdown' | 'json'): Output format

Returns: { "ok": true, "todo": { "id","title",... }, "audit_logged": boolean }

Examples:

  • Quick capture -> title='Confirm iKhokha reversal path', priority='high'

  • Sequenced item -> title='Load the policy book', wave=2, track='SPINE', blocked_by=[''], effort='1 day'

baatjie_update_todoA

Change a todo's status or sequencing metadata by id.

Marking an item done automatically unblocks anything that listed it in blocked_by — the dependency graph is recomputed on read, so the next call to baatjie_next_actions will surface newly available work.

Args:

  • id (string, uuid): Todo id

  • status ('open' | 'in_progress' | 'done' | 'blocked', optional)

  • priority ('critical' | 'high' | 'medium' | 'low', optional)

  • wave (number, optional)

  • track ('A' | 'B' | 'SPINE' | 'TODAY', optional)

  • blocked_by (string[], optional): Replaces the existing blocker list

  • effort (string, optional)

  • detail (string, optional)

  • actor (string): Who is writing, for the audit trail

  • response_format ('markdown' | 'json'): Output format

Returns: { "ok": true, "todo": {...}, "newly_unblocked": [{ "id","title" }], "audit_logged": boolean }

Examples:

  • Close an item -> id='', status='done'

  • Re-sequence -> id='', wave=1, track='SPINE'

baatjie_dashboardA

One call for the whole operational picture: row counts across every tanOS table, the sales position against the 26/day objective, and where the clock sits in the BDOP day (phase, 33/22 sprint block, next angel window).

This is the cheapest way to orient at the start of a session or a sprint. It replaces roughly a dozen separate count queries.

Args:

  • response_format ('markdown' | 'json'): Output format (default: 'markdown')

Returns: { "counts": { "": number | null }, "sales": { "accounts_signed": number, "daily_target": 26, "brms": number, "agent_pool": number, "employer_pool": number, "inherited_book": number }, "property": { "landlords","properties","rooms","tenants","leases", "payments","notices","maintenance" }, "clock": { "phase","sprint","block","minutes_left","next_angel_window" } }

Examples:

  • "Where are we?" / "Status?" -> no args

  • Start of a Factory sprint -> no args, read the clock block

Error Handling:

  • A table that cannot be counted returns null for that entry rather than failing the whole call

baatjie_pipelineA

Roll up sales performance per Business Relationship Manager: inherited book size, agencies signed, and logged outreach/demo/sale activity.

Answers "who is performing", "where is the pipeline", and "are we hitting 26/day".

Args:

  • since (string, optional): ISO date (YYYY-MM-DD). Restrict activity to on/after this date.

  • limit (number): Max BRMs to return (default: 25)

  • response_format ('markdown' | 'json'): Output format

Returns: { "brms": [{ "brm_id","inherited_book_size","accounts_signed", "outreach","demos","sales" }], "totals": { "accounts_signed","outreach","demos","sales","brm_count" }, "against_target": { "daily_target": 26, "signed_today": number, "gap": number } }

Examples:

  • "How's the pipeline?" -> no args

  • "Activity this week" -> since='2026-08-03'

Error Handling:

  • BRMs with no logged activity appear with zeros rather than being omitted, so silence is visible rather than hidden

baatjie_log_activityA

Record a BRM's outreach, demos and sales for a 33/22 sprint block. This is how the daily 26/day objective gets measured — unlogged work is invisible to baatjie_pipeline.

Args:

  • brm_id (string): BRM identifier, must exist in tanOS brms

  • outreach (number): Contacts made in this block (default: 0)

  • demos (number): Demos booked or run (default: 0)

  • sales (number): Agencies signed (default: 0)

  • sprint_block (string, optional): Which block, e.g. 'sprint-3-build'. Defaults to the current 33/22 position from the clock.

  • activity_date (string, optional): YYYY-MM-DD, defaults to today

  • actor (string): Who is logging, for the audit trail

  • response_format ('markdown' | 'json'): Output format

Returns: { "ok": true, "activity": {...}, "clock": {...}, "audit_logged": boolean }

Examples:

  • End of a build block -> brm_id='marius-ai', outreach=12, demos=3

  • Backfill yesterday -> brm_id='...', sales=1, activity_date='2026-08-07'

baatjie_arrearsA

Identify active leases with no recent payment, ranked by days since last payment, alongside how many notices have already been sent on each.

Read-only. It reports the position; it does not send anything. Serving a notice is a separate, deliberate act — in South Africa arrears and eviction notices carry statutory requirements under the Rental Housing Act and PIE Act, so wording and timing should be checked before anything reaches an occupant.

Args:

  • min_days_overdue (number): Only leases with no payment in at least this many days (default: 1)

  • limit (number): Max leases (default: 25)

  • include_pii (boolean): Include tenant identifiers (default: false)

  • response_format ('markdown' | 'json'): Output format

Returns: { "leases": [{ "lease_id","room_id","rent_due_day","status", "last_payment_date","days_since_payment","total_paid","notices_sent" }], "summary": { "active_leases","in_arrears","never_paid","total_notices_sent" } }

Examples:

  • "Who's behind on rent?" -> no args

  • "Anyone more than 30 days down?" -> min_days_overdue=30

Error Handling:

  • Leases with no payment history report last_payment_date=null and are counted under never_paid rather than being silently dropped

baatjie_signal_queueA

List scheduled, sent and failed posts in the sigscheCore broadcast queue, optionally filtered by brand, status or date.

Args:

  • brand_id (string, optional): Restrict to one brand

  • status ('scheduled' | 'sent' | 'failed', optional): Filter by state

  • from_date (string, optional): YYYY-MM-DD, on or after

  • to_date (string, optional): YYYY-MM-DD, on or before

  • limit (number): Max items (default: 25)

  • offset (number): Pagination offset (default: 0)

  • response_format ('markdown' | 'json'): Output format

Returns: { "total","count","offset","items":[{ "id","brand_name","scheduled_date", "scheduled_time","angel_label","platforms","status","caption","is_ad" }], "has_more","next_offset"? }

Examples:

  • "What's queued today?" -> from_date='2026-08-08', to_date='2026-08-08'

  • "Anything failed?" -> status='failed'

  • "locare's schedule" -> brand_id='locare'

baatjie_schedule_signalA

Queue a post or ad for broadcast across platforms, with angel-window awareness.

If the scheduled time matches one of the reserved windows (08:17, 11:11, 13:13, 22:22) the angel label is set automatically and reported back. Times outside those windows are accepted without complaint — the label is simply null.

Args:

  • brand_id (string): Brand key, e.g. 'locare', 'dantalan'

  • brand_name (string): Display name

  • caption (string): Post body

  • platforms (string[]): Target platforms, e.g. ['linkedin','x','instagram']

  • scheduled_date (string): YYYY-MM-DD

  • scheduled_time (string): HH:MM (24h)

  • is_ad (boolean): Whether this is a paid ad (default: false)

  • is_master (boolean): Master/primary signal for the slot (default: false)

  • media (string, optional): Media URL or reference

  • item_type (string, optional): Free-form classification

  • user_id (string, uuid): Owning sigscheCore profile id

  • actor (string): Who is scheduling, for the audit trail

  • response_format ('markdown' | 'json'): Output format

Returns: { "ok": true, "item": {...}, "angel_label": string | null, "audit_logged": boolean }

Examples:

  • Launch post -> brand_id='locare', scheduled_date='2026-08-08', scheduled_time='13:13', platforms=['linkedin','x']

  • Evening story -> scheduled_time='22:22', platforms=['instagram']

Error Handling:

  • Invalid time format is rejected before the write

  • A user_id with no matching profile returns a foreign key explanation

baatjie_brand_snapshotA

Per-brand status across sigscheCore: platform registration progress, queued and sent counts, library depth and how many brand cards exist.

Answers "is this brand ready to broadcast" and "where are we still unregistered".

Args:

  • brand_id (string, optional): One brand; omit to roll up every brand present

  • response_format ('markdown' | 'json'): Output format

Returns: { "brands": [{ "brand_id","queued","sent","failed","library_items", "brand_cards","platforms_registered","platforms_pending" }], "totals": { "brands","queued","sent","registered" } }

Examples:

  • "Is locare ready to post?" -> brand_id='locare'

  • "Which brands still need registration?" -> no args

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dantalan/baatjie-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server