diff --git a/README.md b/README.md index 15546c6..644a21c 100644 --- a/README.md +++ b/README.md @@ -96,14 +96,74 @@ npm install -g @anyproto/anytype-mcp ## Environment Variables -| Variable | Default | Description | -| ------------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `OPENAPI_MCP_HEADERS` | — | JSON object of headers forwarded to the Anytype API on every request. Required for auth: `{"Authorization":"Bearer ", "Anytype-Version":"2025-11-08"}` | -| `ANYTYPE_API_BASE_URL` | `http://127.0.0.1:31009` | Anytype API base URL. Set to `http://localhost:31012` for `anytype-cli`. | -| `MCP_TRANSPORT` | `stdio` | Transport mode. Set to `http` to enable the Streamable HTTP server. | -| `MCP_HOST` | `127.0.0.1` | Host to bind when `MCP_TRANSPORT=http`. | -| `MCP_PORT` | `3666` | Port to listen on when `MCP_TRANSPORT=http`. Must be in range 1024–65535. | -| `MCP_PASSTHROUGH_HEADERS` | `authorization,anytype-version` | Comma-separated list of inbound HTTP header names (lowercase) forwarded from the MCP HTTP client to the Anytype API. Extend with caution — arbitrary headers must not be forwarded. | +| Variable | Default | Description | +| ------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `OPENAPI_MCP_HEADERS` | — | JSON object of headers forwarded to the Anytype API on every request. Required for auth: `{"Authorization":"Bearer ", "Anytype-Version":"2025-11-08"}` | +| `ANYTYPE_API_BASE_URL` | `http://127.0.0.1:31009` | Anytype API base URL. Set to `http://localhost:31012` for `anytype-cli`. | +| `MCP_TRANSPORT` | `stdio` | Transport mode. Set to `http` to enable the Streamable HTTP server. | +| `MCP_HOST` | `127.0.0.1` | Host to bind when `MCP_TRANSPORT=http`. | +| `MCP_PORT` | `3666` | Port to listen on when `MCP_TRANSPORT=http`. Must be in range 1024–65535. | +| `MCP_PASSTHROUGH_HEADERS` | `authorization,anytype-version` | Comma-separated list of inbound HTTP header names (lowercase) forwarded from the MCP HTTP client to the Anytype API. Extend with caution — arbitrary headers must not be forwarded. | +| `MCP_INSTRUCTIONS` | bundled `instructions.md` | Instructions broadcast to MCP clients on connect. `false` disables; a string overrides with custom content; `{file:/path}` loads content from a file. | +| `DISCOVERY_TOOL_CONFIG` | — | JSON config for the `discover-spaces` tool. Accepts inline JSON or `{file:/path/to/config.json}`. Options: `ttlMs` (cache TTL ms, default 300000), `spaces` (per-space/type filter). | + + + +### discover-spaces Tool + +The `discover-spaces` tool returns a complete snapshot of your Anytype workspace — all spaces with their types, properties, tags, and select option IDs — in a single call. AI assistants use it to resolve IDs before creating or updating objects, eliminating the need to chain multiple list calls. + +#### Path narrowing + +Instead of fetching the full structure every time, you can request a sub-tree using bracket-notation path syntax: +``` +discover-spaces(path='spaces["My Space"].tags') +discover-spaces(path='spaces["My Space"].types["Task"].properties["Status"].select') +``` + +#### Filtering spaces and types + +By default all spaces and types are included. +Use `DISCOVERY_TOOL_CONFIG` to limit the scope: +```json +{ + "mcpServers": { + "anytype": { + "command": "npx", + "args": ["-y", "@anyproto/anytype-mcp"], + "env": { + "OPENAPI_MCP_HEADERS": "{\"Authorization\":\"Bearer \", \"Anytype-Version\":\"2025-11-08\"}", + "DISCOVERY_TOOL_CONFIG": "{\"spaces\":{\"Work\":{\"types\":{\"Task\":{},\"Project\":{}}},\"Personal\":{}}}" + } + } + } +} +``` + +For non-trivial configs, use a file reference instead of an inline JSON string: +```json +"DISCOVERY_TOOL_CONFIG": "{file:path/to/discovery-config.json}" +``` + +`discovery-config.json`: +```json +{ + "ttlMs": 300000, + "spaces": { + "Work": { + "types": { + "Task": {}, + "Project": {} + } + }, + "Personal": {} + } +} +``` + +#### Cache + +Results are cached for 5 minutes by default. Set `ttlMs` in `DISCOVERY_TOOL_CONFIG` to adjust. The AI assistant will call `discover-spaces(force_refresh=true)` automatically after schema-mutating operations (creating or modifying a type, property, tag, or space). ### Custom API Base URL diff --git a/eslint.config.js b/eslint.config.js index 4cf8d6c..1fad586 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -27,6 +27,7 @@ export default [ ...tseslint.configs.recommended.rules, "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unused-vars": "off", + "no-undef": "off", // https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors }, }, { diff --git a/instructions.md b/instructions.md new file mode 100644 index 0000000..61d6712 --- /dev/null +++ b/instructions.md @@ -0,0 +1,75 @@ +# Anytype MCP Server — Instructions + +You are connected to an Anytype knowledge base via the **Anytype MCP server**. +Follow these rules precisely to avoid data loss or API errors. + +## Session start — mandatory first step + +Call `discover-spaces` with no arguments **before any other tool call** in a new session. +It returns every space, type, property, tag, and select-option ID you need. +Cache this result mentally for the session — do not call it again unless you have performed a schema-mutating operation (creating or modifying a type, property, tag, or space). + +## ID resolution + +- **Never invent or guess IDs.** Every object, space, type, property, tag, and select option has an opaque content-addressed ID returned by `discover-spaces`. +- **Tags are space-scoped.** The same tag name in two spaces has two different IDs. Always look up the ID from the correct space entry in the `discover-spaces` result. +- **Select option IDs** are nested under `spaces[""].types[""].properties[""].select["