Billy MCP Server
Interact with Billy accounting data through MCP tools, with read-only access by default and opt-in, dry-run-by-default write tools.
Get organization details.
List/get contacts and create/update contacts when writes are enabled.
List/get invoices and create invoices with line items when writes are enabled.
List/get products and create products with pricing when writes are enabled.
List bank payments and create payments to mark invoices/bills as paid when writes are enabled.
List bills and chart-of-accounts entries.
Filter, sort, paginate, and include related resources on list/get calls.
Enforce read-only mode unless
BILLY_ALLOW_WRITES=true; write calls dry-run unlessdryRun: false.
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., "@Billy MCP Servershow me all unpaid invoices"
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.
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-versionandmise.tomlpin it)Billy account with API access
Billy API access token
Installation
Clone or download the server code
Install dependencies:
npm installBuild the TypeScript code:
npm run build
Configuration
Getting a Billy API Token
Log into your Billy account at app.billysbilling.com
Go to Settings → Access tokens
Create a new access token, giving it a descriptive name (e.g.
mcp-server)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 |
| yes | Billy API access token |
| no | Sent as |
| no | Set to |
| no | Overrides the API base URL (defaults to |
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 filteringbilly_get_contact- Get a specific contact by IDbilly_create_contact- Create a new contactbilly_update_contact- Update an existing contact
Invoices
billy_list_invoices- List invoices with optional filteringbilly_get_invoice- Get a specific invoice by IDbilly_create_invoice- Create a new invoice with line itemsbilly_update_invoice- Update an existing invoice
Products
billy_list_products- List products with optional filteringbilly_get_product- Get a specific product by IDbilly_create_product- Create a new product with pricing
Payments
billy_list_bank_payments- List bank paymentsbilly_create_payment- Create a payment to mark invoices as paid
Bills
billy_list_bills- List vendor billsbilly_create_bill- Create a vendor bill
Accounts
billy_list_accounts- List chart of accountsbilly_list_account_groups- List chart-of-accounts groups
VAT and ledger
billy_list_sales_tax_returns- Billy's own VAT returns (momsangivelser) — the authoritative figuresbilly_get_sales_tax_return- Get a single VAT return by IDbilly_list_postings- Ledger postings, where VAT actually landsbilly_list_daybook_transactions- Manual journal entries (kassekladde)billy_create_daybook_transaction- Create a journal entry (draft by default); accounts by number, must balancebilly_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
entryDatePeriodfilter works on/invoices,/billsand/postingsbut is silently ignored on/daybookTransactionsand/salesTaxReturns— they return the full set instead of an error. LikewisetaxRateIdandsalesTaxReturnIdare ignored on/postings. These tools translatefromDate/toDateto 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=trueRead-only is enforced twice, independently:
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.BillyClientrefuses 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:
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, setBILLY_ALLOW_WRITES=true.Write tools dry-run by default. They used to send immediately. Pass
dryRun: falseto send.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 |
| all |
write, non-destructive |
|
write, destructive, idempotent |
|
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 devBuilding
npm run build # compile to build/
npm run typecheck # type-check onlyVerifying 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:connectionnpm 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.envin the working directory is ignored.tests/handlers.test.jscalls every write tool withoutdryRunagainst a local stub of the Billy API and fails if any request other than a GET reaches it.tests/surface.test.jsstarts the server over stdio and compares every tool's name, schema and annotations, in both modes, withtests/fixtures/tool-surface.json. After an intentional change, regenerate it withUPDATE_SNAPSHOT=1 npm test.tests/live/runs only withBILLY_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 fileMCP 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:
Add the API call to
BillyClientinsrc/client.ts. Everything goes throughrequest(), which enforces read-only mode and dry runs.Register the tool in the module for its Billy resource,
src/tools/<resource>.ts, or add a new module and call itsregister…Toolsfunction fromsrc/index.ts.Use the shared fragments from
src/tools/shared.ts:billyEnvelope()for the output schema, an annotation preset (readOnly,creates,updates), andcall()to run the client method.Write tools must be registered as
writeTools.push(server.registerTool(...))so they disappear in read-only mode, and must spread...dryRunParaminto the input schema,...dryRunOutputinto the output schema, and passdryRuntocall().Before exposing a Billy filter, check against a live account that it actually narrows the result (see Date filtering above).
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
"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
"Billy API Error: 401"
Your access token is invalid or has been revoked
Generate a new token from Billy's interface
"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
"Billy API Error: 404"
The requested resource (invoice, contact, etc.) doesn't exist
Check that you're using the correct ID
"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 toolsbilly_create_contactB
Create a new contact in Billy
| Name | Required | Description | Default |
|---|---|---|---|
| city | No | City | |
| name | Yes | Contact name | |
| type | No | Contact type | |
| No | Email address | ||
| phone | No | Phone number | |
| street | No | Street address | |
| zipcode | No | Zipcode | |
| countryId | Yes | Country ID (e.g., 'DK', 'US') | |
| isCustomer | No | Whether contact is a customer | |
| isSupplier | No | Whether contact is a supplier | |
| registrationNo | No | VAT/CVR/Tax ID number | |
| paymentTermsDays | No | Payment terms in days |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| lines | Yes | Invoice lines | |
| state | No | Invoice state | |
| contactId | Yes | Contact ID | |
| entryDate | Yes | Invoice date (YYYY-MM-DD) | |
| invoiceNo | No | Invoice number (optional, auto-generated if not provided) | |
| currencyId | Yes | Currency ID (e.g., 'DKK', 'USD') | |
| contactMessage | No | Message to display on invoice | |
| paymentTermsDays | No | Payment terms in days |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| cashSide | Yes | debit for invoice payments, credit for bill payments | |
| entryDate | Yes | Payment date (YYYY-MM-DD) | |
| feeAmount | No | Bank/payment fee amount | |
| cashAmount | Yes | Payment amount | |
| associations | Yes | Invoice/bill references to pay | |
| feeAccountId | No | Expense account ID for fees | |
| cashAccountId | Yes | Bank account ID where money was deposited/withdrawn |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Product name | |
| prices | No | Product prices for different currencies | |
| accountId | No | Revenue account ID | |
| productNo | No | Product number/SKU | |
| description | No | Product description | |
| salesTaxRulesetId | No | Sales tax ruleset ID |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Contact ID | |
| include | No | Related resources to include (e.g., 'contact.contactPersons') |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Invoice ID | |
| include | No | Related resources to include (e.g., 'invoice.lines,invoice.contact') |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Product ID | |
| include | No | Related resources to include (e.g., 'product.prices') |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination | |
| pageSize | No | Number of items per page (max 1000) | |
| isArchived | No | Filter by archived status | |
| systemRole | No | Filter by system role | |
| sortProperty | No | Property to sort by | |
| sortDirection | No | Sort direction |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination | |
| isVoided | No | Filter by voided status | |
| pageSize | No | Number of items per page (max 1000) | |
| contactId | No | Filter by contact ID | |
| sortProperty | No | Property to sort by | |
| sortDirection | No | Sort direction |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination | |
| state | No | Filter by bill state | |
| isPaid | No | Filter by payment status | |
| pageSize | No | Number of items per page (max 1000) | |
| contactId | No | Filter by contact ID | |
| sortProperty | No | Property to sort by | |
| sortDirection | No | Sort direction |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination | |
| pageSize | No | Number of items per page (max 1000) | |
| isCustomer | No | Filter by customer status | |
| isSupplier | No | Filter by supplier status | |
| sortProperty | No | Property to sort by | |
| sortDirection | No | Sort direction |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination | |
| state | No | Filter by invoice state | |
| isPaid | No | Filter by payment status | |
| include | No | Related resources to include | |
| pageSize | No | Number of items per page (max 1000) | |
| contactId | No | Filter by contact ID | |
| sortProperty | No | Property to sort by | |
| sortDirection | No | Sort direction |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination | |
| include | No | Related resources to include | |
| pageSize | No | Number of items per page (max 1000) | |
| isArchived | No | Filter by archived status | |
| sortProperty | No | Property to sort by | |
| sortDirection | No | Sort direction |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Contact ID | |
| city | No | City | |
| name | No | Contact name | |
| No | Email address | ||
| phone | No | Phone number | |
| street | No | Street address | |
| zipcode | No | Zipcode | |
| isCustomer | No | Whether contact is a customer | |
| isSupplier | No | Whether contact is a supplier | |
| registrationNo | No | VAT/CVR/Tax ID number | |
| paymentTermsDays | No | Payment terms in days |
TDQS
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.
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.
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.
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.
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.
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.
15 tool updates
v1.0.0- First observed
billy_create_contact - First observed
billy_create_invoice - First observed
billy_create_payment - First observed
billy_create_product - First observed
billy_get_contact - First observed
billy_get_invoice - First observed
billy_get_organization - First observed
billy_get_product - First observed
billy_list_accounts - First observed
billy_list_bank_payments - First observed
billy_list_bills - First observed
billy_list_contacts - First observed
billy_list_invoices - First observed
billy_list_products - First observed
billy_update_contact
TDQS
Scored across 15 tools
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.
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.
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.
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
Related MCP Connectors
Read Billy invoices, bills, contacts, products and postings; create contacts and draft invoices.
Invoicing you drive by talking to your AI: log time, raise invoices and track what's owed via MCP.
Connect Exact Online to your AI assistant via MCP. Manage Exact Online with natural language.
Fakturownia.pl (Polish invoicing) via MCP: invoices, clients, products, warehouse. Full read-write.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceComplete 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.39MIT
- AlicenseBqualityDmaintenanceMCP server to interact with the Cuéntica accounting API, allowing users to manage invoices, expenses, income, clients, providers, and bank accounts via natural language.592MIT
- AlicenseBqualityDmaintenanceAn 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.651MIT
- AlicenseAqualityDmaintenanceConnects 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.4042 npm1MIT