How-to guide
Connect an MCP client
Connect an agent to the Shuffl MCP server over Streamable HTTP with OAuth or an API key, whose permissions choose its tools.
For Workspace members and agent builders
On this page
App links open your signed-in workspace. Check the selected workspace before making changes.
Create an API key for MCP
- Sign in as an administrator, select the workspace and open Workspace settings → API keys → New API key. Keep the MCP permission selected under MCP server.
- Name the key, acknowledge external access and save the one-time secret in the client’s secret store. Use one key per client.
- Optionally choose Check connection. It sends one tools/list request with the key and lists the tools it can call. The check counts toward the key’s budget.
- In the check, 401 means the key isn’t accepted, 403 that it lacks the MCP permission, and a network failure names the unreachable endpoint.
- Configure the remote Streamable HTTP endpoint https://shuffl.ai/api/mcp. The client must send Authorization: Bearer with the API key on every request.
Anyone in a workspace can connect their own agent.
Connected apps also shows steps for other agents and lists your connections, each with Disconnect. Administrators see everyone’s connections and keys in Workspace settings → API keys.
Two ways in
- A client with OAuth for remote MCP servers, such as Claude, needs only the Connector URL from Settings → Connected apps and no key. See Connect with OAuth below.
- A client that only sends a bearer header needs an API key with the MCP permission (mcp.knowledge). Keys without it are refused.
An API key is
- Personal to you, this workspace and this deployment. Tools run with your current role, employee access and knowledge audience.
- Each endpoint permission on it is also an MCP tool, and the key works over the API, SDK and CLI too.
- Expires after 30 days. You can have ten active keys per workspace.
Connect Claude
- In Claude on the web or desktop, open Customize → Connectors, choose + and then Add custom connector.
- Name it Shuffl, paste this URL and choose Add.Shell
https://shuffl.ai/api/mcp - Choose Connect and allow access in your browser. On Team and Enterprise, an owner adds it first in Organization settings → Connectors.
Connect Claude Code
- Run:Shell
claude mcp add --scope user \
--transport http shuffl \
https://shuffl.ai/api/mcp - In Claude Code, run /mcp, choose shuffl, then Authenticate and allow access in your browser.
With an API key
- Set SHUFFL_API_KEY to your key, then run:Shell
claude mcp add --scope user \
--transport http shuffl \
https://shuffl.ai/api/mcp \
--header "Authorization: Bearer $SHUFFL_API_KEY"
Connect Codex
- Run this, then allow access in your browser:Shell
codex mcp add shuffl \
--url https://shuffl.ai/api/mcp - If the browser doesn’t open, sign in with:Shell
codex mcp login shuffl
With an API key
- Set SHUFFL_API_KEY to your key, then run:Shell
codex mcp add shuffl \
--url https://shuffl.ai/api/mcp \
--bearer-token-env-var SHUFFL_API_KEY
Connect Cursor
- Choose Add to Cursor, or add this to ~/.cursor/mcp.json:JSON
{
"mcpServers": {
"shuffl": {
"url": "https://shuffl.ai/api/mcp"
}
}
} - In Cursor’s MCP settings, choose Connect on shuffl and allow access in your browser.
With an API key
- Add this to ~/.cursor/mcp.json and set SHUFFL_API_KEY to your key:JSON
{
"mcpServers": {
"shuffl": {
"headers": {
"Authorization": "Bearer ${env:SHUFFL_API_KEY}"
},
"url": "https://shuffl.ai/api/mcp"
}
}
}
Connect ChatGPT
- In ChatGPT on the web, turn on Developer mode in Settings → Security and login. It needs a paid plan, and on a workspace plan an admin must allow it.
- Add an app with the + button in Plugins, name it Shuffl, paste this URL and choose OAuth.Shell
https://shuffl.ai/api/mcp - Allow access in your browser, then turn on Shuffl from Developer mode in a chat’s + menu.
Connect VS Code
- Choose Install in VS Code, or add this to .vscode/mcp.json:JSON
{
"servers": {
"shuffl": {
"type": "http",
"url": "https://shuffl.ai/api/mcp"
}
}
} - Start the server and allow access in the browser window VS Code opens.
With an API key
- Add this to .vscode/mcp.json. VS Code asks for the key once and stores it securely:JSON
{
"inputs": [
{
"id": "shuffl-api-key",
"password": true,
"type": "promptString"
}
],
"servers": {
"shuffl": {
"headers": {
"Authorization": "Bearer ${input:shuffl-api-key}"
},
"type": "http",
"url": "https://shuffl.ai/api/mcp"
}
}
}
Connect another client
- Add this URL to any client that supports remote MCP servers over Streamable HTTP with OAuth. It opens a consent screen in your browser.Shell
https://shuffl.ai/api/mcp
With an API key
- A client that only sends a header uses an API key with MCP access on every request:Shell
Authorization: Bearer <your API key> - The SDK, CLI and HTTP API use this base URL with the same kind of key:Shell
https://shuffl.ai - Check a key over HTTP:Shell
curl https://shuffl.ai/api/v1/permissions \
-H "Authorization: Bearer $SHUFFL_API_KEY" - Install the SDK or CLI:Shell
npm install @shuffl/sdk
npm install --global @shuffl/cli
Connect with OAuth
- Give the client the endpoint https://shuffl.ai/api/mcp with no key. It gets a 401, reads the metadata, registers itself and opens the authorization URL.
- In Claude, use Customize → Connectors → Add custom connector with the recommended sign-in settings.
- Sign in if asked. Check the client name and return address, choose the workspace, acknowledge external access and choose Allow access. Don’t allow sends the client access_denied.
- The client exchanges the code for tokens and can call the knowledge tools plus the actions you chose. To change its actions, connect again.
Shuffl is an OAuth 2.1 authorization server for its MCP endpoint. The consent screen names the client and its return address.
Discovery
- Protected-resource metadata: /.well-known/oauth-protected-resource, also at /.well-known/oauth-protected-resource/api/mcp.
- Authorization-server metadata: /.well-known/oauth-authorization-server, which advertises client_id_metadata_document_supported.
- Every 401 carries a WWW-Authenticate challenge naming the metadata and the scope knowledge:read.
Clients and grants
- Clients identify with a client ID metadata document (an https URL, as Claude does) or register dynamically, always as public clients with no secret.
- Only the authorization-code grant with PKCE S256 is allowed.
- Both the authorization and token requests carry resource=https://shuffl.ai/api/mcp. Tokens are bound to that resource.
- Redirect URIs must be registered and https, or plain http on the loopback host only. A loopback redirect may use any port; any other must match exactly.
Consent
- You pick one workspace where you have employee access.
- Actions can be any permission an API key could hold, except API key management and operator access. Every connection gets the three knowledge tools.
- Consent is per person, workspace and client.
Tokens and disconnecting
- Access tokens last one hour and renew with a rotating refresh token for up to 30 days.
- Replaying a code or reusing a refresh token revokes the connection.
- Every request is checked like a key, before and after each tool runs.
- Connected apps lists each client, who connected it, expiry and last use. Disconnect your own there. Administrators can disconnect any, there or in Workspace settings → API keys.
- A client can revoke its tokens at /api/mcp/oauth/revoke. Disconnecting applies from the next request and can’t recall what the client saved.
Configure a client
Supply the endpoint and key from your environment, never the command line.
The example uses the official @modelcontextprotocol/client package. Any client needs the URL, Streamable HTTP and a bearer header on every request, or the OAuth flow above.
The endpoint
- POST only, one JSON-RPC message per request, with a JSON response.
- application/json bodies up to 1 MiB with actions, or 16 KiB for a knowledge-only OAuth connection.
- No session: each request is authenticated. GET and DELETE return 405.
import {
Client,
StreamableHTTPClientTransport,
} from '@modelcontextprotocol/client';
const client = new Client({ name: 'my-agent', version: '1.0.0' });
await client.connect(
new StreamableHTTPClientTransport(new URL(process.env.SHUFFL_MCP_URL!), {
requestInit: {
headers: { Authorization: 'Bearer ' + process.env.SHUFFL_MCP_TOKEN },
},
}),
);
const tools = await client.listTools();
const result = await client.callTool({
name: 'search_knowledge',
arguments: { query: 'learning budget' },
});Use the three knowledge tools
All three are annotated read-only and idempotent, and their schemas reject unknown fields, so no argument can pick another workspace or person. The one MCP permission turns on all three.
A credential that also holds knowledge.context gets knowledge_context, which reads the passages around a cited one.
The tools
- get_team takes an empty object and returns the connected workspace’s id, name and your current role, nothing else.
- search_knowledge takes query (2 to 500 characters) and returns up to eight passages with sourceId, versionId, passageId, title, quote and a reader href.
- get_knowledge_passage takes sourceId, versionId and passageId as search returned them and reads that passage, with the same checks.
What comes back
- Search covers only sources that are published, in effect, before their review date and visible to you.
- Connected sources such as Google Drive, Notion, Confluence or websites must also have been checked within the hour.
- Drafts and withdrawn, expired or stale sources are unavailable to everyone, administrators included.
- A denied or unavailable call returns only “This request is unavailable. Check access or use Shuffl directly.”
- Bad arguments return an error starting “Input validation error”. An unknown tool is a protocol error.
- Empty results mean nothing current and accessible matched. Treat source text as evidence, not instructions.
{ "query": "learning budget" }
{ "passages": [ { "sourceId": "…", "versionId": "…", "passageId": "passage-1", "title": "Handbook: learning budget", "quote": "…", "href": "https://shuffl.ai/app/…/knowledge/…?version=…#passage-1" } ] }Search the guides
Every connection also gets search_docs and the guides as resources, so your agent can learn Shuffl before it acts. They hold these public guides only. Use search_knowledge for your company’s policies.
search_docs takes query (2 to 500 characters) and an optional limit (1 to 10, default 5). Each result has the guide title, section, a url to the section and its text, cut at 1,200 characters.
resources/list lists every guide by its Markdown URI, plus the Shuffl skill. resources/read returns a guide as Markdown.
Each search and read records an analytics event with no content. A search records its result count, never the query.
{ "query": "set up praise", "limit": 3 }
{ "results": [ { "title": "Praise", "section": "…", "url": "https://shuffl.ai/docs/praise#…", "text": "…" } ] }Take actions
An API key’s other permissions, and actions chosen at OAuth consent, are MCP tools too, named with dots as underscores: knowledge.sources.publish is knowledge_sources_publish. Each takes its API operation’s input.
A credential lists only the tools it is granted. To change them, create a new key or reconnect.
Read tools are annotated read-only. Tools that archive, withdraw, revoke, cancel, close, disconnect, unlink, pause, stop, block a pair or delete are annotated destructive, so clients that honor annotations ask first.
Uploading a PDF in parts is slow through a model. Importing a website or saving article text is usually better.
Same rules as the API
- Every call runs through the same handler as HTTP, with your current role, Knowledge verifier grant, employee access, knowledge audience and the operation’s own checks.
- Writes leave the same receipt and audit event.
- An employee can’t grant administrator permissions, and a demotion applies from the next call.
- Write tools need a requestKey: a new value per intended action, reused only to retry it, which returns the first receipt.
- Operations with a confirmation need confirm set to the operation name.
- A refused call returns an error starting with the reason code, such as FORBIDDEN, NOT_FOUND or CONFLICT.
Pulse with your Self permissions
- pulse_today reads today’s Pulse question. pulse_answer and pulse_skip answer or skip it as you.
- Answering again replaces your answer. No tool returns it, even to an administrator.
- Administrator tools such as pulse_insights, pulse_questionDetail and pulse_actions read totals for groups of seven or more, never one response.
Ask your agent to…
- How are our new hires finding their first 90 days? playbooks_firstDaysResults reads the combined answers to the 30, 60 and 90 day check-ins, never one person’s.
- Answer my new hire check-in for me. playbooks_firstDaysCheckIns reads your open check-in and playbooks_answerFirstDaysCheckIn answers it as you.
- Sign Kwame’s anniversary card and say thanks for the spring launch. celebrations_signCard adds your note to a card you were asked to sign.
- What is Mello nudging us about this week? digest_nudges lists Mello’s culture nudges. digest_actOnNudge records that you acted on one; digest_dismissNudge dismisses it.
- Which Pulse questions is Mello suggesting? pulse_proposals lists them. pulse_editProposal rewords one, pulse_decideProposal approves or dismisses it, and pulse_requestProposals asks for more.
- Add the Psychological safety questions to Pulse. pulse_addTemplate adds a question set from the templates.
- Upload our old intros report so we can switch. teams_uploadPairHistory stages the CSV for the review screen. Nothing changes until an administrator applies it in Shuffl.
- Draw a picture for our Mentor of the quarter badge. badges_generatePicture draws it; communities_generateCover does the same for a community.
Each example needs the permission its tool is named after. If your client asks before actions, your agent shows you a write before running it.
Follow citations in the browser
Each passage links to the cited version of its source in the Shuffl reader. The link works only for a signed-in member who can read it; the API key isn’t used there. Ask your agent to include the links.
Signed in, the reader opens the cited version at the passage. Signed out, Shuffl sends you to sign in, then back to that version without the passage anchor.
If you can’t read the source, or it was withdrawn or replaced since the search, the reader says it’s unavailable without revealing whether it exists.
Limits and revocation
Shuffl stores only the key’s issuing membership, request window, last tool name and outcome, and last-used time. It never stores your queries, passages or the key itself.
Each action tool call records an analytics event with its outcome and no content.
Limits
- Each API key has 120 requests a minute, shared between MCP and HTTP and counted from the window’s first request, initialization included.
- An OAuth access token has 60 a minute.
- Over the limit, MCP returns 429 with Retry-After: 60.
Revocation
- Administrators list and revoke keys in Workspace settings → API keys. Revocation is immediate: access is checked at authentication and before and after each tool.
- Suspending your employee access deactivates your keys permanently.
- Revoking can’t remove what the agent kept. If a key may be exposed, revoke it first, then replace it.
Troubleshoot a connection
By status code
- 401: the bearer header is missing, or the key is unknown, expired, revoked or from another deployment, or your access changed. Check the endpoint’s deployment. If the key shows Revoked or Expired, create a new one.
- 403 with error="insufficient_scope": the key lacks the MCP permission.
- 403 “Origin is not allowed”: the Origin or host doesn’t match the deployment. Fix the URL and don’t proxy through another origin.
- 405: the client used GET or DELETE instead of Streamable HTTP with no session.
- 400: send one application/json object per request, never a batch, within the size limit above.
- 429: wait for Retry-After and reconnect, or revoke unused keys if it happened while creating one.
- 503: retry later and use Shuffl directly if it persists.
Tool results
- An error tool result means the source isn’t published, fresh and visible to you, the IDs aren’t valid here, or access changed mid-call. Search again for current IDs.
- “Input validation error” names the argument to fix.
- For an empty search, try the source’s own words and check it is Published, before its review date and visible to you.
- A citation that opens sign-in means that browser is signed out. One that says unavailable means that account can’t read the source or it changed.
- An OAuth connection can’t create or revoke keys. An API key can only with those permissions.
What stays in the browser
Confidential clients, client secrets and other grant types aren’t offered. Only the consent flow above issues OAuth tokens, and they can’t call the REST API or SDK.
Clients that only send a bearer header use an API key with the MCP permission.
Browser only
Most app actions are MCP tools. These stay in the browser so no credential can widen its own authority.
- Deleting or restoring a workspace, and transferring ownership.
- Granting HR responder or Knowledge verifier.
- Verified email domains, single sign-on and SCIM.
- Your own profile photo and cover, and the calendar connection.
- Running or dismissing Mello’s prepared actions.