Quickstart
Connect Keyboard to Claude, Claude Code, Cursor, ChatGPT, or any other MCP client in a few minutes.
Keyboard works with any MCP client that supports remote servers. Setup is the same everywhere: add Keyboard's server URL to your client, sign in when it prompts you, see it work against the built-in demo workspace, then connect the apps you want your AI to use.
Keyboard's MCP endpoint:
https://mcp.keyboard.dev/mcp1. Add Keyboard to your client
Works for claude.ai in the browser and the Claude desktop and mobile apps — connectors sync across all of them.
- Open Settings → Connectors.
- Click Add custom connector.
- Name it
Keyboardand enter the URLhttps://mcp.keyboard.dev/mcp. - Click Add, then Connect — your browser opens Keyboard's sign-in page. Sign in (or create an account) and approve the connection.
- In any chat, make sure Keyboard is enabled in the search-and-tools menu.
Add Keyboard from your terminal:
claude mcp add --transport http keyboard https://mcp.keyboard.dev/mcpThen, inside a Claude Code session, run /mcp, select keyboard, and
follow the sign-in flow in your browser. Once authenticated, Keyboard's tools
are available in every session.
Whenever Keyboard needs you to visit a link — an app's sign-in page, or the demo workspace — Claude Code can open it in your browser for you, so you don't have to hunt for URLs in the terminal.
Add Keyboard to ~/.cursor/mcp.json (global) or .cursor/mcp.json in a
project:
{
"mcpServers": {
"keyboard": {
"url": "https://mcp.keyboard.dev/mcp"
}
}
}Open Cursor Settings → MCP, find keyboard in the server list, and click through the sign-in prompt when it appears.
Keyboard is also a ChatGPT app, with interactive widgets for connecting accounts and reviewing runs.
- In ChatGPT, open Settings → Apps & Connectors.
- Under Advanced settings, enable Developer mode (required for custom connectors).
- Click Create and enter the server URL
https://mcp.keyboard.dev/mcp. - Complete the OAuth sign-in when ChatGPT prompts you.
Custom connectors in ChatGPT require a paid plan (Plus, Pro, Business, or Enterprise) with developer mode available.
Any client that supports remote MCP servers over streamable HTTP can
connect with just the URL — Keyboard handles OAuth through the standard MCP
authorization flow, including dynamic client registration. For example, in
VS Code (.vscode/mcp.json):
{
"servers": {
"keyboard": {
"type": "http",
"url": "https://mcp.keyboard.dev/mcp"
}
}
}If your client only supports local (stdio) servers, bridge it with
mcp-remote:
{
"mcpServers": {
"keyboard": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.keyboard.dev/mcp"]
}
}
}2. See it work — no connections needed
You don't have to authorize a single real app to watch Keyboard run end to end. Every account comes with Keyboard Workspace, a built-in sandboxed docs app that is already connected — no OAuth, nothing to configure. Ask your client:
I'm new to Keyboard. Show me what it can do using the demo workspace first — create a sample doc and give me the link so I can open it in my browser. Then, once I've seen it, help me connect my own accounts.
Keyboard plans the task, writes a short script, and runs it in an isolated sandbox — with approval controls so you can review what executes. Open workspace.keyboard.dev (sign in with the same Keyboard account) and the doc the AI just created is sitting there. That's the whole loop — auth, planning, sandboxed execution, a real API call — before you've connected anything you care about.
The demo is recommended, not required — if you'd rather point Keyboard at your own apps right away, skip ahead to step 3 (or just tell your AI client to skip the demo).
The sandbox's network egress is locked down: executed code can only reach app APIs through Keyboard's credential-injecting proxy, so your tokens never appear in code, logs, or model context.
3. Connect your apps
Once you've seen the demo work, point Keyboard at your real tools. Keyboard can only reach the apps you've authorized. Connect them at chat.keyboard.dev/connect, or just ask from inside your AI client:
Connect my Slack and GitHub accounts to Keyboard.
Keyboard walks you through each app's own OAuth sign-in. Your credentials are stored by Keyboard and injected at execution time — they're never pasted into config files and never visible to the model.
Then try something that touches a connected app:
What apps do I have connected through Keyboard?
Send "hello from Keyboard" to the #general channel in Slack.
List my open GitHub pull requests and summarize the oldest one.
Sample app: Keyboard Workspace
The demo workspace you used in step 2 is Keyboard Workspace (workspace.keyboard.dev) — a minimal, Google Docs-style document app tied to your Keyboard account. It lets you exercise the entire flow — auth, planning, sandboxed execution, real API calls — without connecting a single production data source.
- Nothing extra to authorize. Workspace signs you in with the same Keyboard account you created in step 1, so "connecting" it grants access to a sandbox, not to any of your real tools.
- Org-scoped and encrypted. Documents are only visible to your organization and their content is encrypted at rest.
- Disposable by design. It's a sandbox — documents are automatically deleted after 7 days.
Try it
Open workspace.keyboard.dev, sign in with Keyboard, and you have an empty workspace. Then ask your MCP client to work with it:
Create a document in my Keyboard Workspace titled "Meeting notes" with a short agenda for a product sync.
List the documents in my Keyboard Workspace and summarize the most recently updated one.
Add a "Decisions" section to the "Meeting notes" document in my Keyboard Workspace.
Refresh the Workspace page after each task — the changes the AI made show up there, so you can watch the full round trip end to end.
How it works: the custom OAuth execute endpoint
You don't need anything in this section to use the sample app — the model writes this code for you. But Workspace is also a working reference for how Keyboard reaches APIs on your behalf, which matters once you register your own apps.
The sandbox that runs Keyboard's generated code has locked-down network
egress: it can't call workspace.keyboard.dev (or any other third-party
host) directly. Instead, code reaches external APIs through Keyboard's
credential-injecting proxies on api.keyboard.dev. Workspace is wired up as
a custom OAuth provider — the same mechanism your org can use to register
its own OAuth2 apps for services (or internal APIs) that Keyboard's built-in
catalogs don't cover — so calls to it go through the custom OAuth execute
endpoint:
POST https://api.keyboard.dev/api/custom-oauth/executeThe request body describes the upstream call; the proxy looks up your stored
token for the provider, attaches Authorization: Bearer <access_token>
itself, and forwards the request:
| Field | Required | Description |
|---|---|---|
providerId | yes | The custom OAuth provider id (from list-connected-accounts → keyboardAccounts[].id) |
url | yes | Full absolute URL of the target API, e.g. https://workspace.keyboard.dev/api/docs |
method | yes | GET, POST, PUT, PATCH, DELETE, HEAD, or OPTIONS |
headers | no | Extra headers — any Authorization you pass is stripped and replaced |
params | no | Query-string parameters (map of string → string) |
body | no | Request body, serialized as JSON by default |
A script the model runs to create a Workspace document looks like this:
const response = await fetch('https://api.keyboard.dev/api/custom-oauth/execute', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.KEYBOARD_PROVIDER_USER_TOKEN_FOR_KEYBOARD,
'Content-Type': 'application/json',
},
body: JSON.stringify({
providerId: '<workspace-provider-id>', // keyboardAccounts[].id
url: 'https://workspace.keyboard.dev/api/docs',
method: 'POST',
body: { title: 'Meeting notes', content: '# Agenda\n- Roadmap review' },
}),
})
const result = await response.json()
console.log(JSON.stringify(result))On success the proxy returns
{ "success": true, "status": 200, "data": { /* upstream response */ } };
a non-2xx from the upstream API comes back as success: false with the
upstream status and body. If there's no valid token for the provider, the
proxy answers { "error": "not_connected" } — reconnect the account and
retry. Expired access tokens are refreshed transparently when the provider
has a refresh token configured, and unlike some of Keyboard's other proxies,
url must always be absolute.
Workspace API reference
Everything the proxy can reach lives under https://workspace.keyboard.dev.
All /api/* routes require auth, and documents are scoped to the
organization in your token — other orgs' documents 404.
| Method | Path | Description |
|---|---|---|
GET | /api/me | Returns user_id, org_id, email from the token |
GET | /api/docs?q=&limit=&offset= | List your org's docs, newest-updated first; q filters titles, limit 1–200 (default 50) |
POST | /api/docs | Create — body { "title": string, "content"?: string } |
GET | /api/docs/:id | Fetch one document, including content |
PATCH | /api/docs/:id | Update — body { "title"?: string, "content"?: string } |
DELETE | /api/docs/:id | Delete |
Limits: titles up to 300 characters, content up to 1,000,000 characters.
Errors are always { "error": "<code>", "message": "<human text>" } with a
matching HTTP status.
Once you've seen the round trip work against Workspace, the exact same pattern applies to your own registrations: register a custom OAuth provider for any service Keyboard doesn't cover, and generated code calls it through the same execute endpoint.
Troubleshooting
- The connector never asks me to sign in. Remove and re-add it, and make
sure you used the full URL including the
/mcppath. - My client can't add remote servers. Use the
mcp-remotebridge shown under Other clients above. - A task fails with a missing-account error. The app isn't connected yet — visit chat.keyboard.dev/connect and authorize it, then retry.
- My Keyboard Workspace documents disappeared. That's the sandbox's 7-day retention doing its job — Workspace is for trying things out, not for keeping anything you care about.