Model or dataset
concierge-hq/concierge avatar
concierge-hq/concierge

Concierge: an MCP SDK that hides tools the agent should not see yet

🚀 Universal SDK for building next-gen MCP servers

528 stars97 forksPythonNOASSERTION

At a glance

What is it?
Concierge wraps an existing MCP server and swaps the tool list per workflow step, so the agent only sees what the current stage allows. The wrap is two lines; the stages and transitions are optional.
Who is it for?
Adopt Concierge if you already run an MCP server and your problem is tool sprawl or agents calling checkout from the browse step: the wrap is two lines and the stages and transitions are additive. Skip it if your server exposes a handful of tools that are all valid at any moment, because the stage map then buys you nothing but a new failure surface.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 114 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: every tool on every request

An MCP server publishes its capabilities through tools/list, and a client asks for that list before it decides what to call. A server with five tools is fine. A server with two hundred tools hands the model two hundred descriptions on every turn, and the model has to pick among them. The README frames the fix as progressive disclosure: "Instead of exposing a flat list of every tool on every request, Concierge progressively discloses only what's relevant." That is the whole pitch, and it is narrower than the repository description ("Universal SDK for building next-gen MCP servers") suggests. Concierge is not a new protocol and not a hosting product. It is a layer that sits between your tool definitions and the MCP client and rewrites what tools/list returns at each point in a workflow.

The audience is therefore specific: teams that already have an MCP server, written with FastMCP or the official mcp package, and that have hit the point where tool selection is unreliable or the context cost of tool descriptions is noticeable. If your server exposes three tools that are all legal at any time, there is nothing here for you. The value appears when tools belong to ordered phases, such as browsing before adding to a cart before paying, and when calling a later-phase tool early is a bug rather than a shortcut.

How the wrapper rewrites tools/list per stage

The mechanism is a decorator-compatible wrapper. The README shows the before and after: a FastMCP instance is passed into Concierge, and the resulting object keeps the same @app.tool() decorators, resources and prompts. What changes is the response to tools/list. The README states the wrapper "dynamically changes which tools are returned by tools/list based on the current workflow step", and adds that the agent and client do not need to know Concierge exists. That last point matters for adoption: you do not have to modify the client, and you do not have to teach the model about stages.

The stage map is a plain dictionary from stage name to a list of tool names, and the transition map is a dictionary from stage name to the list of stages reachable from it. The README's example makes browse reachable only from cart, cart reachable from browse and checkout, and checkout terminal with an empty list. Enforcement happens at the protocol level, so a call to checkout while the session sits in browse is not a prompt-level suggestion the model can ignore. An empty transition list is how you mark a terminal stage, which is a small design detail with a real consequence: a workflow with no terminal stage has no defined end, and the README does not describe what happens to a session that never reaches one.

State is the second mechanism. app.set_state and app.get_state move data between stages without routing it through the model. The README describes state as session-scoped and says it works across distributed replicas, and the repository layout has a state/ directory alongside backends/, which is consistent with pluggable storage. The README does not document which backends are available or what the default is; pyproject.toml lists an optional postgres extra with psycopg2-binary, which is the only state backend dependency visible in the repository files.

Installing concierge-sdk and running the scaffold

The README gives pip as the install path and notes Python 3.9 or newer, recommending uv for dependency resolution. The package on PyPI is concierge-sdk, which is also the name in pyproject.toml. Note that pyproject.toml sets requires-python to ">=3.10" while the README badge and note say 3.9+. Treat the pyproject constraint as the binding one for the published package and check your interpreter before filing a bug about it.

bash
pip install concierge-sdk

After install you get the concierge command, declared in pyproject.toml as the entry point into concierge_cli. The README uses it to generate a runnable project:

bash
concierge init my-store
cd my-store
python main.py

The scaffold writes a project with tools, stages and transitions already wired, and python main.py starts the MCP server over stdio, which is the default transport. If you would rather not scaffold, the README's alternative is to wrap an existing server in two lines. The before and after are literal:

python
from mcp.server.fastmcp import FastMCP
app = FastMCP("my-server")

from concierge import Concierge
app = Concierge(FastMCP("my-server"))

Everything you already registered with @app.tool() keeps working. The wrap alone gives you progressive disclosure only if you then define app.stages; without a stage map there is nothing for the wrapper to filter against. For a web deployment, the README points at a different entry point than app.run(), namely app.streamable_http_app(), and the Dockerfile in the repository exposes port 8000 with concierge-sdk preinstalled at a pinned version.

Semantic search and the hundred-tool ceiling

Stages solve ordering. They do not solve volume inside a single stage. If one stage legitimately contains hundreds of tools, the model is back where it started. The README's answer is a search provider: construct Concierge with a Config whose provider_type is ProviderType.SEARCH and a max_results value, and the entire API collapses behind two meta-tools, search_tools and call_tool. The agent searches by description and then invokes what it found.

This is a real trade-off, not a free win. Two meta-tools mean the model no longer sees tool schemas up front, so it has to form a description-based query before it knows what arguments exist. The README's example sets max_results to 5, which is a recall ceiling: if the right tool is not in the top five matches, the agent cannot call it. The optional extras in pyproject.toml tell you the cost of this path, since the all extra pulls in sentence-transformers and numpy. That is a meaningful dependency footprint for a server that otherwise needs only mcp, httpx and fastmcp. The README does not state which embedding model is used or whether search runs locally or remotely, and it does not describe how search interacts with stages when both are configured.

Where Concierge is the wrong tool

The clearest failure mode is a server whose tools are genuinely independent. Stages impose a directed graph on tool availability, and the README's own example makes the cost visible: in the browse stage, add_to_cart is not in the returned list at all. If your users legitimately jump between operations with no natural order, you have added a state machine that rejects valid calls. The agent sees fewer tools, and some of the calls it used to make now fail at the protocol level.

Second, the wrapper is a single point of failure in the request path. Every tools/list response now depends on the session's current stage, which means the session store is on the critical path. The README claims state is atomic and consistent across distributed replicas, but it does not document the backend, the consistency model or what happens when the store is unreachable. A stateless deployment that previously had no shared dependency now has one.

Third, the repository is not archived, but the last push was on 2026-06-09, which is more than three months before today. The most recent release in the repository is v0.17.0 from 2026-04-17, while pyproject.toml on main still declares version 0.8.0 and the Dockerfile pins CONCIERGE_VERSION to 0.8.0. Those three numbers do not agree, and anyone building a container from the repository Dockerfile without overriding the build arg will install an older release than the one on PyPI. Check the version you actually get before assuming a documented feature is present.

How it differs from running FastMCP directly

The obvious alternative is FastMCP alone, which is already a dependency of concierge-sdk. FastMCP gives you tool registration, resources and prompts, and it returns every registered tool on every tools/list call. Concierge does not replace it; the README's wrapper takes a FastMCP instance as its argument. The difference in approach is where the filtering lives. With FastMCP you control exposure by writing fewer tools, splitting one server into several, or telling the model in the system prompt which tools to prefer. The first two are structural and reliable but coarse, since a split server cannot change its tool list mid-conversation. The third is cheap and unreliable, because a prompt instruction is not enforcement.

Concierge's approach is to keep one server and make the tool list a function of session state. That gives you per-conversation granularity that neither splitting nor prompting offers, at the price of a stage graph you must maintain and a session store you must operate. It also keeps the client untouched, which the split-server approach does not: pointing a client at a different server mid-conversation is not something the MCP client is designed to do. If your ordering rules are simple and few, a system prompt plus disciplined tool naming is less machinery. If an early call to a late tool is a correctness bug, protocol-level enforcement is the only one of these three that actually holds.

Licence, maintenance and upgrade cost

The repository reports the licence as NOASSERTION, which means GitHub could not map the LICENSE file to a known identifier. The Dockerfile, however, carries the label org.opencontainers.image.licenses="MIT". Those two signals disagree, and the README does not discuss licensing at all. Before you vendor or redistribute anything, read the LICENSE file in the repository root yourself rather than trusting either the API field or the image label. That is a factual gap in the documentation, not a legal opinion.

The upgrade surface is small but not zero. The SDK pins mcp>=1.0.0, httpx>=0.25.0 and fastmcp>=2.0.0, so a change in FastMCP's decorator behaviour can reach you through a transitive upgrade. The version skew between pyproject.toml (0.8.0), the Dockerfile build arg (0.8.0) and the newest release (v0.17.0) means the repository's own container recipe is not tracking the release line. Pin concierge-sdk explicitly in your own image rather than reusing the Dockerfile as-is, and check CHANGELOG.md between the version you pin and the version you upgrade to. There is no documented migration guide for stage or transition definitions, so treat a major version bump as something to test against your own workflow graph.

Editorial conclusion

Adopt Concierge if you already run an MCP server and your problem is tool sprawl or agents calling checkout from the browse step: the wrap is two lines and the stages and transitions are additive. Skip it if your server exposes a handful of tools that are all valid at any moment, because the stage map then buys you nothing but a new failure surface. Before committing, check three things in your own checkout: that your Python and mcp versions satisfy the pyproject constraints, which state backend you need for session state across replicas, and whether you want streamable HTTP or stdio as the transport, since those are two different entry points in the README.

Frequently asked questions

Does Concierge require me to rewrite my existing MCP tools?

No. The README shows wrapping a FastMCP instance in a Concierge object, and states that existing @app.tool() decorators, resources and prompts work unchanged. Stages and transitions are added afterwards as attributes.

What Python version does concierge-sdk need?

The README note and badge say Python 3.9+, but pyproject.toml sets requires-python to ">=3.10". Check your interpreter against the pyproject constraint for the published package.

How do I run a Concierge server over HTTP instead of stdio?

The README gives app.streamable_http_app() as the streamable HTTP entry point for web deployments, while app.run() starts the server over stdio, which is the default. The repository Dockerfile exposes port 8000.

What happens when an agent calls a tool outside the current stage?

The README states that Concierge enforces stage transitions at the MCP protocol level and that the agent cannot call checkout from browse, so it is not a prompt-level suggestion. The documentation does not describe the exact error the client receives.

Is Concierge still actively maintained?

The repository is not archived, but the last push was on 2026-06-09. The most recent release listed is v0.17.0 from 2026-04-17, while pyproject.toml and the Dockerfile still reference version 0.8.0.

Official sources

  1. concierge-hq/concierge on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/concierge-hq-concierge.svg)](https://hysenlabs.com/projects/concierge-hq-concierge)