mdcontext 0.0.1 → 0.2.0
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/.changeset/README.md +28 -0
- package/.changeset/config.json +11 -0
- package/.claude/settings.local.json +25 -0
- package/.github/workflows/ci.yml +83 -0
- package/.github/workflows/claude-code-review.yml +44 -0
- package/.github/workflows/claude.yml +85 -0
- package/.github/workflows/release.yml +113 -0
- package/.tldrignore +112 -0
- package/BACKLOG.md +338 -0
- package/CONTRIBUTING.md +186 -0
- package/NOTES/NOTES +44 -0
- package/README.md +434 -11
- package/biome.json +36 -0
- package/cspell.config.yaml +14 -0
- package/dist/chunk-23UPXDNL.js +3044 -0
- package/dist/chunk-2W7MO2DL.js +1366 -0
- package/dist/chunk-3NUAZGMA.js +1689 -0
- package/dist/chunk-7TOWB2XB.js +366 -0
- package/dist/chunk-7XOTOADQ.js +3065 -0
- package/dist/chunk-AH2PDM2K.js +3042 -0
- package/dist/chunk-BNXWSZ63.js +3742 -0
- package/dist/chunk-BTL5DJVU.js +3222 -0
- package/dist/chunk-HDHYG7E4.js +104 -0
- package/dist/chunk-HLR4KZBP.js +3234 -0
- package/dist/chunk-IP3FRFEB.js +1045 -0
- package/dist/chunk-KHU56VDO.js +3042 -0
- package/dist/chunk-KRYIFLQR.js +88 -0
- package/dist/chunk-LBSDNLEM.js +287 -0
- package/dist/chunk-MNTQ7HCP.js +2643 -0
- package/dist/chunk-MUJELQQ6.js +1387 -0
- package/dist/chunk-MXJGMSLV.js +2199 -0
- package/dist/chunk-N6QJGC3Z.js +2636 -0
- package/dist/chunk-OBELGBPM.js +1713 -0
- package/dist/chunk-OT7R5XTA.js +3192 -0
- package/dist/chunk-P7X4RA2T.js +106 -0
- package/dist/chunk-PIDUQNC2.js +3185 -0
- package/dist/chunk-POGCDIH4.js +3187 -0
- package/dist/chunk-PSIEOQGZ.js +3043 -0
- package/dist/chunk-PVRT3IHA.js +3238 -0
- package/dist/chunk-QNN4TT23.js +1430 -0
- package/dist/chunk-RE3R45RJ.js +3042 -0
- package/dist/chunk-S7E6TFX6.js +803 -0
- package/dist/chunk-SG6GLU4U.js +1378 -0
- package/dist/chunk-SJCDV2ST.js +274 -0
- package/dist/chunk-SYE5XLF3.js +104 -0
- package/dist/chunk-T5VLYBZD.js +103 -0
- package/dist/chunk-TOQB7VWU.js +3238 -0
- package/dist/chunk-VFNMZ4ZQ.js +3228 -0
- package/dist/chunk-VVTGZNBT.js +1629 -0
- package/dist/chunk-W7Q4RFEV.js +104 -0
- package/dist/chunk-XTYYVRLO.js +3190 -0
- package/dist/chunk-Y6MDYVJD.js +3063 -0
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +5458 -0
- package/dist/index.d.ts +653 -0
- package/dist/index.js +79 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +472 -0
- package/dist/schema-BAWSG7KY.js +22 -0
- package/dist/schema-E3QUPL26.js +20 -0
- package/dist/schema-EHL7WUT6.js +20 -0
- package/docs/019-USAGE.md +625 -0
- package/docs/020-current-implementation.md +364 -0
- package/docs/021-DOGFOODING-FINDINGS.md +175 -0
- package/docs/BACKLOG.md +80 -0
- package/docs/CONFIG.md +1123 -0
- package/docs/DESIGN.md +439 -0
- package/docs/ERRORS.md +383 -0
- package/docs/PROJECT.md +88 -0
- package/docs/ROADMAP.md +407 -0
- package/docs/summarization.md +320 -0
- package/docs/test-links.md +9 -0
- package/justfile +40 -0
- package/package.json +74 -9
- package/pnpm-workspace.yaml +5 -0
- package/research/INDEX.md +315 -0
- package/research/code-review/README.md +90 -0
- package/research/code-review/cli-error-handling-review.md +979 -0
- package/research/code-review/code-review-validation-report.md +464 -0
- package/research/code-review/main-ts-review.md +1128 -0
- package/research/config-analysis/01-current-implementation.md +470 -0
- package/research/config-analysis/02-strategy-recommendation.md +428 -0
- package/research/config-analysis/03-task-candidates.md +715 -0
- package/research/config-analysis/033-research-configuration-management.md +828 -0
- package/research/config-analysis/034-research-effect-cli-config.md +1504 -0
- package/research/config-analysis/04-consolidated-task-candidates.md +277 -0
- package/research/config-docs/SUMMARY.md +357 -0
- package/research/config-docs/TEST-RESULTS.md +776 -0
- package/research/config-docs/TODO.md +542 -0
- package/research/config-docs/analysis.md +744 -0
- package/research/config-docs/fix-validation.md +502 -0
- package/research/config-docs/help-audit.md +264 -0
- package/research/config-docs/help-system-analysis.md +890 -0
- package/research/dogfood/consolidated-tool-evaluation.md +373 -0
- package/research/dogfood/strategy-a/a-synthesis.md +184 -0
- package/research/dogfood/strategy-a/a1-docs.md +226 -0
- package/research/dogfood/strategy-a/a2-amorphic.md +156 -0
- package/research/dogfood/strategy-a/a3-llm.md +164 -0
- package/research/dogfood/strategy-b/b-synthesis.md +228 -0
- package/research/dogfood/strategy-b/b1-architecture.md +207 -0
- package/research/dogfood/strategy-b/b2-gaps.md +258 -0
- package/research/dogfood/strategy-b/b3-workflows.md +250 -0
- package/research/dogfood/strategy-c/c-synthesis.md +451 -0
- package/research/dogfood/strategy-c/c1-explorer.md +192 -0
- package/research/dogfood/strategy-c/c2-diver-memory.md +145 -0
- package/research/dogfood/strategy-c/c3-diver-control.md +148 -0
- package/research/dogfood/strategy-c/c4-diver-failure.md +151 -0
- package/research/dogfood/strategy-c/c5-diver-execution.md +221 -0
- package/research/dogfood/strategy-c/c6-diver-org.md +221 -0
- package/research/effect-cli-error-handling.md +845 -0
- package/research/effect-errors-as-values.md +943 -0
- package/research/errors-task-analysis/00-consolidated-tasks.md +207 -0
- package/research/errors-task-analysis/cli-commands-analysis.md +909 -0
- package/research/errors-task-analysis/embeddings-analysis.md +709 -0
- package/research/errors-task-analysis/index-search-analysis.md +812 -0
- package/research/frontmatter/COMMENTS-ARE-SKIPPED.md +149 -0
- package/research/frontmatter/LLM-CODE-NAVIGATION.md +276 -0
- package/research/issue-review.md +603 -0
- package/research/llm-summarization/agent-cli-tools-2026.md +1082 -0
- package/research/llm-summarization/alternative-providers-2026.md +1428 -0
- package/research/llm-summarization/anthropic-2026.md +367 -0
- package/research/llm-summarization/claude-cli-integration.md +1706 -0
- package/research/llm-summarization/cli-integration-patterns.md +3155 -0
- package/research/llm-summarization/openai-2026.md +473 -0
- package/research/llm-summarization/openai-compatible-providers-2026.md +1022 -0
- package/research/llm-summarization/opencode-cli-integration.md +1552 -0
- package/research/llm-summarization/prompt-engineering-2026.md +1426 -0
- package/research/llm-summarization/prototype-results.md +56 -0
- package/research/llm-summarization/provider-switching-patterns-2026.md +2153 -0
- package/research/llm-summarization/typescript-llm-libraries-2026.md +2436 -0
- package/research/mdcontext-error-analysis.md +521 -0
- package/research/mdcontext-pudding/00-EXECUTIVE-SUMMARY.md +282 -0
- package/research/mdcontext-pudding/01-index-embed.md +956 -0
- package/research/mdcontext-pudding/02-search-COMMANDS.md +142 -0
- package/research/mdcontext-pudding/02-search-SUMMARY.md +146 -0
- package/research/mdcontext-pudding/02-search.md +970 -0
- package/research/mdcontext-pudding/03-context.md +779 -0
- package/research/mdcontext-pudding/04-navigation-and-analytics.md +803 -0
- package/research/mdcontext-pudding/04-tree.md +704 -0
- package/research/mdcontext-pudding/05-config.md +1038 -0
- package/research/mdcontext-pudding/06-links-summary.txt +87 -0
- package/research/mdcontext-pudding/06-links.md +679 -0
- package/research/mdcontext-pudding/07-stats.md +693 -0
- package/research/mdcontext-pudding/BUG-FIX-PLAN.md +388 -0
- package/research/mdcontext-pudding/P0-BUG-VALIDATION.md +167 -0
- package/research/mdcontext-pudding/README.md +168 -0
- package/research/mdcontext-pudding/TESTING-SUMMARY.md +128 -0
- package/research/npm_publish/011-npm-workflow-research-agent2.md +792 -0
- package/research/npm_publish/012-npm-workflow-research-agent1.md +530 -0
- package/research/npm_publish/013-npm-workflow-research-agent3.md +722 -0
- package/research/npm_publish/014-npm-workflow-synthesis.md +556 -0
- package/research/npm_publish/031-npm-workflow-task-analysis.md +134 -0
- package/research/research-quality-review.md +834 -0
- package/research/semantic-search/002-research-embedding-models.md +490 -0
- package/research/semantic-search/003-research-rag-alternatives.md +523 -0
- package/research/semantic-search/004-research-vector-search.md +841 -0
- package/research/semantic-search/032-research-semantic-search.md +427 -0
- package/research/semantic-search/embedding-text-analysis.md +156 -0
- package/research/semantic-search/multi-word-failure-reproduction.md +171 -0
- package/research/semantic-search/query-processing-analysis.md +207 -0
- package/research/semantic-search/root-cause-and-solution.md +114 -0
- package/research/semantic-search/threshold-validation-report.md +69 -0
- package/research/semantic-search/vector-search-analysis.md +63 -0
- package/research/task-management-2026/00-synthesis-recommendations.md +295 -0
- package/research/task-management-2026/01-ai-workflow-tools.md +416 -0
- package/research/task-management-2026/02-agent-framework-patterns.md +476 -0
- package/research/task-management-2026/03-lightweight-file-based.md +567 -0
- package/research/task-management-2026/04-established-tools-ai-features.md +541 -0
- package/research/task-management-2026/linear/01-core-features-workflow.md +771 -0
- package/research/task-management-2026/linear/02-api-integrations.md +930 -0
- package/research/task-management-2026/linear/03-ai-features.md +368 -0
- package/research/task-management-2026/linear/04-pricing-setup.md +205 -0
- package/research/task-management-2026/linear/05-usage-patterns-best-practices.md +605 -0
- package/research/test-path-issues.md +276 -0
- package/review/ALP-76/1-error-type-design.md +962 -0
- package/review/ALP-76/2-error-handling-patterns.md +906 -0
- package/review/ALP-76/3-error-presentation.md +624 -0
- package/review/ALP-76/4-test-coverage.md +625 -0
- package/review/ALP-76/5-migration-completeness.md +440 -0
- package/review/ALP-76/6-effect-best-practices.md +755 -0
- package/scripts/apply-branch-protection.sh +47 -0
- package/scripts/branch-protection-templates.json +79 -0
- package/scripts/prototype-summarization.ts +346 -0
- package/scripts/rebuild-hnswlib.js +58 -0
- package/scripts/setup-branch-protection.sh +64 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/active-provider.json +7 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.json +541 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/bm25.meta.json +5 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/config.json +8 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/documents.json +60 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/links.json +13 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/.mdcontext/indexes/sections.json +1197 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/configuration-management.md +99 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/distributed-systems.md +92 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/error-handling.md +78 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/failure-automation.md +55 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/job-context.md +69 -0
- package/src/__tests__/fixtures/semantic-search/multi-word-corpus/process-orchestration.md +99 -0
- package/src/cli/argv-preprocessor.test.ts +210 -0
- package/src/cli/argv-preprocessor.ts +202 -0
- package/src/cli/cli.test.ts +627 -0
- package/src/cli/commands/backlinks.ts +54 -0
- package/src/cli/commands/config-cmd.ts +642 -0
- package/src/cli/commands/context.ts +285 -0
- package/src/cli/commands/duplicates.ts +122 -0
- package/src/cli/commands/embeddings.ts +529 -0
- package/src/cli/commands/index-cmd.ts +480 -0
- package/src/cli/commands/index.ts +16 -0
- package/src/cli/commands/links.ts +52 -0
- package/src/cli/commands/search.ts +1281 -0
- package/src/cli/commands/stats.ts +149 -0
- package/src/cli/commands/tree.ts +128 -0
- package/src/cli/config-layer.ts +176 -0
- package/src/cli/error-handler.test.ts +235 -0
- package/src/cli/error-handler.ts +655 -0
- package/src/cli/flag-schemas.ts +341 -0
- package/src/cli/help.ts +588 -0
- package/src/cli/index.ts +9 -0
- package/src/cli/main.ts +435 -0
- package/src/cli/options.ts +41 -0
- package/src/cli/shared-error-handling.ts +199 -0
- package/src/cli/typo-suggester.test.ts +105 -0
- package/src/cli/typo-suggester.ts +130 -0
- package/src/cli/utils.ts +259 -0
- package/src/config/file-provider.test.ts +320 -0
- package/src/config/file-provider.ts +273 -0
- package/src/config/index.ts +72 -0
- package/src/config/integration.test.ts +667 -0
- package/src/config/precedence.test.ts +277 -0
- package/src/config/precedence.ts +451 -0
- package/src/config/schema.test.ts +414 -0
- package/src/config/schema.ts +603 -0
- package/src/config/service.test.ts +320 -0
- package/src/config/service.ts +243 -0
- package/src/config/testing.test.ts +264 -0
- package/src/config/testing.ts +110 -0
- package/src/core/index.ts +1 -0
- package/src/core/types.ts +113 -0
- package/src/duplicates/detector.test.ts +183 -0
- package/src/duplicates/detector.ts +414 -0
- package/src/duplicates/index.ts +18 -0
- package/src/embeddings/embedding-namespace.test.ts +300 -0
- package/src/embeddings/embedding-namespace.ts +947 -0
- package/src/embeddings/heading-boost.test.ts +222 -0
- package/src/embeddings/hnsw-build-options.test.ts +198 -0
- package/src/embeddings/hyde.test.ts +272 -0
- package/src/embeddings/hyde.ts +264 -0
- package/src/embeddings/index.ts +10 -0
- package/src/embeddings/openai-provider.ts +414 -0
- package/src/embeddings/pricing.json +22 -0
- package/src/embeddings/provider-constants.ts +204 -0
- package/src/embeddings/provider-errors.test.ts +967 -0
- package/src/embeddings/provider-errors.ts +565 -0
- package/src/embeddings/provider-factory.test.ts +240 -0
- package/src/embeddings/provider-factory.ts +225 -0
- package/src/embeddings/provider-integration.test.ts +788 -0
- package/src/embeddings/query-preprocessing.test.ts +187 -0
- package/src/embeddings/semantic-search-threshold.test.ts +508 -0
- package/src/embeddings/semantic-search.ts +1270 -0
- package/src/embeddings/types.ts +359 -0
- package/src/embeddings/vector-store.ts +708 -0
- package/src/embeddings/voyage-provider.ts +313 -0
- package/src/errors/errors.test.ts +845 -0
- package/src/errors/index.ts +533 -0
- package/src/index/ignore-patterns.test.ts +354 -0
- package/src/index/ignore-patterns.ts +305 -0
- package/src/index/index.ts +4 -0
- package/src/index/indexer.ts +684 -0
- package/src/index/storage.ts +260 -0
- package/src/index/types.ts +147 -0
- package/src/index/watcher.ts +189 -0
- package/src/index.ts +30 -0
- package/src/integration/search-keyword.test.ts +678 -0
- package/src/mcp/server.ts +612 -0
- package/src/parser/index.ts +1 -0
- package/src/parser/parser.test.ts +291 -0
- package/src/parser/parser.ts +394 -0
- package/src/parser/section-filter.test.ts +277 -0
- package/src/parser/section-filter.ts +392 -0
- package/src/search/__tests__/hybrid-search.test.ts +650 -0
- package/src/search/bm25-store.ts +366 -0
- package/src/search/cross-encoder.test.ts +253 -0
- package/src/search/cross-encoder.ts +406 -0
- package/src/search/fuzzy-search.test.ts +419 -0
- package/src/search/fuzzy-search.ts +273 -0
- package/src/search/hybrid-search.ts +448 -0
- package/src/search/path-matcher.test.ts +276 -0
- package/src/search/path-matcher.ts +33 -0
- package/src/search/query-parser.test.ts +260 -0
- package/src/search/query-parser.ts +319 -0
- package/src/search/searcher.test.ts +280 -0
- package/src/search/searcher.ts +724 -0
- package/src/search/wink-bm25.d.ts +30 -0
- package/src/summarization/cli-providers/claude.ts +202 -0
- package/src/summarization/cli-providers/detection.test.ts +273 -0
- package/src/summarization/cli-providers/detection.ts +118 -0
- package/src/summarization/cli-providers/index.ts +8 -0
- package/src/summarization/cost.test.ts +139 -0
- package/src/summarization/cost.ts +102 -0
- package/src/summarization/error-handler.test.ts +127 -0
- package/src/summarization/error-handler.ts +111 -0
- package/src/summarization/index.ts +102 -0
- package/src/summarization/pipeline.test.ts +498 -0
- package/src/summarization/pipeline.ts +231 -0
- package/src/summarization/prompts.test.ts +269 -0
- package/src/summarization/prompts.ts +133 -0
- package/src/summarization/provider-factory.test.ts +396 -0
- package/src/summarization/provider-factory.ts +178 -0
- package/src/summarization/types.ts +184 -0
- package/src/summarize/budget-bugs.test.ts +620 -0
- package/src/summarize/formatters.ts +419 -0
- package/src/summarize/index.ts +20 -0
- package/src/summarize/summarizer.test.ts +275 -0
- package/src/summarize/summarizer.ts +597 -0
- package/src/summarize/verify-bugs.test.ts +238 -0
- package/src/types/huggingface-transformers.d.ts +66 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/tokens.test.ts +142 -0
- package/src/utils/tokens.ts +186 -0
- package/tests/fixtures/cli/.mdcontext/active-provider.json +7 -0
- package/tests/fixtures/cli/.mdcontext/config.json +8 -0
- package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/embeddings/openai_text-embedding-3-small_512/vectors.meta.bin +0 -0
- package/tests/fixtures/cli/.mdcontext/indexes/documents.json +33 -0
- package/tests/fixtures/cli/.mdcontext/indexes/links.json +12 -0
- package/tests/fixtures/cli/.mdcontext/indexes/sections.json +247 -0
- package/tests/fixtures/cli/README.md +9 -0
- package/tests/fixtures/cli/api-reference.md +11 -0
- package/tests/fixtures/cli/getting-started.md +11 -0
- package/tests/integration/embed-index.test.ts +712 -0
- package/tests/integration/search-context.test.ts +469 -0
- package/tests/integration/search-semantic.test.ts +522 -0
- package/tsconfig.json +26 -0
- package/vitest.config.ts +16 -0
- package/vitest.setup.ts +12 -0
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCP Server for mdcontext
|
|
5
|
+
*
|
|
6
|
+
* Exposes markdown analysis tools for Claude integration
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createRequire } from 'node:module'
|
|
10
|
+
import * as path from 'node:path'
|
|
11
|
+
|
|
12
|
+
// Read version from package.json using createRequire for ESM compatibility
|
|
13
|
+
const require = createRequire(import.meta.url)
|
|
14
|
+
const packageJson = require('../../package.json') as { version: string }
|
|
15
|
+
const MCP_VERSION: string = packageJson.version
|
|
16
|
+
|
|
17
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
|
|
18
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
19
|
+
import type { CallToolResult, Tool } from '@modelcontextprotocol/sdk/types.js'
|
|
20
|
+
import {
|
|
21
|
+
CallToolRequestSchema,
|
|
22
|
+
ListToolsRequestSchema,
|
|
23
|
+
} from '@modelcontextprotocol/sdk/types.js'
|
|
24
|
+
import { Effect } from 'effect'
|
|
25
|
+
import type { MdSection } from '../core/types.js'
|
|
26
|
+
import { semanticSearch } from '../embeddings/semantic-search.js'
|
|
27
|
+
import {
|
|
28
|
+
buildIndex,
|
|
29
|
+
getIncomingLinks,
|
|
30
|
+
getOutgoingLinks,
|
|
31
|
+
} from '../index/indexer.js'
|
|
32
|
+
import { parseFile } from '../parser/parser.js'
|
|
33
|
+
import { search } from '../search/searcher.js'
|
|
34
|
+
import { formatSummary, summarizeFile } from '../summarize/summarizer.js'
|
|
35
|
+
|
|
36
|
+
// Type alias for tool results - uses the SDK type
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Tool Definitions
|
|
40
|
+
// ============================================================================
|
|
41
|
+
|
|
42
|
+
const tools: Tool[] = [
|
|
43
|
+
{
|
|
44
|
+
name: 'md_search',
|
|
45
|
+
description:
|
|
46
|
+
'Search markdown documents by meaning using semantic search. Returns relevant sections based on natural language queries.',
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
query: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description: 'Natural language search query',
|
|
53
|
+
},
|
|
54
|
+
limit: {
|
|
55
|
+
type: 'number',
|
|
56
|
+
description: 'Maximum number of results (default: 5)',
|
|
57
|
+
default: 5,
|
|
58
|
+
},
|
|
59
|
+
path_filter: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
description:
|
|
62
|
+
"Glob pattern to filter files (e.g., '*.md', 'docs/**/*.md')",
|
|
63
|
+
},
|
|
64
|
+
threshold: {
|
|
65
|
+
type: 'number',
|
|
66
|
+
description: 'Minimum similarity threshold 0-1 (default: 0.35)',
|
|
67
|
+
default: 0.35,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
required: ['query'],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'md_context',
|
|
75
|
+
description:
|
|
76
|
+
'Get LLM-ready context from a markdown file. Provides compressed, token-efficient summaries at various detail levels.',
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: 'object',
|
|
79
|
+
properties: {
|
|
80
|
+
path: {
|
|
81
|
+
type: 'string',
|
|
82
|
+
description: 'Path to the markdown file',
|
|
83
|
+
},
|
|
84
|
+
level: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
enum: ['full', 'summary', 'brief'],
|
|
87
|
+
description: 'Compression level (default: summary)',
|
|
88
|
+
default: 'summary',
|
|
89
|
+
},
|
|
90
|
+
max_tokens: {
|
|
91
|
+
type: 'number',
|
|
92
|
+
description: 'Maximum tokens to include in output',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
required: ['path'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'md_structure',
|
|
100
|
+
description:
|
|
101
|
+
'Get the structure/outline of a markdown file. Shows heading hierarchy with token counts.',
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
properties: {
|
|
105
|
+
path: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
description: 'Path to the markdown file',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
required: ['path'],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'md_keyword_search',
|
|
115
|
+
description:
|
|
116
|
+
'Search markdown documents by keyword search (headings, code blocks, lists, tables).',
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: 'object',
|
|
119
|
+
properties: {
|
|
120
|
+
heading: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
description: 'Filter by heading pattern (regex)',
|
|
123
|
+
},
|
|
124
|
+
path_filter: {
|
|
125
|
+
type: 'string',
|
|
126
|
+
description: 'Glob pattern to filter files',
|
|
127
|
+
},
|
|
128
|
+
has_code: {
|
|
129
|
+
type: 'boolean',
|
|
130
|
+
description: 'Only sections with code blocks',
|
|
131
|
+
},
|
|
132
|
+
has_list: {
|
|
133
|
+
type: 'boolean',
|
|
134
|
+
description: 'Only sections with lists',
|
|
135
|
+
},
|
|
136
|
+
has_table: {
|
|
137
|
+
type: 'boolean',
|
|
138
|
+
description: 'Only sections with tables',
|
|
139
|
+
},
|
|
140
|
+
limit: {
|
|
141
|
+
type: 'number',
|
|
142
|
+
description: 'Maximum results (default: 20)',
|
|
143
|
+
default: 20,
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'md_index',
|
|
150
|
+
description:
|
|
151
|
+
'Build or rebuild the index for a directory. Required before using search tools.',
|
|
152
|
+
inputSchema: {
|
|
153
|
+
type: 'object',
|
|
154
|
+
properties: {
|
|
155
|
+
path: {
|
|
156
|
+
type: 'string',
|
|
157
|
+
description: 'Directory to index (default: current directory)',
|
|
158
|
+
default: '.',
|
|
159
|
+
},
|
|
160
|
+
force: {
|
|
161
|
+
type: 'boolean',
|
|
162
|
+
description: 'Force full rebuild (default: false)',
|
|
163
|
+
default: false,
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'md_links',
|
|
170
|
+
description:
|
|
171
|
+
'Get outgoing links from a markdown file. Shows what files this document references/links to.',
|
|
172
|
+
inputSchema: {
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {
|
|
175
|
+
path: {
|
|
176
|
+
type: 'string',
|
|
177
|
+
description: 'Path to the markdown file',
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
required: ['path'],
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: 'md_backlinks',
|
|
185
|
+
description:
|
|
186
|
+
'Get incoming links to a markdown file. Shows what files reference/link to this document.',
|
|
187
|
+
inputSchema: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
path: {
|
|
191
|
+
type: 'string',
|
|
192
|
+
description: 'Path to the markdown file',
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
required: ['path'],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
]
|
|
199
|
+
|
|
200
|
+
// ============================================================================
|
|
201
|
+
// Tool Handlers
|
|
202
|
+
// ============================================================================
|
|
203
|
+
|
|
204
|
+
const handleMdSearch = async (
|
|
205
|
+
args: Record<string, unknown>,
|
|
206
|
+
rootPath: string,
|
|
207
|
+
): Promise<CallToolResult> => {
|
|
208
|
+
const query = args.query as string
|
|
209
|
+
const limit = (args.limit as number) ?? 5
|
|
210
|
+
const pathFilter = args.path_filter as string | undefined
|
|
211
|
+
const threshold = (args.threshold as number) ?? 0.35
|
|
212
|
+
|
|
213
|
+
// Note: catchAll is intentional at this MCP boundary layer.
|
|
214
|
+
// MCP protocol requires JSON error responses, so we convert typed errors
|
|
215
|
+
// to { error: message } format for protocol compliance.
|
|
216
|
+
const result = await Effect.runPromise(
|
|
217
|
+
semanticSearch(rootPath, query, {
|
|
218
|
+
limit,
|
|
219
|
+
threshold,
|
|
220
|
+
pathPattern: pathFilter,
|
|
221
|
+
}).pipe(
|
|
222
|
+
Effect.catchAll((e) => Effect.succeed([{ error: e.message }] as const)),
|
|
223
|
+
),
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
if (Array.isArray(result) && result.length > 0 && 'error' in result[0]) {
|
|
227
|
+
return {
|
|
228
|
+
content: [
|
|
229
|
+
{
|
|
230
|
+
type: 'text',
|
|
231
|
+
text: `Error: ${(result[0] as { error: string }).error}`,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
isError: true,
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const formattedResults = (
|
|
239
|
+
result as Array<{
|
|
240
|
+
sectionId: string
|
|
241
|
+
documentPath: string
|
|
242
|
+
heading: string
|
|
243
|
+
similarity: number
|
|
244
|
+
}>
|
|
245
|
+
).map((r, i) => {
|
|
246
|
+
const similarity = (r.similarity * 100).toFixed(1)
|
|
247
|
+
return `${i + 1}. **${r.heading}** (${similarity}% match)\n ${r.documentPath}`
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
content: [
|
|
252
|
+
{
|
|
253
|
+
type: 'text',
|
|
254
|
+
text:
|
|
255
|
+
formattedResults.length > 0
|
|
256
|
+
? `Found ${formattedResults.length} results for "${query}":\n\n${formattedResults.join('\n\n')}`
|
|
257
|
+
: `No results found for "${query}"`,
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const handleMdContext = async (
|
|
264
|
+
args: Record<string, unknown>,
|
|
265
|
+
rootPath: string,
|
|
266
|
+
): Promise<CallToolResult> => {
|
|
267
|
+
const filePath = args.path as string
|
|
268
|
+
const level = (args.level as 'brief' | 'summary' | 'full') ?? 'summary'
|
|
269
|
+
const maxTokens = args.max_tokens as number | undefined
|
|
270
|
+
|
|
271
|
+
const resolvedPath = path.isAbsolute(filePath)
|
|
272
|
+
? filePath
|
|
273
|
+
: path.join(rootPath, filePath)
|
|
274
|
+
|
|
275
|
+
// Note: catchAll is intentional - MCP boundary converts errors to JSON format
|
|
276
|
+
const result = await Effect.runPromise(
|
|
277
|
+
summarizeFile(resolvedPath, { level, maxTokens }).pipe(
|
|
278
|
+
Effect.catchAll((e) => Effect.succeed({ error: e.message })),
|
|
279
|
+
),
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
if ('error' in result) {
|
|
283
|
+
return {
|
|
284
|
+
content: [{ type: 'text', text: `Error: ${result.error}` }],
|
|
285
|
+
isError: true,
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
content: [{ type: 'text', text: formatSummary(result) }],
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const handleMdStructure = async (
|
|
295
|
+
args: Record<string, unknown>,
|
|
296
|
+
rootPath: string,
|
|
297
|
+
): Promise<CallToolResult> => {
|
|
298
|
+
const filePath = args.path as string
|
|
299
|
+
const resolvedPath = path.isAbsolute(filePath)
|
|
300
|
+
? filePath
|
|
301
|
+
: path.join(rootPath, filePath)
|
|
302
|
+
|
|
303
|
+
// Note: catchAll is intentional - MCP boundary converts errors to JSON format
|
|
304
|
+
const result = await Effect.runPromise(
|
|
305
|
+
parseFile(resolvedPath).pipe(
|
|
306
|
+
Effect.catchAll((e) => Effect.succeed({ error: e.message })),
|
|
307
|
+
),
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
if ('error' in result) {
|
|
311
|
+
return {
|
|
312
|
+
content: [{ type: 'text', text: `Error: ${result.error}` }],
|
|
313
|
+
isError: true,
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const formatSection = (section: MdSection, depth: number = 0): string => {
|
|
318
|
+
const indent = ' '.repeat(depth)
|
|
319
|
+
const marker = '#'.repeat(section.level)
|
|
320
|
+
const meta: string[] = []
|
|
321
|
+
if (section.metadata.hasCode) meta.push('code')
|
|
322
|
+
if (section.metadata.hasList) meta.push('list')
|
|
323
|
+
if (section.metadata.hasTable) meta.push('table')
|
|
324
|
+
const metaStr = meta.length > 0 ? ` [${meta.join(', ')}]` : ''
|
|
325
|
+
|
|
326
|
+
let output = `${indent}${marker} ${section.heading}${metaStr} (${section.metadata.tokenCount} tokens)\n`
|
|
327
|
+
|
|
328
|
+
for (const child of section.children) {
|
|
329
|
+
output += formatSection(child, depth + 1)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return output
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const structure = result.sections.map((s) => formatSection(s)).join('')
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
content: [
|
|
339
|
+
{
|
|
340
|
+
type: 'text',
|
|
341
|
+
text: `# ${result.title}\nPath: ${result.path}\nTotal tokens: ${result.metadata.tokenCount}\n\n${structure}`,
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const handleMdKeywordSearch = async (
|
|
348
|
+
args: Record<string, unknown>,
|
|
349
|
+
rootPath: string,
|
|
350
|
+
): Promise<CallToolResult> => {
|
|
351
|
+
const heading = args.heading as string | undefined
|
|
352
|
+
const pathFilter = args.path_filter as string | undefined
|
|
353
|
+
const hasCode = args.has_code as boolean | undefined
|
|
354
|
+
const hasList = args.has_list as boolean | undefined
|
|
355
|
+
const hasTable = args.has_table as boolean | undefined
|
|
356
|
+
const limit = (args.limit as number) ?? 20
|
|
357
|
+
|
|
358
|
+
// Note: catchAll is intentional - MCP boundary converts errors to JSON format
|
|
359
|
+
const result = await Effect.runPromise(
|
|
360
|
+
search(rootPath, {
|
|
361
|
+
heading,
|
|
362
|
+
pathPattern: pathFilter,
|
|
363
|
+
hasCode,
|
|
364
|
+
hasList,
|
|
365
|
+
hasTable,
|
|
366
|
+
limit,
|
|
367
|
+
}).pipe(
|
|
368
|
+
Effect.catchAll((e) => Effect.succeed([{ error: e.message }] as const)),
|
|
369
|
+
),
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
if (Array.isArray(result) && result.length > 0 && 'error' in result[0]) {
|
|
373
|
+
return {
|
|
374
|
+
content: [
|
|
375
|
+
{
|
|
376
|
+
type: 'text',
|
|
377
|
+
text: `Error: ${(result[0] as { error: string }).error}`,
|
|
378
|
+
},
|
|
379
|
+
],
|
|
380
|
+
isError: true,
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const formattedResults = (
|
|
385
|
+
result as Array<{
|
|
386
|
+
section: {
|
|
387
|
+
heading: string
|
|
388
|
+
level: number
|
|
389
|
+
documentPath: string
|
|
390
|
+
tokenCount: number
|
|
391
|
+
hasCode: boolean
|
|
392
|
+
hasList: boolean
|
|
393
|
+
hasTable: boolean
|
|
394
|
+
}
|
|
395
|
+
}>
|
|
396
|
+
).map((r, i) => {
|
|
397
|
+
const meta: string[] = []
|
|
398
|
+
if (r.section.hasCode) meta.push('code')
|
|
399
|
+
if (r.section.hasList) meta.push('list')
|
|
400
|
+
if (r.section.hasTable) meta.push('table')
|
|
401
|
+
const metaStr = meta.length > 0 ? ` [${meta.join(', ')}]` : ''
|
|
402
|
+
|
|
403
|
+
return `${i + 1}. **${r.section.heading}**${metaStr}\n ${r.section.documentPath} (${r.section.tokenCount} tokens)`
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
return {
|
|
407
|
+
content: [
|
|
408
|
+
{
|
|
409
|
+
type: 'text',
|
|
410
|
+
text:
|
|
411
|
+
formattedResults.length > 0
|
|
412
|
+
? `Found ${formattedResults.length} sections:\n\n${formattedResults.join('\n\n')}`
|
|
413
|
+
: 'No sections found matching criteria',
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const handleMdIndex = async (
|
|
420
|
+
args: Record<string, unknown>,
|
|
421
|
+
rootPath: string,
|
|
422
|
+
): Promise<CallToolResult> => {
|
|
423
|
+
const indexPath = (args.path as string) ?? '.'
|
|
424
|
+
const force = (args.force as boolean) ?? false
|
|
425
|
+
|
|
426
|
+
const resolvedPath = path.isAbsolute(indexPath)
|
|
427
|
+
? indexPath
|
|
428
|
+
: path.join(rootPath, indexPath)
|
|
429
|
+
|
|
430
|
+
// Note: catchAll is intentional - MCP boundary converts errors to JSON format
|
|
431
|
+
const result = await Effect.runPromise(
|
|
432
|
+
buildIndex(resolvedPath, { force }).pipe(
|
|
433
|
+
Effect.catchAll((e) => Effect.succeed({ error: e.message })),
|
|
434
|
+
),
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
if ('error' in result) {
|
|
438
|
+
return {
|
|
439
|
+
content: [{ type: 'text', text: `Error: ${result.error}` }],
|
|
440
|
+
isError: true,
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return {
|
|
445
|
+
content: [
|
|
446
|
+
{
|
|
447
|
+
type: 'text',
|
|
448
|
+
text: `Indexed ${result.documentsIndexed} documents, ${result.sectionsIndexed} sections, ${result.linksIndexed} links in ${result.duration}ms`,
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const handleMdLinks = async (
|
|
455
|
+
args: Record<string, unknown>,
|
|
456
|
+
rootPath: string,
|
|
457
|
+
): Promise<CallToolResult> => {
|
|
458
|
+
const filePath = args.path as string
|
|
459
|
+
const resolvedPath = path.isAbsolute(filePath)
|
|
460
|
+
? filePath
|
|
461
|
+
: path.join(rootPath, filePath)
|
|
462
|
+
|
|
463
|
+
// Note: catchAll is intentional - MCP boundary converts errors to JSON format
|
|
464
|
+
const result = await Effect.runPromise(
|
|
465
|
+
getOutgoingLinks(rootPath, resolvedPath).pipe(
|
|
466
|
+
Effect.catchAll((e) => Effect.succeed({ error: e.message })),
|
|
467
|
+
),
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
if ('error' in result) {
|
|
471
|
+
return {
|
|
472
|
+
content: [{ type: 'text', text: `Error: ${result.error}` }],
|
|
473
|
+
isError: true,
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const links = result as readonly string[]
|
|
478
|
+
const relativePath = path.relative(rootPath, resolvedPath)
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
content: [
|
|
482
|
+
{
|
|
483
|
+
type: 'text',
|
|
484
|
+
text:
|
|
485
|
+
links.length > 0
|
|
486
|
+
? `Outgoing links from ${relativePath}:\n\n${links.map((l) => ` -> ${l}`).join('\n')}\n\nTotal: ${links.length} links`
|
|
487
|
+
: `No outgoing links from ${relativePath}`,
|
|
488
|
+
},
|
|
489
|
+
],
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const handleMdBacklinks = async (
|
|
494
|
+
args: Record<string, unknown>,
|
|
495
|
+
rootPath: string,
|
|
496
|
+
): Promise<CallToolResult> => {
|
|
497
|
+
const filePath = args.path as string
|
|
498
|
+
const resolvedPath = path.isAbsolute(filePath)
|
|
499
|
+
? filePath
|
|
500
|
+
: path.join(rootPath, filePath)
|
|
501
|
+
|
|
502
|
+
// Note: catchAll is intentional - MCP boundary converts errors to JSON format
|
|
503
|
+
const result = await Effect.runPromise(
|
|
504
|
+
getIncomingLinks(rootPath, resolvedPath).pipe(
|
|
505
|
+
Effect.catchAll((e) => Effect.succeed({ error: e.message })),
|
|
506
|
+
),
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
if ('error' in result) {
|
|
510
|
+
return {
|
|
511
|
+
content: [{ type: 'text', text: `Error: ${result.error}` }],
|
|
512
|
+
isError: true,
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const links = result as readonly string[]
|
|
517
|
+
const relativePath = path.relative(rootPath, resolvedPath)
|
|
518
|
+
|
|
519
|
+
return {
|
|
520
|
+
content: [
|
|
521
|
+
{
|
|
522
|
+
type: 'text',
|
|
523
|
+
text:
|
|
524
|
+
links.length > 0
|
|
525
|
+
? `Incoming links to ${relativePath}:\n\n${links.map((l) => ` <- ${l}`).join('\n')}\n\nTotal: ${links.length} backlinks`
|
|
526
|
+
: `No incoming links to ${relativePath}`,
|
|
527
|
+
},
|
|
528
|
+
],
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ============================================================================
|
|
533
|
+
// MCP Server Setup
|
|
534
|
+
// ============================================================================
|
|
535
|
+
|
|
536
|
+
const createServer = (rootPath: string) => {
|
|
537
|
+
const server = new Server(
|
|
538
|
+
{
|
|
539
|
+
name: 'mdcontext-mcp',
|
|
540
|
+
version: MCP_VERSION,
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
capabilities: {
|
|
544
|
+
tools: {},
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
// List available tools
|
|
550
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
551
|
+
tools,
|
|
552
|
+
}))
|
|
553
|
+
|
|
554
|
+
// Handle tool calls
|
|
555
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
556
|
+
const { name, arguments: args } = request.params
|
|
557
|
+
|
|
558
|
+
switch (name) {
|
|
559
|
+
case 'md_search':
|
|
560
|
+
return handleMdSearch(args ?? {}, rootPath)
|
|
561
|
+
case 'md_context':
|
|
562
|
+
return handleMdContext(args ?? {}, rootPath)
|
|
563
|
+
case 'md_structure':
|
|
564
|
+
return handleMdStructure(args ?? {}, rootPath)
|
|
565
|
+
case 'md_keyword_search':
|
|
566
|
+
return handleMdKeywordSearch(args ?? {}, rootPath)
|
|
567
|
+
case 'md_index':
|
|
568
|
+
return handleMdIndex(args ?? {}, rootPath)
|
|
569
|
+
case 'md_links':
|
|
570
|
+
return handleMdLinks(args ?? {}, rootPath)
|
|
571
|
+
case 'md_backlinks':
|
|
572
|
+
return handleMdBacklinks(args ?? {}, rootPath)
|
|
573
|
+
default:
|
|
574
|
+
return {
|
|
575
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
|
|
576
|
+
isError: true,
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
return server
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// ============================================================================
|
|
585
|
+
// Main Entry
|
|
586
|
+
// ============================================================================
|
|
587
|
+
|
|
588
|
+
const main = async () => {
|
|
589
|
+
// Use current working directory as root
|
|
590
|
+
const rootPath = process.cwd()
|
|
591
|
+
|
|
592
|
+
const server = createServer(rootPath)
|
|
593
|
+
const transport = new StdioServerTransport()
|
|
594
|
+
|
|
595
|
+
await server.connect(transport)
|
|
596
|
+
|
|
597
|
+
// Handle graceful shutdown
|
|
598
|
+
process.on('SIGINT', async () => {
|
|
599
|
+
await server.close()
|
|
600
|
+
process.exit(0)
|
|
601
|
+
})
|
|
602
|
+
|
|
603
|
+
process.on('SIGTERM', async () => {
|
|
604
|
+
await server.close()
|
|
605
|
+
process.exit(0)
|
|
606
|
+
})
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
main().catch((error) => {
|
|
610
|
+
console.error('Fatal error:', error)
|
|
611
|
+
process.exit(1)
|
|
612
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './parser.js'
|