Static source inference · medium confidence · evidence: Streamable HTTP
Current-spec patterns detected
Summary
This MCP server exposes 5 banking tools with basic FastAPI endpoints. Tool names follow verb_noun convention (create_account, deposit, withdraw, transactions, balance), which is positive. However, the implementation has significant gaps: (1) No explicit MCP tool registration visible, tool definitions appear to be inferred from HTTP routes rather than formally declared with the MCP SDK, which caps overall confidence; (2) Parameter descriptions exist but are minimal (10-20 chars), below the 50-200 char production baseline; (3) Output schemas are not documented, callers must infer return structure from code inspection; (4) Error handling is basic (HTTPException 404/400) with no recovery guidance; (5) No security considerations visible (no rate limiting, no audit logging, no permission gates for destructive operations); (6) No parameter validation constraints (enums, ranges, patterns) declared. The code shows reasonable database transaction handling (with_for_update locks, rollback on error) but this is implementation detail, not tool-level design. Average per-tool score is 42, reflecting functional naming but weak descriptions and missing schemas.
No explicit MCP tool registration visible in source, tool definitions appear inferred from HTTP routes. Cannot confirm tools are registered with MCP ToolDefinition struct, schemas, and metadata.
Parameter descriptions are too short (10-20 chars). Production baseline is 50-200 chars. E.g., 'Account holder name' (19 chars) and 'The account ID to deposit into' (30 chars) lack context for LLM parameter selection and validation reasoning.
Output schemas not documented. Callers must reverse-engineer return types from code (e.g., create_account returns Account model, deposit returns {'balance': float}). LLMs cannot plan downstream tool calls or extract correct fields without explicit output schema definitions.
create_accountdepositwithdraw
Recommendations
Declare explicit MCP tool definitions using the MCP SDK. Register each tool with ToolDefinition struct containing name, description, inputSchema (with full JSONSchema including min/max/enum constraints), and outputSchema. This is a prerequisite for MCP compliance.
Expand parameter descriptions to 50-150 chars. E.g., 'amount' should be: 'The amount to deposit in USD, positive number. Decimal values (e.g., 100.50) accepted. Must be > 0 and <= 1000000. Transactions over 10000 may incur fees.'
Document all output schemas explicitly. E.g., create_account returns: {id: string (UUID), name: string, email: string, balance: number (default 0.0), created_at: ISO8601 datetime}. Use this in outputSchema field or response description.
Add input validation constraints: (1) amount: minimum 0.01, maximum 1000000, type: number. (2) email: pattern '^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$'. (3) name: minLength 1, maxLength 255. Declare these in the inputSchema and validate in code.
Enhance error messages with recovery guidance. E.g., 'Account with ID "xyz" not found. Verify account_id is correct. To list your accounts, call the get_accounts tool (not yet available, create that first). To create a new account, call create_account with name and email.'
Add a dry-run parameter to withdraw and deposit: 'dry_run: boolean (optional, default false). If true, validate the operation without committing. Useful for agents to preview outcome before executing.'
Implement audit logging. Log all tool calls with: timestamp (ISO8601), caller_id (from request context), tool_name, parameters (omit secrets), result (success/failure), response_code. Use Python logging to stderr or export to external system.
No parameter constraints (enums, min/max, patterns) declared. E.g., 'amount' parameters (deposit/withdraw) accept unbounded numbers, an LLM could pass -1000 or 999999999. No format validation visible for email in create_account.
Error handling lacks recovery guidance. Errors are bare HTTP status codes + messages ('Account not found', 'Insufficient funds'). No suggestion for next steps, no categorization as retryable vs. user-fixable, no alternatives suggested.
Destructive operations (withdraw, deposit modify state) lack confirmation or dry-run support. An agent could accidentally withdraw funds with no undo path documented.
No audit trail visible. Tool calls (especially write operations like create_account, deposit, withdraw) must log who called what, when, and the result for compliance and debugging. Code shows no logging setup.
No rate limiting or request throttling visible. A runaway agent could spam withdraw/deposit calls in a loop, potentially draining accounts or overwhelming the service.
No permission gates visible. Any agent can call withdraw/deposit/create_account. No role-based access control, no scopes, no per-tool permission checks.
Tool descriptions do not declare whether they modify state. 'Deposit money into an account' implies mutation, but 'Get all transactions for an account' is read-only. For safety, all descriptions should explicitly state 'reads', 'creates', 'updates', or 'deletes'.
create_accountdepositwithdraw
Implement rate limiting per-user/agent. E.g., max 100 requests/minute per caller_id. Return 429 Too Many Requests with Retry-After header if exceeded. This prevents runaway retry loops.
Add permission checks to all tools. Define scopes: 'banking:read' (balance, transactions), 'banking:write' (deposit, withdraw), 'banking:admin' (create_account). Verify caller has required scope before executing. Return 403 Forbidden with a clear message if unauthorized.
Add a get_accounts tool (list_accounts) to enable agent discovery: 'Retrieve a paginated list of all accounts for the authenticated user. Returns: accounts (array of {id, name, email, balance, created_at}), total_count (int), next_cursor (string or null).' This follows the tool-chain pattern and reduces lookup failures.
Declare tool annotations in the MCP schema: use readOnlyHint on transactions and balance; use destructiveHint on withdraw, deposit, create_account. This signals to agents which tools are safe to call speculatively.
Add idempotency support to deposit/withdraw. Include an optional 'idempotency_key' parameter (UUID). If the same key is submitted twice, return the cached result instead of creating a duplicate transaction. Log idempotency cache hits.
Return structured, paginated results for transactions tool. Instead of dumping all records, return: {transactions: [{id, account_id, type, amount, created_at}], total_count: int, limit: int, offset: int, next_offset: int or null}. Cap default limit to 20.
Strip sensitive fields from responses. E.g., when creating an account, do not return the database internal created_at if it's not user-relevant. Return only: {id, name, email, balance}. This reduces token waste and confusion.
Specify expected formats for returned dates. Use ISO8601 (e.g., '2025-07-28T14:30:00Z'), not Unix timestamps or epoch milliseconds. LLMs frequently miscalculate timestamp conversions.