Skip to main content
Glama
Billy MCP Server

Billy MCP Server

by markhm

Billy MCP Server

A Model Context Protocol (MCP) server for integrating with Billy's accounting system. This server provides tools to interact with Billy's REST API for managing invoices, contacts, products, payments, and other accounting data.

Features

  • Contact Management: Create, read, update, and list contacts

  • Invoice Management: Create, read, and list invoices with line items

  • Product Management: Create, read, and list products with pricing

  • Payment Processing: Create payments to mark invoices as paid

  • Bill Management: List and manage vendor bills

  • Account Management: Access chart of accounts

  • Organization Info: Get organization details

Related MCP server: Cuéntica MCP

Prerequisites

  • Node.js 26 or higher (.node-version and mise.toml pin it)

  • Billy account with API access

  • Billy API access token

Installation

  1. Clone or download the server code

  2. Install dependencies:

    npm install
  3. Build the TypeScript code:

    npm run build

Configuration

Getting a Billy API Token

  1. Log into your Billy account at app.billysbilling.com

  2. Go to Settings → Access tokens

  3. Create a new access token, giving it a descriptive name (e.g. mcp-server)

  4. Copy the token — see below for where to put it

Two things worth knowing: Billy tokens are permanent (they never expire) and unscoped (there is no read-only token — see Read-only by default). Naming the token is what lets you revoke this integration later without disturbing your other ones.

Where to put your access token

Pick one of these. If more than one is present, real environment variables win over .env, so an MCP client's env block is never shadowed by a stale file.

1. A .env file (easiest for local use)

cp .env.example .env
# then edit .env and set BILLY_ACCESS_TOKEN=...

The server reads .env from the package folder only, so this works wherever your MCP client launches it from. It deliberately ignores a .env in the working directory: an untrusted project could otherwise redirect your token or switch writes on. .env is gitignored.

2. Your MCP client's config (the usual choice for day-to-day use)

Put it in the env block of claude_desktop_config.json (see below). Nothing else on the machine needs the token, and it travels with the client config.

3. Exported in your shell (ad hoc / CI)

export BILLY_ACCESS_TOKEN="your_billy_access_token_here"

Variable

Required

Purpose

BILLY_ACCESS_TOKEN

yes

Billy API access token

BILLY_ORGANIZATION_ID

no

Sent as organizationId on create calls. Billy tokens are organisation-scoped, so this is normally inferred — set it only if the API rejects a create for a missing organization.

BILLY_ALLOW_WRITES

no

Set to true to enable the 9 mutating tools. Off by default — see below. Even then every write dry-runs unless called with dryRun: false.

BILLY_API_BASE_URL

no

Overrides the API base URL (defaults to https://api.billysbilling.com/v2).

MCP Client Configuration

Add the server to your MCP client configuration. For Claude Desktop, add this to your claude_desktop_config.json:

{
  "mcpServers": {
    "billy": {
      "command": "node",
      "args": ["/path/to/billy-mcp-server/build/index.js"],
      "env": {
        "BILLY_ACCESS_TOKEN": "your_billy_access_token_here"
      }
    }
  }
}

Available Tools

Organization

  • billy_get_organization - Get organization details

Contacts

  • billy_list_contacts - List contacts with optional filtering

  • billy_get_contact - Get a specific contact by ID

  • billy_create_contact - Create a new contact

  • billy_update_contact - Update an existing contact

Invoices

  • billy_list_invoices - List invoices with optional filtering

  • billy_get_invoice - Get a specific invoice by ID

  • billy_create_invoice - Create a new invoice with line items

  • billy_update_invoice - Update an existing invoice

Products

  • billy_list_products - List products with optional filtering

  • billy_get_product - Get a specific product by ID

  • billy_create_product - Create a new product with pricing

Payments

  • billy_list_bank_payments - List bank payments

  • billy_create_payment - Create a payment to mark invoices as paid

Bills

  • billy_list_bills - List vendor bills

  • billy_create_bill - Create a vendor bill

Accounts

  • billy_list_accounts - List chart of accounts

  • billy_list_account_groups - List chart-of-accounts groups

VAT and ledger

  • billy_list_sales_tax_returns - Billy's own VAT returns (momsangivelser) — the authoritative figures

  • billy_get_sales_tax_return - Get a single VAT return by ID

  • billy_list_postings - Ledger postings, where VAT actually lands

  • billy_list_daybook_transactions - Manual journal entries (kassekladde)

  • billy_create_daybook_transaction - Create a journal entry (draft by default); accounts by number, must balance

  • billy_delete_daybook_transaction - Delete a draft journal entry (approved entries are refused)

  • billy_list_tax_rates - Configured VAT/tax rates

Date filtering

billy_list_invoices, billy_list_bills, billy_list_postings and billy_list_daybook_transactions accept fromDate/toDate (inclusive, YYYY-MM-DD), filtering on entryDate. A malformed date is rejected rather than silently widening the range.

Why this is handled server-side. Billy's own entryDatePeriod filter works on /invoices, /bills and /postings but is silently ignored on /daybookTransactions and /salesTaxReturns — they return the full set instead of an error. Likewise taxRateId and salesTaxReturnId are ignored on /postings. These tools translate fromDate/toDate to whichever mechanism actually works per endpoint and apply the rest client-side, so a filter either narrows the result or fails loudly. Never pass raw Billy filter syntax and assume it applied.

The auto-paginating tools (sales_tax_returns, postings, daybook_transactions, tax_rates, account_groups) fetch every matching page up to 5,000 records and return retrieved plus a truncated flag. Check truncated before trusting a total.

Read-only by default

This server is read-only unless you explicitly enable writes.

Billy cannot restrict this for you. Its access tokens are unscoped and permanent — any token that can read can also create invoices, edit contacts and register payments. Billy's user roles do not help either: the closest thing to a read-only role (Upload) blocks writes but also blocks reading accounting data, which defeats the purpose. So the restriction has to be enforced here, and it defaults to on.

Out of the box the client sees 16 read tools. The 9 mutating tools (billy_create_*, billy_update_*, billy_delete_daybook_transaction) are absent. To enable them:

BILLY_ALLOW_WRITES=true

Read-only is enforced twice, independently:

  1. The mutating tools are never registered. The model cannot call a write tool because it does not exist — calling one by name returns Tool billy_create_contact not found.

  2. BillyClient refuses any non-GET request, regardless of which tool issued it. A backstop for future tools added without this mode in mind.

Reads behave identically in both modes. The server logs which mode it started in.

Note that readOnlyHint on a tool is advice to the client, not a security boundary — it is what makes a well-behaved client skip a confirmation prompt, nothing more. BILLY_ALLOW_WRITES is the actual enforcement.

Dry run by default

Enabling writes does not make a write happen by accident. Every write tool takes dryRun, which defaults to true: the tool resolves and validates everything it can against live data (GET requests still run), then returns the exact request it would send — method, endpoint and body — without sending it:

{ "dryRun": true, "request": { "method": "POST", "endpoint": "/daybookTransactions", "body": { "...": "..." } },
  "preview": { "lines": [{ "account": "7120 Transferred Result", "side": "debit", "amount": 135000 }] } }

Review that, then repeat the call with dryRun: false. Journal entries add a third safeguard: they are created as drafts by default and only reach the ledger when someone approves them in Billy.

Upgrading from 1.x — three breaking changes in 2.0:

  1. Writes are off by default. They used to be on, gated by BILLY_READ_ONLY. That variable is now ignored (the server warns if it is set). If you rely on the write tools, set BILLY_ALLOW_WRITES=true.

  2. Write tools dry-run by default. They used to send immediately. Pass dryRun: false to send.

  3. Node 26 or higher is required (was 20).

Tool metadata

Every tool declares an outputSchema (results arrive as structuredContent as well as text) and MCP tool annotations, so clients can tell reads from writes:

Annotation

Tools

readOnlyHint: true

all billy_get_* and billy_list_*

write, non-destructive

billy_create_*

write, destructive, idempotent

billy_update_contact, billy_update_invoice, billy_delete_daybook_transaction

Clients that gate on destructiveHint will prompt before the update and delete tools run.

Usage Examples

Create a Contact

// Using the billy_create_contact tool
{
  "name": "Acme Corporation",
  "type": "company",
  "countryId": "DK",
  "street": "Main Street 123",
  "city": "Copenhagen",
  "zipcode": "1000",
  "phone": "+45 12 34 56 78",
  "email": "contact@acme.com",
  "isCustomer": true,
  "paymentTermsDays": 30
}

Create an Invoice

// Using the billy_create_invoice tool
{
  "contactId": "contact-id-here",
  "entryDate": "2024-01-15",
  "currencyId": "DKK",
  "paymentTermsDays": 30,
  "lines": [
    {
      "productId": "product-id-here",
      "description": "Consulting services",
      "quantity": 10,
      "unitPrice": 1000
    }
  ],
  "state": "approved"
}

Create a Payment

// Using the billy_create_payment tool
{
  "entryDate": "2024-01-20",
  "cashAmount": 10000,
  "cashSide": "debit",
  "cashAccountId": "bank-account-id",
  "associations": [
    {
      "subjectReference": "invoice:invoice-id-here"
    }
  ]
}

API Documentation

For detailed information about Billy's API, visit: https://www.billy.dk/api

Development

Running in Development Mode

npm run dev

Building

npm run build      # compile to build/
npm run typecheck  # type-check only

Verifying the connection

npm test               # unit + tool-surface tests: no network, no token needed
npm run test:live      # also runs tests/live/ against your account (dry runs only)
npm run test:connection

npm test builds first and runs tests/ with Node's built-in test runner:

  • tests/unit/ covers the client helpers, the read-only and dry-run guards, journal-entry balancing and account resolution against a stub client, and that a .env in the working directory is ignored.

  • tests/handlers.test.js calls every write tool without dryRun against a local stub of the Billy API and fails if any request other than a GET reaches it.

  • tests/surface.test.js starts the server over stdio and compares every tool's name, schema and annotations, in both modes, with tests/fixtures/tool-surface.json. After an intentional change, regenerate it with UPDATE_SNAPSHOT=1 npm test.

  • tests/live/ runs only with BILLY_LIVE_TESTS=1. Every write call there is a dry run, and the suite fails if the number of journal entries changed.

File Structure

src/
  index.ts            # Entry point: creates the server, registers every tool module
  config.ts           # Loads .env; API base URL, version, the BILLY_ALLOW_WRITES switch
  client.ts           # BillyClient: all HTTP calls to the Billy v2 API
  tools/
    shared.ts         # Schema fragments, annotation presets, dry-run fragments, call()
    organization.ts   # One module per part of the Billy API
    contacts.ts
    invoices.ts
    products.ts
    payments.ts
    bills.ts
    accounts.ts       # Chart of accounts and account groups
    vat.ts            # VAT returns and tax rates
    postings.ts       # Ledger postings
    daybook.ts        # Journal entries: list, create (draft), delete (drafts only)
tests/                # node:test suites (unit, tool surface, live)
test-connection.js    # API connection test utility
.env.example          # Environment variable template
.node-version         # Node 26 (also pinned in mise.toml)
build/                # Compiled JavaScript output
package.json          # Dependencies and scripts
tsconfig.json         # TypeScript configuration
README.md             # This file

MCP protocol version

The MCP TypeScript SDK is on the 1.x line — there is no "MCP 2.0"; protocol revisions are dated. This server uses SDK 1.30.x, which negotiates up to protocol 2025-11-25. The current spec revision, 2026-07-28, is not yet implemented by the TypeScript SDK. This server uses none of the features that revision removes or deprecates, so adopting it should be a dependency bump once SDK support lands.

Error Handling

  • Tool arguments are validated against each tool's schema before any request is made, so bad input fails fast with a field-level message.

  • Billy's error envelope is unwrapped, so failures read as Billy API Error 401: Invalid OAuth 2 access token. (OAUTH_INVALID_ACCESS_TOKEN) rather than an opaque status code.

  • Missing credentials, network failures and Billy API errors are all returned as MCP error results rather than crashing the server.

All errors are returned with descriptive messages to help with debugging.

Supported Billy API Features

This MCP server supports the core Billy API functionality including the list below. For resource-by-resource coverage of the full API, the gaps, and where the implementation and Billy's reference disagree, see Billy MCP API coverage.

  • ✅ Organization management

  • ✅ Contact management (customers/suppliers)

  • ✅ Invoice creation and management

  • ✅ Product catalog management

  • ✅ Payment processing

  • ✅ Bill management (vendor invoices)

  • ✅ Chart of accounts and account groups

  • ✅ VAT returns (momsangivelser) and tax rates

  • ✅ Ledger postings, the ground truth for VAT and balances

  • ✅ Journal entries (kassekladde): list, create as draft, delete drafts

  • ✅ Read-only by default; every write dry-runs unless dryRun: false

  • ✅ Pagination and filtering

  • ✅ Related data inclusion (sideloading/embedding)

  • ✅ Error handling and validation

Limitations

  • Authentication is limited to access tokens (OAuth not yet supported by Billy)

  • Some advanced features like late fees, reminders, and attachments are not yet implemented

  • Bank line matching is not available through the API; match bank lines in Billy. Journal entries (daybook transactions) are supported, as drafts by default.

Security Considerations

  • Store your Billy access token securely

  • Use environment variables rather than hardcoding tokens

  • Tokens in Billy don't expire but can be revoked from the Billy interface

  • Each token is tied to a specific organization

Contributing

To add a tool:

  1. Add the API call to BillyClient in src/client.ts. Everything goes through request(), which enforces read-only mode and dry runs.

  2. Register the tool in the module for its Billy resource, src/tools/<resource>.ts, or add a new module and call its register…Tools function from src/index.ts.

  3. Use the shared fragments from src/tools/shared.ts: billyEnvelope() for the output schema, an annotation preset (readOnly, creates, updates), and call() to run the client method.

  4. Write tools must be registered as writeTools.push(server.registerTool(...)) so they disappear in read-only mode, and must spread ...dryRunParam into the input schema, ...dryRunOutput into the output schema, and pass dryRun to call().

  5. Before exposing a Billy filter, check against a live account that it actually narrows the result (see Date filtering above).

  6. Update this README.

// src/tools/<resource>.ts
writeTools.push(
  server.registerTool(
    "billy_create_thing",
    {
      title: "Create thing",
      description: "Create a thing in Billy",
      inputSchema: { ...dryRunParam, name: z.string().describe("Name") },
      outputSchema: { ...billyEnvelope("things", "list"), ...dryRunOutput },
      annotations: creates,
    },
    ({ dryRun, ...args }) => call((billy) => billy.createThing(args), dryRun)
  )
);

Troubleshooting

Common Issues

  1. "BILLY_ACCESS_TOKEN environment variable is required"

    • Make sure you've set the environment variable correctly

    • Check that your MCP client configuration includes the env section

  2. "Billy API Error: 401"

    • Your access token is invalid or has been revoked

    • Generate a new token from Billy's interface

  3. "Billy API Error: 403"

    • Your token doesn't have permission for the requested operation

    • Check that you're using a company token, not a user token for certain operations

  4. "Billy API Error: 404"

    • The requested resource (invoice, contact, etc.) doesn't exist

    • Check that you're using the correct ID

  5. "Billy API Error: 422"

    • Invalid data in your request

    • Check required fields and data formats (especially dates: YYYY-MM-DD)

Debug Mode

To enable more detailed logging, you can modify the server to log requests:

// Add to the request method in BillyClient
console.error(`Making ${method} request to ${url}`, data);

License

MIT License - feel free to modify and distribute as needed.

Support

For Billy API questions, contact: dev@billy.dk For MCP server issues, please create an issue in your repository.

Available Tools

15 tools
billy_create_contactB

Create a new contact in Billy

NameRequiredDescriptionDefault
cityNoCity
nameYesContact name
typeNoContact type
emailNoEmail address
phoneNoPhone number
streetNoStreet address
zipcodeNoZipcode
countryIdYesCountry ID (e.g., 'DK', 'US')
isCustomerNoWhether contact is a customer
isSupplierNoWhether contact is a supplier
registrationNoNoVAT/CVR/Tax ID number
paymentTermsDaysNoPayment terms in days

TDQS

B3.2/5.0
Behavior2/5

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

With no annotations, the description should disclose behavioral traits such as return values, side effects, or authentication needs. It only says 'Create a new contact' and provides no insight into what happens after creation or any operational constraints.

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

Conciseness5/5

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

The description is a single, clear sentence with no unnecessary words. It is appropriately concise for a simple create operation.

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

Completeness2/5

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

For a tool with 12 parameters and no output schema, the description is insufficient. It fails to mention what is returned after creation, any required prerequisites, or how it relates to other contact operations. The schema is rich, but the descriptive context is too sparse.

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

Parameters3/5

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

Schema description coverage is 100% with every parameter having a description. The tool description adds no extra parameter-level detail, so the baseline of 3 is appropriate.

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

Purpose5/5

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

The description clearly states the action ('Create') and the resource ('a new contact') within the Billy system. It distinguishes from sibling tools like billy_update_contact and billy_list_contacts by specifying 'create'.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives. There are no naming of alternative tools, exclusions, or usage context beyond the mere action of creating.

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

billy_create_invoiceB

Create a new invoice in Billy

NameRequiredDescriptionDefault
linesYesInvoice lines
stateNoInvoice state
contactIdYesContact ID
entryDateYesInvoice date (YYYY-MM-DD)
invoiceNoNoInvoice number (optional, auto-generated if not provided)
currencyIdYesCurrency ID (e.g., 'DKK', 'USD')
contactMessageNoMessage to display on invoice
paymentTermsDaysNoPayment terms in days

TDQS

B3.1/5.0
Behavior2/5

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

With no annotations, the description carries the full burden of behavioral disclosure. It only says 'create' without detailing side effects, default states, auto-generation behavior, or relationship requirements. This is insufficient for a mutation tool.

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

Conciseness4/5

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

The description is a single, concise sentence with no wasted words. It is front-loaded with the verb 'create' but lacks additional structure or detail; still, it is appropriately brief, similar to the TDQS 2.9 example.

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

Completeness2/5

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

The tool has 8 parameters, no annotations, and no output schema. The description fails to mention return values, prerequisites, default behaviors, or other contextual information, making it incomplete for an agent to use correctly.

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

Parameters3/5

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

Schema description coverage is 100%, so the baseline is 3 even with no parameter information in the tool description. The description itself adds no parameter meaning beyond what the schema already provides.

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

Purpose5/5

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

The description 'Create a new invoice in Billy' clearly identifies the action (create) and the resource (invoice), distinguishing it from sibling tools like list/get/update. It 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.

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives, nor any prerequisites or exclusions. The description simply states the action without contextual advice.

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

billy_create_paymentB

Create a payment to mark invoices as paid

NameRequiredDescriptionDefault
cashSideYesdebit for invoice payments, credit for bill payments
entryDateYesPayment date (YYYY-MM-DD)
feeAmountNoBank/payment fee amount
cashAmountYesPayment amount
associationsYesInvoice/bill references to pay
feeAccountIdNoExpense account ID for fees
cashAccountIdYesBank account ID where money was deposited/withdrawn

TDQS

B3.4/5.0
Behavior2/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It only states 'Create a payment to mark invoices as paid' but fails to mention that the tool also handles bills (cashSide credit), that it may update invoice/bill status, or what the response structure is. It does not disclose side effects, permissions, or reversibility, leaving significant uncertainty for a write operation.

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

Conciseness5/5

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

The description is a single, concise sentence, immediately stating the action and purpose. It is front-loaded and contains no fluff or redundant information. Every word contributes to the meaning, making it an example of efficient writing.

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

Completeness2/5

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

Given the tool's complexity (7 parameters, 5 required, no output schema), the description is far too short to be complete. It does not explain the return value, side effects on invoices/bills, or the distinction between paying invoices versus bills. Critical usage context, such as the need for subjectReference formats or fee handling, is only in the schema, leaving the description insufficient for an agent to understand the full scope.

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

Parameters3/5

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

Schema description coverage is 100%, with each parameter having its own description (e.g., cashSide explains debit vs credit, entryDate format). The description of the tool itself adds no parameter-specific semantics beyond implying the purpose of associations. Since the schema is comprehensive, the description provides minimal additional value, earning the baseline score.

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

Purpose5/5

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

The description 'Create a payment to mark invoices as paid' uses a specific verb ('Create') and resource ('payment'), clearly identifying the tool's action. It distinguishes from sibling tools like list_bank_payments (read operation) and create_invoice (different resource). Though it only mentions invoices, the tool also handles bills via cashSide, but the core purpose is still clear.

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

Usage Guidelines3/5

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

The description implies usage for recording payments that mark invoices as paid, but provides no explicit guidance on when to use this versus alternatives. Sibling tools are mostly for different entities (contacts, invoices, products), and only billy_list_bank_payments overlaps slightly, but no alternatives or exclusions are stated. The schema hints at usage via required fields and the cashSide enum, but the description does not elaborate.

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

billy_create_productB

Create a new product in Billy

NameRequiredDescriptionDefault
nameYesProduct name
pricesNoProduct prices for different currencies
accountIdNoRevenue account ID
productNoNoProduct number/SKU
descriptionNoProduct description
salesTaxRulesetIdNoSales tax ruleset ID

TDQS

B3.2/5.0
Behavior2/5

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

With no annotations provided, the description carries full responsibility for disclosing behavioral details. However, it only states 'Create a new product' and does not mention side effects, permissions, idempotency, or error behavior, offering little transparency for a mutation tool.

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

Conciseness5/5

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

The description is a single, direct sentence with no superfluous words. It is efficiently front-loaded and earns its place as a clear, concise statement of the tool's purpose.

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

Completeness2/5

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

Given the tool's complexity (6 parameters) and lack of output schema or annotations, the description is inadequate. It does not explain return values, error conditions, or typical usage contexts, leaving significant gaps in the information an agent needs.

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

Parameters3/5

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

The input schema provides descriptions for all parameters (100% coverage), so the baseline is 3. The description adds no additional parameter context beyond the schema, so it neither enhances nor detracts from what is already available.

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

Purpose5/5

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

The description uses a specific verb 'Create' and clearly identifies the resource ('a new product') within the context of 'Billy'. This distinguishes it from sibling tools like create_contact and create_invoice.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives, no exclusions, and no prerequisites. It merely states the action without contextual cues or alternative suggestions.

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

billy_get_contactA

Get a specific contact by ID

NameRequiredDescriptionDefault
idYesContact ID
includeNoRelated resources to include (e.g., 'contact.contactPersons')

TDQS

A3.8/5.0
Behavior3/5

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

No annotations are provided, so the description carries the burden. 'Get' signals a read-only operation, but the description does not disclose error behavior, authentication requirements, or return format. It is minimal but not misleading.

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

Conciseness5/5

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

The description is a single sentence, concise and front-loaded with the verb 'Get'. Every word is necessary and there is no filler.

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

Completeness4/5

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

For a simple get-by-ID tool with fully documented parameters, the description is adequate. The return value is implied by the tool name, but no output schema exists, so a brief mention of what is returned could have improved completeness.

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

Parameters3/5

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

Schema description coverage is 100%, with both 'id' and 'include' already described. The description adds no additional parameter semantics, so it receives the baseline score of 3.

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

Purpose5/5

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

The description clearly states the verb 'Get', the resource 'contact', and the scope 'by ID', which distinguishes it from list_contacts that retrieves multiple contacts. It 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.

Usage Guidelines3/5

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

The 'by ID' phrasing implies this tool is used when you have a specific contact ID, but it does not explicitly mention alternatives or when not to use it. No reference to sibling tools like list_contacts or get_invoice, so guidance is implied rather than explicit.

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

billy_get_invoiceB

Get a specific invoice by ID

NameRequiredDescriptionDefault
idYesInvoice ID
includeNoRelated resources to include (e.g., 'invoice.lines,invoice.contact')

TDQS

B3.4/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full burden for behavioral disclosure. The description only restates the tool's basic action and does not mention return format, error behavior, permissions, or the impact of the 'include' parameter, leaving significant behavioral aspects undisclosed.

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

Conciseness5/5

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

The description is a single, focused sentence that immediately conveys the tool's purpose. It is appropriately sized for the tool's simplicity and contains no filler.

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

Completeness2/5

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

Given there is no output schema, the description should explain what the tool returns or any relevant behavioral context. It does neither, leaving the agent to guess about the response shape, error handling, or how 'include' affects the result. The description is minimal but insufficiently informative for a complete understanding.

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

Parameters3/5

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

Schema description coverage is 100%: both 'id' and 'include' have descriptions, with 'include' providing an example. The description text adds no additional semantic value beyond what the schema already provides, so the baseline score of 3 is appropriate.

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

Purpose5/5

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

The description 'Get a specific invoice by ID' uses a specific verb ('Get') and resource ('invoice') with a clear scope (by ID). This clearly distinguishes it from sibling tools like billy_list_invoices, which list invoices without an ID filter.

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

Usage Guidelines3/5

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

The tool's purpose is straightforward and implies usage when a specific invoice ID is known. However, it does not explicitly state when to use this over alternatives (e.g., listing invoices) or mention any prerequisites or exclusions.

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

billy_get_organizationB

Get organization details from Billy

NameRequiredDescriptionDefault

No parameters

TDQS

B3.2/5.0
Behavior2/5

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

With no annotations provided, the description is the only source of behavioral information. It only states the action 'Get organization details' with no mention of authentication requirements, rate limits, response structure, or any side effects. This is thin disclosure for an API call, even a read-only one.

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

Conciseness5/5

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

The description is a single, concise sentence with no extraneous words. It is appropriately sized for a parameterless get operation, and the key information ('Get organization details') is front-loaded.

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

Completeness3/5

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

The tool is simple (no parameters, no output schema) but the description still leaves gaps: it doesn't indicate what exactly is returned (e.g., full org object, summary) or any error conditions. Since no output schema exists, the description carries the burden of explaining the return value, which it does not fully do. Overall, adequate for a minimal tool but not complete.

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

Parameters4/5

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

The tool has zero parameters, so the schema trivially covers them. The description adds no parameter information because none is needed. Baseline for zero parameters is 4.

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

Purpose4/5

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

The description clearly identifies the tool's function—retrieving organization details from Billy. It is unambiguous and distinct from sibling tools that target other resources like contacts, invoices, or products, though it does not explicitly differentiate itself. The verb 'Get' is specific and appropriate.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool compared to alternatives. It simply states what it does, with no mention of use cases, prerequisites, or why an agent would choose this over other Billy tools. This is a significant omission.

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

billy_get_productB

Get a specific product by ID

NameRequiredDescriptionDefault
idYesProduct ID
includeNoRelated resources to include (e.g., 'product.prices')

TDQS

B3.3/5.0
Behavior2/5

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

With no annotations, the description carries the full burden. It only says 'Get', implying a read operation, but does not disclose behavior like error handling, return format, or whether related resources can be included. No context is added beyond the basic operation.

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

Conciseness5/5

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

A single, focused sentence that immediately conveys the tool's purpose with no wasted words.

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

Completeness3/5

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

The tool is simple and the description is adequate for a basic get-by-id, but the lack of usage guidelines and behavioral transparency leaves gaps. For a read tool with no annotations, it could benefit from noting safety or typical use cases.

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

Parameters3/5

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

Schema description coverage is 100%, so parameters are already well-documented. The description adds no further meaning to 'id' or 'include', but the schema suffices for a basic get operation.

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

Purpose5/5

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

The description clearly states a specific verb ('Get') and resource ('product') with a scope ('by ID'). It distinguishes this from sibling tools like billy_list_products, which retrieves multiple products.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives, such as billy_list_products for multiple products or billy_create_product for new products. There is no mention of constraints or prerequisites.

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

billy_list_accountsB

List chart of accounts

NameRequiredDescriptionDefault
pageNoPage number for pagination
pageSizeNoNumber of items per page (max 1000)
isArchivedNoFilter by archived status
systemRoleNoFilter by system role
sortPropertyNoProperty to sort by
sortDirectionNoSort direction

TDQS

B3.1/5.0
Behavior2/5

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

With no annotations, the description carries the full burden of behavioral disclosure. It only states 'List chart of accounts' with no mention of readonly behavior, pagination, or return format, leaving the agent without critical context.

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

Conciseness5/5

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

The description is a single concise sentence with no wasted words. It is front-loaded and directly states the purpose, making it easy to process.

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

Completeness3/5

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

The tool is simple and the schema covers all parameters, but the description is minimal. It lacks context about pagination behavior, return value structure, or when to use, which would be helpful given no annotations and no output schema.

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

Parameters3/5

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

The schema covers 100% of parameters with descriptions, so the baseline is 3. The description adds no semantic detail beyond the schema, but the schema already provides sufficient parameter meaning.

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

Purpose4/5

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

The description 'List chart of accounts' clearly states the verb and resource, identifying the tool as a listing operation for accounting accounts. It distinguishes from sibling tools implicitly through the resource name, but does not explicitly differentiate from other list tools.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus alternatives. It does not mention pagination, filtering, or any context for selection among sibling list tools.

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

billy_list_bank_paymentsA

List bank payments with optional filtering and pagination

NameRequiredDescriptionDefault
pageNoPage number for pagination
isVoidedNoFilter by voided status
pageSizeNoNumber of items per page (max 1000)
contactIdNoFilter by contact ID
sortPropertyNoProperty to sort by
sortDirectionNoSort direction

TDQS

A3.5/5.0
Behavior2/5

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

No annotations are provided, so the description carries full behavioral burden. It only mentions 'List bank payments with optional filtering and pagination' but does not disclose response format, default pagination behavior, authentication needs, or any side effects. As a read-only list operation, this is a limited but notable gap.

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

Conciseness5/5

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

The description is a single sentence, front-loaded with 'List bank payments', and contains no superfluous words. It is appropriately sized for a simple list tool with well-documented schema.

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

Completeness3/5

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

The tool has 6 optional parameters and no output schema. The description is minimal but sufficient to convey the basic purpose. However, it lacks context on return structure or any behavioral specifics that could be helpful given no annotations and no output schema.

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

Parameters3/5

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

Schema coverage is 100%, so the baseline is 3. The description's 'optional filtering and pagination' adds only a high-level summary, not specific parameter meaning. The schema itself fully documents each parameter, so the description does not need to compensate.

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

Purpose5/5

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

The description clearly uses the verb 'List' and specifies the resource 'bank payments', distinguishing it from sibling list tools like billy_list_invoices and billy_list_bills. 'Optional filtering and pagination' further clarifies scope.

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

Usage Guidelines3/5

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

The description implies usage for listing bank payments but does not explicitly state when to prefer this tool over alternatives (e.g., billy_list_invoices or billy_list_bills). There are no mention of exclusions or alternative tools.

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

billy_list_billsA

List bills (vendor invoices) with optional filtering and pagination

NameRequiredDescriptionDefault
pageNoPage number for pagination
stateNoFilter by bill state
isPaidNoFilter by payment status
pageSizeNoNumber of items per page (max 1000)
contactIdNoFilter by contact ID
sortPropertyNoProperty to sort by
sortDirectionNoSort direction

TDQS

A3.6/5.0
Behavior3/5

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

With no annotations, the description carries the full burden. It implies a read-only list operation and mentions filtering and pagination, but doesn't disclose pagination defaults, maximums, or sorting behavior beyond what the schema already states.

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

Conciseness5/5

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

A single concise sentence that is front-loaded and contains no filler.

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

Completeness2/5

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

Given the tool has 7 parameters, no output schema, and no annotations, the description is too sparse. It doesn't mention the available filter fields, sorting, or return format, leaving the agent to discover these from the schema.

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

Parameters3/5

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

Schema coverage is 100% and each parameter has a clear description, so the description adds little beyond the schema. The phrase 'optional filtering and pagination' summarizes but doesn't add new meaning.

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

Purpose5/5

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

The description clearly states the tool lists bills and clarifies that bills are vendor invoices, which distinguishes it from the sibling billy_list_invoices. The verb 'List' plus resource 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.

Usage Guidelines3/5

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

The description says 'with optional filtering and pagination', which gives context on how to use it, but it doesn't explicitly say when to use this over billy_list_invoices or other list tools. No alternatives or exclusions are mentioned.

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

billy_list_contactsA

List contacts with optional filtering and pagination

NameRequiredDescriptionDefault
pageNoPage number for pagination
pageSizeNoNumber of items per page (max 1000)
isCustomerNoFilter by customer status
isSupplierNoFilter by supplier status
sortPropertyNoProperty to sort by
sortDirectionNoSort direction

TDQS

A3.7/5.0
Behavior3/5

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

With no annotations provided, the description carries the full burden. It discloses the core behavior (listing) and adds that filtering and pagination are optional, which is helpful. However, it does not mention return format, default pagination behavior, sort defaults, or any side effects (though 'list' implies read-only). It adds some value beyond the name but remains minimal.

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

Conciseness5/5

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

The description is a single sentence, front-loaded with the action and resource, and contains zero wasted words. It efficiently communicates the core functionality without unnecessary elaboration.

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

Completeness3/5

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

Given there is no output schema and no annotations, the description is short but covers the essential behavior. It does not describe return values, edge cases, or what happens with no filters, but for a simple list tool it is minimally viable. More detail about response shape or default behavior would improve completeness.

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

Parameters3/5

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

The input schema has 100% coverage, with descriptions for all six parameters. The description only recaps 'optional filtering and pagination' without adding new syntax or format details. Baseline of 3 is appropriate as the schema does the heavy lifting and the description adds no extra parameter-specific meaning.

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

Purpose5/5

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

The description states 'List contacts' with a specific verb and resource, clearly distinguishing it from 'billy_get_contact' (single contact retrieval). The addition of 'optional filtering and pagination' further scopes the behavior and differentiates it from other list tools like 'billy_list_invoices'.

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

Usage Guidelines3/5

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

The description implies usage through the tool name and the verb 'List', but it does not explicitly state when to choose this over 'billy_get_contact' or mention any exclusions. It provides clear context that it lists contacts with optional filtering/pagination, but lacks explicit alternatives or when-not guidance.

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

billy_list_invoicesA

List invoices with optional filtering and pagination

NameRequiredDescriptionDefault
pageNoPage number for pagination
stateNoFilter by invoice state
isPaidNoFilter by payment status
includeNoRelated resources to include
pageSizeNoNumber of items per page (max 1000)
contactIdNoFilter by contact ID
sortPropertyNoProperty to sort by
sortDirectionNoSort direction

TDQS

A3.6/5.0
Behavior2/5

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

No annotations are provided, so the description must carry the full transparency burden. It only says 'List', which implies a read-only operation, but it does not disclose default behavior, response format, pagination limits, or any side effects. The schema covers parameter details, leaving significant behavioral ambiguity.

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

Conciseness5/5

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

The description is a single, front-loaded sentence with zero wasted words. It effectively communicates the tool's main purpose without redundancy.

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

Completeness2/5

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

With 8 parameters, no annotations, and no output schema, the description is too sparse to be contextually complete. It fails to mention default behavior, how filters combine, what the response looks like, or any usage caveats. The description only scratches the surface for a tool of this complexity.

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

Parameters3/5

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

Schema description coverage is 100%, so parameters are already well-documented. The description adds no additional meaning beyond what the schema provides, so the baseline of 3 is appropriate.

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

Purpose5/5

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

The description uses a specific verb ('List') and resource ('invoices'), and clearly indicates optional filtering and pagination. This distinguishes it from single-invoice retrieval (billy_get_invoice) and other list tools.

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

Usage Guidelines4/5

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

The description clearly states the core use case: listing invoices with optional filters and pagination. It does not explicitly name alternative tools or exclusions, but the context makes the tool's purpose evident among the siblings.

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

billy_list_productsB

List products with optional filtering and pagination

NameRequiredDescriptionDefault
pageNoPage number for pagination
includeNoRelated resources to include
pageSizeNoNumber of items per page (max 1000)
isArchivedNoFilter by archived status
sortPropertyNoProperty to sort by
sortDirectionNoSort direction

TDQS

B3.3/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It only states that filtering and pagination are optional, but does not disclose defaults (e.g., page size), return format, or any side effects. This minimal information is insufficient for a tool with no structured safety annotations.

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

Conciseness5/5

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

The description is a single seven-word sentence that is front-loaded and free of redundancy. Every word earns its place, making it highly efficient.

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

Completeness3/5

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

For a simple list tool with six optional parameters and no output schema, the description is adequate but incomplete. It does not explain the return value structure or provide usage context beyond the bare essentials. The high schema coverage partially compensates, but without annotations, the description could be richer.

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

Parameters3/5

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

Input schema covers 100% of parameters with descriptions, so the baseline is 3. The tool description groups parameters into 'filtering' and 'pagination', but adds no substantive meaning beyond the schema. It is not misleading, just redundant.

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

Purpose4/5

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

The description uses a specific verb ('list') and resource ('products') with mention of optional filtering and pagination. It clearly indicates this is a list operation, distinguishing it from singular get_product and create_product by name, but does not explicitly contrast with those siblings.

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

Usage Guidelines3/5

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

The description implies usage when the goal is to list products with optional filtering/pagination. However, it provides no explicit guidance on when to prefer this over billy_get_product or billy_create_product, nor any exclusions or alternative recommendations.

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

billy_update_contactB

Update an existing contact

NameRequiredDescriptionDefault
idYesContact ID
cityNoCity
nameNoContact name
emailNoEmail address
phoneNoPhone number
streetNoStreet address
zipcodeNoZipcode
isCustomerNoWhether contact is a customer
isSupplierNoWhether contact is a supplier
registrationNoNoVAT/CVR/Tax ID number
paymentTermsDaysNoPayment terms in days

TDQS

B3.4/5.0
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It only says 'Update an existing contact' and fails to mention whether updates are partial or full, what response to expect, or any side effects. This is a significant transparency gap for a mutation tool.

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

Conciseness5/5

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

The description is a single concise sentence with no unnecessary words. It is front-loaded with the verb and object, making it immediately clear what the tool does. Every word earns its place.

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

Completeness2/5

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

Given the high parameter count (11), no output schema, and no annotations, the description is insufficiently complete. It does not explain update semantics (e.g., partial vs. full update), whether the updated contact is returned, or any prerequisites. The agent would need to infer too much from the schema alone.

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

Parameters3/5

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

Schema description coverage is 100% for all 11 parameters, each with a clear description. The tool description adds no parameter-specific information, so the schema carries the semantic weight. This matches the baseline of 3 given high schema coverage.

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

Purpose5/5

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

The description 'Update an existing contact' clearly states the action (update) and resource (contact), distinguishing it from sibling tools like billy_create_contact and billy_get_contact. The verb is specific and the scope is clear.

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

Usage Guidelines3/5

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

The description implies usage for modifying an existing contact, but does not explicitly mention when to use this tool versus creating a new contact or when not to use it. No alternatives are named, leaving the guidance implicit rather than explicit.

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

Tool Schema Changelog

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

  1. 15 tool updatesv1.0.0
    • First observedbilly_create_contact
    • First observedbilly_create_invoice
    • First observedbilly_create_payment
    • First observedbilly_create_product
    • First observedbilly_get_contact
    • First observedbilly_get_invoice
    • First observedbilly_get_organization
    • First observedbilly_get_product
    • First observedbilly_list_accounts
    • First observedbilly_list_bank_payments
    • First observedbilly_list_bills
    • First observedbilly_list_contacts
    • First observedbilly_list_invoices
    • First observedbilly_list_products
    • First observedbilly_update_contact

TDQS

A3.7/5.0

Scored across 15 tools

Disambiguation5/5

Every tool targets a distinct resource and action, with clear separation between entities like contacts, invoices, products, payments, bills, and accounts. List/get/create/update operations are specific to their subject, and even similar tools like list_bills and list_invoices are distinguished by the vendor invoice descriptor.

Naming Consistency5/5

All tool names follow the consistent pattern 'billy_<verb>_<entity>' using snake_case throughout. The verbs (list, get, create, update) are uniform and predictable, making it easy to infer functionality from the name.

Tool Count5/5

With 15 tools, the server is at the upper boundary of the ideal range but remains well-scoped for an accounting/billing API. Each tool represents a meaningful operation across a coherent set of resources without redundancy.

Completeness4/5

The core accounting workflows are covered: contacts (CRUD minus delete), invoices (create/list/get), products (create/list/get), payments (create), and supporting lists for bills and accounts. Minor gaps like invoice updates or product updates exist, but agents can work around them or these may be deliberately omitted for compliance reasons.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Complete Swiss accounting integration for Bexio via MCP. Works with Claude Desktop, n8n, and any MCP client. 221 tools for invoices, contacts, projects & more. Created by Lukas Hertig.
    39
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    MCP server to interact with the Cuéntica accounting API, allowing users to manage invoices, expenses, income, clients, providers, and bank accounts via natural language.
    59
    2
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    An MCP server for Danish accounting via Billy.dk API, enabling natural-language control over invoices, bank lines, reports, and more, with a write-guard for safety.
    65
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Connects AI assistants to the Danish accounting platform Billy (billy.dk) for managing invoices, journal entries, balances, and receipts, with built-in human approval for all write operations.
    40
    42 npm
    1
    MIT