create-academic-research 0.1.13 → 0.1.15

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.
@@ -12,6 +12,27 @@ export interface CapabilityPreset {
12
12
  skill_bundles: string[];
13
13
  mcp_servers: string[];
14
14
  }
15
+ export type McpConnectionMode = "stdio-local" | "remote-curated" | "remote-custom" | "local-service" | "manual-local" | "manual";
16
+ export interface McpServerMode {
17
+ connection_mode: McpConnectionMode;
18
+ readiness?: string;
19
+ priority?: string;
20
+ execution_mode?: string;
21
+ source_need?: string;
22
+ source?: string;
23
+ hosted_url?: string;
24
+ install_command?: string;
25
+ uninstall_command?: string;
26
+ setup_commands?: string[];
27
+ command?: string;
28
+ args?: string[];
29
+ env?: Record<string, string>;
30
+ required_env?: string[];
31
+ recommended_env?: string[];
32
+ local_service?: string;
33
+ smoke_test?: string;
34
+ risks?: string;
35
+ }
15
36
  export interface McpServer {
16
37
  readiness: string;
17
38
  priority: string;
@@ -30,6 +51,15 @@ export interface McpServer {
30
51
  local_service: string;
31
52
  smoke_test: string;
32
53
  risks: string;
54
+ default_mode?: string;
55
+ recommended_mode?: string;
56
+ modes?: Record<string, McpServerMode>;
57
+ }
58
+ export interface ResolvedMcpServer extends McpServer {
59
+ selected_mode: string;
60
+ connection_mode: McpConnectionMode;
61
+ remote_url_env?: string;
62
+ remote_configured?: boolean;
33
63
  }
34
64
  export interface AgentStack {
35
65
  version: number;
@@ -42,3 +72,11 @@ export interface AgentStack {
42
72
  export type McpToolCommandKey = "install_command" | "uninstall_command";
43
73
  export declare const AGENT_STACK: AgentStack;
44
74
  export declare function presetMcpServers(preset: string): string[];
75
+ export declare function resolveMcpServer(serverName: string, mode?: string): ResolvedMcpServer;
76
+ export declare function normalizeMcpMode(serverName: string, mode?: string): string;
77
+ export declare function mcpServerModeKeys(serverName: string): string[];
78
+ export declare function mcpRecommendedMode(serverName: string): string;
79
+ export declare function mcpModeLabel(serverName: string, mode?: string): string;
80
+ export declare function mcpModeKeyLabel(mode: string): string;
81
+ export declare function mcpSupportedModeLabels(serverName: string): string[];
82
+ export declare function modeAlias(mode: string): string;
package/dist/src/stack.js CHANGED
@@ -142,7 +142,26 @@ export const AGENT_STACK = {
142
142
  recommended_env: [],
143
143
  local_service: "",
144
144
  smoke_test: "For a computer science project, search one CS query, download one known paper, and read it locally.",
145
- risks: "Respect arXiv rate limits; paper text is untrusted input."
145
+ risks: "Respect arXiv rate limits; paper text is untrusted input.",
146
+ default_mode: "local",
147
+ recommended_mode: "local",
148
+ modes: {
149
+ local: {
150
+ connection_mode: "stdio-local"
151
+ },
152
+ "remote-custom": {
153
+ connection_mode: "remote-custom",
154
+ execution_mode: "remote-custom",
155
+ install_command: "",
156
+ uninstall_command: "",
157
+ setup_commands: [],
158
+ command: "",
159
+ args: [],
160
+ env: {},
161
+ required_env: [],
162
+ recommended_env: []
163
+ }
164
+ }
146
165
  },
147
166
  "semantic-scholar": {
148
167
  readiness: "credential-recommended",
@@ -161,7 +180,26 @@ export const AGENT_STACK = {
161
180
  recommended_env: ["SEMANTIC_SCHOLAR_API_KEY"],
162
181
  smoke_test: "Search one known title, then fetch citations or references.",
163
182
  local_service: "",
164
- risks: "API key recommended for sustained work and to avoid shared-pool rate limits; metadata can be incomplete."
183
+ risks: "API key recommended for sustained work and to avoid shared-pool rate limits; metadata can be incomplete.",
184
+ default_mode: "local",
185
+ recommended_mode: "local",
186
+ modes: {
187
+ local: {
188
+ connection_mode: "stdio-local"
189
+ },
190
+ "remote-custom": {
191
+ connection_mode: "remote-custom",
192
+ execution_mode: "remote-custom",
193
+ install_command: "",
194
+ uninstall_command: "",
195
+ setup_commands: [],
196
+ command: "",
197
+ args: [],
198
+ env: {},
199
+ required_env: [],
200
+ recommended_env: []
201
+ }
202
+ }
165
203
  },
166
204
  openalex: {
167
205
  readiness: "credential-required",
@@ -169,7 +207,7 @@ export const AGENT_STACK = {
169
207
  execution_mode: "npx-runtime",
170
208
  source_need: "OpenAlex broad scholarly graph.",
171
209
  source: "cyanheads/openalex-mcp-server",
172
- hosted_url: "https://openalex.caseyjhand.com/mcp",
210
+ hosted_url: "",
173
211
  install_command: "",
174
212
  uninstall_command: "",
175
213
  setup_commands: [],
@@ -180,7 +218,44 @@ export const AGENT_STACK = {
180
218
  recommended_env: [],
181
219
  local_service: "",
182
220
  smoke_test: "Search works by title or DOI and confirm stable OpenAlex IDs.",
183
- risks: "The selected local server requires OPENALEX_API_KEY. OpenAlex keys are free and include a free daily quota; check current credit limits, smoke-test coverage, and inspect cost headers before high-volume work."
221
+ risks: "The selected local server requires OPENALEX_API_KEY. OpenAlex keys are free and include a free daily quota; check current credit limits, smoke-test coverage, and inspect cost headers before high-volume work.",
222
+ default_mode: "local",
223
+ recommended_mode: "remote",
224
+ modes: {
225
+ local: {
226
+ connection_mode: "stdio-local"
227
+ },
228
+ remote: {
229
+ connection_mode: "remote-curated",
230
+ execution_mode: "remote-curated",
231
+ hosted_url: "https://openalex.caseyjhand.com/mcp",
232
+ install_command: "",
233
+ uninstall_command: "",
234
+ setup_commands: [],
235
+ command: "",
236
+ args: [],
237
+ env: {},
238
+ required_env: [],
239
+ recommended_env: [],
240
+ smoke_test: "Connect the MCP client to the hosted streamable HTTP endpoint and run a read-only works search.",
241
+ risks: "Hosted endpoint behavior, authentication, rate limits, and availability are controlled by the endpoint operator; verify current policy before sustained use."
242
+ },
243
+ "remote-custom": {
244
+ connection_mode: "remote-custom",
245
+ execution_mode: "remote-custom",
246
+ hosted_url: "",
247
+ install_command: "",
248
+ uninstall_command: "",
249
+ setup_commands: [],
250
+ command: "",
251
+ args: [],
252
+ env: {},
253
+ required_env: [],
254
+ recommended_env: [],
255
+ smoke_test: "Connect the MCP client to the custom streamable HTTP endpoint and run a read-only works search.",
256
+ risks: "Custom endpoint behavior, authentication, rate limits, and availability are controlled by the endpoint operator; verify current policy before sustained use."
257
+ }
258
+ }
184
259
  },
185
260
  crossref: {
186
261
  readiness: "manual",
@@ -199,7 +274,14 @@ export const AGENT_STACK = {
199
274
  recommended_env: [],
200
275
  local_service: "",
201
276
  smoke_test: "Resolve one DOI into publication metadata after choosing a maintained local server.",
202
- risks: "Manual integration only; current zero-friction Crossref-only MCP candidates are less mature than arXiv, DBLP, PubMed, or OpenAlex."
277
+ risks: "Manual integration only; current zero-friction Crossref-only MCP candidates are less mature than arXiv, DBLP, PubMed, or OpenAlex.",
278
+ default_mode: "manual",
279
+ recommended_mode: "manual",
280
+ modes: {
281
+ manual: {
282
+ connection_mode: "manual"
283
+ }
284
+ }
203
285
  },
204
286
  pubmed: {
205
287
  readiness: "domain-specific",
@@ -207,7 +289,7 @@ export const AGENT_STACK = {
207
289
  execution_mode: "npx-runtime",
208
290
  source_need: "PubMed and biomedical literature.",
209
291
  source: "cyanheads/pubmed-mcp-server",
210
- hosted_url: "https://pubmed.caseyjhand.com/mcp",
292
+ hosted_url: "",
211
293
  install_command: "",
212
294
  uninstall_command: "",
213
295
  setup_commands: [],
@@ -218,7 +300,44 @@ export const AGENT_STACK = {
218
300
  recommended_env: ["NCBI_API_KEY", "NCBI_ADMIN_EMAIL"],
219
301
  local_service: "",
220
302
  smoke_test: "Search one PMID or title and fetch metadata.",
221
- risks: "Domain-specific; observe NCBI rate limits. API key and contact email improve reliability."
303
+ risks: "Domain-specific; observe NCBI rate limits. API key and contact email improve reliability.",
304
+ default_mode: "local",
305
+ recommended_mode: "remote",
306
+ modes: {
307
+ local: {
308
+ connection_mode: "stdio-local"
309
+ },
310
+ remote: {
311
+ connection_mode: "remote-curated",
312
+ execution_mode: "remote-curated",
313
+ hosted_url: "https://pubmed.caseyjhand.com/mcp",
314
+ install_command: "",
315
+ uninstall_command: "",
316
+ setup_commands: [],
317
+ command: "",
318
+ args: [],
319
+ env: {},
320
+ required_env: [],
321
+ recommended_env: [],
322
+ smoke_test: "Connect the MCP client to the hosted streamable HTTP endpoint and run a read-only PubMed search.",
323
+ risks: "Hosted endpoint behavior, authentication, NCBI policy handling, and availability are controlled by the endpoint operator; verify current policy before sustained use."
324
+ },
325
+ "remote-custom": {
326
+ connection_mode: "remote-custom",
327
+ execution_mode: "remote-custom",
328
+ hosted_url: "",
329
+ install_command: "",
330
+ uninstall_command: "",
331
+ setup_commands: [],
332
+ command: "",
333
+ args: [],
334
+ env: {},
335
+ required_env: [],
336
+ recommended_env: [],
337
+ smoke_test: "Connect the MCP client to the custom streamable HTTP endpoint and run a read-only PubMed search.",
338
+ risks: "Custom endpoint behavior, authentication, NCBI policy handling, and availability are controlled by the endpoint operator; verify current policy before sustained use."
339
+ }
340
+ }
222
341
  },
223
342
  dblp: {
224
343
  readiness: "low-friction-cs",
@@ -237,7 +356,26 @@ export const AGENT_STACK = {
237
356
  recommended_env: [],
238
357
  local_service: "",
239
358
  smoke_test: "Search one known CS paper title and export or inspect its DBLP BibTeX.",
240
- risks: "CS-specific metadata source; use with arXiv/Semantic Scholar/OpenAlex for coverage beyond DBLP."
359
+ risks: "CS-specific metadata source; use with arXiv/Semantic Scholar/OpenAlex for coverage beyond DBLP.",
360
+ default_mode: "local",
361
+ recommended_mode: "local",
362
+ modes: {
363
+ local: {
364
+ connection_mode: "stdio-local"
365
+ },
366
+ "remote-custom": {
367
+ connection_mode: "remote-custom",
368
+ execution_mode: "remote-custom",
369
+ install_command: "",
370
+ uninstall_command: "",
371
+ setup_commands: [],
372
+ command: "",
373
+ args: [],
374
+ env: {},
375
+ required_env: [],
376
+ recommended_env: []
377
+ }
378
+ }
241
379
  },
242
380
  zotero: {
243
381
  readiness: "local-service",
@@ -256,7 +394,14 @@ export const AGENT_STACK = {
256
394
  recommended_env: [],
257
395
  local_service: "Zotero desktop running with local API enabled; Zoty Bridge required for attachment and collection write operations.",
258
396
  smoke_test: "List collections, search one known item, and export BibTeX.",
259
- risks: "Requires Zotero local API and bridge setup."
397
+ risks: "Requires Zotero local API and bridge setup.",
398
+ default_mode: "local",
399
+ recommended_mode: "local",
400
+ modes: {
401
+ local: {
402
+ connection_mode: "local-service"
403
+ }
404
+ }
260
405
  },
261
406
  overleaf: {
262
407
  readiness: "manual-credentialed",
@@ -268,14 +413,21 @@ export const AGENT_STACK = {
268
413
  install_command: "",
269
414
  uninstall_command: "",
270
415
  setup_commands: [],
271
- command: "",
416
+ command: ".academic-research/mcp/overleaf/run-overleaf-mcp.sh",
272
417
  args: [],
273
418
  env: {},
274
- required_env: ["OVERLEAF_TOKEN"],
275
- recommended_env: ["PROJECT_ID"],
419
+ required_env: ["OVERLEAF_TOKEN", "PROJECT_ID"],
420
+ recommended_env: [],
276
421
  local_service: "Local clone of the Overleaf MCP server configured with uv and an Overleaf project that supports Git sync.",
277
422
  smoke_test: "List projects or read one .tex file; do not write by default.",
278
- risks: "Requires token and project setup; write/push access needs explicit approval."
423
+ risks: "Requires token and project setup; write/push access needs explicit approval.",
424
+ default_mode: "local",
425
+ recommended_mode: "local",
426
+ modes: {
427
+ local: {
428
+ connection_mode: "manual-local"
429
+ }
430
+ }
279
431
  },
280
432
  "paper-search": {
281
433
  readiness: "fallback",
@@ -297,7 +449,14 @@ export const AGENT_STACK = {
297
449
  ],
298
450
  local_service: "Manual review required before enabling; configure only permitted sources.",
299
451
  smoke_test: "Search one harmless query with a source allow-list and verify provenance for each result.",
300
- risks: "Powerful aggregator with optional restricted-source workflows; keep Sci-Hub or questionable download features disabled unless explicitly accepted."
452
+ risks: "Powerful aggregator with optional restricted-source workflows; keep Sci-Hub or questionable download features disabled unless explicitly accepted.",
453
+ default_mode: "manual",
454
+ recommended_mode: "manual",
455
+ modes: {
456
+ manual: {
457
+ connection_mode: "manual"
458
+ }
459
+ }
301
460
  }
302
461
  }
303
462
  };
@@ -307,3 +466,90 @@ export function presetMcpServers(preset) {
307
466
  throw new Error(`unknown capability preset: ${preset}`);
308
467
  return [...config.mcp_servers];
309
468
  }
469
+ export function resolveMcpServer(serverName, mode) {
470
+ const server = AGENT_STACK.mcp_servers[serverName];
471
+ if (!server)
472
+ throw new Error(`unknown MCP server: ${serverName}`);
473
+ const selectedMode = normalizeMcpMode(serverName, mode);
474
+ const variant = server.modes?.[selectedMode];
475
+ return {
476
+ ...server,
477
+ ...variant,
478
+ selected_mode: selectedMode,
479
+ connection_mode: variant?.connection_mode ?? defaultConnectionMode(server.execution_mode)
480
+ };
481
+ }
482
+ export function normalizeMcpMode(serverName, mode) {
483
+ const server = AGENT_STACK.mcp_servers[serverName];
484
+ if (!server)
485
+ throw new Error(`unknown MCP server: ${serverName}`);
486
+ const defaultMode = server.default_mode ?? "local";
487
+ if (!mode)
488
+ return defaultMode;
489
+ const normalized = modeAlias(mode);
490
+ if (server.modes?.[normalized])
491
+ return normalized;
492
+ if (!server.modes && normalized === defaultMode)
493
+ return defaultMode;
494
+ throw new Error(`${serverName} does not support MCP mode ${mode}. Supported modes: ${mcpServerModeKeys(serverName).join(", ")}`);
495
+ }
496
+ export function mcpServerModeKeys(serverName) {
497
+ const server = AGENT_STACK.mcp_servers[serverName];
498
+ if (!server)
499
+ throw new Error(`unknown MCP server: ${serverName}`);
500
+ return Object.keys(server.modes ?? { [server.default_mode ?? "local"]: { connection_mode: defaultConnectionMode(server.execution_mode) } });
501
+ }
502
+ export function mcpRecommendedMode(serverName) {
503
+ const server = AGENT_STACK.mcp_servers[serverName];
504
+ if (!server)
505
+ throw new Error(`unknown MCP server: ${serverName}`);
506
+ return normalizeMcpMode(serverName, server.recommended_mode ?? server.default_mode);
507
+ }
508
+ export function mcpModeLabel(serverName, mode) {
509
+ const server = resolveMcpServer(serverName, mode);
510
+ if (server.selected_mode === "remote-custom")
511
+ return "custom remote";
512
+ if (server.connection_mode === "remote-curated")
513
+ return "remote";
514
+ if (server.connection_mode === "remote-custom")
515
+ return "custom remote";
516
+ if (server.connection_mode === "local-service")
517
+ return "requires local app";
518
+ if (server.connection_mode === "manual-local")
519
+ return "manual setup";
520
+ if (server.connection_mode === "manual")
521
+ return "manual setup";
522
+ return "local";
523
+ }
524
+ export function mcpModeKeyLabel(mode) {
525
+ if (mode === "remote-custom")
526
+ return "custom remote";
527
+ if (mode === "remote" || mode === "remote-curated" || mode === "http-remote")
528
+ return "remote";
529
+ if (mode === "local-service")
530
+ return "requires local app";
531
+ if (mode === "manual-local" || mode === "manual")
532
+ return "manual setup";
533
+ return "local";
534
+ }
535
+ export function mcpSupportedModeLabels(serverName) {
536
+ return mcpServerModeKeys(serverName).map((mode) => mcpModeLabel(serverName, mode));
537
+ }
538
+ export function modeAlias(mode) {
539
+ if (mode === "stdio-local" || mode === "manual-local" || mode === "local-service")
540
+ return "local";
541
+ if (mode === "http-remote" || mode === "remote-curated" || mode === "curated-remote")
542
+ return "remote";
543
+ if (mode === "custom-remote")
544
+ return "remote-custom";
545
+ return mode;
546
+ }
547
+ function defaultConnectionMode(executionMode) {
548
+ if (executionMode === "uvx-runtime" || executionMode === "npx-runtime")
549
+ return "stdio-local";
550
+ if (executionMode === "local-service")
551
+ return "local-service";
552
+ if (executionMode === "manual-local")
553
+ return "manual-local";
554
+ return "manual";
555
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-academic-research",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Scaffold agent-ready academic research repositories with SOTA, source ledgers, wiki memory, MCP setup, and project-local skills.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -49,7 +49,7 @@
49
49
  ],
50
50
  "scripts": {
51
51
  "clean": "rm -rf dist",
52
- "build": "npm run clean && tsc",
52
+ "build": "npm run clean && tsc && node scripts/chmod-bins.mjs",
53
53
  "typecheck": "tsc --noEmit",
54
54
  "test": "npm run build && node --test",
55
55
  "lint": "npm run typecheck && node scripts/validate.mjs",
@@ -31,6 +31,7 @@ source .venv/bin/activate
31
31
  python -m pip install --upgrade pip
32
32
  python -m pip install -e ".[dev]"
33
33
  npm run doctor
34
+ npm run update
34
35
  ```
35
36
 
36
37
  ## Core Folders
@@ -60,11 +61,17 @@ npm run skills:install -- --preset enhanced
60
61
  npm run skills:install -- source-ingestion sota-literature-review
61
62
  npm run skills:list
62
63
  npm run skills:status
64
+ npm run update
63
65
  npm run setup
64
66
  npm run mcp:dotenv
65
67
  npm run mcp:list
68
+ npm run mcp:modes
69
+ npm run mcp:status
66
70
  npm run mcp:env -- openalex semantic-scholar zotero
71
+ npm run mcp:enable -- openalex --mode remote
67
72
  npm run mcp:enable -- arxiv dblp
73
+ npm run mcp:setup -- overleaf --mode local --env-file .env.local
74
+ npm run mcp:client:add -- overleaf --agent codex --dry-run
68
75
  npm run mcp:commands -- arxiv
69
76
  npm run mcp:install -- arxiv
70
77
  npm run mcp:smoke -- --env-file .env.local
@@ -73,13 +80,30 @@ npm run mcp:probe -- arxiv --timeout-ms 5000
73
80
  ```
74
81
 
75
82
  `skills list` reports installed project-local skills. `skills presets` reports
76
- available install presets. `mcp enable` changes project records. `mcp commands`
83
+ available install presets. `mcp enable` changes selected project records and
84
+ can record explicit modes such as `--mode remote`. Use `mcp modes` to see
85
+ which integrations support local, remote, custom remote, local-app, or manual
86
+ setup paths. `mcp status` separates selected records from setup, snippet,
87
+ client registration, and probe readiness; add `--verbose` for technical fields.
88
+ `mcp commands`
77
89
  prints finite external install commands without running them. `mcp env` prints
78
90
  env vars, hosted endpoints, local prerequisites, and setup commands before you
79
91
  enable optional servers. `mcp install` runs only finite tool installation
80
92
  commands; runtime-only `uvx`/`npx` MCP servers may have no install step and are
81
93
  started later by the MCP client.
82
94
 
95
+ `npm run update` always uses `create-academic-research@latest` so older
96
+ projects can preview scaffold migrations with one command. It is a dry-run
97
+ unless you pass `-- --apply`; safe managed files are tracked in
98
+ `.academic-research/managed-files.json` and locally edited files are skipped
99
+ instead of overwritten. If this project was created before the latest update
100
+ script existed, run:
101
+
102
+ ```bash
103
+ npm exec --yes --package=create-academic-research@latest -- academic-research update --root .
104
+ npm exec --yes --package=create-academic-research@latest -- academic-research update --root . --apply
105
+ ```
106
+
83
107
  `.env.example` is the committed MCP environment reference. Regenerate it with
84
108
  `npm run mcp:dotenv`. Copy it to `.env.local`, your shell profile, or your MCP
85
109
  client secret store when secrets are needed. Filled `.env` files are ignored by
@@ -87,11 +111,20 @@ git. `mcp doctor` checks the current process environment unless you explicitly
87
111
  pass `--env-file .env.local`.
88
112
 
89
113
  `setup` prints the current project capability state, installed skill counts,
90
- enabled MCP records, and the next onboarding commands without changing files.
114
+ selected MCP records, and the next onboarding commands without changing files.
91
115
  `mcp smoke` performs a non-launching MCP readiness check: it reports required
92
116
  env vars, local/manual setup, and whether client runtime commands such as `uvx`
93
- or `npx` are available. `mcp probe` is opt-in and starts selected MCP servers
94
- for a real stdio JSON-RPC handshake.
117
+ or `npx` are available. `mcp probe` is opt-in: local stdio servers get a real
118
+ JSON-RPC handshake, while remote endpoints are reported as configured without a
119
+ network probe.
120
+
121
+ Overleaf setup creates a local wrapper under `.academic-research/mcp/` that
122
+ parses `.env.local` safely at runtime. The wrapper path and client/probe
123
+ observations are recorded in `docs/agent/capability-lock.json`; project-local
124
+ skill install/update/remove observations are recorded there too.
125
+ `configs/capabilities.yaml` is intended state, while the capability lock is
126
+ observed setup state. Token values are not stored there or in generated
127
+ snippets.
95
128
 
96
129
  `default` installs the companion academic research skill package and keeps the
97
130
  MCP records focused on low-friction arXiv discovery. `literature` and `full`
@@ -55,6 +55,7 @@ artifacts/cache/**
55
55
  !artifacts/cache/
56
56
  !artifacts/cache/.gitkeep
57
57
  docs/agent/generated/*.local.json
58
+ .academic-research/mcp/
58
59
  .env
59
60
  .env.*
60
61
  !.env.example
@@ -33,6 +33,7 @@ Do not commit filled `.env`, `.env.local`, tokens, cookies, or browser sessions.
33
33
  environment unless you explicitly pass `--env-file .env.local`.
34
34
 
35
35
  ```bash
36
+ npm run mcp:status
36
37
  npm run mcp:doctor -- --env-file .env.local
37
38
  npm run mcp:smoke -- --env-file .env.local
38
39
  npm run mcp:probe -- arxiv --timeout-ms 5000
@@ -54,14 +55,53 @@ client has its own secret store, prefer that store for API keys and tokens. If
54
55
  the client inherits shell environment variables, start it from a shell where the
55
56
  required variables are already exported.
56
57
 
58
+ Codex registration can be automated for servers with a generated command or
59
+ hosted URL:
60
+
61
+ ```bash
62
+ npm run mcp:client:add -- overleaf --agent codex
63
+ npm run mcp:client:remove -- overleaf --agent codex
64
+ ```
65
+
66
+ Use `--dry-run` to print the exact `codex mcp add` or `codex mcp remove`
67
+ command without changing Codex config. Secrets are not written to Codex config;
68
+ credentialed local integrations should use a wrapper that loads `.env.local` at
69
+ runtime. Overleaf client registration is intentionally blocked until
70
+ `npm run mcp:setup -- overleaf --mode local --env-file .env.local` has created
71
+ the wrapper and recorded non-secret setup facts.
72
+
73
+ Custom remote endpoints may use a stored URL or a URL env var name. Bearer token
74
+ support stores only the token env var name. Codex automatic registration
75
+ supports stored URL mode because Codex has `--url`:
76
+
77
+ ```bash
78
+ npm run mcp:enable -- openalex --mode remote-custom --url https://example.com/mcp --bearer-token-env-var OPENALEX_MCP_TOKEN
79
+ ```
80
+
81
+ If the endpoint URL is kept in an env var with `--url-env`, automatic Codex
82
+ registration is not available because the Codex CLI currently has no
83
+ `--url-env` option. Either re-enable the server with `--url <url>` if the
84
+ endpoint URL may be stored in Codex config, or manually register it from a shell
85
+ where the env var is set:
86
+
87
+ ```bash
88
+ codex mcp add openalex --url "$OPENALEX_MCP_URL"
89
+ ```
90
+
91
+ Claude Code, Cursor, and other clients may still require manual registration.
92
+ Use `npm run mcp:status` to see whether the selected server has a generated
93
+ snippet, a supported client registration path, and the next setup action.
94
+
57
95
  ## Workflow
58
96
 
59
97
  1. Enable only the MCP servers needed for the current research task.
60
98
  2. Inspect prerequisites with `npm run mcp:env -- <server>`.
61
99
  3. Put required secrets in the MCP client secret store, shell, or `.env.local`.
62
100
  4. Run `npm run mcp:smoke -- --env-file .env.local`.
63
- 5. Run `npm run mcp:probe -- <server>` only when you want to start
101
+ 5. Run `npm run mcp:status`.
102
+ 6. Register the selected server with the active client, or load the generated
103
+ snippet manually.
104
+ 7. Run `npm run mcp:probe -- <server>` only when you want to start
64
105
  the server and verify a real stdio handshake.
65
- 6. Load the generated snippet in the MCP client.
66
- 7. Treat MCP output as retrieval metadata until it is ingested into repository
106
+ 8. Treat MCP output as retrieval metadata until it is ingested into repository
67
107
  source records.
@@ -10,3 +10,63 @@ with `npm run mcp:dotenv`.
10
10
  Use `npm run mcp:doctor -- --env-file .env.local` when you want the CLI to read
11
11
  an explicit local env file. Use `npm run mcp:probe -- <server>` only when you
12
12
  want to start a selected MCP server and verify a real stdio handshake.
13
+
14
+ Use `npm run mcp:modes` to see what each integration supports. Use
15
+ `npm run mcp:status` to distinguish selected project records from operational
16
+ readiness. Default status uses friendly labels such as ready, not selected,
17
+ setup needed, missing env, probe needed, probe failed, local, remote, requires
18
+ local app, and manual setup.
19
+ Use `npm run mcp:status -- --verbose` when you need technical mode names,
20
+ snippet state, client registration state, and probe details.
21
+
22
+ `configs/capabilities.yaml` records intended project capability state.
23
+ `docs/agent/capability-lock.json` records non-secret observed setup facts for
24
+ MCP setup/client/probe actions and project-local skill operations. The scaffold
25
+ manifest at `.academic-research/managed-files.json` records non-secret
26
+ checksums used by `npm run update` to avoid overwriting local edits.
27
+
28
+ Mode labels:
29
+
30
+ - local: your machine runs the MCP server when the client needs it.
31
+ - remote: your client connects to an existing hosted MCP endpoint.
32
+ - custom remote: you provide the endpoint.
33
+ - requires local app: another app must be running, such as Zotero Desktop.
34
+ - manual setup: guided setup is required before client registration.
35
+
36
+ OpenAlex and PubMed support explicit local and remote modes:
37
+
38
+ ```bash
39
+ npm run mcp:enable -- openalex --mode remote
40
+ npm run mcp:enable -- pubmed --mode local
41
+ ```
42
+
43
+ Advanced custom remote endpoints are non-secret project facts. Store only the
44
+ URL or the env var name that contains the URL. Store token env var names, never
45
+ token values:
46
+
47
+ ```bash
48
+ npm run mcp:enable -- openalex --mode remote-custom --url https://example.com/mcp
49
+ npm run mcp:enable -- openalex --mode remote-custom --url-env OPENALEX_MCP_URL --bearer-token-env-var OPENALEX_MCP_TOKEN
50
+ ```
51
+
52
+ Codex automatic registration supports stored URL mode with `--url`. If the URL
53
+ is kept in an env var with `--url-env`, automatic Codex registration is not
54
+ available because the Codex CLI currently has no `--url-env` option. Manually
55
+ register from a shell where the env var is set, or re-enable with `--url <url>`
56
+ if the endpoint URL may be stored in Codex config.
57
+
58
+ `mcp smoke` checks custom remote URL env vars without launching a local server.
59
+ `mcp probe` does not perform network probes for remote endpoints; it reports a
60
+ remote configured status when the required endpoint configuration is present.
61
+ If you use `--mode remote-custom` without `--url` or `--url-env`, smoke and
62
+ probe report `missing-remote-url`.
63
+
64
+ Overleaf is a manual-local integration. Keep secrets in `.env.local`, then run
65
+ the setup command to create a local wrapper and non-secret capability lock:
66
+
67
+ ```bash
68
+ npm run mcp:env -- overleaf --dotenv
69
+ npm run mcp:setup -- overleaf --mode local --env-file .env.local
70
+ npm run mcp:client:add -- overleaf --agent codex --dry-run
71
+ npm run mcp:probe -- overleaf --env-file .env.local
72
+ ```