# UseMyContext - Deep SDK + MCP Reference
> The long-form companion to /llms.txt, written for AI coding assistants building with the UseMyContext SDK and MCP tools. Every signature, type, and example below is grounded in the shipped source. For the high-level site map, see https://usemycontext.ai/llms.txt.
UseMyContext is a structurally-blind, third-party service for one person's personal context. A user curates their compiled context once, then connects any AI client (Claude, ChatGPT, Gemini, Perplexity) or your own app over MCP. The public surface is structurally blind: it physically cannot read the user's file content. You ship the integration; UseMyContext holds and serves the user's context, and the user controls and can revoke it.
There are two ways to build:
- The MCP surface (7 tools over Streamable HTTP at https://mcp.usemycontext.ai/mcp). Any MCP-speaking client can use it directly.
- The npm SDK (`usemycontext`), a typed client + React hook that wraps those 7 tools for JS/TS apps.
Scope is ALWAYS the authenticated user. It is resolved server-side from the token, never passed as a tool argument. Every tool is read-only except `suggest_update`, which only files a PENDING proposal for the user to review - nothing is ever written to the user's files.
--------------------------------------------------------------------------------
## Install
```bash
npm i usemycontext
```
- Package: `usemycontext` (version 1.0.4 at time of writing).
- ESM + CJS, with bundled TypeScript declarations.
- The core entry is framework-free. The React hook + button live behind the `usemycontext/react` subpath, gated by an OPTIONAL `react` peer dependency (>=17), so importing the core entry never pulls React in.
- Exports:
- `usemycontext` -> the framework-free client factory + types + errors.
- `usemycontext/react` -> the React hook and the drop-in button.
--------------------------------------------------------------------------------
## Quickstart - React
The React hook is `useMyContextReact()` (imported from `usemycontext/react`). It creates one stable client per component instance and re-renders on every connection-state change.
```jsx
import { useMyContextReact } from "usemycontext/react";
// The user supplies their UseMyContext token (they grab one at
// usemycontext.ai/#/connect). This component connects, then drops the user's
// compiled context + relevant passages into a system prompt.
function Assistant({ token }) {
const { state, connected, connect, client } = useMyContextReact();
async function run() {
await connect({ token }); // v1 is TOKEN-IN
const { composite } = await client.profile(); // the user's compiled context
const { passages } = await client.ask("what should I keep in mind?");
const systemPrompt =
`You are helping a specific person. Their context:\n${composite}\n\n` +
`Relevant notes:\n${passages.map((p) => p.text).join("\n")}`;
console.log(systemPrompt); // -> hand this to your LLM
}
return (
{connected ? "Connected" : "Use my context"}
);
}
```
`useMyContextReact(options?)` returns:
```ts
interface UseMyContextReactValue {
state: ConnectState; // re-renders on change
connected: boolean; // state === "connected"
token: string | null; // the held token, else null
client: UseMyContextClient; // the 7 tool wrappers live here
connect: (args: { token: string }) => Promise;
disconnect: () => void;
}
```
There is also a zero-config drop-in button. It renders one `` whose label tracks the connection state; styling is yours:
```jsx
import { ConnectMyContext } from "usemycontext/react";
console.log(s)} />;
```
`ConnectMyContext` props: `token?`, `options?: ClientOptions`, `onConnect?(state)`, `onError?(error)`, `label?: Partial>`, `className?`.
--------------------------------------------------------------------------------
## Quickstart - framework-free
The core entry exposes a factory, `useMyContext(options?)`, that returns a client handle. No React required.
```js
import { useMyContext } from "usemycontext";
const ctx = useMyContext(); // ClientOptions are optional
await ctx.connect({ token }); // v1 is TOKEN-IN
const { composite } = await ctx.profile();
const { passages } = await ctx.ask("summarise my priorities", { k: 8 });
ctx.disconnect(); // clears the token
```
`useMyContext(options?)` returns a `UseMyContextClient`:
```ts
interface UseMyContextClient {
readonly state: ConnectState;
readonly connected: boolean; // state === "connected"
readonly token: string | null; // when connected, else null
subscribe(listener: (state: ConnectState) => void): () => void; // returns unsubscribe
connect(args: { token: string }): Promise;
disconnect(): void;
// --- the 7 MCP tool wrappers ---
profile(): Promise;
listFiles(): Promise;
searchFiles(query: string): Promise;
getFile(fileId: string): Promise;
ask(query: string, opts?: AskOptions): Promise;
suggestUpdate(suggestion: string): Promise;
sharedContext(from?: string): Promise;
}
```
`ClientOptions`:
```ts
interface ClientOptions {
endpoint?: string; // defaults to the production MCP URL
transport?: Transport; // custom transport (tests inject a mock)
storage?: StorageAdapter | null; // token persistence; null disables it
storageKey?: string; // key under which the token is persisted
onStateChange?: (state: ConnectState) => void;
}
```
--------------------------------------------------------------------------------
## Auth model
A connection is the user's own session token plus the live connection state.
- v1 is TOKEN-IN only. You supply the user's UseMyContext session token to `connect({ token })`. The SDK holds that token and calls the MCP endpoint exactly the way Claude does - same trust model, your client shape. Get a token at https://usemycontext.ai/#/connect.
- `connect({ token })` validates the token against the server with one handshake and moves the connection to `connected`. A rejected token (expired/revoked) surfaces as `expired` and throws `TokenExpiredError`. Call `connect({ token })` again with a fresh token to recover.
- `disconnect()` clears the token (and any persisted copy) and moves to `disconnected`.
Token persistence:
- DEFAULT is memory-only. The token is never written to `localStorage` unless you opt in, and does not survive a reload by default. This reduces exposure (nothing at rest on disk) but does not eliminate it (while connected, the token still lives in the host page's memory, so an untrusted script on your page could read it during a live session).
- Opt in to reload-surviving persistence knowingly:
```js
import { useMyContext, webStorage } from "usemycontext";
// The token now also lives in localStorage, readable by any script on the page.
useMyContext({ storage: webStorage(localStorage) });
```
- Pass `storage: null` for a no-op store, or supply your own `StorageAdapter`.
Token lifecycle (v2, the planned model):
- A short-lived access token plus a rotating, httpOnly refresh cookie served from connect.usemycontext.ai, with silent re-mint of access tokens and revoke-kills-re-mint. The host page never holds a long-lived credential. Until v2 lands, treat the v1 token as sensitive and keep your page free of untrusted scripts.
The connect state machine (`ConnectState`):
```
idle -> connecting -> connected
\-> declined (user/host refused; reserved for the v2 popup path)
\-> error (network / transport / parse failure)
connected -> expired (token rejected mid-session - reconnect)
-> disconnected (disconnect() was called)
```
```ts
type ConnectState =
| "idle"
| "connecting"
| "connected"
| "declined"
| "expired"
| "error"
| "disconnected";
```
Error taxonomy (every failure is a typed subclass of `UseMyContextError`):
- `NotConnectedError` - a tool wrapper was called before `connect()`.
- `TokenExpiredError` - the server rejected the token (carries the `WWW-Authenticate` header value).
- `ScopeDeniedError` - this connection is not authorized for that tool.
- `ToolCallError` - the tool returned an error result.
- `TransportError` - the network/transport failed.
- `UseMyContextConnectArgError` - a bad SDK call argument (a developer error, e.g. an empty token or empty `fileId`).
--------------------------------------------------------------------------------
## The 7 MCP tools
These are the authoritative MCP tool input schemas (the server advertises them on connect). Scope is always the authenticated user, resolved server-side, never a tool argument. All are read-only except `suggest_update`. Each tool returns MCP content text; the SDK wrappers parse that text into the typed shapes shown under "Key types".
### 1. profile
- MCP tool: `profile`
- Input schema: no parameters. `{ "type": "object", "properties": {}, "additionalProperties": false }`
- SDK wrapper: `client.profile() => Promise`
- Returns the user's compiled personal context (a compact synthesized summary). No file content.
Request:
```json
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": { "name": "profile", "arguments": {} } }
```
SDK result (representative):
```json
{ "composite": "Designs developer tools. Prefers concise writing. Based in Singapore. ..." }
```
### 2. list_files
- MCP tool: `list_files`
- Input schema: no parameters. `{ "type": "object", "properties": {}, "additionalProperties": false }`
- SDK wrapper: `client.listFiles() => Promise`
- Lists the user's files (metadata only: id, name, size, content-type, modified).
SDK result (representative):
```json
[
{ "id": "f_abc123", "name": "resume.pdf", "size": 184320,
"contentType": "application/pdf", "modified": "2026-05-01T10:22:00Z",
"status": "available" }
]
```
### 3. search_files
- MCP tool: `search_files`
- Input schema: `query` (string, REQUIRED) - "Filename query to match."
- SDK wrapper: `client.searchFiles(query: string) => Promise`
- Searches the user's files by filename; returns matching `FileMeta[]`, ranked by name match.
Request:
```json
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": { "name": "search_files", "arguments": { "query": "resume" } } }
```
### 4. get_file
- MCP tool: `get_file`
- Input schema: `fileId` (string, REQUIRED) - "The id of the file to fetch."
- SDK wrapper: `client.getFile(fileId: string) => Promise`
- Returns one file's FULL extracted text (large files are size-guarded and truncated; for targeted passages use `ask_docs`). Binary files (images etc.) return a short-lived download link instead, surfaced as `downloadUrl`. Audited.
Request:
```json
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": { "name": "get_file", "arguments": { "fileId": "f_abc123" } } }
```
SDK result (representative):
```json
{ "text": "Full extracted text of resume.pdf ...", "downloadUrl": undefined }
```
### 5. ask_docs
- MCP tool: `ask_docs`
- Input schema:
- `query` (string, REQUIRED) - "What to find in the user's documents (a question or topic)."
- `k` (integer, OPTIONAL, minimum 1, maximum 50) - "How many passages to return (default 12, max 50)."
- SDK wrapper: `client.ask(query: string, opts?: AskOptions) => Promise` where `AskOptions = { k?: number; projectId?: string }`. The SDK maps `opts.k` to the tool's `k`.
- Note: the parameter is `k` (default 12, max 50). There is NO `limit` parameter.
- Returns the most relevant cited passages (the actual chunk text), each cited with its source file - grounded source content for the LLM to read and quote, NOT a file link, NOT a filename list, and NOT a generated answer (you do the reasoning).
Request:
```json
{ "jsonrpc": "2.0", "id": 4, "method": "tools/call",
"params": { "name": "ask_docs", "arguments": { "query": "what are my priorities this quarter?", "k": 8 } } }
```
SDK result (representative):
```json
{
"passages": [
{ "index": 1, "text": "Ship the SDK reference and the pricing page.",
"file": "plan.md", "scope": "u_9f2a", "score": 0.842 }
],
"text": "[1] plan.md · u_9f2a · score 0.842\nShip the SDK reference and the pricing page."
}
```
### 6. suggest_update
- MCP tool: `suggest_update` (the ONLY write tool)
- Input schema: `suggestion` (string, REQUIRED) - "The proposed fact or update about the user, in one short sentence."
- SDK wrapper: `client.suggestUpdate(suggestion: string) => Promise`
- Files a PENDING suggestion the user reviews and accepts or ignores. It does NOT change the profile directly, and nothing is ever written to the user's files.
Request:
```json
{ "jsonrpc": "2.0", "id": 5, "method": "tools/call",
"params": { "name": "suggest_update", "arguments": { "suggestion": "Prefers async standups over meetings." } } }
```
SDK result (representative):
```json
{ "id": "cand_7h2", "text": "Saved as a pending suggestion for review. (id: cand_7h2)" }
```
### 7. shared_context
- MCP tool: `shared_context`
- Input schema (ALL parameters OPTIONAL):
- `from` (string) - the grantId of a share to READ. Omit to LIST the available shares.
- `handle` (string) - NETWORK read: a member's @handle (with or without the leading @) whose network-opened context to pull. You must already know it; there is no directory.
- `project` (string) - NETWORK read: which of that member's projects to read (defaults to their primary project). Only used alongside `handle`.
- `org` (string) - ORGANISATION read: the id of an organisation you and the target are BOTH members of (on an active team plan). Used together with `member`.
- `member` (string) - ORGANISATION read: the member id of the teammate whose live composite you want to read. Only used alongside `org`.
- `orgProject` (string) - ORGANISATION read: which of that teammate's projects to read (defaults to their primary project). Only used alongside `org` + `member`.
- SDK wrapper: `client.sharedContext(from?: string) => Promise`. With no `from`, it LISTS who shared what (ids only, no content); with a `from` (a grantId from that list) it READS that person's shared composite. (The network `handle`/`project` and organisation `org`/`member`/`orgProject` reads are available at the MCP layer; the v1 SDK wrapper exposes the `from` selector.)
- Read-only. You only ever see what was shared WITH you, opened to the network, or a teammate's context within your own organisation. There is no directory or browse - you must already know the ids.
List request (no arguments):
```json
{ "jsonrpc": "2.0", "id": 6, "method": "tools/call",
"params": { "name": "shared_context", "arguments": {} } }
```
SDK list result (representative):
```json
{ "mode": "list",
"shares": [ { "ownerLabel": "Jordan", "grantId": "g_55ab" } ],
"composite": null,
"text": "1 shared context available. Call this tool again with from= to read one:\n- Jordan (from: g_55ab)" }
```
Read request:
```json
{ "jsonrpc": "2.0", "id": 7, "method": "tools/call",
"params": { "name": "shared_context", "arguments": { "from": "g_55ab" } } }
```
SDK read result (representative):
```json
{ "mode": "read", "shares": [], "composite": "Jordan's shared composite ...",
"text": "Shared context from Jordan:\n\nJordan's shared composite ..." }
```
--------------------------------------------------------------------------------
## Key types
The DTOs the SDK wrappers return (copied faithfully from the published types).
```ts
/** One file's metadata as returned by list_files / search_files. */
interface FileMeta {
id: string;
name: string;
size: number;
contentType: string;
modified: string;
/** Owner-side processing status; may be absent on legacy shapes. */
status?: "not-processed" | "processing" | "available" | "error";
}
/** The compiled personal context the profile tool serves. */
interface ProfileResult {
/** The compiled composite text, ready to drop into a system prompt. */
composite: string;
/** Raw facts, present only when the service fell back (no compile yet). */
facts?: string[];
}
/** One cited passage returned by ask_docs. */
interface AskPassage {
index: number; // 1-based citation index
text: string; // the passage text to reason over and quote
file?: string; // the source file the passage was cited from
scope?: string; // the access scope (the owning user id) as cited
score?: number; // retrieval score (higher = more relevant)
}
/** The result of an ask_docs call. */
interface AskResult {
passages: AskPassage[]; // cited passages, in rank order; empty when nothing matched
text: string; // the raw rendered text (citations + passages)
}
/** Options accepted by ask(). */
interface AskOptions {
k?: number; // how many passages to return (default 12, max 50)
projectId?: string; // bound an "all"-token call to one of your projects (server-validated)
}
/** The result of a get_file call. */
interface GetFileResult {
text: string; // the full rendered text for the file
downloadUrl?: string; // a short-lived download link, when the file is binary
}
/** The result of a suggest_update call (the one write tool). */
interface SuggestUpdateResult {
id?: string; // the candidate id, when it could be parsed
text: string; // the full rendered acknowledgement text
}
/** One share listed by shared_context (LIST mode). */
interface SharedContextEntry {
ownerLabel: string; // who shared it (a display label)
grantId: string; // pass it back as `from` to READ that share
}
/** The result of a shared_context call. */
interface SharedContextResult {
mode: "list" | "read"; // "list" with no `from`, "read" when a `from` was given
shares: SharedContextEntry[]; // LIST mode: the available shares (metadata only)
composite: string | null; // READ mode: the selected composite, or null
text: string; // the full rendered text
}
```
--------------------------------------------------------------------------------
## Blog posts
- [What is UseMyContext Premium?](https://usemycontext.ai/blog/what-is-premium): UseMyContext Premium is the $20/month plan. It raises your limits from 2 projects and 20 MB to 10 projects and 100 MB. Everything else is the same as Free.
- [What is UseMyContext Team?](https://usemycontext.ai/blog/what-is-team): UseMyContext Team is the $100/month plan, billed flat per team for up to 10 seats. It gives your group one shared team context, so your AIs all read the same current picture of the team.
- [You're not behind on AI. You just start over every time.](https://usemycontext.ai/blog/start-over-every-time): If using AI at work feels like more effort than it's worth, the problem usually isn't you - it's that you re-explain yourself from scratch every single time. Here's why that happens and how to fix it.
## Notes
- Structural blindness. The public surface physically cannot read the user's file content - it declares no data bindings and relays inward to an isolated, per-user data plane. Your integration moves the user's own curated context into your app; UseMyContext never exposes raw private data through the public surface, and the user can revoke access at any time.
- MCP endpoint: https://mcp.usemycontext.ai/mcp - Streamable HTTP, OAuth 2.1. The SDK defaults to this endpoint; override it with `ClientOptions.endpoint` only for testing.
- Read-only by design. Six of the seven tools are reads. `suggest_update` is the single write, and even it only files a PENDING proposal the user reviews - it never edits the profile directly and nothing is ever written to the user's files.
- Naming: this SDK's React entry exports `useMyContextReact` (the connection hook). It is not React's built-in `useContext` - different thing, different import (`usemycontext/react`).