builder-gps-mcp 0.1.1__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.
- builder_gps_mcp-0.1.1/PKG-INFO +147 -0
- builder_gps_mcp-0.1.1/README.md +123 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp/__init__.py +8 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp/api_client.py +69 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp/server.py +193 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp.egg-info/PKG-INFO +147 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp.egg-info/SOURCES.txt +11 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp.egg-info/dependency_links.txt +1 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp.egg-info/entry_points.txt +2 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp.egg-info/requires.txt +3 -0
- builder_gps_mcp-0.1.1/builder_gps_mcp.egg-info/top_level.txt +1 -0
- builder_gps_mcp-0.1.1/pyproject.toml +41 -0
- builder_gps_mcp-0.1.1/setup.cfg +4 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: builder-gps-mcp
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: MCP server for Builder GPS — chat with your Agentic AI Build Week schedule from any AI editor.
|
|
5
|
+
Author: Builder GPS contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Kyle8Bits/builder-gps
|
|
8
|
+
Project-URL: Repository, https://github.com/Kyle8Bits/builder-gps
|
|
9
|
+
Project-URL: Issues, https://github.com/Kyle8Bits/builder-gps/issues
|
|
10
|
+
Keywords: mcp,ai,agents,aabw,schedule,claude,cursor
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: mcp>=1.2.0
|
|
22
|
+
Requires-Dist: httpx>=0.27.0
|
|
23
|
+
Requires-Dist: pydantic>=2.10.0
|
|
24
|
+
|
|
25
|
+
# Builder GPS MCP Server
|
|
26
|
+
|
|
27
|
+
Chat with your AABW schedule from Claude Desktop, Claude Code, Cursor, or any
|
|
28
|
+
other MCP-aware AI tool. No notifications — request/response only.
|
|
29
|
+
|
|
30
|
+
## What you get
|
|
31
|
+
|
|
32
|
+
4 tools, all keyed off your `builder_id` UUID:
|
|
33
|
+
|
|
34
|
+
| Tool | What it does |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `get_path` | Your full path + prerequisites + readiness % |
|
|
37
|
+
| `get_next_session` | The next session you haven't marked yet |
|
|
38
|
+
| `mark_session` | attended / skipped / blocked → triggers a reroute |
|
|
39
|
+
| `regenerate_path` | Re-runs the planner against your current history |
|
|
40
|
+
|
|
41
|
+
## 30-second setup
|
|
42
|
+
|
|
43
|
+
### 1. Get your builder_id
|
|
44
|
+
|
|
45
|
+
Open the web app → fill the goal form → on the timeline, expand
|
|
46
|
+
**"Connect via MCP? Show builder ID"** → copy the UUID.
|
|
47
|
+
|
|
48
|
+
### 2. Install the server
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cd builder-gps/apps/mcp
|
|
52
|
+
pip install -e .
|
|
53
|
+
# verify the script lands on your PATH:
|
|
54
|
+
builder-gps-mcp --help # (no-op; just confirms install)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The package exposes a `builder-gps-mcp` console script.
|
|
58
|
+
|
|
59
|
+
### 3. Wire it into your AI tool
|
|
60
|
+
|
|
61
|
+
**Claude Desktop** — edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"builder-gps": {
|
|
67
|
+
"command": "builder-gps-mcp",
|
|
68
|
+
"env": {
|
|
69
|
+
"BUILDER_GPS_API_URL": "http://localhost:8000",
|
|
70
|
+
"BUILDER_GPS_BUILDER_ID": "PASTE-YOUR-UUID-HERE"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Restart Claude Desktop. The compass icon → MCP → you should see `builder-gps`
|
|
78
|
+
with 4 tools.
|
|
79
|
+
|
|
80
|
+
**Claude Code** — one-liner:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
claude mcp add builder-gps \
|
|
84
|
+
--env BUILDER_GPS_API_URL=http://localhost:8000 \
|
|
85
|
+
--env BUILDER_GPS_BUILDER_ID=PASTE-YOUR-UUID-HERE \
|
|
86
|
+
-- builder-gps-mcp
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Cursor** — `~/.cursor/mcp.json`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"builder-gps": {
|
|
95
|
+
"command": "builder-gps-mcp",
|
|
96
|
+
"env": {
|
|
97
|
+
"BUILDER_GPS_API_URL": "http://localhost:8000",
|
|
98
|
+
"BUILDER_GPS_BUILDER_ID": "PASTE-YOUR-UUID-HERE"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Demo conversation
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
You: What's next on my AABW schedule?
|
|
109
|
+
Claude: [calls get_next_session]
|
|
110
|
+
Your next session is "Building production-ready agents with Apify"
|
|
111
|
+
on Day 3 (Jul 10) at 14:00 in Hall B. It's on your path because you
|
|
112
|
+
flagged scraping as a stack item.
|
|
113
|
+
|
|
114
|
+
You: I'll skip the morning one — mark it skipped.
|
|
115
|
+
Claude: [calls mark_session("d3-morning-deep-dive", "skipped")]
|
|
116
|
+
Marked skipped. Three changes to your path:
|
|
117
|
+
• Added "Agent Eval Frameworks" (you still need eval skills)
|
|
118
|
+
• Removed "LangGraph 101" (dependency on the skipped session)
|
|
119
|
+
• Reordered Day 4 to move "Demo Polish" earlier
|
|
120
|
+
Readiness held at 62%.
|
|
121
|
+
|
|
122
|
+
You: Give me a fresh plan based on what I've actually attended.
|
|
123
|
+
Claude: [calls regenerate_path]
|
|
124
|
+
... [new path]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Env vars
|
|
128
|
+
|
|
129
|
+
| Name | Required | Default | Notes |
|
|
130
|
+
|---|---|---|---|
|
|
131
|
+
| `BUILDER_GPS_BUILDER_ID` | yes | — | UUID from the web app footer. **This is your auth token — don't share publicly.** |
|
|
132
|
+
| `BUILDER_GPS_API_URL` | no | `http://localhost:8000` | Point at your deployed backend in prod |
|
|
133
|
+
|
|
134
|
+
## Security model
|
|
135
|
+
|
|
136
|
+
The `builder_id` UUID is a bearer credential — anyone with it can mark sessions
|
|
137
|
+
on your behalf. For hackathon scope this is intentional (low-stakes, makes
|
|
138
|
+
sharing trivial). Don't paste it into screenshots or public configs.
|
|
139
|
+
|
|
140
|
+
## Troubleshooting
|
|
141
|
+
|
|
142
|
+
| Symptom | Likely cause |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `BUILDER_GPS_BUILDER_ID env var not set` | Env block not loaded — restart the AI tool after editing config |
|
|
145
|
+
| `[400] No builder session` | The UUID is wrong or you haven't submitted the form yet |
|
|
146
|
+
| `[404] No path yet` | Backend can't find your record — re-submit the form on the web app |
|
|
147
|
+
| Tools missing from Claude Desktop | Check Claude Desktop logs at `~/Library/Logs/Claude/mcp*.log` |
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Builder GPS MCP Server
|
|
2
|
+
|
|
3
|
+
Chat with your AABW schedule from Claude Desktop, Claude Code, Cursor, or any
|
|
4
|
+
other MCP-aware AI tool. No notifications — request/response only.
|
|
5
|
+
|
|
6
|
+
## What you get
|
|
7
|
+
|
|
8
|
+
4 tools, all keyed off your `builder_id` UUID:
|
|
9
|
+
|
|
10
|
+
| Tool | What it does |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `get_path` | Your full path + prerequisites + readiness % |
|
|
13
|
+
| `get_next_session` | The next session you haven't marked yet |
|
|
14
|
+
| `mark_session` | attended / skipped / blocked → triggers a reroute |
|
|
15
|
+
| `regenerate_path` | Re-runs the planner against your current history |
|
|
16
|
+
|
|
17
|
+
## 30-second setup
|
|
18
|
+
|
|
19
|
+
### 1. Get your builder_id
|
|
20
|
+
|
|
21
|
+
Open the web app → fill the goal form → on the timeline, expand
|
|
22
|
+
**"Connect via MCP? Show builder ID"** → copy the UUID.
|
|
23
|
+
|
|
24
|
+
### 2. Install the server
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cd builder-gps/apps/mcp
|
|
28
|
+
pip install -e .
|
|
29
|
+
# verify the script lands on your PATH:
|
|
30
|
+
builder-gps-mcp --help # (no-op; just confirms install)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The package exposes a `builder-gps-mcp` console script.
|
|
34
|
+
|
|
35
|
+
### 3. Wire it into your AI tool
|
|
36
|
+
|
|
37
|
+
**Claude Desktop** — edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"builder-gps": {
|
|
43
|
+
"command": "builder-gps-mcp",
|
|
44
|
+
"env": {
|
|
45
|
+
"BUILDER_GPS_API_URL": "http://localhost:8000",
|
|
46
|
+
"BUILDER_GPS_BUILDER_ID": "PASTE-YOUR-UUID-HERE"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Restart Claude Desktop. The compass icon → MCP → you should see `builder-gps`
|
|
54
|
+
with 4 tools.
|
|
55
|
+
|
|
56
|
+
**Claude Code** — one-liner:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
claude mcp add builder-gps \
|
|
60
|
+
--env BUILDER_GPS_API_URL=http://localhost:8000 \
|
|
61
|
+
--env BUILDER_GPS_BUILDER_ID=PASTE-YOUR-UUID-HERE \
|
|
62
|
+
-- builder-gps-mcp
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Cursor** — `~/.cursor/mcp.json`:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"mcpServers": {
|
|
70
|
+
"builder-gps": {
|
|
71
|
+
"command": "builder-gps-mcp",
|
|
72
|
+
"env": {
|
|
73
|
+
"BUILDER_GPS_API_URL": "http://localhost:8000",
|
|
74
|
+
"BUILDER_GPS_BUILDER_ID": "PASTE-YOUR-UUID-HERE"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Demo conversation
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
You: What's next on my AABW schedule?
|
|
85
|
+
Claude: [calls get_next_session]
|
|
86
|
+
Your next session is "Building production-ready agents with Apify"
|
|
87
|
+
on Day 3 (Jul 10) at 14:00 in Hall B. It's on your path because you
|
|
88
|
+
flagged scraping as a stack item.
|
|
89
|
+
|
|
90
|
+
You: I'll skip the morning one — mark it skipped.
|
|
91
|
+
Claude: [calls mark_session("d3-morning-deep-dive", "skipped")]
|
|
92
|
+
Marked skipped. Three changes to your path:
|
|
93
|
+
• Added "Agent Eval Frameworks" (you still need eval skills)
|
|
94
|
+
• Removed "LangGraph 101" (dependency on the skipped session)
|
|
95
|
+
• Reordered Day 4 to move "Demo Polish" earlier
|
|
96
|
+
Readiness held at 62%.
|
|
97
|
+
|
|
98
|
+
You: Give me a fresh plan based on what I've actually attended.
|
|
99
|
+
Claude: [calls regenerate_path]
|
|
100
|
+
... [new path]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Env vars
|
|
104
|
+
|
|
105
|
+
| Name | Required | Default | Notes |
|
|
106
|
+
|---|---|---|---|
|
|
107
|
+
| `BUILDER_GPS_BUILDER_ID` | yes | — | UUID from the web app footer. **This is your auth token — don't share publicly.** |
|
|
108
|
+
| `BUILDER_GPS_API_URL` | no | `http://localhost:8000` | Point at your deployed backend in prod |
|
|
109
|
+
|
|
110
|
+
## Security model
|
|
111
|
+
|
|
112
|
+
The `builder_id` UUID is a bearer credential — anyone with it can mark sessions
|
|
113
|
+
on your behalf. For hackathon scope this is intentional (low-stakes, makes
|
|
114
|
+
sharing trivial). Don't paste it into screenshots or public configs.
|
|
115
|
+
|
|
116
|
+
## Troubleshooting
|
|
117
|
+
|
|
118
|
+
| Symptom | Likely cause |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `BUILDER_GPS_BUILDER_ID env var not set` | Env block not loaded — restart the AI tool after editing config |
|
|
121
|
+
| `[400] No builder session` | The UUID is wrong or you haven't submitted the form yet |
|
|
122
|
+
| `[404] No path yet` | Backend can't find your record — re-submit the form on the web app |
|
|
123
|
+
| Tools missing from Claude Desktop | Check Claude Desktop logs at `~/Library/Logs/Claude/mcp*.log` |
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Builder GPS MCP server — chat with your AABW path from any AI tool.
|
|
2
|
+
|
|
3
|
+
Auth model: the builder_id UUID is the bearer. Set via env:
|
|
4
|
+
BUILDER_GPS_API_URL (default http://localhost:8000)
|
|
5
|
+
BUILDER_GPS_BUILDER_ID (required, taken from web app footer)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Thin httpx wrapper around the Builder GPS FastAPI backend.
|
|
2
|
+
|
|
3
|
+
The cookie jar holds `builder_gps_id` so we reuse the cookie-bound web routes
|
|
4
|
+
verbatim — no parallel auth surface.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ApiError(RuntimeError):
|
|
15
|
+
"""HTTP-level failure from the backend (status + body)."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, status: int, body: str) -> None:
|
|
18
|
+
super().__init__(f"[{status}] {body}")
|
|
19
|
+
self.status = status
|
|
20
|
+
self.body = body
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BuilderGpsClient:
|
|
24
|
+
"""Sync httpx wrapper. One client per MCP server lifetime."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, base_url: str, builder_id: str, timeout: float = 30.0):
|
|
27
|
+
self._base = base_url.rstrip("/")
|
|
28
|
+
self._client = httpx.Client(
|
|
29
|
+
base_url=self._base,
|
|
30
|
+
cookies={"builder_gps_id": builder_id},
|
|
31
|
+
timeout=timeout,
|
|
32
|
+
headers={"User-Agent": "builder-gps-mcp/0.1"},
|
|
33
|
+
)
|
|
34
|
+
self.builder_id = builder_id
|
|
35
|
+
|
|
36
|
+
def close(self) -> None:
|
|
37
|
+
self._client.close()
|
|
38
|
+
|
|
39
|
+
# -- read --------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
def get_path(self) -> dict[str, Any]:
|
|
42
|
+
"""Return the current PathResponse JSON."""
|
|
43
|
+
return self._json("GET", "/path")
|
|
44
|
+
|
|
45
|
+
def get_sessions(self) -> list[dict[str, Any]]:
|
|
46
|
+
"""Return the full session catalog (read-only)."""
|
|
47
|
+
return self._json("GET", "/sessions")
|
|
48
|
+
|
|
49
|
+
# -- mutate ------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
def mark_session(self, session_id: str, status: str) -> dict[str, Any]:
|
|
52
|
+
"""attended | skipped | blocked → triggers a reroute."""
|
|
53
|
+
return self._json(
|
|
54
|
+
"POST",
|
|
55
|
+
f"/sessions/{session_id}/mark",
|
|
56
|
+
json={"status": status},
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def regenerate(self) -> dict[str, Any]:
|
|
60
|
+
"""Recompute path against current state + history. No state change."""
|
|
61
|
+
return self._json("POST", "/path/regenerate")
|
|
62
|
+
|
|
63
|
+
# -- internal ----------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
def _json(self, method: str, path: str, **kw: Any) -> Any:
|
|
66
|
+
r = self._client.request(method, path, **kw)
|
|
67
|
+
if r.status_code >= 400:
|
|
68
|
+
raise ApiError(r.status_code, r.text)
|
|
69
|
+
return r.json()
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""Builder GPS MCP server (stdio transport).
|
|
2
|
+
|
|
3
|
+
Four tools, no auth flows, no extra state. The builder_id from
|
|
4
|
+
$BUILDER_GPS_BUILDER_ID becomes the cookie on every httpx call.
|
|
5
|
+
|
|
6
|
+
Run:
|
|
7
|
+
BUILDER_GPS_BUILDER_ID=<uuid> builder-gps-mcp
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
from datetime import datetime, timezone
|
|
15
|
+
from typing import Any
|
|
16
|
+
from zoneinfo import ZoneInfo
|
|
17
|
+
|
|
18
|
+
from mcp.server.fastmcp import FastMCP
|
|
19
|
+
|
|
20
|
+
from .api_client import ApiError, BuilderGpsClient
|
|
21
|
+
|
|
22
|
+
SAIGON = ZoneInfo("Asia/Saigon")
|
|
23
|
+
DEFAULT_API_URL = "https://api-builder-gps-production.up.railway.app"
|
|
24
|
+
|
|
25
|
+
mcp = FastMCP("builder-gps")
|
|
26
|
+
_client: BuilderGpsClient | None = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _get_client() -> BuilderGpsClient:
|
|
30
|
+
"""Lazy-init singleton. Surfaces config errors as MCP tool errors."""
|
|
31
|
+
global _client
|
|
32
|
+
if _client is not None:
|
|
33
|
+
return _client
|
|
34
|
+
builder_id = os.environ.get("BUILDER_GPS_BUILDER_ID", "").strip()
|
|
35
|
+
if not builder_id:
|
|
36
|
+
raise RuntimeError(
|
|
37
|
+
"BUILDER_GPS_BUILDER_ID env var not set. "
|
|
38
|
+
"Copy the builder_id from the web app footer (Connect via MCP "
|
|
39
|
+
"panel) and add it to your MCP client config."
|
|
40
|
+
)
|
|
41
|
+
base = os.environ.get("BUILDER_GPS_API_URL", DEFAULT_API_URL)
|
|
42
|
+
_client = BuilderGpsClient(base, builder_id)
|
|
43
|
+
return _client
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _safe_call(fn, *args, **kwargs) -> dict[str, Any]:
|
|
47
|
+
"""Convert ApiError → structured tool failure so the LLM can recover."""
|
|
48
|
+
try:
|
|
49
|
+
return fn(*args, **kwargs)
|
|
50
|
+
except ApiError as e:
|
|
51
|
+
return {
|
|
52
|
+
"ok": False,
|
|
53
|
+
"error": str(e),
|
|
54
|
+
"hint": (
|
|
55
|
+
"If status=400/404, the builder probably hasn't submitted "
|
|
56
|
+
"their goal yet — open the web app and fill the form."
|
|
57
|
+
),
|
|
58
|
+
}
|
|
59
|
+
except RuntimeError as e:
|
|
60
|
+
return {"ok": False, "error": str(e)}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _enrich(path: dict[str, Any]) -> dict[str, Any]:
|
|
64
|
+
"""Attach session catalog details to each PathSession entry."""
|
|
65
|
+
catalog = {s["id"]: s for s in _get_client().get_sessions()}
|
|
66
|
+
enriched: list[dict[str, Any]] = []
|
|
67
|
+
for ps in path.get("sessions", []):
|
|
68
|
+
s = catalog.get(ps["session_id"])
|
|
69
|
+
if s is None:
|
|
70
|
+
enriched.append(ps)
|
|
71
|
+
continue
|
|
72
|
+
enriched.append({**ps, "session": s})
|
|
73
|
+
return {**path, "sessions": enriched}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# ---------------------------------------------------------------------------
|
|
77
|
+
# Tools
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@mcp.tool()
|
|
82
|
+
def get_path() -> dict[str, Any]:
|
|
83
|
+
"""Return the builder's current AABW path.
|
|
84
|
+
|
|
85
|
+
Includes prerequisites (capabilities to acquire), each path session with
|
|
86
|
+
full schedule details (day, start, end, venue, title, signup_url), and
|
|
87
|
+
overall readiness percentage.
|
|
88
|
+
"""
|
|
89
|
+
return _safe_call(lambda: _enrich(_get_client().get_path()))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@mcp.tool()
|
|
93
|
+
def get_next_session(now_iso: str | None = None) -> dict[str, Any]:
|
|
94
|
+
"""Return the next recommended session relative to `now_iso` (Asia/Saigon).
|
|
95
|
+
|
|
96
|
+
Defaults to actual now. Skips sessions already marked attended/skipped.
|
|
97
|
+
Returns null if no future session remains.
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
now = (
|
|
101
|
+
datetime.fromisoformat(now_iso).astimezone(SAIGON)
|
|
102
|
+
if now_iso
|
|
103
|
+
else datetime.now(timezone.utc).astimezone(SAIGON)
|
|
104
|
+
)
|
|
105
|
+
except ValueError as e:
|
|
106
|
+
return {"ok": False, "error": f"Invalid now_iso: {e}"}
|
|
107
|
+
|
|
108
|
+
def _impl() -> dict[str, Any]:
|
|
109
|
+
path = _get_client().get_path()
|
|
110
|
+
catalog = {s["id"]: s for s in _get_client().get_sessions()}
|
|
111
|
+
upcoming: list[dict[str, Any]] = []
|
|
112
|
+
for ps in path.get("sessions", []):
|
|
113
|
+
if ps.get("status") in ("attended", "skipped"):
|
|
114
|
+
continue
|
|
115
|
+
s = catalog.get(ps["session_id"])
|
|
116
|
+
if s is None:
|
|
117
|
+
continue
|
|
118
|
+
start = _parse_session_start(s)
|
|
119
|
+
if start is None or start < now:
|
|
120
|
+
continue
|
|
121
|
+
upcoming.append(
|
|
122
|
+
{
|
|
123
|
+
"session_id": ps["session_id"],
|
|
124
|
+
"reason": ps.get("reason", ""),
|
|
125
|
+
"session": s,
|
|
126
|
+
"starts_at_iso": start.isoformat(),
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
upcoming.sort(key=lambda x: x["starts_at_iso"])
|
|
130
|
+
if not upcoming:
|
|
131
|
+
return {"ok": True, "next": None, "msg": "No future sessions."}
|
|
132
|
+
return {"ok": True, "next": upcoming[0]}
|
|
133
|
+
|
|
134
|
+
return _safe_call(_impl)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@mcp.tool()
|
|
138
|
+
def mark_session(session_id: str, status: str) -> dict[str, Any]:
|
|
139
|
+
"""Mark a session and trigger a reroute.
|
|
140
|
+
|
|
141
|
+
status must be one of: attended, skipped, blocked.
|
|
142
|
+
Returns the new path + a `last_change` diff explaining what shifted.
|
|
143
|
+
"""
|
|
144
|
+
if status not in ("attended", "skipped", "blocked"):
|
|
145
|
+
return {"ok": False, "error": f"Invalid status: {status}"}
|
|
146
|
+
return _safe_call(lambda: _get_client().mark_session(session_id, status))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@mcp.tool()
|
|
150
|
+
def regenerate_path() -> dict[str, Any]:
|
|
151
|
+
"""Recompute the path against current state + history without mutating it.
|
|
152
|
+
|
|
153
|
+
Use when the builder wants a fresh suggestion (e.g. "give me another plan").
|
|
154
|
+
"""
|
|
155
|
+
return _safe_call(lambda: _get_client().regenerate())
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# ---------------------------------------------------------------------------
|
|
159
|
+
# Helpers
|
|
160
|
+
# ---------------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
# AABW Jul 8 (Tue) - Jul 12 (Sat) 2026. Same constants as ical_export.
|
|
163
|
+
AABW_DATES = {
|
|
164
|
+
1: "2026-07-08",
|
|
165
|
+
2: "2026-07-09",
|
|
166
|
+
3: "2026-07-10",
|
|
167
|
+
4: "2026-07-11",
|
|
168
|
+
5: "2026-07-12",
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _parse_session_start(session: dict[str, Any]) -> datetime | None:
|
|
173
|
+
"""Compose Asia/Saigon datetime from session.day + session.start (HH:MM)."""
|
|
174
|
+
date = AABW_DATES.get(session.get("day"))
|
|
175
|
+
start = session.get("start")
|
|
176
|
+
if not date or not start:
|
|
177
|
+
return None
|
|
178
|
+
try:
|
|
179
|
+
return datetime.fromisoformat(f"{date}T{start}:00").replace(tzinfo=SAIGON)
|
|
180
|
+
except ValueError:
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def main() -> None:
|
|
185
|
+
"""Entrypoint for `builder-gps-mcp` script."""
|
|
186
|
+
try:
|
|
187
|
+
mcp.run()
|
|
188
|
+
except KeyboardInterrupt:
|
|
189
|
+
sys.exit(0)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if __name__ == "__main__":
|
|
193
|
+
main()
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: builder-gps-mcp
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: MCP server for Builder GPS — chat with your Agentic AI Build Week schedule from any AI editor.
|
|
5
|
+
Author: Builder GPS contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Kyle8Bits/builder-gps
|
|
8
|
+
Project-URL: Repository, https://github.com/Kyle8Bits/builder-gps
|
|
9
|
+
Project-URL: Issues, https://github.com/Kyle8Bits/builder-gps/issues
|
|
10
|
+
Keywords: mcp,ai,agents,aabw,schedule,claude,cursor
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: mcp>=1.2.0
|
|
22
|
+
Requires-Dist: httpx>=0.27.0
|
|
23
|
+
Requires-Dist: pydantic>=2.10.0
|
|
24
|
+
|
|
25
|
+
# Builder GPS MCP Server
|
|
26
|
+
|
|
27
|
+
Chat with your AABW schedule from Claude Desktop, Claude Code, Cursor, or any
|
|
28
|
+
other MCP-aware AI tool. No notifications — request/response only.
|
|
29
|
+
|
|
30
|
+
## What you get
|
|
31
|
+
|
|
32
|
+
4 tools, all keyed off your `builder_id` UUID:
|
|
33
|
+
|
|
34
|
+
| Tool | What it does |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `get_path` | Your full path + prerequisites + readiness % |
|
|
37
|
+
| `get_next_session` | The next session you haven't marked yet |
|
|
38
|
+
| `mark_session` | attended / skipped / blocked → triggers a reroute |
|
|
39
|
+
| `regenerate_path` | Re-runs the planner against your current history |
|
|
40
|
+
|
|
41
|
+
## 30-second setup
|
|
42
|
+
|
|
43
|
+
### 1. Get your builder_id
|
|
44
|
+
|
|
45
|
+
Open the web app → fill the goal form → on the timeline, expand
|
|
46
|
+
**"Connect via MCP? Show builder ID"** → copy the UUID.
|
|
47
|
+
|
|
48
|
+
### 2. Install the server
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cd builder-gps/apps/mcp
|
|
52
|
+
pip install -e .
|
|
53
|
+
# verify the script lands on your PATH:
|
|
54
|
+
builder-gps-mcp --help # (no-op; just confirms install)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The package exposes a `builder-gps-mcp` console script.
|
|
58
|
+
|
|
59
|
+
### 3. Wire it into your AI tool
|
|
60
|
+
|
|
61
|
+
**Claude Desktop** — edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"builder-gps": {
|
|
67
|
+
"command": "builder-gps-mcp",
|
|
68
|
+
"env": {
|
|
69
|
+
"BUILDER_GPS_API_URL": "http://localhost:8000",
|
|
70
|
+
"BUILDER_GPS_BUILDER_ID": "PASTE-YOUR-UUID-HERE"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Restart Claude Desktop. The compass icon → MCP → you should see `builder-gps`
|
|
78
|
+
with 4 tools.
|
|
79
|
+
|
|
80
|
+
**Claude Code** — one-liner:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
claude mcp add builder-gps \
|
|
84
|
+
--env BUILDER_GPS_API_URL=http://localhost:8000 \
|
|
85
|
+
--env BUILDER_GPS_BUILDER_ID=PASTE-YOUR-UUID-HERE \
|
|
86
|
+
-- builder-gps-mcp
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Cursor** — `~/.cursor/mcp.json`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"builder-gps": {
|
|
95
|
+
"command": "builder-gps-mcp",
|
|
96
|
+
"env": {
|
|
97
|
+
"BUILDER_GPS_API_URL": "http://localhost:8000",
|
|
98
|
+
"BUILDER_GPS_BUILDER_ID": "PASTE-YOUR-UUID-HERE"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Demo conversation
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
You: What's next on my AABW schedule?
|
|
109
|
+
Claude: [calls get_next_session]
|
|
110
|
+
Your next session is "Building production-ready agents with Apify"
|
|
111
|
+
on Day 3 (Jul 10) at 14:00 in Hall B. It's on your path because you
|
|
112
|
+
flagged scraping as a stack item.
|
|
113
|
+
|
|
114
|
+
You: I'll skip the morning one — mark it skipped.
|
|
115
|
+
Claude: [calls mark_session("d3-morning-deep-dive", "skipped")]
|
|
116
|
+
Marked skipped. Three changes to your path:
|
|
117
|
+
• Added "Agent Eval Frameworks" (you still need eval skills)
|
|
118
|
+
• Removed "LangGraph 101" (dependency on the skipped session)
|
|
119
|
+
• Reordered Day 4 to move "Demo Polish" earlier
|
|
120
|
+
Readiness held at 62%.
|
|
121
|
+
|
|
122
|
+
You: Give me a fresh plan based on what I've actually attended.
|
|
123
|
+
Claude: [calls regenerate_path]
|
|
124
|
+
... [new path]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Env vars
|
|
128
|
+
|
|
129
|
+
| Name | Required | Default | Notes |
|
|
130
|
+
|---|---|---|---|
|
|
131
|
+
| `BUILDER_GPS_BUILDER_ID` | yes | — | UUID from the web app footer. **This is your auth token — don't share publicly.** |
|
|
132
|
+
| `BUILDER_GPS_API_URL` | no | `http://localhost:8000` | Point at your deployed backend in prod |
|
|
133
|
+
|
|
134
|
+
## Security model
|
|
135
|
+
|
|
136
|
+
The `builder_id` UUID is a bearer credential — anyone with it can mark sessions
|
|
137
|
+
on your behalf. For hackathon scope this is intentional (low-stakes, makes
|
|
138
|
+
sharing trivial). Don't paste it into screenshots or public configs.
|
|
139
|
+
|
|
140
|
+
## Troubleshooting
|
|
141
|
+
|
|
142
|
+
| Symptom | Likely cause |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `BUILDER_GPS_BUILDER_ID env var not set` | Env block not loaded — restart the AI tool after editing config |
|
|
145
|
+
| `[400] No builder session` | The UUID is wrong or you haven't submitted the form yet |
|
|
146
|
+
| `[404] No path yet` | Backend can't find your record — re-submit the form on the web app |
|
|
147
|
+
| Tools missing from Claude Desktop | Check Claude Desktop logs at `~/Library/Logs/Claude/mcp*.log` |
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
builder_gps_mcp/__init__.py
|
|
4
|
+
builder_gps_mcp/api_client.py
|
|
5
|
+
builder_gps_mcp/server.py
|
|
6
|
+
builder_gps_mcp.egg-info/PKG-INFO
|
|
7
|
+
builder_gps_mcp.egg-info/SOURCES.txt
|
|
8
|
+
builder_gps_mcp.egg-info/dependency_links.txt
|
|
9
|
+
builder_gps_mcp.egg-info/entry_points.txt
|
|
10
|
+
builder_gps_mcp.egg-info/requires.txt
|
|
11
|
+
builder_gps_mcp.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
builder_gps_mcp
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "builder-gps-mcp"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
description = "MCP server for Builder GPS — chat with your Agentic AI Build Week schedule from any AI editor."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = { text = "MIT" }
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Builder GPS contributors" },
|
|
10
|
+
]
|
|
11
|
+
keywords = ["mcp", "ai", "agents", "aabw", "schedule", "claude", "cursor"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"mcp>=1.2.0",
|
|
24
|
+
"httpx>=0.27.0",
|
|
25
|
+
"pydantic>=2.10.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/Kyle8Bits/builder-gps"
|
|
30
|
+
Repository = "https://github.com/Kyle8Bits/builder-gps"
|
|
31
|
+
Issues = "https://github.com/Kyle8Bits/builder-gps/issues"
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
builder-gps-mcp = "builder_gps_mcp.server:main"
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["setuptools>=68", "wheel"]
|
|
38
|
+
build-backend = "setuptools.build_meta"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
include = ["builder_gps_mcp*"]
|