@switchy-ai/sdk
v0.4.0
Published
Official TypeScript/JavaScript SDK for Switchy: the v1 memory API and the MCP server, authenticated with an org API key.
Maintainers
Readme
@switchy-ai/sdk
Official TypeScript / JavaScript SDK for Switchy. Switchy is a client for the Switchy v1 API, which gives you team memory over HTTP and authenticates with an org API key (sk_live_…). McpClient is a client for Switchy's MCP server and authenticates with an MCP key.
Upgrading from 0.3.x? 0.3.x called Switchy's session-only web-app API, so with an API key every resource call returned
401. 0.4.0 targets the v1 API. See Migrating from 0.3.
Install
npm install @switchy-ai/sdkNode 18+ or any runtime with a global fetch.
Get an API key
An owner or admin of your org mints an sk_live_… key in Settings → API keys. The key is shown once. It is scoped to that org and acts as the user who minted it. (McpClient uses a different key; see MCP client.)
Hello world
import { Switchy } from '@switchy-ai/sdk';
const client = new Switchy({ apiKey: process.env.SWITCHY_API_KEY! });
const memory = await client.memory.create({
content: 'Deploys go out on Thursdays.',
type: 'FACT',
visibility: 'ORG',
});
const hits = await client.memory.search({ query: 'deploys' });
console.log(hits[0].content, hits[0].relevance);
const { memories, total } = await client.memory.list({ limit: 20 });
await client.memory.delete(memory.id);What you can do
client.memory.list({ page, limit, type, minImportance }) // GET /memory → MemoryPage
client.memory.create({ content, type, visibility, projectId, tags }) // POST /memory → CreatedMemory
client.memory.search({ query, type, limit, minImportance }) // POST /memory/search → MemorySearchHit[]
client.memory.delete(id) // DELETE /memory?id= → { deleted: true, id }- Visibility:
PRIVATE(only you, and the default),PROJECT(members of one Project, which needsprojectId), orORG(everyone in the org). Reads only return what the key's user is allowed to see. typeis required on create:FACT,CONTEXT,INSTRUCTION,PREFERENCE,CONVERSATION,SUMMARYorINSIGHT.searchreturns memories whose content containsquery, case-insensitively, best match first. It is a text match, not a semantic search.listis ordered by importance, then newest first. The server ranks at most 100 visible memories, sototal,statsand paging stop there.- Duplicates: writing content that already exists in the org throws
ConflictErrorwithcode: 'DUPLICATE_CONTENT', anddetails.idholds the existing memory's id.
Every response type is exported: Memory, MemoryPage, MemoryStats, CreatedMemory, MemorySearchHit, DeletedMemory, Visibility, MemoryType.
For other v1 endpoints (spec at /api/v1/openapi.json), use the underlying HTTP client. It handles the auth header, the envelope and errors:
const data = await client.http.request<{ namespaces: unknown[] }>('GET', '/namespaces');MCP client
Switchy is also an MCP server. You can call its tools over JSON-RPC from your own code:
import { McpClient } from '@switchy-ai/sdk'; // or '@switchy-ai/sdk/mcp'
const mcp = new McpClient({ apiKey: process.env.SWITCHY_API_KEY! });
const tools = await mcp.tools();
const { memories } = await mcp.searchMemory({ query: 'launch readiness' });McpClient takes the site origin as baseUrl (default https://switchy.build) and posts to {baseUrl}/mcp/rpc. Do not pass it the REST base URL (…/api/v1).
Tool calls need a key with the matching mcp:* scopes. Click Mint MCP key in Settings → API keys to get one. An sk_live_ org key can initialize() and list tools, but it has no mcp:* scopes, so tool calls throw McpAuthError (403, SCOPE_MISSING). See /docs/mcp for the tool list and scopes.
Errors
Every method returns the unwrapped data on success. On failure it throws a typed error, chosen by HTTP status. The server's own code is on err.code:
| Class | HTTP | Typical code |
|-------|------|----------------|
| ValidationError | 400 | VALIDATION_ERROR, plus issues |
| AuthError | 401 | AUTH_ERROR |
| ForbiddenError | 403 | AUTHORIZATION_ERROR, INSUFFICIENT_SCOPE, NOT_ORG_MEMBER, NOT_PROJECT_MEMBER |
| NotFoundError | 404 | NOT_FOUND |
| ConflictError | 409 | DUPLICATE_CONTENT |
| RateLimitError | 429 | RATE_LIMIT_EXCEEDED, plus retryAfter in seconds |
| ServerError | 5xx | INTERNAL_ERROR |
An AuthError message tells you what to check: whether the key was revoked, whether it is an sk_live_ org key, and whether baseUrl points at the v1 API. It also names the base URL the client used.
import { AuthError, ConflictError, RateLimitError } from '@switchy-ai/sdk';
try {
await client.memory.create({ content, type: 'FACT' });
} catch (err) {
if (err instanceof ConflictError) console.log('already stored as', (err.details as { id: string }).id);
else if (err instanceof RateLimitError) console.log(`retry in ${err.retryAfter}s`);
else if (err instanceof AuthError) console.error(err.message);
else throw err;
}Rate limits and retries
v1 requests are rate limited per plan, per minute and per day. The SDK retries a 429 up to maxRetries times (default 2), but only when Retry-After is 60 seconds or less. A longer wait, such as a daily cap, throws RateLimitError right away so your process doesn't sleep for hours.
Migrating from 0.3
0.3.x called https://switchy.build/api, the API behind the Switchy web app. It authenticates with a browser session, not an API key, so every 0.3.x resource call returned 401. 0.4.0 calls the v1 API instead.
| 0.3.x | 0.4.0 |
|-------|-------|
| client.memory.create({ content, visibility: 'SPACE', spaceId }) | client.memory.create({ content, type: 'FACT', visibility: 'PROJECT', projectId }) |
| client.memory.search({ query, spaceId }) → { memory, score }[] | client.memory.search({ query }) → { ...memory, relevance }[] |
| client.memory.list({ visibility, spaceId, limit }) → Memory[] | client.memory.list({ page, limit, type, minImportance }) → MemoryPage |
| client.memory.delete(id) → void | client.memory.delete(id) → { deleted: true, id } |
| client.spaces, sessions, messages, members, invitations | Removed. Use the web app, or McpClient (listSpaces, listSessions, getSessionTranscript, postMessage) |
| client.billing, client.mcp, client.keys | Removed. Manage billing, MCP servers and keys in the web app |
| client.realtime(...) and the ably peer dependency | Removed |
| { idempotencyKey } | Removed. No route implemented it. Duplicate memories are rejected by content |
The full list is in CHANGELOG.md.
Configuration reference
new Switchy({
apiKey: 'sk_live_...', // required
baseUrl: 'https://switchy.build/api/v1', // default
timeout: 60_000, // ms, default 60s
maxRetries: 2, // 429 retries (Retry-After ≤ 60s)
fetch, // custom fetch (tests / non-Node)
userAgent: 'my-app/1.0', // optional
});License
MIT
