Notion Internal Integration binding for Codex, Claude Code, and other MCP clients.
Project description
Notion Agent Labbook
A local MCP server that connects AI coding agents (Codex, Claude Code, OpenCode) to Notion through a Notion Internal Integration secret.
No OAuth, no hosted broker, no cloud worker. The secret lives in your system keychain or 1Password, and the server calls the Notion API directly.
Main Features
- Open the Notion integrations dashboard and guide the user to the Internal Integration Secret.
- Detect whether system keychain and 1Password are available, and let the user choose.
- Store the secret in the local system keychain, in 1Password, or override it with
NOTION_AGENT_LABBOOK_TOKEN. - Search the pages and data sources the bot can access.
- Bind only the pages or data sources a project should use.
- Return access tokens, headers, and bound resource IDs for the official Notion API.
- Work with Codex, Claude Code, and other MCP-capable clients.
Install
Requirements:
- Python 3.10 or newer
uv- a Codex, Claude Code, or another MCP-capable client
Recommended:
codex mcp add labbook -- uvx agent-labbook mcp
claude mcp add --scope project labbook -- uvx agent-labbook mcp
For OpenCode or other MCP clients, add the following to your .mcp.json:
{
"mcpServers": {
"labbook": {
"command": "uvx",
"args": ["agent-labbook", "mcp"]
}
}
}
Or generate this config with:
uvx agent-labbook print-mcp-config
Or use the checked-in .mcp.json for local development from a cloned copy of this repo.
Architecture
┌──────────────┐ MCP (stdio) ┌──────────────────┐ HTTPS ┌───────────┐
│ AI Agent │◄─────────────────►│ agent-labbook │◄──────────►│ Notion API│
│ (Codex, │ │ MCP server │ └───────────┘
│ Claude Code)│ └──────┬───────────┘
└──────────────┘ │
▼
┌──────────────┐
│ Secret Store │
│ (keychain / │
│ 1Password / │
│ env var) │
└──────────────┘
Modules:
| Module | Responsibility |
|---|---|
mcp_server.py |
MCP tool/resource/prompt definitions, server lifecycle |
auth_flow.py |
Secret detection, storage orchestration, API context assembly |
notion_api.py |
HTTP client for Notion API with retry and backoff |
binding_ops.py |
Binding CRUD: search, discover, bind, unbind, alias management |
binding_discovery.py |
Breadth-first child discovery, resource normalization |
binding_browser_page.py |
HTML template renderer for the local binding chooser UI |
binding_ui.py |
Local HTTP server for browser-based binding selection |
state.py |
.labbook/ project state persistence (session, bindings) |
cli.py |
CLI entry points (mcp, doctor, print-mcp-config) |
Recommended Flow
- Read
labbook://agent-labbook/project/statusor runnotion_status. - Run
notion_prepare_internal_integrationto open the Notion integrations dashboard and inspectstorage_options,storage_default, andstorage_choice_required. - Create a Notion Internal Integration, copy its secret from the
Configurationtab, and share the target pages or data sources with the bot in Notion. - Save the secret with
notion_configure_internal_integration, choosingstorage=keychainorstorage=1password, or setNOTION_AGENT_LABBOOK_TOKEN. - If you already know the exact Notion links, use
notion_bind_resource_urls. - On desktop machines, use
notion_open_binding_browserfor a local chooser. - In headless environments, prefer
notion_bind_resource_urlswhen the user can paste exact Notion links. Otherwise combinenotion_search_resources,notion_discover_children, andnotion_bind_resources. - Read
labbook://agent-labbook/project/bindingsor runnotion_list_bindingsto inspect the bound roots. - Run
notion_get_api_contextand use the returned token, headers, and resource IDs with the official Notion API.
Binding Options
- Direct URLs -- Use
notion_bind_resource_urlswhen the user already has exact page or data source links. - Local browser chooser -- Use
notion_open_binding_browseron desktop machines to search, expand child pages, and bind multiple roots visually. - Headless MCP flow -- On SSH or other headless environments, use
notion_bind_resource_urlswhen the user can paste exact links. If they cannot, usenotion_search_resources,notion_discover_children, and thennotion_bind_resources.
Save The Secret
Use notion_configure_internal_integration for persistent storage:
storage=keychain-- Default recommendation for local development when system keychain is available.storage=1password-- Use when theopCLI is installed and signed in. You can optionally provideop_vaultandop_item_title.NOTION_AGENT_LABBOOK_TOKEN-- Use for CI, temporary runs, or environments where no local secret backend is available.
If more than one local backend is available and you omit storage, the tool will ask the caller to make an explicit choice instead of guessing.
Check The Secret
Use notion_status or agent-labbook doctor to inspect the current setup without retrieving the secret itself.
Important fields:
authenticated-- Whether the project currently has a usable Internal Integration secret.storage-- Which persistent backend this project is configured to use.secret_plan-- The recommended secret strategy for this machine right now.storage_options-- The detected local storage backends and their availability.storage_choice_required-- Whether the caller should ask the user to choose between keychain and 1Password.
To verify that the secret also has the correct Notion permissions, prefer notion_search_resources instead of notion_get_api_context.
Guide Users
The recommended user-facing flow for agents is:
- Call
notion_status. - If
authenticated=false, callnotion_prepare_internal_integration. - If
storage_choice_required=true, ask the user whether they wantkeychainor1password. - Tell the user to copy the
Internal Integration Secretfrom Notion'sConfigurationtab. - Call
notion_configure_internal_integration. - Tell the user to share the target pages or data sources with the integration bot.
- Prefer
notion_bind_resource_urlswhen the user pastes exact Notion links. - On desktop machines, use
notion_open_binding_browserfor tree-style selection. In headless environments, prefernotion_bind_resource_urlswhen the user can paste exact links. - Otherwise call
notion_search_resources, optionallynotion_discover_children, and thennotion_bind_resources.
Do not call notion_get_api_context just to check whether the setup worked. That tool returns the secret and should only be used when the client is ready to make real Notion API calls.
If your content already exists as markdown, prefer Notion's markdown content APIs:
POST /v1/pageswithmarkdownGET /v1/pages/{page_id}/markdownPATCH /v1/pages/{page_id}/markdown
Reference: Working with Markdown Content
Contributing
See CONTRIBUTING.md for development setup, testing, and code style guidelines.
Notes
.labbook/should never be committed.- This repo handles local configuration and project binding, not general Notion API wrapping.
- The system keychain is the default recommendation. 1Password is supported when the
opCLI is available and signed in. notion_get_api_contextreturns the secret. Treat it as a last-mile API call step, not a health check.- For local setup notes, see docs/self-host.md.
- For versioning details, see docs/versioning.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_labbook-0.17.2.tar.gz.
File metadata
- Download URL: agent_labbook-0.17.2.tar.gz
- Upload date:
- Size: 58.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af04880cd512f2ba3f6001a00af6e037f03964e6165b8b79209ff8147bca9ac4
|
|
| MD5 |
1c1e4c14fc320bde52e18fd6e15502e1
|
|
| BLAKE2b-256 |
b4ef1da093d1a9388588868ffe6190cd00ca5b3bf2d967aa6c4676c0733b9b34
|
Provenance
The following attestation bundles were made for agent_labbook-0.17.2.tar.gz:
Publisher:
publish-pypi.yml on binbinsh/agent-labbook
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_labbook-0.17.2.tar.gz -
Subject digest:
af04880cd512f2ba3f6001a00af6e037f03964e6165b8b79209ff8147bca9ac4 - Sigstore transparency entry: 1282519928
- Sigstore integration time:
-
Permalink:
binbinsh/agent-labbook@b334b363811aa8c1df51997fdc86c0a1ba8119ad -
Branch / Tag:
refs/heads/main - Owner: https://github.com/binbinsh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b334b363811aa8c1df51997fdc86c0a1ba8119ad -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file agent_labbook-0.17.2-py3-none-any.whl.
File metadata
- Download URL: agent_labbook-0.17.2-py3-none-any.whl
- Upload date:
- Size: 50.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
997d25cd2e3a840d4ed6ad697b49ee66e170a8f7caf2b330fac9065912280f27
|
|
| MD5 |
3d3a36293caf9bdd9fb7aa45484db8a4
|
|
| BLAKE2b-256 |
5b5d34103e5bbc44e127c4461178baa2a5ec8e10e5bbdb3c92c888aba74e9c3f
|
Provenance
The following attestation bundles were made for agent_labbook-0.17.2-py3-none-any.whl:
Publisher:
publish-pypi.yml on binbinsh/agent-labbook
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_labbook-0.17.2-py3-none-any.whl -
Subject digest:
997d25cd2e3a840d4ed6ad697b49ee66e170a8f7caf2b330fac9065912280f27 - Sigstore transparency entry: 1282519955
- Sigstore integration time:
-
Permalink:
binbinsh/agent-labbook@b334b363811aa8c1df51997fdc86c0a1ba8119ad -
Branch / Tag:
refs/heads/main - Owner: https://github.com/binbinsh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@b334b363811aa8c1df51997fdc86c0a1ba8119ad -
Trigger Event:
workflow_dispatch
-
Statement type: