Nobody says that your tools declaration must be hardcoded – you can resolve them at runtime. MCP simply describes convention on how to do it. The benefit is that you can write your own provider this way and if you follow this convention anybody can use it easily similarly to how people can use published packages (npm, python package etc.) that follow their publish/consume conventions.
Their config manifest is like package.json's dependencies.
Their init is like import resolution.
Jsonrpc methods are like exported functions in package.
Json schema declarations are like type declarations (ie. .d.ts) files.
In your config manifest you specify "imports" that llm can use and it handles populating tools - it's like npm for llm sessions.