backpack-ontology 0.2.0 → 0.2.2
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/README.md +78 -139
- package/dist/auth/oauth.d.ts +32 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +208 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/bin/backpack-app.d.ts +3 -0
- package/dist/bin/backpack-app.d.ts.map +1 -0
- package/dist/bin/backpack-app.js +37 -0
- package/dist/bin/backpack-app.js.map +1 -0
- package/dist/bin/backpack-sync.d.ts +3 -0
- package/dist/bin/backpack-sync.d.ts.map +1 -0
- package/dist/bin/backpack-sync.js +148 -0
- package/dist/bin/backpack-sync.js.map +1 -0
- package/dist/bin/backpack.js +4 -4
- package/dist/bin/backpack.js.map +1 -1
- package/dist/bin/init.js +12 -79
- package/dist/bin/init.js.map +1 -1
- package/dist/core/hooks.d.ts +6 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +68 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +24 -4
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +29 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/bulk-tools.js +1 -1
- package/dist/mcp/tools/bulk-tools.js.map +1 -1
- package/dist/mcp/tools/edge-tools.js +3 -3
- package/dist/mcp/tools/edge-tools.js.map +1 -1
- package/dist/mcp/tools/node-tools.js +7 -7
- package/dist/mcp/tools/node-tools.js.map +1 -1
- package/dist/mcp/tools/ontology-tools.js +5 -5
- package/dist/mcp/tools/ontology-tools.js.map +1 -1
- package/dist/storage/backpack-app-backend.d.ts +22 -0
- package/dist/storage/backpack-app-backend.d.ts.map +1 -0
- package/dist/storage/backpack-app-backend.js +80 -0
- package/dist/storage/backpack-app-backend.js.map +1 -0
- package/hooks/hooks.json +2 -2
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -1,198 +1,137 @@
|
|
|
1
|
-
# Backpack
|
|
1
|
+
# Backpack
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Give your AI a memory it can actually use.** Backpack lets Claude remember what matters — your clients, your processes, your decisions — across every conversation.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## What it does
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
npm install -g backpack-ontology
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Setup
|
|
12
|
-
|
|
13
|
-
Add Backpack to your Claude Code project (`.mcp.json`):
|
|
14
|
-
|
|
15
|
-
```json
|
|
16
|
-
{
|
|
17
|
-
"mcpServers": {
|
|
18
|
-
"backpack": {
|
|
19
|
-
"command": "npx",
|
|
20
|
-
"args": ["backpack-ontology"]
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Or register it globally:
|
|
7
|
+
When you're working with Claude and something worth remembering comes up — a relationship, a project decision, a workflow, a domain concept — Backpack saves it as a structured knowledge graph. Next time you ask, Claude already knows.
|
|
27
8
|
|
|
28
|
-
```bash
|
|
29
|
-
claude mcp add backpack -- npx backpack-ontology
|
|
30
9
|
```
|
|
10
|
+
You: "We just signed Acme Corp, they're on the Enterprise tier, main contact is Sarah Chen"
|
|
31
11
|
|
|
32
|
-
|
|
12
|
+
Claude: [saves to backpack → clients ontology]
|
|
33
13
|
|
|
34
|
-
|
|
14
|
+
--- weeks later, different conversation ---
|
|
35
15
|
|
|
36
|
-
|
|
16
|
+
You: "What do we know about Acme Corp?"
|
|
37
17
|
|
|
18
|
+
Claude: "Acme Corp is on the Enterprise tier, main contact is Sarah Chen..."
|
|
38
19
|
```
|
|
39
|
-
[Ingredient: garlic] --USED_IN--> [Recipe: Aglio e Olio]
|
|
40
|
-
[Module: auth] --DEPENDS_ON--> [Module: database]
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Tell Claude what to store:
|
|
44
20
|
|
|
45
|
-
|
|
21
|
+
No copy-pasting. No re-explaining. Your knowledge carries forward.
|
|
46
22
|
|
|
47
|
-
|
|
23
|
+
## Get started
|
|
48
24
|
|
|
49
|
-
|
|
25
|
+
Tell Claude to set up Backpack:
|
|
50
26
|
|
|
51
|
-
|
|
27
|
+
> "Add backpack to this project"
|
|
52
28
|
|
|
53
|
-
|
|
29
|
+
Claude will configure the MCP server for you. Restart Claude Code and you're ready.
|
|
54
30
|
|
|
55
|
-
|
|
56
|
-
|-------|-------|---------|
|
|
57
|
-
| **Discover** | `backpack_list`, `backpack_create`, `backpack_describe` | Ontology names, descriptions, type counts |
|
|
58
|
-
| **Browse** | `backpack_list_nodes`, `backpack_node_types`, `backpack_search` | Paginated node summaries (id, type, label) |
|
|
59
|
-
| **Inspect** | `backpack_get_node`, `backpack_get_neighbors` | Full node data, graph traversal |
|
|
60
|
-
| **Mutate** | `backpack_add_node`, `backpack_update_node`, `backpack_add_edge`, ... | Create and modify data |
|
|
31
|
+
Or set it up yourself — pick local or cloud:
|
|
61
32
|
|
|
62
|
-
|
|
33
|
+
| Mode | Setup command |
|
|
34
|
+
|---|---|
|
|
35
|
+
| **Local** (free, private, on your machine) | `claude mcp add backpack -- npx backpack-ontology` |
|
|
36
|
+
| **Backpack App** (free account, cloud sync) | `claude mcp add backpack-app -- npx backpack-app` |
|
|
63
37
|
|
|
64
|
-
|
|
38
|
+
Backpack App syncs your knowledge across devices and gives you access to the web-based graph visualizer at [app.backpackontology.com](https://app.backpackontology.com). On first run, a browser window opens for sign-in — after that, it's automatic.
|
|
65
39
|
|
|
66
|
-
|
|
67
|
-
|------|-------------|
|
|
68
|
-
| `backpack_list` | List all ontologies with names, descriptions, and summary counts |
|
|
69
|
-
| `backpack_create` | Create a new empty ontology |
|
|
70
|
-
| `backpack_delete` | Permanently delete an ontology and all its data |
|
|
71
|
-
| `backpack_describe` | Inspect ontology structure: node types, edge types, counts |
|
|
40
|
+
## What to say to Claude
|
|
72
41
|
|
|
73
|
-
|
|
42
|
+
You don't need to learn commands or tools. Just talk to Claude naturally. Here's what you can do:
|
|
74
43
|
|
|
75
|
-
|
|
76
|
-
|------|-------------|
|
|
77
|
-
| `backpack_node_types` | List distinct node types with counts |
|
|
78
|
-
| `backpack_list_nodes` | Paginated node summaries, optionally filtered by type |
|
|
79
|
-
| `backpack_search` | Case-insensitive text search across all node properties |
|
|
44
|
+
### Remember something
|
|
80
45
|
|
|
81
|
-
|
|
46
|
+
> "Remember that Acme Corp is on the Enterprise tier, main contact is Sarah Chen"
|
|
82
47
|
|
|
83
|
-
|
|
84
|
-
|------|-------------|
|
|
85
|
-
| `backpack_get_node` | Full node with all properties and connected edge summaries |
|
|
86
|
-
| `backpack_get_neighbors` | BFS graph traversal from a node (max depth 3) |
|
|
48
|
+
> "Add our new vendor agreement details to backpack"
|
|
87
49
|
|
|
88
|
-
|
|
50
|
+
> "Start an ontology for our hiring process"
|
|
89
51
|
|
|
90
|
-
|
|
91
|
-
|------|-------------|
|
|
92
|
-
| `backpack_add_node` | Add a node with a freeform type and properties |
|
|
93
|
-
| `backpack_update_node` | Merge new properties into an existing node |
|
|
94
|
-
| `backpack_remove_node` | Remove a node and cascade-delete its edges |
|
|
95
|
-
| `backpack_add_edge` | Create a typed relationship between two nodes |
|
|
96
|
-
| `backpack_remove_edge` | Remove a relationship |
|
|
97
|
-
| `backpack_import_nodes` | Bulk-add multiple nodes in a single operation |
|
|
52
|
+
### Find something
|
|
98
53
|
|
|
99
|
-
|
|
54
|
+
> "What's in my backpack about Acme Corp?"
|
|
100
55
|
|
|
101
|
-
|
|
56
|
+
> "Search backpack for anything related to compliance"
|
|
102
57
|
|
|
103
|
-
|
|
104
|
-
import { Backpack, JsonFileBackend } from "backpack-ontology";
|
|
58
|
+
> "What do we know about the deployment process?"
|
|
105
59
|
|
|
106
|
-
|
|
107
|
-
await backpack.initialize();
|
|
60
|
+
### See the big picture
|
|
108
61
|
|
|
109
|
-
|
|
110
|
-
const node = await backpack.addNode("my-graph", "Person", { name: "Alice" });
|
|
111
|
-
await backpack.addEdge("my-graph", "KNOWS", node.id, otherNodeId);
|
|
62
|
+
> "Show me my knowledge graph"
|
|
112
63
|
|
|
113
|
-
|
|
114
|
-
const results = await backpack.searchNodes("my-graph", "alice");
|
|
64
|
+
> "What's in my backpack?"
|
|
115
65
|
|
|
116
|
-
|
|
117
|
-
const neighbors = await backpack.getNeighbors("my-graph", node.id, undefined, "both", 2);
|
|
118
|
-
```
|
|
66
|
+
> "Describe the clients ontology"
|
|
119
67
|
|
|
120
|
-
|
|
68
|
+
Claude will open the graph visualizer so you can explore your knowledge visually.
|
|
121
69
|
|
|
122
|
-
|
|
70
|
+
### Move to the cloud
|
|
123
71
|
|
|
124
|
-
|
|
125
|
-
import { Backpack, StorageBackend } from "backpack-ontology";
|
|
72
|
+
> "Sync my backpack to the cloud"
|
|
126
73
|
|
|
127
|
-
|
|
128
|
-
// initialize, listOntologies, loadOntology, saveOntology,
|
|
129
|
-
// createOntology, deleteOntology, ontologyExists
|
|
130
|
-
}
|
|
74
|
+
> "Upload my local ontologies to Backpack App"
|
|
131
75
|
|
|
132
|
-
|
|
133
|
-
```
|
|
76
|
+
Claude will migrate your local knowledge to Backpack App so you can access it from any device.
|
|
134
77
|
|
|
135
|
-
##
|
|
78
|
+
## What people use it for
|
|
136
79
|
|
|
137
|
-
|
|
80
|
+
- **Client management** — keep track of accounts, contacts, contract details, and conversations across sessions
|
|
81
|
+
- **Process documentation** — capture how things are done so Claude can help consistently
|
|
82
|
+
- **Project knowledge** — architecture decisions, vendor relationships, compliance requirements
|
|
83
|
+
- **Domain expertise** — industry terminology, regulatory frameworks, best practices
|
|
84
|
+
- **Team onboarding** — new team members get Claude with your organization's context already loaded
|
|
138
85
|
|
|
139
|
-
|
|
140
|
-
~/.local/share/backpack/ontologies/
|
|
141
|
-
├── cooking/
|
|
142
|
-
│ └── ontology.json
|
|
143
|
-
└── codebase-arch/
|
|
144
|
-
└── ontology.json
|
|
145
|
-
```
|
|
86
|
+
## How it works
|
|
146
87
|
|
|
147
|
-
|
|
88
|
+
You have one backpack — it goes everywhere with you. Inside it, you organize knowledge into **ontologies**, each one covering a different topic (clients, processes, compliance, etc.). Within each ontology, information is stored as things connected by relationships. You don't need to think about the structure. Claude handles it automatically based on what you're discussing.
|
|
148
89
|
|
|
149
|
-
|
|
150
|
-
|----------|--------|
|
|
151
|
-
| `XDG_DATA_HOME` | Override data location (default: `~/.local/share`) |
|
|
152
|
-
| `XDG_CONFIG_HOME` | Override config location (default: `~/.config`) |
|
|
153
|
-
| `BACKPACK_DIR` | Override both — config at `$BACKPACK_DIR/config`, data at `$BACKPACK_DIR/data` |
|
|
90
|
+
## Data and privacy
|
|
154
91
|
|
|
155
|
-
|
|
92
|
+
**Local mode**: Your data is stored as readable JSON files on your computer at `~/.local/share/backpack/ontologies/`. You can inspect, edit, back up, or version-control these files directly.
|
|
156
93
|
|
|
157
|
-
Backpack
|
|
94
|
+
**Backpack App**: Your data is stored securely in our cloud infrastructure. See our [privacy policy](https://backpackontology.com/privacy) for details.
|
|
158
95
|
|
|
159
|
-
**
|
|
160
|
-
- Tool call counts (which tools are used, not what data is passed)
|
|
161
|
-
- Session duration
|
|
162
|
-
- Aggregate ontology statistics (total node/edge counts, not names or content)
|
|
163
|
-
- Runtime environment (Node.js version, OS, platform)
|
|
96
|
+
**Telemetry**: Backpack collects anonymous usage statistics (which tools are used, session duration) to improve the product. No content, names, or personal data is ever collected. Opt out with `DO_NOT_TRACK=1`.
|
|
164
97
|
|
|
165
|
-
|
|
166
|
-
- Ontology names, descriptions, or content
|
|
167
|
-
- Node or edge properties
|
|
168
|
-
- File paths or user identifiers
|
|
169
|
-
- Tool arguments or query strings
|
|
98
|
+
## Reference
|
|
170
99
|
|
|
171
|
-
|
|
100
|
+
### CLI commands
|
|
172
101
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
102
|
+
| Command | What it does |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `npx backpack-ontology` | Start the local MCP server |
|
|
105
|
+
| `npx backpack-app` | Start the Backpack App MCP server (cloud) |
|
|
106
|
+
| `npx backpack-sync` | Upload local ontologies to Backpack App |
|
|
107
|
+
| `npx backpack-viewer` | Open the graph visualizer (http://localhost:5173) |
|
|
108
|
+
| `npx backpack-init` | Reinstall auto-capture hooks if removed |
|
|
176
109
|
|
|
177
|
-
|
|
178
|
-
export BACKPACK_TELEMETRY_DISABLED=1
|
|
179
|
-
```
|
|
110
|
+
### Tools
|
|
180
111
|
|
|
181
|
-
|
|
112
|
+
Claude uses these automatically — you don't need to call them directly.
|
|
182
113
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
114
|
+
| What Claude does | How |
|
|
115
|
+
|---|---|
|
|
116
|
+
| See what's in the backpack | `backpack_list`, `backpack_describe` |
|
|
117
|
+
| Add a new ontology to the backpack | `backpack_create` |
|
|
118
|
+
| Find something in the backpack | `backpack_search`, `backpack_list_nodes` |
|
|
119
|
+
| Get full details on an item | `backpack_get_node`, `backpack_get_neighbors` |
|
|
120
|
+
| Add or update knowledge | `backpack_add_node`, `backpack_update_node`, `backpack_add_edge` |
|
|
121
|
+
| Bulk import | `backpack_import_nodes` |
|
|
122
|
+
| Clean up | `backpack_remove_node`, `backpack_remove_edge`, `backpack_delete` |
|
|
188
123
|
|
|
189
|
-
|
|
124
|
+
### Advanced configuration
|
|
190
125
|
|
|
191
|
-
|
|
126
|
+
| Variable | Effect |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `XDG_DATA_HOME` | Change local data location (default: `~/.local/share`) |
|
|
129
|
+
| `BACKPACK_DIR` | Override all Backpack directories |
|
|
130
|
+
| `DO_NOT_TRACK` | Disable anonymous telemetry |
|
|
192
131
|
|
|
193
132
|
## Support
|
|
194
133
|
|
|
195
|
-
|
|
134
|
+
Questions, feedback, or partnership inquiries: **support@backpackontology.com**
|
|
196
135
|
|
|
197
136
|
## License
|
|
198
137
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth2 authorization code flow with PKCE for CLI/MCP clients.
|
|
3
|
+
*
|
|
4
|
+
* On first run: opens the browser → user signs in via Entra → callback
|
|
5
|
+
* captures the code → exchanges for tokens → caches to disk.
|
|
6
|
+
*
|
|
7
|
+
* On subsequent runs: uses cached token, refreshes if expired.
|
|
8
|
+
*/
|
|
9
|
+
export declare class OAuthClient {
|
|
10
|
+
private clientId;
|
|
11
|
+
private issuerUrl;
|
|
12
|
+
private tokenCachePath;
|
|
13
|
+
private cachedToken;
|
|
14
|
+
private endpoints;
|
|
15
|
+
constructor(clientId: string, issuerUrl: string, cacheKey: string);
|
|
16
|
+
/** Returns a valid token for Bearer auth, refreshing or re-authenticating as needed. */
|
|
17
|
+
getAccessToken(): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Prefer id_token for Bearer auth. Entra CIAM access tokens have
|
|
20
|
+
* Microsoft Graph as the audience, which oauth2-proxy won't accept.
|
|
21
|
+
* The id_token has the correct issuer and audience (our client ID).
|
|
22
|
+
*/
|
|
23
|
+
private getBearerToken;
|
|
24
|
+
private discoverEndpoints;
|
|
25
|
+
private authorize;
|
|
26
|
+
private refreshToken;
|
|
27
|
+
private startCallbackServer;
|
|
28
|
+
private openBrowser;
|
|
29
|
+
private loadCachedToken;
|
|
30
|
+
private saveToken;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"AAmBA;;;;;;;GAOG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,SAAS,CAA8B;gBAEnC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAMjE,wFAAwF;IAClF,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IA0BvC;;;;OAIG;IACH,OAAO,CAAC,cAAc;YAIR,iBAAiB;YAQjB,SAAS;YA4DT,YAAY;IAyB1B,OAAO,CAAC,mBAAmB;IAqD3B,OAAO,CAAC,WAAW;YAiBL,eAAe;YASf,SAAS;CAQxB"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import * as http from "node:http";
|
|
3
|
+
import * as fs from "node:fs/promises";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { exec } from "node:child_process";
|
|
6
|
+
import { configDir } from "../core/paths.js";
|
|
7
|
+
/**
|
|
8
|
+
* OAuth2 authorization code flow with PKCE for CLI/MCP clients.
|
|
9
|
+
*
|
|
10
|
+
* On first run: opens the browser → user signs in via Entra → callback
|
|
11
|
+
* captures the code → exchanges for tokens → caches to disk.
|
|
12
|
+
*
|
|
13
|
+
* On subsequent runs: uses cached token, refreshes if expired.
|
|
14
|
+
*/
|
|
15
|
+
export class OAuthClient {
|
|
16
|
+
clientId;
|
|
17
|
+
issuerUrl;
|
|
18
|
+
tokenCachePath;
|
|
19
|
+
cachedToken = null;
|
|
20
|
+
endpoints = null;
|
|
21
|
+
constructor(clientId, issuerUrl, cacheKey) {
|
|
22
|
+
this.clientId = clientId;
|
|
23
|
+
this.issuerUrl = issuerUrl.replace(/\/+$/, "");
|
|
24
|
+
this.tokenCachePath = path.join(configDir(), "app-tokens", `${cacheKey}.json`);
|
|
25
|
+
}
|
|
26
|
+
/** Returns a valid token for Bearer auth, refreshing or re-authenticating as needed. */
|
|
27
|
+
async getAccessToken() {
|
|
28
|
+
if (!this.cachedToken) {
|
|
29
|
+
this.cachedToken = await this.loadCachedToken();
|
|
30
|
+
}
|
|
31
|
+
if (this.cachedToken) {
|
|
32
|
+
// Still valid (with 60s buffer)
|
|
33
|
+
if (this.cachedToken.expires_at > Date.now() / 1000 + 60) {
|
|
34
|
+
return this.getBearerToken();
|
|
35
|
+
}
|
|
36
|
+
// Try refresh
|
|
37
|
+
if (this.cachedToken.refresh_token) {
|
|
38
|
+
try {
|
|
39
|
+
await this.refreshToken(this.cachedToken.refresh_token);
|
|
40
|
+
return this.getBearerToken();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
console.error("Token refresh failed, re-authenticating...");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Full browser-based authorization
|
|
48
|
+
await this.authorize();
|
|
49
|
+
return this.getBearerToken();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Prefer id_token for Bearer auth. Entra CIAM access tokens have
|
|
53
|
+
* Microsoft Graph as the audience, which oauth2-proxy won't accept.
|
|
54
|
+
* The id_token has the correct issuer and audience (our client ID).
|
|
55
|
+
*/
|
|
56
|
+
getBearerToken() {
|
|
57
|
+
return this.cachedToken.id_token ?? this.cachedToken.access_token;
|
|
58
|
+
}
|
|
59
|
+
async discoverEndpoints() {
|
|
60
|
+
if (this.endpoints)
|
|
61
|
+
return this.endpoints;
|
|
62
|
+
const res = await fetch(`${this.issuerUrl}/.well-known/openid-configuration`);
|
|
63
|
+
if (!res.ok)
|
|
64
|
+
throw new Error(`OIDC discovery failed: ${res.status}`);
|
|
65
|
+
this.endpoints = (await res.json());
|
|
66
|
+
return this.endpoints;
|
|
67
|
+
}
|
|
68
|
+
async authorize() {
|
|
69
|
+
const endpoints = await this.discoverEndpoints();
|
|
70
|
+
// PKCE
|
|
71
|
+
const codeVerifier = crypto.randomBytes(32).toString("base64url");
|
|
72
|
+
const codeChallenge = crypto
|
|
73
|
+
.createHash("sha256")
|
|
74
|
+
.update(codeVerifier)
|
|
75
|
+
.digest("base64url");
|
|
76
|
+
// Start a temporary callback server on a random port
|
|
77
|
+
const { port, codePromise } = await this.startCallbackServer();
|
|
78
|
+
const redirectUri = `http://localhost:${port}`;
|
|
79
|
+
const params = new URLSearchParams({
|
|
80
|
+
client_id: this.clientId,
|
|
81
|
+
response_type: "code",
|
|
82
|
+
redirect_uri: redirectUri,
|
|
83
|
+
scope: "openid email profile offline_access",
|
|
84
|
+
code_challenge: codeChallenge,
|
|
85
|
+
code_challenge_method: "S256",
|
|
86
|
+
});
|
|
87
|
+
const authUrl = `${endpoints.authorization_endpoint}?${params}`;
|
|
88
|
+
console.error("Opening browser for sign-in...");
|
|
89
|
+
await this.openBrowser(authUrl);
|
|
90
|
+
// Block until the user completes sign-in (or 120s timeout)
|
|
91
|
+
const code = await codePromise;
|
|
92
|
+
// Exchange authorization code for tokens
|
|
93
|
+
const tokenRes = await fetch(endpoints.token_endpoint, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
96
|
+
body: new URLSearchParams({
|
|
97
|
+
client_id: this.clientId,
|
|
98
|
+
grant_type: "authorization_code",
|
|
99
|
+
code,
|
|
100
|
+
redirect_uri: redirectUri,
|
|
101
|
+
code_verifier: codeVerifier,
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
if (!tokenRes.ok) {
|
|
105
|
+
const body = await tokenRes.text();
|
|
106
|
+
throw new Error(`Token exchange failed (${tokenRes.status}): ${body}`);
|
|
107
|
+
}
|
|
108
|
+
const data = (await tokenRes.json());
|
|
109
|
+
this.cachedToken = {
|
|
110
|
+
access_token: data.access_token,
|
|
111
|
+
refresh_token: data.refresh_token,
|
|
112
|
+
expires_at: Date.now() / 1000 + (data.expires_in ?? 3600),
|
|
113
|
+
id_token: data.id_token,
|
|
114
|
+
};
|
|
115
|
+
await this.saveToken(this.cachedToken);
|
|
116
|
+
console.error("Authenticated successfully.");
|
|
117
|
+
}
|
|
118
|
+
async refreshToken(refreshToken) {
|
|
119
|
+
const endpoints = await this.discoverEndpoints();
|
|
120
|
+
const res = await fetch(endpoints.token_endpoint, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
123
|
+
body: new URLSearchParams({
|
|
124
|
+
client_id: this.clientId,
|
|
125
|
+
grant_type: "refresh_token",
|
|
126
|
+
refresh_token: refreshToken,
|
|
127
|
+
}),
|
|
128
|
+
});
|
|
129
|
+
if (!res.ok)
|
|
130
|
+
throw new Error(`Refresh failed: ${res.status}`);
|
|
131
|
+
const data = (await res.json());
|
|
132
|
+
this.cachedToken = {
|
|
133
|
+
access_token: data.access_token,
|
|
134
|
+
refresh_token: data.refresh_token ?? refreshToken,
|
|
135
|
+
expires_at: Date.now() / 1000 + (data.expires_in ?? 3600),
|
|
136
|
+
id_token: data.id_token,
|
|
137
|
+
};
|
|
138
|
+
await this.saveToken(this.cachedToken);
|
|
139
|
+
}
|
|
140
|
+
startCallbackServer() {
|
|
141
|
+
return new Promise((resolve) => {
|
|
142
|
+
const server = http.createServer();
|
|
143
|
+
const codePromise = new Promise((resolveCode, rejectCode) => {
|
|
144
|
+
const timeout = setTimeout(() => {
|
|
145
|
+
server.close();
|
|
146
|
+
rejectCode(new Error("Authentication timed out (120s)"));
|
|
147
|
+
}, 120_000);
|
|
148
|
+
server.on("request", (req, res) => {
|
|
149
|
+
const url = new URL(req.url, "http://localhost");
|
|
150
|
+
const code = url.searchParams.get("code");
|
|
151
|
+
const error = url.searchParams.get("error");
|
|
152
|
+
const errorDesc = url.searchParams.get("error_description");
|
|
153
|
+
if (error) {
|
|
154
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
155
|
+
res.end("<html><body><h1>Authentication failed</h1><p>You can close this tab.</p></body></html>");
|
|
156
|
+
clearTimeout(timeout);
|
|
157
|
+
server.close();
|
|
158
|
+
rejectCode(new Error(`OAuth error: ${error} — ${errorDesc}`));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (code) {
|
|
162
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
163
|
+
res.end("<html><body><h1>Signed in to Backpack</h1><p>You can close this tab.</p></body></html>");
|
|
164
|
+
clearTimeout(timeout);
|
|
165
|
+
server.close();
|
|
166
|
+
resolveCode(code);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
res.writeHead(400);
|
|
170
|
+
res.end();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
server.listen(0, "127.0.0.1", () => {
|
|
174
|
+
const addr = server.address();
|
|
175
|
+
resolve({ port: addr.port, codePromise });
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
openBrowser(url) {
|
|
180
|
+
const cmd = process.platform === "darwin"
|
|
181
|
+
? "open"
|
|
182
|
+
: process.platform === "win32"
|
|
183
|
+
? "start"
|
|
184
|
+
: "xdg-open";
|
|
185
|
+
return new Promise((resolve) => {
|
|
186
|
+
exec(`${cmd} "${url}"`, (err) => {
|
|
187
|
+
if (err) {
|
|
188
|
+
console.error(`Could not open browser. Please visit:\n${url}`);
|
|
189
|
+
}
|
|
190
|
+
resolve();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
async loadCachedToken() {
|
|
195
|
+
try {
|
|
196
|
+
const raw = await fs.readFile(this.tokenCachePath, "utf-8");
|
|
197
|
+
return JSON.parse(raw);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async saveToken(token) {
|
|
204
|
+
await fs.mkdir(path.dirname(this.tokenCachePath), { recursive: true });
|
|
205
|
+
await fs.writeFile(this.tokenCachePath, JSON.stringify(token, null, 2), "utf-8");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backpack-app.d.ts","sourceRoot":"","sources":["../../src/bin/backpack-app.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { createMcpServer } from "../mcp/server.js";
|
|
4
|
+
import { ensureHooksInstalled } from "../core/hooks.js";
|
|
5
|
+
import { shutdown as shutdownTelemetry } from "../core/telemetry.js";
|
|
6
|
+
// Production defaults — users never need to configure these.
|
|
7
|
+
// Env vars override for development/testing only.
|
|
8
|
+
const DEFAULTS = {
|
|
9
|
+
url: "https://app.backpackontology.com",
|
|
10
|
+
clientId: "YOUR_ENTRA_CLIENT_ID_HERE",
|
|
11
|
+
issuerUrl: "https://YOUR_TENANT.ciamlogin.com/YOUR_TENANT_ID/v2.0",
|
|
12
|
+
};
|
|
13
|
+
async function main() {
|
|
14
|
+
// Install hooks on first run (silent, non-blocking)
|
|
15
|
+
ensureHooksInstalled().catch(() => { });
|
|
16
|
+
const apiUrl = process.env.BACKPACK_APP_URL || DEFAULTS.url;
|
|
17
|
+
const clientId = process.env.BACKPACK_APP_CLIENT_ID || DEFAULTS.clientId;
|
|
18
|
+
const issuerUrl = process.env.BACKPACK_APP_ISSUER_URL || DEFAULTS.issuerUrl;
|
|
19
|
+
const staticToken = process.env.BACKPACK_APP_TOKEN;
|
|
20
|
+
const server = await createMcpServer(staticToken
|
|
21
|
+
? { mode: "app", url: apiUrl, token: staticToken }
|
|
22
|
+
: { mode: "app", url: apiUrl, clientId, issuerUrl });
|
|
23
|
+
const transport = new StdioServerTransport();
|
|
24
|
+
await server.connect(transport);
|
|
25
|
+
console.error(`Backpack App MCP server running on stdio (${apiUrl})`);
|
|
26
|
+
}
|
|
27
|
+
async function gracefulShutdown() {
|
|
28
|
+
await shutdownTelemetry();
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
process.on("SIGINT", gracefulShutdown);
|
|
32
|
+
process.on("SIGTERM", gracefulShutdown);
|
|
33
|
+
main().catch((error) => {
|
|
34
|
+
console.error("Fatal error:", error);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=backpack-app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backpack-app.js","sourceRoot":"","sources":["../../src/bin/backpack-app.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAErE,6DAA6D;AAC7D,kDAAkD;AAClD,MAAM,QAAQ,GAAG;IACf,GAAG,EAAE,kCAAkC;IACvC,QAAQ,EAAE,2BAA2B;IACrC,SAAS,EAAE,uDAAuD;CACnE,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,oDAAoD;IACpD,oBAAoB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,QAAQ,CAAC,GAAG,CAAC;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,QAAQ,CAAC,QAAQ,CAAC;IACzE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,QAAQ,CAAC,SAAS,CAAC;IAC5E,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAEnD,MAAM,MAAM,GAAG,MAAM,eAAe,CAClC,WAAW;QACT,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE;QAClD,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,CACtD,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,KAAK,CAAC,6CAA6C,MAAM,GAAG,CAAC,CAAC;AACxE,CAAC;AAED,KAAK,UAAU,gBAAgB;IAC7B,MAAM,iBAAiB,EAAE,CAAC;IAC1B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AACvC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAExC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backpack-sync.d.ts","sourceRoot":"","sources":["../../src/bin/backpack-sync.ts"],"names":[],"mappings":""}
|