Skip to main content
Glama
sap-b1-mcp

sap-b1-mcp

by kodenova

sap-b1-mcp: read-only SAP Business One MCP server

An open-source Model Context Protocol server that lets AI assistants (Claude, ChatGPT via a bridge, Cursor, VS Code and other MCP clients) read data from one SAP Business One company through the Service Layer REST API.

It is a deliberately small, auditable starter:

  • Read-only by design. There are no tools that create, change or delete anything, and the HTTP client refuses any request other than GET, Login, Logout and running a pre-created SQLQueries entry.

  • No free SQL and no free filters. Every tool has a typed input schema, a row limit and a field whitelist. Custom reports go through run_saved_query, which only runs queries an administrator registered in a config file.

  • Credentials stay private. They come from environment variables, are never logged, and are redacted from every error message.

  • Runs without SAP. SAPB1_MOCK=1 serves bundled demo fixtures, so you can try it and run the tests on any machine.

SAP and SAP Business One are trademarks or registered trademarks of SAP SE in Germany and other countries. This project is independent and is not affiliated with, sponsored by or endorsed by SAP SE.

Tools

Tool

What it returns

Key inputs

Row limit

get_business_partner

One customer, supplier or lead by exact CardCode

cardCode, optional fields

1

search_business_partners

Partners whose code or name contains text

query, type (customer / supplier / lead), limit, fields

limit (≤ SAPB1_MAX_ROWS)

get_item

One item master record by exact ItemCode

itemCode, optional fields

1

search_items

Items whose code or name contains text

query, inStockOnly, limit, fields

limit

get_open_sales_orders

Open sales orders, newest first

optional cardCode, limit, fields

limit

get_customer_balance

Account balance, open orders, open deliveries, credit limit and available credit

cardCode

1

get_open_invoices

Open A/R invoices with unpaid amount and days overdue, plus a total

optional cardCode, overdueOnly, limit

limit

get_stock_by_warehouse

In stock, committed, ordered and available per warehouse for one item

itemCode, optional warehouseCode, includeEmpty

all warehouses of one item

run_saved_query

Result of a query pre-registered by an administrator

name, params, limit

min(limit, query maxRows)

Every tool is annotated readOnlyHint: true, destructiveHint: false.

Field whitelists

The fields input only accepts names from these lists, so the model cannot pull other columns:

  • Business partners: CardCode, CardName, CardType, GroupCode, Phone1, EmailAddress, City, Country, Currency, FederalTaxID, Valid, Frozen

  • Balance: CardCode, CardName, Currency, CurrentAccountBalance, OpenOrdersBalance, OpenDeliveryNotesBalance, CreditLimit

  • Items: ItemCode, ItemName, ItemsGroupCode, BarCode, InventoryItem, SalesItem, PurchaseItem, InventoryUOM, QuantityOnStock, QuantityOrderedFromVendors, QuantityOrderedByCustomers, Valid, Frozen

  • Documents (orders, invoices): DocEntry, DocNum, CardCode, CardName, NumAtCard, DocDate, DocDueDate, DocTotal, DocCurrency, PaidToDate, DocumentStatus

Edit the lists in src/server.ts to fit your company.

Related MCP server: servicios-mcp

Quick start (no SAP needed)

npx -y @kodenova/sap-b1-mcp        # with SAPB1_MOCK=1 in the environment

Or from source:

git clone https://github.com/kodenova/sap-b1-mcp.git
cd sap-b1-mcp
npm install
npm run build
npm test                           # runs in mock mode, no SAP needed
SAPB1_MOCK=1 node dist/index.js    # stdio MCP server on demo data

Requires Node.js 18.17 or later.

Environment variables

Variable

Required

Description

SAPB1_SERVICE_LAYER_URL

yes

Service Layer base URL, e.g. https://b1server:50000/b1s/v1

SAPB1_COMPANY_DB

yes

Company database / schema name

SAPB1_USERNAME

yes

Dedicated read-only B1 user (see Security)

SAPB1_PASSWORD

yes

Password of that user. Never logged, redacted from errors

SAPB1_ALLOW_SELF_SIGNED

no

true to accept a self-signed TLS certificate. Off by default

SAPB1_ALLOW_HTTP

no

true to allow a plain http:// URL. Only for a local test system

SAPB1_MAX_ROWS

no

Maximum rows any tool may return. Default 50, hard cap 500

SAPB1_TIMEOUT_MS

no

Per-request timeout. Default 30000

SAPB1_SAVED_QUERIES_FILE

no

Path to your saved-queries JSON (see below)

SAPB1_LOG_LEVEL

no

debug, info (default), warn, error, silent. Logs go to stderr

SAPB1_MOCK

no

true / 1 to use the bundled fixtures instead of SAP

See .env.example.

Client setup

Claude Desktop

Edit claude_desktop_config.json (Settings, Developer, Edit Config):

{
  "mcpServers": {
    "sap-b1": {
      "command": "npx",
      "args": ["-y", "@kodenova/sap-b1-mcp"],
      "env": {
        "SAPB1_SERVICE_LAYER_URL": "https://b1server:50000/b1s/v1",
        "SAPB1_COMPANY_DB": "SBODEMOUS",
        "SAPB1_USERNAME": "mcp_readonly",
        "SAPB1_PASSWORD": "your-password",
        "SAPB1_MAX_ROWS": "50"
      }
    }
  }
}

To try it without SAP, replace the env block with { "SAPB1_MOCK": "1" }. On Windows, if npx is not found, use "command": "cmd" and "args": ["/c", "npx", "-y", "@kodenova/sap-b1-mcp"].

Claude Code

claude mcp add sap-b1 \
  -e SAPB1_SERVICE_LAYER_URL=https://b1server:50000/b1s/v1 \
  -e SAPB1_COMPANY_DB=SBODEMOUS \
  -e SAPB1_USERNAME=mcp_readonly \
  -e SAPB1_PASSWORD=your-password \
  -- npx -y @kodenova/sap-b1-mcp

VS Code (GitHub Copilot agent mode)

.vscode/mcp.json, with the password prompted instead of stored:

{
  "inputs": [
    { "type": "promptString", "id": "sapb1-password", "description": "SAP B1 password", "password": true }
  ],
  "servers": {
    "sap-b1": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@kodenova/sap-b1-mcp"],
      "env": {
        "SAPB1_SERVICE_LAYER_URL": "https://b1server:50000/b1s/v1",
        "SAPB1_COMPANY_DB": "SBODEMOUS",
        "SAPB1_USERNAME": "mcp_readonly",
        "SAPB1_PASSWORD": "${input:sapb1-password}"
      }
    }
  }
}

Cursor, Windsurf and other stdio clients

Use the same command, args and env as the Claude Desktop example in the client's MCP config file (for Cursor: ~/.cursor/mcp.json or .cursor/mcp.json).

ChatGPT and other remote-only clients

ChatGPT connects to remote MCP servers over HTTPS; it does not launch local stdio processes. This package is a stdio server, so for ChatGPT you need to host it behind an MCP stdio-to-HTTP bridge on a server you control, with HTTPS and authentication in front of it. Do not expose an unauthenticated endpoint that holds your SAP credentials. If you want a hosted, authenticated HTTP version, see the footer.

Saved queries (run_saved_query)

The model cannot send SQL or OData filters. It can only pick a query by name from a JSON file you control and pass the typed parameters that query declares. Copy config/saved-queries.example.json to config/saved-queries.json and point SAPB1_SAVED_QUERIES_FILE at it.

Two kinds are supported:

{
  "queries": {
    "customers_over_balance": {
      "kind": "odata",
      "description": "Customers whose account balance is above a threshold",
      "resource": "BusinessPartners",
      "select": ["CardCode", "CardName", "CurrentAccountBalance"],
      "filter": { "and": [
        { "field": "CardType", "op": "eq", "value": "cCustomer" },
        { "field": "CurrentAccountBalance", "op": "gt", "value": { "param": "minBalance" } }
      ]},
      "orderBy": "CurrentAccountBalance desc",
      "maxRows": 100,
      "params": { "minBalance": { "type": "number", "default": 0 } }
    },
    "sales_by_month": {
      "kind": "sqlquery",
      "description": "Net A/R sales per month for a year",
      "sqlCode": "KN_SALES_BY_MONTH",
      "params": { "year": { "type": "integer", "required": true } }
    }
  }
}
  • odata queries run against a Service Layer entity set with a fixed $select and a structured filter. Parameter values are type-checked (string, number, integer, date, boolean) and escaped; field names are validated.

  • sqlquery queries run a SQLQueries entry that your administrator already created in Service Layer (POST SQLQueries('code')/List with a ParamList). Service Layer only accepts SELECT statements there. This server cannot create or change SQLQueries entries.

Security

  • No write path. The client-side guard (assertReadOnly in src/serviceLayer.ts) blocks PATCH, PUT, DELETE and every POST except Login, Logout and SQLQueries('…')/List, before any request is sent. Tests cover this.

  • Use a dedicated least-privilege B1 user. Create a separate user (for example mcp_readonly) for this server. Do not use manager or a superuser. In Administration → System Initialization → Authorizations → General Authorizations, set:

    • Read Only for Business Partner Master Data, Item Master Data, Sales A/R (Orders, A/R Invoices) and Inventory reports you want exposed

    • No Authorization for everything else, including Administration, Banking, Financials and all purchasing or posting screens you do not need

    The server is read-only on its own; the B1 authorizations are your second, independent layer. Service Layer logins need a suitable B1 user license, so check the licensing with your SAP partner.

  • Credentials. Read only from environment variables. Never written to logs. Password, B1SESSION and ROUTEID values are redacted from every error and log line. Prefer your client's secret prompt (as in the VS Code example) over storing the password in a config file.

  • TLS. Certificate verification is on by default. SAPB1_ALLOW_SELF_SIGNED=true turns it off for the Service Layer host only and logs a warning. Plain http:// is refused unless SAPB1_ALLOW_HTTP=true.

  • Bounded output. Every list tool has a row limit (default 20, max SAPB1_MAX_ROWS, hard cap 500) and a field whitelist, so a prompt cannot dump whole tables.

  • Prompt injection. Data returned from SAP (names, remarks) is passed to the model as data. Because the tools cannot write, a malicious record cannot make the model change your ERP through this server. Still, review what other tools you connect alongside it.

  • Logs go to stderr, never stdout (stdout is the MCP protocol channel).

Service Layer version notes

  • Built for the Service Layer v1 endpoint (/b1s/v1), which uses OData v3-style JSON (odata.nextLink, {"error":{"message":{"value":…}}}). The client also reads the v2 (/b1s/v2, OData v4) @odata.nextLink and error format, but filters with dates are written in v1 syntax, so v1 is the supported endpoint for 0.1.0.

  • Paging: Service Layer returns 20 rows per page by default. The server sends Prefer: odata.maxpagesize=N and follows odata.nextLink until the row limit is reached.

  • Sessions: login is POST /Login with CompanyDB, UserName and Password; the B1SESSION (and ROUTEID when load-balanced) cookies are reused. When the session times out (30 minutes by default), the server logs in again once and retries. It logs out on shutdown.

  • contains() and startswith() are used for search. On SAP HANA, string comparison is case-sensitive, so search_items with widget will not match Widget.

  • SQLQueries (used by sqlquery saved queries) exists only in newer Service Layer releases. Check that SQLQueries appears in your $metadata before using that kind.

  • Field names follow the standard Service Layer metadata (BusinessPartners, Items, Orders, Invoices). If your release or localization differs, adjust the whitelists in src/server.ts.

Limitations

  • Read-only. No document creation, approvals, payments or master-data changes.

  • One company database per server process. Run several processes for several companies.

  • Service Layer only. The DI API (COM) and direct database access are not used.

  • No user-defined fields (UDFs) in the default whitelists. Add U_… fields yourself if needed.

  • Search uses contains(), which can be slow on very large tables without suitable indexes; keep limits small.

  • stdio transport only in this release. Remote clients such as ChatGPT need a bridge you host and secure.

  • Tested with unit tests, the bundled fixtures and a fake Service Layer HTTP server. Validate against a test company before you point it at production.

Development

npm install
npm run build
npm test

Project layout:

src/index.ts         stdio entry point (bin)
src/server.ts        the 9 MCP tools, schemas, whitelists
src/serviceLayer.ts  Service Layer client: login, cookies, paging, read-only guard
src/mock.ts          fixture-backed data source for SAPB1_MOCK=1
src/savedQueries.ts  saved-query config loader and parameter binding
src/odata.ts         structured filter → OData, escaping
src/redact.ts        credential redaction
fixtures/            demo data (fictional)
config/              saved-queries example
test/                vitest suites (mock mode + fake Service Layer)

Contributions are welcome. Please keep the server read-only: pull requests that add write endpoints will not be merged into this package.

License

MIT © 2026 Kodenova / Zain Abbas. See LICENSE.

SAP and SAP Business One are trademarks or registered trademarks of SAP SE in Germany and other countries. This project is not affiliated with, sponsored by or endorsed by SAP SE. All demo data in fixtures/ is fictional.


Built by Kodenova, an independent SAP Business One development studio that works alongside your SAP partner. Need write access, custom tools or DI API? kodenova.com/services/mcp-server-development/

Available Tools

9 tools
get_business_partnerGet business partnerA
Read-onlyIdempotent

Fetch one business partner (customer, supplier or lead) by its exact CardCode.

NameRequiredDescriptionDefault
fieldsNoSubset of fields to return. Allowed: CardCode, CardName, CardType, GroupCode, Phone1, EmailAddress, City, Country, Currency, FederalTaxID, Valid, Frozen
cardCodeYesCardCode (exact code, case-sensitive on HANA)

TDQS

A3.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds the entity-type scope but says nothing about not-found behavior, whether the response is a single object or empty, or the case-sensitivity caveat (that lives only in the schema).

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 sentence with the resource and the lookup key front-loaded, and no filler. Nothing can be removed without losing information.

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 two-parameter read with no output schema and full schema coverage, the definition gives enough to invoke it correctly. The only real gap is the absence of a not-found/response-shape note, which is minor for a straightforward lookup.

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% and both parameters are documented there, including the case-sensitive HANA note, so the schema carries the burden. The description reinforces that cardCode must be exact but never mentions the optional fields projection parameter.

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?

States a specific verb and resource ("Fetch one business partner") and narrows the domain with "(customer, supplier or lead)". The words "one" and "exact CardCode" implicitly separate it from the list-style sibling search_business_partners, but that sibling is never named.

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 phrase "by its exact CardCode" implies the precondition (you must already know the code) and hints that broad matching belongs elsewhere, but no alternative is named and no when-not condition is given. An agent must infer that search_business_partners is the fallback when the code is unknown or uncertain.

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

get_customer_balanceGet customer balanceA
Read-onlyIdempotent

Account balance, open orders balance, open deliveries balance and credit limit for one business partner.

NameRequiredDescriptionDefault
cardCodeYesCardCode (exact code, case-sensitive on HANA)

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so safety is covered. The description adds genuine value by disclosing the payload contents (four balance figures plus credit limit), which matters since there is no output schema. It says nothing about behavior for unknown card codes, empty results, or whether balances are real-time.

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?

A single tight sentence that front-loads the returned metrics with zero filler. It is a noun fragment rather than a full sentence, which is minor, but every word carries information.

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 one-parameter read tool with full schema coverage and rich annotations, the description is nearly sufficient; enumerating the returned fields compensates for the absent output schema. Missing are edge-case behavior and result-shape hints (e.g. whether all four figures are always present).

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

Parameters3/5

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

Schema coverage is 100% and the single parameter is fully documented, including case sensitivity on HANA. The description's phrase 'for one business partner' reinforces that cardCode identifies exactly one partner rather than filtering a list, but adds no format or lookup guidance beyond the schema. Baseline 3 applies.

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 names the specific resource (business partner) and enumerates the four values returned: account balance, open orders balance, open deliveries balance and credit limit. Combined with the tool name the verb is unambiguous. It does not explicitly contrast with get_business_partner, so it falls short of sibling differentiation.

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?

Usage is only implied: it fetches figures for exactly one business partner, which tells an agent this is a single-record lookup rather than a search. There is no statement of when to prefer get_business_partner or get_open_invoices, and no preconditions such as the card code needing to exist.

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

get_itemGet itemA
Read-onlyIdempotent

Fetch one item master record by its exact ItemCode.

NameRequiredDescriptionDefault
fieldsNoSubset of fields to return. Allowed: ItemCode, ItemName, ItemsGroupCode, BarCode, InventoryItem, SalesItem, PurchaseItem, InventoryUOM, QuantityOnStock, QuantityOrderedFromVendors, QuantityOrderedByCustomers, Valid, Frozen
itemCodeYesItemCode (exact code, case-sensitive on HANA)

TDQS

A3.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=true, so the safety profile is covered externally. The description contributes the exact-match/case-sensitivity framing but says nothing about not-found behavior or whether missing items return empty vs. error.

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 front-loaded sentence with no filler; the key constraint (exact code) is placed where it is read first.

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 two-parameter, fully documented read tool with rich annotations and no output schema, this is close to sufficient. The only meaningful omission is behavior on a non-existent ItemCode and whether 'fields' projection affects payload size.

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%, including the case-sensitivity note on HANA and the full enum list for 'fields'. The description's mention of 'exact ItemCode' restates the schema rather than adding format, casing, or projection guidance.

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?

Names a specific verb (Fetch) and resource (one item master record) with the lookup key (exact ItemCode), so an agent knows this is a single-record exact-match read. It does not explicitly name search_items as the alternative for fuzzy/list lookups, so the sibling distinction is only implied by 'one' and 'exact'.

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 phrase 'by its exact ItemCode' implies the precondition for use (you must already know the code), which is meaningful guidance. But it never states when to prefer search_items instead, nor what happens when the code does not exist.

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

get_open_invoicesGet open A/R invoicesA
Read-onlyIdempotent

Open A/R invoices with the unpaid balance (DocTotal - PaidToDate), optionally for one customer or only overdue ones.

NameRequiredDescriptionDefault
limitNoMax rows to return (1-50, default 20)
cardCodeNoCardCode (exact code, case-sensitive on HANA)
overdueOnlyNoOnly invoices with DocDueDate before today

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so safety is covered. The description adds real value by spelling out the unpaid-balance formula, but says nothing about ordering, pagination behavior, or what happens when no filters are supplied.

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?

A single tight sentence that front-loads the resource and immediately defines the balance calculation, with no filler. It is appropriately sized for a simple read tool, though the parenthetical formula slightly interrupts the flow.

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 three-parameter read-only listing tool with a fully described schema and no output schema, the definition covers what the tool returns (invoices plus unpaid balance) and the optional narrowing options. Only minor gaps remain, such as default sort order or maximum result behavior.

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 all three parameters are already documented, including limits and the HANA case-sensitivity note. The description only loosely restates customer and overdue filtering and adds no format or edge-case detail beyond the schema, so the baseline of 3 applies.

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

Purpose4/5

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

Names a specific resource (open A/R invoices) and defines the key computed field as DocTotal - PaidToDate, which tells an agent exactly what it will get back. It is less explicit about how it differs from close siblings like get_customer_balance or get_open_sales_orders, so it stops short of a 5.

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 phrase 'optionally for one customer or only overdue ones' hints at when the optional parameters apply, but there is no explicit when-to-use or when-not-to-use guidance and no mention of the sibling tools (e.g. get_customer_balance, get_open_sales_orders) that an agent might otherwise pick.

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

get_open_sales_ordersGet open sales ordersA
Read-onlyIdempotent

Open (not closed, not cancelled) sales orders, optionally for one customer, newest first.

NameRequiredDescriptionDefault
limitNoMax rows to return (1-50, default 20)
fieldsNoSubset of fields to return. Allowed: DocEntry, DocNum, CardCode, CardName, NumAtCard, DocDate, DocDueDate, DocTotal, DocCurrency, PaidToDate, DocumentStatus
cardCodeNoCardCode (exact code, case-sensitive on HANA)

TDQS

A3.8/5.0
Behavior4/5

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

The annotations already declare the operation as read-only, idempotent, open-world, and non-destructive. The description adds meaningful context by defining 'open' as not closed and not cancelled, and by stating the default ordering is newest first.

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 compact sentence with no wasted words. The key scope and ordering information is front-loaded and easy to parse.

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 read-only list tool with rich annotations and complete schema documentation, the description covers the essential scope and behavior. It could say slightly more about result shape or pagination expectations, but nothing critical is missing.

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 limit, fields, and cardCode are already fully documented in the schema. The description reinforces that customer filtering is optional but does not add syntax, edge cases, or other meaning beyond the schema.

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 states the resource ('sales orders') and scope ('open, not closed, not cancelled'), which distinguishes it from read-only invoice tools. It does not explicitly name sibling alternatives, but the resource and status are specific enough for an agent to identify the operation.

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?

It implies usage by saying the results can be optionally filtered for one customer and are returned newest first. However, it does not state when to use this tool instead of siblings like get_open_invoices or run_saved_query, nor does it give exclusions.

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

get_stock_by_warehouseGet stock by warehouseB
Read-onlyIdempotent

In-stock, committed, ordered and available quantity per warehouse for one item (from ItemWarehouseInfoCollection).

NameRequiredDescriptionDefault
itemCodeYesItemCode (exact code, case-sensitive on HANA)
includeEmptyNoInclude warehouses with zero stock (default false)
warehouseCodeNoOnly this warehouse (WhsCode)

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint and non-destructive behavior, so the safety profile is covered structurally. The description adds genuine context by naming the underlying collection (ItemWarehouseInfoCollection), which hints at data provenance and result shape, but says nothing about error behavior for unknown item codes or how empty warehouses are handled at the response level.

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?

A single dense sentence with no filler, and the resource is front-loaded ahead of the qualifier ('from ItemWarehouseInfoCollection'). Slightly awkward phrasing but zero waste.

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?

With no output schema, the description carries the return-value burden and does so by listing the four quantity measures, which is the key thing an agent needs. Missing only edge-case notes (unknown item, empty result set) for a lookup tool that is otherwise straightforward.

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 itemCode, includeEmpty and warehouseCode are already documented in the schema. The description only restates the 'one item / per warehouse' scoping, adding no format, case-sensitivity or default details beyond what the schema provides. Baseline 3 applies.

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 names the exact resource (per-warehouse stock quantities for a single item) and enumerates the returned measures (in-stock, committed, ordered, available), so an agent can distinguish it from get_item. It doesn't explicitly name a sibling it is not, so it stops short of a 5.

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?

There is no when-to-use guidance and no routing to alternatives such as get_item or search_items when the agent has a partial code. Usage is only implied by 'for one item', leaving the agent to infer when this tool beats the broader item lookup.

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

run_saved_queryRun saved queryA
Read-onlyIdempotent

Run a query that an administrator pre-registered in the saved-queries config file. No free SQL or free filters are accepted. Available: customers_over_balance: Customers whose account balance is above a threshold, highest first; invoices_due_before: Open A/R invoices due before a date; sales_by_month: Net A/R sales per month for a year (needs SQLQueries entry KN_SALES_BY_MONTH created by your admin)

NameRequiredDescriptionDefault
nameYesSaved query name
limitNoMax rows to return (1-50, default 20)
paramsNoParameters declared by that saved query

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare read-only, idempotent, non-destructive, open-world behavior, so the bar is lower. The description adds genuinely new behavioral context: the query set is fixed by an administrator in a config file, arbitrary SQL/filters are rejected, and sales_by_month additionally requires a KN_SALES_BY_MONTH entry to exist. It does not say what happens when an unregistered name or undeclared param is supplied.

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?

Front-loaded with the core constraint (pre-registered only, no free SQL) before the catalog, and every clause carries information. The dense single-sentence catalog is slightly harder to scan than a list would be, but nothing is redundant.

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?

There is no output schema, and the description does not describe the shape of returned rows, though "highest first" hints at ordering for one query. For a tool with a nested free-form params object, the missing param key names and unspecified behavior on an invalid name leave real gaps for correct invocation.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3, but the description meaningfully upgrades the schema: the schema types "name" as a bare string with no enum, and the description supplies the closed list of three valid values. It also clarifies that "params" must match the declaration of the chosen query rather than being free-form, though it never states the actual param key names (threshold, date, year) an agent must pass.

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?

States a specific verb and resource ("Run a query that an administrator pre-registered") and then enumerates the exact closed set of allowed query names with a one-line meaning for each. This immediately separates it from the sibling tools, which are direct entity getters rather than pre-registered, parameterized queries.

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?

"No free SQL or free filters are accepted" plus the admin-config prerequisite gives a clear condition for use and rules out ad-hoc filtering attempts. It stops short of naming a sibling to fall back on (e.g., use get_open_invoices for a plain listing), so the routing guidance is one-sided.

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

search_business_partnersSearch business partnersA
Read-onlyIdempotent

Search business partners whose CardCode or CardName contains the text. Optionally filter by type.

NameRequiredDescriptionDefault
typeNo
limitNoMax rows to return (1-50, default 20)
queryNoText contained in CardCode or CardName
fieldsNoSubset of fields to return. Allowed: CardCode, CardName, CardType, GroupCode, Phone1, EmailAddress, City, Country, Currency, FederalTaxID, Valid, Frozen

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so safety is covered without the description's help. The description adds real value in disclosing the matching rule (substring contained in CardCode OR CardName), which is behavior beyond the annotations. It does not disclose result ordering, case sensitivity, or whether inactive/frozen partners are included, which matter for a search 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?

Two short sentences, front-loaded with the primary matching rule and followed by the optional refinement — no filler. It is perhaps too terse for a tool with four parameters, but nothing is wasted or buried.

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 fully read-only, and annotations plus the schema cover the safety profile and most parameters, so the bar is modest. Still missing for correct invocation: behavior with an empty or omitted query (return everything capped at limit?), case sensitivity, and result ordering — all relevant to a free-text search over a large partner master.

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

Parameters4/5

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

Schema coverage is 75% and the description reinforces the query semantics ('contains') and defines the purpose of the type filter, whose enum values carry no description in the schema. It adds little for limit and fields, but those are already self-describing in the schema, so the description complements rather than duplicates.

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?

States a specific verb and resource ('Search business partners') plus the exact match semantics (substring on CardCode or CardName) and an optional type filter. This implicitly distinguishes it from the sibling get_business_partner (exact single-record lookup), but it never names the sibling or draws the contrast explicitly.

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?

Usage is only implied: an agent can infer this is the tool for partial-text/exact-prefix lookup, and the 'optionally filter by type' clause hints at narrowing. There is no guidance on when to prefer get_business_partner, what happens with an empty query, or how to page beyond the limit, so the agent must infer the boundary conditions.

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

search_itemsSearch itemsA
Read-onlyIdempotent

Search items whose ItemCode or ItemName contains the text.

NameRequiredDescriptionDefault
limitNoMax rows to return (1-50, default 20)
queryNoText contained in ItemCode or ItemName
fieldsNoSubset of fields to return. Allowed: ItemCode, ItemName, ItemsGroupCode, BarCode, InventoryItem, SalesItem, PurchaseItem, InventoryUOM, QuantityOnStock, QuantityOrderedFromVendors, QuantityOrderedByCustomers, Valid, Frozen
inStockOnlyNoOnly items with QuantityOnStock > 0

TDQS

A3.5/5.0
Behavior3/5

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

The annotations already declare readOnlyHint, idempotentHint, non-destructive and openWorld, so the safety profile is covered. The description adds the matching semantics (containment on ItemCode or ItemName) beyond the annotations, which is useful, but says nothing about case sensitivity, result ordering, or what happens when the limit truncates a larger result set.

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 sentence with no filler, and the most important information (what is searched, and on which fields) is front-loaded. Nothing in it could be removed without losing meaning.

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?

With four optional parameters, full schema coverage and no output schema, the description is close to sufficient, but it leaves real ambiguity: whether matching is case-sensitive or tokenized, whether results are ordered, and how the default limit of 20 interacts with a broad query. For a search tool these are the details an agent most 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?

Schema description coverage is 100%, so limit, query, fields and inStockOnly are all documented in the schema itself. The description restates the query semantics that the schema already gives and adds nothing about the other three parameters; baseline 3 is appropriate when the schema does the heavy lifting.

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 names a specific verb ("Search") and resource ("items") and states the matching rule: substring match on ItemCode or ItemName. That is enough to distinguish it from get_item (key lookup) by implication, but it never names the sibling explicitly, so the differentiation is inferred rather than stated.

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?

Usage is only implied: the agent must infer that this tool is for partial-text lookup while get_item is for exact retrieval. There is no explicit when-to-use guidance, no mention of when not to use it, and no reference to search_business_partners as the analogous tool for a different resource.

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. 9 tool updatesv0.1.0
    • First observedget_business_partner
    • First observedget_customer_balance
    • First observedget_item
    • First observedget_open_invoices
    • First observedget_open_sales_orders
    • First observedget_stock_by_warehouse
    • First observedrun_saved_query
    • First observedsearch_business_partners
    • First observedsearch_items

TDQS

A3.7/5.0

Scored across 9 tools

Disambiguation4/5

The get_by_exact_key vs search_by_text split is clean and consistent across business partners and items, and the transactional tools (open orders, open invoices, stock by warehouse) target distinct resources. The only fuzziness is between run_saved_query's pre-built queries (customers_over_balance, invoices_due_before) and the single-record tools get_customer_balance/get_open_invoices, which an agent could pick wrongly, though the descriptions differentiate them.

Naming Consistency5/5

All names are snake_case with a leading verb (get_, search_, run_), and the pattern maps predictably to intent: get_ = exact-key fetch, search_ = text lookup, get_open_* = filtered document lists. No mixed conventions or vague verbs.

Tool Count5/5

Nine tools is well within the sweet spot and each covers a distinct read pattern (master data, balances, stock, open documents, canned reports). Nothing looks padded or redundant.

Completeness3/5

The server is coherently read-only, but the document surface stops at list level: there is no tool to fetch a single sales order or invoice with its line details, no price-list/item-warehouse-adjacent lookups beyond the one stock call, and no purchase-side coverage. run_saved_query is an admin-gated escape hatch rather than a general remedy, so agents will hit dead ends when drilling into a document.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with SAP Business One via Service Layer REST API to retrieve and create business data such as partners, orders, invoices, items, and stock levels through natural language.
    1
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Read-only MCP server that exposes SAP Business One Service Layer and Cisco CCWR contract search APIs for querying sales orders, delivery notes, business partners, and service contracts, without modifying data.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants like Claude, ChatGPT, and Copilot to access SAP Business One, S/4HANA Cloud, and Concur data through MCP tools for partners, orders, invoices, expense reports, and more.
    AGPL 3.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Connects SAP Business One to Claude, ChatGPT, and Copilot, providing 12 MCP tools to read business partners, items, sales orders, invoices, quotations, and delivery notes, and to create sales orders.
    AGPL 3.0