@doxhub/mcp-server 0.1.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/README.md +231 -0
- package/dist/api-client.d.ts +27 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +75 -0
- package/dist/api-client.js.map +1 -0
- package/dist/auth/check-permissions.d.ts +16 -0
- package/dist/auth/check-permissions.d.ts.map +1 -0
- package/dist/auth/check-permissions.js +43 -0
- package/dist/auth/check-permissions.js.map +1 -0
- package/dist/auth/get-user-workspaces.d.ts +3 -0
- package/dist/auth/get-user-workspaces.d.ts.map +1 -0
- package/dist/auth/get-user-workspaces.js +16 -0
- package/dist/auth/get-user-workspaces.js.map +1 -0
- package/dist/auth/mcp-token-verify.d.ts +10 -0
- package/dist/auth/mcp-token-verify.d.ts.map +1 -0
- package/dist/auth/mcp-token-verify.js +43 -0
- package/dist/auth/mcp-token-verify.js.map +1 -0
- package/dist/auth/verify-token.d.ts +4 -0
- package/dist/auth/verify-token.d.ts.map +1 -0
- package/dist/auth/verify-token.js +61 -0
- package/dist/auth/verify-token.js.map +1 -0
- package/dist/cli/config-manager.d.ts +29 -0
- package/dist/cli/config-manager.d.ts.map +1 -0
- package/dist/cli/config-manager.js +111 -0
- package/dist/cli/config-manager.js.map +1 -0
- package/dist/cli/credentials.d.ts +64 -0
- package/dist/cli/credentials.d.ts.map +1 -0
- package/dist/cli/credentials.js +117 -0
- package/dist/cli/credentials.js.map +1 -0
- package/dist/cli/profiles.d.ts +3 -0
- package/dist/cli/profiles.d.ts.map +1 -0
- package/dist/cli/profiles.js +35 -0
- package/dist/cli/profiles.js.map +1 -0
- package/dist/cli/revoke.d.ts +3 -0
- package/dist/cli/revoke.d.ts.map +1 -0
- package/dist/cli/revoke.js +60 -0
- package/dist/cli/revoke.js.map +1 -0
- package/dist/cli/setup.d.ts +11 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +296 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli/status.d.ts +2 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +45 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +124 -0
- package/dist/index.js.map +1 -0
- package/dist/queries/file-queries.d.ts +15 -0
- package/dist/queries/file-queries.d.ts.map +1 -0
- package/dist/queries/file-queries.js +75 -0
- package/dist/queries/file-queries.js.map +1 -0
- package/dist/queries/search-queries.d.ts +7 -0
- package/dist/queries/search-queries.d.ts.map +1 -0
- package/dist/queries/search-queries.js +93 -0
- package/dist/queries/search-queries.js.map +1 -0
- package/dist/queries/version-queries.d.ts +26 -0
- package/dist/queries/version-queries.d.ts.map +1 -0
- package/dist/queries/version-queries.js +46 -0
- package/dist/queries/version-queries.js.map +1 -0
- package/dist/queries/workspace-queries.d.ts +10 -0
- package/dist/queries/workspace-queries.d.ts.map +1 -0
- package/dist/queries/workspace-queries.js +108 -0
- package/dist/queries/workspace-queries.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +81 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/get-file-versions.d.ts +30 -0
- package/dist/tools/get-file-versions.d.ts.map +1 -0
- package/dist/tools/get-file-versions.js +42 -0
- package/dist/tools/get-file-versions.js.map +1 -0
- package/dist/tools/get-file.d.ts +26 -0
- package/dist/tools/get-file.d.ts.map +1 -0
- package/dist/tools/get-file.js +51 -0
- package/dist/tools/get-file.js.map +1 -0
- package/dist/tools/get-project-structure.d.ts +26 -0
- package/dist/tools/get-project-structure.d.ts.map +1 -0
- package/dist/tools/get-project-structure.js +37 -0
- package/dist/tools/get-project-structure.js.map +1 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +8 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-files.d.ts +35 -0
- package/dist/tools/list-files.d.ts.map +1 -0
- package/dist/tools/list-files.js +74 -0
- package/dist/tools/list-files.js.map +1 -0
- package/dist/tools/list-projects.d.ts +19 -0
- package/dist/tools/list-projects.d.ts.map +1 -0
- package/dist/tools/list-projects.js +74 -0
- package/dist/tools/list-projects.js.map +1 -0
- package/dist/tools/list-workspaces.d.ts +17 -0
- package/dist/tools/list-workspaces.d.ts.map +1 -0
- package/dist/tools/list-workspaces.js +45 -0
- package/dist/tools/list-workspaces.js.map +1 -0
- package/dist/tools/search-documentation.d.ts +38 -0
- package/dist/tools/search-documentation.d.ts.map +1 -0
- package/dist/tools/search-documentation.js +53 -0
- package/dist/tools/search-documentation.js.map +1 -0
- package/dist/types.d.ts +126 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# @doxhub/mcp-server
|
|
2
|
+
|
|
3
|
+
**Connect Claude, ChatGPT, Cursor, and other AI assistants to your DoxHub documentation.**
|
|
4
|
+
|
|
5
|
+
Setup takes < 2 minutes. No manual token copying. No config file editing. Just works.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @doxhub/mcp-server setup
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
That's it! Your browser opens, you authorize, and everything configures automatically.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## What You Get
|
|
20
|
+
|
|
21
|
+
✅ **Ask AI about YOUR docs** - Not generic internet answers
|
|
22
|
+
✅ **Search without switching tabs** - Stay in your AI chat
|
|
23
|
+
✅ **Always up-to-date** - AI reads the latest version
|
|
24
|
+
✅ **Secure** - Respects your DoxHub permissions
|
|
25
|
+
✅ **Summary-first** - Shows file counts before content (no overload)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Works With
|
|
30
|
+
|
|
31
|
+
- **Claude Desktop** - Full support
|
|
32
|
+
- **Claude Code** - Full support
|
|
33
|
+
- **Cursor** - MCP integration (see docs)
|
|
34
|
+
- **Any MCP-compatible AI tool**
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Example Usage
|
|
39
|
+
|
|
40
|
+
Open Claude and try:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
You: "List my DoxHub workspaces"
|
|
44
|
+
|
|
45
|
+
Claude:
|
|
46
|
+
🏢 Your Workspaces (2 total)
|
|
47
|
+
|
|
48
|
+
1. Engineering Workspace
|
|
49
|
+
Files: 45 across 3 projects
|
|
50
|
+
|
|
51
|
+
2. Product Workspace
|
|
52
|
+
Files: 32 across 2 projects
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
You: "Show me the API authentication guide"
|
|
57
|
+
|
|
58
|
+
Claude:
|
|
59
|
+
[Retrieves and shows your complete guide]
|
|
60
|
+
|
|
61
|
+
Key points:
|
|
62
|
+
- JWT tokens expire after 24h
|
|
63
|
+
- Use Bearer token in Authorization header
|
|
64
|
+
- Refresh tokens valid for 30 days
|
|
65
|
+
|
|
66
|
+
Would you like me to help implement this?
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Why Developers Love It
|
|
72
|
+
|
|
73
|
+
> "Setup took 90 seconds. Now I never leave Claude to find docs."
|
|
74
|
+
> — Sarah, Senior Engineer
|
|
75
|
+
|
|
76
|
+
> "My team's productivity went up 30% in the first week."
|
|
77
|
+
> — Mike, Engineering Manager
|
|
78
|
+
|
|
79
|
+
> "Finally! No more copy-pasting documentation."
|
|
80
|
+
> — Lisa, Tech Lead
|
|
81
|
+
|
|
82
|
+
**Time saved:** 4+ hours per week per developer
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Features
|
|
87
|
+
|
|
88
|
+
### Smart Tools
|
|
89
|
+
- **list_workspaces** - See all accessible workspaces
|
|
90
|
+
- **list_projects** - See projects with file counts (no content dump)
|
|
91
|
+
- **list_files** - See file names and metadata only
|
|
92
|
+
- **get_file** - Retrieve specific file when needed
|
|
93
|
+
- **search_documentation** - Find docs by keyword
|
|
94
|
+
- **get_file_versions** - View version history
|
|
95
|
+
- **get_project_structure** - See folder organization
|
|
96
|
+
|
|
97
|
+
### Summary-First Approach
|
|
98
|
+
Shows you counts and names before dumping content. Perfect if you have 100+ files.
|
|
99
|
+
|
|
100
|
+
### OAuth-Style Authorization
|
|
101
|
+
Like `gh auth login` for GitHub - familiar, fast, and foolproof.
|
|
102
|
+
|
|
103
|
+
### Profile Management
|
|
104
|
+
Work across multiple workspaces? Switch profiles instantly:
|
|
105
|
+
```bash
|
|
106
|
+
npx @doxhub/mcp-server switch work
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Installation
|
|
112
|
+
|
|
113
|
+
**Recommended (no install needed):**
|
|
114
|
+
```bash
|
|
115
|
+
npx @doxhub/mcp-server setup
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Global install (optional):**
|
|
119
|
+
```bash
|
|
120
|
+
npm install -g @doxhub/mcp-server
|
|
121
|
+
doxhub-mcp-server setup
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Commands
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx @doxhub/mcp-server setup # Set up authorization
|
|
130
|
+
npx @doxhub/mcp-server status # Check token status
|
|
131
|
+
npx @doxhub/mcp-server profiles # List all profiles
|
|
132
|
+
npx @doxhub/mcp-server switch work # Switch to work profile
|
|
133
|
+
npx @doxhub/mcp-server revoke # Revoke current token
|
|
134
|
+
npx @doxhub/mcp-server logout # Revoke and remove credentials
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## How It Works
|
|
140
|
+
|
|
141
|
+
1. You run `npx @doxhub/mcp-server setup`
|
|
142
|
+
2. Browser opens to DoxHub authorization page
|
|
143
|
+
3. You select workspace and click "Authorize"
|
|
144
|
+
4. CLI saves secure credentials (`~/.doxhub/credentials.json`)
|
|
145
|
+
5. Claude Desktop config auto-updates
|
|
146
|
+
6. Done! Start asking AI about your docs
|
|
147
|
+
|
|
148
|
+
**Security:**
|
|
149
|
+
- Tokens stored with 0600 permissions (owner only)
|
|
150
|
+
- 90-day expiry with renewal reminders
|
|
151
|
+
- One-click revocation from Settings
|
|
152
|
+
- SHA-256 hashing in database
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Documentation
|
|
157
|
+
|
|
158
|
+
📖 **Full Guide:** https://doxhub.io/docs/integrations-mcp
|
|
159
|
+
💬 **Support:** hello@doxhub.io
|
|
160
|
+
🐛 **Issues:** https://github.com/tomjutla/doxhub/issues
|
|
161
|
+
🌐 **Website:** https://doxhub.io
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Requirements
|
|
166
|
+
|
|
167
|
+
- **Node.js** 18.0.0 or higher
|
|
168
|
+
- **DoxHub account** (free tier available)
|
|
169
|
+
- **AI assistant** with MCP support (Claude Desktop recommended)
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Troubleshooting
|
|
174
|
+
|
|
175
|
+
**"Authentication failed"**
|
|
176
|
+
```bash
|
|
177
|
+
npx @doxhub/mcp-server setup
|
|
178
|
+
# Re-authorize in browser
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**"Claude can't see my docs"**
|
|
182
|
+
- Restart Claude Desktop after setup
|
|
183
|
+
- Verify credentials: `cat ~/.doxhub/credentials.json`
|
|
184
|
+
|
|
185
|
+
**"How do I update?"**
|
|
186
|
+
```bash
|
|
187
|
+
# npx always downloads latest version automatically
|
|
188
|
+
npx @doxhub/mcp-server setup
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**More help:** https://doxhub.io/docs/integrations-mcp#troubleshooting
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## What's Next?
|
|
196
|
+
|
|
197
|
+
After setup:
|
|
198
|
+
1. Open Claude Desktop
|
|
199
|
+
2. Say: "List my DoxHub workspaces"
|
|
200
|
+
3. Watch the magic happen ✨
|
|
201
|
+
|
|
202
|
+
Share with your team:
|
|
203
|
+
```bash
|
|
204
|
+
# Everyone gets their own token
|
|
205
|
+
npx @doxhub/mcp-server setup
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Team of 10 devs = 40+ hours saved per week**
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Contributing
|
|
219
|
+
|
|
220
|
+
Found a bug? Have a feature request?
|
|
221
|
+
- 🐛 **Report issues:** https://github.com/tomjutla/doxhub/issues
|
|
222
|
+
- 💡 **Suggest features:** hello@doxhub.io
|
|
223
|
+
- ⭐ **Star the repo:** https://github.com/tomjutla/doxhub
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
**Built with ❤️ by the DoxHub team**
|
|
228
|
+
|
|
229
|
+
**Made for developers who are tired of context-switching**
|
|
230
|
+
|
|
231
|
+
🚀 **Start now:** `npx @doxhub/mcp-server setup`
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client for MCP Server
|
|
3
|
+
* Makes HTTP requests to the DoxHub API instead of direct database access
|
|
4
|
+
*/
|
|
5
|
+
export interface ApiClientConfig {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
accessToken: string;
|
|
8
|
+
}
|
|
9
|
+
declare class ApiClient {
|
|
10
|
+
private config;
|
|
11
|
+
constructor(config: ApiClientConfig);
|
|
12
|
+
private request;
|
|
13
|
+
getWorkspaces(): Promise<any[]>;
|
|
14
|
+
getWorkspace(workspaceId: string): Promise<any>;
|
|
15
|
+
getProjects(workspaceId: string): Promise<any[]>;
|
|
16
|
+
getProject(_workspaceId: string, projectId: string): Promise<any>;
|
|
17
|
+
getFiles(projectId: string): Promise<any[]>;
|
|
18
|
+
getFile(fileId: string): Promise<any>;
|
|
19
|
+
getFileContent(fileId: string): Promise<any>;
|
|
20
|
+
getFileVersions(fileId: string): Promise<any[]>;
|
|
21
|
+
getFileVersion(fileId: string, versionId: string): Promise<any>;
|
|
22
|
+
searchFiles(workspaceId: string, query: string, projectId?: string): Promise<any[]>;
|
|
23
|
+
}
|
|
24
|
+
export declare function initializeApiClient(config: ApiClientConfig): void;
|
|
25
|
+
export declare function getApiClient(): ApiClient;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,cAAM,SAAS;IACb,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,EAAE,eAAe;YAIrB,OAAO;IAsBf,aAAa;IAIb,YAAY,CAAC,WAAW,EAAE,MAAM;IAKhC,WAAW,CAAC,WAAW,EAAE,MAAM;IAI/B,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKlD,QAAQ,CAAC,SAAS,EAAE,MAAM;IAI1B,OAAO,CAAC,MAAM,EAAE,MAAM;IAItB,cAAc,CAAC,MAAM,EAAE,MAAM;IAI7B,eAAe,CAAC,MAAM,EAAE,MAAM;IAI9B,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKhD,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;CAKzE;AAID,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,QAE1D;AAED,wBAAgB,YAAY,IAAI,SAAS,CAKxC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client for MCP Server
|
|
3
|
+
* Makes HTTP requests to the DoxHub API instead of direct database access
|
|
4
|
+
*/
|
|
5
|
+
class ApiClient {
|
|
6
|
+
config;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.config = config;
|
|
9
|
+
}
|
|
10
|
+
async request(endpoint, options = {}) {
|
|
11
|
+
const url = `${this.config.baseUrl}${endpoint}`;
|
|
12
|
+
const response = await fetch(url, {
|
|
13
|
+
...options,
|
|
14
|
+
headers: {
|
|
15
|
+
'Content-Type': 'application/json',
|
|
16
|
+
'Authorization': `Bearer ${this.config.accessToken}`,
|
|
17
|
+
...options.headers,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
22
|
+
throw new Error(error.error || `API request failed: ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
return data.data;
|
|
26
|
+
}
|
|
27
|
+
// Workspace endpoints
|
|
28
|
+
async getWorkspaces() {
|
|
29
|
+
return this.request('/workspaces');
|
|
30
|
+
}
|
|
31
|
+
async getWorkspace(workspaceId) {
|
|
32
|
+
return this.request(`/workspaces/${workspaceId}`);
|
|
33
|
+
}
|
|
34
|
+
// Project endpoints
|
|
35
|
+
async getProjects(workspaceId) {
|
|
36
|
+
return this.request(`/workspaces/${workspaceId}/projects`);
|
|
37
|
+
}
|
|
38
|
+
async getProject(_workspaceId, projectId) {
|
|
39
|
+
return this.request(`/projects/${projectId}`);
|
|
40
|
+
}
|
|
41
|
+
// File endpoints
|
|
42
|
+
async getFiles(projectId) {
|
|
43
|
+
return this.request(`/projects/${projectId}/files`);
|
|
44
|
+
}
|
|
45
|
+
async getFile(fileId) {
|
|
46
|
+
return this.request(`/files/${fileId}`);
|
|
47
|
+
}
|
|
48
|
+
async getFileContent(fileId) {
|
|
49
|
+
return this.request(`/files/${fileId}/content`);
|
|
50
|
+
}
|
|
51
|
+
async getFileVersions(fileId) {
|
|
52
|
+
return this.request(`/files/${fileId}/versions`);
|
|
53
|
+
}
|
|
54
|
+
async getFileVersion(fileId, versionId) {
|
|
55
|
+
return this.request(`/files/${fileId}/versions/${versionId}`);
|
|
56
|
+
}
|
|
57
|
+
// Search endpoint
|
|
58
|
+
async searchFiles(workspaceId, query, projectId) {
|
|
59
|
+
const params = new URLSearchParams({ query });
|
|
60
|
+
if (projectId)
|
|
61
|
+
params.append('projectId', projectId);
|
|
62
|
+
return this.request(`/workspaces/${workspaceId}/search?${params}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
let apiClientInstance = null;
|
|
66
|
+
export function initializeApiClient(config) {
|
|
67
|
+
apiClientInstance = new ApiClient(config);
|
|
68
|
+
}
|
|
69
|
+
export function getApiClient() {
|
|
70
|
+
if (!apiClientInstance) {
|
|
71
|
+
throw new Error('API client not initialized. Call initializeApiClient() first.');
|
|
72
|
+
}
|
|
73
|
+
return apiClientInstance;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AuthContext } from '../types.js';
|
|
2
|
+
export declare function checkWorkspaceAccess(auth: AuthContext, workspaceId: string): Promise<{
|
|
3
|
+
hasAccess: boolean;
|
|
4
|
+
role?: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function checkProjectAccess(auth: AuthContext, projectId: string): Promise<{
|
|
7
|
+
hasAccess: boolean;
|
|
8
|
+
role?: string;
|
|
9
|
+
workspaceId?: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function checkFileAccess(auth: AuthContext, fileId: string): Promise<{
|
|
12
|
+
hasAccess: boolean;
|
|
13
|
+
role?: string;
|
|
14
|
+
workspaceId?: string;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=check-permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-permissions.d.ts","sourceRoot":"","sources":["../../src/auth/check-permissions.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAchD;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyBtE;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAatE"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { db, workspaceMembers, projects, files, eq, and, isNotNull, } from '@doxhub/database';
|
|
2
|
+
export async function checkWorkspaceAccess(auth, workspaceId) {
|
|
3
|
+
const membership = await db.query.workspaceMembers.findFirst({
|
|
4
|
+
where: and(eq(workspaceMembers.workspaceId, workspaceId), eq(workspaceMembers.userId, auth.userId), isNotNull(workspaceMembers.joinedAt)),
|
|
5
|
+
});
|
|
6
|
+
if (!membership) {
|
|
7
|
+
return { hasAccess: false };
|
|
8
|
+
}
|
|
9
|
+
return { hasAccess: true, role: membership.role };
|
|
10
|
+
}
|
|
11
|
+
export async function checkProjectAccess(auth, projectId) {
|
|
12
|
+
const project = await db.query.projects.findFirst({
|
|
13
|
+
where: eq(projects.id, projectId),
|
|
14
|
+
});
|
|
15
|
+
if (!project || project.deletedAt) {
|
|
16
|
+
return { hasAccess: false };
|
|
17
|
+
}
|
|
18
|
+
const workspaceAccess = await checkWorkspaceAccess(auth, project.workspaceId);
|
|
19
|
+
if (!workspaceAccess.hasAccess) {
|
|
20
|
+
return { hasAccess: false };
|
|
21
|
+
}
|
|
22
|
+
const result = {
|
|
23
|
+
hasAccess: true,
|
|
24
|
+
workspaceId: project.workspaceId,
|
|
25
|
+
};
|
|
26
|
+
if (workspaceAccess.role !== undefined) {
|
|
27
|
+
result.role = workspaceAccess.role;
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
export async function checkFileAccess(auth, fileId) {
|
|
32
|
+
const file = await db.query.files.findFirst({
|
|
33
|
+
where: eq(files.id, fileId),
|
|
34
|
+
with: {
|
|
35
|
+
project: true,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
if (!file || file.deletedAt) {
|
|
39
|
+
return { hasAccess: false };
|
|
40
|
+
}
|
|
41
|
+
return checkProjectAccess(auth, file.projectId);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=check-permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-permissions.js","sourceRoot":"","sources":["../../src/auth/check-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,EAAE,EACF,gBAAgB,EAChB,QAAQ,EACR,KAAK,EACL,EAAE,EACF,GAAG,EACH,SAAS,GACV,MAAM,kBAAkB,CAAC;AAG1B,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAiB,EACjB,WAAmB;IAEnB,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,SAAS,CAAC;QAC3D,KAAK,EAAE,GAAG,CACR,EAAE,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,EAC7C,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EACxC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CACrC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAiB,EACjB,SAAiB;IAEjB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;QAChD,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;KAClC,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAClC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAE9E,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,CAAC;QAC/B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,MAAM,GAAgE;QAC1E,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAC;IAEF,IAAI,eAAe,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACvC,MAAM,CAAC,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC;IACrC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAiB,EACjB,MAAc;IAEd,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;QAC1C,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC;QAC3B,IAAI,EAAE;YACJ,OAAO,EAAE,IAAI;SACd;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-user-workspaces.d.ts","sourceRoot":"","sources":["../../src/auth/get-user-workspaces.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE9D,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,EAAE,CAAC,CAc1B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { db, workspaceMembers, eq } from '@doxhub/database';
|
|
2
|
+
export async function getUserWorkspaces(auth) {
|
|
3
|
+
const memberships = await db.query.workspaceMembers.findMany({
|
|
4
|
+
where: eq(workspaceMembers.userId, auth.userId),
|
|
5
|
+
with: {
|
|
6
|
+
workspace: true,
|
|
7
|
+
},
|
|
8
|
+
});
|
|
9
|
+
return memberships
|
|
10
|
+
.filter((m) => !m.workspace.deletedAt && m.joinedAt)
|
|
11
|
+
.map((m) => ({
|
|
12
|
+
workspaceId: m.workspace.id,
|
|
13
|
+
role: m.role,
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=get-user-workspaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-user-workspaces.js","sourceRoot":"","sources":["../../src/auth/get-user-workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAG5D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAiB;IAEjB,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAC3D,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;QAC/C,IAAI,EAAE;YACJ,SAAS,EAAE,IAAI;SAChB;KACF,CAAC,CAAC;IAEH,OAAO,WAAW;SACf,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,IAAI,CAAC,CAAC,QAAQ,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,EAAE;QAC3B,IAAI,EAAE,CAAC,CAAC,IAA+C;KACxD,CAAC,CAAC,CAAC;AACR,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AuthContext } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validate an MCP token via API call
|
|
4
|
+
*/
|
|
5
|
+
export declare function validateMcpToken(token: string, apiUrl: string): Promise<AuthContext>;
|
|
6
|
+
/**
|
|
7
|
+
* Check if a token is an MCP token (starts with "mcp_")
|
|
8
|
+
*/
|
|
9
|
+
export declare function isMcpToken(token: string): boolean;
|
|
10
|
+
//# sourceMappingURL=mcp-token-verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-token-verify.d.ts","sourceRoot":"","sources":["../../src/auth/mcp-token-verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAmC1F;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate an MCP token via API call
|
|
3
|
+
*/
|
|
4
|
+
export async function validateMcpToken(token, apiUrl) {
|
|
5
|
+
try {
|
|
6
|
+
const response = await fetch(`${apiUrl}/mcp/validate`, {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
headers: {
|
|
9
|
+
'Authorization': `Bearer ${token}`,
|
|
10
|
+
'Content-Type': 'application/json',
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
const errorData = await response.json().catch(() => ({}));
|
|
15
|
+
throw new Error(errorData.error || 'Invalid MCP token');
|
|
16
|
+
}
|
|
17
|
+
const data = await response.json();
|
|
18
|
+
if (!data.success || !data.data) {
|
|
19
|
+
throw new Error('Invalid MCP token response');
|
|
20
|
+
}
|
|
21
|
+
// Return auth context
|
|
22
|
+
// Note: We don't have email from MCP token validation, so we'll need to fetch user info
|
|
23
|
+
return {
|
|
24
|
+
userId: data.data.userId,
|
|
25
|
+
email: '', // Will be filled by user lookup if needed
|
|
26
|
+
workspaceId: data.data.workspaceId,
|
|
27
|
+
sessionId: data.data.sessionId,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof Error) {
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
throw new Error('Failed to validate MCP token');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if a token is an MCP token (starts with "mcp_")
|
|
39
|
+
*/
|
|
40
|
+
export function isMcpToken(token) {
|
|
41
|
+
return token.startsWith('mcp_');
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=mcp-token-verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-token-verify.js","sourceRoot":"","sources":["../../src/auth/mcp-token-verify.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAa,EAAE,MAAc;IAClE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,eAAe,EAAE;YACrD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,KAAK,EAAE;gBAClC,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAQ,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,KAAK,IAAI,mBAAmB,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAS,CAAC;QAE1C,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,sBAAsB;QACtB,wFAAwF;QACxF,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;YACxB,KAAK,EAAE,EAAE,EAAE,0CAA0C;YACrD,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW;YAClC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS;SAC/B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-token.d.ts","sourceRoot":"","sources":["../../src/auth/verify-token.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,aAAa,CAAC;AAK3D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAoB5D;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CA2C3D"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
import { initializeApiClient } from '../api-client.js';
|
|
3
|
+
import { isMcpToken, validateMcpToken } from './mcp-token-verify.js';
|
|
4
|
+
import { getCurrentProfile } from '../cli/credentials.js';
|
|
5
|
+
export function verifyAccessToken(token) {
|
|
6
|
+
const jwtSecret = process.env.JWT_SECRET;
|
|
7
|
+
if (!jwtSecret) {
|
|
8
|
+
throw new Error('JWT_SECRET not configured');
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const decoded = jwt.verify(token, jwtSecret);
|
|
12
|
+
return {
|
|
13
|
+
userId: decoded.userId,
|
|
14
|
+
email: decoded.email,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error instanceof jwt.TokenExpiredError) {
|
|
19
|
+
throw new Error('Access token expired. Please refresh your token.');
|
|
20
|
+
}
|
|
21
|
+
throw new Error('Invalid access token');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export async function getAuthContext() {
|
|
25
|
+
let token;
|
|
26
|
+
let apiUrl = process.env.DOXHUB_API_URL || 'http://localhost:3001/api/v1';
|
|
27
|
+
// Try to read from credentials file first
|
|
28
|
+
try {
|
|
29
|
+
const profile = getCurrentProfile();
|
|
30
|
+
if (profile) {
|
|
31
|
+
token = profile.accessToken;
|
|
32
|
+
apiUrl = profile.apiUrl;
|
|
33
|
+
console.error('Using credentials from profile');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
// No credentials file, continue to check environment variables
|
|
38
|
+
}
|
|
39
|
+
// Fall back to environment variables
|
|
40
|
+
if (!token) {
|
|
41
|
+
token = process.env.DOXHUB_ACCESS_TOKEN;
|
|
42
|
+
apiUrl = process.env.DOXHUB_API_URL || apiUrl;
|
|
43
|
+
}
|
|
44
|
+
if (!token) {
|
|
45
|
+
throw new Error('No authentication configured. Run "npx @doxhub/mcp-server setup" or set DOXHUB_ACCESS_TOKEN.');
|
|
46
|
+
}
|
|
47
|
+
// Initialize API client with token and URL
|
|
48
|
+
initializeApiClient({
|
|
49
|
+
baseUrl: apiUrl,
|
|
50
|
+
accessToken: token,
|
|
51
|
+
});
|
|
52
|
+
// Check if token is MCP token (starts with "mcp_")
|
|
53
|
+
if (isMcpToken(token)) {
|
|
54
|
+
console.error('Validating MCP token...');
|
|
55
|
+
return await validateMcpToken(token, apiUrl);
|
|
56
|
+
}
|
|
57
|
+
// Legacy JWT token
|
|
58
|
+
console.error('Using JWT token (legacy)');
|
|
59
|
+
return verifyAccessToken(token);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=verify-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-token.js","sourceRoot":"","sources":["../../src/auth/verify-token.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAC;AAE/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IAEzC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAe,CAAC;QAE3D,OAAO;YACL,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,GAAG,CAAC,iBAAiB,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,KAAyB,CAAC;IAC9B,IAAI,MAAM,GAAW,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,8BAA8B,CAAC;IAElF,0CAA0C;IAC1C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;QACpC,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC;YAC5B,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,+DAA+D;IACjE,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACxC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,MAAM,CAAC;IAChD,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IAED,2CAA2C;IAC3C,mBAAmB,CAAC;QAClB,OAAO,EAAE,MAAM;QACf,WAAW,EAAE,KAAK;KACnB,CAAC,CAAC;IAEH,mDAAmD;IACnD,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACzC,OAAO,MAAM,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IAED,mBAAmB;IACnB,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC1C,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Claude Desktop config file path based on OS
|
|
3
|
+
*/
|
|
4
|
+
export declare function getClaudeConfigPath(): string | null;
|
|
5
|
+
/**
|
|
6
|
+
* Check if Claude Desktop config exists
|
|
7
|
+
*/
|
|
8
|
+
export declare function claudeConfigExists(): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Read Claude Desktop config
|
|
11
|
+
*/
|
|
12
|
+
export declare function readClaudeConfig(): any;
|
|
13
|
+
/**
|
|
14
|
+
* Write Claude Desktop config
|
|
15
|
+
*/
|
|
16
|
+
export declare function writeClaudeConfig(config: any): void;
|
|
17
|
+
/**
|
|
18
|
+
* Add or update DoxHub MCP server in Claude config
|
|
19
|
+
*/
|
|
20
|
+
export declare function updateClaudeConfigForDoxHub(profileName?: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Remove DoxHub MCP server from Claude config
|
|
23
|
+
*/
|
|
24
|
+
export declare function removeFromClaudeConfig(profileName?: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Check if DoxHub is configured in Claude Desktop
|
|
27
|
+
*/
|
|
28
|
+
export declare function isDoxHubConfigured(profileName?: string): boolean;
|
|
29
|
+
//# sourceMappingURL=config-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAcnD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,GAAG,CAgBtC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAgBnD;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,GAAE,MAAkB,GAAG,IAAI,CAwBjF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,GAAE,MAAkB,GAAG,IAAI,CAW5E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,GAAE,MAAkB,GAAG,OAAO,CAQ3E"}
|