# Model Context Protocol

> Developer guide to build and integrate a custom MCP client with Capacities (OAuth 2.1, PKCE, Dynamic Client Registration, token refresh).

<capacities-pro-label>



</capacities-pro-label>

## Overview

Build your own app, agent, or bot and integrate it with a Capacities space by implementing a **custom MCP client** using the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) open standard.
We host a server that provides secure access to a selected Capacities space via **OAuth 2.1** (including PKCE, Dynamic Client Registration, and refresh tokens).

### Supported tools

You can connect the Capacities MCP server to all AI tools that support the MCP protocol and connection via oAuth.

- If you want to **use an existing AI chat app** (no custom development), see **AI Chat Connectors**.
- If you want to **build your own integration**, continue below.

## Available tools

### `search`

Permissions access: `read`

Searches across your space via keywords. Results include:

- Object ID
- Object title
- Object Type
- Properties and content snippet

Search uses both title search and semantic search to find and rank the best results.

Example prompt: *"Find all Painting objects related to Claude Monet."*

### `getObjectContent`

Permissions access: `read`

Retrieves all content and properties from a specific object in markdown format.

Example prompt: *"Read my highlights on The Happiness Hypothesis in Capacities and summarize the most important concepts."*

### `createObjectLink`

Permissions access: `read`

Generates a valid URL to access a specific object.

Example prompt: *"Give me a link to my Cheesecake recipe in Capacities."*

### `saveToDailyNote`

Permissions access: `write`

Stores text within today's daily note.

Example prompt: *"Send your conclusions about why folder structures don't work to my Capacities daily note."*

### `createPage`

Permissions access: `write`

Creates a simple Page object with a title and markdown content.

Example prompt: *"Create a Capacities page titled 'Weekly review template' with my checklist as markdown."*

### `createTask`

Permissions access: `write`

Creates a Task object with a title, status, priority, date, deadline, and markdown body content.

Example prompt: *"Add a high-priority Capacities task to finish the MCP docs by Friday."*

### `appendMdToObject`

Permissions access: `write`

Appends markdown content to an existing object.

Example prompt: *"Append a summary of this conversation to my meeting note about the product launch in Capacities."*

### `createObjectViaMd`

Permissions access: `write`

Creates an object of any object type. Content is matched against the type's writable properties; anything else is placed in the body. Call `getObjectTypeShape` first to see which properties are available. Frontmatter structures are recommended for mapping properties.

Example prompt: *"Create a new Book object in Capacities for 'Thinking, Fast and Slow' with author and status in the frontmatter."*

### `updateObjectViaMD`

Permissions access: `write`

Updates writable properties on an existing object from YAML frontmatter in a Markdown string. Only keys listed in the frontmatter are changed; other properties stay as they are. A `title` key renames the object. Any Markdown body after the closing `---` is ignored; use `appendMdToObject` to add content. If the string has no `---` delimiters, the entire input is treated as bare YAML key-value pairs. Only object types that support `PATCH /object` can be updated this way.

Example prompt: *"Set the status on my Capacities Book object for 'Deep Work' to finished."*

### `getObjectTypeShape`

Permissions access: `read`

Returns information about an object type's properties so you can create new objects with the right structure.

Example prompt: *"What properties does my Meeting type have so you can log today's standup in Capacities?"*

### `uploadFile`

Permissions access: `write`

Uploads a file from a publicly accessible URL, the URL will get processed accordingly into a PDF, Image, Weblink or File object. Note that apps like ChatGPT, Claude or Mistral can share files attached in messages via temporary links.

Example prompt: *"Save this image in Capacities"*

### `listObjectsByObjectType`

Permissions access: `read`

Paginates through objects of a specific object type.

Example prompt: *"Fetch all my Movie objects in Capacities and tell me which genre I write about the most"*

### `listObjectsByTag`

Permissions access: `read`

Paginates through objects with a specific tag.

Example prompt: *"Surface three random objects I have tagged with #biology-exam"*

### `listObjectsByCollection`

Permissions access: `read`

Paginates through objects within a specific Collection.

Example prompt: *"Draft a trip itinerary to Madrid using all Place objects in the Madrid collection."*

### `uploadMedia`

Permissions access: `write`

Uploads an image, PDF, or other file into your space as a media object.

Example prompt: *"Upload this PDF into my Capacities space."*

### Creation limits

`createPage`, `createTask`, and `createObjectViaMd` share a per-user creation quota. The hard limit is 5,000 objects. Once you reach it, we increase the hard limit by 100 objects each month.

## Known limitations

The Capacities MCP server works best when the assistant can target a clear set of objects. Use `search` for keyword lookup, or `listObjects` to fetch objects by tag, collection, or object type. After an object is identified, use another tool to read or modify it.

Broad prompts that need to study every object in a space without a filter may still be a poor fit. Example prompt: *"Study all my Trip objects and tell me how many flights I've documented this year"*. Prefer listing or searching first, then reading specific objects.

Prompts that act on a single object are supported. For example:

- *"Add a new Trip object with all this planned route"*
- *"Read my Japan Trip object and give me a bullet point list of all the monuments I visited"*

## Build a custom MCP client

If you are building a custom implementation or a private tool and would like to integrate it with our MCP server, please follow this guide:

### 1. Start from the MCP URL

This is the resource your token must be valid for.

- Canonical MCP resource URL: `https://api.capacities.io/mcp`
- Transport: Streamable HTTP on `/mcp`
- Do not configure Server-Sent Events (SSE) for Capacities MCP

### 2. Discover protected resource metadata (RFC 9728)

It tells you which authorization server to use.

- Fetch: `https://api.capacities.io/.well-known/oauth-protected-resource/mcp`
- Fallback: read `WWW-Authenticate: Bearer resource_metadata="..."`
- Store:

  - `resource`
  - `authorization_servers`

### 3. Discover authorization server metadata (RFC 8414)

You need endpoints and capabilities before auth starts.

- Fetch: `https://api.capacities.io/.well-known/oauth-authorization-server`
- Confirm:

  - `authorization_endpoint`
  - `token_endpoint`
  - `registration_endpoint`
  - `code_challenge_methods_supported` includes `S256` (SHA-256)

### 4. Generate Proof Key for Code Exchange (PKCE) parameters

PKCE protects public clients from code interception.

Before redirect:

1. Generate high-entropy `code_verifier`
2. Derive `code_challenge` using SHA-256 (`S256`)
3. Generate random `state`
4. Store `code_verifier` and `state` securely until callback

### 5. Register the client dynamically (RFC 7591)

Dynamic Client Registration (DCR) gives your app a valid `client_id`.

POST to `registration_endpoint` with:

1. `client_name`
2. `redirect_uris`
3. `grant_types`: `authorization_code`, `refresh_token`
4. `response_types`: `code`
5. `token_endpoint_auth_method`: `none`

Persist:

- `client_id`

Custom clients you build will almost always register as native, public clients (`token_endpoint_auth_method: none`, PKCE, no client secret) using a loopback `redirect_uris`. Hosted HTTPS callbacks and custom URI schemes are not accepted via DCR. See [Redirect URI policy](#redirect-uri-policy) to have those pre-registered. A `client_secret` is only issued to specific pre-arranged web-based partner integrations.

Pick a distinct `client_name`. Names of well-known clients (such as "Claude", "ChatGPT", "Cursor", or "Capacities") are reserved and will be rejected unless your registration proves ownership.

Recommended optional fields: `software_id` (a stable UUID identical across all installs of your client), `software_version`, `client_uri`, and `contacts`. These help us identify and support your integration.

### 6. Start authorization code flow

This is the user consent and authorization step.

Redirect users to `authorization_endpoint` with:

1. `response_type=code`
2. `client_id`
3. `redirect_uri`
4. `scope` (request only needed scopes: `mcp:read`, `mcp:write`)
5. `state`
6. `code_challenge`
7. `code_challenge_method=S256`
8. `resource=https://api.capacities.io/mcp`

### 7. Handle OAuth callback safely

Callback validation prevents Cross-Site Request Forgery (CSRF) and flow confusion.

On callback:

1. Validate `state` exactly
2. Read `code`
3. If `error` exists, stop and surface provider error

### 8. Exchange code for tokens

This returns the access token used for MCP calls.

POST to `token_endpoint` with:

1. `grant_type=authorization_code`
2. `code`
3. `redirect_uri`
4. `code_verifier`
5. `client_id`
6. `client_secret` (non-native/web-based clients only)

Persist securely:

- `access_token`
- `refresh_token`
- expiry metadata

### 9. Call MCP with bearer auth

Tokens are sent as standard OAuth bearer credentials.

- Header: `Authorization: Bearer <access_token>`
- Use Streamable HTTP transport

### 10. Implement refresh token handling

Refresh keeps sessions working without constant re-login.

Before token expiry:

1. Call token endpoint with `grant_type=refresh_token`
2. Save new refresh token if rotation returns one
3. On `invalid_grant`, require full re-auth

### 11. Follow security baseline

OAuth integrations fail safely only when these baseline controls are in place.

1. Use Hypertext Transfer Protocol Secure (HTTPS) in production
2. Validate callback `state` on every auth response
3. Store tokens in secure backend storage or OS keystore
4. Request minimum scopes needed
5. Treat refresh tokens as long-lived credentials

### Redirect URI policy

To keep every user's space secure, we don't accept arbitrary redirect URIs. What you need depends on your client's callback type.

**Loopback redirects work automatically, with no contact needed.**

If your client receives the authorization code on a loopback address, it registers via DCR (step 5) and completes OAuth with no manual step from us:

- `http://127.0.0.1` (any port, any path)
- `http://localhost` (any port, any path)

This is the RFC 8252 native-app path, and it's the recommended option for CLIs and local desktop tools. Only `http` on these hosts is accepted. `https://127.0.0.1` and IPv6 `http://[::1]` are not.

**Hosted HTTPS callbacks and custom URI schemes require pre-registration.**

A public web callback (`https://yourapp.com/callback`) or a custom scheme (`yourapp://callback`) cannot be self-registered via DCR. Your registration will fail with `invalid redirect_uris`. These are where authorization-code interception and impersonation risks concentrate, so we register the client on our side first.

Email [team@capacities.io](mailto:team@capacities.io) with:

1. A brief description of your project/client (include your public repository, if available).
2. The exact redirect URI(s) and your DCR `client_name`.
3. Whether the callback is a hosted HTTPS URL or a custom URI scheme.
4. A public URL to your application's icon (for example, your `favicon.ico`).

We'll confirm once your client is registered.

### Registration request processing

All MCP client registration requests are processed within **7 business days**. If you emailed us within the last 7 business days, we already have your request. Please do not follow up during that window. If you emailed more than 7 business days ago and have not heard back, email [team@capacities.io](mailto:team@capacities.io) again and let us know.

### Using a pre-registered client ID

Some tools can't use Dynamic Client Registration (for example, clients whose callback is a custom URI scheme). For those, we issue a fixed public `client_id` that you set in the tool's MCP config instead of registering dynamically. This is how clients like Cursor connect today. If your client falls in this category, email [team@capacities.io](mailto:team@capacities.io) with the same details listed above. Pre-registered clients are public (PKCE, no secret).

## Roadmap for the Capacities MCP Server

We do not envision the MCP to be a tool to "automate knowledge work", but rather a tool to help you to be more productive and creative.

The Capacities MCP server will be developed in conjunction with the [Capacities API](https://developers.capacities.io). We'll fine-tune API routes for AI usage so the Capacities MCP server is a powerful companion when working with AI.

If the official MCP is not enough for your needs, you'll be able to derive your own MCP server from the Capacities API.
