Roma is a powerful remote operations management tool for managing SSH servers, databases, Docker, Windows, routers, switches, and other network resources via SSH terminal or REST API
Static source inference · medium confidence · detected: HTTP+SSE transport
Deprecated protocol patterns detected
Summary
ROMA exposes 51 tools with significant quality gaps across naming, descriptions, and schemas. While tool names follow a verb_noun pattern (GetDatabaseConnectionInfo, ExecuteDockerCommand), descriptions are uniformly generic and underdeveloped (40-80 chars, below the 194-char baseline). Most critically, NO INPUT SCHEMAS are visible in the provided source code, only parameter names and types are inferred from the handler signatures in core/routers/router.go, not from explicit schema definitions. The server exposes powerful destructive operations (ExecuteDatabaseQuery with WRITE risk, DeleteUserByID, DeleteApikeyByID) without documented error handling, confirmation patterns, or permission gates. No tool annotations (readOnlyHint, destructiveHint, idempotentHint) are present. Output schemas are not documented anywhere. The naming convention is inconsistent: some tools use 'Get' (GetDatabaseConnectionInfo), others use 'List' (GetAllUsers, GetAllRoles), creating ambiguity for LLM tool selection. Several tools combine multiple responsibilities: AddSpaceMember/RemoveSpaceMember operate on the same resource but lack clear chaining. The tool set lacks pagination support despite many list operations (GetAllUsers, GetAllRoles, GetAllResource, GetAllApikeys). Overall, this is a functional API surface wrapped as an MCP server, but tool definitions fall short of production-grade agent requirements.
Tools (51)
AddResourcewriteauth32/100
Add a new resource (database, Docker, router, switch, Windows)
Tool descriptions uniformly underdeveloped (40-80 chars). Baseline: 194 chars. No context on WHEN to use the tool vs alternatives, no prerequisites stated, no guidance for multi-step operations. Example: 'Get database connection information' does not explain when to call GetDatabaseConnectionInfo vs ExecuteDatabaseQuery.
Recommendations
Generate explicit JSON Schema input definitions for all 51 tools and embed them in the MCP protocol handshake. Schema MUST include type, description, enum, pattern, minimum, maximum for every parameter. Do not infer schemas from handler signatures, register them as first-class MCP metadata.
Expand tool descriptions from 40-80 chars to 150-250 chars. Format as: 'WHAT (one sentence action). WHEN (use case vs alternatives). PREREQUISITES (required setup). RETURNS (key output fields).' Example: 'Execute a database query on a connected MySQL/PostgreSQL/SQLite resource. Use this after GetDatabaseConnectionInfo to fetch data or apply changes. Requires a valid resource ID and SQL statement (SELECT, INSERT, UPDATE, DELETE). Returns query result rows or affected row count.'
Add parameter descriptions with constraints. Example for ExecuteDatabaseQuery.query: 'SQL or database query to execute (SELECT, INSERT, UPDATE, DELETE). Max 10KB. Special characters must be escaped. Recommended: use parameterized queries to prevent injection.'
Document output schemas for every tool. Use structured format: '{"type": "object", "properties": {"user_id": {"type": "integer"}, "username": {"type": "string"}, ...}, "required": ["user_id"]}'.
Add tool annotations to MCP tool definitions: readOnlyHint=true for Get* and List* operations; destructiveHint=true for Delete* operations; idempotentHint=true for GetCurrentUser, GetHealth, GetSystemInfo (reading state that does not change).
Add pagination support to all list operations: parameters (limit: 1 - 100, default 20; offset or page_number). Return a response containing {items: [...], total_count: N, has_more: boolean, next_offset/next_cursor: string}.
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on HTTP+SSE-only transport (deprecated) - migrate to Streamable HTTP
Score history
Overall score trend
↑ 29 points across a rubric change (v1 → v2)
29/100
Scored
Grade
Overall
Spec posture
Rubric
2026-09-22
F
29
<=2025-11-25
v2
2026-03-09
F
0
-
v1
destructiveauth30/100
Delete a resource
DeleteRoleByIDdestructiveauth32/100
Delete a role
DeleteUserByIDdestructiveauth32/100
Delete a user account
ExecuteDatabaseQuerywriteauth30/100
Execute a database query on a connected database resource
ExecuteDockerCommandwriteauth30/100
Execute a Docker command on a connected Docker resource
ExecuteRouterCommandwriteauth30/100
Execute a command on a connected router via SSH
ExecuteSwitchCommandwriteauth30/100
Execute a command on a connected network switch
GenerateSSHKeywriteauth32/100
Generate a new SSH key pair for the user
GetAccessLogsread onlyauth33/100
Get access logs for audit purposes
GetAllApikeysread onlyauth28/100
Get list of all API keys
GetAllBlacklistsread onlyauth28/100
Get the IP blacklist
GetAllResourceread onlyauth28/100
Get list of all resources
GetAllRolesread onlyauth28/100
Get list of all roles in the system
GetAllSpacesread onlyauth28/100
Get list of all spaces
GetAllUsersread onlyauth28/100
Get list of all users in the system
GetApikeyByIDread onlyauth33/100
Get a specific API key by ID
GetAuditLogsread onlyauth33/100
Get audit logs for system changes
GetBlacklistByIPread onlyauth33/100
Get blacklist information for a specific IP
GetCredentialLogsread onlyauth33/100
Get credential access logs
GetCurrentUserread onlyauth33/100
Get information about the currently authenticated user
GetDatabaseConnectionInforead onlyauth33/100
Get database connection information for executing queries
GetDatabaseTypesread onlyauth33/100
Get list of supported database types
GetDockerConnectionInforead onlyauth33/100
Get Docker connection information for a Docker resource
GetHealthread only33/100
Get system health status for health checks
GetIPInforead onlyauth33/100
Get information about an IP address
GetMySSHKeyread onlyauth33/100
Get the current user's SSH public key
GetResourceByIDread onlyauth35/100
Get a specific resource by ID
GetRoleByIDread onlyauth35/100
Get a specific role by ID
GetRouterConnectionInforead onlyauth33/100
Get router connection information including SSH and web management details
GetSpaceByIDread onlyauth35/100
Get a specific space by ID
GetSwitchConnectionInforead onlyauth33/100
Get switch connection information for network switch management
GetSystemInforead onlyauth33/100
Get system information and health status
GetUserByIDread onlyauth35/100
Get a specific user by ID
GetWindowsConnectionInforead onlyauth33/100
Get Windows connection information for RDP or WinRM access
No output schemas documented. LLMs cannot infer response structure, breaking downstream tool chaining. E.g., if GetUserByID response does not document a 'user_id' field, UpdateUserByID cannot be called with that ID.
List operations (GetAllUsers, GetAllRoles, GetAllResource, GetAllApikeys, GetAllSpaces, GetAllBlacklists) lack pagination parameters (limit, offset, page_size, next_cursor) and return no total count or next_cursor. Context window risk for large datasets.
No permission scope declarations (e.g., 'read:user', 'write:database', 'delete:resource'). Cannot enforce least-privilege agent configurations or audit who did what.
Multi-responsibility operations: AddSpaceMember + RemoveSpaceMember are complementary but lack documented error handling for constraints (e.g., 'Cannot remove last admin from space'). Tool composition not self-documenting.
AddSpaceMemberRemoveSpaceMember
Implement error recovery guidance. Example: 'If GetUserByID returns 404, call SearchUsers(partial_name) to find the correct user_id first. If CreateUser fails with 'email already exists', call GetUserByEmail(email) to retrieve the existing account.'
Add permission scope declarations to every tool definition. Example: {tool_name: 'DeleteUserByID', scopes_required: ['admin:user', 'write:user'], scopes_implied_by_agents: ['admin:all']}. This enables least-privilege MCP client configuration.
Implement dry-run or confirmation pattern for destructive operations: add boolean parameter (dry_run: true) to DeleteUserByID, DeleteRoleByID, DeleteResource, DeleteApikeyByID. Return 'Would delete X record(s). Call again with confirmation=true to proceed.'
Consolidate conflicting parameter names: ExecuteRouterCommand.command and ExecuteSwitchCommand.command should accept/return structured command results (status, stdout, stderr, exit_code), not plain strings. Document the command syntax (CLI flags, escaping) in parameter description.
For tools that manage related resources (CreateUser → UpdateUserByID → DeleteUserByID), ensure response chaining: CreateUser must return user_id so UpdateUserByID and DeleteUserByID can be called immediately without extra lookup.
Add 'related tools' hints to descriptions. Example GetUserByID description: 'Retrieve a single user record by ID. To list all users, call GetAllUsers. To update, call UpdateUserByID. To delete, call DeleteUserByID.'
Validate inputs early with actionable error messages. Instead of HTTP 500 with stack trace, return: 'Invalid status value. Got "pending_review" but expected one of: open, in_progress, resolved, closed. Did you mean "in_progress"?'
Document idempotency guarantees. E.g., 'CreateApikey is idempotent: calling it twice with the same user_id returns the same key, not a duplicate.' This guides agent retry logic.