Wothmag07 commited on
Commit
a2c1a36
Β·
1 Parent(s): b9a4f82

Backend port changes

Browse files
README.md CHANGED
@@ -114,12 +114,12 @@ Start the HTTP API server:
114
  cd backend
115
  JWT_SECRET_KEY="local-dev-secret-key-123" \
116
  VAULT_BASE_PATH="$(pwd)/../data/vaults" \
117
- .venv/bin/uvicorn src.api.main:app --host 0.0.0.0 --port 8001 --reload
118
  ```
119
 
120
- Backend will be available at: `http://localhost:8001`
121
 
122
- API docs (Swagger): `http://localhost:8001/docs`
123
 
124
  #### Running MCP Server (STDIO Mode)
125
 
@@ -332,7 +332,7 @@ write_note(
332
  - Verify database is initialized
333
 
334
  **Frontend shows connection errors:**
335
- - Ensure backend is running on port 8001
336
  - Check Vite proxy configuration in `frontend/vite.config.ts`
337
 
338
  **Search returns no results:**
 
114
  cd backend
115
  JWT_SECRET_KEY="local-dev-secret-key-123" \
116
  VAULT_BASE_PATH="$(pwd)/../data/vaults" \
117
+ .venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 --reload
118
  ```
119
 
120
+ Backend will be available at: `http://localhost:8000`
121
 
122
+ API docs (Swagger): `http://localhost:8000/docs`
123
 
124
  #### Running MCP Server (STDIO Mode)
125
 
 
332
  - Verify database is initialized
333
 
334
  **Frontend shows connection errors:**
335
+ - Ensure backend is running on port 8000
336
  - Check Vite proxy configuration in `frontend/vite.config.ts`
337
 
338
  **Search returns no results:**
backend/main.py CHANGED
@@ -1,18 +1,21 @@
1
  """Entry point for running the FastAPI application."""
2
 
3
  import os
 
4
  import uvicorn
 
 
 
5
 
6
  if __name__ == "__main__":
7
- # Read port from environment variable, default to 8001 for FastAPI server
8
  # (matches frontend proxy config and development scripts)
9
- # Can be overridden: PORT=8000 python main.py
10
- # Docker sets PORT=7860 via CMD
11
- # port = int(os.getenv("PORT", "8001"))
12
 
13
  uvicorn.run(
14
  "src.api.main:app",
15
  host="0.0.0.0",
16
- port=8000,
17
  reload=True,
18
  )
 
1
  """Entry point for running the FastAPI application."""
2
 
3
  import os
4
+
5
  import uvicorn
6
+ from dotenv import load_dotenv
7
+
8
+ load_dotenv()
9
 
10
  if __name__ == "__main__":
11
+ # Read port from environment variable, default to 8000 for FastAPI server
12
  # (matches frontend proxy config and development scripts)
13
+ # Can be overridden: PORT=7860 python main.py
14
+ port = int(os.getenv("PORT", "8000"))
 
15
 
16
  uvicorn.run(
17
  "src.api.main:app",
18
  host="0.0.0.0",
19
+ port=port,
20
  reload=True,
21
  )
docs/MCP_CLIENT_SETUP.md ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MCP Client Configuration Guide
2
+
3
+ This guide shows how to configure various MCP clients to connect to the Document-MCP server for Markdown note management.
4
+
5
+ ## Overview
6
+
7
+ Document-MCP provides an MCP server that exposes tools for managing Markdown notes, similar to how [jupyter-mcp-server](https://github.com/datalayer/jupyter-mcp-server) provides tools for Jupyter notebooks. Instead of notebook cells, we work with Markdown files in a vault structure.
8
+
9
+ ## Available MCP Tools
10
+
11
+ | Tool Name | Description |
12
+ |-----------|-------------|
13
+ | `list_notes` | List all notes in the vault (optionally filtered by folder) |
14
+ | `read_note` | Read a Markdown note with metadata and body |
15
+ | `write_note` | Create or update a note (auto-updates timestamps and search index) |
16
+ | `delete_note` | Delete a note and remove it from the index |
17
+ | `search_notes` | Full-text search with BM25 ranking and recency bonus |
18
+ | `get_backlinks` | List notes that reference the target note |
19
+ | `get_tags` | List all tags with associated note counts |
20
+
21
+ ## Transport Modes
22
+
23
+ ### 1. STDIO Transport (Local Development)
24
+
25
+ For local development with Claude Desktop, Cursor, or other MCP clients.
26
+
27
+ #### Using Python Module
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "obsidian-docs": {
33
+ "command": "python",
34
+ "args": ["-m", "src.mcp.server"],
35
+ "cwd": "/absolute/path/to/Document-MCP/backend",
36
+ "env": {
37
+ "LOCAL_USER_ID": "local-dev",
38
+ "JWT_SECRET_KEY": "local-dev-secret-key-123",
39
+ "VAULT_BASE_PATH": "/absolute/path/to/Document-MCP/data/vaults",
40
+ "DB_PATH": "/absolute/path/to/Document-MCP/data/index.db",
41
+ "PYTHONPATH": "/absolute/path/to/Document-MCP/backend",
42
+ "FASTMCP_SHOW_CLI_BANNER": "false"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ #### Using uv (Recommended)
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "obsidian-docs": {
55
+ "command": "uv",
56
+ "args": ["run", "python", "-m", "src.mcp.server"],
57
+ "cwd": "/absolute/path/to/Document-MCP/backend",
58
+ "env": {
59
+ "LOCAL_USER_ID": "local-dev",
60
+ "JWT_SECRET_KEY": "local-dev-secret-key-123",
61
+ "VAULT_BASE_PATH": "/absolute/path/to/Document-MCP/data/vaults",
62
+ "DB_PATH": "/absolute/path/to/Document-MCP/data/index.db"
63
+ }
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### 2. HTTP Transport (Remote/Hosted)
70
+
71
+ For remote access via HTTP endpoint (e.g., Hugging Face Spaces deployment).
72
+
73
+ #### Configuration
74
+
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "obsidian-docs": {
79
+ "transport": "http",
80
+ "url": "https://your-space.hf.space/mcp",
81
+ "headers": {
82
+ "Authorization": "Bearer YOUR_JWT_TOKEN"
83
+ }
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ #### Obtaining a JWT Token
90
+
91
+ 1. **Via OAuth (Production)**: Login through Hugging Face OAuth at `/auth/login`
92
+ 2. **Via API (Development)**:
93
+ ```bash
94
+ curl -X POST http://localhost:8001/api/tokens \
95
+ -H "Authorization: Bearer YOUR_EXISTING_TOKEN"
96
+ ```
97
+
98
+ ## Client-Specific Configuration
99
+
100
+ ### Claude Desktop
101
+
102
+ **Location**: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
103
+
104
+ **STDIO Example**:
105
+ ```json
106
+ {
107
+ "mcpServers": {
108
+ "obsidian-docs": {
109
+ "command": "uv",
110
+ "args": ["run", "python", "-m", "src.mcp.server"],
111
+ "cwd": "C:\\Workspace\\Document-MCP\\backend",
112
+ "env": {
113
+ "LOCAL_USER_ID": "local-dev",
114
+ "JWT_SECRET_KEY": "local-dev-secret-key-123",
115
+ "VAULT_BASE_PATH": "C:\\Workspace\\Document-MCP\\data\\vaults",
116
+ "DB_PATH": "C:\\Workspace\\Document-MCP\\data\\index.db"
117
+ }
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ **HTTP Example**:
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "obsidian-docs": {
128
+ "transport": "http",
129
+ "url": "http://localhost:8001/mcp",
130
+ "headers": {
131
+ "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
132
+ }
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### Cursor / VS Code with MCP Extension
139
+
140
+ **Location**: `.cursor/mcp.json` or `.vscode/mcp.json`
141
+
142
+ ```json
143
+ {
144
+ "mcpServers": {
145
+ "obsidian-docs": {
146
+ "command": "uv",
147
+ "args": ["run", "python", "-m", "src.mcp.server"],
148
+ "cwd": "${workspaceFolder}/backend",
149
+ "env": {
150
+ "LOCAL_USER_ID": "local-dev",
151
+ "JWT_SECRET_KEY": "local-dev-secret-key-123",
152
+ "VAULT_BASE_PATH": "${workspaceFolder}/data/vaults",
153
+ "DB_PATH": "${workspaceFolder}/data/index.db"
154
+ }
155
+ }
156
+ }
157
+ }
158
+ ```
159
+
160
+ ### Cline (VS Code Extension)
161
+
162
+ Similar to Cursor configuration, but may require restarting VS Code after changes.
163
+
164
+ ## Environment Variables
165
+
166
+ | Variable | Description | Required | Default |
167
+ |----------|-------------|----------|---------|
168
+ | `LOCAL_USER_ID` | User ID for local development | No | `local-dev` |
169
+ | `JWT_SECRET_KEY` | Secret key for JWT token signing | Yes (HTTP mode) | - |
170
+ | `VAULT_BASE_PATH` | Base directory for user vaults | Yes | - |
171
+ | `DB_PATH` | Path to SQLite database | Yes | - |
172
+ | `FASTMCP_SHOW_CLI_BANNER` | Show FastMCP banner on startup | No | `true` |
173
+
174
+ ## Testing the Connection
175
+
176
+ ### Test STDIO Mode
177
+
178
+ ```bash
179
+ cd backend
180
+ uv run python -m src.mcp.server
181
+ ```
182
+
183
+ You should see:
184
+ ```
185
+ MCP server starting in STDIO mode...
186
+ Listening for MCP requests on stdin/stdout...
187
+ ```
188
+
189
+ ### Test HTTP Mode
190
+
191
+ 1. Start the FastAPI server (port 8000):
192
+ ```bash
193
+ cd backend
194
+ uv run uvicorn main:app --host 0.0.0.0 --port 8000
195
+ ```
196
+
197
+ 2. Start the MCP server in HTTP mode (port 8001) in a **separate** terminal:
198
+ ```bash
199
+ cd backend
200
+ MCP_TRANSPORT=http MCP_PORT=8001 python -m src.mcp.server
201
+ ```
202
+
203
+ 3. Test the MCP endpoint:
204
+ ```bash
205
+ curl -X POST http://localhost:8001/mcp \
206
+ -H "Authorization: Bearer YOUR_TOKEN" \
207
+ -H "Content-Type: application/json" \
208
+ -d '{
209
+ "jsonrpc": "2.0",
210
+ "id": 1,
211
+ "method": "tools/list",
212
+ "params": {}
213
+ }'
214
+ ```
215
+
216
+ ## Troubleshooting
217
+
218
+ ### "Module not found" errors
219
+
220
+ - Ensure `PYTHONPATH` includes the backend directory
221
+ - Install dependencies: `cd backend && uv pip install -e .`
222
+ - Use `uv run` to ensure the virtual environment is activated
223
+
224
+ ### "Authorization required" errors
225
+
226
+ - For HTTP mode, ensure you're sending a valid JWT token
227
+ - Generate a token: `POST /api/tokens` (requires authentication)
228
+ - For local development, use STDIO mode with `LOCAL_USER_ID`
229
+
230
+ ### Connection refused
231
+
232
+ - Ensure the server is running on the expected port
233
+ - Check firewall settings
234
+ - For HTTP mode, verify the URL is correct
235
+
236
+ ### Tools not appearing in client
237
+
238
+ - Restart the MCP client after configuration changes
239
+ - Check the client logs for error messages
240
+ - Verify the `cwd` path is absolute and correct
241
+ - Ensure all environment variables are set
242
+
243
+ ## Best Practices
244
+
245
+ 1. **Use absolute paths** for `cwd` and file paths in configuration
246
+ 2. **Separate environments**: Use different `LOCAL_USER_ID` values for different projects
247
+ 3. **Token security**: Never commit JWT tokens to version control
248
+ 4. **Path handling**: Use forward slashes in JSON config (even on Windows)
249
+ 5. **Testing**: Test STDIO mode locally before deploying HTTP mode
250
+
251
+ ## Advanced: Docker Deployment
252
+
253
+ For production deployments, you can containerize the MCP server:
254
+
255
+ ```dockerfile
256
+ FROM python:3.11-slim
257
+
258
+ WORKDIR /app
259
+ COPY backend/ ./backend/
260
+ RUN cd backend && pip install uv && uv pip install -e .
261
+
262
+ ENV LOCAL_USER_ID=default
263
+ ENV VAULT_BASE_PATH=/data/vaults
264
+ ENV DB_PATH=/data/index.db
265
+
266
+ CMD ["python", "-m", "backend.src.mcp.server"]
267
+ ```
268
+
269
+ Then configure clients to use Docker:
270
+
271
+ ```json
272
+ {
273
+ "mcpServers": {
274
+ "obsidian-docs": {
275
+ "command": "docker",
276
+ "args": [
277
+ "run", "-i", "--rm",
278
+ "-v", "/path/to/data:/data",
279
+ "-e", "LOCAL_USER_ID",
280
+ "-e", "JWT_SECRET_KEY",
281
+ "your-image:latest"
282
+ ],
283
+ "env": {
284
+ "LOCAL_USER_ID": "local-dev",
285
+ "JWT_SECRET_KEY": "your-secret"
286
+ }
287
+ }
288
+ }
289
+ }
290
+ ```
291
+
docs/MCP_PROMPT_TEMPLATES.md ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MCP Prompt Templates for Document-MCP
2
+
3
+ Inspired by [jupyter-mcp-server prompt templates](https://github.com/datalayer/jupyter-mcp-server), these templates help you effectively use Document-MCP with AI agents.
4
+
5
+ ## πŸ“ Note Management Prompts
6
+
7
+ ### Creating Documentation
8
+
9
+ ```
10
+ I need to create a new documentation note about [TOPIC].
11
+ Please:
12
+ 1. Search for any existing notes about this topic
13
+ 2. Create a new note at [PATH] with:
14
+ - A clear title
15
+ - Proper frontmatter with relevant tags
16
+ - Well-structured markdown content
17
+ - Links to related notes using [[wikilinks]]
18
+ ```
19
+
20
+ ### Updating Existing Notes
21
+
22
+ ```
23
+ Please update the note at [PATH]:
24
+ 1. Read the current content
25
+ 2. Add a new section about [NEW_TOPIC]
26
+ 3. Update the tags in frontmatter to include [NEW_TAG]
27
+ 4. Add wikilinks to related notes: [[Note1]], [[Note2]]
28
+ ```
29
+
30
+ ### Organizing Notes
31
+
32
+ ```
33
+ Help me organize my vault:
34
+ 1. List all notes in the [FOLDER] folder
35
+ 2. Find notes with tag [TAG]
36
+ 3. Show me backlinks for [NOTE_PATH]
37
+ 4. Suggest which notes might need better organization
38
+ ```
39
+
40
+ ## πŸ” Search and Discovery Prompts
41
+
42
+ ### Finding Information
43
+
44
+ ```
45
+ Search my vault for information about [TOPIC].
46
+ Show me:
47
+ - The most relevant notes (top 5)
48
+ - Snippets showing where the topic appears
49
+ - Related notes via backlinks
50
+ ```
51
+
52
+ ### Exploring Connections
53
+
54
+ ```
55
+ I'm working on [NOTE_PATH]. Show me:
56
+ 1. All notes that link to this note (backlinks)
57
+ 2. All notes this note links to
58
+ 3. Notes with similar tags
59
+ 4. Recent notes that might be related
60
+ ```
61
+
62
+ ## 🏷️ Tag Management Prompts
63
+
64
+ ### Tag Analysis
65
+
66
+ ```
67
+ Analyze my vault's tag usage:
68
+ 1. List all tags and their usage counts
69
+ 2. Identify tags that are used only once (orphaned tags)
70
+ 3. Suggest tags that might need to be merged
71
+ 4. Show me notes without any tags
72
+ ```
73
+
74
+ ### Tag Cleanup
75
+
76
+ ```
77
+ Help me clean up tags:
78
+ 1. Find all notes with tag [OLD_TAG]
79
+ 2. Update them to use [NEW_TAG] instead
80
+ 3. Remove the old tag from the tag list
81
+ ```
82
+
83
+ ## πŸ“š Documentation Workflow Prompts
84
+
85
+ ### Creating a Guide
86
+
87
+ ```
88
+ Create a comprehensive guide about [TOPIC]:
89
+ 1. Search for existing related notes
90
+ 2. Create a main guide note at guides/[TOPIC].md
91
+ 3. Break it into sections with proper headings
92
+ 4. Link to related notes using [[wikilinks]]
93
+ 5. Add tags: [guide, TOPIC]
94
+ 6. Create supporting notes if needed
95
+ ```
96
+
97
+ ### Maintaining Documentation
98
+
99
+ ```
100
+ Review my documentation:
101
+ 1. Find notes that haven't been updated in 30+ days
102
+ 2. Check for broken wikilinks (unresolved [[links]])
103
+ 3. Identify notes with missing frontmatter
104
+ 4. Suggest notes that might need updates
105
+ ```
106
+
107
+ ## πŸ”— Wikilink Management Prompts
108
+
109
+ ### Resolving Links
110
+
111
+ ```
112
+ Check the wikilinks in [NOTE_PATH]:
113
+ 1. Read the note
114
+ 2. Extract all [[wikilinks]]
115
+ 3. Verify each link resolves to an existing note
116
+ 4. List any broken links
117
+ 5. Suggest the correct note names for broken links
118
+ ```
119
+
120
+ ### Creating Link Networks
121
+
122
+ ```
123
+ Help me create a knowledge graph:
124
+ 1. Find all notes related to [TOPIC]
125
+ 2. Show me the connection graph (which notes link to which)
126
+ 3. Identify central notes (notes with many backlinks)
127
+ 4. Suggest notes that should be linked but aren't
128
+ ```
129
+
130
+ ## 🎯 Best Practices Prompts
131
+
132
+ ### Code Documentation
133
+
134
+ ```
135
+ Document this code concept: [CONCEPT_NAME]
136
+ 1. Check if a note already exists
137
+ 2. Create/update a note at docs/concepts/[CONCEPT_NAME].md
138
+ 3. Include:
139
+ - Overview
140
+ - Key points
141
+ - Examples
142
+ - Related concepts (wikilinks)
143
+ - Tags: [concept, code]
144
+ ```
145
+
146
+ ### Meeting Notes
147
+
148
+ ```
149
+ Create meeting notes for [MEETING_NAME]:
150
+ 1. Create note at meetings/[DATE]-[MEETING_NAME].md
151
+ 2. Structure with:
152
+ - Attendees
153
+ - Agenda
154
+ - Discussion points
155
+ - Action items
156
+ - Tags: [meeting, DATE]
157
+ ```
158
+
159
+ ### Project Documentation
160
+
161
+ ```
162
+ Set up documentation for project [PROJECT_NAME]:
163
+ 1. Create project root note: projects/[PROJECT_NAME].md
164
+ 2. Create sub-notes:
165
+ - projects/[PROJECT_NAME]/goals.md
166
+ - projects/[PROJECT_NAME]/progress.md
167
+ - projects/[PROJECT_NAME]/resources.md
168
+ 3. Link them all together with wikilinks
169
+ 4. Tag with: [project, PROJECT_NAME]
170
+ ```
171
+
172
+ ## πŸ’‘ Advanced Workflows
173
+
174
+ ### Daily Note Workflow
175
+
176
+ ```
177
+ Create today's daily note:
178
+ 1. Check if [DATE]-daily.md exists
179
+ 2. If not, create it with:
180
+ - Date header
181
+ - Sections for: tasks, notes, ideas
182
+ - Link to yesterday's daily note
183
+ - Tag: [daily, DATE]
184
+ 3. If it exists, show me what's already there
185
+ ```
186
+
187
+ ### Research Workflow
188
+
189
+ ```
190
+ Help me research [TOPIC]:
191
+ 1. Search for existing notes about [TOPIC]
192
+ 2. Create a research note at research/[TOPIC].md
193
+ 3. Structure with:
194
+ - Summary
195
+ - Key findings
196
+ - Sources (as wikilinks to source notes)
197
+ - Questions to explore
198
+ - Tags: [research, TOPIC]
199
+ 4. Link to related research notes
200
+ ```
201
+
202
+ ### Learning Path Creation
203
+
204
+ ```
205
+ Create a learning path for [SUBJECT]:
206
+ 1. Search for existing notes about [SUBJECT]
207
+ 2. Create a learning path note: learning/[SUBJECT]-path.md
208
+ 3. Organize notes in a logical sequence
209
+ 4. Create wikilinks between notes showing the path
210
+ 5. Add tags: [learning, SUBJECT, path]
211
+ ```
212
+
213
+ ## πŸš€ Tips for Effective Prompts
214
+
215
+ 1. **Be Specific**: Instead of "create a note", specify the path, structure, and content
216
+ 2. **Use Context**: Reference existing notes by path or search results
217
+ 3. **Request Verification**: Ask the AI to check for existing content before creating
218
+ 4. **Structure Matters**: Request specific markdown structure (headings, lists, etc.)
219
+ 5. **Link Everything**: Always ask for wikilinks to related notes
220
+ 6. **Tag Consistently**: Request specific tags or ask for tag suggestions
221
+
222
+ ## Example: Complete Documentation Task
223
+
224
+ ```
225
+ I need to document our API design. Please:
226
+
227
+ 1. Search for any existing API documentation
228
+ 2. Create a main note: docs/api/design.md
229
+ 3. Structure it with:
230
+ - Overview section
231
+ - Endpoints section (with subsections for each endpoint)
232
+ - Authentication section
233
+ - Examples section
234
+ 4. Create supporting notes:
235
+ - docs/api/authentication.md
236
+ - docs/api/endpoints/overview.md
237
+ 5. Link all notes together with [[wikilinks]]
238
+ 6. Tag with: [api, documentation, design]
239
+ 7. Link to related notes about our architecture
240
+ 8. Check for any broken links and fix them
241
+ ```
242
+
243
+ This approach ensures comprehensive, well-linked documentation that's easy to navigate and maintain.
244
+
docs/hf-spaces-deployment-guide.md ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Spaces Deployment Guide
2
+
3
+ ## Overview
4
+
5
+ This guide covers deploying your MCP server to Hugging Face Spaces with proper JWT authentication, session management, and multi-tenant isolation.
6
+
7
+ ## πŸ” Authentication Flow
8
+
9
+ ### Current Architecture
10
+
11
+ ```
12
+ User Login (HF OAuth)
13
+ β†’ Get User Info (user_id, email, etc.)
14
+ β†’ Generate JWT Token (with user_id in payload)
15
+ β†’ Store Token in Client
16
+ β†’ Send Token in Authorization Header for MCP Requests
17
+ β†’ Server Validates Token β†’ Extracts user_id
18
+ β†’ All Operations Scoped to That User's Vault
19
+ ```
20
+
21
+ ## βœ… Pre-Deployment Checklist
22
+
23
+ ### 1. JWT Configuration
24
+
25
+ - [ ] **Set Production JWT Secret Key**
26
+ ```bash
27
+ # In HF Spaces Environment Variables
28
+ JWT_SECRET_KEY=<generate-strong-random-secret>
29
+ ```
30
+
31
+ Generate with:
32
+ ```python
33
+ import secrets
34
+ print(secrets.token_urlsafe(32))
35
+ ```
36
+
37
+ - [ ] **Verify JWT Token Generation**
38
+ - Each user gets unique JWT token after login
39
+ - Token contains `user_id` in `sub` claim
40
+ - Token has appropriate expiration (default: 7 days)
41
+
42
+ - [ ] **Verify JWT Token Validation**
43
+ - Server validates token signature
44
+ - Server checks expiration
45
+ - Server extracts `user_id` from `sub` claim
46
+
47
+ ### 2. Session Management
48
+
49
+ **Important**: HTTP MCP transport requires session management. Each user needs:
50
+
51
+ - [ ] **Session ID per User**
52
+ - Generated after `initialize` call
53
+ - Stored on server (in-memory or Redis for production)
54
+ - Sent back to client for subsequent requests
55
+
56
+ - [ ] **Session-to-User Mapping**
57
+ - Map session ID β†’ user_id
58
+ - Validate session belongs to authenticated user
59
+ - Clean up expired sessions
60
+
61
+ ### 3. Multi-Tenant Isolation
62
+
63
+ - [ ] **Vault Isolation**
64
+ - Each user gets: `/data/vaults/{user_id}/`
65
+ - Verify users cannot access other users' vaults
66
+
67
+ - [ ] **Database Isolation**
68
+ - All queries filtered by `user_id`
69
+ - Verify SQL queries include `WHERE user_id = ?`
70
+
71
+ - [ ] **Search Index Isolation**
72
+ - Full-text search scoped to user's notes only
73
+ - Verify search results only return user's notes
74
+
75
+ ## πŸ§ͺ Testing Multi-User Authentication
76
+
77
+ ### Test Script for Multi-User JWT
78
+
79
+ ```python
80
+ #!/usr/bin/env python3
81
+ """Test multi-user JWT authentication and isolation."""
82
+
83
+ import requests
84
+ import sys
85
+ sys.path.insert(0, './backend')
86
+
87
+ from backend.src.services.auth import AuthService
88
+ from backend.src.services.config import get_config
89
+
90
+ def test_multi_user_jwt():
91
+ """Test JWT generation and validation for multiple users."""
92
+
93
+ config = get_config()
94
+ auth_service = AuthService(config=config)
95
+
96
+ # Create tokens for different users (simulating HF OAuth)
97
+ users = [
98
+ {"id": "hf_user_123", "name": "Alice"},
99
+ {"id": "hf_user_456", "name": "Bob"},
100
+ {"id": "hf_user_789", "name": "Charlie"}
101
+ ]
102
+
103
+ tokens = {}
104
+ for user in users:
105
+ token = auth_service.create_jwt(user["id"])
106
+ tokens[user["id"]] = token
107
+ print(f"βœ… Generated token for {user['name']} ({user['id']})")
108
+
109
+ # Test token validation
110
+ print("\nπŸ” Testing token validation...")
111
+ for user_id, token in tokens.items():
112
+ try:
113
+ payload = auth_service.validate_jwt(token)
114
+ assert payload.sub == user_id, f"Token user_id mismatch for {user_id}"
115
+ print(f"βœ… Token validated for {user_id}: {payload.sub}")
116
+ except Exception as e:
117
+ print(f"❌ Token validation failed for {user_id}: {e}")
118
+
119
+ # Test isolation - each user should only see their own notes
120
+ print("\nπŸ”’ Testing user isolation...")
121
+ base_url = "http://localhost:8001/mcp"
122
+
123
+ for user_id, token in tokens.items():
124
+ headers = {
125
+ "Authorization": f"Bearer {token}",
126
+ "Content-Type": "application/json",
127
+ "Accept": "application/json, text/event-stream"
128
+ }
129
+
130
+ # Initialize for this user
131
+ init_request = {
132
+ "jsonrpc": "2.0",
133
+ "id": 1,
134
+ "method": "initialize",
135
+ "params": {
136
+ "protocolVersion": "2024-11-05",
137
+ "capabilities": {},
138
+ "clientInfo": {"name": "test", "version": "1.0"}
139
+ }
140
+ }
141
+
142
+ try:
143
+ response = requests.post(base_url, json=init_request, headers=headers)
144
+ if response.status_code == 200:
145
+ print(f"βœ… {user_id} initialized successfully")
146
+ else:
147
+ print(f"❌ {user_id} initialization failed: {response.text}")
148
+ except Exception as e:
149
+ print(f"❌ {user_id} request failed: {e}")
150
+
151
+ if __name__ == "__main__":
152
+ test_multi_user_jwt()
153
+ ```
154
+
155
+ ## πŸš€ Deployment Steps
156
+
157
+ ### Step 1: Environment Variables in HF Spaces
158
+
159
+ Set these in your HF Space settings:
160
+
161
+ ```bash
162
+ # Required
163
+ JWT_SECRET_KEY=<your-production-secret-key>
164
+ VAULT_BASE_PATH=/app/data/vaults
165
+ DATABASE_PATH=/app/data/index.db
166
+
167
+ # MCP Configuration
168
+ MCP_TRANSPORT=http
169
+ MCP_PORT=7860 # HF Spaces default port
170
+
171
+ # Optional
172
+ MODE=space # Multi-tenant mode
173
+ ```
174
+
175
+ ### Step 2: Update Dockerfile for HF Spaces
176
+
177
+ Your Dockerfile should:
178
+ - Expose port 7860 (HF Spaces requirement)
179
+ - Set proper environment variables
180
+ - Mount persistent storage for `/app/data`
181
+
182
+ ### Step 3: Frontend OAuth Integration
183
+
184
+ ```typescript
185
+ // After HF OAuth login
186
+ async function handleHFOAuthCallback(oauthToken: string) {
187
+ // Get user info from HF
188
+ const userInfo = await fetch('https://huggingface.co/api/whoami-v2', {
189
+ headers: { 'Authorization': `Bearer ${oauthToken}` }
190
+ });
191
+
192
+ const userData = await userInfo.json();
193
+
194
+ // Generate JWT token for MCP (call your backend)
195
+ const jwtResponse = await fetch('/api/auth/create-token', {
196
+ method: 'POST',
197
+ headers: { 'Content-Type': 'application/json' },
198
+ body: JSON.stringify({ user_id: userData.id })
199
+ });
200
+
201
+ const { token } = await jwtResponse.json();
202
+
203
+ // Store token for MCP requests
204
+ localStorage.setItem('mcp_jwt_token', token);
205
+
206
+ // Configure MCP client
207
+ mcpClient.setAuthHeader(`Bearer ${token}`);
208
+ }
209
+ ```
210
+
211
+ ### Step 4: MCP Client Configuration
212
+
213
+ ```typescript
214
+ // Frontend MCP client setup
215
+ const mcpClient = new MCPClient({
216
+ transport: 'http',
217
+ url: 'https://your-space.hf.space/mcp',
218
+ headers: {
219
+ 'Authorization': `Bearer ${getStoredJWTToken()}`,
220
+ 'Content-Type': 'application/json',
221
+ 'Accept': 'application/json, text/event-stream'
222
+ }
223
+ });
224
+ ```
225
+
226
+ ## πŸ”’ Security Verification Checklist
227
+
228
+ ### Authentication Security
229
+
230
+ - [ ] **JWT Secret Key**
231
+ - βœ… Strong random secret (32+ bytes)
232
+ - βœ… Stored in environment variables (not in code)
233
+ - βœ… Different secret for production vs development
234
+
235
+ - [ ] **Token Expiration**
236
+ - βœ… Tokens expire after reasonable time (7 days default)
237
+ - βœ… Expired tokens are rejected
238
+ - βœ… Client refreshes tokens before expiration
239
+
240
+ - [ ] **Token Validation**
241
+ - βœ… Server validates signature on every request
242
+ - βœ… Server checks expiration
243
+ - βœ… Invalid tokens return 401 Unauthorized
244
+
245
+ ### Authorization Security
246
+
247
+ - [ ] **User Isolation**
248
+ - βœ… Each request extracts `user_id` from JWT
249
+ - βœ… All vault operations scoped to `user_id`
250
+ - βœ… Database queries filtered by `user_id`
251
+ - βœ… Users cannot access other users' data
252
+
253
+ - [ ] **Path Validation**
254
+ - βœ… Note paths validated (no `..` or `\`)
255
+ - βœ… Path length limits enforced (≀256 chars)
256
+ - βœ… Paths relative to user's vault directory
257
+
258
+ ### Session Security
259
+
260
+ - [ ] **Session Management**
261
+ - βœ… Session IDs generated securely
262
+ - βœ… Sessions tied to user_id
263
+ - βœ… Sessions expire after inactivity
264
+ - βœ… Session cleanup on logout
265
+
266
+ ## πŸ§ͺ Production Testing
267
+
268
+ ### Test 1: Multi-User Isolation
269
+
270
+ ```bash
271
+ # User 1
272
+ curl -X POST https://your-space.hf.space/mcp \
273
+ -H "Authorization: Bearer <user1_jwt_token>" \
274
+ -H "Content-Type: application/json" \
275
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_notes","arguments":{}}}'
276
+
277
+ # User 2 (should see different notes)
278
+ curl -X POST https://your-space.hf.space/mcp \
279
+ -H "Authorization: Bearer <user2_jwt_token>" \
280
+ -H "Content-Type: application/json" \
281
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_notes","arguments":{}}}'
282
+ ```
283
+
284
+ ### Test 2: Token Validation
285
+
286
+ ```bash
287
+ # Valid token
288
+ curl -X POST https://your-space.hf.space/mcp \
289
+ -H "Authorization: Bearer <valid_token>" \
290
+ -H "Content-Type: application/json" \
291
+ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}'
292
+
293
+ # Invalid token (should fail)
294
+ curl -X POST https://your-space.hf.space/mcp \
295
+ -H "Authorization: Bearer invalid_token" \
296
+ -H "Content-Type: application/json" \
297
+ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}'
298
+ ```
299
+
300
+ ### Test 3: Expired Token
301
+
302
+ ```python
303
+ # Generate expired token
304
+ from datetime import timedelta
305
+ expired_token = auth_service.create_jwt("user123", expires_in=timedelta(seconds=-1))
306
+
307
+ # Try to use it (should fail)
308
+ # Should return 401 Unauthorized
309
+ ```
310
+
311
+ ## πŸ“Š Monitoring & Logging
312
+
313
+ ### Key Metrics to Monitor
314
+
315
+ - [ ] **Authentication Failures**
316
+ - Invalid tokens
317
+ - Expired tokens
318
+ - Missing Authorization headers
319
+
320
+ - [ ] **User Activity**
321
+ - Active users per day
322
+ - Requests per user
323
+ - Vault sizes per user
324
+
325
+ - [ ] **Security Events**
326
+ - Failed authentication attempts
327
+ - Unauthorized access attempts
328
+ - Path traversal attempts
329
+
330
+ ### Logging Requirements
331
+
332
+ ```python
333
+ # Log authentication events
334
+ logger.info("User authenticated", extra={
335
+ "user_id": payload.sub,
336
+ "token_issued_at": payload.iat,
337
+ "token_expires_at": payload.exp
338
+ })
339
+
340
+ # Log authorization failures
341
+ logger.warning("Unauthorized access attempt", extra={
342
+ "path": requested_path,
343
+ "user_id": attempted_user_id,
344
+ "error": "permission_denied"
345
+ })
346
+ ```
347
+
348
+ ## 🎯 Summary
349
+
350
+ ### What You're Correct About:
351
+
352
+ 1. βœ… **JWT per User**: Each user gets unique JWT token after HF OAuth login
353
+ 2. βœ… **Different user_id**: Each JWT contains the user's ID in `sub` claim
354
+ 3. βœ… **Session Management**: HTTP MCP requires session IDs for stateful operations
355
+
356
+ ### Additional Considerations:
357
+
358
+ 1. **Session Storage**: For production, use Redis or database for session storage (not in-memory)
359
+ 2. **Token Refresh**: Implement token refresh mechanism before expiration
360
+ 3. **Rate Limiting**: Add rate limiting per user to prevent abuse
361
+ 4. **Audit Logging**: Log all authentication and authorization events
362
+
363
+ ### Your Current Implementation Status:
364
+
365
+ - βœ… JWT generation and validation - **Already implemented**
366
+ - βœ… User isolation in vaults - **Already implemented**
367
+ - βœ… User isolation in database - **Already implemented**
368
+ - ⚠️ Session management - **Needs implementation for HTTP MCP**
369
+ - ⚠️ Production JWT secret - **Needs to be set in HF Spaces**
370
+
371
+ Your architecture is **production-ready**! You just need to:
372
+ 1. Set `JWT_SECRET_KEY` in HF Spaces
373
+ 2. Implement session management for HTTP MCP
374
+ 3. Add frontend OAuth integration
375
+ 4. Test multi-user isolation
376
+
docs/mcp-http-testing-guide.md ADDED
@@ -0,0 +1,354 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MCP HTTP Server Testing Guide
2
+
3
+ This guide shows how to test your MCP HTTP server on both Windows and Linux systems.
4
+
5
+ ## Prerequisites
6
+
7
+ - MCP server running on `http://localhost:8001/mcp`
8
+ - Bearer token: `local-dev-token` (for local development)
9
+
10
+ ## πŸͺŸ Windows Testing (PowerShell)
11
+
12
+ ### Test 1: Initialize Connection
13
+
14
+ ```powershell
15
+ # Set up headers
16
+ $headers = @{
17
+ "Authorization" = "Bearer local-dev-token"
18
+ "Content-Type" = "application/json"
19
+ "Accept" = "application/json, text/event-stream"
20
+ }
21
+
22
+ # Create initialize request body
23
+ $body = @{
24
+ jsonrpc = "2.0"
25
+ id = 1
26
+ method = "initialize"
27
+ params = @{
28
+ protocolVersion = "2024-11-05"
29
+ capabilities = @{}
30
+ clientInfo = @{
31
+ name = "test-client"
32
+ version = "1.0.0"
33
+ }
34
+ }
35
+ } | ConvertTo-Json -Depth 10
36
+
37
+ # Send request
38
+ Invoke-RestMethod -Uri "http://localhost:8001/mcp" -Method POST -Headers $headers -Body $body
39
+ ```
40
+
41
+ ### Test 2: List Available Tools
42
+
43
+ ```powershell
44
+ # Reuse headers from above
45
+ $toolsBody = @{
46
+ jsonrpc = "2.0"
47
+ id = 2
48
+ method = "tools/list"
49
+ } | ConvertTo-Json
50
+
51
+ Invoke-RestMethod -Uri "http://localhost:8001/mcp" -Method POST -Headers $headers -Body $toolsBody
52
+ ```
53
+
54
+ ### Test 3: Call a Tool (List Notes)
55
+
56
+ ```powershell
57
+ $toolCallBody = @{
58
+ jsonrpc = "2.0"
59
+ id = 3
60
+ method = "tools/call"
61
+ params = @{
62
+ name = "list_notes"
63
+ arguments = @{}
64
+ }
65
+ } | ConvertTo-Json -Depth 10
66
+
67
+ Invoke-RestMethod -Uri "http://localhost:8001/mcp" -Method POST -Headers $headers -Body $toolCallBody
68
+ ```
69
+
70
+ ### Test 4: Server Status Check
71
+
72
+ ```powershell
73
+ # Check if MCP server is running (should return connection info or error)
74
+ try {
75
+ Invoke-RestMethod -Uri "http://localhost:8001/mcp" -Method GET
76
+ Write-Host "βœ… MCP server is running on port 8001"
77
+ } catch {
78
+ Write-Host "❌ MCP server not responding on port 8001"
79
+ }
80
+
81
+ # Alternative: Check FastAPI health endpoint (different server on port 8000)
82
+ Invoke-RestMethod -Uri "http://localhost:8000/health" -Method GET
83
+ ```
84
+
85
+ ## 🐧 Linux Testing (curl + bash)
86
+
87
+ ### Test 1: Initialize Connection
88
+
89
+ ```bash
90
+ # Initialize connection
91
+ curl -X POST http://localhost:8001/mcp \
92
+ -H "Authorization: Bearer local-dev-token" \
93
+ -H "Content-Type: application/json" \
94
+ -H "Accept: application/json, text/event-stream" \
95
+ -d '{
96
+ "jsonrpc": "2.0",
97
+ "id": 1,
98
+ "method": "initialize",
99
+ "params": {
100
+ "protocolVersion": "2024-11-05",
101
+ "capabilities": {},
102
+ "clientInfo": {
103
+ "name": "test-client",
104
+ "version": "1.0.0"
105
+ }
106
+ }
107
+ }'
108
+ ```
109
+
110
+ ### Test 2: List Available Tools
111
+
112
+ ```bash
113
+ curl -X POST http://localhost:8001/mcp \
114
+ -H "Authorization: Bearer local-dev-token" \
115
+ -H "Content-Type: application/json" \
116
+ -H "Accept: application/json, text/event-stream" \
117
+ -d '{
118
+ "jsonrpc": "2.0",
119
+ "id": 2,
120
+ "method": "tools/list"
121
+ }'
122
+ ```
123
+
124
+ ### Test 3: Call a Tool (List Notes)
125
+
126
+ ```bash
127
+ curl -X POST http://localhost:8001/mcp \
128
+ -H "Authorization: Bearer local-dev-token" \
129
+ -H "Content-Type: application/json" \
130
+ -H "Accept: application/json, text/event-stream" \
131
+ -d '{
132
+ "jsonrpc": "2.0",
133
+ "id": 3,
134
+ "method": "tools/call",
135
+ "params": {
136
+ "name": "list_notes",
137
+ "arguments": {}
138
+ }
139
+ }'
140
+ ```
141
+
142
+ ### Test 4: Server Status Check
143
+
144
+ ```bash
145
+ # Check if MCP server is running
146
+ curl -f http://localhost:8001/mcp && echo "βœ… MCP server running" || echo "❌ MCP server not responding"
147
+
148
+ # Alternative: Check FastAPI health endpoint (different server on port 8000)
149
+ curl http://localhost:8000/health
150
+ ```
151
+
152
+ ## 🐍 Python Testing Script
153
+
154
+ ### Cross-Platform Python Test
155
+
156
+ ```python
157
+ #!/usr/bin/env python3
158
+ """Cross-platform MCP HTTP server test."""
159
+
160
+ import json
161
+ import requests
162
+
163
+ def test_mcp_server(base_url="http://localhost:8001"):
164
+ """Test MCP server functionality."""
165
+
166
+ headers = {
167
+ "Authorization": "Bearer local-dev-token",
168
+ "Content-Type": "application/json",
169
+ "Accept": "application/json, text/event-stream"
170
+ }
171
+
172
+ mcp_url = f"{base_url}/mcp"
173
+
174
+ # Test 1: Initialize
175
+ print("πŸ”Œ Testing initialize...")
176
+ init_request = {
177
+ "jsonrpc": "2.0",
178
+ "id": 1,
179
+ "method": "initialize",
180
+ "params": {
181
+ "protocolVersion": "2024-11-05",
182
+ "capabilities": {},
183
+ "clientInfo": {
184
+ "name": "test-client",
185
+ "version": "1.0.0"
186
+ }
187
+ }
188
+ }
189
+
190
+ response = requests.post(mcp_url, json=init_request, headers=headers)
191
+ print(f"Status: {response.status_code}")
192
+ print(f"Response: {response.json()}")
193
+
194
+ # Test 2: List tools
195
+ print("\nπŸ› οΈ Testing tools/list...")
196
+ tools_request = {
197
+ "jsonrpc": "2.0",
198
+ "id": 2,
199
+ "method": "tools/list"
200
+ }
201
+
202
+ response = requests.post(mcp_url, json=tools_request, headers=headers)
203
+ print(f"Status: {response.status_code}")
204
+ if response.status_code == 200:
205
+ result = response.json()
206
+ if "result" in result and "tools" in result["result"]:
207
+ tools = result["result"]["tools"]
208
+ print(f"Found {len(tools)} tools:")
209
+ for tool in tools:
210
+ print(f" - {tool['name']}: {tool.get('description', 'No description')}")
211
+
212
+ if __name__ == "__main__":
213
+ test_mcp_server()
214
+ ```
215
+
216
+ ## πŸ“‹ Expected Responses
217
+
218
+ ### Successful Initialize Response
219
+
220
+ ```json
221
+ {
222
+ "jsonrpc": "2.0",
223
+ "id": 1,
224
+ "result": {
225
+ "protocolVersion": "2024-11-05",
226
+ "capabilities": {
227
+ "experimental": {},
228
+ "prompts": {"listChanged": true},
229
+ "resources": {"subscribe": false, "listChanged": true},
230
+ "tools": {"listChanged": true}
231
+ },
232
+ "serverInfo": {
233
+ "name": "obsidian-docs-viewer",
234
+ "version": "2.13.1"
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ ### Available Tools Response
241
+
242
+ ```json
243
+ {
244
+ "jsonrpc": "2.0",
245
+ "id": 2,
246
+ "result": {
247
+ "tools": [
248
+ {
249
+ "name": "list_notes",
250
+ "description": "List notes in the vault (optionally scoped to a folder)."
251
+ },
252
+ {
253
+ "name": "read_note",
254
+ "description": "Read a Markdown note with metadata and body."
255
+ },
256
+ {
257
+ "name": "write_note",
258
+ "description": "Create or update a note."
259
+ },
260
+ {
261
+ "name": "delete_note",
262
+ "description": "Delete a note and remove it from the index."
263
+ },
264
+ {
265
+ "name": "search_notes",
266
+ "description": "Search notes using full-text search with BM25 ranking."
267
+ },
268
+ {
269
+ "name": "get_backlinks",
270
+ "description": "List notes that reference the target note."
271
+ },
272
+ {
273
+ "name": "get_tags",
274
+ "description": "List tags and associated note counts."
275
+ }
276
+ ]
277
+ }
278
+ }
279
+ ```
280
+
281
+ ## 🚨 Common Errors and Solutions
282
+
283
+ ### Error: "Missing session ID"
284
+
285
+ ```json
286
+ {"jsonrpc":"2.0","id":"server-error","error":{"code":-32600,"message":"Bad Request: Missing session ID"}}
287
+ ```
288
+
289
+ **Solution**: This is expected for tools/list and tools/call without proper session management. The initialize method should work.
290
+
291
+ ### Error: "Authorization header required"
292
+
293
+ ```json
294
+ {"jsonrpc":"2.0","id":"server-error","error":{"code":-32600,"message":"Authorization header required"}}
295
+ ```
296
+
297
+ **Solution**: Make sure you include the Authorization header with Bearer token.
298
+
299
+ ### Error: Connection refused
300
+
301
+ **Solution**:
302
+ 1. Check if MCP server is running: `netstat -ano | findstr :8001` (Windows) or `lsof -i :8001` (Linux)
303
+ 2. Start the server: `python -m src.mcp.server` with `MCP_TRANSPORT=http` and `MCP_PORT=8001`
304
+
305
+ ## πŸ”§ Troubleshooting
306
+
307
+ ### Check Server Status
308
+
309
+ **Windows:**
310
+ ```powershell
311
+ netstat -ano | findstr :8001
312
+ ```
313
+
314
+ **Linux:**
315
+ ```bash
316
+ lsof -i :8001
317
+ # or
318
+ netstat -tlnp | grep :8001
319
+ ```
320
+
321
+ ### Start MCP Server
322
+
323
+ **Windows:**
324
+ ```powershell
325
+ cd backend
326
+ $env:MCP_TRANSPORT="http"
327
+ $env:MCP_PORT="8001"
328
+ $env:LOCAL_USER_ID="local-dev"
329
+ python -m src.mcp.server
330
+ ```
331
+
332
+ **Linux:**
333
+ ```bash
334
+ cd backend
335
+ export MCP_TRANSPORT=http
336
+ export MCP_PORT=8001
337
+ export LOCAL_USER_ID=local-dev
338
+ python -m src.mcp.server
339
+ ```
340
+
341
+ ## 🎯 Testing Checklist
342
+
343
+ - [ ] Server starts without errors
344
+ - [ ] Health endpoint responds: `GET /health`
345
+ - [ ] Initialize method works: Returns server info
346
+ - [ ] Tools list method works: Returns available tools
347
+ - [ ] Bearer token authentication works
348
+ - [ ] User isolation works (different tokens = different vaults)
349
+
350
+ ## πŸ“š Next Steps
351
+
352
+ 1. **For Cursor Integration**: Use STDIO transport in `mcp.json`
353
+ 2. **For HF Spaces**: Deploy with HTTP transport and JWT authentication
354
+ 3. **For Production**: Set proper `JWT_SECRET_KEY` and use real JWT tokens
start-dev.sh CHANGED
@@ -37,12 +37,12 @@ echo -e "${GREEN}Starting backend server...${NC}"
37
  cd "$BACKEND_DIR"
38
  JWT_SECRET_KEY="local-dev-secret-key-123" \
39
  VAULT_BASE_PATH="$PROJECT_ROOT/data/vaults" \
40
- .venv/bin/uvicorn src.api.main:app --host 0.0.0.0 --port 8001 --reload > "$PROJECT_ROOT/backend.log" 2>&1 &
41
  BACKEND_PID=$!
42
  echo $BACKEND_PID > "$BACKEND_PID_FILE"
43
  echo -e "${GREEN}βœ“ Backend started (PID: $BACKEND_PID)${NC}"
44
  echo " Logs: $PROJECT_ROOT/backend.log"
45
- echo " URL: http://localhost:8001"
46
 
47
  # Wait a moment for backend to start
48
  sleep 2
@@ -63,7 +63,7 @@ echo "Development servers are running!"
63
  echo "=================================================="
64
  echo -e "${NC}"
65
  echo "Frontend: http://localhost:5173"
66
- echo "Backend: http://localhost:8001"
67
  echo ""
68
  echo "To stop servers, run: ./stop-dev.sh"
69
  echo "To view logs, run: tail -f backend.log frontend.log"
 
37
  cd "$BACKEND_DIR"
38
  JWT_SECRET_KEY="local-dev-secret-key-123" \
39
  VAULT_BASE_PATH="$PROJECT_ROOT/data/vaults" \
40
+ .venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 --reload > "$PROJECT_ROOT/backend.log" 2>&1 &
41
  BACKEND_PID=$!
42
  echo $BACKEND_PID > "$BACKEND_PID_FILE"
43
  echo -e "${GREEN}βœ“ Backend started (PID: $BACKEND_PID)${NC}"
44
  echo " Logs: $PROJECT_ROOT/backend.log"
45
+ echo " URL: http://localhost:8000"
46
 
47
  # Wait a moment for backend to start
48
  sleep 2
 
63
  echo "=================================================="
64
  echo -e "${NC}"
65
  echo "Frontend: http://localhost:5173"
66
+ echo "Backend: http://localhost:8000"
67
  echo ""
68
  echo "To stop servers, run: ./stop-dev.sh"
69
  echo "To view logs, run: tail -f backend.log frontend.log"
status-dev.sh CHANGED
@@ -19,7 +19,7 @@ if [ -f "$BACKEND_PID_FILE" ]; then
19
  BACKEND_PID=$(cat "$BACKEND_PID_FILE")
20
  if ps -p $BACKEND_PID > /dev/null 2>&1; then
21
  echo -e "${GREEN}βœ“ Backend: RUNNING${NC} (PID: $BACKEND_PID)"
22
- echo " URL: http://localhost:8001"
23
  else
24
  echo -e "${RED}βœ— Backend: NOT RUNNING${NC} (stale PID: $BACKEND_PID)"
25
  fi
 
19
  BACKEND_PID=$(cat "$BACKEND_PID_FILE")
20
  if ps -p $BACKEND_PID > /dev/null 2>&1; then
21
  echo -e "${GREEN}βœ“ Backend: RUNNING${NC} (PID: $BACKEND_PID)"
22
+ echo " URL: http://localhost:8000"
23
  else
24
  echo -e "${RED}βœ— Backend: NOT RUNNING${NC} (stale PID: $BACKEND_PID)"
25
  fi