baatjie-mcp-server
This server provides a unified MCP interface to the Baatjie Group's tanOS (property OS, sales pipeline, sequencing) and sigscheCore (signal scheduler) systems, offering 16 tools across generic CRUD, task management, operational reporting, signal scheduling, and safety features.
Schema & Data Access:
baatjie_describe_schemalists tables and columns.baatjie_queryreads with filtering, sorting, pagination, and optional PII.baatjie_insert,baatjie_update, andbaatjie_deletehandle writes with audit logging; destructive actions require confirmations or filters.Task Sequencing & Action Planning:
baatjie_create_todo,baatjie_list_todos,baatjie_update_todomanage todos with dependencies, waves, tracks, and effort.baatjie_next_actionsidentifies startable tasks ranked by unblocking power.Operations & Sales:
baatjie_dashboardgives a table count snapshot and BDOP clock phase.baatjie_pipelineshows per-BRM outreach/demos/sales vs. 26/day target.baatjie_log_activityrecords BRM actions.baatjie_arrearslists overdue active leases with notice counts.Signal Scheduling (sigscheCore):
baatjie_signal_queuelists posts by brand/status/date.baatjie_schedule_signalqueues posts, recognizing angel windows (08:17, 11:11, 13:13, 22:22).baatjie_brand_snapshotshows platform readiness and content library depth.Safety & Compliance: PII is redacted by default except where explicitly allowed; all writes are audited; deletions require confirmation; unfiltered updates/deletes are refused; table access is allowlisted (24 tables) and non-destructive tools carry read-only hints.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@baatjie-mcp-serverWhat should I do next on the property plan?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
baatjie-mcp-server
An MCP server exposing the two Baatjie Group systems through one interface:
tanOS — property OS, sales pipeline, and the dependency-aware action plan
sigscheCore — multi-brand signal scheduler across 33 platforms
Sixteen tools: five generic CRUD tools covering every allowlisted table, and eleven workflow tools for the paths used daily.
Install
npm install
npm run build
cp .env.example .env # then fill in both service role keysRelated MCP server: fallpharm-mcp
Run
# stdio (local MCP clients — Claude Desktop, Claude Code)
npm start
# streamable HTTP
TRANSPORT=http PORT=3000 npm startClaude Desktop / Claude Code config
{
"mcpServers": {
"baatjie": {
"command": "node",
"args": ["/absolute/path/to/baatjie-mcp-server/dist/index.js"],
"env": {
"TANOS_URL": "https://tlhzwovsgjptifhnzcvh.supabase.co",
"TANOS_SERVICE_KEY": "...",
"SIGSCHE_URL": "https://bikmrclrpgxenncqodti.supabase.co",
"SIGSCHE_SERVICE_KEY": "..."
}
}
}
}⚠️ Read this before pointing it at production
Service role keys are required, and this is not a preference. RLS is enabled on
every table in both projects with zero policies defined. A non-privileged key
therefore returns empty result sets rather than errors — the server would cheerfully
report 0 agencies signed, 0 tenants, 0 todos as though those were the facts.
This was observed during testing, not theorised.
baatjie_dashboard warns when every table reads zero, since all-zero across nineteen
tables is far more likely to be a credentials problem than a genuinely empty group.
Treat that warning as a hard stop.
The same fact has a second consequence worth stating plainly: because there are no RLS policies, the service role key is the only thing standing between this server and every row in both databases — tenant ID numbers, passport numbers and permit status, landlord banking details, and the policy book. Until RLS policies exist, guard the key accordingly and keep the server local rather than exposed over HTTP.
Design notes
Personal data is withheld by default. Reads of tenants, foreign_nationals,
landlords and agents drop direct identifiers (ID numbers, passport numbers, phone,
email, banking details) unless include_pii: true is passed, and the response reports
which fields were withheld. Routine queries shouldn't pull identity numbers into an
agent's context as a side effect.
Every write is audited. Inserts, updates and deletes write a row to tanOS
audit_log with the actor you supply. Pass a meaningful actor (baatjie,
marius-ai, deon-ai) rather than the default. If the audit write fails, the response
says so rather than pretending it succeeded.
Destructive operations are guarded. baatjie_delete requires confirm: true.
Unfiltered updates and deletes are refused outright rather than rewriting a whole table.
Tools carry MCP annotations (readOnlyHint, destructiveHint, idempotentHint) so
calling agents can reason about consequences.
Table access is allowlisted. The generic CRUD tools reach only the nineteen tanOS
and five sigscheCore tables named in constants.ts. They are not an arbitrary-schema
backdoor.
Tools
Generic — comprehensive coverage
Tool | Purpose |
| List reachable tables per project. Start here when unsure. |
| Read any table: filters, column selection, ordering, pagination |
| Insert rows into any table |
| Update rows matching a filter |
| Delete rows — requires |
Sequencing — the dependency graph
Tool | Purpose |
| What is genuinely startable now, ranked by downstream unblock count |
| Full board with wave, track, effort, blockers |
| Add an item, optionally sequenced |
| Change status/sequencing; reports what the change unblocked |
baatjie_next_actions is the one to reach for on "what should I do next". A flat todo
list hides the fact that most items are blocked; this answers the question the list is
standing in for.
Operations
Tool | Purpose |
| Counts across every table, sales position, BDOP clock and 33/22 sprint block |
| Sales rollup per BRM against the 26/day objective |
| Record a BRM's outreach/demos/sales for a sprint block |
| Active leases with no recent payment, ranked, with notices already sent |
sigscheCore
Tool | Purpose |
| Scheduled, sent and failed posts |
| Queue a post; sets the angel-window label automatically |
| Per-brand readiness across platforms |
Angel windows (08:17, 11:11, 13:13, 22:22) are recognised automatically when scheduling. Times outside them are accepted; the label is simply null.
A note on notices
notices rows and the baatjie_arrears report describe real occupants. baatjie_arrears
is deliberately read-only — it reports the position and does not send anything, because
serving a notice should be a separate deliberate act.
South African arrears and eviction notices carry statutory requirements under the Rental
Housing Act and the PIE Act, and proof-of-service technicalities are exactly where cases
fail. Route wording and timing through the legal-exposure-check skill before anything
reaches an occupant rather than after.
Development
npm run dev # watch mode
npm run build # compile to dist/
node test-harness.mjs # protocol + guardrail checks (needs env vars set)
npm run test:rls # RLS isolation regression (needs TANOS_ANON_KEY too, see below)test-harness.mjs verifies initialisation, tool registration, annotation coverage,
description quality, the delete confirmation guard, unfiltered-write refusal, Zod range
validation, and actionable error text. All 13 checks should pass.
tests/rls-regression.mjs automates the P0.1 isolation check that was previously run by
hand: seeds two agencies and two real Supabase Auth users, confirms an unauthenticated
(anon) read returns empty rather than erroring, confirms agency A can read its own row,
and confirms agency A's cross-agency read/update/delete/insert against agency B's row
are all blocked — then tears every fixture down in a finally block regardless of
outcome. Needs TANOS_ANON_KEY in addition to the usual service key, since the whole
point is to test as a non-privileged client rather than the key that bypasses RLS.
Scoped to the 10 tables that actually carry account_id + policies today (landlords,
properties, rooms, tenants, foreign_nationals, leases, lease_agreements, payments,
maintenance, notices) — a live get_advisors check on 2026-08-11 found ten other
tables (agents, ai_agents, audit_log, brms, daily_activity, employers, locare_accounts,
member_consents, policies, todos) still have RLS enabled with zero policies. That's
default-deny, not a live hole, but there's no per-agency scoping on those tables yet
for a test like this one to exercise.
evaluations.xml contains ten questions for testing whether an LLM can actually use
this server to answer realistic operational questions.
Available Tools
16 toolsbaatjie_arrearsArrears ReportARead-onlyIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return (1-200, default 25) | |
| include_pii | No | ||
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
| min_days_overdue | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint, idempotentHint, destructiveHint), the description discloses that it reports position without sending anything, includes legal context for South African arrears/eviction notices, and explains how leases with no payment history are handled (never_paid rather than dropped).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: one-sentence purpose, read-only note, legal context, then arguments, returns, examples, and error handling in a clear format. Each section adds necessary information for correct invocation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description provides a detailed Returns structure and error handling for edge cases (never_paid). It also gives two concrete examples and notes that the tool is read-only, making the behavior clear for an AI agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides descriptions for limit and response_format, but not for min_days_overdue or include_pii. The description's Args section covers all four with meaningful semantics, including defaults and allowed values, compensating for the schema's gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Identify active leases with no recent payment, ranked by days since last payment, alongside how many notices have already been sent on each.' This clearly distinguishes it from generic query/scheduling/integration tools among its siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states 'Read-only' and explicitly says it does not send anything, contrasting with serving a notice which is a 'separate, deliberate act' with statutory requirements. It gives example queries for common use cases. However, it does not explicitly name alternative tools for sending notices or other actions, so it narrowly misses a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_brand_snapshotBrand Snapshot Across PlatformsARead-onlyIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| brand_id | No | ||
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral context: it is a read-only aggregate snapshot, clarifies that omitting brand_id returns a rollup of all brands, and documents the response structure. This goes beyond the annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and concise: a summary sentence, the key questions answered, a bulleted args section, a return structure code block, and examples. Every part adds value and is correctly front-loaded with the most important information. No fluff or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description provides a clear return structure, explains aggregation behavior, and gives practical examples. The combination of args, returns, and examples makes the tool self-contained and complete for an agent to select and invoke correctly. The tool's complexity is low (2 optional params), and the description fully covers it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description significantly enhances the brand_id parameter, explaining that omitting it returns a rollup across all brands, which is not in the schema. The response_format parameter is only described as 'Output format', though the schema already provides a fuller description with enum values and default. With 50% schema coverage, the description compensates for brand_id but could also add a bit more detail about response_format, so a 4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: providing per-brand status across sigscheCore with specific counts (queued, sent, library items, brand cards, platform registration). It also frames the purpose around concrete questions ('is this brand ready to broadcast' and 'where are we still unregistered'), which distinguishes it from sibling tools like baatjie_signal_queue or baatjie_dashboard.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly mentions the tool answers two key questions, giving clear context for when to use it. It also explains how to use the optional brand_id (omit for a rollup) and includes examples. However, it does not explicitly contrast with alternative tools or state when not to use it, though the questions provide strong implied guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_create_todoCreate a 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'
| Name | Required | Description | Default |
|---|---|---|---|
| wave | No | ||
| actor | No | Who is performing this write, recorded in tanOS audit_log (e.g. 'baatjie', 'marius-ai', 'deon-ai') | mcp |
| title | Yes | Short imperative summary | |
| track | No | ||
| detail | No | Context and definition of done | |
| effort | No | ||
| product | No | cross-cutting | |
| category | No | general | |
| priority | No | medium | |
| blocked_by | No | Todo ids that must be done first | |
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations mark readOnly=false and idempotent=false, which aligns with 'Add a todo'; no contradiction. The description adds an audit trail requirement (actor) and explicitly declares the return shape including audit_logged, going beyond the structured fields. It stops short of noting duplicate behavior or permissions, but the core side effects are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but structured with Args/Returns/Examples and front-loads the one-sentence purpose. Each section earns its place given 11 parameters, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Because there is no output schema, the Returns block is valuable and explicit. Combined with parameter semantics and two examples, the description fully equips an agent to invoke the tool for both simple and sequenced todos.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers only about 45% of parameters with descriptions, so the description carries the load; it explains every parameter, including enums and defaults for product, priority, track, and wave mappings (0=today, 1=root, etc.). The examples also clarify blocked_by usage. This adds substantial semantics beyond the JSON schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening line 'Add a todo to the tanOS action plan' names a concrete verb and target resource, and the sibling list (list_todos, update_todo) confirms this is the creation tool. The mention of 'optionally with sequencing metadata' further distinguishes it from a plain insert.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Examples show when to use simple 'Quick capture' versus a 'Sequenced item' with wave/track/blocked_by, providing useful context. It does not explicitly name alternatives or state when not to use this tool, but the create-vs-update distinction is clear from the sibling names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_dashboardBaatjie Group Operations SnapshotARead-onlyIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/no destructive flags, but the description adds valuable behavioral context beyond that: it explains the error-handling behavior (a table that cannot be counted returns null rather than failing the whole call) and highlights performance characteristics ('cheapest way'). This goes well beyond what annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections (main purpose, usage, Args, Returns, Examples, Error Handling). It is somewhat verbose due to the detailed Returns JSON, but that length is justified since there is no output schema. The opening sentence is front-loaded and immediately conveys the tool's purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity and lack of output schema, the description is remarkably complete: it explains the data returned, provides concrete examples, and covers error handling. The only minor gap is not defining terms like 'brms' or 'angel window', but these are context-specific and the overall description is sufficient for correct selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema fully documents the single parameter 'response_format' with enum and default, so schema coverage is 100%. The description essentially repeats the same information in the Args section and only implicitly adds that 'no args' uses the default. This does not meaningfully exceed the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool provides a comprehensive operational snapshot: row counts across all tanOS tables, sales position against the daily objective, and BDOP day status. This distinguishes it from sibling tools like baatjie_query or baatjie_schedule_signal by explicitly framing it as the single-call alternative to a dozen count queries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance on when to use the tool (start of a session or sprint, with examples like 'Where are we?') and notes it replaces about a dozen separate count queries. However, it does not explicitly name alternative tools to use when a more targeted query is needed, so it lacks full when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_deleteDelete RowsADestructiveIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| actor | No | Who is performing this write, recorded in tanOS audit_log (e.g. 'baatjie', 'marius-ai', 'deon-ai') | mcp |
| table | Yes | Target table | |
| confirm | No | Must be true to actually delete | |
| filters | No | Filters combined with AND. Example: [{"column":"status","op":"eq","value":"open"}] | |
| project | Yes | Which system: 'tanos' (property OS, pipeline, sequencing) or 'sigsche' (signal scheduler) | |
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reveals key behavioral traits beyond the annotations: irreversibility ('Permanently delete', 'Deletes are irreversible'), audit logging ('Recorded in tanOS audit_log'), and error handling ('confirm=false returns an explanation without deleting anything', 'Foreign key violations name the dependent rows'). These add significant context beyond the destructiveHint and idempotentHint annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a clear summary, usage rationale, argument list, return signature, and error handling sections. Every sentence serves a purpose, including the architectural guidance about append-only ledgers, and there is no redundant repetition of schema details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive tool with no output schema, the description is fully self-contained. It covers behavior, prerequisites, return format, error handling, and audit trail implications. It also provides enough context about the ledger design to help an agent decide between deletion and updates.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% parameter description coverage, so the baseline is high. The description adds valuable extra semantics: filters 'must be empty' (constraint not in schema) and confirm 'guards against accidental invocation' (provides rationale). This supplements rather than repeats the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: 'Permanently delete rows matching a filter.' It identifies the resource (rows), the operation (delete), and the scope (matching a filter). It also distinguishes itself from the sibling tool baatjie_update by explicitly recommending a status change over deletion when a schema has a status column.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use and when-not-to-use guidance. It says 'Prefer a status change (baatjie_update) over deletion wherever the schema has a status column' and gives the architectural rationale. It also states preconditions: 'Requires confirm=true and at least one filter.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_describe_schemaDescribe Baatjie Group SchemaARead-onlyIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| project | No | Which system: 'tanos' (property OS, pipeline, sequencing) or 'sigsche' (signal scheduler) | |
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds useful behavioral context, including the return structure, the effect of omitting 'project', and the explicit list of tables per project. However, the description says 'with row counts' but the shown return structure omits row counts, creating a minor inconsistency that prevents a perfect score.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured, with a concise opening sentence, clear usage guidance, an Args section, a Returns section, and a catalog of tables. Every section contributes directly to helping the agent use the tool correctly. The table lists are informative yet compact, and the format makes the information easily scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Because there is no output schema, the description carries the burden of explaining return values, and it does so by providing a detailed JSON structure. It also explains both projects and lists all expected tables, covering the tool's scope well. The only gap is the row-count discrepancy and the lack of any caveat about count accuracy, which leaves a small hole in an otherwise complete description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already documents both parameters with enums, defaults, and descriptions, achieving 100% schema coverage. The description adds value by clarifying that omitting 'project' describes both systems and by explaining the semantic difference between 'tanos' and 'sigsche'. This goes slightly beyond the schema, so a score above baseline is warranted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'List every table reachable through this server, with row counts and column names.' It also explicitly frames the tool as an orientation aid ('Call this first when you are unsure which table or column to use'), which distinguishes it from sibling tools that query, insert, update, or delete data. The verb+resource ('List tables') is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage guidance: 'Call this first when you are unsure which table or column to use. It is the cheapest way to orient before querying.' This tells the agent exactly when to invoke this tool and implies that it should be used before other data-access tools. Although it doesn't name alternatives, the context makes the intended usage clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_insertInsert RowsA
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
| Name | Required | Description | Default |
|---|---|---|---|
| rows | Yes | Rows to insert | |
| actor | No | Who is performing this write, recorded in tanOS audit_log (e.g. 'baatjie', 'marius-ai', 'deon-ai') | mcp |
| table | Yes | Target table | |
| project | Yes | Which system: 'tanos' (property OS, pipeline, sequencing) or 'sigsche' (signal scheduler) | |
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, etc.), the description discloses critical behaviors: every insert is recorded in tanOS audit_log with the actor, rows are limited to 1-100, and foreign key/CHECK constraint failures produce specific error messages. It also warns that writes to occupant-facing tables are flagged and that 'notices' rows carry statutory legal requirements. This is far richer than the annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections: purpose, Args, Returns, Examples, Note, and Error Handling. Every sentence earns its place—there is no filler or repetition of schema details. The most important purpose statement is front-loaded, and the legal warning is set off as a prominent note.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-parameter tool with no output schema, the description is remarkably complete. It provides the return shape, example payloads, error behavior, special-case warnings, and even guidance on legal compliance. This enables an agent to invoke the tool correctly without needing additional external context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% coverage, but the description adds substantial meaning: 'Omit columns with database defaults,' the 1-100 row limit, the default actor 'mcp,' and the project enum explanation ('tanos' vs 'sigsche'). The concrete examples show exactly how to structure rows for real use cases, which goes well beyond the schema's bare property definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Insert one or more rows into any table in tanOS or sigscheCore.' It clearly distinguishes itself from siblings like baatjie_update, baatjie_delete, and baatjie_query by focusing on adding new rows, not modifying or removing. The scope is explicit, naming the two systems and covering the core action.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context on when to insert rows, including examples like logging an agency and recording a payment. It does not explicitly name alternatives such as 'use baatjie_update to modify existing rows,' but the insert-vs-update distinction is strongly implied by the examples and the 'Insert' title. The legal caution for occupant-facing tables adds important usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_list_todosList Todos With SequencingARead-onlyIdempotent
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'
| Name | Required | Description | Default |
|---|---|---|---|
| wave | No | ||
| limit | No | Maximum rows to return (1-200, default 25) | |
| track | No | ||
| offset | No | Rows to skip, for pagination | |
| status | No | Filter by status; omit for all non-done | |
| priority | No | ||
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although the annotations already declare the tool read-only and idempotent, the description adds behavioral detail by stating the default status filter ('Omit to return everything except done'), pagination semantics, and the shape of the response. It doesn't contradict annotations and provides useful context beyond the structured metadata.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured into a summary, usage context, Args list, Returns shape, and Examples. Every section carries informative content without fluff. The formatting makes it easy to scan, and the examples are concise yet illustrative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite lacking an output schema, the description fully specifies the return structure ('total', 'count', 'offset', 'items', 'has_more', 'next_offset') and item fields. It also covers defaults, pagination, and response formats, making the tool usable without needing to probe the schema or guess behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description's Args block goes beyond the schema's raw enums by explaining wave meaning ('0=today, 1=roots, 2..4=later'), the default behavior of omitting status, and practical examples mapping natural language to parameter values (e.g., "Show the critical list" -> priority='critical'). With 57% schema coverage, this compensation is necessary and successful.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with a specific verb and resource: 'List todos with their wave, track, effort, blocker count and unblock count.' It clearly differentiates from the sibling tools like baatjie_next_actions by explaining what this tool covers (full board picture) versus the alternative. The examples further cement its purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool: 'Use this for a full picture of the board.' It also calls out a better alternative for a specific need: 'For "what do I do next", baatjie_next_actions is the better tool because it filters to what is actually actionable.' This is a clear, actionable usage guideline.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_log_activityLog BRM Sprint 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'
| Name | Required | Description | Default |
|---|---|---|---|
| actor | No | Who is performing this write, recorded in tanOS audit_log (e.g. 'baatjie', 'marius-ai', 'deon-ai') | mcp |
| demos | No | ||
| sales | No | ||
| brm_id | Yes | BRM identifier | |
| outreach | No | ||
| sprint_block | No | ||
| activity_date | No | ||
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With all annotations false, the description carries the transparency burden. It discloses that brm_id must exist in tanOS brms, that actor is recorded in the audit trail, that sprint_block defaults to the current 33/22 position from the clock, and that the return includes an audit_logged boolean. These details go beyond what schema/annotations provide, though it does not discuss overwrite or concurrency behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with an opening purpose, a concise Args list, a Returns shape, and practical examples. Every sentence adds value—there is no fluff, and the format is scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description provides the return object structure, usage examples, and contextual linkage to baatjie_pipeline. It does not explain nested fields of 'activity' or error handling, but for a logging tool with 8 parameters and no output schema, this level of detail is sufficient for an agent to use it effectively.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 38%, but the description compensates by explaining each parameter: outreach, demos, sales, sprint_block, activity_date, actor, response_format, and brm_id. It provides defaults, formats, and examples, making all 8 parameters meaningful beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Record a BRM's outreach, demos and sales for a 33/22 sprint block.' This is a specific verb+resource+scope statement. It clearly distinguishes the tool from siblings like baatjie_query or baatjie_pipeline by focusing on logging activity metrics.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states 'This is how the daily 26/day objective gets measured — unlogged work is invisible to baatjie_pipeline,' which tells the agent when to use this tool and its downstream effect. Examples (end of build block, backfill yesterday) illustrate common scenarios. However, it does not explicitly contrast with alternative logging tools like baatjie_insert.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_next_actionsWhat Can Actually Be Started NowARead-onlyIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return (1-200, default 25) | |
| track | No | Restrict to one workstream | |
| priority | No | Minimum priority to include | |
| include_blocked | No | Also return blocked items | |
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds valuable behavioral context beyond that: it explains ranking by how much each todo unblocks downstream, how blocked items are handled (included only if include_blocked=true), and the error behavior when all items are blocked (returns empty list with explanation). It also discloses the return structure in detail. There is no contradiction 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections: purpose, usage context, parameters, return structure, examples, and error handling. The opening sentence is concise and informative, front-loading the core purpose. While it is longer than minimal, every section earns its place and there is no redundant filler. The use of a JSON example for returns and example queries improves scannability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that there is no output schema, the description fully compensates by specifying the return structure with an example JSON object, including fields like startable, blocked_count, roots, and summary. It also covers error handling (empty startable list explanation) and provides practical examples for different use cases. Combined with the annotations and schema, the description leaves no significant gaps for an agent to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds meaningful semantics beyond the schema. For example, it expands the track enum values ('A = agency business, B = payroll housing rail, SPINE = shared infrastructure, TODAY = time-boxed launch-day items') and clarifies include_blocked as 'also list blocked items with their blocker counts' rather than just 'also return blocked items'. This additional context helps the agent select the correct parameter values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Return the todos that are genuinely startable right now — every blocker done — ranked by how much each one unblocks downstream.' This is a specific verb+resource with a distinct scope (startable todos) and a clear ranking behavior, which distinguishes it from a raw todo list. The title 'What Can Actually Be Started Now' reinforces the purpose. It effectively differentiates from sibling tools like baatjie_list_todos by emphasizing the filtering and ranking of startable items.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells users when to use this tool: 'This is the tool to reach for when asked "what should I do next", "what's the priority", or "what's blocking us"' and contrasts it with a 'raw todo list' that hides startability. While it identifies the alternative conceptually, it doesn't name the specific sibling tool (e.g., baatjie_list_todos), which would make the guidance more actionable. Examples also illustrate common use cases with specific arguments, but it doesn't explicitly state when not to use it beyond the raw list contrast.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_pipelineSales Pipeline by BRMARead-onlyIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return (1-200, default 25) | |
| since | No | Only count activity on or after this date | |
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, and non-destructive behavior. The description adds valuable behavioral context: BRMs with no logged activity are shown as zeros rather than omitted, and the output includes a comparison against a daily target of 26. This goes beyond what annotations provide, though it does not cover every edge case (e.g., timezone handling).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized with clear sections (main purpose, arguments, return structure, examples, error handling). It is concise, front-loaded, and every sentence adds value without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only aggregation tool with no output schema, the description is remarkably complete: it covers purpose, parameters, return format (with a detailed example structure), usage examples, and error handling. There are no obvious gaps that would prevent an AI agent from using it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes all three parameters with types, defaults, and descriptions, and the schema coverage is 100%. The description repeats the parameter basics but adds concrete examples (e.g., since='2026-08-03' for 'Activity this week'), which is helpful but not a significant addition beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's specific function: rolling up sales performance per Business Relationship Manager, including metrics like inherited book size, agencies signed, and logged activity. It also lists the questions it answers, distinguishing it from broader tools like the dashboard or query.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides example use cases (e.g., 'How's the pipeline?', 'Activity this week') and implies when to use it, but it does not explicitly discuss alternatives or when not to use it. The context is clear, but there are no exclusion statements.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_queryQuery Any Baatjie TableARead-onlyIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return (1-200, default 25) | |
| table | Yes | Table name (see allowlist) | |
| offset | No | Rows to skip, for pagination | |
| columns | No | Specific columns to return. Omit for all columns. Narrowing columns is the cheapest way to keep large result sets inside the response limit. | |
| filters | No | Filters combined with AND. Example: [{"column":"status","op":"eq","value":"open"}] | |
| project | Yes | Which system: 'tanos' (property OS, pipeline, sequencing) or 'sigsche' (signal scheduler) | |
| order_by | No | Column to sort by | |
| ascending | No | Sort ascending (default true) | |
| include_pii | No | Include direct personal identifiers (ID numbers, passport numbers, phone, email, banking details). Defaults to false so routine queries do not pull personal data unnecessarily. Set true only when the task genuinely needs it. | |
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint, idempotentHint, destructiveHint=false), the description discloses a non-obvious behavioral trait: personal identifiers are withheld unless include_pii is true, and the response reports which fields were redacted. It also describes error behavior (unknown table lists valid tables; column errors suggest baatjie_describe_schema), which is useful operational context not captured in structured metadata.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every section earns its place: a one-sentence purpose, explicit alternative guidance, a concise PII warning, structured Args and Returns, 3 practical examples, error handling notes, and a categorized table list. It is front-loaded with the core action, then organized with headers, making it easy to parse without wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 10 parameters, 2 projects, and many tables, the description covers all operational aspects: what it does, when to use it, how parameters map to examples, what the return structure looks like, how PII is redacted, and how errors are reported. The explicit Returns block compensates for the lack of an output schema, and the table allowlist removes ambiguity about valid values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides 100% parameter coverage, so the baseline is 3. The description adds value beyond the schema with real-world filter examples, a table allowlist, and clarifications like 'Narrowing columns is the cheapest way' and the full list of PII fields that include_pii controls. These enrich the schema descriptions meaningfully, though the schema already covers the mechanics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Read rows from any table in tanOS or sigscheCore', followed by a clear list of capabilities (filtering, column selection, ordering, pagination). It explicitly distinguishes itself from siblings by naming baatjie_next_actions and baatjie_dashboard as cheaper and better-shaped alternatives for specific use cases.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly positions itself as 'the general-purpose read' and tells the agent when NOT to use it: 'For sequencing work prefer baatjie_next_actions, and for the ops snapshot prefer baatjie_dashboard'. It also provides multiple concrete examples mapping natural-language intents to parameter values, giving clear guidance on how to invoke the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_schedule_signalSchedule a Signal PostA
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
| Name | Required | Description | Default |
|---|---|---|---|
| actor | No | Who is performing this write, recorded in tanOS audit_log (e.g. 'baatjie', 'marius-ai', 'deon-ai') | mcp |
| is_ad | No | ||
| media | No | ||
| caption | Yes | Post body | |
| user_id | Yes | Owning sigscheCore profile id | |
| brand_id | Yes | Brand key | |
| is_master | No | ||
| item_type | No | ||
| platforms | Yes | Target platforms | |
| brand_name | Yes | Brand display name | |
| scheduled_date | Yes | ||
| scheduled_time | Yes | ||
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (which only indicate non-read-only, non-idempotent, non-destructive), the description discloses the angel-window auto-labeling behavior, acceptance of non-window times, audit logging, return shape, and pre-write validation. This adds substantial behavioral context that annotations alone cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and uses clear sections (Args, Returns, Examples, Error Handling) that make scanning easy. It is slightly longer than necessary because the Args list largely mirrors the input schema, but every section contributes practical context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter write tool with no output schema, the description covers the key bases: parameter list, return shape, examples, and error cases. It lacks detail on the exact contents of the returned 'item' object and the semantics of is_master/item_type, but overall it is sufficiently complete for correct use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 54%, and the description compensates by documenting every parameter with concrete examples (e.g., brand_id 'locare', scheduled_time '13:13') and clarifying defaults for is_ad/is_master. It adds value beyond the schema, though some params like media and item_type remain terse.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Queue') and resource ('post or ad'), plus the distinguishing scope ('for broadcast across platforms, with angel-window awareness'). This clearly differentiates the tool from siblings like baatjie_signal_queue or generic baatjie_insert/update.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description strongly implies its use for scheduling post/ad broadcasts and includes illustrative examples, but it never explicitly contrasts with alternatives or states when not to use it. The primary use is clear, yet explicit when-vs-alternatives guidance is absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_signal_queueList the Signal QueueARead-onlyIdempotent
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'
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return (1-200, default 25) | |
| offset | No | Rows to skip, for pagination | |
| status | No | ||
| to_date | No | ||
| brand_id | No | ||
| from_date | No | ||
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavior: it enumerates the filterable states (scheduled, sent, failed), shows the pagination contract (limit/offset, has_more, next_offset), and explains response_format options. It also documents the exact return object shape, which is especially valuable given there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is efficiently structured: one purpose sentence, a compact Args list, a Returns outline, and three realistic examples. No content is wasted or redundant. The most critical information (what it lists) appears first, and the parameter/return/examples sections are easy to scan. It earns every line it uses.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with 7 optional parameters and no output schema, the description is quite complete. It documents all parameters, provides a return shape, and gives example mappings to natural-language intents. The only gap is explicit guidance on when to use this tool versus sibling list/dashboard tools, but the examples and purpose statement make its domain reasonably clear. Missing just a bit of 'when not to use' or alternative tool references.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 43%, but the description's explicit Args block compensates fully. It gives every parameter a name, type, optional/default indicator, and semantic meaning (e.g., 'from_date: YYYY-MM-DD, on or after'). It even clarifies response_format choices ('markdown' for human-readable, 'json' for machine-readable') and provides example parameter combinations. This goes well beyond the sparse schema entries for status, brand_id, and the dates.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'List scheduled, sent and failed posts in the sigcheCore broadcast queue.' This clearly distinguishes it from sibling tools like baatjie_schedule_signal (which likely creates queue entries) and baatjie_query (general-purpose querying). The title aligns with the description, making it unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied through three concrete examples ('What's queued today?', 'Anything failed?', 'locare's schedule') that map to parameter choices. However, the description does not explicitly state when to prefer this tool over siblings such as baatjie_dashboard or baatjie_query, nor does it mention when not to use it. This is adequate implied guidance but lacks explicit exclusions or alternative naming.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_updateUpdate RowsADestructiveIdempotent
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
| Name | Required | Description | Default |
|---|---|---|---|
| actor | No | Who is performing this write, recorded in tanOS audit_log (e.g. 'baatjie', 'marius-ai', 'deon-ai') | mcp |
| patch | Yes | Columns to set | |
| table | Yes | Target table | |
| filters | No | Filters combined with AND. Example: [{"column":"status","op":"eq","value":"open"}] | |
| project | Yes | Which system: 'tanos' (property OS, pipeline, sequencing) or 'sigsche' (signal scheduler) | |
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true, but the description adds substantial context: updates are 'Recorded in tanOS audit_log,' empty filters are rejected, and unknown columns are reported by name. This goes beyond the binary annotations to explain real behavioral safeguards.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with Summary, Args, Returns, Examples, and Error Handling sections, front-loaded with the core purpose. It is lengthier than minimal, but every section provides useful information relative to the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given nested filters, two systems, and no output schema, the description compensates by documenting the return format and error behaviors. It leaves no major gaps for invocation, though exact output semantics (e.g., 'affected' meaning) are left to the schema-less return description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema covers 100% of parameters, but the description adds value with examples of filter structures, a clarification that 'filters must not be empty,' and an explanation of the project enum. While the Args list largely repeats schema descriptions, the examples and additional constraints improve semantic clarity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Update rows matching a filter, in any table in either system,' which specifies the verb (update), resource (rows in any table), and scope (two systems). This differentiates it from specialized siblings like baatjie_update_todo, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly implies general-purpose use ('in any table in either system') and includes a critical safety guideline: 'an unfiltered update is refused rather than rewriting the whole table.' However, it does not explicitly name alternatives or when-not-to-use scenarios, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
baatjie_update_todoUpdate a TodoADestructiveIdempotent
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'
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Todo id | |
| wave | No | ||
| actor | No | Who is performing this write, recorded in tanOS audit_log (e.g. 'baatjie', 'marius-ai', 'deon-ai') | mcp |
| track | No | ||
| detail | No | ||
| effort | No | ||
| status | No | ||
| priority | No | ||
| blocked_by | No | ||
| response_format | No | Output format: 'markdown' for human-readable, 'json' for machine-readable | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses the automatic unblocking behavior and dependency graph recomputation, which goes beyond the annotations. It also clearly states that blocked_by replaces the existing blocker list. While destructiveHint is true, the description doesn't explicitly mention destructive aspects, but the provided context is valuable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a clear intro, Args list, Returns section, and examples. Every sentence contributes meaning, and the format is easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 10 parameters and no output schema, the description provides a detailed return shape and examples. It covers side effects (unblocking) and the audit trail, making the tool's behavior fully understandable. The absence of an output schema is compensated by the explicit Returns field.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With only 30% schema description coverage, the description compensates by listing all args with types and enriching key params like blocked_by ('Replaces the existing blocker list') and actor ('Who is writing, for the audit trail'). Some params like wave are merely listed without deeper meaning, but overall it adds significant value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states 'Change a todo's status or sequencing metadata by id,' which is a specific verb+resource+scope. It clearly distinguishes from sibling tools like baatjie_update (generic) and baatjie_create_todo by focusing on status/sequencing updates.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied through the description and examples ('Close an item', 'Re-sequence'), but there are no explicit alternatives or when-not-to-use conditions. The note about dependency graph recomputation hints at a workflow but doesn't name alternative tools.
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.
16 tool updates
v1.0.0- First observed
baatjie_arrears - First observed
baatjie_brand_snapshot - First observed
baatjie_create_todo - First observed
baatjie_dashboard - First observed
baatjie_delete - First observed
baatjie_describe_schema - First observed
baatjie_insert - First observed
baatjie_list_todos - First observed
baatjie_log_activity - First observed
baatjie_next_actions - First observed
baatjie_pipeline - First observed
baatjie_query - First observed
baatjie_schedule_signal - First observed
baatjie_signal_queue - First observed
baatjie_update - First observed
baatjie_update_todo
TDQS
Scored across 16 tools
Tools are mostly distinct: generic CRUD (query/insert/update/delete) is clearly separated from specialized reads like dashboard, pipeline, arrears, and signal_queue. A few overlaps exist (e.g., baatjie_query could be used for many read needs), but descriptions guide to the specialized tools, so confusion is minimal.
All tools share the 'baatjie_' prefix and mostly use snake_case with verb_noun patterns (schedule_signal, list_todos, create_todo, update_todo, log_activity). However, some are noun-only (dashboard, pipeline, arrears, signal_queue, brand_snapshot), which is a minor deviation from the otherwise consistent pattern.
With 16 tools, the server sits just above the ideal 3-15 range but feels justified given the two subsystems (tanOS and sigscheCore) and the combination of generic CRUD plus domain-specific reads/actions. The count is manageable and not bloated.
Generic CRUD tools (query/insert/update/delete) cover virtually all tables, while specialized tools like baatjie_next_actions, baatjie_pipeline, baatjie_arrears, and baatjie_signal_queue provide high-level views. Minor gaps like a specific cancel_signal or update_signal are covered by the generic update/delete, so there are no critical dead ends.
Maintenance
Related MCP Connectors
Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.
Guarded MCP server for agent-readable business truth, provenance, readiness, and discovery.
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Hosted MCP server for AI-driven data ops. Create apps, manage schemas, and CRUD structured data.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA production-grade MCP server designed for multi-tenant, authenticated, and observable AI agent systems, enabling secure tool execution across heterogeneous data sources.64MIT
- AlicenseNot gradedqualityCmaintenanceProvides a sovereign, MIT-licensed MCP server for professional-service workflows, running entirely on your infrastructure with Ed25519 cryptographic signing for every action.MIT
- AlicenseNot gradedqualityCmaintenanceA sovereign, MIT-licensed MCP server for professional-service workflow automation, enabling offline-capable, cryptographically signed operations without vendor lock-in.MIT
- FlicenseNot gradedqualityBmaintenanceA governed MCP server with OAuth 2.1 + PKCE, declarative tool scoping, row-level data filters, per-identity rate limits, and a tamper-evident audit trail.-