{"slug": "how-to-install-an-mcp-server-from-the-official-registry", "title": "How to Install an MCP Server from the Official Registry", "summary": "SAFi, a developer tool, now includes built-in support for installing MCP servers from the official registry, allowing users to search and add servers via command-line scripts. The tool automatically detects the server's ecosystem (e.g., Python or Node) and uses the appropriate launcher, while also supporting remote servers with optional OAuth authentication.", "body_md": "SAFi comes already packaged to handle MCP tool installation, including its own\n\nregistry search, which looks for MCP servers published at the official MCP\n\nregistry, https://registry.modelcontextprotocol.io\n\nTo search for an MCP server is easy. For example, if you want to see whether\n\nSmartsheet has published an MCP server in the registry, you search for it with\n\nthis command.\n\nOn Docker:\n\n```\ndocker compose exec app python scripts/safi_mcp.py search smartsheet\n```\n\nOn bare metal, first move into your SAFi directory and activate the virtual\n\nenvironment, then run the same script:\n\n```\ncd /var/www/safi\nsource venv/bin/activate\npython3 scripts/safi_mcp.py search smartsheet\n```\n\nYour prompt changes to show `(venv)`\n\nonce the environment is active. That is how\n\nyou know it worked. If you skip this step, Python will not find SAFi’s\n\ndependencies and the script will fail before it does anything.\n\nEvery bare-metal command in this post assumes you have done those two lines\n\nfirst. When you are finished, `deactivate`\n\nputs your shell back.\n\nHere is what came back:\n\n```\nio.github.christianclaudio/smartsheet-rm  (package, v1.0.2)  [pypi:mcp-server-smartsheet-rm@1.0.2]\n    MCP server for Smartsheet Resource Management (10,000ft API) time tracking\n    and scheduling.\n\nAdd one with:  scripts/safi_mcp.py add <name>\n```\n\nYou may also see a few `faiss`\n\nlines above that about AVX2 support. Ignore them.\n\nThat is the search index loading and it has nothing to do with MCP.\n\nFour things in that one line tell you what you are dealing with.\n\n** io.github.christianclaudio/smartsheet-rm** is the name you install by. Note\n\n`io.github`\n\nprefix: this is a server published by an individual developer,** (package, ...)** means it runs as a process on your own machine. The other\n\n** v1.0.2** is the version, and it is pinned. Good. A server that updates can\n\n** [pypi:...]** is the ecosystem.\n\n`pypi`\n\nmeans Python and SAFi will launch it`uvx`\n\n. If it said `npm`\n\n, SAFi would launch it with `npx`\n\n. This detailBecause the registry knows the details, you install by name and SAFi works out\n\nthe command:\n\n```\n# Docker\ndocker compose exec app python scripts/safi_mcp.py add io.github.christianclaudio/smartsheet-rm\n\n# Bare metal\npython3 scripts/safi_mcp.py add io.github.christianclaudio/smartsheet-rm\n```\n\n**On a fresh install this will refuse, and that is the system working.** SAFi\n\nchecks that the launcher exists before it writes anything, so you get a message\n\nnaming the missing binary rather than a server that silently never starts:\n\n```\n'uvx' is not on PATH here, so this server could never start.\ninstall uv (pip install uv), which provides uvx.\n```\n\nSAFi ships with Node and `npx`\n\n, so `npm`\n\nservers work out of the box. It does\n\nnot ship `uv`\n\n, so a Python server needs it installed once:\n\n```\n# Bare metal, with the venv active\npip install uv\n\n# Docker, add it to your Dockerfile and rebuild, otherwise it disappears\n# on the next `docker compose up --build`\nRUN pip install uv\n```\n\nThat last point matters on Docker. Installing `uv`\n\ninside a running container\n\nworks until the next rebuild, and then the server stops connecting for a reason\n\nthat looks like nothing to do with you. Put it in the image.\n\nThen run the `add`\n\ncommand again and it will save.\n\nIf your search returns a remote server rather than a package, there is nothing\n\nto install locally. You point SAFi at the URL:\n\n```\n# Docker\ndocker compose exec app python scripts/safi_mcp.py add --url https://mcp.example.com/mcp \\\n    --key example --label \"Example\"\n\n# Bare metal\npython3 scripts/safi_mcp.py add --url https://mcp.example.com/mcp \\\n    --key example --label \"Example\"\n```\n\nSome remote servers support per-user sign-in, so each member connects their own\n\naccount and every call runs as them. Add `--auth oauth`\n\nfor those. To find out\n\nwhether a server offers it, ask the server:\n\n```\ncurl -s https://mcp.example.com/.well-known/oauth-authorization-server\n```\n\nIf that returns a document, use `--auth oauth`\n\n. If it returns nothing, the server\n\ntakes one static credential shared by everybody.\n\nPrefer per-user sign-in whenever the data belongs to a person, which is exactly\n\nthe case with project tools. Each member’s calls then inherit their own\n\npermissions in the source system, appear under their own name in that system’s\n\naudit log, and stop working when they are offboarded. One shared credential is\n\nthe right model for a shared resource, such as an internal pricing service, and\n\nthe wrong one for somebody’s projects.\n\nMost servers need an API token. The server’s own documentation tells you which\n\nenvironment variable it reads. This one wants `SMARTSHEET_RM_API_TOKEN`\n\n.\n\nPass it as a reference, never as the value:\n\n```\n# Bare metal\npython3 scripts/safi_mcp.py add io.github.christianclaudio/smartsheet-rm \\\n    --env SMARTSHEET_RM_API_TOKEN='${SMARTSHEET_RM_API_TOKEN}' \\\n    --env SMARTSHEET_RM_READONLY=true\n```\n\nWrite `${SMARTSHEET_RM_API_TOKEN}`\n\nliterally, exactly as shown, braces and\n\nquotes included. SAFi resolves it from the environment when it connects. The\n\nreal token goes in your `.env`\n\nfile, so the server list stays safe to copy, back\n\nup and share with a colleague.\n\nIf the server offers a read-only switch, as this one does, turn it on for the\n\nfirst install. You can relax it later once you know what the tools return.\n\nThis is the thing to understand before you give a tool to anybody.\n\nA package server is a process on your machine holding one API token. Every\n\nmember’s agents act as whoever owns that token. Everyone sees whatever that\n\naccount can see, the source system’s audit log records that account rather than\n\nthe person who asked, and access does not end when someone leaves the company.\n\nThat is the correct model for a shared resource, such as an internal pricing\n\nservice or a company API. It is the wrong model for “show me my projects”,\n\nbecause there is no “my” in it.\n\nIt does not matter that the service has user logins of its own. Smartsheet has\n\naccounts and permissions, but a local server reaches it with one token, so all\n\nof that collapses into a single identity on the way through.\n\nPer-user sign-in exists in SAFi, and it is the answer to this, but it needs a\n\nremote server that implements the MCP authorization specification. A local\n\nprocess cannot take part. That is why some cards in the Tools Catalog have a**Sign in** button and others do not.\n\nSo choose deliberately. Use a service account with the narrowest permissions\n\nthat still make the tools useful, and enable only read tools to begin with. If\n\nmembers genuinely need their own view of their own data, a shared token is not\n\nthe way to get there.\n\n```\n# Docker\ndocker compose exec app python scripts/safi_mcp.py check\ndocker compose exec app python scripts/safi_mcp.py list\n\n# Bare metal\npython3 scripts/safi_mcp.py check\npython3 scripts/safi_mcp.py list\n```\n\n`check`\n\nconnects to every configured server and reports what it found. `list`\n\nshows what is configured and where it came from.\n\nYou do not need to restart anything. Every write bumps a counter that the\n\nrunning workers watch, so they pick up the new server on their next request.\n\n**“Connected” does not mean authenticated.** When the Tools Catalog shows a\n\nserver as connected, it means the process started and answered SAFi’s question\n\nabout what tools it has. That is a local conversation between SAFi and that\n\nprocess. Nothing has contacted the vendor yet.\n\nSo a server with a missing or wrong API token still shows as connected, with its\n\nfull tool list. You find out on the first real tool call, which comes back as an\n\nauthentication error from the vendor rather than as a connection problem in the\n\ncatalog. The green state is real, it just certifies less than it looks like: the\n\nserver is installed and running, not that it can reach anything.\n\nThis is the step people skip.\n\nInstalling a server puts it in Settings, Tools Catalog, where the server and its\n\ntools are visible and **completely inactive**. Nothing can call them yet.\n\nDiscovery never grants anything.\n\nThree steps make a tool usable:\n\nStart with the read-only tools. Get those working, then decide about anything\n\nthat creates, updates, moves or deletes, and give that one a reviewer.\n\nTwo things to know before you enable a server you did not write. Its tool\n\ndescriptions are written by the publisher and go into the model’s context. And a\n\ntool result becomes part of the governance record, so whatever it returns\n\ninherits that record’s retention.\n\nInstalling an MCP server is done from the shell, by whoever controls the\n\ndeployment. That is the only way, for remote servers as much as for packages.\n\nThere is no admin screen for it and no API route, on purpose.\n\nThe browser installs nothing. Settings, Tools Catalog is where you see what is\n\ninstalled, where members sign in to servers that support it, and where you\n\nconfirm what a server offers. It is not a place to add one.\n\nThis is deliberate rather than unfinished. Installing a server is a decision\n\nabout what code runs next to your data and what leaves your network, and whoever\n\nmakes it should already hold the rights that implies. On a deployment serving\n\nseveral organizations, an admin who could install a server would be making that\n\ndecision for everybody on the host, not just for their own organization.\n\nWhat an organization admin controls is the part that matters day to day: which\n\nof the installed tools their policies enable, and which agents get them.\n\nThere are seven. Everything in this post is one of these.\n\n```\nscripts/safi_mcp.py search <term>     # find servers in the official registry\nscripts/safi_mcp.py add <name>        # install one\nscripts/safi_mcp.py list              # show what is configured, and where from\nscripts/safi_mcp.py check             # connect to everything and report\nscripts/safi_mcp.py disable <key>     # stop connecting, keep the definition\nscripts/safi_mcp.py enable <key>      # start connecting again\nscripts/safi_mcp.py remove <key>      # delete the definition entirely\n```\n\n`disable`\n\nand `remove`\n\nare the pair worth understanding. `disable`\n\nkeeps\n\neverything you configured and just stops SAFi connecting to it, which is what\n\nyou want when a server is misbehaving and you are still working out why.`remove`\n\ndeletes the definition, so reinstalling means retyping the arguments,\n\nthe credentials and the org list.\n\nNeither of them changes what a policy allows. If you remove a server, the tools\n\nit provided simply stop existing, and the Will refuses any call naming them.\n\n`check`\n\ntakes an optional `--key`\n\nto test one server instead of all of them,\n\nwhich is faster when you are debugging a single install.\n\nThe flags on `add`\n\nyou are most likely to need:\n\n```\n--url          a remote server's endpoint, instead of a registry name\n--auth oauth   the server supports per-user sign-in\n--command      the local program to run, for a package server\n--args         comma-separated arguments for --command\n--env          KEY=VALUE for the server process, repeatable\n--key          the short name you will use in every other command\n--label        the display name people see in the tool picker\n--orgs         which organizations may use it, on a shared deployment\n--force        install even if the check fails\n```\n\nOne trap with `--args`\n\n. If your first argument starts with a dash, use the\n\nequals form or argparse reads it as another option:\n\n```\n--args=\"-y,@scope/package@1.2.3\"\n```\n\nUse `--force`\n\nsparingly. The check exists so a server that cannot start fails\n\nnow, while you are looking at it, rather than becoming a mystery next week.\n\nEvery SAFi install ships with a small demo MCP server so you can watch this work\n\nend to end:\n\n```\n# Docker\ndocker compose exec app python scripts/safi_mcp.py add \\\n    --command python --args \"/app/mcp/demo_server.py\" --key demo --label \"Demo Server\"\n\n# Bare metal\npython3 scripts/safi_mcp.py add \\\n    --command python3 --args \"/var/www/safi/mcp/demo_server.py\" --key demo --label \"Demo Server\"\n```\n\nIt has two tools. Install it, enable one of them in a policy, and watch an agent\n\nget exactly that one. Then ask the agent to use the other one, and read the\n\ngovernance record for that turn.\n\nRun it and tell us where it fails.", "url": "https://wpnews.pro/news/how-to-install-an-mcp-server-from-the-official-registry", "canonical_source": "https://dev.to/nelson_amaya_16872e58232b/how-to-install-an-mcp-server-from-the-official-registry-589l", "published_at": "2026-09-01 08:00:05+00:00", "updated_at": "2026-09-01 08:22:15.637863+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools"], "entities": ["SAFi", "MCP", "Smartsheet", "Christian Claudio"], "alternates": {"html": "https://wpnews.pro/news/how-to-install-an-mcp-server-from-the-official-registry", "markdown": "https://wpnews.pro/news/how-to-install-an-mcp-server-from-the-official-registry.md", "text": "https://wpnews.pro/news/how-to-install-an-mcp-server-from-the-official-registry.txt", "jsonld": "https://wpnews.pro/news/how-to-install-an-mcp-server-from-the-official-registry.jsonld"}}