@hybridlabor-api/aos 4.4.1 → 4.4.2-beta.0
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.
- package/.agents/skills/firecrawl/SKILL.md +149 -0
- package/.agents/skills/firecrawl/rules/install.md +82 -0
- package/.agents/skills/firecrawl/rules/security.md +26 -0
- package/.agents/skills/firecrawl-agent/SKILL.md +58 -0
- package/.agents/skills/firecrawl-build/SKILL.md +39 -0
- package/.agents/skills/firecrawl-build-interact/SKILL.md +68 -0
- package/.agents/skills/firecrawl-build-onboarding/SKILL.md +103 -0
- package/.agents/skills/firecrawl-build-onboarding/references/auth-flow.md +39 -0
- package/.agents/skills/firecrawl-build-onboarding/references/project-setup.md +20 -0
- package/.agents/skills/firecrawl-build-onboarding/references/sdk-installation.md +17 -0
- package/.agents/skills/firecrawl-build-scrape/SKILL.md +69 -0
- package/.agents/skills/firecrawl-build-search/SKILL.md +69 -0
- package/.agents/skills/firecrawl-crawl/SKILL.md +59 -0
- package/.agents/skills/firecrawl-download/SKILL.md +70 -0
- package/.agents/skills/firecrawl-interact/SKILL.md +84 -0
- package/.agents/skills/firecrawl-map/SKILL.md +51 -0
- package/.agents/skills/firecrawl-scrape/SKILL.md +69 -0
- package/.agents/skills/firecrawl-search/SKILL.md +60 -0
- package/CLAUDE.md +573 -0
- package/README.de.md +0 -8
- package/README.md +0 -8
- package/README.pt.md +0 -8
- package/assets/brand/ao-ant-mark.svg +91 -0
- package/assets/brand/bdb-core-mark.svg +34 -0
- package/assets/brand/heimdall-guardian-mark.svg +16 -0
- package/assets/brand/memb-crystal-mark.svg +18 -0
- package/bin/aos-config.mjs +89 -0
- package/bin/aos-dashboard.mjs +608 -0
- package/bin/aos-uninstall.mjs +227 -0
- package/docs/sessions/audit-2026-09-14-silent-failures.md +114 -0
- package/docs/skills_table.md +0 -3
- package/installer.js +387 -237
- package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +10 -0
- package/mcps/after-effects-mcp/build/index.js +840 -0
- package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +153 -0
- package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +218 -0
- package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +71 -0
- package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +147 -0
- package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +114 -0
- package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +115 -0
- package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +192 -0
- package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +90 -0
- package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +50 -0
- package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +1773 -0
- package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +160 -0
- package/mcps/computer-use-mcp/dist/client.d.ts +150 -0
- package/mcps/computer-use-mcp/dist/client.js +136 -0
- package/mcps/computer-use-mcp/dist/entrypoint.d.ts +16 -0
- package/mcps/computer-use-mcp/dist/entrypoint.js +26 -0
- package/mcps/computer-use-mcp/dist/native.d.ts +212 -0
- package/mcps/computer-use-mcp/dist/native.js +50 -0
- package/mcps/computer-use-mcp/dist/server.d.ts +32 -0
- package/mcps/computer-use-mcp/dist/server.js +342 -0
- package/mcps/computer-use-mcp/dist/session.d.ts +101 -0
- package/mcps/computer-use-mcp/dist/session.js +2372 -0
- package/package.json +13 -4
- package/skills/global_config/aos-project-init/SKILL.md +97 -130
- package/skills/global_config/aos-project-init/assets/openwikiignore.template +62 -0
- package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +38 -1
- package/skills/global_config/aos-setup/SKILL.md +98 -8
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +21 -2
- package/skills/global_config/ask-tim/SKILL.md +2 -7
- package/skills/global_config/openwiki-skill/scripts/openwiki_daemon.py +65 -12
- package/bin/setup-saas.mjs +0 -792
- package/mcps/blender-mcp-server/.dockerignore +0 -19
- package/mcps/blender-mcp-server/.github/workflows/ci.yml +0 -67
- package/mcps/blender-mcp-server/.github/workflows/publish-pypi.yml +0 -54
- package/mcps/blender-mcp-server/CHANGELOG.md +0 -64
- package/mcps/blender-mcp-server/CONTRIBUTING.md +0 -107
- package/mcps/blender-mcp-server/Dockerfile +0 -19
- package/mcps/blender-mcp-server/LICENSE +0 -21
- package/mcps/blender-mcp-server/README.md +0 -409
- package/mcps/blender-mcp-server/addon/__init__.py +0 -1440
- package/mcps/blender-mcp-server/addon/models.py +0 -223
- package/mcps/blender-mcp-server/pyproject.toml +0 -120
- package/mcps/blender-mcp-server/scripts/blender_bridge_request.py +0 -71
- package/mcps/blender-mcp-server/scripts/blender_create_test_cube.py +0 -49
- package/mcps/blender-mcp-server/scripts/blender_scene_info.py +0 -38
- package/mcps/blender-mcp-server/scripts/build_addon_zip.sh +0 -29
- package/mcps/blender-mcp-server/scripts/demos/README.md +0 -186
- package/mcps/blender-mcp-server/scripts/demos/dam_break_scene.py +0 -276
- package/mcps/blender-mcp-server/scripts/demos/open_dam_break_gui.py +0 -33
- package/mcps/blender-mcp-server/scripts/demos/pipe_movement_study.py +0 -518
- package/mcps/blender-mcp-server/scripts/demos/pipe_pressure_failure_scene.py +0 -806
- package/mcps/blender-mcp-server/scripts/demos/procedural_dam_break_scene.py +0 -600
- package/mcps/blender-mcp-server/scripts/demos/run_dam_break.py +0 -510
- package/mcps/blender-mcp-server/scripts/launch_blender_gui.py +0 -41
- package/mcps/blender-mcp-server/scripts/library/README.md +0 -64
- package/mcps/blender-mcp-server/scripts/library/apply_transforms.py +0 -46
- package/mcps/blender-mcp-server/scripts/library/camera.py +0 -51
- package/mcps/blender-mcp-server/scripts/library/collections.py +0 -65
- package/mcps/blender-mcp-server/scripts/library/create_mesh.py +0 -41
- package/mcps/blender-mcp-server/scripts/library/effector.py +0 -48
- package/mcps/blender-mcp-server/scripts/library/fluid_domain.py +0 -80
- package/mcps/blender-mcp-server/scripts/library/fluid_inflow.py +0 -98
- package/mcps/blender-mcp-server/scripts/library/frame_range.py +0 -35
- package/mcps/blender-mcp-server/scripts/library/keyframes.py +0 -59
- package/mcps/blender-mcp-server/scripts/library/rigid_body.py +0 -52
- package/mcps/blender-mcp-server/scripts/library/save_blend.py +0 -40
- package/mcps/blender-mcp-server/scripts/server_start.sh +0 -26
- package/mcps/blender-mcp-server/src/blender_mcp_server/__init__.py +0 -3
- package/mcps/blender-mcp-server/src/blender_mcp_server/headless.py +0 -330
- package/mcps/blender-mcp-server/src/blender_mcp_server/server.py +0 -606
- package/mcps/davinci-mcp-professional/.bandit +0 -35
- package/mcps/davinci-mcp-professional/.claude/commands/security-review.md +0 -191
- package/mcps/davinci-mcp-professional/.claude/settings.json +0 -1
- package/mcps/davinci-mcp-professional/.editorconfig +0 -27
- package/mcps/davinci-mcp-professional/.gitattributes +0 -207
- package/mcps/davinci-mcp-professional/.github/CODEOWNERS +0 -2
- package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
- package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
- package/mcps/davinci-mcp-professional/.github/PULL_REQUEST_TEMPLATE.md +0 -20
- package/mcps/davinci-mcp-professional/.github/SECURITY.md +0 -97
- package/mcps/davinci-mcp-professional/.github/dependabot.yml +0 -27
- package/mcps/davinci-mcp-professional/.github/workflows/ci.yml +0 -39
- package/mcps/davinci-mcp-professional/ATTRIBUTION.md +0 -4
- package/mcps/davinci-mcp-professional/AUTHORS.md +0 -9
- package/mcps/davinci-mcp-professional/BUGS.md +0 -55
- package/mcps/davinci-mcp-professional/CLAUDE.md +0 -229
- package/mcps/davinci-mcp-professional/CONTRIBUTING.md +0 -51
- package/mcps/davinci-mcp-professional/COPYING.md +0 -228
- package/mcps/davinci-mcp-professional/Doxyfile +0 -379
- package/mcps/davinci-mcp-professional/README.md +0 -143
- package/mcps/davinci-mcp-professional/SECURITY.md +0 -40
- package/mcps/davinci-mcp-professional/USING.md +0 -301
- package/mcps/davinci-mcp-professional/VERSION.md +0 -13
- package/mcps/davinci-mcp-professional/build.py +0 -169
- package/mcps/davinci-mcp-professional/claude_desktop_config_template.json +0 -11
- package/mcps/davinci-mcp-professional/hooks/ci-check.sh +0 -29
- package/mcps/davinci-mcp-professional/hooks/pre-push +0 -46
- package/mcps/davinci-mcp-professional/main.py +0 -40
- package/mcps/davinci-mcp-professional/mcp_server.py +0 -30
- package/mcps/davinci-mcp-professional/pyproject.toml +0 -115
- package/mcps/davinci-mcp-professional/security_audit.py +0 -379
- package/mcps/davinci-mcp-professional/src/davinci_mcp/__init__.py +0 -19
- package/mcps/davinci-mcp-professional/src/davinci_mcp/cli.py +0 -138
- package/mcps/davinci-mcp-professional/src/davinci_mcp/resolve_client.py +0 -342
- package/mcps/davinci-mcp-professional/src/davinci_mcp/resources/__init__.py +0 -60
- package/mcps/davinci-mcp-professional/src/davinci_mcp/server.py +0 -185
- package/mcps/davinci-mcp-professional/src/davinci_mcp/tools/__init__.py +0 -146
- package/mcps/davinci-mcp-professional/src/davinci_mcp/types.py +0 -125
- package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/__init__.py +0 -19
- package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/platform.py +0 -239
- package/mcps/davinci-mcp-professional/test.py +0 -186
- package/mcps/davinci-mcp-professional/uv.lock +0 -2073
- package/mcps/davinci-resolve-mcp/.claude/skills/media-analysis.md +0 -44
- package/mcps/davinci-resolve-mcp/.clinerules +0 -17
- package/mcps/davinci-resolve-mcp/.cursorrules +0 -17
- package/mcps/davinci-resolve-mcp/.github/copilot-instructions.md +0 -17
- package/mcps/davinci-resolve-mcp/.github/workflows/npm-publish.yml +0 -109
- package/mcps/davinci-resolve-mcp/.windsurfrules +0 -17
- package/mcps/davinci-resolve-mcp/AGENTS.md +0 -114
- package/mcps/davinci-resolve-mcp/CHANGELOG.md +0 -2648
- package/mcps/davinci-resolve-mcp/CLAUDE.md +0 -15
- package/mcps/davinci-resolve-mcp/LICENSE +0 -21
- package/mcps/davinci-resolve-mcp/README.md +0 -173
- package/mcps/davinci-resolve-mcp/SECURITY.md +0 -53
- package/mcps/davinci-resolve-mcp/bin/davinci-resolve-mcp.mjs +0 -450
- package/mcps/davinci-resolve-mcp/examples/README.md +0 -53
- package/mcps/davinci-resolve-mcp/examples/markers/README.md +0 -81
- package/mcps/davinci-resolve-mcp/examples/media/README.md +0 -94
- package/mcps/davinci-resolve-mcp/examples/timeline/README.md +0 -98
- package/mcps/davinci-resolve-mcp/install.py +0 -1687
- package/mcps/davinci-resolve-mcp/package.json +0 -52
- package/mcps/davinci-resolve-mcp/release-notes/v2.22.0.md +0 -51
- package/mcps/davinci-resolve-mcp/release-notes/v2.23.0.md +0 -51
- package/mcps/davinci-resolve-mcp/release-notes/v2.23.1.md +0 -35
- package/mcps/davinci-resolve-mcp/release-notes/v2.24.1.md +0 -32
- package/mcps/davinci-resolve-mcp/scripts/audit_api_parity.py +0 -275
- package/mcps/davinci-resolve-mcp/scripts/audit_readwrite_symmetry.py +0 -80
- package/mcps/davinci-resolve-mcp/scripts/doctor.py +0 -227
- package/mcps/davinci-resolve-mcp/scripts/gen_api_limitations.py +0 -144
- package/mcps/davinci-resolve-mcp/scripts/live_media_analysis_polish_probe.py +0 -65
- package/mcps/davinci-resolve-mcp/scripts/measure_bridge_cost.py +0 -65
- package/mcps/davinci-resolve-mcp/scripts/regen_panel_screenshots.py +0 -76
- package/mcps/davinci-resolve-mcp/src/__init__.py +0 -3
- package/mcps/davinci-resolve-mcp/src/analysis_dashboard.py +0 -15505
- package/mcps/davinci-resolve-mcp/src/batch_cli.py +0 -540
- package/mcps/davinci-resolve-mcp/src/control_panel.py +0 -13
- package/mcps/davinci-resolve-mcp/src/granular/__init__.py +0 -17
- package/mcps/davinci-resolve-mcp/src/granular/common.py +0 -741
- package/mcps/davinci-resolve-mcp/src/granular/folder.py +0 -420
- package/mcps/davinci-resolve-mcp/src/granular/gallery.py +0 -306
- package/mcps/davinci-resolve-mcp/src/granular/graph.py +0 -309
- package/mcps/davinci-resolve-mcp/src/granular/media_pool.py +0 -679
- package/mcps/davinci-resolve-mcp/src/granular/media_pool_item.py +0 -1020
- package/mcps/davinci-resolve-mcp/src/granular/media_storage.py +0 -179
- package/mcps/davinci-resolve-mcp/src/granular/project.py +0 -1654
- package/mcps/davinci-resolve-mcp/src/granular/resolve_control.py +0 -538
- package/mcps/davinci-resolve-mcp/src/granular/timeline.py +0 -1075
- package/mcps/davinci-resolve-mcp/src/granular/timeline_item.py +0 -2251
- package/mcps/davinci-resolve-mcp/src/resolve_mcp_server.py +0 -43
- package/mcps/davinci-resolve-mcp/src/server.py +0 -24116
- package/mcps/davinci-resolve-mcp/src/utils/__init__.py +0 -3
- package/mcps/davinci-resolve-mcp/src/utils/actor_identity.py +0 -46
- package/mcps/davinci-resolve-mcp/src/utils/analysis_caps.py +0 -678
- package/mcps/davinci-resolve-mcp/src/utils/analysis_memory.py +0 -755
- package/mcps/davinci-resolve-mcp/src/utils/analysis_runs.py +0 -307
- package/mcps/davinci-resolve-mcp/src/utils/analysis_store.py +0 -945
- package/mcps/davinci-resolve-mcp/src/utils/api_truth.py +0 -525
- package/mcps/davinci-resolve-mcp/src/utils/app_control.py +0 -319
- package/mcps/davinci-resolve-mcp/src/utils/audio_fairlight_live_probe.py +0 -263
- package/mcps/davinci-resolve-mcp/src/utils/brain_edits.py +0 -387
- package/mcps/davinci-resolve-mcp/src/utils/bridge_metrics.py +0 -76
- package/mcps/davinci-resolve-mcp/src/utils/cdl.py +0 -20
- package/mcps/davinci-resolve-mcp/src/utils/clip_query.py +0 -85
- package/mcps/davinci-resolve-mcp/src/utils/cloud_operations.py +0 -192
- package/mcps/davinci-resolve-mcp/src/utils/color_grade_live_probe.py +0 -444
- package/mcps/davinci-resolve-mcp/src/utils/contracts.py +0 -102
- package/mcps/davinci-resolve-mcp/src/utils/cut_ir.py +0 -115
- package/mcps/davinci-resolve-mcp/src/utils/dctl_templates.py +0 -368
- package/mcps/davinci-resolve-mcp/src/utils/deep_vision.py +0 -643
- package/mcps/davinci-resolve-mcp/src/utils/destructive_hook.py +0 -606
- package/mcps/davinci-resolve-mcp/src/utils/edit_engine.py +0 -737
- package/mcps/davinci-resolve-mcp/src/utils/embeddings.py +0 -922
- package/mcps/davinci-resolve-mcp/src/utils/entities.py +0 -579
- package/mcps/davinci-resolve-mcp/src/utils/extension_authoring_live_probe.py +0 -292
- package/mcps/davinci-resolve-mcp/src/utils/failure_tracker.py +0 -119
- package/mcps/davinci-resolve-mcp/src/utils/fuse_templates.py +0 -1968
- package/mcps/davinci-resolve-mcp/src/utils/fusion_composition_live_probe.py +0 -284
- package/mcps/davinci-resolve-mcp/src/utils/fusion_group_settings.py +0 -334
- package/mcps/davinci-resolve-mcp/src/utils/layout_presets.py +0 -333
- package/mcps/davinci-resolve-mcp/src/utils/mcp_stdio.py +0 -32
- package/mcps/davinci-resolve-mcp/src/utils/mcp_transport.py +0 -128
- package/mcps/davinci-resolve-mcp/src/utils/media_analysis.py +0 -7690
- package/mcps/davinci-resolve-mcp/src/utils/media_analysis_jobs.py +0 -805
- package/mcps/davinci-resolve-mcp/src/utils/media_pool_changes.py +0 -121
- package/mcps/davinci-resolve-mcp/src/utils/media_pool_ingest_live_probe.py +0 -592
- package/mcps/davinci-resolve-mcp/src/utils/multicam.py +0 -393
- package/mcps/davinci-resolve-mcp/src/utils/object_inspection.py +0 -301
- package/mcps/davinci-resolve-mcp/src/utils/page_lock.py +0 -75
- package/mcps/davinci-resolve-mcp/src/utils/platform.py +0 -157
- package/mcps/davinci-resolve-mcp/src/utils/proc.py +0 -26
- package/mcps/davinci-resolve-mcp/src/utils/project_cleanup.py +0 -73
- package/mcps/davinci-resolve-mcp/src/utils/project_lifecycle_live_probe.py +0 -376
- package/mcps/davinci-resolve-mcp/src/utils/project_lint.py +0 -131
- package/mcps/davinci-resolve-mcp/src/utils/project_properties.py +0 -601
- package/mcps/davinci-resolve-mcp/src/utils/project_spec.py +0 -459
- package/mcps/davinci-resolve-mcp/src/utils/readback.py +0 -91
- package/mcps/davinci-resolve-mcp/src/utils/render_deliver_live_probe.py +0 -384
- package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_governance.py +0 -214
- package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_ledger.py +0 -244
- package/mcps/davinci-resolve-mcp/src/utils/resolve_busy.py +0 -171
- package/mcps/davinci-resolve-mcp/src/utils/resolve_connection.py +0 -77
- package/mcps/davinci-resolve-mcp/src/utils/review_annotation_live_probe.py +0 -352
- package/mcps/davinci-resolve-mcp/src/utils/script_templates.py +0 -1193
- package/mcps/davinci-resolve-mcp/src/utils/shot_relationships.py +0 -544
- package/mcps/davinci-resolve-mcp/src/utils/structural_diff.py +0 -175
- package/mcps/davinci-resolve-mcp/src/utils/sync_detection.py +0 -889
- package/mcps/davinci-resolve-mcp/src/utils/timeline_brain_db.py +0 -826
- package/mcps/davinci-resolve-mcp/src/utils/timeline_conform_live_probe.py +0 -280
- package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_live_probe.py +0 -1092
- package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_probe.py +0 -185
- package/mcps/davinci-resolve-mcp/src/utils/timeline_title_text.py +0 -87
- package/mcps/davinci-resolve-mcp/src/utils/timeline_versioning.py +0 -730
- package/mcps/davinci-resolve-mcp/src/utils/update_check.py +0 -685
- package/mcps/vectorworks-mcp/.dockerignore +0 -8
- package/mcps/vectorworks-mcp/Dockerfile +0 -28
- package/mcps/vectorworks-mcp/README.md +0 -156
- package/mcps/vectorworks-mcp/app/__init__.py +0 -2
- package/mcps/vectorworks-mcp/app/api.py +0 -52
- package/mcps/vectorworks-mcp/app/chunking.py +0 -56
- package/mcps/vectorworks-mcp/app/config.py +0 -29
- package/mcps/vectorworks-mcp/app/embeddings.py +0 -28
- package/mcps/vectorworks-mcp/app/indexer.py +0 -106
- package/mcps/vectorworks-mcp/app/main.py +0 -33
- package/mcps/vectorworks-mcp/app/mcp_server.py +0 -71
- package/mcps/vectorworks-mcp/app/search.py +0 -54
- package/mcps/vectorworks-mcp/app/utils.py +0 -14
- package/mcps/vectorworks-mcp/data/.gitkeep +0 -1
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_PluginScript.htm +0 -95
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_ScriptEditor.htm +0 -266
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_Scripting.htm +0 -106
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2023_CreatingScriptedPlugins.htm +0 -327
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2024_RunningScripts.htm +0 -116
- package/mcps/vectorworks-mcp/data/vw-devwiki/VS_Function_Reference_category.html +0 -2129
- package/mcps/vectorworks-mcp/data/vw-jp-ref/ObjectsSymbols.html +0 -2035
- package/mcps/vectorworks-mcp/data/vw-jp-ref/ScriptFunctionReference.html +0 -29
- package/mcps/vectorworks-mcp/design.md +0 -57
- package/mcps/vectorworks-mcp/docker-compose.yml +0 -18
- package/mcps/vectorworks-mcp/index/.gitkeep +0 -1
- package/mcps/vectorworks-mcp/index/meta.jsonl +0 -3956
- package/mcps/vectorworks-mcp/index/vw.faiss +0 -0
- package/mcps/vectorworks-mcp/requirements.txt +0 -10
- package/mcps/vectorworks-mcp/scripts/fetch_docs_minimal.sh +0 -84
- package/mcps/vectorworks-mcp/scripts/fetch_github_vectorworks.sh +0 -85
- package/mcps/vectorworks-mcp/templates/index.html +0 -40
- package/scripts/ecosystem-health-audit.js +0 -257
- package/skills/bdb-dev-os-skill/SKILL.md +0 -49
- package/skills/bdb-dev-os-skill/package.json +0 -11
- package/skills/bdbsaastraining/SKILL.md +0 -316
- package/skills/bdbsaastraining/references/exam-pool.md +0 -313
- package/skills/bdbsaastraining/references/interaction-modes.md +0 -94
- package/skills/bdbsaastraining/references/track-a-ai-agent.md +0 -111
- package/skills/bdbsaastraining/references/track-b-wordpress.md +0 -111
- package/skills/bdbsaastraining/references/track-c-mailserver.md +0 -107
- package/skills/bdbsaastraining/references/track-d-debian.md +0 -109
- package/skills/bdbsaastraining/references/track-e-custom.md +0 -83
- package/skills/bdbsaastraining/scripts/build_profile.py +0 -529
- package/skills/bdbsaastraining/scripts/generate_certificate.py +0 -161
- package/skills/bdbsaastraining/scripts/preflight_check.sh +0 -150
- package/skills/bdbsaastraining/templates/certificate_template.html +0 -508
- package/skills/global_config/bdb-ecosystem-health/SKILL.md +0 -68
- package/skills/global_config/bdbsaas-ops/SKILL.md +0 -16
- package/skills/global_config/bdbsaashost/SKILL.md +0 -125
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
DaVinci Resolve MCP Server - Layout Presets Utilities
|
|
4
|
-
|
|
5
|
-
This module provides functions for working with DaVinci Resolve UI layout presets:
|
|
6
|
-
- Saving layout presets
|
|
7
|
-
- Loading layout presets
|
|
8
|
-
- Exporting/importing preset files
|
|
9
|
-
- Managing layout configurations
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import os
|
|
13
|
-
import json
|
|
14
|
-
import logging
|
|
15
|
-
from typing import Dict, List, Any, Optional, Union
|
|
16
|
-
|
|
17
|
-
# Configure logging
|
|
18
|
-
logger = logging.getLogger("davinci-resolve-mcp.layout_presets")
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _validate_path_within_directory(path: str, allowed_dir: str) -> bool:
|
|
22
|
-
"""Validate that a resolved path is within the allowed directory.
|
|
23
|
-
|
|
24
|
-
Prevents path traversal attacks (e.g. preset_name='../../etc/passwd').
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
path: The path to validate (will be resolved to absolute).
|
|
28
|
-
allowed_dir: The directory the path must reside within.
|
|
29
|
-
|
|
30
|
-
Returns:
|
|
31
|
-
True if the path is safely within allowed_dir.
|
|
32
|
-
"""
|
|
33
|
-
resolved = os.path.realpath(path)
|
|
34
|
-
allowed = os.path.realpath(allowed_dir)
|
|
35
|
-
# Ensure the resolved path starts with the allowed directory
|
|
36
|
-
# (trailing sep prevents '/presets2' matching '/presets')
|
|
37
|
-
return resolved.startswith(allowed + os.sep) or resolved == allowed
|
|
38
|
-
|
|
39
|
-
# Default preset locations by platform
|
|
40
|
-
DEFAULT_PRESET_PATHS = {
|
|
41
|
-
"darwin": "~/Library/Application Support/Blackmagic Design/DaVinci Resolve/Presets/",
|
|
42
|
-
"win32": "C:\\ProgramData\\Blackmagic Design\\DaVinci Resolve\\Presets\\",
|
|
43
|
-
"linux": "~/.local/share/DaVinciResolve/Presets/"
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
def get_layout_preset_path(platform: str = None) -> str:
|
|
47
|
-
"""
|
|
48
|
-
Get the path to layout presets for the current platform.
|
|
49
|
-
|
|
50
|
-
Args:
|
|
51
|
-
platform: Override the detected platform (darwin, win32, linux)
|
|
52
|
-
|
|
53
|
-
Returns:
|
|
54
|
-
Path to the layout presets directory
|
|
55
|
-
"""
|
|
56
|
-
import platform as platform_module
|
|
57
|
-
import os
|
|
58
|
-
|
|
59
|
-
# Determine platform if not specified
|
|
60
|
-
if platform is None:
|
|
61
|
-
platform = platform_module.system().lower()
|
|
62
|
-
if platform == "darwin":
|
|
63
|
-
platform = "darwin"
|
|
64
|
-
elif platform == "windows":
|
|
65
|
-
platform = "win32"
|
|
66
|
-
elif platform == "linux":
|
|
67
|
-
platform = "linux"
|
|
68
|
-
else:
|
|
69
|
-
platform = "darwin" # Default to macOS if unknown
|
|
70
|
-
|
|
71
|
-
# Get default path for platform
|
|
72
|
-
preset_path = DEFAULT_PRESET_PATHS.get(platform, DEFAULT_PRESET_PATHS["darwin"])
|
|
73
|
-
|
|
74
|
-
# Expand user directory if needed
|
|
75
|
-
preset_path = os.path.expanduser(preset_path)
|
|
76
|
-
|
|
77
|
-
# Ensure directory exists
|
|
78
|
-
if not os.path.exists(preset_path):
|
|
79
|
-
os.makedirs(preset_path, exist_ok=True)
|
|
80
|
-
|
|
81
|
-
return preset_path
|
|
82
|
-
|
|
83
|
-
def get_ui_layout_path(preset_path: str = None) -> str:
|
|
84
|
-
"""
|
|
85
|
-
Get the path to UI layout presets.
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
preset_path: Base preset directory path (determined automatically if None)
|
|
89
|
-
|
|
90
|
-
Returns:
|
|
91
|
-
Path to the UI layout presets directory
|
|
92
|
-
"""
|
|
93
|
-
if preset_path is None:
|
|
94
|
-
preset_path = get_layout_preset_path()
|
|
95
|
-
|
|
96
|
-
# UI layouts are in a specific subdirectory
|
|
97
|
-
ui_layout_path = os.path.join(preset_path, "UILayouts")
|
|
98
|
-
|
|
99
|
-
# Ensure directory exists
|
|
100
|
-
if not os.path.exists(ui_layout_path):
|
|
101
|
-
os.makedirs(ui_layout_path, exist_ok=True)
|
|
102
|
-
|
|
103
|
-
return ui_layout_path
|
|
104
|
-
|
|
105
|
-
def list_layout_presets(layout_type: str = "ui") -> List[Dict[str, Any]]:
|
|
106
|
-
"""
|
|
107
|
-
List available layout presets.
|
|
108
|
-
|
|
109
|
-
Args:
|
|
110
|
-
layout_type: Type of layout presets to list ('ui', 'window', 'workspace')
|
|
111
|
-
|
|
112
|
-
Returns:
|
|
113
|
-
List of preset information dictionaries
|
|
114
|
-
"""
|
|
115
|
-
# Get appropriate preset directory
|
|
116
|
-
if layout_type.lower() == "ui":
|
|
117
|
-
preset_dir = get_ui_layout_path()
|
|
118
|
-
else:
|
|
119
|
-
# Other layout types would be handled here
|
|
120
|
-
preset_dir = get_ui_layout_path()
|
|
121
|
-
|
|
122
|
-
# List files in the directory
|
|
123
|
-
if not os.path.exists(preset_dir):
|
|
124
|
-
return []
|
|
125
|
-
|
|
126
|
-
presets = []
|
|
127
|
-
for filename in os.listdir(preset_dir):
|
|
128
|
-
# Only include layout preset files
|
|
129
|
-
if filename.endswith(".layout"):
|
|
130
|
-
preset_path = os.path.join(preset_dir, filename)
|
|
131
|
-
presets.append({
|
|
132
|
-
"name": os.path.splitext(filename)[0],
|
|
133
|
-
"path": preset_path,
|
|
134
|
-
"type": layout_type,
|
|
135
|
-
"size": os.path.getsize(preset_path)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
return presets
|
|
139
|
-
|
|
140
|
-
def save_layout_preset(resolve_obj, preset_name: str, layout_type: str = "ui") -> bool:
|
|
141
|
-
"""
|
|
142
|
-
Save the current layout as a preset.
|
|
143
|
-
|
|
144
|
-
Args:
|
|
145
|
-
resolve_obj: DaVinci Resolve API object
|
|
146
|
-
preset_name: Name for the saved preset
|
|
147
|
-
layout_type: Type of layout to save ('ui', 'window', 'workspace')
|
|
148
|
-
|
|
149
|
-
Returns:
|
|
150
|
-
True if successful, False otherwise
|
|
151
|
-
"""
|
|
152
|
-
try:
|
|
153
|
-
# Ensure preset name has no spaces or special characters
|
|
154
|
-
safe_name = preset_name.replace(" ", "_").replace("/", "_").replace("\\", "_")
|
|
155
|
-
|
|
156
|
-
# Different layout types have different save methods
|
|
157
|
-
if layout_type.lower() == "ui":
|
|
158
|
-
# For UI layouts, use the UI Manager
|
|
159
|
-
ui_manager = resolve_obj.GetUIManager()
|
|
160
|
-
if not ui_manager:
|
|
161
|
-
logger.error("Failed to get UI Manager")
|
|
162
|
-
return False
|
|
163
|
-
|
|
164
|
-
# Save the current UI layout
|
|
165
|
-
return ui_manager.SaveUILayout(safe_name)
|
|
166
|
-
else:
|
|
167
|
-
# Other layout types would be handled here
|
|
168
|
-
logger.error(f"Unsupported layout type: {layout_type}")
|
|
169
|
-
return False
|
|
170
|
-
except Exception as e:
|
|
171
|
-
logger.error(f"Error saving layout preset: {str(e)}")
|
|
172
|
-
return False
|
|
173
|
-
|
|
174
|
-
def load_layout_preset(resolve_obj, preset_name: str, layout_type: str = "ui") -> bool:
|
|
175
|
-
"""
|
|
176
|
-
Load a layout preset.
|
|
177
|
-
|
|
178
|
-
Args:
|
|
179
|
-
resolve_obj: DaVinci Resolve API object
|
|
180
|
-
preset_name: Name of the preset to load
|
|
181
|
-
layout_type: Type of layout to load ('ui', 'window', 'workspace')
|
|
182
|
-
|
|
183
|
-
Returns:
|
|
184
|
-
True if successful, False otherwise
|
|
185
|
-
"""
|
|
186
|
-
try:
|
|
187
|
-
# Different layout types have different load methods
|
|
188
|
-
if layout_type.lower() == "ui":
|
|
189
|
-
# For UI layouts, use the UI Manager
|
|
190
|
-
ui_manager = resolve_obj.GetUIManager()
|
|
191
|
-
if not ui_manager:
|
|
192
|
-
logger.error("Failed to get UI Manager")
|
|
193
|
-
return False
|
|
194
|
-
|
|
195
|
-
# Load the specified UI layout
|
|
196
|
-
return ui_manager.LoadUILayout(preset_name)
|
|
197
|
-
else:
|
|
198
|
-
# Other layout types would be handled here
|
|
199
|
-
logger.error(f"Unsupported layout type: {layout_type}")
|
|
200
|
-
return False
|
|
201
|
-
except Exception as e:
|
|
202
|
-
logger.error(f"Error loading layout preset: {str(e)}")
|
|
203
|
-
return False
|
|
204
|
-
|
|
205
|
-
def export_layout_preset(preset_name: str, export_path: str, layout_type: str = "ui") -> bool:
|
|
206
|
-
"""
|
|
207
|
-
Export a layout preset to a file.
|
|
208
|
-
|
|
209
|
-
Args:
|
|
210
|
-
preset_name: Name of the preset to export
|
|
211
|
-
export_path: Path to export the preset file to
|
|
212
|
-
layout_type: Type of layout to export ('ui', 'window', 'workspace')
|
|
213
|
-
|
|
214
|
-
Returns:
|
|
215
|
-
True if successful, False otherwise
|
|
216
|
-
"""
|
|
217
|
-
try:
|
|
218
|
-
# Get the source preset path
|
|
219
|
-
if layout_type.lower() == "ui":
|
|
220
|
-
preset_dir = get_ui_layout_path()
|
|
221
|
-
else:
|
|
222
|
-
# Other layout types would be handled here
|
|
223
|
-
preset_dir = get_ui_layout_path()
|
|
224
|
-
|
|
225
|
-
# Construct source path and validate it stays within preset_dir
|
|
226
|
-
source_path = os.path.join(preset_dir, f"{preset_name}.layout")
|
|
227
|
-
if not _validate_path_within_directory(source_path, preset_dir):
|
|
228
|
-
logger.error(f"Path traversal blocked in preset name: {preset_name}")
|
|
229
|
-
return False
|
|
230
|
-
|
|
231
|
-
# Ensure source file exists
|
|
232
|
-
if not os.path.exists(source_path):
|
|
233
|
-
logger.error(f"Preset file not found: {source_path}")
|
|
234
|
-
return False
|
|
235
|
-
|
|
236
|
-
# Ensure destination directory exists
|
|
237
|
-
export_dir = os.path.dirname(export_path)
|
|
238
|
-
if export_dir and not os.path.exists(export_dir):
|
|
239
|
-
os.makedirs(export_dir, exist_ok=True)
|
|
240
|
-
|
|
241
|
-
# Copy the preset file
|
|
242
|
-
import shutil
|
|
243
|
-
shutil.copy2(source_path, export_path)
|
|
244
|
-
|
|
245
|
-
return True
|
|
246
|
-
except Exception as e:
|
|
247
|
-
logger.error(f"Error exporting layout preset: {str(e)}")
|
|
248
|
-
return False
|
|
249
|
-
|
|
250
|
-
def import_layout_preset(import_path: str, preset_name: str = None, layout_type: str = "ui") -> bool:
|
|
251
|
-
"""
|
|
252
|
-
Import a layout preset from a file.
|
|
253
|
-
|
|
254
|
-
Args:
|
|
255
|
-
import_path: Path to the preset file to import
|
|
256
|
-
preset_name: Name to save the imported preset as (uses filename if None)
|
|
257
|
-
layout_type: Type of layout to import ('ui', 'window', 'workspace')
|
|
258
|
-
|
|
259
|
-
Returns:
|
|
260
|
-
True if successful, False otherwise
|
|
261
|
-
"""
|
|
262
|
-
try:
|
|
263
|
-
# Ensure source file exists
|
|
264
|
-
if not os.path.exists(import_path):
|
|
265
|
-
logger.error(f"Import file not found: {import_path}")
|
|
266
|
-
return False
|
|
267
|
-
|
|
268
|
-
# Get the destination preset path
|
|
269
|
-
if layout_type.lower() == "ui":
|
|
270
|
-
preset_dir = get_ui_layout_path()
|
|
271
|
-
else:
|
|
272
|
-
# Other layout types would be handled here
|
|
273
|
-
preset_dir = get_ui_layout_path()
|
|
274
|
-
|
|
275
|
-
# Use filename as preset name if not specified
|
|
276
|
-
if preset_name is None:
|
|
277
|
-
preset_name = os.path.splitext(os.path.basename(import_path))[0]
|
|
278
|
-
|
|
279
|
-
# Ensure preset name has no spaces or special characters
|
|
280
|
-
safe_name = preset_name.replace(" ", "_").replace("/", "_").replace("\\", "_")
|
|
281
|
-
|
|
282
|
-
# Construct destination path and validate it stays within preset_dir
|
|
283
|
-
dest_path = os.path.join(preset_dir, f"{safe_name}.layout")
|
|
284
|
-
if not _validate_path_within_directory(dest_path, preset_dir):
|
|
285
|
-
logger.error(f"Path traversal blocked in preset name: {preset_name}")
|
|
286
|
-
return False
|
|
287
|
-
|
|
288
|
-
# Copy the preset file
|
|
289
|
-
import shutil
|
|
290
|
-
shutil.copy2(import_path, dest_path)
|
|
291
|
-
|
|
292
|
-
return True
|
|
293
|
-
except Exception as e:
|
|
294
|
-
logger.error(f"Error importing layout preset: {str(e)}")
|
|
295
|
-
return False
|
|
296
|
-
|
|
297
|
-
def delete_layout_preset(preset_name: str, layout_type: str = "ui") -> bool:
|
|
298
|
-
"""
|
|
299
|
-
Delete a layout preset.
|
|
300
|
-
|
|
301
|
-
Args:
|
|
302
|
-
preset_name: Name of the preset to delete
|
|
303
|
-
layout_type: Type of layout to delete ('ui', 'window', 'workspace')
|
|
304
|
-
|
|
305
|
-
Returns:
|
|
306
|
-
True if successful, False otherwise
|
|
307
|
-
"""
|
|
308
|
-
try:
|
|
309
|
-
# Get the preset path
|
|
310
|
-
if layout_type.lower() == "ui":
|
|
311
|
-
preset_dir = get_ui_layout_path()
|
|
312
|
-
else:
|
|
313
|
-
# Other layout types would be handled here
|
|
314
|
-
preset_dir = get_ui_layout_path()
|
|
315
|
-
|
|
316
|
-
# Construct the preset file path and validate it stays within preset_dir
|
|
317
|
-
preset_path = os.path.join(preset_dir, f"{preset_name}.layout")
|
|
318
|
-
if not _validate_path_within_directory(preset_path, preset_dir):
|
|
319
|
-
logger.error(f"Path traversal blocked in preset name: {preset_name}")
|
|
320
|
-
return False
|
|
321
|
-
|
|
322
|
-
# Ensure file exists
|
|
323
|
-
if not os.path.exists(preset_path):
|
|
324
|
-
logger.error(f"Preset file not found: {preset_path}")
|
|
325
|
-
return False
|
|
326
|
-
|
|
327
|
-
# Delete the file
|
|
328
|
-
os.remove(preset_path)
|
|
329
|
-
|
|
330
|
-
return True
|
|
331
|
-
except Exception as e:
|
|
332
|
-
logger.error(f"Error deleting layout preset: {str(e)}")
|
|
333
|
-
return False
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"""FastMCP stdio helpers with strict LF line endings across platforms."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import sys
|
|
6
|
-
from io import TextIOWrapper
|
|
7
|
-
|
|
8
|
-
import anyio
|
|
9
|
-
from mcp.server.stdio import stdio_server
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def create_text_stdio():
|
|
13
|
-
"""Wrap stdio in UTF-8 text mode without platform newline translation."""
|
|
14
|
-
stdin = anyio.wrap_file(TextIOWrapper(sys.stdin.buffer, encoding="utf-8", newline=""))
|
|
15
|
-
stdout = anyio.wrap_file(TextIOWrapper(sys.stdout.buffer, encoding="utf-8", newline=""))
|
|
16
|
-
return stdin, stdout
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
async def run_fastmcp_stdio_async(fastmcp):
|
|
20
|
-
"""Run a FastMCP server over stdio using strict LF-delimited JSON."""
|
|
21
|
-
stdin, stdout = create_text_stdio()
|
|
22
|
-
async with stdio_server(stdin=stdin, stdout=stdout) as (read_stream, write_stream):
|
|
23
|
-
await fastmcp._mcp_server.run( # noqa: SLF001 - no public injection point exists yet
|
|
24
|
-
read_stream,
|
|
25
|
-
write_stream,
|
|
26
|
-
fastmcp._mcp_server.create_initialization_options(),
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def run_fastmcp_stdio(fastmcp):
|
|
31
|
-
"""Synchronous entrypoint for strict-LF FastMCP stdio."""
|
|
32
|
-
anyio.run(lambda: run_fastmcp_stdio_async(fastmcp))
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
"""Networked transport for the MCP server (opt-in via --transport).
|
|
2
|
-
|
|
3
|
-
stdio remains the default. The `sse` and `streamable-http` modes bind to
|
|
4
|
-
loopback (127.0.0.1) by default and REQUIRE a bearer token on every request, so
|
|
5
|
-
turning networking on never silently exposes Resolve. The token comes from
|
|
6
|
-
``$DAVINCI_MCP_TOKEN`` or is generated and logged at startup. A small state file
|
|
7
|
-
lets the control panel show the live connection URL + token.
|
|
8
|
-
|
|
9
|
-
Security posture:
|
|
10
|
-
- Default host is loopback; a non-loopback bind logs a loud warning.
|
|
11
|
-
- Every HTTP request must carry ``Authorization: Bearer <token>`` (constant-time
|
|
12
|
-
compared); otherwise 401.
|
|
13
|
-
- stdio (the default transport) is unaffected by anything here.
|
|
14
|
-
"""
|
|
15
|
-
import json
|
|
16
|
-
import logging
|
|
17
|
-
import os
|
|
18
|
-
import secrets
|
|
19
|
-
import tempfile
|
|
20
|
-
import time
|
|
21
|
-
|
|
22
|
-
logger = logging.getLogger("davinci-resolve-mcp")
|
|
23
|
-
|
|
24
|
-
TRANSPORT_STATE_PATH = os.path.join(
|
|
25
|
-
tempfile.gettempdir(), "davinci_resolve_mcp_transport.json"
|
|
26
|
-
)
|
|
27
|
-
LOOPBACK_HOSTS = {"127.0.0.1", "localhost", "::1"}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def resolve_token():
|
|
31
|
-
"""Return (token, was_generated). Honors $DAVINCI_MCP_TOKEN."""
|
|
32
|
-
tok = os.environ.get("DAVINCI_MCP_TOKEN")
|
|
33
|
-
if tok:
|
|
34
|
-
return tok, False
|
|
35
|
-
return secrets.token_urlsafe(24), True
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _auth_middleware_cls(token):
|
|
39
|
-
from starlette.middleware.base import BaseHTTPMiddleware
|
|
40
|
-
from starlette.responses import JSONResponse
|
|
41
|
-
|
|
42
|
-
expected = f"Bearer {token}"
|
|
43
|
-
|
|
44
|
-
class BearerAuth(BaseHTTPMiddleware):
|
|
45
|
-
async def dispatch(self, request, call_next):
|
|
46
|
-
provided = request.headers.get("authorization", "")
|
|
47
|
-
if not secrets.compare_digest(provided, expected):
|
|
48
|
-
return JSONResponse(
|
|
49
|
-
{"error": "unauthorized: Authorization: Bearer <token> required"},
|
|
50
|
-
status_code=401,
|
|
51
|
-
)
|
|
52
|
-
return await call_next(request)
|
|
53
|
-
|
|
54
|
-
return BearerAuth
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def write_transport_state(transport, host, port, token):
|
|
58
|
-
try:
|
|
59
|
-
with open(TRANSPORT_STATE_PATH, "w", encoding="utf-8") as fh:
|
|
60
|
-
json.dump({
|
|
61
|
-
"transport": transport,
|
|
62
|
-
"host": host,
|
|
63
|
-
"port": port,
|
|
64
|
-
"url": f"http://{host}:{port}",
|
|
65
|
-
"token": token,
|
|
66
|
-
"loopback": host in LOOPBACK_HOSTS,
|
|
67
|
-
"pid": os.getpid(),
|
|
68
|
-
"started_at": time.time(),
|
|
69
|
-
}, fh)
|
|
70
|
-
except OSError as exc:
|
|
71
|
-
logger.warning("could not write transport state: %s", exc)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def clear_transport_state():
|
|
75
|
-
try:
|
|
76
|
-
os.remove(TRANSPORT_STATE_PATH)
|
|
77
|
-
except OSError:
|
|
78
|
-
pass
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def read_transport_state():
|
|
82
|
-
"""Return the live transport state dict, or None if no networked instance.
|
|
83
|
-
|
|
84
|
-
Treats a state file whose pid is no longer alive as stale (returns None).
|
|
85
|
-
"""
|
|
86
|
-
try:
|
|
87
|
-
with open(TRANSPORT_STATE_PATH, encoding="utf-8") as fh:
|
|
88
|
-
state = json.load(fh)
|
|
89
|
-
except (OSError, ValueError):
|
|
90
|
-
return None
|
|
91
|
-
pid = state.get("pid")
|
|
92
|
-
if isinstance(pid, int):
|
|
93
|
-
try:
|
|
94
|
-
os.kill(pid, 0)
|
|
95
|
-
except (OSError, ProcessLookupError):
|
|
96
|
-
return None
|
|
97
|
-
return state
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def run_networked(mcp, transport):
|
|
101
|
-
"""Serve `mcp` over an authenticated HTTP transport ('sse'|'streamable-http')."""
|
|
102
|
-
import uvicorn
|
|
103
|
-
|
|
104
|
-
host = os.environ.get("DAVINCI_MCP_HOST") or mcp.settings.host or "127.0.0.1"
|
|
105
|
-
port = int(os.environ.get("DAVINCI_MCP_PORT") or mcp.settings.port or 8000)
|
|
106
|
-
mcp.settings.host = host
|
|
107
|
-
mcp.settings.port = port
|
|
108
|
-
token, generated = resolve_token()
|
|
109
|
-
|
|
110
|
-
app = mcp.sse_app() if transport == "sse" else mcp.streamable_http_app()
|
|
111
|
-
app.add_middleware(_auth_middleware_cls(token))
|
|
112
|
-
|
|
113
|
-
if host not in LOOPBACK_HOSTS:
|
|
114
|
-
logger.warning(
|
|
115
|
-
"SECURITY: MCP %s transport bound to NON-loopback host %r — Resolve "
|
|
116
|
-
"control is exposed on the network. Ensure this is intended.",
|
|
117
|
-
transport, host,
|
|
118
|
-
)
|
|
119
|
-
logger.info("MCP %s transport: http://%s:%s (bearer token required)",
|
|
120
|
-
transport, host, port)
|
|
121
|
-
if generated:
|
|
122
|
-
logger.info("Generated bearer token (set $DAVINCI_MCP_TOKEN to pin it): %s", token)
|
|
123
|
-
|
|
124
|
-
write_transport_state(transport, host, port, token)
|
|
125
|
-
try:
|
|
126
|
-
uvicorn.run(app, host=host, port=port, log_level="warning")
|
|
127
|
-
finally:
|
|
128
|
-
clear_transport_state()
|