ocp-mcp-server 0.2.0b1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "WebFetch(domain:api-dev.bimplus.net)",
5
+ "Bash(curl -s -I \"https://api-dev.bimplus.net/swagger/index.html\")",
6
+ "Bash(curl -s \"https://api-dev.bimplus.net/swagger/index.html\")",
7
+ "Bash(curl *)",
8
+ "Bash(python3 *)",
9
+ "Bash(.venv/bin/pip install *)",
10
+ "Bash(pip3 --version)",
11
+ "Read(//usr/local/bin/**)",
12
+ "Read(//opt/homebrew/bin/**)",
13
+ "Bash(brew list *)",
14
+ "Bash(command -v pyenv)",
15
+ "Bash(pyenv versions *)",
16
+ "Bash(command -v uv)",
17
+ "Bash(uv python *)",
18
+ "Read(//Users/jabualdenien/.pyenv/**)",
19
+ "Bash(uv venv *)",
20
+ "Bash(uv pip *)",
21
+ "Bash(.venv/bin/python3 *)",
22
+ "Bash(.venv/bin/python *)",
23
+ "Bash(pkill -x \"Claude\")",
24
+ "Bash(open -a \"Claude\")",
25
+ "Bash(grep -v '^$')",
26
+ "Bash(/Users/jabualdenien/Downloads/claude-test/bimplus-api-mcp/.venv/bin/pip install *)",
27
+ "Bash(uv --version)",
28
+ "Bash(gtimeout 5 .venv/bin/python server.py)",
29
+ "Bash(/Users/jabualdenien/Downloads/claude-test/bimplus-api-mcp/.venv/bin/python *)",
30
+ "Read(//Users/jabualdenien/Downloads/claude-test/**)",
31
+ "Bash(zip -r bimplus-api-mcp.zip bimplus-api-mcp/ --exclude 'bimplus-api-mcp/.venv/*' --exclude 'bimplus-api-mcp/__pycache__/*' --exclude bimplus-api-mcp/runtime_config.json --exclude bimplus-api-mcp/CLAUDE.md)",
32
+ "Bash(zip -r bimplus-api-mcp.zip bimplus-api-mcp/ --exclude 'bimplus-api-mcp/.venv/*' --exclude 'bimplus-api-mcp/__pycache__/*' --exclude bimplus-api-mcp/runtime_config.json --exclude bimplus-api-mcp/CLAUDE.md --exclude 'bimplus-api-mcp/.claude/*')",
33
+ "Bash(unzip -l bimplus-api-mcp.zip)",
34
+ "Bash(rm bimplus-api-mcp.zip)",
35
+ "Bash(zip bimplus-api-mcp.zip bimplus-api-mcp/server.py bimplus-api-mcp/swagger.json bimplus-api-mcp/pyproject.toml bimplus-api-mcp/install.sh bimplus-api-mcp/README.md)",
36
+ "Bash(chmod +x bimplus-api-mcp/install.sh)",
37
+ "Bash(bash -n /Users/jabualdenien/Downloads/claude-test/bimplus-api-mcp/install.sh)",
38
+ "Bash(open *)",
39
+ "Bash(ls /Users/jabualdenien/Downloads/GIT/ocp-mcp-server/bimplus-api-mcp/*.md /Users/jabualdenien/Downloads/GIT/ocp-mcp-server/bimplus-api-mcp/../*.md 2>/dev/null)",
40
+ "Read(//Users/jabualdenien/Downloads/GIT/ocp-mcp-server/**)",
41
+ "Bash(uv build *)"
42
+ ]
43
+ }
44
+ }
@@ -0,0 +1,35 @@
1
+ # Runtime configuration with credentials - NEVER commit
2
+ runtime_config.json
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.pyc
7
+ *.pyo
8
+ *.egg-info/
9
+ .eggs/
10
+ dist/
11
+ build/
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ env/
17
+
18
+ # IDE
19
+ .vscode/
20
+ .idea/
21
+ *.swp
22
+ *.swo
23
+ *~
24
+
25
+ # OS
26
+ .DS_Store
27
+ Thumbs.db
28
+
29
+ # Logs
30
+ *.log
31
+
32
+ # Environment files with secrets
33
+ .env
34
+ .env.local
35
+ .env.*.local
@@ -0,0 +1,83 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## What this project is
6
+
7
+ A Python MCP (Model Context Protocol) server that dynamically exposes the BimPlus API (394 endpoints) as MCP tools, plus a handful of hand-crafted "smart tools" that chain multiple API calls.
8
+
9
+ ## Running and development
10
+
11
+ ```bash
12
+ # Run the MCP server directly (stdio transport)
13
+ .venv/bin/python server.py
14
+
15
+ # Install/sync dependencies (uses uv or pip into the local .venv)
16
+ uv pip install -e .
17
+ # or
18
+ .venv/bin/pip install -e .
19
+ ```
20
+
21
+ There are no tests and no build step — the single source file is `server.py`.
22
+
23
+ ## Architecture
24
+
25
+ All logic lives in `server.py`. The startup flow is:
26
+
27
+ 1. `swagger.json` is loaded at module import time into `SPEC`.
28
+ 2. `_populate_tools()` iterates every path+method in the spec and registers an entry in `_TOOLS` (a `dict[name → (method, path, op)]`). Tool names are derived from the HTTP method and path slug, deduplicated with a numeric suffix.
29
+ 3. The MCP `list_tools` handler returns the hand-crafted config/search tools followed by all auto-generated API tools.
30
+ 4. The MCP `call_tool` handler dispatches to config tools first, then looks up the name in `_TOOLS` and executes the request via `httpx`.
31
+
32
+ ### Config system
33
+
34
+ Runtime config is layered (later wins):
35
+ - Defaults (`_DEFAULT_CONFIG`)
36
+ - Environment variables (`BIMPLUS_TOKEN`, `BIMPLUS_BASE_URL`, `BIMPLUS_TEAM_SLUG`, etc.)
37
+ - `runtime_config.json` (written by the `set_bimplus_config` tool)
38
+
39
+ Config is read fresh on every tool call so changes take effect without a restart.
40
+
41
+ ### Hand-crafted tools
42
+
43
+ Beyond the auto-generated API tools, `server.py` defines these named tools:
44
+
45
+ | Tool | Purpose |
46
+ |---|---|
47
+ | `ocp_help` | Front-door routing; returns capabilities and example prompts |
48
+ | `set_bimplus_config` | Write fields to `~/.config/ocp-mcp/runtime_config.json` |
49
+ | `get_bimplus_config` | Read current config (sensitive fields masked) |
50
+ | `authenticate_bimplus` | POST `/v2/authorize` with stored credentials and save token |
51
+ | `start_sso_login` | Full OAuth2 PKCE browser flow: asyncio local server → Keycloak → cross-token → Identity token |
52
+ | `set_bimplus_sso_token` | Validate and save a pasted Bearer/Identity token |
53
+ | `list_my_teams` | GET `/v2/teams` with normalized output |
54
+ | `list_team_projects` | GET projects for a team with optional filter |
55
+ | `list_project_models` | GET divisions (models) for a project with optional filter |
56
+ | `search_objects` | 5-step chain: topology → divisions → filter → exportobjects → filtered results |
57
+ | `count_elements_by_type` | Count objects per element type (parallel requests) |
58
+ | `count_elements_by_property_value` | Count objects of a type where a property matches a value |
59
+ | `bulk_update_property_by_filter` | Safe mass attribute update with dry-run, batching, and read-back verification |
60
+ | `project_dashboard_insights` | One-call project dashboard: issues, element totals, top types, area/volume |
61
+
62
+ ### Auto-generated tool naming
63
+
64
+ `_build_tool_name(method, path)` strips the `/v2` prefix, converts `{param}` to `by_param`, replaces non-alphanumeric characters with underscores, and prefixes with the HTTP method. Names are truncated to 61 chars to leave room for dedup suffixes.
65
+
66
+ ### Schema resolution
67
+
68
+ `_resolve_schema()` walks `$ref` chains up to depth 4, flattening OpenAPI component schemas into inline MCP-compatible JSON Schema. Request bodies are exposed as a single `body` property.
69
+
70
+ ### `teamSlug` auto-fill
71
+
72
+ If a tool has a `teamSlug` path parameter and the caller omits it, the value from config is substituted automatically before the request is made.
73
+
74
+ ## Key files
75
+
76
+ - `server.py` — entire server (~2700 lines)
77
+ - `swagger.json` — BimPlus OpenAPI v2 spec (394 paths, ~2.3 MB)
78
+ - `~/.config/ocp-mcp/runtime_config.json` — persisted runtime config (token, base_url, team_slug, credentials)
79
+ - `pyproject.toml` — project metadata, entry point `ocp-mcp = "server:main"`
80
+
81
+ ## Credentials note
82
+
83
+ `runtime_config.json` contains live credentials and tokens. Do not commit it. The file is read at runtime and written by `set_bimplus_config`.
@@ -0,0 +1,384 @@
1
+ Metadata-Version: 2.4
2
+ Name: ocp-mcp-server
3
+ Version: 0.2.0b1
4
+ Summary: OCP (Open Collaboration Platform) MCP server — exposes the BimPlus API as Claude tools [BETA]
5
+ License: MIT
6
+ Classifier: Development Status :: 4 - Beta
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: httpx>=0.27.0
14
+ Requires-Dist: mcp>=1.0.0
15
+ Description-Content-Type: text/markdown
16
+
17
+ # BimPlus API — Claude MCP Server
18
+
19
+ Gives Claude desktop direct access to the full BimPlus API (394 endpoints) plus smart tools for searching and managing BIM objects.
20
+
21
+ ---
22
+
23
+ ## Prerequisites
24
+
25
+ | Requirement | Notes |
26
+ |---|---|
27
+ | **macOS** | Windows not yet supported |
28
+ | **Python 3.10+** | Check with `python3 --version`. Download from [python.org](https://www.python.org/downloads/) if needed |
29
+ | **Claude desktop** | Download from [claude.ai/download](https://claude.ai/download) |
30
+ | **BimPlus account** | You need your Nemetschek email and password |
31
+
32
+ ---
33
+
34
+ ## Security Notes
35
+
36
+ **⚠️ Credentials in `runtime_config.json`**
37
+
38
+ When you authenticate, your token is saved to `~/.config/ocp-mcp/runtime_config.json`. **This file contains live credentials and should NEVER be committed to version control.**
39
+
40
+ **Guidelines:**
41
+ - ✅ `.gitignore` already contains `runtime_config.json` — verify this before committing
42
+ - ✅ Restrict file permissions: `chmod 600 runtime_config.json` (owner read-only)
43
+ - ✅ Never share this file or its contents with others
44
+ - ✅ Tokens automatically expire; re-authenticate when needed
45
+ - ⚠️ For production deployments, use secure credential storage (e.g., AWS Secrets Manager, HashiCorp Vault)
46
+
47
+ **SSL Verification (Advanced)**
48
+ By default, SSL certificate verification is **enabled** (`verify_ssl=true`). For staging environments with self-signed certificates, you can disable it via environment variable:
49
+ ```bash
50
+ export BIMPLUS_VERIFY_SSL=false
51
+ ```
52
+ Or in `runtime_config.json`:
53
+ ```json
54
+ {
55
+ "verify_ssl": "false"
56
+ }
57
+ ```
58
+ ⚠️ Only disable for development/staging — always enable for production.
59
+
60
+ ---
61
+
62
+ ## Installation (2 minutes)
63
+
64
+ **1. Download and extract** the zip file to a permanent location on your Mac.
65
+ > Tip: put it somewhere it won't be accidentally deleted, e.g. `~/Applications/bimplus-mcp/`
66
+
67
+ **2. Open Terminal** — press `Cmd+Space`, type `Terminal`, press Enter.
68
+
69
+ **3. Run the installer:**
70
+
71
+ ```bash
72
+ cd /path/to/bimplus-api-mcp
73
+ bash install.sh
74
+ ```
75
+
76
+ Replace `/path/to/bimplus-api-mcp` with the actual folder you extracted to.
77
+ Example: `cd ~/Applications/bimplus-mcp && bash install.sh`
78
+
79
+ **4. Restart Claude desktop** — quit (`Cmd+Q`) and reopen it.
80
+
81
+ **5. Authenticate** — in a new Claude conversation, type:
82
+
83
+ ```
84
+ Use authenticate_bimplus to log me in with email jabualdenien@nemetschek.com
85
+ ```
86
+
87
+ Claude will ask for your password and save the token for future sessions.
88
+
89
+ ---
90
+
91
+ ## What you can do after setup
92
+
93
+ Just ask Claude in plain English:
94
+
95
+ - *"Show me all models in team acme-corp"*
96
+ - *"Find all doors on the second floor"*
97
+ - *"What are the properties of element XYZ?"*
98
+ - *"Search for walls with fire rating EI60"*
99
+
100
+ ---
101
+
102
+ ## Smart tools (LLM-friendly)
103
+
104
+ This server exposes all API endpoints from `swagger.json` and also provides higher-level tools that combine multiple API calls.
105
+
106
+ ### `ocp_help`
107
+ - Purpose: Front-door routing tool. Returns available capabilities and example prompts.
108
+ - Use when: Prompt contains "OCP", "BimPlus", "construction platform", or when unsure which tool to use.
109
+ - Trigger phrases: "what can OCP do", "help with OCP", "what tools are available", "open OCP".
110
+ - Output: Full list of capabilities with example prompts.
111
+
112
+ ### `set_bimplus_config`
113
+ - Purpose: Save runtime connection settings (token, base URL, team, credentials).
114
+ - Use when: Authentication or API calls fail due to missing config.
115
+ - Output: Saved config with sensitive fields masked.
116
+
117
+ ### `get_bimplus_config`
118
+ - Purpose: Read current runtime settings.
119
+ - Use when: You want to verify what token/team/base URL is active.
120
+ - Output: Current config with sensitive fields masked. Shows a first-run hint if no config file exists yet.
121
+
122
+ ### `authenticate_bimplus`
123
+ - Purpose: Log in with stored credentials and save a fresh token.
124
+ - Primary tool for: "login to OCP", "log in to OCP", "authenticate OCP", "connect to BimPlus".
125
+ - Required config first: `user_id`, `password`, `application_id`.
126
+ - Output: Auth status and token metadata.
127
+
128
+ ### `start_sso_login`
129
+ - Purpose: Full browser-based SSO login — opens the Allplan login page and captures the token automatically via OAuth2 PKCE. No manual token copy-paste required.
130
+ - Use when: "Login to OCP with SSO", "browser login", "login via portal".
131
+ - Flow: browser opens → user logs in → token saved automatically.
132
+ - Optional input: `clear_password` (default `true`), `timeout_seconds` (default `120`).
133
+ - Output: Login status and masked token metadata.
134
+
135
+ ### `set_bimplus_sso_token`
136
+ - Purpose: Manually paste a Bearer token (fallback when browser login isn't possible).
137
+ - Use when: You already have an OCP/BimPlus access token from another source.
138
+ - Required input: `token`.
139
+ - Optional input: `token_type` (default `Bearer`), `clear_password` (default `true`).
140
+ - Output: Token validation status and masked token metadata.
141
+
142
+ ### `list_my_teams`
143
+ - Purpose: List teams available to the current user.
144
+ - Use when: You ask "list my teams" / "show available teams" / "search team".
145
+ - Optional input: `query`, `limit`.
146
+ - Output: Normalized team rows (`id`, `name`, `slug`).
147
+
148
+ ### `list_team_projects`
149
+ - Purpose: List projects in a team and optionally search by name/ID.
150
+ - Use when: You ask "list all projects" / "search team project".
151
+ - Optional input: `team_slug`, `query`, `limit`.
152
+ - Output: Normalized project rows (`id`, `name`, `number`, `status`).
153
+
154
+ ### `list_project_models`
155
+ - Purpose: List models (project divisions) in the current project and optionally filter them.
156
+ - Use when: You ask "show the model names" / "which models are available here" / "list models" / "what models are in this project".
157
+ - Optional input: `team_slug`, `project_id`, `query`, `limit`.
158
+ - Output: Normalized model rows (`id`, `name`) plus the current model when available.
159
+
160
+ ### `search_objects`
161
+ - Purpose: Run object search across project topology with optional filters.
162
+ - Required input: `project_id`.
163
+ - Filter options:
164
+ - `conditions`: structured equality filters.
165
+ - `filter_string`: raw advanced BIMPlus filter syntax.
166
+ - Output: Filtered result hierarchy/export payload.
167
+
168
+ ### `count_elements_by_type`
169
+ - Purpose: Count objects per element type in a project.
170
+ - Required input: `project_id`.
171
+ - Optional input: `team_slug`, `include_zero`, `max_concurrency`.
172
+ - Output: Per-type counts, per-discipline totals, and errors.
173
+
174
+ ### `count_elements_by_property_value`
175
+ - Purpose: Count objects where a property equals a value for a specific type.
176
+ - Required input: `project_id`, `type_name_or_id`, `property_name`, `property_value`.
177
+ - Optional input: `case_sensitive`, `trim_whitespace`, `sample_limit`.
178
+ - Output: Matched count, sample IDs, and top value distribution.
179
+
180
+ ### `bulk_update_property_by_filter`
181
+ - Purpose: Safely update an attribute for all objects matched by a filter.
182
+ - Required input: `project_id`, `type_name_or_id`, `filter_property_name`, `filter_property_value`, `attribute_id`, `new_value`.
183
+ - Safety flow:
184
+ - Preview first with `dry_run=true`.
185
+ - Apply only with `dry_run=false` and `confirm=true`.
186
+ - Optionally verify read-back with `verify=true` and `target_property_name`.
187
+ - Output: Match summary, update status, failed IDs, verification details.
188
+
189
+ ### `project_dashboard_insights`
190
+ - Purpose: Build a one-call project dashboard with project details, issue summaries, element totals, top types, and area/volume insights.
191
+ - Required input: `project_id`.
192
+ - Optional input: `team_slug`, `top_n_types`, `sample_issue_limit`, `include_element_samples`, `area_property_names`, `volume_property_names`.
193
+ - Output: Normalized dashboard JSON suitable for charts/tables and follow-up analysis.
194
+
195
+ ### Generic API endpoint tools
196
+ - Purpose: Direct access to each endpoint in the BIMPlus OpenAPI spec.
197
+ - Naming: Derived from HTTP method and path, for example `get_by_teamslug_projects_by_projectid_element_types`.
198
+ - Output: HTTP status and raw endpoint response.
199
+
200
+ ---
201
+
202
+ ## Example prompts
203
+
204
+ **Getting started**
205
+ - "What can OCP do?" *(routes to ocp_help)*
206
+ - "Login to OCP." *(credentials in config)*
207
+ - "Login to OCP with SSO." *(browser opens automatically)*
208
+ - "Login to OCP with SSO token <paste token>." *(manual paste fallback)*
209
+
210
+ **Discovery**
211
+ - "List my teams."
212
+ - "List all projects in my current team."
213
+ - "Which models are available here?"
214
+ - "Show OCP projects in team <slug>."
215
+
216
+ **Analysis**
217
+ - "Count all object types in project <project_id>."
218
+ - "How many Columns have material C30/37?"
219
+ - "Show project dashboard for <project_id>."
220
+ - "Search OCP objects where material is C30/37."
221
+
222
+ **Edits**
223
+ - "Preview updating Product name to Claude for Columns where material is C30/37."
224
+ - "Apply that update now with confirm=true and verify using target property Product name."
225
+
226
+ **Low-level**
227
+ - "Call get_by_teamslug_projects_by_projectid_element_types for team <team_slug> and project <project_id>."
228
+
229
+ ---
230
+
231
+ ## Tool Catalog Modes And Fallback
232
+
233
+ This server supports three catalog modes:
234
+
235
+ - `smart`: smart tools only (lowest token usage)
236
+ - `hybrid`: smart tools + curated autogenerated endpoints
237
+ - `full`: smart tools + full autogenerated endpoint catalog (can be capped)
238
+
239
+ To reduce "tool not available" responses while staying efficient, smart mode can expose a fallback slice:
240
+
241
+ - `tool_catalog_fallback_mode`: `off` | `hybrid` | `full`
242
+ - `tool_catalog_fallback_limit`: number of fallback autogenerated tools to expose in smart mode
243
+
244
+ You can set these via `set_bimplus_config`:
245
+
246
+ ```text
247
+ Set tool_catalog_mode to "smart"
248
+ Set tool_catalog_fallback_mode to "hybrid"
249
+ Set tool_catalog_fallback_limit to 25
250
+ ```
251
+
252
+ Or directly in `runtime_config.json` / env vars (`BIMPLUS_TOOL_CATALOG_*`).
253
+
254
+ ---
255
+
256
+ ## Session1 Regression Script
257
+
258
+ You can run a full scenario regression matching the historical `session1.md` workflow.
259
+
260
+ ### Safe mode (default, no writes)
261
+
262
+ ```bash
263
+ .venv/bin/python scripts/session1_regression.py
264
+ ```
265
+
266
+ This runs authentication, read-only checks, the new model discovery step, and the bulk-update **dry-run** safety step.
267
+ If stored credentials are stale, the auth step falls back to validating the existing session token so the rest of the regression can still complete.
268
+
269
+ ### Full parity mode (includes write apply)
270
+
271
+ ```bash
272
+ .venv/bin/python scripts/session1_regression.py --apply-writes
273
+ ```
274
+
275
+ This also executes the bulk update apply step and writes data (same target value used in session: `Claude`).
276
+
277
+ ### Useful flags
278
+
279
+ ```bash
280
+ .venv/bin/python scripts/session1_regression.py \
281
+ --team-slug ctf-nemetschek-allplan-gmbh-ft \
282
+ --project-id 3e9fed73-0c06-48fb-888a-d5b2ad7b3c05 \
283
+ --model-id 9deba3db-2c4a-4ce6-b1ec-45c5b2b35929 \
284
+ --keep-config
285
+ ```
286
+
287
+ Notes:
288
+ - Exit code is `0` when all scenarios pass, otherwise `1`.
289
+ - By default, the script restores your previous runtime config after execution.
290
+
291
+ ---
292
+
293
+ ## Changing your team or project
294
+
295
+ ```
296
+ Set the BimPlus team slug to "my-team-name"
297
+ Set the BimPlus project ID to "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
298
+ ```
299
+
300
+ Claude will remember these settings between sessions.
301
+
302
+ ---
303
+
304
+ ## Troubleshooting
305
+
306
+ **"bimplus-api" does not appear in Claude's tools**
307
+ - Make sure you fully quit and reopened Claude desktop after installation.
308
+ - Re-run `bash install.sh` to check for errors.
309
+
310
+ **Authentication fails**
311
+ - Ask Claude: *"What is the current BimPlus config?"* to verify the token field.
312
+ - Try authenticating again: *"Run authenticate_bimplus"*
313
+ - If you see HTTP 401 Unauthorized, update `password` and/or `application_id` via `set_bimplus_config`, then retry.
314
+ - Do not store masked values (e.g. `Micr...09`) in `runtime_config.json`; authentication requires the full plaintext password.
315
+
316
+ ### Prefer SSO Login (No Password In Config)
317
+
318
+ The easiest way — no password, no copy-paste:
319
+
320
+ ```text
321
+ Login to OCP with SSO.
322
+ ```
323
+
324
+ Claude opens the Allplan login page in your browser. Once you complete login, the token is captured and saved automatically. The whole flow takes about 15 seconds.
325
+
326
+ **How it works under the hood:**
327
+ 1. A temporary local HTTP server starts on port `8766`.
328
+ 2. Your browser opens to the Allplan Keycloak login page (OAuth2 PKCE flow).
329
+ 3. After login, Keycloak redirects to `http://localhost:8766/callback` with an authorization code.
330
+ 4. The server exchanges the code for a Keycloak token, then exchanges that for a BimPlus Identity token via `/v2/cross-token` → `/v2/cross-authorize`.
331
+ 5. The Identity token is saved to config; the local server shuts down.
332
+
333
+ **Fallback — paste a token manually:**
334
+
335
+ If the browser flow isn't available, call `set_bimplus_sso_token` and paste a token directly:
336
+
337
+ ```text
338
+ Use set_bimplus_sso_token with:
339
+ - token: <PASTE_ACCESS_TOKEN>
340
+ - token_type: Identity
341
+ - clear_password: true
342
+ ```
343
+
344
+ The server validates via `GET /v2/authorize` before saving.
345
+
346
+ **Config knobs:**
347
+ - `sso_callback_port` — local port for the OAuth redirect (default `8766`)
348
+ - `sso_auth_server` — Keycloak base URL (auto-derived from `base_url` if empty)
349
+
350
+ **Python not found**
351
+ - Install Python 3.10+ from [python.org](https://www.python.org/downloads/) and re-run `install.sh`.
352
+
353
+ ---
354
+
355
+ ## What install.sh does
356
+
357
+ 1. Checks that Python 3.10+ is installed
358
+ 2. Creates a local `.venv` virtual environment (uses `uv` if available, otherwise `python -m venv`)
359
+ 3. Installs the two dependencies: `mcp` and `httpx`
360
+ 4. Patches `~/Library/Application Support/Claude/claude_desktop_config.json` to register the `bimplus-api` MCP server entry pointing at the local venv and `server.py`
361
+
362
+ It is safe to re-run — it will update an existing installation in place.
363
+
364
+ ---
365
+
366
+ ## Sharing with colleagues
367
+
368
+ Send them the zip and this message:
369
+
370
+ > Extract the zip somewhere permanent (e.g. `~/Applications/bimplus-mcp/`), open Terminal, run `bash install.sh`, restart Claude desktop, then ask Claude to run `authenticate_bimplus` with your Nemetschek credentials.
371
+
372
+ ---
373
+
374
+ ## Files in this package
375
+
376
+ | File | Purpose |
377
+ |---|---|
378
+ | `server.py` | The MCP server (all logic lives here) |
379
+ | `swagger.json` | Full BimPlus API specification |
380
+ | `pyproject.toml` | Python package metadata |
381
+ | `install.sh` | Automated setup script |
382
+ | `README.md` | This file |
383
+
384
+ `runtime_config.json` is created automatically the first time you authenticate — it stores your token locally and is never sent anywhere except to the BimPlus API.