MCP client
Cursor
Command or phase
Other
Namespace affected
Multiple namespaces
Environment
_find_operation in src/generators/tool_generator.py looks up an operation by name with no namespace scoping:
def _find_operation(self, operation_id):
for op in self.operations:
if op.registered_name == operation_id:
return op # first match across ALL namespaces
raise KeyError(...)
self.operations is the flat list of every namespace's operations, so this returns the first match regardless of which namespace it belongs to. get_operation_schema then caches the result keyed by operation_id alone, so the first answer is used for the life of the process.
resolve_collisions runs per file. extract_operations is called once per namespace YAML in load_operations_from_yamls, so it only de-duplicates operationIds within a single namespace. If the same bare operationId appears in two namespace specs, both keep the plain operationId as their registered_name, and the global first-match decides the winner. Files load in sorted order, so the alphabetically-earlier namespace wins.
getOperationSchema
getCodeSample
getOperationPermissions
All call _find_operation so all are affected. This will never show up in a single-namespace test.
The SchemaResolver has a related problem for shared model names. combined_schemas is built by update() across all namespace files (last writer wins), and $ref is cached by bare ref name, so a component schema defined in two namespaces resolves to whichever file loaded last. That can hand the model the wrong body shape for a common name across specs.
Suggestions:
- Key
_find_operation and the schema cache on (namespace, operation_id) rather than operation_id alone.
- Scope
SchemaResolver and its $ref cache per namespace as well, so a shared model name in one spec cannot overwrite another.
Steps to reproduce
- Create an artifacts directory with two namespace specs that share one operationId. clustermgmt sorts before vmm, so clustermgmt will win.
clustermgmt-v4.0-all-documentation.yaml:
openapi: 3.0.0
paths:
/clustermgmt/v4.0/config/disks/{extId}:
get:
operationId: getDiskById
summary: Get a cluster disk by ID
vmm-v4.0-all-documentation.yaml:
openapi: 3.0.0
paths:
/vmm/v4.0/ahv/config/vms/{vmExtId}/disks/{extId}:
get:
operationId: getDiskById
summary: Get a VM disk by ID
- Point the server at that directory and ask for the schema of the vmm operation:
from src.config import Settings
from src.server import build_runtime_dispatcher
settings = Settings(pc_host=None, artifacts_dir=<dir above>, default_artifacts_dir=<empty dir>)
dispatcher = build_runtime_dispatcher(settings)
print(dispatcher.call_tool("getOperationSchema", {"operation": "getDiskById"}).payload)
Expected behavior
For a vmm disk lookup, the schema shows path /vmm/v4.0/ahv/config/vms/{vmExtId}/disks/{extId} with both vmExtId and extId path parameters.
Actual behavior
The payload shows the clustermgmt operation instead: path /clustermgmt/v4.0/config/disks/{extId}, summary "Get a cluster disk by ID", and only the extId parameter. _find_operation returned the first getDiskById in the flat list, which is the alphabetically earlier clustermgmt spec.
MCP client
Cursor
Command or phase
Other
Namespace affected
Multiple namespaces
Environment
_find_operationinsrc/generators/tool_generator.pylooks up an operation by name with no namespace scoping:self.operationsis the flat list of every namespace's operations, so this returns the first match regardless of which namespace it belongs to.get_operation_schemathen caches the result keyed byoperation_idalone, so the first answer is used for the life of the process.resolve_collisionsruns per file.extract_operationsis called once per namespace YAML inload_operations_from_yamls, so it only de-duplicates operationIds within a single namespace. If the same bareoperationIdappears in two namespace specs, both keep the plain operationId as their registered_name, and the global first-match decides the winner. Files load in sorted order, so the alphabetically-earlier namespace wins.getOperationSchemagetCodeSamplegetOperationPermissionsAll
call _find_operationso all are affected. This will never show up in a single-namespace test.The SchemaResolver has a related problem for shared model names.
combined_schemasis built byupdate()across all namespace files (last writer wins), and$refis cached by bare ref name, so a component schema defined in two namespaces resolves to whichever file loaded last. That can hand the model the wrong body shape for a common name across specs.Suggestions:
_find_operationand the schema cache on (namespace, operation_id) rather thanoperation_idalone.SchemaResolverand its$refcache per namespace as well, so a shared model name in one spec cannot overwrite another.Steps to reproduce
Expected behavior
For a vmm disk lookup, the schema shows path
/vmm/v4.0/ahv/config/vms/{vmExtId}/disks/{extId}with bothvmExtIdandextIdpath parameters.Actual behavior
The payload shows the clustermgmt operation instead:
path /clustermgmt/v4.0/config/disks/{extId}, summary "Get a cluster disk by ID", and only the extId parameter._find_operationreturned the firstgetDiskByIdin the flat list, which is the alphabetically earlier clustermgmt spec.