Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
bloodyad-mcp suffers from fundamental definition quality issues across nearly all 18 tools. While tool names follow verb_noun convention and most descriptions exist, they are severely underdeveloped. Parameter descriptions are generic placeholders (e.g., 'Target host', 'Domain name', 'Username for authentication') with NO guidance on format, constraints, required values, or relationships. No input schemas are explicitly visible in the source code, schemas are inferred from the @mcp.tool() decorator signatures in Python, but the actual JSON Schema structures are not defined or validated. No output schemas are documented. Many parameters accept string types that should be enums (e.g., auth_format, otype, right, expire). Critical security parameters like passwords are exposed as function arguments rather than injected server-side. Error handling is minimal, tools return raw exceptions as strings ('Error: {e}') with no recovery guidance. Across all 18 tools, there is no evidence of: input validation, explicit enum constraints, dependency documentation between parameters, pagination support, result limits, or destructive operation confirmations. The codebase shows connection caching but no per-tool security gates, permission declarations, or audit logging. Most tools lack any guidance on when to call them vs similar tools.
No explicit JSON Schema definitions visible in source code. All 18 tools rely on Python type hints without formal schema registration. Tool input structures are inferred from function signatures, not declaratively defined. This violates pattern:tool and makes schema validation unreliable.
Passwords exposed as tool parameters (bloodyad_get_object, bloodyad_get_children, bloodyad_set_password, all 18 tools). Credentials should be injected server-side via environment or vault, not passed in function arguments. Agent traces will log these values.
Recommendations
Add explicit JSON Schema definitions for all 18 tools. Move beyond Python type hints to declarative schema with type, description, enum (where applicable), minLength, maxLength, pattern for each parameter.
Remove password/credential parameters from all tool signatures. Implement server-side secret injection: read credentials from environment variables (e.g., BLOODYAD_USER, BLOODYAD_PASSWORD) or a vault at startup, then pass them to get_connection() internally.
Expand parameter descriptions to 50 - 150 characters each. Include format expectations, valid value ranges, and constraints. Example: 'auth_format (string): Authentication method. Valid: "default", "simple", "gssapi". Default: "default".'
Define enum constraints for categorical parameters: auth_format (default|simple|gssapi), otype (user|group|computer|ou), right (write|modify|delete), expire (true|false). This prevents LLM hallucination and makes constraints machine-parseable.
Document output schemas for every tool. Example: bloodyad_get_object returns {status: string, object: {dn: string, attributes: {[key]: [values]}}}. Include which fields are always present vs optional.
Add confirm/dry-run parameters to destructive operations (bloodyad_set_password, bloodyad_remove_object, etc.). Example: bloodyad_set_password(target, new_password, confirm=false) returns a confirmation step before executing.
Replace raw exception strings with structured error responses: {error: string, error_code: string, recoverable: boolean, next_steps: string}. Categorize errors (CONNECTION_FAILED, AUTH_FAILED, INVALID_DN, PERMISSION_DENIED, etc.) with actionable guidance.
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Generic parameter descriptions throughout. Examples: 'Target host', 'Domain name', 'Username for authentication', 'Target user DN', 'New password'. No guidance on format, validation rules, constraints, or how values relate to each other.
No enum constraints on categorical parameters. auth_format, otype, right, expire, resolve_sd, secure_ldap are all free-form strings. Should declare valid values as enums to let LLMs pick from constrained sets and prevent hallucinated invalid options.
No output schemas documented. All 18 tools return JSON strings via format_output(), but the structure of that JSON is never specified. LLMs cannot reliably parse responses or chain them to downstream tools. Example: bloodyad_get_search returns a formatted result, but the schema of that result (fields, types, pagination) is invisible.
Destructive operations (bloodyad_set_password, bloodyad_set_owner, bloodyad_set_rbcd, bloodyad_set_spn, bloodyad_set_dontexpire, bloodyad_add_user_to_group, bloodyad_remove_user_from_group, bloodyad_remove_object) have no confirmation step, dry-run, or explicit warning in descriptions. LLMs can invoke irreversible changes without safeguards.
Error responses are raw exception strings: 'Error: {e}'. No categorization (retryable vs fatal), no recovery guidance, no actionable error messages. Example: instead of 'Error: [Errno 111] Connection refused', respond 'Connection failed to host example.com:389. Verify host is reachable and LDAP port is open. Check network connectivity.'
No permission gates or scope declarations. Tools like bloodyad_remove_object are callable without checking if the calling agent/user has authority to delete. No audit logging of who called what tool when.
No input validation. Parameters like 'target' (LDAP DN) have no format validation. 'kerberos_args' is an unbounded array with no size limits. 'page_size' not configurable on list tools. Unbounded inputs can cause timeouts or buffer exhaustion.
No pagination support on list/search tools. bloodyad_get_children, bloodyad_get_search, bloodyad_get_writable can return large result sets without limit or offset parameters. Large responses blow context window and degrade LLM reasoning.
Tool descriptions do not indicate when to use each tool vs similar ones. Example: bloodyad_get_children and bloodyad_get_search both query LDAP but lack guidance on which to choose for a given task. Descriptions should state prerequisites and decision factors.
Add permission checks before executing tools. Example: bloodyad_remove_object should verify the calling user has delete permission on the target object before executing. Log all attempts (success and failure).
Add pagination to list/search tools: bloodyad_get_children(target, otype, limit=20, offset=0), bloodyad_get_search(base, filter, attr, limit=20, offset=0). Return {items: [...], total: N, next_offset: M} to enable result iteration without context explosion.
Add input validation: validate DN format, bound array sizes, timeout handling for slow LDAP servers, rate limiting to prevent runaway agent loops.
Enhance tool descriptions to clarify use cases and decision factors. Example: 'bloodyad_get_object: Retrieve attributes of a single LDAP object. Use this when you know the exact DN. If searching by name or filter, use bloodyad_get_search() instead.'
Add tool annotations (readOnlyHint, destructiveHint) to the @mcp.tool() decorators to signal to LLMs which tools are safe to retry and which require confirmation.
Document dependency relationships between parameters. Example: 'If resolve_sd=true, the response will include security descriptor details (slower). Only use if needed for permission analysis.'
Return IDs and references that downstream tools accept. Example: bloodyad_get_children should return the DN of each child so bloodyad_get_object can be called directly with that DN.
Add rate limiting and timeout guards: set max retries, exponential backoff for transient failures, and explicit timeout errors with guidance to retry later.