Keyboard

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/mcp

1. 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.

  1. Open Settings → Connectors.
  2. Click Add custom connector.
  3. Name it Keyboard and enter the URL https://mcp.keyboard.dev/mcp.
  4. Click Add, then Connect — your browser opens Keyboard's sign-in page. Sign in (or create an account) and approve the connection.
  5. 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/mcp

Then, 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.

  1. In ChatGPT, open Settings → Apps & Connectors.
  2. Under Advanced settings, enable Developer mode (required for custom connectors).
  3. Click Create and enter the server URL https://mcp.keyboard.dev/mcp.
  4. 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/execute

The 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:

FieldRequiredDescription
providerIdyesThe custom OAuth provider id (from list-connected-accountskeyboardAccounts[].id)
urlyesFull absolute URL of the target API, e.g. https://workspace.keyboard.dev/api/docs
methodyesGET, POST, PUT, PATCH, DELETE, HEAD, or OPTIONS
headersnoExtra headers — any Authorization you pass is stripped and replaced
paramsnoQuery-string parameters (map of string → string)
bodynoRequest 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.

MethodPathDescription
GET/api/meReturns 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/docsCreate — body { "title": string, "content"?: string }
GET/api/docs/:idFetch one document, including content
PATCH/api/docs/:idUpdate — body { "title"?: string, "content"?: string }
DELETE/api/docs/:idDelete

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 /mcp path.
  • My client can't add remote servers. Use the mcp-remote bridge 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.

On this page