This MCP server provides 27 tools for Newline banking API integration, but suffers from pervasive quality gaps across naming, descriptions, schemas, and error handling. While most tools follow a consistent verb_noun pattern (list-*, get-*, create-*, delete-*), descriptions are generic and parameter documentation is minimal. The majority of tools (25 of 27) have empty input schemas ({}), meaning parameters exist in the API but are not exposed to the LLM. Two tools (create-synthetic-account, list-customers) expose complex nested schemas, but most lack depth. Error handling is not visible in the source code, there is no evidence of recovery guidance, error classification, or actionable messages. The server does not implement tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite having clear risk profiles (READ_ONLY, WRITE, DESTRUCTIVE). Overall, this is a data-access wrapper that prioritizes API transparency over LLM usability.
25 of 27 tools have empty input schemas ({}), meaning available parameters and filtering options are not exposed to the LLM. Tools like list-customers, list-synthetic-accounts, and list-custodial-accounts likely support pagination, filtering, and sorting, but the schema does not declare them. This forces LLMs to call tools with no parameters or to guess parameter names, and requires source code inspection to discover capabilities.
Tool descriptions are generic and under 50 characters (baseline: avg 194 chars for A+ tools). E.g., 'Get a list of combined transfers' and 'Get details for a specific combined transfer' provide minimal context about when to call which tool, what filters are available, or what the response contains. LLMs cannot distinguish between similar tools (list_* vs describe_*) without richer descriptions.
Recommendations
Expand tool descriptions from ~30 chars to 100-200 chars. Include: what the tool does, when to use it instead of a similar tool, what structure it returns, and any prerequisites. Example: 'List all customers with optional filtering by UID, status, KYC status, customer type, or business name. Returns paginated results (default 20 per page). Use this to discover customer UIDs before calling get-customer for detailed info.'
Expose all supported parameters in input schemas with proper type declarations and descriptions. For list-customers, declare uid, status, kyc_status, customer_type, first_name, last_name, email, locked, program_uid, business_name, external_uid, pool_uid, limit, offset, sort, and include_initiated as schema properties with type, description, and constraints (e.g., limit: 1-100, offset >= 0, sort enum: asc|desc).
Add tool annotations: mark all READ_ONLY tools with readOnlyHint=true, create-synthetic-account with no annotation (WRITE is implicit), and delete-synthetic-account with destructiveHint=true. This signals to the LLM which tools are safe to call speculatively and which require confirmation.
Document output schemas in tool descriptions or separate schema references. Example: 'Returns: { uid: string, name: string, status: enum(active|inactive|suspended), created_at: ISO8601, pool_uid: string, ... }'
Add parameter descriptions to all uid fields. Specify the format (e.g., 'UUID v4 string', 'alphanumeric 20-char token') and explain how to obtain it (e.g., 'from the uid field in list-customers response'). This enables tool chaining without LLM guessing.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are missing despite explicit risk profiles. create-synthetic-account is marked WRITE, delete-synthetic-account is marked DESTRUCTIVE, and 25 tools are marked READ_ONLY. These should be declared as tool annotations so the LLM understands the safety profile and can plan accordingly.
No parameter descriptions for uid fields. Tools like get-combined-transfer, get-customer, get-synthetic-account accept a 'uid' parameter, but the parameter description is minimal ('The combined transfer UID') and provides no format guidance (e.g., is it a UUID, alphanumeric string, or opaque token?). LLMs cannot determine if a uid from list-customers can be passed directly to get-customer.
No evidence of error handling or recovery guidance in source code. The index.ts and service implementations do not show error categorization, actionable messages, or retry guidance. E.g., if get-customer receives an invalid uid, the LLM has no hint to try list-customers first or what field to search by.
list-customers exposes complex nested parameter schema (16 optional filters: uid array, status array, kyc_status array, etc.) but lacks any descriptions for most parameters. Field names are self-documenting (kyc_status, customer_type) but format constraints, examples, and mutual-exclusivity rules are missing. This invites incorrect filter construction by LLMs.
Output schemas are not documented in the MCP server definitions. Neither the tool descriptions nor the source code visible here defines what fields are returned by list-customers, get-customer, create-synthetic-account, etc. LLMs must infer response structure from tool names alone.
No pagination guidance in list_* tools. list-customers accepts 'limit' and 'offset' parameters but they are not declared in the schema. Baseline expectation is that discovery tools accept page/offset and limit and document result caps. Without pagination info, LLMs may request excessive results or not understand how to iterate.
create-synthetic-account has a deeply nested schema with optional objects (instant_payment, wire, ach) but no documentation of mutual exclusivity or required-one-of constraints. The description 'Create a synthetic account for newline' does not explain which payment method objects should be supplied or how to choose between them.
create-synthetic-account
Implement error handling with actionable messages. For 404 responses, return 'Customer UID not found. Call list-customers to discover valid UIDs.' For 400 invalid-parameter responses, return 'Invalid status value: got "active_pending". Must be one of: active, inactive, suspended, locked.'
For create-synthetic-account, document the payment method selection logic. Example: 'Supply exactly one of instant_payment, wire, or ach. instant_payment requires counterparty_address and counterparty_name. wire requires counterparty_name, counterparty_bank_name, and counterparty_bank_address. ach requires account_type and counterparty_name.'
Declare pagination support explicitly in list_* tool descriptions. Example: 'Supports pagination via limit (1-100, default 20) and offset (0-indexed, default 0). Response includes total_count and next_offset for continuation.'
Add descriptions to boolean and enum-like parameters. Example: for list-customers locked field, describe: 'If true, filter for locked accounts. If false, filter for unlocked. If omitted, return all.' For sort, describe: 'Sort order: asc (ascending by uid) or desc (descending). Default: asc.'
Consider adding helper discovery tools if the API supports it: search-customers-by-name (accepts first_name, last_name, business_name and returns condensed results) to reduce the LLM's need to construct complex filter objects.