added mcp fixes

This commit is contained in:
Gamosoft 2026-06-16 18:09:48 +02:00
parent 0499798e48
commit e899dc79ae
5 changed files with 108 additions and 38 deletions

View File

@ -210,20 +210,21 @@ The MCP server provides these tools to AI assistants:
| Tool | Description | | Tool | Description |
|------|-------------| |------|-------------|
| `health_check` | Verify server connectivity | | `health_check` | Verify server connectivity |
| `get_config` | Get server config (name, version, enabled features, autosave delay) |
## Tool Details ## Tool Details
### Pagination with `max_results` and `offset` ### Pagination with `limit` and `offset`
Some tools support optional pagination parameters for large vaults: Some tools support optional pagination parameters for large vaults:
| Tool | Parameters | Description | | Tool | Parameters | Description |
|------|------------|-------------| |------|------------|-------------|
| `search_notes` | `max_results`, `offset` | Paginate search results | | `search_notes` | `limit`, `offset` | Paginate search results |
| `list_notes` | `max_results`, `offset` | Paginate notes list | | `list_notes` | `limit`, `offset` | Paginate notes list |
| `get_notes_by_tag` | `max_results`, `offset` | Paginate notes by tag | | `get_notes_by_tag` | `limit`, `offset` | Paginate notes by tag |
- `max_results` - Maximum items to return (omit for all) - `limit` - Maximum items to return (omit for all)
- `offset` - Number of items to skip (for pagination) - `offset` - Number of items to skip (for pagination)
**Example prompts:** **Example prompts:**

View File

@ -16,7 +16,33 @@ Environment Variables:
NOTEDISCOVERY_API_KEY: API key for authentication (optional) NOTEDISCOVERY_API_KEY: API key for authentication (optional)
""" """
__version__ = "1.0.0" from pathlib import Path
def _read_version() -> str:
"""
Resolve the package version.
Order:
1. importlib.metadata works when installed via pip/uvx/setuptools
2. VERSION file at repo root works when running from source / Docker
3. fallback string so the server still starts cleanly in odd setups
"""
try:
from importlib.metadata import version
return version("notediscovery")
except Exception:
pass
try:
version_file = Path(__file__).resolve().parent.parent / "VERSION"
if version_file.is_file():
return version_file.read_text(encoding="utf-8").strip()
except Exception:
pass
return "0.0.0+dev"
__version__ = _read_version()
__author__ = "NoteDiscovery" __author__ = "NoteDiscovery"
from .server import main from .server import main

View File

@ -170,9 +170,16 @@ class NoteDiscoveryClient:
Returns: Returns:
APIResponse with note content and metadata APIResponse with note content and metadata
""" """
# URL-encode the path # /api/notes/{path} defaults to include_backlinks=True server-side,
# which scans every note in the vault. The MCP get_note tool only
# surfaces content + metadata, so we skip the backlinks computation.
# Backlinks are still available via the dedicated get_backlinks method.
encoded_path = urllib.parse.quote(path, safe="") encoded_path = urllib.parse.quote(path, safe="")
return self._request("GET", f"/api/notes/{encoded_path}") return self._request(
"GET",
f"/api/notes/{encoded_path}",
params={"include_backlinks": "false"},
)
def create_note(self, path: str, content: str) -> APIResponse: def create_note(self, path: str, content: str) -> APIResponse:
""" """

View File

@ -13,6 +13,7 @@ import sys
import traceback import traceback
from typing import Any, Optional from typing import Any, Optional
from . import __version__
from .config import load_config, MCPConfig from .config import load_config, MCPConfig
from .client import NoteDiscoveryClient, APIResponse from .client import NoteDiscoveryClient, APIResponse
from .tools import TOOLS, get_tool_names from .tools import TOOLS, get_tool_names
@ -21,10 +22,11 @@ from .tools import TOOLS, get_tool_names
# MCP Protocol version # MCP Protocol version
MCP_VERSION = "2024-11-05" MCP_VERSION = "2024-11-05"
# Server info # Server info: version comes from the package (resolved against the VERSION
# file at repo root, or importlib.metadata when pip-installed).
SERVER_INFO = { SERVER_INFO = {
"name": "notediscovery-mcp", "name": "notediscovery-mcp",
"version": "1.0.0", "version": __version__,
} }
@ -208,14 +210,14 @@ class MCPServer:
def _tool_search_notes(self, args: dict) -> str: def _tool_search_notes(self, args: dict) -> str:
"""Search notes by query.""" """Search notes by query."""
query = args.get("query", "").strip() query = args.get("query", "").strip()
max_results = args.get("max_results") limit = args.get("limit")
offset = args.get("offset", 0) offset = args.get("offset", 0)
if not query: if not query:
return "No search term provided. Please specify a query." return "No search term provided. Please specify a query."
# Use server-side pagination if max_results is specified # Use server-side pagination if limit is specified
response = self.client.search(query, limit=max_results, offset=offset) response = self.client.search(query, limit=limit, offset=offset)
if not response.success: if not response.success:
return f"Search failed: {response.error}" return f"Search failed: {response.error}"
@ -252,17 +254,17 @@ class MCPServer:
# Add pagination hint if there are more results # Add pagination hint if there are more results
if pagination and pagination.get("has_more"): if pagination and pagination.get("has_more"):
output.append(f"... more results available (use max_results and offset to paginate)") output.append(f"... more results available (use limit and offset to paginate)")
return "\n".join(output) return "\n".join(output)
def _tool_list_notes(self, args: dict) -> str: def _tool_list_notes(self, args: dict) -> str:
"""List all notes.""" """List all notes."""
max_results = args.get("max_results") limit = args.get("limit")
offset = args.get("offset", 0) offset = args.get("offset", 0)
# Use server-side pagination if max_results is specified # Use server-side pagination if limit is specified
response = self.client.list_notes(limit=max_results, offset=offset) response = self.client.list_notes(limit=limit, offset=offset)
if not response.success: if not response.success:
return f"Failed to list notes: {response.error}" return f"Failed to list notes: {response.error}"
@ -298,7 +300,7 @@ class MCPServer:
# Add pagination hint if there are more results # Add pagination hint if there are more results
if pagination and pagination.get("has_more"): if pagination and pagination.get("has_more"):
output.append(f"... more notes available (use max_results to limit)") output.append(f"... more notes available (use limit and offset to paginate)")
return "\n".join(output) return "\n".join(output)
@ -350,14 +352,14 @@ class MCPServer:
def _tool_get_notes_by_tag(self, args: dict) -> str: def _tool_get_notes_by_tag(self, args: dict) -> str:
"""Get notes with a specific tag.""" """Get notes with a specific tag."""
tag = args.get("tag", "") tag = args.get("tag", "")
max_results = args.get("max_results") limit = args.get("limit")
offset = args.get("offset", 0) offset = args.get("offset", 0)
if not tag: if not tag:
return "Error: tag is required" return "Error: tag is required"
# Use server-side pagination if max_results is specified # Use server-side pagination if limit is specified
response = self.client.get_notes_by_tag(tag, limit=max_results, offset=offset) response = self.client.get_notes_by_tag(tag, limit=limit, offset=offset)
if not response.success: if not response.success:
return f"Failed to get notes by tag: {response.error}" return f"Failed to get notes by tag: {response.error}"
@ -382,7 +384,7 @@ class MCPServer:
# Add pagination hint if there are more results # Add pagination hint if there are more results
if pagination and pagination.get("has_more"): if pagination and pagination.get("has_more"):
output.append(f"\n... more notes available (use max_results to limit)") output.append(f"\n... more notes available (use limit and offset to paginate)")
return "\n".join(output) return "\n".join(output)
@ -650,6 +652,26 @@ class MCPServer:
return f"✅ NoteDiscovery is healthy at {self.config.base_url}" return f"✅ NoteDiscovery is healthy at {self.config.base_url}"
def _tool_get_config(self, args: dict) -> str:
"""Get NoteDiscovery server configuration."""
response = self.client.get_config()
if not response.success:
return f"Failed to get config: {response.error}"
data = response.data or {}
if not data:
return "Server returned empty configuration."
output = ["NoteDiscovery Server Configuration:\n"]
for key in sorted(data.keys()):
value = data[key]
if isinstance(value, (dict, list)):
value = json.dumps(value, ensure_ascii=False)
output.append(f" {key}: {value}")
return "\n".join(output)
# ========================================================================= # =========================================================================
# Main Loop # Main Loop
# ========================================================================= # =========================================================================

View File

@ -22,13 +22,13 @@ TOOLS: list[dict[str, Any]] = [
"type": "string", "type": "string",
"description": "Search query. Can be keywords, phrases, or natural language." "description": "Search query. Can be keywords, phrases, or natural language."
}, },
"max_results": { "limit": {
"type": "integer", "type": "integer",
"description": "Maximum number of results to return. Useful for large vaults. If not specified, returns all matches." "description": "Maximum number of results to return. Useful for large vaults. If not specified, returns all matches."
}, },
"offset": { "offset": {
"type": "integer", "type": "integer",
"description": "Number of results to skip. Use with max_results for pagination." "description": "Number of results to skip. Use with limit for pagination."
} }
}, },
"required": ["query"] "required": ["query"]
@ -40,13 +40,13 @@ TOOLS: list[dict[str, Any]] = [
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"properties": { "properties": {
"max_results": { "limit": {
"type": "integer", "type": "integer",
"description": "Maximum number of notes to return. Useful for large vaults. If not specified, returns all notes." "description": "Maximum number of notes to return. Useful for large vaults. If not specified, returns all notes."
}, },
"offset": { "offset": {
"type": "integer", "type": "integer",
"description": "Number of notes to skip. Use with max_results for pagination." "description": "Number of notes to skip. Use with limit for pagination."
} }
}, },
"required": [] "required": []
@ -89,13 +89,13 @@ TOOLS: list[dict[str, Any]] = [
"type": "string", "type": "string",
"description": "Tag name (without the # symbol)" "description": "Tag name (without the # symbol)"
}, },
"max_results": { "limit": {
"type": "integer", "type": "integer",
"description": "Maximum number of notes to return. Useful for large vaults. If not specified, returns all matches." "description": "Maximum number of notes to return. Useful for large vaults. If not specified, returns all matches."
}, },
"offset": { "offset": {
"type": "integer", "type": "integer",
"description": "Number of notes to skip. Use with max_results for pagination." "description": "Number of notes to skip. Use with limit for pagination."
} }
}, },
"required": ["tag"] "required": ["tag"]
@ -298,6 +298,20 @@ TOOLS: list[dict[str, Any]] = [
"required": [] "required": []
} }
}, },
{
"name": "get_config",
"description": (
"Get NoteDiscovery server configuration: app name, version, "
"whether search is enabled, authentication mode, autosave delay. "
"Useful for confirming what server you're connected to and what "
"features are available before calling other tools."
),
"inputSchema": {
"type": "object",
"properties": {},
"required": []
}
},
] ]