Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `get_server_status` — New MCP tool showing registered LSP servers and their status (ready/initializing/etc.), with document counts per language

### Changed

- **Shorter tool descriptions** — Condensed MCP tool descriptions for better compatibility with AI agent context windows

## [0.3.0] - 2025-12-28

Major feature release adding LSP notification handling and 3 new MCP tools for real-time diagnostics and server monitoring.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ Claude: [get_references] Found 4 matches:

| Tool | What it does |
|------|--------------|
| `get_server_status` | Show registered LSP servers and their status |
| `get_server_logs` | Debug LSP issues with internal log messages |
| `get_server_messages` | User-facing messages from the language server |

Expand Down
42 changes: 42 additions & 0 deletions crates/mcpls-core/src/bridge/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ impl DocumentTracker {
self.documents.is_empty()
}

/// Get all tracked documents.
#[must_use]
pub const fn documents(&self) -> &HashMap<PathBuf, DocumentState> {
&self.documents
}

/// Open a document and track its state.
///
/// Returns the document URI for use in LSP requests.
Expand Down Expand Up @@ -641,4 +647,40 @@ mod tests {
let result = tracker.open(PathBuf::from("/test/over.rs"), over_size_content);
assert!(matches!(result, Err(Error::FileSizeLimitExceeded { .. })));
}

#[test]
fn test_documents_accessor_returns_empty_map_for_new_tracker() {
let tracker = DocumentTracker::new();
let docs = tracker.documents();
assert!(docs.is_empty());
}

#[test]
fn test_documents_accessor_returns_all_open_documents() {
let mut tracker = DocumentTracker::new();
let path1 = PathBuf::from("/test/file1.rs");
let path2 = PathBuf::from("/test/file2.rs");

tracker.open(path1.clone(), "content1".to_string()).unwrap();
tracker.open(path2.clone(), "content2".to_string()).unwrap();

let docs = tracker.documents();
assert_eq!(docs.len(), 2);
assert!(docs.contains_key(&path1));
assert!(docs.contains_key(&path2));
}

#[test]
fn test_documents_accessor_reflects_document_state() {
let mut tracker = DocumentTracker::new();
let path = PathBuf::from("/test/file.rs");

tracker.open(path.clone(), "initial".to_string()).unwrap();
tracker.update(&path, "updated".to_string());

let docs = tracker.documents();
let state = docs.get(&path).unwrap();
assert_eq!(state.content, "updated");
assert_eq!(state.version, 2);
}
}
Loading