mne-docs-mcp 1.0.0 → 1.0.4

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 weiyongxu
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 weiyongxu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,140 +1,157 @@
1
- # MNE Docs MCP Server
2
-
3
- MCP server providing access to MNE-Python documentation, source code, GitHub issues, and community forum across the MNE ecosystem.
4
-
5
- ## Quick Start
6
-
7
- ```bash
8
- # Clone and install
9
- git clone https://github.com/weiyongxu/mne-docs-mcp.git
10
- cd mne-docs-mcp
11
- npm install
12
-
13
- # Set GitHub token (required)
14
- export MNE_GITHUB_TOKEN=ghp_your_token_here
15
-
16
- # Start server
17
- npm start
18
- ```
19
-
20
- Server runs on `http://localhost:8000`. Verify with `curl http://localhost:8000/health`.
21
-
22
- ## MCP Client Integration
23
-
24
- ### Claude Desktop / Kiro / Claude Code
25
-
26
- Add to your MCP config (`claude_desktop_config.json`, `.kiro/settings/mcp.json`, or `~/.claude/settings.json`):
27
-
28
- ```json
29
- {
30
- "mcpServers": {
31
- "mne-docs": {
32
- "command": "node",
33
- "args": ["/path/to/mne-docs-mcp/dist/index.js"],
34
- "env": {
35
- "MNE_GITHUB_TOKEN": "ghp_your_token_here",
36
- "MNE_TRANSPORT": "stdio"
37
- }
38
- }
39
- }
40
- }
41
- ```
42
-
43
- > **Windows:** Add `"MNE_PYTHON_PATH": "python"` to env.
44
-
45
- ### HTTP Mode
46
-
47
- ```bash
48
- MNE_TRANSPORT=http npm start
49
- # Connect to http://localhost:8000/mcp
50
- ```
51
-
52
- ### Docker
53
-
54
- ```bash
55
- docker run -p 8000:8000 -e MNE_GITHUB_TOKEN=ghp_your_token mne-docs-mcp
56
- ```
57
-
58
- ### Docker Compose
59
-
60
- ```bash
61
- # Set your token
62
- export MNE_GITHUB_TOKEN=ghp_your_token_here
63
-
64
- # Start
65
- docker-compose up -d
66
-
67
- # View logs
68
- docker-compose logs -f
69
- ```
70
-
71
- ## Tools
72
-
73
- | Tool | Description |
74
- |------|-------------|
75
- | `list_mne_versions` | List available MNE releases |
76
- | `get_mne_file` | Fetch source code |
77
- | `get_mne_doc` | Get symbol documentation |
78
- | `find_mne_symbol` | Search for symbols |
79
- | `search_mne_docs` | Unified code/docs search |
80
- | `search_mne_issues` | Search GitHub issues |
81
- | `get_mne_issue` | Get issue details |
82
- | `get_mne_issue_comments` | Get issue comments |
83
- | `search_mne_forum` | Search community forum |
84
- | `get_mne_forum_topic` | Get full forum discussion |
85
- | `get_symbol_references` | Get callees/callers |
86
- | `get_related_symbols` | Find related functions |
87
- | `get_mne_changelog` | Get version changes |
88
- | `get_mne_example` | Get tutorial code |
89
- | `lookup_mne_error` | Diagnose MNE errors |
90
-
91
- All tools support a `package` parameter to query across the MNE ecosystem: `mne-python` (default), `mne-bids-pipeline`, `mne-bids`, `mne-connectivity`, `mne-nirs`, `mne-rsa`, `mne-icalabel`, `mne-realtime`, `mne-lsl`, `mne-gui-addons`.
92
-
93
- ## Configuration
94
-
95
- | Variable | Description | Default |
96
- |----------|-------------|---------|
97
- | `MNE_GITHUB_TOKEN` | GitHub PAT (required) | - |
98
- | `MNE_PORT` | Server port | `8000` |
99
- | `MNE_TRANSPORT` | `http` or `stdio` | `http` |
100
- | `MNE_PYTHON_PATH` | Python executable | `python3` |
101
- | `MNE_LOG_LEVEL` | `debug`/`info`/`warn`/`error` | `info` |
102
-
103
- See `.env.example` for all options including cache TTLs and timeouts.
104
-
105
- ## Architecture
106
-
107
- ```
108
- ┌─────────────────────────────────────────────────────────┐
109
- │ TypeScript Server (Node.js) │
110
- │ ├─ MCP Tools (McpServer API, SDK v1.18+) │
111
- │ ├─ GitHub Client (rate limiting, caching) │
112
- │ └─ Python Parser Bridge ──┐ │
113
- └────────────────────────────┼────────────────────────────┘
114
-
115
- ┌─────────────────┐
116
- │ Python Parser │
117
- │ (AST, stdlib) │
118
- └─────────────────┘
119
- ```
120
-
121
- Built with the official [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk).
122
-
123
- ## Development
124
-
125
- ```bash
126
- npm run dev # Watch mode
127
- npm run build # Compile TypeScript
128
- npm test # Run tests
129
- npm run lint # ESLint
130
- ```
131
-
132
- ## Troubleshooting
133
-
134
- - **Rate limits:** Ensure `MNE_GITHUB_TOKEN` is set
135
- - **Parser fails:** Check Python 3 is installed; Windows users set `MNE_PYTHON_PATH=python`
136
- - **Test setup:** Run `npx tsx examples/mcp-client.ts` to verify
137
-
138
- ## License
139
-
140
- MIT
1
+ # MNE Docs MCP Server
2
+
3
+ MCP server providing access to MNE-Python documentation, source code, GitHub issues, and community forum across the MNE ecosystem.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Clone and install
9
+ git clone https://github.com/weiyongxu/mne-docs-mcp.git
10
+ cd mne-docs-mcp
11
+ npm install
12
+
13
+ # Set GitHub token (required)
14
+ export MNE_GITHUB_TOKEN=ghp_your_token_here
15
+
16
+ # Start server
17
+ npm start
18
+ ```
19
+
20
+ Server runs on `http://localhost:8000`. Verify with `curl http://localhost:8000/health`.
21
+
22
+ ## MCP Client Integration
23
+
24
+ ### Claude Desktop / Kiro / Claude Code
25
+
26
+ Add to your MCP config (`claude_desktop_config.json`, `.kiro/settings/mcp.json`, or `~/.claude/settings.json`):
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "mne-docs": {
32
+ "command": "node",
33
+ "args": ["/path/to/mne-docs-mcp/dist/index.js"],
34
+ "env": {
35
+ "MNE_GITHUB_TOKEN": "ghp_your_token_here",
36
+ "MNE_TRANSPORT": "stdio"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ > **Windows:** Add `"MNE_PYTHON_PATH": "python"` to env.
44
+
45
+ ### HTTP Mode
46
+
47
+ ```bash
48
+ MNE_TRANSPORT=http npm start
49
+ # Connect to http://localhost:8000/mcp
50
+ ```
51
+
52
+ ### Docker
53
+
54
+ ```bash
55
+ docker run -p 8000:8000 -e MNE_GITHUB_TOKEN=ghp_your_token mne-docs-mcp
56
+ ```
57
+
58
+ ### Docker Compose
59
+
60
+ ```bash
61
+ # Set your token
62
+ export MNE_GITHUB_TOKEN=ghp_your_token_here
63
+
64
+ # Start
65
+ docker-compose up -d
66
+
67
+ # View logs
68
+ docker-compose logs -f
69
+ ```
70
+
71
+ ## Tools
72
+
73
+ | Tool | Description |
74
+ |------|-------------|
75
+ | `list_mne_versions` | List available MNE releases |
76
+ | `get_mne_file` | Fetch source code |
77
+ | `get_mne_doc` | Get symbol documentation |
78
+ | `find_mne_symbol` | Search for symbols |
79
+ | `search_mne_docs` | Unified code/docs search |
80
+ | `search_mne_issues` | Search GitHub issues |
81
+ | `get_mne_issue` | Get issue details |
82
+ | `get_mne_issue_comments` | Get issue comments |
83
+ | `search_mne_forum` | Search community forum |
84
+ | `get_mne_forum_topic` | Get full forum discussion |
85
+ | `get_symbol_references` | Get callees/callers |
86
+ | `get_related_symbols` | Find related functions |
87
+ | `get_mne_changelog` | Get version changes |
88
+ | `get_mne_example` | Get tutorial code |
89
+ | `lookup_mne_error` | Diagnose MNE errors |
90
+
91
+ All tools support a `package` parameter to query across the MNE ecosystem: `mne-python` (default), `mne-bids-pipeline`, `mne-bids`, `mne-connectivity`, `mne-nirs`, `mne-rsa`, `mne-icalabel`, `mne-realtime`, `mne-lsl`, `mne-gui-addons`.
92
+
93
+ ## Configuration
94
+
95
+ | Variable | Description | Default |
96
+ |----------|-------------|---------|
97
+ | `MNE_GITHUB_TOKEN` | GitHub PAT (required) | - |
98
+ | `MNE_PORT` | Server port | `8000` |
99
+ | `MNE_TRANSPORT` | `http` or `stdio` | `http` |
100
+ | `MNE_PYTHON_PATH` | Python executable | `python3` |
101
+ | `MNE_LOG_LEVEL` | `debug`/`info`/`warn`/`error` | `info` |
102
+
103
+ See `.env.example` for all options including cache TTLs and timeouts.
104
+
105
+ ## Architecture
106
+
107
+ ```
108
+ ┌─────────────────────────────────────────────────────────┐
109
+ │ TypeScript Server (Node.js) │
110
+ │ ├─ MCP Tools (McpServer API, SDK v1.18+) │
111
+ │ ├─ GitHub Client (rate limiting, caching) │
112
+ │ └─ Python Parser Bridge ──┐ │
113
+ └────────────────────────────┼────────────────────────────┘
114
+
115
+ ┌─────────────────┐
116
+ │ Python Parser │
117
+ │ (AST, stdlib) │
118
+ └─────────────────┘
119
+ ```
120
+
121
+ Built with the official [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk).
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ npm run dev # Watch mode
127
+ npm run build # Compile TypeScript
128
+ npm test # Run tests
129
+ npm run lint # ESLint
130
+ ```
131
+
132
+ ## Releasing
133
+
134
+ First-time setup (one-time only):
135
+ ```bash
136
+ npm login
137
+ npm publish
138
+ ```
139
+
140
+ Then for all future releases:
141
+ ```bash
142
+ npm run release:patch # 1.0.0 → 1.0.1
143
+ npm run release:minor # 1.0.0 → 1.1.0
144
+ npm run release:major # 1.0.0 → 2.0.0
145
+ ```
146
+
147
+ This bumps versions, commits, tags, and pushes. GitHub Actions then publishes to npm and MCP Registry automatically.
148
+
149
+ ## Troubleshooting
150
+
151
+ - **Rate limits:** Ensure `MNE_GITHUB_TOKEN` is set
152
+ - **Parser fails:** Check Python 3 is installed; Windows users set `MNE_PYTHON_PATH=python`
153
+ - **Test setup:** Run `npx tsx examples/mcp-client.ts` to verify
154
+
155
+ ## License
156
+
157
+ MIT
@@ -137,91 +137,91 @@ function getSolutions(errorType, message, codeContext) {
137
137
  if (lower.includes('no events found')) {
138
138
  solutions.push({
139
139
  description: 'The events array is empty. Check your event detection parameters.',
140
- codeExample: `# Check available events in your data
141
- events = mne.find_events(raw, stim_channel='STI 014')
142
- print(f"Found {len(events)} events")
143
-
144
- # If no events, try different parameters:
145
- events = mne.find_events(raw, stim_channel='STI 014',
146
- min_duration=0.002,
147
- shortest_event=1)
148
-
149
- # Or check available stim channels:
140
+ codeExample: `# Check available events in your data
141
+ events = mne.find_events(raw, stim_channel='STI 014')
142
+ print(f"Found {len(events)} events")
143
+
144
+ # If no events, try different parameters:
145
+ events = mne.find_events(raw, stim_channel='STI 014',
146
+ min_duration=0.002,
147
+ shortest_event=1)
148
+
149
+ # Or check available stim channels:
150
150
  print(raw.info['ch_names']) # Look for STI/STIM channels`,
151
151
  });
152
152
  }
153
153
  if (lower.includes('baseline period')) {
154
154
  solutions.push({
155
155
  description: 'Baseline period extends beyond epoch boundaries.',
156
- codeExample: `# Ensure baseline is within tmin/tmax
157
- epochs = mne.Epochs(raw, events,
158
- tmin=-0.2, tmax=0.5,
159
- baseline=(-0.2, 0)) # baseline must be within [-0.2, 0.5]
160
-
161
- # Or use None for no baseline correction:
156
+ codeExample: `# Ensure baseline is within tmin/tmax
157
+ epochs = mne.Epochs(raw, events,
158
+ tmin=-0.2, tmax=0.5,
159
+ baseline=(-0.2, 0)) # baseline must be within [-0.2, 0.5]
160
+
161
+ # Or use None for no baseline correction:
162
162
  epochs = mne.Epochs(raw, events, tmin=-0.2, tmax=0.5, baseline=None)`,
163
163
  });
164
164
  }
165
165
  if (lower.includes('data not loaded') || lower.includes('preload')) {
166
166
  solutions.push({
167
167
  description: 'Data needs to be loaded into memory before this operation.',
168
- codeExample: `# Load data into memory
169
- raw.load_data()
170
-
171
- # Or load when reading:
168
+ codeExample: `# Load data into memory
169
+ raw.load_data()
170
+
171
+ # Or load when reading:
172
172
  raw = mne.io.read_raw_fif('file.fif', preload=True)`,
173
173
  });
174
174
  }
175
175
  if (lower.includes('channel') && (lower.includes('not found') || lower.includes('missing'))) {
176
176
  solutions.push({
177
177
  description: 'The specified channel was not found in the data.',
178
- codeExample: `# List available channels
179
- print(raw.ch_names)
180
-
181
- # Pick channels by type
182
- raw.pick_types(eeg=True, meg=False)
183
-
184
- # Or pick specific channels
178
+ codeExample: `# List available channels
179
+ print(raw.ch_names)
180
+
181
+ # Pick channels by type
182
+ raw.pick_types(eeg=True, meg=False)
183
+
184
+ # Or pick specific channels
185
185
  raw.pick_channels(['EEG 001', 'EEG 002'])`,
186
186
  });
187
187
  }
188
188
  if (lower.includes('filter') && (lower.includes('nyquist') || lower.includes('frequency'))) {
189
189
  solutions.push({
190
190
  description: 'Filter frequency exceeds Nyquist frequency (half the sampling rate).',
191
- codeExample: `# Check sampling rate
192
- print(f"Sampling rate: {raw.info['sfreq']} Hz")
193
- print(f"Nyquist frequency: {raw.info['sfreq'] / 2} Hz")
194
-
195
- # Resample if needed before filtering
196
- raw.resample(sfreq=250) # Resample to 250 Hz
191
+ codeExample: `# Check sampling rate
192
+ print(f"Sampling rate: {raw.info['sfreq']} Hz")
193
+ print(f"Nyquist frequency: {raw.info['sfreq'] / 2} Hz")
194
+
195
+ # Resample if needed before filtering
196
+ raw.resample(sfreq=250) # Resample to 250 Hz
197
197
  raw.filter(l_freq=1, h_freq=40)`,
198
198
  });
199
199
  }
200
200
  if (lower.includes('memory') || lower.includes('memoryerror')) {
201
201
  solutions.push({
202
202
  description: 'Not enough memory for the operation.',
203
- codeExample: `# Use preload=False to reduce memory
204
- raw = mne.io.read_raw_fif('file.fif', preload=False)
205
-
206
- # Decimate data to reduce size
207
- epochs.decimate(4) # Keep every 4th sample
208
-
209
- # Or process in chunks
210
- for start in range(0, len(raw.times), chunk_size):
211
- chunk = raw.get_data(start=start, stop=start+chunk_size)
203
+ codeExample: `# Use preload=False to reduce memory
204
+ raw = mne.io.read_raw_fif('file.fif', preload=False)
205
+
206
+ # Decimate data to reduce size
207
+ epochs.decimate(4) # Keep every 4th sample
208
+
209
+ # Or process in chunks
210
+ for start in range(0, len(raw.times), chunk_size):
211
+ chunk = raw.get_data(start=start, stop=start+chunk_size)
212
212
  # Process chunk...`,
213
213
  });
214
214
  }
215
215
  if (lower.includes('ica') && lower.includes('fit')) {
216
216
  solutions.push({
217
217
  description: 'ICA fitting issue - check data quality and parameters.',
218
- codeExample: `# Ensure data is filtered before ICA
219
- raw.filter(l_freq=1, h_freq=None)
220
-
221
- # Use fewer components if data is short
222
- ica = ICA(n_components=15, random_state=97, max_iter='auto')
223
-
224
- # Fit on filtered data
218
+ codeExample: `# Ensure data is filtered before ICA
219
+ raw.filter(l_freq=1, h_freq=None)
220
+
221
+ # Use fewer components if data is short
222
+ ica = ICA(n_components=15, random_state=97, max_iter='auto')
223
+
224
+ # Fit on filtered data
225
225
  ica.fit(raw)`,
226
226
  });
227
227
  }
@@ -230,16 +230,16 @@ ica.fit(raw)`,
230
230
  if (lowerContext.includes('epochs') && lower.includes('baseline')) {
231
231
  solutions.unshift({
232
232
  description: 'Baseline error in Epochs - check tmin/tmax and baseline parameters match.',
233
- codeExample: `# Ensure baseline period is within epoch bounds
234
- # If tmin=-0.2, tmax=0.5, baseline must be within that range
233
+ codeExample: `# Ensure baseline period is within epoch bounds
234
+ # If tmin=-0.2, tmax=0.5, baseline must be within that range
235
235
  epochs = mne.Epochs(raw, events, tmin=-0.2, tmax=0.5, baseline=(-0.2, 0))`,
236
236
  });
237
237
  }
238
238
  if (lowerContext.includes('raw') && lower.includes('preload')) {
239
239
  solutions.unshift({
240
240
  description: 'Raw data needs to be loaded before this operation.',
241
- codeExample: `# Load data into memory first
242
- raw.load_data()
241
+ codeExample: `# Load data into memory first
242
+ raw.load_data()
243
243
  # Then perform your operation`,
244
244
  });
245
245
  }