Build client workflows with MCP
Discover capabilities, page through and cache lists, avoid name collisions, and keep the user in control.
- Page through
tools/listwith cursors and cache it withttlMs - Combine tools from several servers without name collisions
- Route a model’s tool call and keep the user in the loop
The host’s job, in a loop:
- Discover each server’s tools (and resources, prompts).
- Offer the tools to the model, alongside the conversation.
- When the model asks for a call, show it to the user and confirm if it is sensitive.
- Route the call through the right client, then hand the result (or tool error) back to the model.
Pagination and caching
Long lists come in pages: a result with nextCursor means there is more - send the same request again with params.cursor set to it, until a page has no nextCursor. In the current revision, list results also carry ttlMs (how long the answer may be reused) and cacheScope, so a client doesn’t need to re-fetch the tool list before every message. Servers should return tools in a stable order, which also helps model prompt caching.
1pages = {
2 None: {"tools": ["search", "fetch"], "nextCursor": "p2"},
3 "p2": {"tools": ["summarize"], "nextCursor": "p3"},
4 "p3": {"tools": ["translate"]},
5}
6cursor, tools = None, []
7while True:
8 page = pages[cursor]
9 tools += page["tools"]
10 cursor = page.get("nextCursor")
11 if cursor is None:
12 break
13print(tools)['search', 'fetch', 'summarize', 'translate']
Many servers, one model
Tool names are only unique within one server. Connect a GitHub server and a Jira server that both expose search, and the model sees two tools with the same name. The spec says hosts should disambiguate - typically by prefixing each tool with a server identifier the host chose (github__search, jira__search). Don’t rely on a server’s self-reported name for this: it isn’t guaranteed unique.
Key takeaways
Follow
nextCursoruntil it disappears; reuse list results within theirttlMs.Prefix tool names with your own server label to avoid collisions.
The host decides, shows and confirms - the model only suggests calls.
Lesson quiz
7 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: build an MCP server
Write Python in the editor and run it against sample inputs. Python runs locally in your browser using a WebAssembly runtime.
Merge tools from several servers
Each input line is a server label followed by a JSON list of its tool names, like github ["search", "create_issue"]. Print every tool as LABEL__NAME, sorted alphabetically, one per line.
- A collision
- One server
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Decide whether to re-fetch
The first line is fetched_at_ms ttl_ms for a cached tools/list result. Each following line is a current time in milliseconds. For each, print cached if the result is still fresh (now − fetched_at < ttl), otherwise refetch.
- Before and after expiry
- Zero TTL
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…