@geminilight/mindos 0.1.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/.env.local.example +38 -0
- package/LICENSE +21 -0
- package/README.md +423 -0
- package/README_zh.md +423 -0
- package/app/README.md +152 -0
- package/app/app/api/ask/route.ts +170 -0
- package/app/app/api/ask-sessions/route.ts +90 -0
- package/app/app/api/auth/route.ts +37 -0
- package/app/app/api/backlinks/route.ts +22 -0
- package/app/app/api/bootstrap/route.ts +37 -0
- package/app/app/api/extract-pdf/route.ts +82 -0
- package/app/app/api/file/route.ts +138 -0
- package/app/app/api/files/route.ts +12 -0
- package/app/app/api/git/route.ts +42 -0
- package/app/app/api/graph/route.ts +113 -0
- package/app/app/api/recent-files/route.ts +10 -0
- package/app/app/api/search/route.ts +17 -0
- package/app/app/api/settings/reset-token/route.ts +21 -0
- package/app/app/api/settings/route.ts +123 -0
- package/app/app/error.tsx +33 -0
- package/app/app/globals.css +368 -0
- package/app/app/icon.svg +35 -0
- package/app/app/layout.tsx +103 -0
- package/app/app/login/page.tsx +120 -0
- package/app/app/page.tsx +12 -0
- package/app/app/view/[...path]/ViewPageClient.tsx +343 -0
- package/app/app/view/[...path]/error.tsx +33 -0
- package/app/app/view/[...path]/loading.tsx +15 -0
- package/app/app/view/[...path]/page.tsx +93 -0
- package/app/components/AskFab.tsx +59 -0
- package/app/components/AskModal.tsx +398 -0
- package/app/components/Backlinks.tsx +75 -0
- package/app/components/Breadcrumb.tsx +31 -0
- package/app/components/CsvView.tsx +325 -0
- package/app/components/DirView.tsx +138 -0
- package/app/components/Editor.tsx +124 -0
- package/app/components/EditorWrapper.tsx +17 -0
- package/app/components/ErrorBoundary.tsx +53 -0
- package/app/components/FileTree.tsx +369 -0
- package/app/components/HomeContent.tsx +262 -0
- package/app/components/JsonView.tsx +27 -0
- package/app/components/MarkdownEditor.tsx +95 -0
- package/app/components/MarkdownView.tsx +118 -0
- package/app/components/SearchModal.tsx +193 -0
- package/app/components/SettingsModal.tsx +237 -0
- package/app/components/Sidebar.tsx +136 -0
- package/app/components/SidebarLayout.tsx +36 -0
- package/app/components/TableOfContents.tsx +150 -0
- package/app/components/ThemeToggle.tsx +34 -0
- package/app/components/WysiwygEditor.tsx +75 -0
- package/app/components/ask/FileChip.tsx +30 -0
- package/app/components/ask/MentionPopover.tsx +52 -0
- package/app/components/ask/MessageList.tsx +126 -0
- package/app/components/ask/SessionHistory.tsx +49 -0
- package/app/components/renderers/AgentInspectorRenderer.tsx +277 -0
- package/app/components/renderers/BacklinksRenderer.tsx +147 -0
- package/app/components/renderers/ConfigRenderer.tsx +236 -0
- package/app/components/renderers/CsvRenderer.tsx +77 -0
- package/app/components/renderers/DiffRenderer.tsx +310 -0
- package/app/components/renderers/GraphRenderer.tsx +428 -0
- package/app/components/renderers/SummaryRenderer.tsx +251 -0
- package/app/components/renderers/TimelineRenderer.tsx +213 -0
- package/app/components/renderers/TodoRenderer.tsx +474 -0
- package/app/components/renderers/WorkflowRenderer.tsx +404 -0
- package/app/components/renderers/csv/BoardView.tsx +146 -0
- package/app/components/renderers/csv/ConfigPanel.tsx +117 -0
- package/app/components/renderers/csv/EditableCell.tsx +43 -0
- package/app/components/renderers/csv/GalleryView.tsx +40 -0
- package/app/components/renderers/csv/TableView.tsx +164 -0
- package/app/components/renderers/csv/types.ts +87 -0
- package/app/components/settings/AiTab.tsx +111 -0
- package/app/components/settings/AppearanceTab.tsx +101 -0
- package/app/components/settings/KnowledgeTab.tsx +157 -0
- package/app/components/settings/PluginsTab.tsx +82 -0
- package/app/components/settings/Primitives.tsx +60 -0
- package/app/components/settings/ShortcutsTab.tsx +22 -0
- package/app/components/settings/types.ts +41 -0
- package/app/components/ui/button.tsx +60 -0
- package/app/components/ui/dialog.tsx +157 -0
- package/app/components/ui/input.tsx +20 -0
- package/app/components/ui/scroll-area.tsx +55 -0
- package/app/components/ui/toggle.tsx +44 -0
- package/app/components/ui/tooltip.tsx +66 -0
- package/app/components.json +25 -0
- package/app/data/pages/home-dark.png +0 -0
- package/app/data/pages/home-mobile-crop.png +0 -0
- package/app/data/pages/home-mobile.png +0 -0
- package/app/data/pages/home.png +0 -0
- package/app/data/pages/view-dir.png +0 -0
- package/app/data/pages/view-file-bot.png +0 -0
- package/app/data/pages/view-file-dark-crop.png +0 -0
- package/app/data/pages/view-file-dark.png +0 -0
- package/app/data/pages/view-file-mobile.png +0 -0
- package/app/data/pages/view-file-sm.png +0 -0
- package/app/data/pages/view-file-top.png +0 -0
- package/app/data/pages/view-file.png +0 -0
- package/app/eslint.config.mjs +18 -0
- package/app/hooks/useAskSession.ts +181 -0
- package/app/hooks/useFileUpload.ts +126 -0
- package/app/hooks/useMention.ts +65 -0
- package/app/lib/LocaleContext.tsx +40 -0
- package/app/lib/actions.ts +40 -0
- package/app/lib/agent/index.ts +3 -0
- package/app/lib/agent/model.ts +18 -0
- package/app/lib/agent/prompt.ts +32 -0
- package/app/lib/agent/tools.ts +151 -0
- package/app/lib/api.ts +55 -0
- package/app/lib/core/backlinks.ts +40 -0
- package/app/lib/core/csv.ts +28 -0
- package/app/lib/core/fs-ops.ts +118 -0
- package/app/lib/core/git.ts +50 -0
- package/app/lib/core/index.ts +58 -0
- package/app/lib/core/lines.ts +89 -0
- package/app/lib/core/search.ts +79 -0
- package/app/lib/core/security.ts +43 -0
- package/app/lib/core/tree.ts +113 -0
- package/app/lib/core/types.ts +40 -0
- package/app/lib/fs.ts +467 -0
- package/app/lib/i18n.ts +300 -0
- package/app/lib/jwt.ts +58 -0
- package/app/lib/renderers/index.ts +79 -0
- package/app/lib/renderers/registry.ts +70 -0
- package/app/lib/settings.ts +150 -0
- package/app/lib/types.ts +32 -0
- package/app/lib/utils.ts +34 -0
- package/app/next-env.d.ts +6 -0
- package/app/next.config.ts +10 -0
- package/app/package-lock.json +15306 -0
- package/app/package.json +71 -0
- package/app/postcss.config.mjs +7 -0
- package/app/proxy.ts +64 -0
- package/app/public/file.svg +1 -0
- package/app/public/globe.svg +1 -0
- package/app/public/landing/index.html +353 -0
- package/app/public/landing/style.css +216 -0
- package/app/public/logo-square.svg +37 -0
- package/app/public/logo.svg +37 -0
- package/app/public/next.svg +1 -0
- package/app/public/vercel.svg +1 -0
- package/app/public/window.svg +1 -0
- package/app/scripts/extract-pdf.cjs +56 -0
- package/app/tsconfig.json +34 -0
- package/app/vitest.config.ts +14 -0
- package/assets/demo-flow-zh.html +622 -0
- package/assets/images/demo-flow-dark.png +0 -0
- package/assets/images/demo-flow-light.png +0 -0
- package/assets/images/demo-flow-zh-dark.png +0 -0
- package/assets/images/demo-flow-zh-light.png +0 -0
- package/assets/images/gui-sync-cv.png +0 -0
- package/assets/logo-square.svg +37 -0
- package/bin/cli.js +894 -0
- package/mcp/README.md +113 -0
- package/mcp/package-lock.json +1717 -0
- package/mcp/package.json +18 -0
- package/mcp/src/index.ts +494 -0
- package/mcp/tsconfig.json +13 -0
- package/package.json +49 -0
- package/scripts/setup.js +675 -0
- package/scripts/upgrade-prompt.md +147 -0
- package/skills/mindos/SKILL.md +319 -0
- package/skills/mindos-zh/SKILL.md +318 -0
- package/templates/README.md +31 -0
- package/templates/empty/CHANGELOG.md +9 -0
- package/templates/empty/CONFIG.json +197 -0
- package/templates/empty/CONFIG.md +73 -0
- package/templates/empty/INSTRUCTION.md +177 -0
- package/templates/empty/README.md +27 -0
- package/templates/en/CHANGELOG.md +9 -0
- package/templates/en/CONFIG.json +197 -0
- package/templates/en/CONFIG.md +73 -0
- package/templates/en/INSTRUCTION.md +177 -0
- package/templates/en/README.md +27 -0
- package/templates/en/TODO.md +13 -0
- package/templates/en//360/237/221/244 Profile/INSTRUCTION.md" +21 -0
- package/templates/en//360/237/221/244 Profile/README.md" +15 -0
- package/templates/en//360/237/221/244 Profile//342/232/231/357/270/217 Preferences.md" +21 -0
- package/templates/en//360/237/221/244 Profile//360/237/216/257 Focus.md" +31 -0
- package/templates/en//360/237/221/244 Profile//360/237/221/244 Identity.md" +22 -0
- package/templates/en//360/237/223/232 Resources/INSTRUCTION.md" +29 -0
- package/templates/en//360/237/223/232 Resources/README.md" +21 -0
- package/templates/en//360/237/223/232 Resources//360/237/247/276 AI Influencers.csv" +1 -0
- package/templates/en//360/237/223/232 Resources//360/237/247/276 AI Products.csv" +1 -0
- package/templates/en//360/237/223/232 Resources//360/237/247/276 AI Scholars.csv" +1 -0
- package/templates/en//360/237/223/232 Resources//360/237/247/276 AI Tools.csv" +1 -0
- package/templates/en//360/237/223/235 Notes/INSTRUCTION.md" +31 -0
- package/templates/en//360/237/223/235 Notes/Ideas/README.md" +8 -0
- package/templates/en//360/237/223/235 Notes/Ideas//360/237/247/252_example_product_idea.md" +16 -0
- package/templates/en//360/237/223/235 Notes/Inbox/README.md" +8 -0
- package/templates/en//360/237/223/235 Notes/Inbox//360/237/247/252_example_quick_capture.md" +14 -0
- package/templates/en//360/237/223/235 Notes/Meetings/README.md" +8 -0
- package/templates/en//360/237/223/235 Notes/Meetings//360/237/247/252_example_meeting_note.md" +17 -0
- package/templates/en//360/237/223/235 Notes/README.md" +24 -0
- package/templates/en//360/237/223/235 Notes/Waiting/README.md" +8 -0
- package/templates/en//360/237/223/235 Notes/Waiting//360/237/247/252_example_blocked_item.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Configurations/README.md" +3 -0
- package/templates/en//360/237/224/204 Workflows/Configurations//360/237/247/252_example_config_update_sop.md" +14 -0
- package/templates/en//360/237/224/204 Workflows/INSTRUCTION.md" +21 -0
- package/templates/en//360/237/224/204 Workflows/Information/README.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Information//360/237/247/252_example_info_capture_sop.md" +13 -0
- package/templates/en//360/237/224/204 Workflows/Media/README.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Media//360/237/247/252_example_content_publish_sop.md" +13 -0
- package/templates/en//360/237/224/204 Workflows/README.md" +22 -0
- package/templates/en//360/237/224/204 Workflows/Research/README.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Research//360/237/247/252_example_lit_review_sop.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Startup/README.md" +3 -0
- package/templates/en//360/237/224/204 Workflows/Startup//360/237/247/252_example_weekly_founder_ops.md" +22 -0
- package/templates/en//360/237/224/227 Connections/Classmates/README.md" +11 -0
- package/templates/en//360/237/224/227 Connections/Classmates//360/237/247/252_example_leo_chen.md" +16 -0
- package/templates/en//360/237/224/227 Connections/Colleagues/README.md" +11 -0
- package/templates/en//360/237/224/227 Connections/Colleagues//360/237/247/252_example_ethan_zhao.md" +16 -0
- package/templates/en//360/237/224/227 Connections/Connections Overview.csv" +5 -0
- package/templates/en//360/237/224/227 Connections/Family/README.md" +11 -0
- package/templates/en//360/237/224/227 Connections/Family//360/237/247/252_example_james_wang.md" +16 -0
- package/templates/en//360/237/224/227 Connections/Friends/README.md" +11 -0
- package/templates/en//360/237/224/227 Connections/Friends//360/237/247/252_example_lily_lin.md" +16 -0
- package/templates/en//360/237/224/227 Connections/INSTRUCTION.md" +56 -0
- package/templates/en//360/237/224/227 Connections/README.md" +20 -0
- package/templates/en//360/237/232/200 Projects/Archived/README.md" +9 -0
- package/templates/en//360/237/232/200 Projects/Archived//360/237/247/252_example_archived_project_note.md" +14 -0
- package/templates/en//360/237/232/200 Projects/INSTRUCTION.md" +29 -0
- package/templates/en//360/237/232/200 Projects/Products/README.md" +16 -0
- package/templates/en//360/237/232/200 Projects/Products//360/237/247/252_example_product_project_brief.md" +20 -0
- package/templates/en//360/237/232/200 Projects/README.md" +21 -0
- package/templates/en//360/237/232/200 Projects/Research/README.md" +16 -0
- package/templates/en//360/237/232/200 Projects/Research//360/237/247/252_example_research_project_brief.md" +16 -0
- package/templates/template-generation-skill.md +79 -0
- package/templates/zh/CHANGELOG.md +9 -0
- package/templates/zh/CONFIG.json +197 -0
- package/templates/zh/CONFIG.md +66 -0
- package/templates/zh/INSTRUCTION.md +177 -0
- package/templates/zh/README.md +27 -0
- package/templates/zh/TODO.md +13 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217/INSTRUCTION.md" +28 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217/README.md" +20 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217//342/232/231/357/270/217 Preferences.md" +21 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217//360/237/216/257 Focus.md" +31 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217//360/237/221/244 Identity.md" +22 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220/INSTRUCTION.md" +29 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220/README.md" +21 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220//360/237/247/276 AI Inferencers.csv" +1 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220//360/237/247/276 AI /344/272/247/345/223/201.csv" +1 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220//360/237/247/276 AI /345/255/246/350/200/205/346/270/205/345/215/225.csv" +1 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220//360/237/247/276 AI /345/267/245/345/205/267/346/270/205/345/215/225.csv" +1 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260/INSTRUCTION.md" +31 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260/README.md" +24 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//344/274/232/350/256/256/README.md" +8 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//344/274/232/350/256/256//360/237/247/252_example_/344/274/232/350/256/256/347/272/252/350/246/201.md" +17 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//345/276/205/345/217/215/351/246/210/README.md" +8 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//345/276/205/345/217/215/351/246/210//360/237/247/252_example_/345/276/205/345/217/215/351/246/210/344/272/213/351/241/271.md" +16 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//346/203/263/346/263/225/README.md" +8 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//346/203/263/346/263/225//360/237/247/252_example_/344/272/247/345/223/201/346/203/263/346/263/225.md" +16 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//346/224/266/344/273/266/347/256/261/README.md" +8 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//346/224/266/344/273/266/347/256/261//360/237/247/252_example_/344/270/264/346/227/266/351/200/237/350/256/260.md" +13 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213/INSTRUCTION.md" +29 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213/README.md" +21 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//344/277/241/346/201/257/README.md" +16 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//344/277/241/346/201/257//360/237/247/252_example_/344/277/241/346/201/257/351/207/207/351/233/206/346/265/201/347/250/213.md" +13 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//345/252/222/344/275/223/README.md" +16 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//345/252/222/344/275/223//360/237/247/252_example_/345/206/205/345/256/271/345/217/221/345/270/203/346/265/201/347/250/213.md" +13 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//347/247/221/347/240/224/README.md" +16 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//347/247/221/347/240/224//360/237/247/252_example_/346/226/207/347/214/256/347/273/274/350/277/260/346/265/201/347/250/213.md" +16 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//351/205/215/347/275/256/README.md" +3 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//351/205/215/347/275/256//360/237/247/252_example_/351/205/215/347/275/256/346/233/264/346/226/260/346/265/201/347/250/213.md" +26 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273/INSTRUCTION.md" +62 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273/README.md" +20 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/205/263/347/263/273/346/200/273/350/247/210.csv" +5 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/220/214/344/272/213/README.md" +11 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/220/214/344/272/213//360/237/247/252_example_/345/220/214/344/272/213/350/265/265/344/270/200/350/276/260.md" +16 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/220/214/345/255/246/README.md" +11 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/220/214/345/255/246//360/237/247/252_example_/345/220/214/345/255/246/351/231/210/347/253/213/346/254/247.md" +16 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/256/266/344/272/272/README.md" +11 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/256/266/344/272/272//360/237/247/252_example_/345/256/266/344/272/272/347/216/213/345/273/272/345/233/275.md" +16 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//346/234/213/345/217/213/README.md" +11 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//346/234/213/345/217/213//360/237/247/252_example_/346/234/213/345/217/213/346/236/227/345/260/217/344/270/275.md" +16 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256/INSTRUCTION.md" +31 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256/README.md" +21 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//344/272/247/345/223/201/README.md" +16 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//344/272/247/345/223/201//360/237/247/252_example_/344/272/247/345/223/201/351/241/271/347/233/256/347/256/200/346/212/245.md" +20 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//345/267/262/345/275/222/346/241/243/README.md" +9 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//345/267/262/345/275/222/346/241/243//360/237/247/252_example_/345/275/222/346/241/243/351/241/271/347/233/256/350/256/260/345/275/225.md" +15 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//347/247/221/347/240/224/README.md" +16 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//347/247/221/347/240/224//360/237/247/252_example_/347/247/221/347/240/224/351/241/271/347/233/256/347/256/200/346/212/245.md" +16 -0
package/mcp/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mindos-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "npx tsx src/index.ts"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@modelcontextprotocol/sdk": "^1.6.1",
|
|
11
|
+
"zod": "^3.23.8"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^25.4.0",
|
|
15
|
+
"tsx": "^4.19.0",
|
|
16
|
+
"typescript": "^5"
|
|
17
|
+
}
|
|
18
|
+
}
|
package/mcp/src/index.ts
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindOS MCP Server — HTTP client wrapper
|
|
3
|
+
*
|
|
4
|
+
* Pure protocol adapter: maps MCP tools to App REST API calls via fetch.
|
|
5
|
+
* Zero business logic — all operations delegated to the App.
|
|
6
|
+
*
|
|
7
|
+
* Transport modes:
|
|
8
|
+
* Streamable HTTP (default):
|
|
9
|
+
* mindos mcp
|
|
10
|
+
*
|
|
11
|
+
* stdio:
|
|
12
|
+
* MCP_TRANSPORT=stdio mindos mcp
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
17
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
18
|
+
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
|
|
19
|
+
import { randomUUID } from "node:crypto";
|
|
20
|
+
import { createServer } from "node:http";
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
|
|
23
|
+
// ─── Config ──────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
const BASE_URL = process.env.MINDOS_URL ?? "http://localhost:3000";
|
|
26
|
+
const AUTH_TOKEN = process.env.AUTH_TOKEN;
|
|
27
|
+
const MCP_TRANSPORT = process.env.MCP_TRANSPORT ?? "http"; // "http" | "stdio"
|
|
28
|
+
const MCP_HOST = process.env.MCP_HOST ?? "127.0.0.1";
|
|
29
|
+
const MCP_PORT = parseInt(process.env.MCP_PORT ?? "8787", 10);
|
|
30
|
+
const MCP_ENDPOINT = process.env.MCP_ENDPOINT ?? "/mcp";
|
|
31
|
+
const CHARACTER_LIMIT = 25_000;
|
|
32
|
+
|
|
33
|
+
function headers(): Record<string, string> {
|
|
34
|
+
const h: Record<string, string> = { "Content-Type": "application/json" };
|
|
35
|
+
if (AUTH_TOKEN) h["Authorization"] = `Bearer ${AUTH_TOKEN}`;
|
|
36
|
+
return h;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ─── HTTP helpers ────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
async function get(path: string, params?: Record<string, string>): Promise<Record<string, unknown>> {
|
|
42
|
+
const url = new URL(path, BASE_URL);
|
|
43
|
+
if (params) {
|
|
44
|
+
for (const [k, v] of Object.entries(params)) {
|
|
45
|
+
if (v !== undefined && v !== null) url.searchParams.set(k, v);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const res = await fetch(url.toString(), { headers: headers() });
|
|
49
|
+
const json = await res.json() as Record<string, unknown>;
|
|
50
|
+
if (!res.ok) throw new Error((json.error as string) ?? `HTTP ${res.status}`);
|
|
51
|
+
return json;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function post(path: string, body: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
55
|
+
const res = await fetch(new URL(path, BASE_URL).toString(), {
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: headers(),
|
|
58
|
+
body: JSON.stringify(body),
|
|
59
|
+
});
|
|
60
|
+
const json = await res.json() as Record<string, unknown>;
|
|
61
|
+
if (!res.ok) throw new Error((json.error as string) ?? `HTTP ${res.status}`);
|
|
62
|
+
return json;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function ok(text: string) {
|
|
66
|
+
return { content: [{ type: "text" as const, text }] };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function error(msg: string) {
|
|
70
|
+
return { isError: true, content: [{ type: "text" as const, text: `Error: ${msg}` }] };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function truncate(text: string, limit = CHARACTER_LIMIT): string {
|
|
74
|
+
if (text.length <= limit) return text;
|
|
75
|
+
return text.slice(0, limit) + `\n\n[... truncated at ${limit} characters. Use offset/limit params for paginated access.]`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ─── MCP Server ──────────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
const server = new McpServer({ name: "mindos-mcp-server", version: "1.0.0" });
|
|
81
|
+
|
|
82
|
+
// ── mindos_list_files ───────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
server.registerTool("mindos_list_files", {
|
|
85
|
+
title: "List Knowledge Base Files",
|
|
86
|
+
description: "Return the full file tree of the MindOS knowledge base as a directory tree.",
|
|
87
|
+
inputSchema: z.object({
|
|
88
|
+
response_format: z.enum(["markdown", "json"]).default("markdown"),
|
|
89
|
+
}),
|
|
90
|
+
annotations: { readOnlyHint: true },
|
|
91
|
+
}, async ({ response_format }) => {
|
|
92
|
+
try {
|
|
93
|
+
const json = await get("/api/files", { format: response_format });
|
|
94
|
+
return ok(typeof json.tree === "string" ? json.tree : JSON.stringify(json.tree ?? json, null, 2));
|
|
95
|
+
} catch (e) { return error(String(e)); }
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// ── mindos_read_file ────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
server.registerTool("mindos_read_file", {
|
|
101
|
+
title: "Read File Content",
|
|
102
|
+
description: "Read the full content of a file in the MindOS knowledge base.",
|
|
103
|
+
inputSchema: z.object({
|
|
104
|
+
path: z.string().min(1),
|
|
105
|
+
offset: z.number().int().min(0).default(0),
|
|
106
|
+
limit: z.number().int().min(1).max(CHARACTER_LIMIT).default(CHARACTER_LIMIT),
|
|
107
|
+
}),
|
|
108
|
+
annotations: { readOnlyHint: true },
|
|
109
|
+
}, async ({ path, offset, limit }) => {
|
|
110
|
+
try {
|
|
111
|
+
const json = await get("/api/file", { path, op: "read_file" });
|
|
112
|
+
const content = json.content as string;
|
|
113
|
+
const slice = content.slice(offset, offset + limit);
|
|
114
|
+
const hasMore = offset + limit < content.length;
|
|
115
|
+
const header = hasMore
|
|
116
|
+
? `[Showing characters ${offset}–${offset + slice.length} of ${content.length}. Use offset=${offset + limit} for next page.]\n\n`
|
|
117
|
+
: offset > 0 ? `[Showing characters ${offset}–${offset + slice.length} of ${content.length}]\n\n` : "";
|
|
118
|
+
return ok(header + slice);
|
|
119
|
+
} catch (e) { return error(String(e)); }
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// ── mindos_write_file ───────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
server.registerTool("mindos_write_file", {
|
|
125
|
+
title: "Write File Content",
|
|
126
|
+
description: "Overwrite the entire content of an existing file.",
|
|
127
|
+
inputSchema: z.object({
|
|
128
|
+
path: z.string().min(1),
|
|
129
|
+
content: z.string(),
|
|
130
|
+
}),
|
|
131
|
+
}, async ({ path, content }) => {
|
|
132
|
+
try {
|
|
133
|
+
await post("/api/file", { op: "save_file", path, content });
|
|
134
|
+
return ok(`Successfully wrote ${content.length} characters to "${path}"`);
|
|
135
|
+
} catch (e) { return error(String(e)); }
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// ── mindos_create_file ──────────────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
server.registerTool("mindos_create_file", {
|
|
141
|
+
title: "Create New File",
|
|
142
|
+
description: "Create a new file in the knowledge base. Only .md and .csv files allowed.",
|
|
143
|
+
inputSchema: z.object({
|
|
144
|
+
path: z.string().min(1).regex(/\.(md|csv)$/),
|
|
145
|
+
content: z.string().default(""),
|
|
146
|
+
}),
|
|
147
|
+
}, async ({ path, content }) => {
|
|
148
|
+
try {
|
|
149
|
+
await post("/api/file", { op: "create_file", path, content });
|
|
150
|
+
return ok(`Created "${path}" (${content.length} characters)`);
|
|
151
|
+
} catch (e) { return error(String(e)); }
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// ── mindos_delete_file ──────────────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
server.registerTool("mindos_delete_file", {
|
|
157
|
+
title: "Delete File",
|
|
158
|
+
description: "Permanently delete a file from the knowledge base.",
|
|
159
|
+
inputSchema: z.object({
|
|
160
|
+
path: z.string().min(1),
|
|
161
|
+
}),
|
|
162
|
+
annotations: { destructiveHint: true },
|
|
163
|
+
}, async ({ path }) => {
|
|
164
|
+
try {
|
|
165
|
+
await post("/api/file", { op: "delete_file", path });
|
|
166
|
+
return ok(`Deleted "${path}"`);
|
|
167
|
+
} catch (e) { return error(String(e)); }
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// ── mindos_rename_file ──────────────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
server.registerTool("mindos_rename_file", {
|
|
173
|
+
title: "Rename File",
|
|
174
|
+
description: "Rename a file within its current directory.",
|
|
175
|
+
inputSchema: z.object({
|
|
176
|
+
path: z.string().min(1),
|
|
177
|
+
new_name: z.string().min(1),
|
|
178
|
+
}),
|
|
179
|
+
}, async ({ path, new_name }) => {
|
|
180
|
+
try {
|
|
181
|
+
const json = await post("/api/file", { op: "rename_file", path, new_name });
|
|
182
|
+
return ok(`Renamed "${path}" → "${json.newPath}"`);
|
|
183
|
+
} catch (e) { return error(String(e)); }
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// ── mindos_move_file ────────────────────────────────────────────────────────
|
|
187
|
+
|
|
188
|
+
server.registerTool("mindos_move_file", {
|
|
189
|
+
title: "Move File",
|
|
190
|
+
description: "Move a file to a new path. Returns affected backlinks.",
|
|
191
|
+
inputSchema: z.object({
|
|
192
|
+
from_path: z.string().min(1),
|
|
193
|
+
to_path: z.string().min(1),
|
|
194
|
+
}),
|
|
195
|
+
}, async ({ from_path, to_path }) => {
|
|
196
|
+
try {
|
|
197
|
+
const json = await post("/api/file", { op: "move_file", path: from_path, to_path });
|
|
198
|
+
const affected = json.affectedFiles as string[] ?? [];
|
|
199
|
+
const lines = [`Moved "${from_path}" → "${json.newPath}"`];
|
|
200
|
+
if (affected.length > 0) {
|
|
201
|
+
lines.push("", `${affected.length} file(s) reference the old path:`);
|
|
202
|
+
for (const f of affected) lines.push(` - ${f}`);
|
|
203
|
+
}
|
|
204
|
+
return ok(lines.join("\n"));
|
|
205
|
+
} catch (e) { return error(String(e)); }
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// ── mindos_search_notes ─────────────────────────────────────────────────────
|
|
209
|
+
|
|
210
|
+
server.registerTool("mindos_search_notes", {
|
|
211
|
+
title: "Search Knowledge Base",
|
|
212
|
+
description: "Full-text search across all .md and .csv files.",
|
|
213
|
+
inputSchema: z.object({
|
|
214
|
+
query: z.string().min(1).max(200),
|
|
215
|
+
limit: z.number().int().min(1).max(50).default(20),
|
|
216
|
+
scope: z.string().optional(),
|
|
217
|
+
file_type: z.enum(["md", "csv", "all"]).default("all"),
|
|
218
|
+
modified_after: z.string().optional(),
|
|
219
|
+
response_format: z.enum(["markdown", "json"]).default("markdown"),
|
|
220
|
+
}),
|
|
221
|
+
annotations: { readOnlyHint: true },
|
|
222
|
+
}, async ({ query, limit, scope, file_type, modified_after, response_format }) => {
|
|
223
|
+
try {
|
|
224
|
+
const params: Record<string, string> = { q: query, limit: String(limit) };
|
|
225
|
+
if (scope) params.scope = scope;
|
|
226
|
+
if (file_type !== "all") params.file_type = file_type;
|
|
227
|
+
if (modified_after) params.modified_after = modified_after;
|
|
228
|
+
if (response_format) params.format = response_format;
|
|
229
|
+
const json = await get("/api/search", params);
|
|
230
|
+
return ok(truncate(JSON.stringify(json, null, 2)));
|
|
231
|
+
} catch (e) { return error(String(e)); }
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// ── mindos_get_recent ───────────────────────────────────────────────────────
|
|
235
|
+
|
|
236
|
+
server.registerTool("mindos_get_recent", {
|
|
237
|
+
title: "Get Recently Modified Files",
|
|
238
|
+
description: "Return recently modified files sorted by modification time.",
|
|
239
|
+
inputSchema: z.object({
|
|
240
|
+
limit: z.number().int().min(1).max(50).default(10),
|
|
241
|
+
response_format: z.enum(["markdown", "json"]).default("markdown"),
|
|
242
|
+
}),
|
|
243
|
+
annotations: { readOnlyHint: true },
|
|
244
|
+
}, async ({ limit, response_format }) => {
|
|
245
|
+
try {
|
|
246
|
+
const json = await get("/api/recent-files", { limit: String(limit), format: response_format });
|
|
247
|
+
return ok(JSON.stringify(json, null, 2));
|
|
248
|
+
} catch (e) { return error(String(e)); }
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// ── mindos_read_lines ───────────────────────────────────────────────────────
|
|
252
|
+
|
|
253
|
+
server.registerTool("mindos_read_lines", {
|
|
254
|
+
title: "Read File as Lines",
|
|
255
|
+
description: "Read file content as a numbered array of lines (0-indexed).",
|
|
256
|
+
inputSchema: z.object({
|
|
257
|
+
path: z.string().min(1),
|
|
258
|
+
}),
|
|
259
|
+
annotations: { readOnlyHint: true },
|
|
260
|
+
}, async ({ path }) => {
|
|
261
|
+
try {
|
|
262
|
+
const json = await get("/api/file", { path, op: "read_lines" });
|
|
263
|
+
const lines = json.lines as string[];
|
|
264
|
+
const numbered = lines.map((l, i) => `${i}: ${l}`).join("\n");
|
|
265
|
+
return ok(`${lines.length} lines total:\n\n${numbered}`);
|
|
266
|
+
} catch (e) { return error(String(e)); }
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// ── mindos_insert_lines ─────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
server.registerTool("mindos_insert_lines", {
|
|
272
|
+
title: "Insert Lines into File",
|
|
273
|
+
description: "Insert lines at a specific position (0-based, -1 to prepend).",
|
|
274
|
+
inputSchema: z.object({
|
|
275
|
+
path: z.string().min(1),
|
|
276
|
+
after_index: z.number().int(),
|
|
277
|
+
lines: z.array(z.string()).min(1),
|
|
278
|
+
}),
|
|
279
|
+
}, async ({ path, after_index, lines }) => {
|
|
280
|
+
try {
|
|
281
|
+
await post("/api/file", { op: "insert_lines", path, after_index, lines });
|
|
282
|
+
return ok(`Inserted ${lines.length} line(s) after index ${after_index} in "${path}"`);
|
|
283
|
+
} catch (e) { return error(String(e)); }
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// ── mindos_update_lines ─────────────────────────────────────────────────────
|
|
287
|
+
|
|
288
|
+
server.registerTool("mindos_update_lines", {
|
|
289
|
+
title: "Replace Lines in File",
|
|
290
|
+
description: "Replace a range of lines (inclusive, 0-based).",
|
|
291
|
+
inputSchema: z.object({
|
|
292
|
+
path: z.string().min(1),
|
|
293
|
+
start: z.number().int().min(0),
|
|
294
|
+
end: z.number().int().min(0),
|
|
295
|
+
lines: z.array(z.string()).min(1),
|
|
296
|
+
}),
|
|
297
|
+
}, async ({ path, start, end, lines }) => {
|
|
298
|
+
try {
|
|
299
|
+
await post("/api/file", { op: "update_lines", path, start, end, lines });
|
|
300
|
+
return ok(`Replaced lines ${start}–${end} in "${path}" with ${lines.length} new line(s)`);
|
|
301
|
+
} catch (e) { return error(String(e)); }
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// ── mindos_append_to_file ───────────────────────────────────────────────────
|
|
305
|
+
|
|
306
|
+
server.registerTool("mindos_append_to_file", {
|
|
307
|
+
title: "Append Content to File",
|
|
308
|
+
description: "Append text to the end of an existing file.",
|
|
309
|
+
inputSchema: z.object({
|
|
310
|
+
path: z.string().min(1),
|
|
311
|
+
content: z.string().min(1),
|
|
312
|
+
}),
|
|
313
|
+
}, async ({ path, content }) => {
|
|
314
|
+
try {
|
|
315
|
+
await post("/api/file", { op: "append_to_file", path, content });
|
|
316
|
+
return ok(`Appended ${content.length} character(s) to "${path}"`);
|
|
317
|
+
} catch (e) { return error(String(e)); }
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// ── mindos_insert_after_heading ─────────────────────────────────────────────
|
|
321
|
+
|
|
322
|
+
server.registerTool("mindos_insert_after_heading", {
|
|
323
|
+
title: "Insert Content After Heading",
|
|
324
|
+
description: "Insert content after a Markdown heading.",
|
|
325
|
+
inputSchema: z.object({
|
|
326
|
+
path: z.string().min(1),
|
|
327
|
+
heading: z.string().min(1),
|
|
328
|
+
content: z.string().min(1),
|
|
329
|
+
}),
|
|
330
|
+
}, async ({ path, heading, content }) => {
|
|
331
|
+
try {
|
|
332
|
+
await post("/api/file", { op: "insert_after_heading", path, heading, content });
|
|
333
|
+
return ok(`Inserted content after heading "${heading}" in "${path}"`);
|
|
334
|
+
} catch (e) { return error(String(e)); }
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// ── mindos_update_section ───────────────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
server.registerTool("mindos_update_section", {
|
|
340
|
+
title: "Replace Markdown Section Content",
|
|
341
|
+
description: "Replace the content of a Markdown section identified by heading.",
|
|
342
|
+
inputSchema: z.object({
|
|
343
|
+
path: z.string().min(1),
|
|
344
|
+
heading: z.string().min(1),
|
|
345
|
+
content: z.string(),
|
|
346
|
+
}),
|
|
347
|
+
}, async ({ path, heading, content }) => {
|
|
348
|
+
try {
|
|
349
|
+
await post("/api/file", { op: "update_section", path, heading, content });
|
|
350
|
+
return ok(`Updated section "${heading}" in "${path}"`);
|
|
351
|
+
} catch (e) { return error(String(e)); }
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
// ── mindos_append_csv ───────────────────────────────────────────────────────
|
|
355
|
+
|
|
356
|
+
server.registerTool("mindos_append_csv", {
|
|
357
|
+
title: "Append Row to CSV",
|
|
358
|
+
description: "Append a row to a CSV file with RFC 4180 escaping.",
|
|
359
|
+
inputSchema: z.object({
|
|
360
|
+
path: z.string().min(1).regex(/\.csv$/),
|
|
361
|
+
row: z.array(z.string()).min(1),
|
|
362
|
+
}),
|
|
363
|
+
}, async ({ path, row }) => {
|
|
364
|
+
try {
|
|
365
|
+
const json = await post("/api/file", { op: "append_csv", path, row });
|
|
366
|
+
return ok(`Appended row to "${path}". File now has ${json.newRowCount} rows.`);
|
|
367
|
+
} catch (e) { return error(String(e)); }
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// ── mindos_get_backlinks ────────────────────────────────────────────────────
|
|
371
|
+
|
|
372
|
+
server.registerTool("mindos_get_backlinks", {
|
|
373
|
+
title: "Find Backlinks to File",
|
|
374
|
+
description: "Find all files that reference a given file path.",
|
|
375
|
+
inputSchema: z.object({
|
|
376
|
+
path: z.string().min(1),
|
|
377
|
+
}),
|
|
378
|
+
annotations: { readOnlyHint: true },
|
|
379
|
+
}, async ({ path }) => {
|
|
380
|
+
try {
|
|
381
|
+
const json = await get("/api/backlinks", { path });
|
|
382
|
+
return ok(JSON.stringify(json, null, 2));
|
|
383
|
+
} catch (e) { return error(String(e)); }
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// ── mindos_bootstrap ────────────────────────────────────────────────────────
|
|
387
|
+
|
|
388
|
+
server.registerTool("mindos_bootstrap", {
|
|
389
|
+
title: "Bootstrap Agent Context",
|
|
390
|
+
description: "Load MindOS startup context: INSTRUCTION.md, README.md, CONFIG files, and optional target directory context.",
|
|
391
|
+
inputSchema: z.object({
|
|
392
|
+
target_dir: z.string().optional(),
|
|
393
|
+
}),
|
|
394
|
+
annotations: { readOnlyHint: true },
|
|
395
|
+
}, async ({ target_dir }) => {
|
|
396
|
+
try {
|
|
397
|
+
const params: Record<string, string> = {};
|
|
398
|
+
if (target_dir) params.target_dir = target_dir;
|
|
399
|
+
const json = await get("/api/bootstrap", params);
|
|
400
|
+
const sections = Object.entries(json)
|
|
401
|
+
.filter(([, v]) => v !== undefined && v !== null)
|
|
402
|
+
.map(([key, val]) => `--- ${key} ---\n\n${val}`)
|
|
403
|
+
.join("\n\n");
|
|
404
|
+
return ok(truncate(sections));
|
|
405
|
+
} catch (e) { return error(String(e)); }
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// ── mindos_get_history ──────────────────────────────────────────────────────
|
|
409
|
+
|
|
410
|
+
server.registerTool("mindos_get_history", {
|
|
411
|
+
title: "Get File Git History",
|
|
412
|
+
description: "Get git commit history for a file.",
|
|
413
|
+
inputSchema: z.object({
|
|
414
|
+
path: z.string().min(1),
|
|
415
|
+
limit: z.number().int().min(1).max(50).default(10),
|
|
416
|
+
}),
|
|
417
|
+
annotations: { readOnlyHint: true },
|
|
418
|
+
}, async ({ path, limit }) => {
|
|
419
|
+
try {
|
|
420
|
+
const json = await get("/api/git", { op: "history", path, limit: String(limit) });
|
|
421
|
+
const entries = json.entries as Array<{ hash: string; date: string; message: string; author: string }>;
|
|
422
|
+
if (entries.length === 0) return ok(`No git history found for "${path}"`);
|
|
423
|
+
const lines = [`# Git History: ${path}`, "", `${entries.length} commit(s):`, ""];
|
|
424
|
+
for (const h of entries) {
|
|
425
|
+
lines.push(`- **${h.date}** \`${h.hash.slice(0, 8)}\` — ${h.message} (${h.author})`);
|
|
426
|
+
}
|
|
427
|
+
return ok(lines.join("\n"));
|
|
428
|
+
} catch (e) { return error(String(e)); }
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
// ── mindos_get_file_at_version ──────────────────────────────────────────────
|
|
432
|
+
|
|
433
|
+
server.registerTool("mindos_get_file_at_version", {
|
|
434
|
+
title: "Read File at Git Version",
|
|
435
|
+
description: "Read file content at a specific git commit.",
|
|
436
|
+
inputSchema: z.object({
|
|
437
|
+
path: z.string().min(1),
|
|
438
|
+
commit: z.string().min(4),
|
|
439
|
+
}),
|
|
440
|
+
annotations: { readOnlyHint: true },
|
|
441
|
+
}, async ({ path, commit }) => {
|
|
442
|
+
try {
|
|
443
|
+
const json = await get("/api/git", { op: "show", path, commit });
|
|
444
|
+
const content = json.content as string;
|
|
445
|
+
return ok(truncate(`# ${path} @ ${commit.slice(0, 8)}\n\n${content}`));
|
|
446
|
+
} catch (e) { return error(String(e)); }
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// ─── Start ───────────────────────────────────────────────────────────────────
|
|
450
|
+
|
|
451
|
+
async function main() {
|
|
452
|
+
if (MCP_TRANSPORT === "http") {
|
|
453
|
+
// ── Streamable HTTP mode ──────────────────────────────────────────────
|
|
454
|
+
const transport = new StreamableHTTPServerTransport({
|
|
455
|
+
sessionIdGenerator: () => randomUUID(),
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const expressApp = createMcpExpressApp({ host: MCP_HOST });
|
|
459
|
+
|
|
460
|
+
// Auth middleware
|
|
461
|
+
if (AUTH_TOKEN) {
|
|
462
|
+
expressApp.use(MCP_ENDPOINT, (req, res, next) => {
|
|
463
|
+
const bearer = req.headers.authorization?.replace("Bearer ", "");
|
|
464
|
+
if (bearer !== AUTH_TOKEN) {
|
|
465
|
+
res.status(401).json({ error: "Unauthorized" });
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
next();
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
expressApp.all(MCP_ENDPOINT, async (req, res) => {
|
|
473
|
+
await transport.handleRequest(req, res);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
await server.connect(transport);
|
|
477
|
+
|
|
478
|
+
const httpServer = createServer(expressApp as Parameters<typeof createServer>[1]);
|
|
479
|
+
httpServer.listen(MCP_PORT, MCP_HOST, () => {
|
|
480
|
+
console.error(`MindOS MCP server (HTTP) listening on http://${MCP_HOST}:${MCP_PORT}${MCP_ENDPOINT}`);
|
|
481
|
+
console.error(`API backend: ${BASE_URL}`);
|
|
482
|
+
});
|
|
483
|
+
} else {
|
|
484
|
+
// ── stdio mode (default) ──────────────────────────────────────────────
|
|
485
|
+
const transport = new StdioServerTransport();
|
|
486
|
+
await server.connect(transport);
|
|
487
|
+
console.error(`MindOS MCP server started (stdio, API: ${BASE_URL})`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
main().catch((e) => {
|
|
492
|
+
console.error("Fatal:", e);
|
|
493
|
+
process.exit(1);
|
|
494
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@geminilight/mindos",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MindOS — Human-Agent Collaborative Mind System. Local-first knowledge base that syncs your mind to all AI Agents via MCP.",
|
|
5
|
+
"keywords": ["mindos", "mcp", "knowledge-base", "ai-agent", "local-first", "second-brain"],
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "GeminiLight",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/GeminiLight/MindOS"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"mindos": "bin/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"workspaces": ["app", "mcp"],
|
|
17
|
+
"files": [
|
|
18
|
+
"app/",
|
|
19
|
+
"mcp/",
|
|
20
|
+
"templates/",
|
|
21
|
+
"skills/",
|
|
22
|
+
"bin/",
|
|
23
|
+
"scripts/",
|
|
24
|
+
"assets/",
|
|
25
|
+
"README.md",
|
|
26
|
+
"README_zh.md",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
".env.local.example",
|
|
29
|
+
"!app/node_modules",
|
|
30
|
+
"!app/.next",
|
|
31
|
+
"!app/.env.local",
|
|
32
|
+
"!app/.claude",
|
|
33
|
+
"!app/__tests__",
|
|
34
|
+
"!app/**/*.bak",
|
|
35
|
+
"!mcp/node_modules",
|
|
36
|
+
"!mcp/dist"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"setup": "node scripts/setup.js",
|
|
40
|
+
"dev": "mindos dev",
|
|
41
|
+
"build": "mindos build",
|
|
42
|
+
"start": "mindos start",
|
|
43
|
+
"mcp": "mindos mcp",
|
|
44
|
+
"test": "cd app && npx vitest run"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18"
|
|
48
|
+
}
|
|
49
|
+
}
|