{"record":{"id":"cefe7a61fac8385f","repo":"nicolargo/glances","slug":"glancesmcpserver-stats-manager-is-not-yet-initial","errorCode":null,"errorMessage":"GlancesMcpServer: stats manager is not yet initialized. Call set_stats() before serving MCP requests.","messagePattern":"GlancesMcpServer: stats manager is not yet initialized\\. Call set_stats\\(\\) before serving MCP requests\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"glances/outputs/glances_mcp.py","lineNumber":170,"sourceCode":"        Otherwise each hostname is converted to a \"host:*\" pattern (any port)\n        and paired with http/https origin patterns.\n        \"\"\"\n        if self.mcp_allowed_hosts == [\"*\"]:\n            return TransportSecuritySettings(enable_dns_rebinding_protection=False)\n\n        # Append :* to plain hostnames so the middleware matches any port.\n        allowed_hosts = [h if \":\" in h else f\"{h}:*\" for h in self.mcp_allowed_hosts]\n        allowed_origins = [f\"http://{h}\" for h in allowed_hosts] + [f\"https://{h}\" for h in allowed_hosts]\n        return TransportSecuritySettings(\n            enable_dns_rebinding_protection=True,\n            allowed_hosts=allowed_hosts,\n            allowed_origins=allowed_origins,\n        )\n\n    def _get_stats(self):\n        \"\"\"Return the stats manager, raising RuntimeError if not yet set.\"\"\"\n        if self._stats is None:\n            raise RuntimeError(\n                \"GlancesMcpServer: stats manager is not yet initialized. Call set_stats() before serving MCP requests.\"\n            )\n        return self._stats\n\n    def _serialize(self, data) -> str:\n        \"\"\"Return a UTF-8 JSON string using Glances' custom serializer.\n\n        Glances' json_dumps handles non-standard numeric types and datetime\n        objects that the stdlib json module cannot encode out of the box.\n        \"\"\"\n        return json_dumps(data).decode(\"utf-8\")\n\n    # ------------------------------------------------------------------\n    # Resources\n    # ------------------------------------------------------------------\n\n    def _setup_resources(self):\n        \"\"\"Declare all MCP resources on the FastMCP instance.\"\"\"","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/nicolargo/glances/blob/a240d8dfb3105a38b5964357ec21768594b0e83e/glances/outputs/glances_mcp.py#L152-L188","documentation":"Every MCP resource/tool in GlancesMcpServer (plugins_list, all_stats, plugin_stats, plugin_history, plugin_limits, all_limits) calls _get_stats(), which raises RuntimeError if the stats manager was never injected via set_stats(). This is an internal wiring invariant: the server was constructed but not attached to a live Glances stats loop.","triggerScenarios":"Programmatically creating GlancesMcpServer(stats=None) (or omitting stats) and then serving MCP requests; any integration that builds the server manually and forgets set_stats(). Note the constructor stores stats positionally, so passing None explicitly or constructing before stats exist triggers it.","commonSituations":"Embedding Glances' MCP server into a custom script; test harnesses instantiating the server standalone; version upgrades changing the init signature.","solutions":["Pass the stats manager when constructing: GlancesMcpServer(stats, args, config).","Or call server.set_stats(stats_manager) before run()/serve().","When using the documented --mint CLI path, ensure you're on a Glances version where the entrypoint wires stats automatically; report a bug if the CLI path hits this."],"exampleFix":"# before\nserver = GlancesMcpServer(None, args, config)\nserver.run()\n\n# after\nserver = GlancesMcpServer(stats, args, config)\n# or: server.set_stats(stats)\nserver.run()","handlingStrategy":"validation","validationCode":"assert server._stats is not None or stats_manager is not None, 'call set_stats() before serving'","typeGuard":null,"tryCatchPattern":"try:\n    stats = server._get_stats()\nexcept RuntimeError:\n    server.set_stats(stats_manager)  # late-bind then retry","preventionTips":["Always construct GlancesMcpServer with the live stats manager, or call set_stats() before run().","In tests, stub a stats manager rather than passing None."],"tags":["mcp","initialization-order","internal-invariant"],"backgroundTag":"server-not-initialized","analyzedSha":"a240d8dfb3105a38b5964357ec21768594b0e83e","analyzedAt":"2026-08-27T19:15:19.178Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}