vibedasher-mcp 0.1.0__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.
- vibedasher_mcp-0.1.0/.gitignore +143 -0
- vibedasher_mcp-0.1.0/PKG-INFO +99 -0
- vibedasher_mcp-0.1.0/README.md +81 -0
- vibedasher_mcp-0.1.0/pyproject.toml +35 -0
- vibedasher_mcp-0.1.0/run-local.sh +40 -0
- vibedasher_mcp-0.1.0/tests/__init__.py +0 -0
- vibedasher_mcp-0.1.0/tests/conftest.py +16 -0
- vibedasher_mcp-0.1.0/tests/test_mcp.py +1194 -0
- vibedasher_mcp-0.1.0/vibedasher_mcp/__init__.py +21 -0
- vibedasher_mcp-0.1.0/vibedasher_mcp/__main__.py +4 -0
- vibedasher_mcp-0.1.0/vibedasher_mcp/client.py +248 -0
- vibedasher_mcp-0.1.0/vibedasher_mcp/config.py +44 -0
- vibedasher_mcp-0.1.0/vibedasher_mcp/eject.py +1650 -0
- vibedasher_mcp-0.1.0/vibedasher_mcp/server.py +175 -0
- vibedasher_mcp-0.1.0/vibedasher_mcp/tools.py +199 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Node (Nuxt.js)
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Side-lambda build artifacts — deploy_side_lambdas() builds in a temp dir
|
|
5
|
+
# (mktemp), but legacy in-place runs left these behind; never commit them.
|
|
6
|
+
lambdas/*/package-lock.json
|
|
7
|
+
lambdas/*/deployment.zip
|
|
8
|
+
|
|
9
|
+
# Claude Code local backups (contains secrets — never commit)
|
|
10
|
+
.claude/backups/
|
|
11
|
+
test-results/
|
|
12
|
+
frontend/playwright-report
|
|
13
|
+
scheduled_tasks.lock
|
|
14
|
+
playwright-report
|
|
15
|
+
.playwright-mcp/
|
|
16
|
+
.npm/
|
|
17
|
+
yarn.lock
|
|
18
|
+
pnpm-lock.yaml
|
|
19
|
+
dist/
|
|
20
|
+
.nuxt/
|
|
21
|
+
output/
|
|
22
|
+
.env
|
|
23
|
+
.env.*
|
|
24
|
+
.DS_Store
|
|
25
|
+
aider
|
|
26
|
+
api/build/
|
|
27
|
+
.lambda-builds/
|
|
28
|
+
api/debug_logs_json/
|
|
29
|
+
api/seeds/shadcn-source/
|
|
30
|
+
bi_test_datasets/
|
|
31
|
+
build/cron/
|
|
32
|
+
api/debug_logs/
|
|
33
|
+
|
|
34
|
+
# Python (FastAPI)
|
|
35
|
+
__pycache__/
|
|
36
|
+
*.py[cod]
|
|
37
|
+
*.pyo
|
|
38
|
+
*.pyd
|
|
39
|
+
*.pyc
|
|
40
|
+
*.pyo
|
|
41
|
+
*.pyd
|
|
42
|
+
.Python
|
|
43
|
+
env/
|
|
44
|
+
venv/
|
|
45
|
+
ENV/
|
|
46
|
+
.venv/
|
|
47
|
+
*.egg-info/
|
|
48
|
+
.eggs/
|
|
49
|
+
*.egg
|
|
50
|
+
pip-log.txt
|
|
51
|
+
pip-delete-this-directory.txt
|
|
52
|
+
|
|
53
|
+
# Tauri
|
|
54
|
+
/src-tauri/target/
|
|
55
|
+
/src-tauri/.cargo/
|
|
56
|
+
/src-tauri/Cargo.lock
|
|
57
|
+
/src-tauri/Cargo.toml.orig
|
|
58
|
+
/src-tauri/.tauri-build
|
|
59
|
+
/src-tauri/.tauri
|
|
60
|
+
|
|
61
|
+
# VSCode
|
|
62
|
+
.vscode/
|
|
63
|
+
|
|
64
|
+
# Terraform
|
|
65
|
+
.terraform/
|
|
66
|
+
*.tfstate
|
|
67
|
+
*.tfstate.*
|
|
68
|
+
crash.log
|
|
69
|
+
# Allow environment-specific tfvars in infra/
|
|
70
|
+
!infra/*.tfvars
|
|
71
|
+
!infra/**/*.tfvars
|
|
72
|
+
override.tf
|
|
73
|
+
override.tf.json
|
|
74
|
+
*_override.tf
|
|
75
|
+
*_override.tf.json
|
|
76
|
+
.terraformrc
|
|
77
|
+
terraform.rc
|
|
78
|
+
|
|
79
|
+
# OS
|
|
80
|
+
Thumbs.db
|
|
81
|
+
.DS_Store
|
|
82
|
+
|
|
83
|
+
# Logs
|
|
84
|
+
*.log
|
|
85
|
+
|
|
86
|
+
# Misc
|
|
87
|
+
.idea/
|
|
88
|
+
*.swp
|
|
89
|
+
*.swo
|
|
90
|
+
|
|
91
|
+
# Local DBs
|
|
92
|
+
*.db
|
|
93
|
+
|
|
94
|
+
# Test/coverage
|
|
95
|
+
coverage/
|
|
96
|
+
*.cover
|
|
97
|
+
*.pyc
|
|
98
|
+
*.pyo
|
|
99
|
+
*.pyd
|
|
100
|
+
.cache/
|
|
101
|
+
|
|
102
|
+
# Lambda/Serverless
|
|
103
|
+
.serverless/
|
|
104
|
+
|
|
105
|
+
# Docker
|
|
106
|
+
*.pid
|
|
107
|
+
*.pid.lock
|
|
108
|
+
|
|
109
|
+
# Others
|
|
110
|
+
*.bak
|
|
111
|
+
*.tmp
|
|
112
|
+
|
|
113
|
+
# Ignore local secrets
|
|
114
|
+
secrets.*
|
|
115
|
+
api/*.local.env
|
|
116
|
+
|
|
117
|
+
# SSL certificates (never commit private keys!)
|
|
118
|
+
nginx/ssl/*.pem
|
|
119
|
+
nginx/ssl/*.key
|
|
120
|
+
nginx/ssl/*.crt
|
|
121
|
+
|
|
122
|
+
# Production build outputs
|
|
123
|
+
dist/
|
|
124
|
+
|
|
125
|
+
# On-premise configuration (contains secrets)
|
|
126
|
+
.env
|
|
127
|
+
config/*.env
|
|
128
|
+
!config/*.env.example
|
|
129
|
+
|
|
130
|
+
.agents
|
|
131
|
+
skills
|
|
132
|
+
_bmad
|
|
133
|
+
.envrc
|
|
134
|
+
.vercel
|
|
135
|
+
HARDENING/screenshots/s3b-session.har
|
|
136
|
+
HARDENING/screenshots/*.har
|
|
137
|
+
|
|
138
|
+
# i18n_sync.py dispatch manifest — regenerated on demand, not source
|
|
139
|
+
i18n-delta.json
|
|
140
|
+
|
|
141
|
+
# `skills` above swallows api/seeds/skills/** — those are lambda-bundled seed assets and MUST be tracked
|
|
142
|
+
!api/seeds/skills/
|
|
143
|
+
!api/seeds/skills/**
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vibedasher-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server exposing the Vibedasher data engine (datasets, query, viz) to a customer's AI.
|
|
5
|
+
Project-URL: Homepage, https://vibedasher.com
|
|
6
|
+
Project-URL: Source, https://github.com/JulienGdnr/vibedasher
|
|
7
|
+
Author: Vibedasher
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: analytics,bi,eject,mcp,model-context-protocol,vibedasher
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
12
|
+
Requires-Dist: httpx<0.29.0,>=0.23.0
|
|
13
|
+
Requires-Dist: msgpack>=1.0.0
|
|
14
|
+
Requires-Dist: vibedasher>=2.0.0
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# vibedasher-mcp
|
|
20
|
+
|
|
21
|
+
An [MCP](https://modelcontextprotocol.io) server that exposes the **Vibedasher data
|
|
22
|
+
engine** — datasets, CSV upload + ETL, headless SQL query, and dashboard (viz)
|
|
23
|
+
management — as tools a customer's AI (Claude Code, Cursor, ...) can drive directly.
|
|
24
|
+
|
|
25
|
+
This is the **control plane** (VD-601, PIVOT/PLAN.md EP-6). It wraps the published
|
|
26
|
+
[`vibedasher` Python SDK](https://pypi.org/project/vibedasher/) and calls only the public, metered `/api/v1/*`
|
|
27
|
+
API. The *eject* tools (pull a viz's code + SDK-wiring manifest so your AI recreates
|
|
28
|
+
the dashboard natively in your stack) ship separately as VD-602.
|
|
29
|
+
|
|
30
|
+
## Tools
|
|
31
|
+
|
|
32
|
+
| Tool | What it does |
|
|
33
|
+
|------|--------------|
|
|
34
|
+
| `list_datasets` | List datasets the key can read (id, name, `cleanSQLName`, status). |
|
|
35
|
+
| `get_dataset(dataset_id)` | One dataset's metadata + column schema. |
|
|
36
|
+
| `upload_dataset(name, csv_content, ...)` | Create a CSV dataset, upload, load, poll to READY. |
|
|
37
|
+
| `run_query(dataset_ids, sql, params)` | Inline alias-only SQL across your datasets (plural `datasetIds`, joins allowed) → typed columns + rows. |
|
|
38
|
+
| `list_vizzes(include_unpublished=False)` | List dashboards. |
|
|
39
|
+
| `get_viz(viz_id)` | One viz's metadata. |
|
|
40
|
+
| `create_viz(name, dataset_ids, seed_id/dashboard_config, ...)` | Create a viz (AI dashboard-build entry). |
|
|
41
|
+
| `build_viz(viz_id, branch)` | Compile a viz branch into a renderable bundle. |
|
|
42
|
+
|
|
43
|
+
`run_query` reuses the SDK's hand-written `query()` transport (VD-301): the caller
|
|
44
|
+
never sees inline-vs-presigned delivery, MessagePack, or retries — one call in,
|
|
45
|
+
typed rows out. Each dataset id resolves server-side to that dataset's
|
|
46
|
+
`cleanSQLName` alias under the VD-203 RLS/alias-rewrite; SQL references only aliases.
|
|
47
|
+
|
|
48
|
+
## Auth
|
|
49
|
+
|
|
50
|
+
API key only, via `X-Api-Key` (handled by the SDK's `create_client`). Set:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
export VIBEDASHER_API_KEY=... # mint via `POST /v1/api-keys` or the console
|
|
54
|
+
export VIBEDASHER_REGION=eu-central-1 # or us-east-1
|
|
55
|
+
# export VIBEDASHER_BASE_URL=... # optional override (on-prem/staging)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The key is read once at first tool call and is never logged or echoed in any
|
|
59
|
+
tool result.
|
|
60
|
+
|
|
61
|
+
## Metering
|
|
62
|
+
|
|
63
|
+
Every tool hits the public, metered endpoints (`create_dataset` is credit-gated;
|
|
64
|
+
`run_query` is metered via the usage/credits event). The MCP adds no side channel
|
|
65
|
+
and bypasses no metering.
|
|
66
|
+
|
|
67
|
+
## Run
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install vibedasher-mcp # (monorepo dev: also make `vibedasher` importable)
|
|
71
|
+
vibedasher-mcp # stdio MCP server
|
|
72
|
+
# or: python -m vibedasher_mcp
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
MCP client config (Claude Code / Cursor):
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"mcpServers": {
|
|
80
|
+
"vibedasher": {
|
|
81
|
+
"command": "vibedasher-mcp",
|
|
82
|
+
"env": { "VIBEDASHER_API_KEY": "...", "VIBEDASHER_REGION": "eu-central-1" }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Development
|
|
89
|
+
|
|
90
|
+
The package depends on the sibling SDK at `../sdk/py`. Tests wire that path
|
|
91
|
+
automatically (`tests/conftest.py`), so from `packages/mcp`:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
python -m pytest tests/ -q
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
> Note: `fastmcp` is a **client-side** dependency of this standalone package; it is
|
|
98
|
+
> not bundled into the API Lambdas, so the `export_requirements.py` step in the root
|
|
99
|
+
> `CLAUDE.md` does not apply here.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# vibedasher-mcp
|
|
2
|
+
|
|
3
|
+
An [MCP](https://modelcontextprotocol.io) server that exposes the **Vibedasher data
|
|
4
|
+
engine** — datasets, CSV upload + ETL, headless SQL query, and dashboard (viz)
|
|
5
|
+
management — as tools a customer's AI (Claude Code, Cursor, ...) can drive directly.
|
|
6
|
+
|
|
7
|
+
This is the **control plane** (VD-601, PIVOT/PLAN.md EP-6). It wraps the published
|
|
8
|
+
[`vibedasher` Python SDK](https://pypi.org/project/vibedasher/) and calls only the public, metered `/api/v1/*`
|
|
9
|
+
API. The *eject* tools (pull a viz's code + SDK-wiring manifest so your AI recreates
|
|
10
|
+
the dashboard natively in your stack) ship separately as VD-602.
|
|
11
|
+
|
|
12
|
+
## Tools
|
|
13
|
+
|
|
14
|
+
| Tool | What it does |
|
|
15
|
+
|------|--------------|
|
|
16
|
+
| `list_datasets` | List datasets the key can read (id, name, `cleanSQLName`, status). |
|
|
17
|
+
| `get_dataset(dataset_id)` | One dataset's metadata + column schema. |
|
|
18
|
+
| `upload_dataset(name, csv_content, ...)` | Create a CSV dataset, upload, load, poll to READY. |
|
|
19
|
+
| `run_query(dataset_ids, sql, params)` | Inline alias-only SQL across your datasets (plural `datasetIds`, joins allowed) → typed columns + rows. |
|
|
20
|
+
| `list_vizzes(include_unpublished=False)` | List dashboards. |
|
|
21
|
+
| `get_viz(viz_id)` | One viz's metadata. |
|
|
22
|
+
| `create_viz(name, dataset_ids, seed_id/dashboard_config, ...)` | Create a viz (AI dashboard-build entry). |
|
|
23
|
+
| `build_viz(viz_id, branch)` | Compile a viz branch into a renderable bundle. |
|
|
24
|
+
|
|
25
|
+
`run_query` reuses the SDK's hand-written `query()` transport (VD-301): the caller
|
|
26
|
+
never sees inline-vs-presigned delivery, MessagePack, or retries — one call in,
|
|
27
|
+
typed rows out. Each dataset id resolves server-side to that dataset's
|
|
28
|
+
`cleanSQLName` alias under the VD-203 RLS/alias-rewrite; SQL references only aliases.
|
|
29
|
+
|
|
30
|
+
## Auth
|
|
31
|
+
|
|
32
|
+
API key only, via `X-Api-Key` (handled by the SDK's `create_client`). Set:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
export VIBEDASHER_API_KEY=... # mint via `POST /v1/api-keys` or the console
|
|
36
|
+
export VIBEDASHER_REGION=eu-central-1 # or us-east-1
|
|
37
|
+
# export VIBEDASHER_BASE_URL=... # optional override (on-prem/staging)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The key is read once at first tool call and is never logged or echoed in any
|
|
41
|
+
tool result.
|
|
42
|
+
|
|
43
|
+
## Metering
|
|
44
|
+
|
|
45
|
+
Every tool hits the public, metered endpoints (`create_dataset` is credit-gated;
|
|
46
|
+
`run_query` is metered via the usage/credits event). The MCP adds no side channel
|
|
47
|
+
and bypasses no metering.
|
|
48
|
+
|
|
49
|
+
## Run
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install vibedasher-mcp # (monorepo dev: also make `vibedasher` importable)
|
|
53
|
+
vibedasher-mcp # stdio MCP server
|
|
54
|
+
# or: python -m vibedasher_mcp
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
MCP client config (Claude Code / Cursor):
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"vibedasher": {
|
|
63
|
+
"command": "vibedasher-mcp",
|
|
64
|
+
"env": { "VIBEDASHER_API_KEY": "...", "VIBEDASHER_REGION": "eu-central-1" }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Development
|
|
71
|
+
|
|
72
|
+
The package depends on the sibling SDK at `../sdk/py`. Tests wire that path
|
|
73
|
+
automatically (`tests/conftest.py`), so from `packages/mcp`:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python -m pytest tests/ -q
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> Note: `fastmcp` is a **client-side** dependency of this standalone package; it is
|
|
80
|
+
> not bundled into the API Lambdas, so the `export_requirements.py` step in the root
|
|
81
|
+
> `CLAUDE.md` does not apply here.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vibedasher-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "MCP server exposing the Vibedasher data engine (datasets, query, viz) to a customer's AI."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Vibedasher" }]
|
|
13
|
+
keywords = ["vibedasher", "mcp", "model-context-protocol", "bi", "analytics", "eject"]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"fastmcp>=2.0.0",
|
|
16
|
+
"httpx>=0.23.0,<0.29.0",
|
|
17
|
+
"msgpack>=1.0.0",
|
|
18
|
+
# The published Vibedasher SDK — the MCP wraps it for auth + the query()
|
|
19
|
+
# transport. Pinned to the current major; in this monorepo it resolves from
|
|
20
|
+
# ../sdk/py during development (see README).
|
|
21
|
+
"vibedasher>=2.0.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
dev = ["pytest>=7.0"]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
vibedasher-mcp = "vibedasher_mcp.server:main"
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://vibedasher.com"
|
|
32
|
+
Source = "https://github.com/JulienGdnr/vibedasher"
|
|
33
|
+
|
|
34
|
+
[tool.hatch.build.targets.wheel]
|
|
35
|
+
packages = ["vibedasher_mcp"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Run the vibedasher MCP server straight from this monorepo.
|
|
3
|
+
#
|
|
4
|
+
# WHY THIS EXISTS: `vibedasher-mcp` is not published to PyPI yet (see
|
|
5
|
+
# GOLIVE_QA/PHASE208/EJECT-QA-FINDINGS.md F-01), so the README's
|
|
6
|
+
# `pip install vibedasher-mcp` cannot work and there is no `vibedasher-mcp`
|
|
7
|
+
# binary on PATH. This script is the monorepo stand-in: it puts the sibling SDK
|
|
8
|
+
# on PYTHONPATH and launches the stdio server.
|
|
9
|
+
#
|
|
10
|
+
# Once the packages ARE published, delete this and use the README's config:
|
|
11
|
+
# { "command": "vibedasher-mcp", "env": { "VIBEDASHER_API_KEY": "..." } }
|
|
12
|
+
#
|
|
13
|
+
# SECRETS: the API key is NEVER stored in the repo. It lives in
|
|
14
|
+
# ~/.vibedasher-mcp.env (chmod 600), which this script sources. Create it with:
|
|
15
|
+
# VIBEDASHER_API_KEY=<key from POST /v1/api-keys>
|
|
16
|
+
# VIBEDASHER_REGION=eu-central-1
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
21
|
+
ENV_FILE="${VIBEDASHER_MCP_ENV_FILE:-$HOME/.vibedasher-mcp.env}"
|
|
22
|
+
|
|
23
|
+
if [ -f "$ENV_FILE" ]; then
|
|
24
|
+
set -a
|
|
25
|
+
# shellcheck disable=SC1090
|
|
26
|
+
. "$ENV_FILE"
|
|
27
|
+
set +a
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
if [ -z "${VIBEDASHER_API_KEY:-}" ]; then
|
|
31
|
+
echo "vibedasher-mcp: VIBEDASHER_API_KEY is not set." >&2
|
|
32
|
+
echo " Expected it in $ENV_FILE (chmod 600) or the environment." >&2
|
|
33
|
+
echo " Mint one with: POST /v1/api-keys (session JWT auth)." >&2
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
export VIBEDASHER_REGION="${VIBEDASHER_REGION:-eu-central-1}"
|
|
38
|
+
export PYTHONPATH="$REPO_ROOT/packages/sdk/py:$REPO_ROOT/packages/mcp${PYTHONPATH:+:$PYTHONPATH}"
|
|
39
|
+
|
|
40
|
+
exec python3 -m vibedasher_mcp "$@"
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Dev-time path wiring so tests import the in-repo package + sibling SDK.
|
|
2
|
+
|
|
3
|
+
In a real install, ``vibedasher_mcp`` and ``vibedasher`` are pip-installed and
|
|
4
|
+
this file is unnecessary; it only makes the monorepo checkout runnable without an
|
|
5
|
+
editable install.
|
|
6
|
+
"""
|
|
7
|
+
import pathlib
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
_MCP_ROOT = pathlib.Path(__file__).resolve().parents[1] # packages/mcp
|
|
11
|
+
_SDK_PY = _MCP_ROOT.parent / "sdk" / "py" # packages/sdk/py
|
|
12
|
+
|
|
13
|
+
for path in (_MCP_ROOT, _SDK_PY):
|
|
14
|
+
p = str(path)
|
|
15
|
+
if p not in sys.path:
|
|
16
|
+
sys.path.insert(0, p)
|