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

Concierge: A Python Wrapper That Filters MCP Tools by Workflow Stage

🚀 Universal SDK for building next-gen MCP servers

533 stars98 forksPythonNOASSERTION

At a glance

What is it?
Concierge is an SDK that sits between an MCP client and a FastMCP server, changing which tools appear in tools/list depending on the current workflow stage. It targets developers whose agents pick the wrong tool from a long, flat list.
Who is it for?
Adopt Concierge if your MCP server exposes a tool list long enough that agents call the wrong one, and you can express your domain as named stages with explicit transitions. Do not adopt it if your server is a small set of independent tools with no natural ordering, or if you need the licence question settled before shipping, because the repository metadata reports NOASSERTION and the README does not resolve it.
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 99 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 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem: a flat tools/list makes agents guess

Every MCP server answers tools/list with the full set of tools it exposes. That is fine for five tools and awkward for fifty. The model has to pick from everything at every turn, including tools that make no sense yet, such as a checkout function before anything is in a cart. The README frames this directly: instead of exposing a flat list of every tool on every request, Concierge progressively discloses only what is relevant. The intended user is a Python developer who already has an MCP server built on FastMCP and has watched an agent call a plausible but wrong tool. The pitch is not a new protocol. It is a filter placed in front of an existing one.

Stages and transitions: the actual mechanism

Concierge is constructed around an existing FastMCP app: app = Concierge(FastMCP("my-server")). Your @app.tool() decorators stay as they are. On top of that you declare two dictionaries. app.stages maps a stage name to the tool names visible in that stage, for example "browse": ["search_products", "view_product"]. app.transitions maps a stage to the stages reachable from it, so "browse": ["cart"] means the workflow can only advance to cart, while "cart": ["browse", "checkout"] permits going back or forward, and an empty list marks a terminal stage. The README states that Concierge changes which tools are returned by tools/list based on the current workflow step, and that the agent and client do not need to know Concierge exists. That is the key design decision: enforcement lives at the protocol boundary, not in the system prompt. The README's shopping example makes the boundary concrete. The agent starts at browse, can move to cart, then checkout, and cannot call checkout from browse. No prompt engineering is involved. Whether a client that caches tool lists or assumes a stable toolset will handle a shifting tools/list is not addressed in the material.

State that stays on the server

The second mechanism is app.set_state and app.get_state. The README example stores a selected product during the browse stage and reads it back during cart, with the comment that this avoids round-tripping through the LLM. The README describes state as session-scoped, atomic and consistent, and says it works across distributed replicas. That last claim is the one worth checking against the docs at docs.getconcierge.app before you depend on it, because the README does not name the backing store. If state is held in process memory, horizontal scaling would break it, and the README's wording implies it is not. This matters most when the data is large or structured: passing a product record through a tool result and back into the next prompt costs tokens and invites transcription errors, while get_state returns the object you stored.

Installing and the two ways to start

The package is concierge-sdk on PyPI and requires Python 3.9 or later. The README recommends uv for dependency resolution but states pip works as well: pip install concierge-sdk. For a new project, the scaffolding CLI generates a runnable layout: concierge init my-store, then cd my-store, then python main.py to start the MCP server. For an existing server you change two lines: replace from mcp.server.fastmcp import FastMCP plus app = FastMCP("my-server") with from concierge import Concierge and app = Concierge(FastMCP("my-server")). The README notes that this wrap-and-go form gives progressive tool disclosure immediately, and that app.stages and app.transitions are added later when you want full workflow control, with no other code changes. Transports are selected at the call site: app.run() uses stdio, which the README calls the default for CLI-based clients, while app.streamable_http_app() is recommended for web deployments, and SSE is listed among the supported transports. A third configuration path exists for large APIs, using Config(provider_type=ProviderType.SEARCH, max_results=5), which the README says collapses the whole API behind two meta-tools named search_tools and call_tool.

Where the abstraction breaks down

Stages assume your domain has an order. A server exposing independent utilities, such as a filesystem reader, a calculator and a time lookup, has no honest stage graph, and forcing one into browse/cart/checkout shape adds configuration without removing any ambiguity. The transition model is also stricter than it first looks: a terminal stage with an empty list means the workflow cannot resume, so any retry or correction path has to be modelled as an explicit transition or the agent is stuck. The README presents stages, transitions, state and semantic search as optional and independent, which is accurate, but the value of the wrapper is proportional to how many tools you have and how much their order matters. Below roughly a dozen tools, the filter is doing little that a clear tool description would not. The semantic search mode introduces a different trade-off: the agent sees only two meta-tools and must describe what it wants in a query, so discovery quality depends on your tool descriptions rather than on the model seeing the full list. The README does not state which embedding provider backs that search.

How this differs from the MCP Python SDK alone

The mcp Python SDK, and FastMCP on top of it, gives you the server: decorators, resources, prompts, transports. It returns your tools as one set for the life of the connection. Concierge does not replace that layer, it wraps it and interposes on tools/list. The difference in approach is where control lives. With plain FastMCP, if you want the agent to search before it adds to cart, you write that instruction into a tool description or a system prompt and hope. With Concierge, the checkout tool is absent from tools/list until the session is in the checkout stage, so there is nothing to hope about. The cost is that you now maintain a stage graph alongside your tool definitions, and every new tool has to be assigned to a stage or it will not appear. That is a real ongoing obligation, not a one-time setup.

Licence and maintenance signals

The repository metadata reports the licence as NOASSERTION, which means GitHub could not map the licence file to a known identifier. The README does not state terms. If you are evaluating this for a commercial deployment, read the LICENSE file in the repository yourself rather than inferring anything from the SDK being installable from PyPI. On maintenance, the release history shows v0.15.0 and v0.16.0 within two days of each other in March 2026, then v0.17.0 in April 2026, and the last push to the default branch is dated 2026-06-09. The version numbers are still in the 0.x range, which conventionally signals that the public API can change between minor releases. Pinning concierge-sdk to a specific version in your requirements file is the practical response, and the wrap-and-go construction means an upstream change to the Concierge constructor or the stages dictionary would touch a small part of your codebase.

Editorial conclusion

Adopt Concierge if your MCP server exposes a tool list long enough that agents call the wrong one, and you can express your domain as named stages with explicit transitions. Do not adopt it if your server is a small set of independent tools with no natural ordering, or if you need the licence question settled before shipping, because the repository metadata reports NOASSERTION and the README does not resolve it. Verify two things first: that wrapping your existing FastMCP instance leaves your @app.tool() decorators, resources and prompts working, and that your client tolerates tools/list returning different sets across a session, since that dynamic behaviour is the whole point and also the main compatibility risk.

Official sources

  1. concierge-hq/concierge on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Community notes

Community notes