This is page 1 of 8. Use http://codebase.md/cyanheads/atlas-mcp-server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .clinerules
├── .dockerignore
├── .env.example
├── .github
│ ├── FUNDING.yml
│ └── workflows
│ └── publish.yml
├── .gitignore
├── .ncurc.json
├── .repomixignore
├── automated-tests
│ └── AGENT_TEST_05282025.md
├── CHANGELOG.md
├── CLAUDE.md
├── docker-compose.yml
├── docs
│ └── tree.md
├── examples
│ ├── backup-example
│ │ ├── knowledges.json
│ │ ├── projects.json
│ │ ├── relationships.json
│ │ └── tasks.json
│ ├── deep-research-example
│ │ ├── covington_community_grant_research.md
│ │ └── full-export.json
│ ├── README.md
│ └── webui-example.png
├── LICENSE
├── mcp.json
├── package-lock.json
├── package.json
├── README.md
├── repomix.config.json
├── scripts
│ ├── clean.ts
│ ├── fetch-openapi-spec.ts
│ ├── make-executable.ts
│ └── tree.ts
├── smithery.yaml
├── src
│ ├── config
│ │ └── index.ts
│ ├── index.ts
│ ├── mcp
│ │ ├── resources
│ │ │ ├── index.ts
│ │ │ ├── knowledge
│ │ │ │ └── knowledgeResources.ts
│ │ │ ├── projects
│ │ │ │ └── projectResources.ts
│ │ │ ├── tasks
│ │ │ │ └── taskResources.ts
│ │ │ └── types.ts
│ │ ├── server.ts
│ │ ├── tools
│ │ │ ├── atlas_database_clean
│ │ │ │ ├── cleanDatabase.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_deep_research
│ │ │ │ ├── deepResearch.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_knowledge_add
│ │ │ │ ├── addKnowledge.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_knowledge_delete
│ │ │ │ ├── deleteKnowledge.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_knowledge_list
│ │ │ │ ├── index.ts
│ │ │ │ ├── listKnowledge.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_project_create
│ │ │ │ ├── createProject.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_project_delete
│ │ │ │ ├── deleteProject.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_project_list
│ │ │ │ ├── index.ts
│ │ │ │ ├── listProjects.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_project_update
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── updateProject.ts
│ │ │ ├── atlas_task_create
│ │ │ │ ├── createTask.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_task_delete
│ │ │ │ ├── deleteTask.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_task_list
│ │ │ │ ├── index.ts
│ │ │ │ ├── listTasks.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ └── types.ts
│ │ │ ├── atlas_task_update
│ │ │ │ ├── index.ts
│ │ │ │ ├── responseFormat.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── updateTask.ts
│ │ │ └── atlas_unified_search
│ │ │ ├── index.ts
│ │ │ ├── responseFormat.ts
│ │ │ ├── types.ts
│ │ │ └── unifiedSearch.ts
│ │ └── transports
│ │ ├── authentication
│ │ │ └── authMiddleware.ts
│ │ ├── httpTransport.ts
│ │ └── stdioTransport.ts
│ ├── services
│ │ └── neo4j
│ │ ├── backupRestoreService
│ │ │ ├── backupRestoreTypes.ts
│ │ │ ├── backupUtils.ts
│ │ │ ├── exportLogic.ts
│ │ │ ├── importLogic.ts
│ │ │ ├── index.ts
│ │ │ └── scripts
│ │ │ ├── db-backup.ts
│ │ │ └── db-import.ts
│ │ ├── driver.ts
│ │ ├── events.ts
│ │ ├── helpers.ts
│ │ ├── index.ts
│ │ ├── knowledgeService.ts
│ │ ├── projectService.ts
│ │ ├── searchService
│ │ │ ├── fullTextSearchLogic.ts
│ │ │ ├── index.ts
│ │ │ ├── searchTypes.ts
│ │ │ └── unifiedSearchLogic.ts
│ │ ├── taskService.ts
│ │ ├── types.ts
│ │ └── utils.ts
│ ├── types
│ │ ├── errors.ts
│ │ ├── mcp.ts
│ │ └── tool.ts
│ ├── utils
│ │ ├── index.ts
│ │ ├── internal
│ │ │ ├── errorHandler.ts
│ │ │ ├── index.ts
│ │ │ ├── logger.ts
│ │ │ └── requestContext.ts
│ │ ├── metrics
│ │ │ ├── index.ts
│ │ │ └── tokenCounter.ts
│ │ ├── parsing
│ │ │ ├── dateParser.ts
│ │ │ ├── index.ts
│ │ │ └── jsonParser.ts
│ │ └── security
│ │ ├── idGenerator.ts
│ │ ├── index.ts
│ │ ├── rateLimiter.ts
│ │ └── sanitization.ts
│ └── webui
│ ├── index.html
│ ├── logic
│ │ ├── api-service.js
│ │ ├── app-state.js
│ │ ├── config.js
│ │ ├── dom-elements.js
│ │ ├── main.js
│ │ └── ui-service.js
│ └── styling
│ ├── base.css
│ ├── components.css
│ ├── layout.css
│ └── theme.css
├── tsconfig.json
├── tsconfig.typedoc.json
└── typedoc.json
```
# Files
--------------------------------------------------------------------------------
/.ncurc.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "reject": ["chrono-node"]
3 | }
4 |
```
--------------------------------------------------------------------------------
/.repomixignore:
--------------------------------------------------------------------------------
```
1 | # Environment and secrets
2 | .env
3 | .env.*
4 | !.env.example
5 | .venv/
6 | .venv3/
7 |
8 | # Python
9 | __pycache__/
10 | *.py[cod]
11 | *$py.class
12 | *.so
13 | .Python
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | .eggs/
20 | lib/
21 | lib64/
22 | parts/
23 | sdist/
24 | var/
25 | wheels/
26 | *.egg-info/
27 | .installed.cfg
28 | *.egg
29 | MANIFEST
30 | .python-version
31 | venv/
32 | env/
33 | ENV/
34 |
35 | # IDE
36 | .idea/
37 | .vscode/
38 | *.swp
39 | *.swo
40 | .DS_Store
41 |
42 | # Project specific
43 | logs/
44 | output/
45 | data/*
46 | !data/.gitkeep
47 |
48 | # LaTeX
49 | *.aux
50 | *.lof
51 | *.log
52 | *.lot
53 | *.fls
54 | *.out
55 | *.toc
56 | *.fmt
57 | *.fot
58 | *.cb
59 | *.cb2
60 | .*.lb
61 | *.dvi
62 | *.xdv
63 | *-converted-to.*
64 | *.pdf
65 | *.fdb_latexmk
66 | *.synctex
67 | *.synctex(busy)
68 | *.synctex.gz
69 | *.synctex.gz(busy)
70 | *.pdfsync
71 | latex.out/
72 | node_modules/
73 |
74 | # Misc
75 | repomix/
76 | repomix-output.txt
77 | repomix-output.xml
78 | repomix-output.json
79 | logs/
80 | ideas/
81 | backups/
82 | src/mcp/
```
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
```
1 | # Neo4j Configuration
2 | NEO4J_URI=bolt://localhost:7687
3 | NEO4J_USER=neo4j
4 | NEO4J_PASSWORD=password2
5 |
6 | # Application Configuration
7 | LOG_LEVEL=info # Log level: emerg, alert, crit, error, warning, notice, info, debug (corresponds to MCP_LOG_LEVEL)
8 | NODE_ENV=development # development, production
9 |
10 | # MCP Transport Configuration
11 | MCP_TRANSPORT_TYPE=stdio # 'stdio' or 'http'. Default: stdio
12 | MCP_HTTP_HOST=127.0.0.1 # Host for HTTP transport. Default: 127.0.0.1
13 | MCP_HTTP_PORT=3010 # Port for HTTP transport. Default: 3010
14 | # MCP_ALLOWED_ORIGINS=http://localhost:3000,https://your-client.com # Comma-separated list of allowed origins for HTTP CORS. Optional.
15 |
16 | # MCP Security Configuration
17 | # MCP_AUTH_SECRET_KEY=your_very_long_and_secure_secret_key_min_32_chars # Secret key for JWT authentication (if HTTP transport is used and auth is desired). Optional.
18 | MCP_RATE_LIMIT_WINDOW_MS=60000 # Rate limit window in milliseconds. Default: 60000 (1 minute)
19 | MCP_RATE_LIMIT_MAX_REQUESTS=100 # Max requests per window per IP. Default: 100
20 |
21 | # Database Backup Configuration
22 | BACKUP_MAX_COUNT=10 # Maximum number of backup files to keep. Default: 10
23 | BACKUP_FILE_DIR=./backups # Directory where backup files will be stored (relative to project root). Default: ./backups
24 |
```
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
```
1 | # =============================================================================
2 | # OPERATING SYSTEM FILES
3 | # =============================================================================
4 | .DS_Store
5 | .DS_Store?
6 | ._*
7 | .Spotlight-V100
8 | .Trashes
9 | ehthumbs.db
10 | Thumbs.db
11 |
12 | # =============================================================================
13 | # IDE AND EDITOR FILES
14 | # =============================================================================
15 | .idea/
16 | .vscode/
17 | *.swp
18 | *.swo
19 | *~
20 | *.sublime-workspace
21 | *.sublime-project
22 | .history/
23 |
24 | # =============================================================================
25 | # NODE.JS & PACKAGE MANAGERS
26 | # =============================================================================
27 | node_modules/
28 | npm-debug.log*
29 | yarn-debug.log*
30 | yarn-error.log*
31 | .pnpm-debug.log*
32 | .npm
33 | .pnp.js
34 | .pnp.cjs
35 | .pnp.mjs
36 | .pnp.json
37 | .pnp.ts
38 |
39 | # =============================================================================
40 | # TYPESCRIPT & JAVASCRIPT
41 | # =============================================================================
42 | *.tsbuildinfo
43 | .tscache/
44 | *.js.map
45 | *.mjs.map
46 | *.cjs.map
47 | *.d.ts.map
48 | *.d.ts
49 | !*.d.ts.template
50 | *.tgz
51 | .eslintcache
52 | .rollup.cache
53 |
54 | # =============================================================================
55 | # PYTHON
56 | # =============================================================================
57 | __pycache__/
58 | *.py[cod]
59 | *$py.class
60 | *.so
61 | .Python
62 | develop-eggs/
63 | eggs/
64 | .eggs/
65 | lib/
66 | lib64/
67 | parts/
68 | sdist/
69 | var/
70 | wheels/
71 | *.egg-info/
72 | .installed.cfg
73 | *.egg
74 | .pytest_cache/
75 | .coverage
76 | htmlcov/
77 | .tox/
78 | .venv
79 | venv/
80 | ENV/
81 |
82 | # =============================================================================
83 | # JAVA
84 | # =============================================================================
85 | *.class
86 | *.jar
87 | *.war
88 | *.nar
89 | *.ear
90 | hs_err_pid*
91 | target/
92 | .gradle/
93 |
94 | # =============================================================================
95 | # RUBY
96 | # =============================================================================
97 | *.gem
98 | *.rbc
99 | /.config
100 | /coverage/
101 | /InstalledFiles
102 | /pkg/
103 | /spec/reports/
104 | /spec/examples.txt
105 | /test/tmp/
106 | /test/version_tmp/
107 | /tmp/
108 | .byebug_history
109 |
110 | # =============================================================================
111 | # BUILD & DISTRIBUTION
112 | # =============================================================================
113 | build/
114 | dist/
115 | out/
116 |
117 | # =============================================================================
118 | # COMPILED FILES
119 | # =============================================================================
120 | *.com
121 | *.dll
122 | *.exe
123 | *.o
124 |
125 | # =============================================================================
126 | # PACKAGE & ARCHIVE FILES
127 | # =============================================================================
128 | *.7z
129 | *.dmg
130 | *.gz
131 | *.iso
132 | *.rar
133 | *.tar
134 | *.tar.gz
135 | *.zip
136 |
137 | # =============================================================================
138 | # LOGS & DATABASES
139 | # =============================================================================
140 | *.log
141 | *.sql
142 | *.sqlite
143 | *.sqlite3
144 | logs/
145 |
146 | # =============================================================================
147 | # TESTING & COVERAGE
148 | # =============================================================================
149 | coverage/
150 | .nyc_output/
151 |
152 | # =============================================================================
153 | # CACHE & TEMPORARY FILES
154 | # =============================================================================
155 | .cache/
156 | .parcel-cache/
157 | *.bak
158 |
159 | # =============================================================================
160 | # ENVIRONMENT & CONFIGURATION
161 | # =============================================================================
162 | .env
163 | .env.local
164 | .env.development.local
165 | .env.test.local
166 | .env.production.local
167 | .sample-env
168 | sample.*
169 | !sample.template.*
170 | mcp-servers.json
171 | mcp-config.json
172 |
173 | # =============================================================================
174 | # DEMO & EXAMPLE DIRECTORIES
175 | # =============================================================================
176 | demo/
177 | demos/
178 | example/
179 | examples/
180 | samples/
181 |
182 | # =============================================================================
183 | # GENERATED DOCUMENTATION
184 | # =============================================================================
185 | docs/api/
186 |
187 | # =============================================================================
188 | # APPLICATION SPECIFIC
189 | # =============================================================================
190 | repomix-output*
191 | duckdata/
192 | .claude
193 | *atlas-backups*
194 |
```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | # =============================================================================
2 | # OPERATING SYSTEM FILES
3 | # =============================================================================
4 | .DS_Store
5 | .DS_Store?
6 | ._*
7 | .Spotlight-V100
8 | .Trashes
9 | ehthumbs.db
10 | Thumbs.db
11 |
12 | # =============================================================================
13 | # IDE AND EDITOR FILES
14 | # =============================================================================
15 | .idea/
16 | .vscode/
17 | *.swp
18 | *.swo
19 | *~
20 | *.sublime-workspace
21 | *.sublime-project
22 | .history/
23 |
24 | # =============================================================================
25 | # NODE.JS & PACKAGE MANAGERS
26 | # =============================================================================
27 | node_modules/
28 | npm-debug.log*
29 | yarn-debug.log*
30 | yarn-error.log*
31 | .pnpm-debug.log*
32 | .npm
33 | .pnp.js
34 | .pnp.cjs
35 | .pnp.mjs
36 | .pnp.json
37 | .pnp.ts
38 |
39 | # =============================================================================
40 | # TYPESCRIPT & JAVASCRIPT
41 | # =============================================================================
42 | *.tsbuildinfo
43 | .tscache/
44 | *.js.map
45 | *.mjs.map
46 | *.cjs.map
47 | *.d.ts.map
48 | *.d.ts
49 | !*.d.ts.template
50 | *.tgz
51 | .eslintcache
52 | .rollup.cache
53 |
54 | # =============================================================================
55 | # PYTHON
56 | # =============================================================================
57 | __pycache__/
58 | *.py[cod]
59 | *$py.class
60 | *.so
61 | .Python
62 | develop-eggs/
63 | eggs/
64 | .eggs/
65 | lib/
66 | lib64/
67 | parts/
68 | sdist/
69 | var/
70 | wheels/
71 | *.egg-info/
72 | .installed.cfg
73 | *.egg
74 | .pytest_cache/
75 | .coverage
76 | htmlcov/
77 | .tox/
78 | .venv
79 | venv/
80 | ENV/
81 |
82 | # =============================================================================
83 | # JAVA
84 | # =============================================================================
85 | *.class
86 | *.jar
87 | *.war
88 | *.nar
89 | *.ear
90 | hs_err_pid*
91 | target/
92 | .gradle/
93 |
94 | # =============================================================================
95 | # RUBY
96 | # =============================================================================
97 | *.gem
98 | *.rbc
99 | /.config
100 | /coverage/
101 | /InstalledFiles
102 | /pkg/
103 | /spec/reports/
104 | /spec/examples.txt
105 | /test/tmp/
106 | /test/version_tmp/
107 | /tmp/
108 | .byebug_history
109 |
110 | # =============================================================================
111 | # BUILD & DISTRIBUTION
112 | # =============================================================================
113 | build/
114 | dist/
115 | out/
116 |
117 | # =============================================================================
118 | # COMPILED FILES
119 | # =============================================================================
120 | *.com
121 | *.dll
122 | *.exe
123 | *.o
124 |
125 | # =============================================================================
126 | # PACKAGE & ARCHIVE FILES
127 | # =============================================================================
128 | *.7z
129 | *.dmg
130 | *.gz
131 | *.iso
132 | *.rar
133 | *.tar
134 | *.tar.gz
135 | *.zip
136 |
137 | # =============================================================================
138 | # LOGS & DATABASES
139 | # =============================================================================
140 | *.log
141 | *.sql
142 | *.sqlite
143 | *.sqlite3
144 | logs/
145 |
146 | # =============================================================================
147 | # TESTING & COVERAGE
148 | # =============================================================================
149 | coverage/
150 | .nyc_output/
151 |
152 | # =============================================================================
153 | # CACHE & TEMPORARY FILES
154 | # =============================================================================
155 | .cache/
156 | .parcel-cache/
157 | *.bak
158 |
159 | # =============================================================================
160 | # ENVIRONMENT & CONFIGURATION
161 | # =============================================================================
162 | .env
163 | .env.local
164 | .env.development.local
165 | .env.test.local
166 | .env.production.local
167 | .sample-env
168 | sample.*
169 | !sample.template.*
170 | mcp-servers.json
171 | mcp-config.json
172 |
173 | # =============================================================================
174 | # DEMO & EXAMPLE DIRECTORIES
175 | # =============================================================================
176 | demo/
177 | demos/
178 | example/
179 | examples/
180 | samples/
181 |
182 | # =============================================================================
183 | # GENERATED DOCUMENTATION
184 | # =============================================================================
185 | docs/api/
186 |
187 | # =============================================================================
188 | # APPLICATION SPECIFIC
189 | # =============================================================================
190 | repomix-output*
191 | duckdata/
192 | .claude
193 | *atlas-backups*
194 |
```
--------------------------------------------------------------------------------
/.clinerules:
--------------------------------------------------------------------------------
```
1 | # Atlas MCP Server Developer Cheat Sheet
2 |
3 | This document provides essential guidelines and code snippets for developers working within the Atlas MCP Server repository. Adhering to these conventions ensures consistency, maintainability, and security.
4 |
5 | ## 1. Request Context (`src/utils/internal/requestContext.ts`)
6 |
7 | All operations that handle requests or perform distinct units of work MUST utilize a `RequestContext`. This context provides a unique `requestId` for tracing and a `timestamp`.
8 |
9 | **Interface:**
10 | ```typescript
11 | export interface RequestContext {
12 | requestId: string;
13 | timestamp: string;
14 | [key: string]: unknown; // For additional context-specific data
15 | }
16 | ```
17 |
18 | **Creating a Request Context:**
19 | Use the `requestContextService` to create new contexts.
20 | ```typescript
21 | import { requestContextService } from './src/utils/index.js'; // Or specific path
22 |
23 | // Basic context
24 | const context = requestContextService.createRequestContext();
25 | // { requestId: "uuid-v4-string", timestamp: "iso-string" }
26 |
27 | // Context with additional data
28 | const userContext = requestContextService.createRequestContext({
29 | userId: "user123",
30 | operationName: "getUserProfile"
31 | });
32 | // { requestId: "uuid-v4-string", timestamp: "iso-string", userId: "user123", operationName: "getUserProfile" }
33 | ```
34 |
35 | **Usage:**
36 | Pass the `RequestContext` object (or its `requestId`) to logging functions and through service layers to correlate operations.
37 |
38 | ## 2. Logging (`src/utils/internal/logger.ts`)
39 |
40 | Our `logger` is a singleton instance of a Winston-based logger, adapted for MCP. It supports multiple log levels and can send MCP notifications.
41 |
42 | **Log Levels (RFC 5424):**
43 | `emerg` (0), `alert` (1), `crit` (2), `error` (3), `warning` (4), `notice` (5), `info` (6), `debug` (7)
44 |
45 | **Initialization (in `src/index.ts`):**
46 | The logger is initialized within the `start` function in `src/index.ts`.
47 | ```typescript
48 | // In src/index.ts
49 | import { logger } from './src/utils/index.js';
50 | import { config } from './src/config/index.js'; // McpLogLevel is typically part of config types
51 |
52 | async function start() {
53 | // ... other setup ...
54 | await logger.initialize(config.logLevel); // config.logLevel is McpLogLevel
55 | // ... rest of app initialization
56 | }
57 | ```
58 |
59 | **Using the Logger:**
60 | Always provide meaningful messages. For errors, include the `Error` object. Contextual information should be passed as the second argument (an object).
61 | ```typescript
62 | import { logger } from './src/utils/index.js';
63 | import { requestContextService } from './src/utils/index.js';
64 |
65 | const requestContext = requestContextService.createRequestContext({ userId: 'user-abc' });
66 |
67 | // Debug log
68 | logger.debug('Processing user request', { requestId: requestContext.requestId, details: 'some detail' });
69 |
70 | // Info log
71 | logger.info('User authenticated successfully', { userId: requestContext.userId, requestId: requestContext.requestId });
72 |
73 | // Warning log
74 | logger.warning('User session nearing expiration', { userId: 'user-xyz', expiresIn: '5m', requestId: requestContext.requestId });
75 |
76 | // Error log
77 | try {
78 | // ... some operation that might fail ...
79 | throw new Error("Something went wrong");
80 | } catch (err) {
81 | // The 'err' parameter in logger.error can be an Error instance or an object for additional context.
82 | // If 'err' is an Error instance, its message and stack will be logged.
83 | // The third parameter 'context' is for additional structured data.
84 | logger.error('Failed to process payment', err as Error, {
85 | requestId: requestContext.requestId,
86 | paymentId: 'payment-123'
87 | });
88 | }
89 |
90 | // Critical error
91 | const criticalError = new Error("Database connection lost");
92 | logger.crit('Critical database failure', criticalError, { component: 'DatabaseService', requestId: requestContext.requestId });
93 |
94 | // Fatal error (alias for emerg)
95 | logger.fatal('System shutting down due to unrecoverable error', { reason: 'disk full' }, criticalError);
96 | ```
97 | **Log Output:**
98 | - Logs are written to files in the `logs/` directory (e.g., `error.log`, `combined.log`).
99 | - Console logging is active if `logLevel` is `debug` AND `stdout` is a TTY.
100 | - Sensitive data in log context is automatically redacted (see Sanitization).
101 |
102 | ## 3. Error Handling (`src/utils/internal/errorHandler.ts` & `src/types/errors.ts`)
103 |
104 | We use a standardized approach to error handling, centered around `McpError` and the `ErrorHandler` utility.
105 |
106 | **`McpError` (`src/types/errors.ts`):**
107 | Custom error class that includes an error `code` (from `BaseErrorCode` or feature-specific enums) and optional `details`.
108 | ```typescript
109 | import { McpError, BaseErrorCode } from './src/types/errors.js';
110 |
111 | throw new McpError(
112 | BaseErrorCode.VALIDATION_ERROR,
113 | "User ID is missing.",
114 | { field: "userId", inputReceived: { username: "test" } }
115 | );
116 | ```
117 |
118 | **`ErrorHandler.handleError`:**
119 | Centralized function to log errors consistently and optionally rethrow them.
120 | ```typescript
121 | import { ErrorHandler } from './src/utils/internal/errorHandler.js';
122 | import { BaseErrorCode } from './src/types/errors.js';
123 | import { requestContextService } from './src/utils/index.js';
124 |
125 | const requestContext = requestContextService.createRequestContext();
126 |
127 | async function someOperation(data: any) {
128 | try {
129 | if (!data.id) {
130 | throw new Error("ID is required for this operation.");
131 | }
132 | // ... perform operation ...
133 | } catch (error) {
134 | // Handle and rethrow as McpError
135 | throw ErrorHandler.handleError(error, {
136 | operation: 'someOperation',
137 | context: { requestId: requestContext.requestId, customInfo: 'some_value' },
138 | input: data, // Will be sanitized for logging
139 | errorCode: BaseErrorCode.VALIDATION_ERROR, // Optionally override determined code
140 | rethrow: true, // Default is false
141 | critical: false, // Default is false
142 | });
143 | }
144 | }
145 | ```
146 | **Key `ErrorHandlerOptions`:**
147 | - `operation`: (string, required) Name of the operation (e.g., "UserLogin", "CreateTask").
148 | - `context`: (ErrorContext, optional) Includes `requestId` and other debug info.
149 | - `input`: (unknown, optional) Input data that caused the error (sanitized before logging).
150 | - `rethrow`: (boolean, optional, default: `false`) If `true`, rethrows the (potentially transformed) error.
151 | - `errorCode`: (BaseErrorCode, optional) Explicitly set the error code.
152 | - `critical`: (boolean, optional, default: `false`) Mark as critical for logging/alerting.
153 |
154 | **`ErrorHandler.tryCatch`:**
155 | A wrapper to simplify try-catch blocks for asynchronous or synchronous functions.
156 | ```typescript
157 | import { ErrorHandler } from './src/utils/internal/errorHandler.js';
158 |
159 | async function getUser(userId: string) {
160 | // ... logic to get user ...
161 | // if (!user) throw new Error("User not found"); // Example error
162 | return { id: userId, name: "Test User" }; // Example success
163 | }
164 |
165 | const safeGetUser = (userId: string) => ErrorHandler.tryCatch(
166 | () => getUser(userId),
167 | { operation: 'getUser', input: { userId } } // rethrow is true by default in tryCatch
168 | );
169 |
170 | try {
171 | const user = await safeGetUser("123");
172 | } catch (e) {
173 | // e will be an McpError, logged by ErrorHandler.handleError
174 | // console.error("Caught error:", (e as McpError).code, (e as McpError).message);
175 | }
176 | ```
177 |
178 | ## 4. Sanitization (`src/utils/security/sanitization.ts`)
179 |
180 | Input sanitization is CRITICAL for security. Use the `sanitization` service (from `src/utils/index.js` or `src/utils/security/sanitization.js`).
181 |
182 | **`sanitizeInputForLogging(input: unknown): unknown`:**
183 | Automatically used by `ErrorHandler.handleError` for the `input` field. Manually use it if logging raw input elsewhere. Redacts sensitive fields like 'password', 'token', etc.
184 | ```typescript
185 | import { sanitizeInputForLogging, logger } from './src/utils/index.js';
186 |
187 | const sensitiveData = { password: "supersecret", username: "admin" };
188 | logger.info("User login attempt", { data: sanitizeInputForLogging(sensitiveData) });
189 | // Log output for data.password will be "[REDACTED]"
190 | ```
191 |
192 | **`sanitizeHtml(input: string, config?: HtmlSanitizeConfig): string`:**
193 | For cleaning HTML strings.
194 | ```typescript
195 | import { sanitization } from './src/utils/index.js';
196 | const unsafeHtml = "<script>alert('xss')</script><p>Hello</p>";
197 | const safeHtml = sanitization.sanitizeHtml(unsafeHtml);
198 | // safeHtml will be "<p>Hello</p>"
199 | ```
200 |
201 | **`sanitizeString(input: string, options?: SanitizeStringOptions): string`:**
202 | General string sanitization. Context can be 'text', 'html', 'attribute', 'url'.
203 | **NEVER use `context: 'javascript'`.**
204 | ```typescript
205 | import { sanitization } from './src/utils/index.js';
206 | const userInput = " Test User <img src=x onerror=alert(1)> ";
207 | const safeText = sanitization.sanitizeString(userInput, { context: 'text' }); // "Test User <img src=x onerror=alert(1)>"
208 | const safeAttribute = sanitization.sanitizeString("javascript:alert(1)", { context: 'attribute' }); // ""
209 | ```
210 |
211 | **`sanitizeUrl(input: string, allowedProtocols?: string[]): string`:**
212 | Validates and cleans URLs.
213 | ```typescript
214 | import { sanitization } from './src/utils/index.js';
215 | try {
216 | const cleanUrl = sanitization.sanitizeUrl("https://example.com/path?query=value");
217 | // const maliciousUrl = sanitization.sanitizeUrl("javascript:alert('evil')"); // Throws McpError
218 | } catch (e) {
219 | // logger.error("URL sanitization failed", e as Error);
220 | }
221 | ```
222 |
223 | **`sanitizePath(input: string, options?: PathSanitizeOptions): SanitizedPathInfo`:**
224 | Crucial for handling file paths to prevent traversal.
225 | ```typescript
226 | import { sanitization } from './src/utils/index.js';
227 | try {
228 | // Basic relative path
229 | const pathInfo1 = sanitization.sanitizePath("some/file.txt");
230 | // pathInfo1.sanitizedPath will be "some/file.txt"
231 |
232 | // Attempted traversal (throws McpError by default if not rooted and escapes CWD)
233 | // const pathInfo2 = sanitization.sanitizePath("../../../etc/passwd");
234 |
235 | // Rooted path
236 | const pathInfo3 = sanitization.sanitizePath("user/uploads/image.jpg", { rootDir: "/var/www/app" });
237 | // pathInfo3.sanitizedPath will be "user/uploads/image.jpg" (assuming it's within rootDir)
238 |
239 | const pathInfo4 = sanitization.sanitizePath("/absolute/path/file.txt", { allowAbsolute: true });
240 | // pathInfo4.sanitizedPath will be "/absolute/path/file.txt"
241 |
242 | } catch (e) {
243 | // logger.error("Path sanitization failed", e as Error);
244 | }
245 | ```
246 |
247 | **`sanitizeJson<T = unknown>(input: string, maxSize?: number): T`:**
248 | Parses JSON string safely, with optional size validation.
249 | ```typescript
250 | import { sanitization } from './src/utils/index.js';
251 | const jsonString = '{"name": "Test", "value": 123}';
252 | try {
253 | const jsonData = sanitization.sanitizeJson<{ name: string, value: number }>(jsonString);
254 | } catch (e) {
255 | // logger.error("JSON sanitization failed", e as Error);
256 | }
257 | ```
258 |
259 | **`sanitizeNumber(input: number | string, min?: number, max?: number): number`:**
260 | Validates and clamps numbers.
261 | ```typescript
262 | import { sanitization } from './src/utils/index.js';
263 | const num1 = sanitization.sanitizeNumber("123.45"); // 123.45
264 | const num2 = sanitization.sanitizeNumber("5", 10, 20); // 10 (clamped)
265 | try {
266 | const invalidNum = sanitization.sanitizeNumber("not-a-number"); // Throws McpError
267 | } catch (e) {
268 | // logger.error("Number sanitization failed", e as Error);
269 | }
270 | ```
271 |
272 | ## 5. General Best Practices
273 |
274 | - **Imports:** Use `.js` extension for local module imports (e.g., `import { logger } from './logger.js';`). Prefer importing from barrel files (`index.ts` or `index.js`) where available (e.g. `import { logger } from '../index.js'`).
275 | - **Async/Await:** Use `async/await` for all asynchronous operations.
276 | - **Type Safety:** Leverage TypeScript. Define clear interfaces and types. Avoid `any` where possible.
277 | - **Configuration:** Access application configuration via the `config` object from `src/config/index.js`.
278 | - **Immutability:** Prefer immutable data structures where practical.
279 | - **Testing:** Write unit tests for new logic, especially for utilities and services.
280 | - **Code Comments:** Document complex logic, non-obvious decisions, and public APIs with JSDoc.
281 |
282 | ## 6. Key Repository Structure and Conventions
283 |
284 | This section outlines other important directories and their roles within the Atlas MCP Server.
285 |
286 | ### 6.0. Application Entry Point (`src/index.ts`)
287 | - **Purpose:** The main entry point for the Atlas MCP Server application. It orchestrates the startup sequence, including logger initialization, configuration loading, server transport initialization, and setting up graceful shutdown handlers.
288 | - **Key Responsibilities:**
289 | - Initializes the `logger` (see Section 2).
290 | - Loads application `config` and `environment` from `src/config/index.js` (see Section 6.1).
291 | - Calls `initializeAndStartServer` from `src/mcp/server.js` to start the MCP server.
292 | - Manages a global `serverInstance` for `stdio` transport to facilitate graceful shutdown.
293 | - Implements a `shutdown` function that handles `SIGTERM`, `SIGINT`, `uncaughtException`, and `unhandledRejection` signals/events to ensure services like Neo4j connections (via `closeNeo4jConnection`) are closed properly before exiting.
294 | - Uses `requestContextService` for creating context for startup and shutdown operations.
295 | - **Convention:** This file is critical for understanding the application lifecycle. Modifications here typically relate to fundamental startup or shutdown procedures.
296 |
297 | ### 6.1. Configuration (`src/config/index.ts`)
298 | - **Purpose:** Centralized application configuration. This file likely exports a configuration object (`config`) and an environment identifier (`environment`), loaded from environment variables, `.env` files, or default values.
299 | - **Usage:** Import the `config` and `environment` objects from this module to access configuration settings and environment context throughout the application.
300 | ```typescript
301 | import { config, environment } from './src/config/index.js';
302 |
303 | const apiKey = config.someApiServiceKey;
304 | const port = config.serverPort;
305 | const currentEnv = environment; // e.g., 'development', 'production'
306 | ```
307 | - **Convention:** Avoid hardcoding configuration values. Define them in `.env` (for local development, gitignored) or environment variables for production, and access them via the exported `config` object.
308 |
309 | ### 6.2. MCP Layer (`src/mcp/`)
310 | This directory contains the core logic for the Model Context Protocol (MCP) server.
311 |
312 | #### 6.2.1. Resources (`src/mcp/resources/`)
313 | - **Purpose:** Defines and manages the data entities (like knowledge, projects, tasks) that the MCP server exposes. Each subdirectory (e.g., `knowledge/`, `projects/`, `tasks/`) typically handles CRUD-like operations or access logic for a specific resource type.
314 | - `index.ts` in this directory aggregates and exports all resource handlers.
315 | - `types.ts` defines common types or interfaces used across different resources.
316 | - **Convention:** When adding a new data entity to be managed by MCP, create a new subdirectory here with its corresponding logic (e.g., `*ResourceName*Resources.ts`) and types. Ensure it's exported via `src/mcp/resources/index.ts`.
317 |
318 | #### 6.2.2. Tools (`src/mcp/tools/`)
319 | - **Purpose:** Implements the specific tools that the MCP server offers (e.g., `atlas_deep_research`, `atlas_knowledge_add`). Each tool is usually in its own subdirectory.
320 | - **Structure per tool:**
321 | - `*ToolName*.ts`: Contains the main execution logic for the tool (e.g., `addKnowledge.ts`).
322 | - `index.ts`: Exports the tool's definition and handler.
323 | - `responseFormat.ts`: Defines the structure of the tool's successful response.
324 | - `types.ts`: Defines input/argument types and other specific types for the tool.
325 | - **Convention:** New tools should follow this established directory structure. Ensure tools perform input validation (using types from `types.ts`) and return responses as defined in `responseFormat.ts` or an `McpError`.
326 |
327 | #### 6.2.3. Transports (`src/mcp/transports/`)
328 | - **Purpose:** Handles the communication protocols for the MCP server, such as HTTP (`httpTransport.ts`) and standard I/O (`stdioTransport.ts`).
329 | - `authentication/authMiddleware.ts`: Handles JWT Bearer token authentication for HTTP transport. Verifies tokens, extracts `clientId` and `scopes` into an `AuthInfo` object (conforming to MCP SDK) on `req.auth`, and integrates `requestContextService` for logging.
330 | - **Convention:** Modifications to how the server receives requests or sends responses, or changes to authentication mechanisms, would be made here.
331 |
332 | #### 6.2.4. Server (`src/mcp/server.ts`)
333 | - **Purpose:** The main entry point or orchestrator for the MCP server logic. It likely initializes transports, registers tools and resources, and starts listening for incoming requests. This is called by `src/index.ts`.
334 | - **Convention:** This file ties together the different parts of the `src/mcp/` layer.
335 |
336 | ### 6.3. Services (`src/services/neo4j/`)
337 | - **Purpose:** Encapsulates all interactions with the Neo4j graph database. Logic is typically separated into service files based on the data entity they manage (e.g., `knowledgeService.ts`, `projectService.ts`, `taskService.ts`, `searchService.ts`) or specific functionalities (`backupRestoreService.ts`).
338 | - `driver.ts`: Manages the Neo4j driver instance and database connection.
339 | - `events.ts`: May define or handle domain events related to database interactions.
340 | - `helpers.ts`, `utils.ts`: Contain utility functions specific to Neo4j interactions.
341 | - `types.ts`: Defines types and interfaces relevant to Neo4j data models and query results.
342 | - `index.ts`: Barrel file that exports key services and utilities for easy import.
343 | - **Convention:** All database operations MUST go through these services. Avoid direct database calls from other parts of the application (e.g., from MCP tools). Services should handle query building, execution, and mapping results to application-defined types.
344 |
345 | ### 6.4. Core Types (`src/types/`)
346 | - **Purpose:** Defines global and core TypeScript types and interfaces used across the application.
347 | - `errors.ts`: (Covered in Section 3) Defines `McpError` and various error code enums.
348 | - `mcp.ts`: Likely defines core MCP structures, such as the shape of MCP requests and responses, content types, etc.
349 | - `tool.ts`: Probably defines the generic structure or interface for an MCP tool definition, including its input schema and handler function signature.
350 | - **Convention:** When defining types that are broadly applicable or fundamental to the MCP framework or tool interactions, place them here.
351 |
352 | ### 6.5. Utility Scripts (`scripts/`)
353 | - **Purpose:** Contains various TypeScript-based utility scripts for development, maintenance, and operational tasks.
354 | - Examples:
355 | - `clean.ts`: Possibly for cleaning build artifacts or temporary files.
356 | - `db-backup.ts`, `db-import.ts`: For backing up and restoring the Neo4j database.
357 | - `fetch-openapi-spec.ts`: For fetching or updating OpenAPI specifications, potentially for tool schema generation or documentation.
358 | - `make-executable.ts`: Might be used to set execute permissions on scripts.
359 | - `tree.ts`: Generates the `docs/tree.md` file.
360 | - **Convention:** Scripts should be well-documented regarding their purpose and usage. Use `npm run script-name` (after defining in `package.json` scripts section) or `npx tsx scripts/scriptName.ts` to execute them.
361 |
362 | ### 6.6. Core Utilities (`src/utils/`)
363 | This directory houses various utility modules, organized by concern. Sections 1, 2, 3, and 4 of this document cover `requestContext.ts`, `logger.ts`, `errorHandler.ts` (all in `src/utils/internal/`) and `sanitization.ts` (in `src/utils/security/`) respectively. Other key subdirectories include:
364 |
365 | #### 6.6.1. Metrics (`src/utils/metrics/`)
366 | - **Purpose:** Provides utilities related to application metrics and monitoring.
367 | - `tokenCounter.ts`: Implements functionality for counting or tracking token usage, which can be essential for services interacting with token-based APIs (e.g., LLMs).
368 | - `index.ts`: Barrel file exporting metrics utilities.
369 |
370 | #### 6.6.2. Parsing (`src/utils/parsing/`)
371 | - **Purpose:** Contains modules for parsing various data formats safely and effectively.
372 | - `dateParser.ts`: Utilities for parsing and handling date strings or objects.
373 | - `jsonParser.ts`: Provides safe JSON parsing capabilities. Note: `sanitization.sanitizeJson` (Section 4) also offers JSON parsing with validation and should be preferred for external inputs. This module might offer alternative or supplementary JSON processing tools.
374 | - `index.ts`: Barrel file exporting parsing utilities.
375 |
376 | #### 6.6.3. Security (`src/utils/security/`)
377 | - **Purpose:** Centralizes security-related utilities beyond what's covered in Section 4 (Sanitization).
378 | - `sanitization.ts`: (Covered in detail in Section 4).
379 | - `idGenerator.ts`: Provides functions for generating various types of unique identifiers used within the application (e.g., UUIDs).
380 | - `rateLimiter.ts`: Implements mechanisms for rate limiting requests or operations to protect system resources and prevent abuse.
381 | - `index.ts`: Barrel file exporting security utilities.
382 |
383 | #### 6.6.4. General Utilities (`src/utils/index.ts`)
384 | - The `src/utils/index.ts` file serves as the primary barrel file for all utilities, re-exporting modules from `internal`, `metrics`, `parsing`, and `security` subdirectories, providing a single point of import for most utility functions.
385 | ```typescript
386 | // Example: Importing multiple utils
387 | import { logger, requestContextService, sanitization, idGenerator } from './src/utils/index.js';
388 | ```
389 |
390 | ---
391 | *This cheat sheet is a living document. Please contribute improvements and keep it up-to-date.*
392 |
```
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Atlas MCP Server Backup Example
2 |
3 | This repository contains the `backup-example/` directory which demonstrates how Atlas MCP Server's backup functionality works.
4 |
5 | ## Overview
6 |
7 | The backup feature allows you to export your project's knowledge and tasks into JSON format for external storage, sharing, or analysis. The example project in this directory shows what the output from running `npm run db:backup` looks like.
8 |
9 | ## Contents
10 |
11 | The `backup-example/` directory contains:
12 |
13 | - Sample task data exported in JSON format
14 | - Example of how knowledge and context are stored
15 | - Format of the backup files generated by the system
16 |
17 | ## How to Use the Backup Feature
18 |
19 | To backup your own Atlas MCP Server data:
20 |
21 | 1. Navigate to your Atlas MCP Server project root directory
22 | 2. Run `npm run db:backup` in your terminal
23 | 3. Your data will be exported to a format similar to the examples in this directory
24 |
25 | ## Example Structure
26 |
27 | The backup files include:
28 |
29 | - `tasks.json`: Contains all project tasks with their metadata, status, and requirements
30 | - Knowledge data with context and relationships
31 | - Project configuration information
32 |
33 | ## Purpose
34 |
35 | This example is provided to:
36 |
37 | - Help users understand the structure of backed-up data
38 | - Demonstrate the completeness of the backup feature
39 | - Provide a reference for data restoration or migration
40 |
41 | ## Notes
42 |
43 | The backup feature is designed for data portability and disaster recovery. Regular backups are recommended to ensure your project data is protected.
44 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # ATLAS: Task Management System
2 |
3 | [](https://www.typescriptlang.org/)
4 | [](https://modelcontextprotocol.io/)
5 | [](https://github.com/cyanheads/atlas-mcp-server/releases)
6 | [](https://opensource.org/licenses/Apache-2.0)
7 | []()
8 | [](https://github.com/cyanheads/atlas-mcp-server)
9 |
10 | ATLAS (Adaptive Task & Logic Automation System) is a project, knowledge, and task management system for LLM Agents.
11 |
12 | Built on a 3-node architecture:
13 |
14 | ```
15 | +-------------------------------------------+
16 | | PROJECT |
17 | |-------------------------------------------|
18 | | id: string |
19 | | name: string |
20 | | description: string |
21 | | status: string |
22 | | urls?: Array<{title: string, url: string}>|
23 | | completionRequirements: string |
24 | | outputFormat: string |
25 | | taskType: string |
26 | | createdAt: string |
27 | | updatedAt: string |
28 | +----------------+--------------------------+
29 | | |
30 | | |
31 | v v
32 | +----------------------------------+ +----------------------------------+
33 | | TASK | | KNOWLEDGE |
34 | |----------------------------------| |----------------------------------|
35 | | id: string | | id: string |
36 | | projectId: string | | projectId: string |
37 | | title: string | | text: string |
38 | | description: string | | tags?: string[] |
39 | | priority: string | | domain: string |
40 | | status: string | | citations?: string[] |
41 | | assignedTo?: string | | createdAt: string |
42 | | urls?: Array<{title: string, | | |
43 | | url: string}> | | updatedAt: string |
44 | | tags?: string[] | | |
45 | | completionRequirements: string | | |
46 | | outputFormat: string | | |
47 | | taskType: string | | |
48 | | createdAt: string | | |
49 | | updatedAt: string | | |
50 | +----------------------------------+ +----------------------------------+
51 | ```
52 |
53 | Implemented as a Model Context Protocol (MCP) server, ATLAS allows LLM agents to interact with a project management database, enabling them to manage projects, tasks, and knowledge items.
54 |
55 | > **Important Version Note**: [Version 1.5.4](https://github.com/cyanheads/atlas-mcp-server/releases/tag/v1.5.4) is the last version that uses SQLite as the database. Version 2.0 and onwards has been completely rewritten to use Neo4j, which requires either:
56 | >
57 | > - Self-hosting using Docker (docker-compose included in repository)
58 | > - Using Neo4j AuraDB cloud service: https://neo4j.com/product/auradb/
59 | >
60 | > Version 2.5.0 introduces a new 3-node system (Projects, Tasks, Knowledge) that replaces the previous structure.
61 |
62 | ## Table of Contents
63 |
64 | - [Overview](#overview)
65 | - [Features](#features)
66 | - [Installation](#installation)
67 | - [Running the Server](#running-the-server)
68 | - [Web UI (Experimental)](#web-ui-experimental)
69 | - [Configuration](#configuration)
70 | - [Project Structure](#project-structure)
71 | - [Tools](#tools)
72 | - [Resources](#resources)
73 | - [Database Backup and Restore](#database-backup-and-restore)
74 | - [Examples](#examples)
75 | - [License](#license)
76 |
77 | ## Overview
78 |
79 | ATLAS implements the Model Context Protocol (MCP), enabling standardized communication between LLMs and external systems through:
80 |
81 | - **Clients**: Claude Desktop, IDEs, and other MCP-compatible clients
82 | - **Servers**: Tools and resources for project, task, and knowledge management
83 | - **LLM Agents**: AI models that leverage the server's management capabilities
84 |
85 | ### System Integration
86 |
87 | The Atlas Platform integrates these components into a cohesive system:
88 |
89 | - **Project-Task Relationship**: Projects contain tasks that represent actionable steps needed to achieve project goals. Tasks inherit context from their parent project while providing granular tracking of individual work items.
90 | - **Knowledge Integration**: Both projects and tasks can be enriched with knowledge items, providing team members with necessary information and context.
91 | - **Dependency Management**: Both projects and tasks support dependency relationships, allowing for complex workflows with prerequisites and sequential execution requirements.
92 | - **Unified Search**: The platform provides cross-entity search capabilities, allowing users to find relevant projects, tasks, or knowledge based on various criteria.
93 |
94 | ## Features
95 |
96 | | Feature Area | Key Capabilities |
97 | | :----------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
98 | | **Project Management** | - Comprehensive Tracking: Manage project metadata, statuses, and rich content (notes, links, etc.) with built-in support for bulk operations.<br />- Dependency & Relationship Handling: Automatically validate and track inter-project dependencies. |
99 | | **Task Management** | - Task Lifecycle Management: Create, track, and update tasks through their entire lifecycle.<br />- Prioritization & Categorization: Assign priority levels and categorize tasks with tags for better organization.<br />- Dependency Tracking: Establish task dependencies to create structured workflows. |
100 | | **Knowledge Management** | - Structured Knowledge Repository: Maintain a searchable repository of project-related information.<br />- Domain Categorization: Organize knowledge by domain and tags for easy retrieval.<br />- Citation Support: Track sources and references for knowledge items. |
101 | | **Graph Database Integration** | - Native Relationship Management: Leverage Neo4j's ACID-compliant transactions and optimized queries for robust data integrity.<br />- Advanced Search & Scalability: Perform property-based searches with fuzzy matching and wildcards while maintaining high performance. |
102 | | **Unified Search** | - Cross-Entity Search: Find relevant projects, tasks, or knowledge based on content, metadata, or relationships.<br />- Flexible Query Options: Support for case-insensitive, fuzzy, and advanced filtering options. |
103 |
104 | ## Installation
105 |
106 | 1. **Clone the repository:**
107 |
108 | ```bash
109 | git clone https://github.com/cyanheads/atlas-mcp-server.git
110 | cd atlas-mcp-server
111 | ```
112 |
113 | 2. **Install dependencies:**
114 |
115 | ```bash
116 | npm install
117 | ```
118 |
119 | 3. **Configure Neo4j:**
120 | Ensure you have a Neo4j instance running and accessible. You can start one using the provided Docker configuration:
121 |
122 | ```bash
123 | docker-compose up -d
124 | ```
125 |
126 | Update your `.env` file with the Neo4j connection details (see [Configuration](#configuration)).
127 |
128 | 4. **Build the project:**
129 | ```bash
130 | npm run build
131 | ```
132 |
133 | ## Running the Server
134 |
135 | Most MCP Clients run the server automatically, but you can also run it manually for testing or development purposes using the following commands.
136 |
137 | ATLAS MCP Server supports multiple transport mechanisms for communication:
138 |
139 | - **Standard I/O (stdio):** This is the default mode and is typically used for direct integration with local MCP clients (like IDE extensions).
140 |
141 | ```bash
142 | npm run start:stdio
143 | ```
144 |
145 | This uses the `MCP_TRANSPORT_TYPE=stdio` setting.
146 |
147 | - **Streamable HTTP:** This mode allows the server to listen for MCP requests over HTTP, suitable for remote clients or web-based integrations.
148 |
149 | ```bash
150 | npm run start:http
151 | ```
152 |
153 | This uses the `MCP_TRANSPORT_TYPE=http` setting. The server will listen on the host and port defined in your `.env` file (e.g., `MCP_HTTP_HOST` and `MCP_HTTP_PORT`, defaulting to `127.0.0.1:3010`). Ensure your firewall allows connections if accessing remotely.
154 |
155 | ## Web UI (Experimental)
156 |
157 | A basic Web UI is available for viewing Project, Task, & Knowledge details.
158 |
159 | - **Opening the UI**:
160 |
161 | - To open the UI directly in your browser, run the following command in your terminal:
162 | ```bash
163 | npm run webui
164 | ```
165 |
166 | - **Functionality**:
167 | - You can see an example screenshot of the Web UI [here](./examples/webui-example.png).
168 |
169 | ## Configuration
170 |
171 | ### Environment Variables
172 |
173 | Environment variables should be set in the client config in your MCP Client, or in a `.env` file in the project root for local development.
174 |
175 | ```bash
176 | # Neo4j Configuration
177 | NEO4J_URI=bolt://localhost:7687
178 | NEO4J_USER=neo4j
179 | NEO4J_PASSWORD=password2
180 |
181 | # Application Configuration
182 | MCP_LOG_LEVEL=debug # Minimum logging level. Options: emerg, alert, crit, error, warning, notice, info, debug. Default: "debug".
183 | LOGS_DIR=./logs # Directory for log files. Default: "./logs" in project root.
184 | NODE_ENV=development # 'development' or 'production'. Default: "development".
185 |
186 | # MCP Transport Configuration
187 | MCP_TRANSPORT_TYPE=stdio # 'stdio' or 'http'. Default: "stdio".
188 | MCP_HTTP_HOST=127.0.0.1 # Host for HTTP transport. Default: "127.0.0.1".
189 | MCP_HTTP_PORT=3010 # Port for HTTP transport. Default: 3010.
190 | # MCP_ALLOWED_ORIGINS=http://localhost:someport,https://your-client.com # Optional: Comma-separated list of allowed origins for HTTP CORS.
191 |
192 | # MCP Security Configuration
193 | # MCP_AUTH_SECRET_KEY=your_very_long_and_secure_secret_key_min_32_chars # Optional: Secret key (min 32 chars) for JWT authentication if HTTP transport is used. CRITICAL for production. *Note: Production environment use has not been tested yet.*
194 | MCP_RATE_LIMIT_WINDOW_MS=60000 # Rate limit window in milliseconds. Default: 60000 (1 minute).
195 | MCP_RATE_LIMIT_MAX_REQUESTS=100 # Max requests per window per IP for HTTP transport. Default: 100.
196 |
197 | # Database Backup Configuration
198 | BACKUP_MAX_COUNT=10 # Maximum number of backup sets to keep. Default: 10.
199 | BACKUP_FILE_DIR=./atlas-backups # Directory where backup files will be stored (relative to project root). Default: "./atlas-backups".
200 | ```
201 |
202 | Refer to `src/config/index.ts` for all available environment variables, their descriptions, and default values.
203 |
204 | ### MCP Client Settings
205 |
206 | How you configure your MCP client depends on the client itself and the chosen transport type. An `mcp.json` file in the project root can be used by some clients (like `mcp-inspector`) to define server configurations; update as needed.
207 |
208 | **For Stdio Transport (Example Configuration):**
209 |
210 | ```json
211 | {
212 | "mcpServers": {
213 | "atlas-mcp-server-stdio": {
214 | "command": "node",
215 | "args": ["/full/path/to/atlas-mcp-server/dist/index.js"],
216 | "env": {
217 | "NEO4J_URI": "bolt://localhost:7687",
218 | "NEO4J_USER": "neo4j",
219 | "NEO4J_PASSWORD": "password2",
220 | "MCP_LOG_LEVEL": "info",
221 | "NODE_ENV": "development",
222 | "MCP_TRANSPORT_TYPE": "stdio"
223 | }
224 | }
225 | }
226 | }
227 | ```
228 |
229 | **For Streamable HTTP (Example Configuration):**
230 | If your client supports connecting to an MCP server via Streamable HTTP, you provide the server's endpoint (e.g., `http://localhost:3010/mcp`) in your client configuration.
231 |
232 | ```json
233 | {
234 | "mcpServers": {
235 | "atlas-mcp-server-http": {
236 | "command": "node",
237 | "args": ["/full/path/to/atlas-mcp-server/dist/index.js"],
238 | "env": {
239 | "NEO4J_URI": "bolt://localhost:7687",
240 | "NEO4J_USER": "neo4j",
241 | "NEO4J_PASSWORD": "password2",
242 | "MCP_LOG_LEVEL": "info",
243 | "NODE_ENV": "development",
244 | "MCP_TRANSPORT_TYPE": "http",
245 | "MCP_HTTP_PORT": "3010",
246 | "MCP_HTTP_HOST": "127.0.0.1"
247 | // "MCP_AUTH_SECRET_KEY": "your-secure-token" // If authentication is enabled on the server
248 | }
249 | }
250 | }
251 | }
252 | ```
253 |
254 | **Note:** Always use absolute paths for `args` when configuring client commands if the server is not in the client's immediate working directory. The `MCP_AUTH_SECRET_KEY` in the client's `env` block is illustrative; actual token handling for client-to-server communication would depend on the client's capabilities and the server's authentication mechanism (e.g., sending a JWT in an `Authorization` header).
255 |
256 | ## Project Structure
257 |
258 | The codebase follows a modular structure:
259 |
260 | ```
261 | src/
262 | ├── config/ # Configuration management (index.ts)
263 | ├── index.ts # Main server entry point
264 | ├── mcp/ # MCP server implementation (server.ts)
265 | │ ├── resources/ # MCP resource handlers (index.ts, types.ts, knowledge/, projects/, tasks/)
266 | │ └── tools/ # MCP tool handlers (individual tool directories)
267 | ├── services/ # Core application services
268 | │ └── neo4j/ # Neo4j database services (index.ts, driver.ts, backupRestoreService.ts, etc.)
269 | ├── types/ # Shared TypeScript type definitions (errors.ts, mcp.ts, tool.ts)
270 | └── utils/ # Utility functions and internal services (e.g., logger, errorHandler, sanitization)
271 | ```
272 |
273 | ## Tools
274 |
275 | ATLAS provides a comprehensive suite of tools for project, task, and knowledge management, callable via the Model Context Protocol.
276 |
277 | ### Project Operations
278 |
279 | | Tool Name | Description | Key Arguments |
280 | | :--------------------- | :--------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
281 | | `atlas_project_create` | Creates new projects (single/bulk). | `mode` ('single'/'bulk'), `id` (optional client-generated ID for single mode), project details (`name`, `description`, `status`, `urls`, `completionRequirements`, `dependencies`, `outputFormat`, `taskType`). For bulk mode, use `projects` (array of project objects). `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
282 | | `atlas_project_list` | Lists projects (all/details). | `mode` ('all'/'details', default: 'all'), `id` (for details mode), filters (`status`, `taskType`), pagination (`page`, `limit`), includes (`includeKnowledge`, `includeTasks`), `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
283 | | `atlas_project_update` | Updates existing projects (single/bulk). | `mode` ('single'/'bulk'), `id` (for single mode), `updates` object. For bulk mode, use `projects` (array of objects, each with `id` and `updates`). `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
284 | | `atlas_project_delete` | Deletes projects (single/bulk). | `mode` ('single'/'bulk'), `id` (for single mode) or `projectIds` (array for bulk mode). `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
285 |
286 | ### Task Operations
287 |
288 | | Tool Name | Description | Key Arguments |
289 | | :------------------ | :------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
290 | | `atlas_task_create` | Creates new tasks (single/bulk). | `mode` ('single'/'bulk'), `id` (optional client-generated ID), `projectId`, task details (`title`, `description`, `priority`, `status`, `assignedTo`, `urls`, `tags`, `completionRequirements`, `dependencies`, `outputFormat`, `taskType`). For bulk mode, use `tasks` (array of task objects). `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
291 | | `atlas_task_update` | Updates existing tasks (single/bulk). | `mode` ('single'/'bulk'), `id` (for single mode), `updates` object. For bulk mode, use `tasks` (array of objects, each with `id` and `updates`). `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
292 | | `atlas_task_delete` | Deletes tasks (single/bulk). | `mode` ('single'/'bulk'), `id` (for single mode) or `taskIds` (array for bulk mode). `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
293 | | `atlas_task_list` | Lists tasks for a specific project. | `projectId` (required), filters (`status`, `assignedTo`, `priority`, `tags`, `taskType`), sorting (`sortBy`, `sortDirection`), pagination (`page`, `limit`), `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
294 |
295 | ### Knowledge Operations
296 |
297 | | Tool Name | Description | Key Arguments |
298 | | :----------------------- | :-------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
299 | | `atlas_knowledge_add` | Adds new knowledge items (single/bulk). | `mode` ('single'/'bulk'), `id` (optional client-generated ID), `projectId`, knowledge details (`text`, `tags`, `domain`, `citations`). For bulk mode, use `knowledge` (array of knowledge objects). `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
300 | | `atlas_knowledge_delete` | Deletes knowledge items (single/bulk). | `mode` ('single'/'bulk'), `id` (for single mode) or `knowledgeIds` (array for bulk mode). `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
301 | | `atlas_knowledge_list` | Lists knowledge items for a specific project. | `projectId` (required), filters (`tags`, `domain`, `search`), pagination (`page`, `limit`), `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
302 |
303 | ### Search Operations
304 |
305 | | Tool Name | Description | Key Arguments |
306 | | :--------------------- | :--------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
307 | | `atlas_unified_search` | Performs unified search across entities. | `value` (search term, required), `property` (optional: if specified, performs regex search on this property; if omitted, performs full-text search), filters (`entityTypes`, `taskType`, `assignedToUserId`), options (`caseInsensitive` (default: true, for regex), `fuzzy` (default: false, for regex 'contains' or full-text Lucene fuzzy)), pagination (`page`, `limit`), `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
308 |
309 | ### Research Operations
310 |
311 | | Tool Name | Description | Key Arguments |
312 | | :-------------------- | :------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
313 | | `atlas_deep_research` | Initiates a structured deep research process by creating a hierarchical plan within the Atlas knowledge base. | `projectId` (required), `researchTopic` (required), `researchGoal` (required), `scopeDefinition` (optional), `subTopics` (required array of objects, each with `question` (required), `initialSearchQueries` (optional array), `nodeId` (optional), `priority` (optional), `assignedTo` (optional), `initialStatus` (optional, default: 'todo')), `researchDomain` (optional), `initialTags` (optional), `planNodeId` (optional), `createTasks` (optional, default: true), `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
314 |
315 | ### Database Operations
316 |
317 | | Tool Name | Description | Key Arguments |
318 | | :--------------------- | :-------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- |
319 | | `atlas_database_clean` | **Destructive:** Completely resets the database, removing all projects, tasks, and knowledge. | `acknowledgement` (must be set to `true` to confirm, required), `responseFormat` ('formatted'/'json', optional, default: 'formatted'). |
320 |
321 | ## Resources
322 |
323 | ATLAS exposes project, task, and knowledge data through standard MCP resource endpoints.
324 |
325 | ### Direct Resources
326 |
327 | | Resource Name | Description |
328 | | :------------------ | :--------------------------------------------------------------------------------------- |
329 | | `atlas://projects` | List of all projects in the Atlas platform with pagination support. |
330 | | `atlas://tasks` | List of all tasks in the Atlas platform with pagination and filtering support. |
331 | | `atlas://knowledge` | List of all knowledge items in the Atlas platform with pagination and filtering support. |
332 |
333 | ### Resource Templates
334 |
335 | | Resource Name | Description |
336 | | :--------------------------------------- | :--------------------------------------------------------------------------- |
337 | | `atlas://projects/{projectId}` | Retrieves a single project by its unique identifier (`projectId`). |
338 | | `atlas://tasks/{taskId}` | Retrieves a single task by its unique identifier (`taskId`). |
339 | | `atlas://projects/{projectId}/tasks` | Retrieves all tasks belonging to a specific project (`projectId`). |
340 | | `atlas://knowledge/{knowledgeId}` | Retrieves a single knowledge item by its unique identifier (`knowledgeId`). |
341 | | `atlas://projects/{projectId}/knowledge` | Retrieves all knowledge items belonging to a specific project (`projectId`). |
342 |
343 | ## Database Backup and Restore
344 |
345 | ATLAS provides functionality to back up and restore the Neo4j database content. The core logic resides in `src/services/neo4j/backupRestoreService.ts`.
346 |
347 | ### Backup Process
348 |
349 | - **Mechanism**: The backup process exports all `Project`, `Task`, and `Knowledge` nodes, along with their relationships, into separate JSON files. A `full-export.json` containing all data is also created.
350 | - **Output**: Each backup creates a timestamped directory (e.g., `atlas-backup-YYYYMMDDHHMMSS`) within the configured backup path (default: `./atlas-backups/`). This directory contains `projects.json`, `tasks.json`, `knowledge.json`, `relationships.json`, and `full-export.json`.
351 | - **Manual Backup**: You can trigger a manual backup using the provided script:
352 | ```bash
353 | npm run db:backup
354 | ```
355 | This command executes `src/services/neo4j/backupRestoreService/scripts/db-backup.ts`, which calls the `exportDatabase` function.
356 |
357 | ### Restore Process
358 |
359 | - **Mechanism**: The restore process first completely clears the existing Neo4j database. Then, it imports nodes and relationships from the JSON files located in the specified backup directory. It prioritizes `full-export.json` if available.
360 | - **Warning**: Restoring from a backup is a destructive operation. **It will overwrite all current data in your Neo4j database.**
361 | - **Manual Restore**: To restore the database from a backup directory, use the import script:
362 | ```bash
363 | npm run db:import <path_to_backup_directory>
364 | ```
365 | Replace `<path_to_backup_directory>` with the actual path to the backup folder (e.g., `./atlas-backups/atlas-backup-20250326120000`). This command executes `src/services/neo4j/backupRestoreService/scripts/db-import.ts`, which calls the `importDatabase` function.
366 | - **Relationship Handling**: The import process attempts to recreate relationships based on the `id` properties stored within the nodes during export. Ensure your nodes have consistent `id` properties for relationships to be restored correctly.
367 |
368 | ## Examples
369 |
370 | The `examples/` directory contains practical examples demonstrating various features of the ATLAS MCP Server.
371 |
372 | - **Backup Example**: Located in `examples/backup-example/`, this shows the structure and format of the JSON files generated by the `npm run db:backup` command. See the [Examples README](./examples/README.md) for more details.
373 | - **Deep Research Example**: Located in `examples/deep-research-example/`, this demonstrates the output and structure generated by the `atlas_deep_research` tool. It includes a markdown file (`covington_community_grant_research.md`) summarizing the research plan and a JSON file (`full-export.json`) containing the raw data exported from the database after the research plan was created. See the [Examples README](./examples/README.md) for more details.
374 |
375 | ## License
376 |
377 | Apache License 2.0
378 |
379 | ---
380 |
381 | <div align="center">
382 | Built with the Model Context Protocol
383 | </div>
384 |
```
--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------
```markdown
1 | # CLAUDE.md
2 |
3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4 |
5 | ## Essential Development Commands
6 |
7 | ### Build and Development
8 |
9 | - `npm run build` - Build the TypeScript project and make executable
10 | - `npm run dev` - Watch mode for TypeScript compilation
11 | - `npm run rebuild` - Clean and rebuild project completely
12 | - `npm run format` - Format code with Prettier
13 |
14 | ### Database Operations
15 |
16 | - `npm run db:backup` - Create database backup with timestamped directory
17 | - `npm run db:import <backup_path>` - Restore database from backup (destructive)
18 | - `docker-compose up -d` - Start Neo4j database
19 | - `docker-compose down` - Stop Neo4j database
20 |
21 | ### Running the Server
22 |
23 | - `npm run start:stdio` - Run with stdio transport (default for MCP clients)
24 | - `npm run start:http` - Run with HTTP transport on localhost:3010
25 | - `npm run inspector` - Run MCP inspector for debugging
26 |
27 | ### Testing and Quality
28 |
29 | - `npm run webui` - Open basic web UI for viewing data
30 | - `npm run tree` - Generate project structure documentation
31 |
32 | ## Core Architecture
33 |
34 | ATLAS is an MCP (Model Context Protocol) server with a three-tier Neo4j-backed architecture:
35 |
36 | **Transport Layer** (`src/mcp/transports/`):
37 |
38 | - `stdioTransport.ts` - Direct stdio communication (default)
39 | - `httpTransport.ts` - HTTP server with authentication/rate limiting
40 |
41 | **MCP Layer** (`src/mcp/`):
42 |
43 | - `server.ts` - Main MCP server setup, tool/resource registration
44 | - `tools/` - MCP tool implementations (15 total tools)
45 | - `resources/` - MCP resource handlers for direct data access
46 |
47 | **Data Layer** (`src/services/neo4j/`):
48 |
49 | - Core services: `projectService.ts`, `taskService.ts`, `knowledgeService.ts`
50 | - `searchService.ts` - Unified search across all entities
51 | - `backupRestoreService.ts` - Database backup/restore operations
52 |
53 | **Three-Tier Data Model**:
54 |
55 | ```
56 | PROJECT (top-level containers)
57 | ├── TASK (actionable items within projects)
58 | ├── KNOWLEDGE (information/context for projects)
59 | └── DEPENDENCIES (relationships between entities)
60 | ```
61 |
62 | ## Configuration
63 |
64 | Environment variables are validated via Zod schema in `src/config/index.ts`. Key settings:
65 |
66 | **Database**: `NEO4J_URI`, `NEO4J_USER`, `NEO4J_PASSWORD`
67 | **Transport**: `MCP_TRANSPORT_TYPE` (stdio/http), `MCP_HTTP_PORT` (3010)
68 | **Logging**: `MCP_LOG_LEVEL` (debug), `LOGS_DIR` (./logs)
69 | **Backup**: `BACKUP_FILE_DIR` (./atlas-backups), `BACKUP_MAX_COUNT` (10)
70 |
71 | ## Key Implementation Notes
72 |
73 | - All tools support both single and bulk operations via `mode` parameter
74 | - Comprehensive input validation using Zod schemas per tool
75 | - Request context tracking for operations (`src/utils/internal/requestContext.ts`)
76 | - Structured logging with Winston (`src/utils/internal/logger.ts`)
77 | - Backup/restore creates timestamped directories with JSON exports
78 | - Rate limiting and authentication available for HTTP transport
79 | - LLM provider integration available via OpenRouter (`src/services/llm-providers/`)
80 |
81 | ## Database Schema
82 |
83 | Neo4j constraints and indexes are auto-created on startup. Core node types:
84 |
85 | - `Project` nodes with `id` property (unique constraint)
86 | - `Task` nodes with `id` property, linked to projects via `BELONGS_TO`
87 | - `Knowledge` nodes with `id` property, linked to projects via `BELONGS_TO`
88 | - `DEPENDS_ON` relationships for dependency tracking
89 |
90 | ## Testing & Development
91 |
92 | No formal test framework detected. Use:
93 |
94 | - `npm run inspector` for MCP protocol testing
95 | - Manual testing via stdio/HTTP transports
96 | - Database backup/restore for data safety during development
97 | - Web UI for visual data verification
98 |
```
--------------------------------------------------------------------------------
/tsconfig.typedoc.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "."
5 | },
6 | "include": ["src/**/*", "scripts/**/*.ts"]
7 | // The 'exclude' is also inherited.
8 | }
9 |
```
--------------------------------------------------------------------------------
/src/utils/metrics/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Barrel file for metrics-related utility modules.
3 | * This file re-exports utilities for collecting and processing metrics,
4 | * such as token counting.
5 | * @module src/utils/metrics
6 | */
7 |
8 | export * from "./tokenCounter.js";
9 |
```
--------------------------------------------------------------------------------
/src/utils/parsing/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Barrel file for parsing utility modules.
3 | * This file re-exports utilities related to parsing various data formats,
4 | * such as JSON and dates.
5 | * @module src/utils/parsing
6 | */
7 |
8 | export * from "./dateParser.js";
9 | export * from "./jsonParser.js";
10 |
```
--------------------------------------------------------------------------------
/src/utils/security/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Barrel file for security-related utility modules.
3 | * This file re-exports utilities for input sanitization, rate limiting,
4 | * and ID generation.
5 | * @module src/utils/security
6 | */
7 |
8 | export * from "./idGenerator.js";
9 | export * from "./rateLimiter.js";
10 | export * from "./sanitization.js";
11 |
```
--------------------------------------------------------------------------------
/src/utils/internal/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Barrel file for internal utility modules.
3 | * This file re-exports core internal utilities related to error handling,
4 | * logging, and request context management.
5 | * @module src/utils/internal
6 | */
7 |
8 | export * from "./errorHandler.js";
9 | export * from "./logger.js";
10 | export * from "./requestContext.js";
11 |
```
--------------------------------------------------------------------------------
/typedoc.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "$schema": "https://typedoc.org/schema.json",
3 | "entryPoints": ["src", "scripts"],
4 | "entryPointStrategy": "expand",
5 | "out": "docs/api",
6 | "readme": "README.md",
7 | "name": "atlas-mcp-server API Documentation",
8 | "includeVersion": true,
9 | "excludePrivate": true,
10 | "excludeProtected": true,
11 | "excludeInternal": true,
12 | "theme": "default"
13 | }
14 |
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "module": "ESNext",
5 | "moduleResolution": "node",
6 | "esModuleInterop": true,
7 | "strict": true,
8 | "outDir": "./dist",
9 | "rootDir": "./src",
10 | "declaration": true,
11 | "skipLibCheck": true,
12 | "forceConsistentCasingInFileNames": true
13 | },
14 | "include": ["src/**/*"],
15 | "exclude": ["node_modules", "dist"]
16 | }
17 |
```
--------------------------------------------------------------------------------
/repomix.config.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "output": {
3 | "filePath": "repomix-output.xml",
4 | "style": "xml",
5 | "removeComments": false,
6 | "removeEmptyLines": false,
7 | "topFilesLength": 5,
8 | "showLineNumbers": false,
9 | "copyToClipboard": false
10 | },
11 | "include": [],
12 | "ignore": {
13 | "useGitignore": true,
14 | "useDefaultPatterns": true,
15 | "customPatterns": [".clinerules"]
16 | },
17 | "security": {
18 | "enableSecurityCheck": true
19 | }
20 | }
21 |
```
--------------------------------------------------------------------------------
/src/services/neo4j/backupRestoreService/backupRestoreTypes.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Defines types related to backup and restore functionality in the Neo4j service.
3 | * @module src/services/neo4j/backupRestoreService/backupRestoreTypes
4 | */
5 |
6 | /**
7 | * Interface for the full export containing all entities and their relationships in a nested structure.
8 | * Nodes are stored in an object keyed by their label.
9 | */
10 | export interface FullExport {
11 | nodes: { [label: string]: Record<string, any>[] };
12 | relationships: {
13 | startNodeId: string;
14 | endNodeId: string;
15 | type: string;
16 | properties: Record<string, any>;
17 | }[];
18 | }
19 |
```
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: Publish Package to npm
2 | on:
3 | push:
4 | tags:
5 | - "v*"
6 |
7 | jobs:
8 | build-and-publish:
9 | runs-on: ubuntu-latest
10 | permissions:
11 | contents: read
12 | steps:
13 | - uses: actions/checkout@v4
14 |
15 | - name: Setup Node.js
16 | uses: actions/setup-node@v4
17 | with:
18 | node-version: "20.x"
19 | registry-url: "https://registry.npmjs.org"
20 | cache: "npm"
21 |
22 | - name: Install dependencies
23 | run: npm ci
24 |
25 | - name: Build
26 | run: npm run build
27 |
28 | - name: Publish to npm
29 | run: npm publish
30 | env:
31 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
32 |
```
--------------------------------------------------------------------------------
/src/services/neo4j/searchService/searchTypes.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Defines types related to search functionality in the Neo4j service.
3 | * @module src/services/neo4j/searchService/searchTypes
4 | */
5 |
6 | /**
7 | * Type for search result items - Made generic
8 | */
9 | export type SearchResultItem = {
10 | id: string;
11 | type: string; // Node label
12 | entityType?: string; // Optional: Specific classification (e.g., taskType, domain)
13 | title: string; // Best guess title (name, title, truncated text)
14 | description?: string; // Optional: Full description or text
15 | matchedProperty: string;
16 | matchedValue: string; // Potentially truncated
17 | createdAt?: string; // Optional
18 | updatedAt?: string; // Optional
19 | projectId?: string; // Optional
20 | projectName?: string; // Optional
21 | score: number;
22 | };
23 |
```
--------------------------------------------------------------------------------
/mcp.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "mcpServers": {
3 | "atlas-mcp-server": {
4 | "command": "node",
5 | "args": ["dist/index.js"],
6 | "env": {
7 | "NEO4J_URI": "bolt://localhost:7687",
8 | "NEO4J_USER": "neo4j",
9 | "NEO4J_PASSWORD": "password2",
10 | "LOG_LEVEL": "info",
11 | "NODE_ENV": "development",
12 | "MCP_TRANSPORT_TYPE": "http",
13 | "MCP_HTTP_HOST": "127.0.0.1",
14 | "MCP_HTTP_PORT": "3010",
15 | "MCP_ALLOWED_ORIGINS": "",
16 | "MCP_AUTH_SECRET_KEY": "your-super-secret-key-min-32-chars",
17 | "MCP_RATE_LIMIT_WINDOW_MS": "60000",
18 | "MCP_RATE_LIMIT_MAX_REQUESTS": "100",
19 | "BACKUP_MAX_COUNT": "10",
20 | "BACKUP_FILE_DIR": "./atlas-backups",
21 | "LOGS_DIR": "./logs"
22 | }
23 | }
24 | }
25 | }
26 |
```
--------------------------------------------------------------------------------
/src/mcp/resources/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2 | import { registerProjectResources } from "./projects/projectResources.js";
3 | import { registerTaskResources } from "./tasks/taskResources.js";
4 | import { registerKnowledgeResources } from "./knowledge/knowledgeResources.js";
5 |
6 | /**
7 | * Register all Atlas MCP resources
8 | *
9 | * This function registers all resources available in the Atlas MCP server:
10 | * - Projects
11 | * - Tasks
12 | * - Knowledge
13 | *
14 | * @param server The MCP server instance
15 | */
16 | export function registerMcpResources(server: McpServer) {
17 | // Register project resources
18 | registerProjectResources(server);
19 |
20 | // Register task resources
21 | registerTaskResources(server);
22 |
23 | // Register knowledge resources
24 | registerKnowledgeResources(server);
25 | }
26 |
```
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Barrel file for the utils module.
3 | * This file re-exports all utilities from their categorized subdirectories,
4 | * providing a single entry point for accessing utility functions.
5 | * @module src/utils
6 | */
7 |
8 | // Re-export all utilities from their categorized subdirectories
9 | export * from "./internal/index.js";
10 | export * from "./metrics/index.js";
11 | export * from "./parsing/index.js";
12 | export * from "./security/index.js";
13 |
14 | // It's good practice to have index.ts files in each subdirectory
15 | // that export the contents of that directory.
16 | // Assuming those will be created or already exist.
17 | // If not, this might need adjustment to export specific files, e.g.:
18 | // export * from './internal/errorHandler.js';
19 | // export * from './internal/logger.js';
20 | // ... etc.
21 |
```
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
```yaml
1 | # These are supported funding model platforms
2 |
3 | github: cyanheads
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | buy_me_a_coffee: cyanheads
14 | thanks_dev: # Replace with a single thanks.dev username
15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
16 |
```
--------------------------------------------------------------------------------
/src/webui/logic/config.js:
--------------------------------------------------------------------------------
```javascript
1 | /**
2 | * @fileoverview Application configuration constants.
3 | * @module src/webui/logic/config
4 | */
5 |
6 | /**
7 | * Application configuration settings.
8 | * @type {object}
9 | * @property {string} NEO4J_URI - The URI for the Neo4j database.
10 | * @property {string} NEO4J_USER - The username for Neo4j authentication.
11 | * @property {string} NEO4J_PASSWORD - The password for Neo4j authentication.
12 | * @property {string} DEFAULT_THEME - The default theme ('light' or 'dark').
13 | * @property {string} MERMAID_THEME_LIGHT - Mermaid theme for light mode.
14 | * @property {string} MERMAID_THEME_DARK - Mermaid theme for dark mode.
15 | */
16 | export const config = {
17 | NEO4J_URI: window.NEO4J_URI || "bolt://localhost:7687",
18 | NEO4J_USER: window.NEO4J_USER || "neo4j",
19 | NEO4J_PASSWORD: window.NEO4J_PASSWORD || "password2",
20 | DEFAULT_THEME: "light",
21 | MERMAID_THEME_LIGHT: "default",
22 | MERMAID_THEME_DARK: "dark",
23 | };
24 |
```
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
```yaml
1 | version: '3'
2 | services:
3 | neo4j:
4 | image: neo4j:5-community
5 | container_name: neo4j-atlas-mcp-server
6 | ports:
7 | - "7474:7474" # HTTP Browser
8 | - "7687:7687" # Bolt protocol
9 | environment:
10 | NEO4J_PLUGINS: '["apoc"]' # Install APOC plugin
11 | NEO4J_AUTH: neo4j/password2 # Change password for production use
12 | NEO4J_dbms_usage__report_enabled: "false"
13 | NEO4J_server_bolt_listen__address: ":7687"
14 | NEO4J_server_bolt_advertised__address: ":7687"
15 | NEO4J_server_memory_heap_initial__size: "512m"
16 | NEO4J_server_memory_heap_max__size: "1G"
17 | NEO4J_server_jvm_additional: "-XX:+HeapDumpOnOutOfMemoryError"
18 | NEO4J_db_logs_query_enabled: "INFO"
19 | NEO4J_db_logs_query_threshold: "0"
20 | NEO4J_db_transaction_timeout: "5s"
21 | NEO4J_dbms_security_procedures_unrestricted: "apoc.*" # Allow APOC procedures
22 | volumes:
23 | - neo4j_data:/data
24 | - neo4j_logs:/logs
25 | - neo4j_import:/var/lib/neo4j/import
26 | volumes:
27 | neo4j_data:
28 | neo4j_logs:
29 | neo4j_import:
```
--------------------------------------------------------------------------------
/src/services/neo4j/backupRestoreService/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Main entry point for the Neo4j Backup and Restore Service.
3 | * This module exports the primary functions for database backup and restore operations.
4 | * @module src/services/neo4j/backupRestoreService/index
5 | */
6 |
7 | import { _exportDatabase } from "./exportLogic.js";
8 | import { _importDatabase } from "./importLogic.js";
9 | import { FullExport } from "./backupRestoreTypes.js";
10 |
11 | // Re-export types
12 | export { FullExport } from "./backupRestoreTypes.js";
13 |
14 | /**
15 | * Exports the current Neo4j database to a timestamped directory.
16 | * Manages backup rotation.
17 | * @returns {Promise<string>} Path to the backup directory.
18 | * @throws Error if export fails.
19 | */
20 | export const exportDatabase = async (): Promise<string> => {
21 | return _exportDatabase();
22 | };
23 |
24 | /**
25 | * Imports data from a specified backup directory into the Neo4j database,
26 | * overwriting existing data.
27 | * @param {string} backupDirInput - Path to the backup directory.
28 | * @returns {Promise<void>}
29 | * @throws Error if import fails or backup directory is invalid.
30 | */
31 | export const importDatabase = async (backupDirInput: string): Promise<void> => {
32 | return _importDatabase(backupDirInput);
33 | };
34 |
```
--------------------------------------------------------------------------------
/examples/backup-example/projects.json:
--------------------------------------------------------------------------------
```json
1 | [
2 | {
3 | "createdAt": "2025-03-26T18:39:53.529Z",
4 | "taskType": "generation",
5 | "urls": "[{\"title\":\"GitHub Repository\",\"url\":\"https://github.com/cyanheads/portfolio\"},{\"title\":\"Live Website\",\"url\":\"https://cyanheads.dev\"}]",
6 | "completionRequirements": "The portfolio website will be considered complete when it includes all required sections (Home, About, Projects, Skills, Experience, Contact), is fully responsive, achieves a Lighthouse score of at least 90 across all categories, includes proper SEO optimization, and is deployed to production with CI/CD pipeline integration.",
7 | "name": "Cyanheads Portfolio Website",
8 | "description": "A modern, responsive portfolio website showcasing cyanheads' skills, projects, and professional experience as a software developer based in Seattle, WA. The site will feature a clean, intuitive design with sections for About, Projects, Skills, Experience, and Contact information. The portfolio will emphasize cyanheads' expertise in full-stack development, cloud technologies, and open source contributions.",
9 | "id": "portfolio-main",
10 | "outputFormat": "The final deliverable will be a fully functional website deployed to a production environment with source code hosted on GitHub. Documentation will include setup instructions, deployment procedures, and content management guidelines.",
11 | "updatedAt": "2025-03-26T18:39:53.529Z",
12 | "status": "active"
13 | }
14 | ]
15 |
```
--------------------------------------------------------------------------------
/src/services/neo4j/searchService/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Provides a SearchService class for unified and full-text search
3 | * across Neo4j entities. This service acts as an orchestrator for different
4 | * search strategies.
5 | * @module src/services/neo4j/searchService/index
6 | */
7 |
8 | import { PaginatedResult, SearchOptions } from "../types.js";
9 | import { _fullTextSearch } from "./fullTextSearchLogic.js";
10 | import { SearchResultItem } from "./searchTypes.js";
11 | import { _searchUnified } from "./unifiedSearchLogic.js";
12 |
13 | export { SearchResultItem } from "./searchTypes.js";
14 |
15 | /**
16 | * Service for unified and full-text search functionality across all entity types.
17 | */
18 | export class SearchService {
19 | /**
20 | * Perform a unified search across multiple entity types (node labels).
21 | * Searches common properties like name, title, description, text.
22 | * Applies pagination after combining and sorting results from individual label searches.
23 | * @param options Search options
24 | * @returns Paginated search results
25 | */
26 | static async search(
27 | options: SearchOptions,
28 | ): Promise<PaginatedResult<SearchResultItem>> {
29 | return _searchUnified(options);
30 | }
31 |
32 | /**
33 | * Perform a full-text search using pre-configured Neo4j full-text indexes.
34 | * @param searchValue The string to search for.
35 | * @param options Search options, excluding those not relevant to full-text search.
36 | * @returns Paginated search results
37 | */
38 | static async fullTextSearch(
39 | searchValue: string,
40 | options: Omit<
41 | SearchOptions,
42 | "value" | "fuzzy" | "caseInsensitive" | "property" | "assignedToUserId"
43 | > = {},
44 | ): Promise<PaginatedResult<SearchResultItem>> {
45 | return _fullTextSearch(searchValue, options);
46 | }
47 | }
48 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_database_clean/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 | import {
3 | McpToolResponse,
4 | ResponseFormat,
5 | createResponseFormatEnum,
6 | } from "../../../types/mcp.js";
7 |
8 | /**
9 | * Schema for database clean operation
10 | * This operation requires an explicit acknowledgement to prevent accidental data loss
11 | */
12 | export const AtlasDatabaseCleanSchema = z
13 | .object({
14 | acknowledgement: z
15 | .literal(true)
16 | .describe(
17 | "Explicit acknowledgement to reset the entire database (must be set to TRUE)",
18 | ),
19 | responseFormat: createResponseFormatEnum()
20 | .optional()
21 | .default(ResponseFormat.FORMATTED)
22 | .describe(
23 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
24 | ),
25 | })
26 | .strict();
27 |
28 | /**
29 | * Schema shape for tool registration
30 | */
31 | export const AtlasDatabaseCleanSchemaShape = {
32 | acknowledgement: z
33 | .literal(true)
34 | .describe(
35 | "Explicit acknowledgement to reset the entire database (must be set to TRUE)",
36 | ),
37 | responseFormat: createResponseFormatEnum()
38 | .optional()
39 | .describe(
40 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
41 | ),
42 | } as const;
43 |
44 | /**
45 | * Type for database clean input (empty object)
46 | */
47 | export type AtlasDatabaseCleanInput = z.infer<typeof AtlasDatabaseCleanSchema>;
48 |
49 | /**
50 | * Type for database clean response
51 | */
52 | export interface AtlasDatabaseCleanResponse extends McpToolResponse {
53 | success: boolean;
54 | message: string;
55 | timestamp: string;
56 | }
57 |
58 | /**
59 | * Type for formatted database clean response
60 | */
61 | export interface FormattedDatabaseCleanResponse {
62 | success: boolean;
63 | message: string;
64 | timestamp: string;
65 | // Removed optional 'details' field as the current implementation doesn't provide these counts
66 | }
67 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_delete/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 | import {
3 | McpToolResponse,
4 | ResponseFormat,
5 | createResponseFormatEnum,
6 | } from "../../../types/mcp.js";
7 |
8 | // Schema for individual task deletion
9 | const SingleTaskSchema = z
10 | .object({
11 | mode: z.literal("single"),
12 | id: z
13 | .string()
14 | .describe("Task identifier to permanently remove from the system"),
15 | responseFormat: createResponseFormatEnum()
16 | .optional()
17 | .default(ResponseFormat.FORMATTED)
18 | .describe(
19 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
20 | ),
21 | })
22 | .describe("Remove a specific task entity by its unique identifier");
23 |
24 | // Schema for multi-task cleanup operation
25 | const BulkTaskSchema = z
26 | .object({
27 | mode: z.literal("bulk"),
28 | taskIds: z
29 | .array(z.string())
30 | .min(1)
31 | .describe(
32 | "Collection of task identifiers to remove in a single operation",
33 | ),
34 | responseFormat: createResponseFormatEnum()
35 | .optional()
36 | .default(ResponseFormat.FORMATTED)
37 | .describe(
38 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
39 | ),
40 | })
41 | .describe("Batch removal of multiple task entities in a single transaction");
42 |
43 | // Schema shapes for tool registration
44 | export const AtlasTaskDeleteSchemaShape = {
45 | mode: z
46 | .enum(["single", "bulk"])
47 | .describe(
48 | "Operation mode - 'single' for one task, 'bulk' for multiple tasks",
49 | ),
50 | id: z
51 | .string()
52 | .optional()
53 | .describe("Task ID to delete (required for mode='single')"),
54 | taskIds: z
55 | .array(z.string())
56 | .optional()
57 | .describe("Array of task IDs to delete (required for mode='bulk')"),
58 | responseFormat: createResponseFormatEnum()
59 | .optional()
60 | .describe(
61 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
62 | ),
63 | } as const;
64 |
65 | // Schema for validation
66 | export const AtlasTaskDeleteSchema = z.discriminatedUnion("mode", [
67 | SingleTaskSchema,
68 | BulkTaskSchema,
69 | ]);
70 |
71 | export type AtlasTaskDeleteInput = z.infer<typeof AtlasTaskDeleteSchema>;
72 | export type AtlasTaskDeleteResponse = McpToolResponse;
73 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_database_clean/responseFormat.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { FormattedDatabaseCleanResponse } from "./types.js";
2 | import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator
3 |
4 | /**
5 | * Defines a generic interface for formatting data into a string.
6 | * This was previously imported but is now defined locally as the original seems to be removed.
7 | */
8 | interface ResponseFormatter<T> {
9 | format(data: T): string;
10 | }
11 |
12 | /**
13 | * Formatter for database clean operation responses
14 | */
15 | export class DatabaseCleanFormatter
16 | implements ResponseFormatter<FormattedDatabaseCleanResponse>
17 | {
18 | format(data: FormattedDatabaseCleanResponse): string {
19 | // Destructure without 'details' as it's no longer part of the interface or provided by the implementation
20 | const { success, message, timestamp } = data;
21 |
22 | // Create a summary section with operation results
23 | const summaryHeader = success
24 | ? "Database Reset Successfully"
25 | : "Database Reset Failed";
26 | const summary =
27 | `${summaryHeader}\n\n` +
28 | `Status: ${success ? "✅ Success" : "❌ Failed"}\n` +
29 | `Message: ${message}\n` +
30 | `Timestamp: ${new Date(timestamp).toLocaleString()}\n`;
31 |
32 | // Removed the 'detailsSection' as the implementation doesn't provide these details
33 |
34 | // Add warning about permanent data loss
35 | const warning =
36 | "\n⚠️ WARNING\n" +
37 | "This operation has permanently removed all data from the database. " +
38 | "This action cannot be undone. If you need to restore the data, you must use a backup.";
39 |
40 | // Return summary and warning only
41 | return `${summary}${warning}`;
42 | }
43 | }
44 |
45 | /**
46 | * Create a formatted, human-readable response for the atlas_database_clean tool
47 | *
48 | * @param data The raw database clean response data
49 | * @param isError Whether this response represents an error condition
50 | * @returns Formatted MCP tool response with appropriate structure
51 | */
52 | export function formatDatabaseCleanResponse(
53 | data: FormattedDatabaseCleanResponse,
54 | isError = false,
55 | ): any {
56 | const formatter = new DatabaseCleanFormatter();
57 | const formattedText = formatter.format(data);
58 | return createToolResponse(formattedText, isError);
59 | }
60 |
```
--------------------------------------------------------------------------------
/src/services/neo4j/backupRestoreService/scripts/db-backup.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 | import { exportDatabase } from "../../index.js"; // Adjusted path
3 | import { closeNeo4jConnection } from "../../index.js"; // Adjusted path
4 | import { logger, requestContextService } from "../../../../utils/index.js"; // Adjusted path
5 | import { config } from "../../../../config/index.js"; // Adjusted path
6 | import { McpLogLevel } from "../../../../utils/internal/logger.js"; // Added McpLogLevel import
7 |
8 | /**
9 | * Manual backup script entry point.
10 | * This script is intended to be run from the project root.
11 | */
12 | const runManualBackup = async () => {
13 | // Initialize logger for standalone script execution
14 | await logger.initialize(config.logLevel as McpLogLevel);
15 | logger.info("Starting manual database backup...");
16 |
17 | try {
18 | const backupPath = await exportDatabase();
19 | logger.info(
20 | `Manual backup completed successfully. Backup created at: ${backupPath}`,
21 | );
22 | } catch (error) {
23 | const reqContext = requestContextService.createRequestContext({
24 | operation: "runManualBackup.catch",
25 | });
26 | // Ensure logger is initialized before trying to use it in catch, though it should be by now.
27 | if (!logger["initialized"]) {
28 | // Accessing private member for a check, not ideal but pragmatic for script
29 | console.error(
30 | "Logger not initialized during catch block. Original error:",
31 | error,
32 | );
33 | } else {
34 | logger.error(
35 | "Manual database backup failed:",
36 | error as Error,
37 | reqContext,
38 | );
39 | }
40 | process.exitCode = 1; // Indicate failure
41 | } finally {
42 | // Ensure the Neo4j connection is closed after the script runs
43 | // Also ensure logger is available for these final messages
44 | if (!logger["initialized"]) {
45 | console.info("Closing Neo4j connection (logger was not initialized)...");
46 | } else {
47 | logger.info("Closing Neo4j connection...");
48 | }
49 | await closeNeo4jConnection();
50 | if (!logger["initialized"]) {
51 | console.info("Neo4j connection closed (logger was not initialized).");
52 | } else {
53 | logger.info("Neo4j connection closed.");
54 | }
55 | }
56 | };
57 |
58 | // Execute the backup process
59 | runManualBackup();
60 |
```
--------------------------------------------------------------------------------
/src/services/neo4j/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * Neo4j Services Module
3 | *
4 | * This module exports all Neo4j database services to provide a unified API for interacting
5 | * with the Neo4j graph database. It encapsulates the complexity of Neo4j queries and
6 | * transactions, providing a clean interface for application code.
7 | */
8 |
9 | // Export core database driver and utilities
10 | // Removed: export { autoExportManager } from './backup_services/autoExportManager.js';
11 | export { neo4jDriver } from "./driver.js";
12 | export { databaseEvents, DatabaseEventType } from "./events.js";
13 | export * from "./helpers.js";
14 | export { Neo4jUtils } from "./utils.js";
15 |
16 | // Export entity services
17 | // Removed backup_services exports
18 | export { KnowledgeService } from "./knowledgeService.js";
19 | export { ProjectService } from "./projectService.js";
20 | export { SearchService } from "./searchService/index.js";
21 | export type { SearchResultItem } from "./searchService/index.js";
22 | export { TaskService } from "./taskService.js";
23 | export {
24 | exportDatabase,
25 | importDatabase,
26 | } from "./backupRestoreService/index.js";
27 | export type { FullExport } from "./backupRestoreService/index.js";
28 |
29 | // Export common types
30 | export * from "./types.js";
31 |
32 | /**
33 | * Initialize the Neo4j database and related services
34 | * Should be called at application startup
35 | */
36 | // Removed initializeNeo4jServices function as it relied on backup_services
37 |
38 | /**
39 | * Initialize the Neo4j database schema
40 | * Should be called at application startup
41 | */
42 | export async function initializeNeo4jSchema(): Promise<void> {
43 | const { Neo4jUtils } = await import("./utils.js");
44 | return Neo4jUtils.initializeSchema();
45 | }
46 |
47 | // Removed restoreFromLatestBackup function
48 | // Removed getLatestBackupFile function
49 | // Removed createManualBackup function
50 |
51 | /**
52 | * Clear and reset the Neo4j database
53 | * WARNING: This permanently deletes all data
54 | */
55 | export async function clearNeo4jDatabase(): Promise<void> {
56 | const { Neo4jUtils } = await import("./utils.js");
57 | return Neo4jUtils.clearDatabase();
58 | }
59 |
60 | /**
61 | * Close the Neo4j database connection
62 | * Should be called when shutting down the application
63 | */
64 | export async function closeNeo4jConnection(): Promise<void> {
65 | const { neo4jDriver } = await import("./driver.js");
66 | return neo4jDriver.close();
67 | }
68 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_delete/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 | import {
3 | McpToolResponse,
4 | ResponseFormat,
5 | createResponseFormatEnum,
6 | } from "../../../types/mcp.js";
7 |
8 | // Schema for individual knowledge item removal
9 | const SingleKnowledgeSchema = z
10 | .object({
11 | mode: z.literal("single"),
12 | id: z
13 | .string()
14 | .describe("Knowledge item identifier to remove from the system"),
15 | responseFormat: createResponseFormatEnum()
16 | .optional()
17 | .default(ResponseFormat.FORMATTED)
18 | .describe(
19 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
20 | ),
21 | })
22 | .describe("Remove a specific knowledge item by its unique identifier");
23 |
24 | // Schema for multi-knowledge cleanup operation
25 | const BulkKnowledgeSchema = z
26 | .object({
27 | mode: z.literal("bulk"),
28 | knowledgeIds: z
29 | .array(z.string())
30 | .min(1)
31 | .describe(
32 | "Collection of knowledge identifiers to remove in a single operation",
33 | ),
34 | responseFormat: createResponseFormatEnum()
35 | .optional()
36 | .default(ResponseFormat.FORMATTED)
37 | .describe(
38 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
39 | ),
40 | })
41 | .describe(
42 | "Batch removal of multiple knowledge items in a single transaction",
43 | );
44 |
45 | // Schema shapes for tool registration
46 | export const AtlasKnowledgeDeleteSchemaShape = {
47 | mode: z
48 | .enum(["single", "bulk"])
49 | .describe(
50 | "Operation mode - 'single' for individual removal, 'bulk' for batch operations",
51 | ),
52 | id: z
53 | .string()
54 | .optional()
55 | .describe("Knowledge ID to delete (required for mode='single')"),
56 | knowledgeIds: z
57 | .array(z.string())
58 | .optional()
59 | .describe("Array of knowledge IDs to delete (required for mode='bulk')"),
60 | responseFormat: createResponseFormatEnum()
61 | .optional()
62 | .describe(
63 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
64 | ),
65 | } as const;
66 |
67 | // Schema for validation
68 | export const AtlasKnowledgeDeleteSchema = z.discriminatedUnion("mode", [
69 | SingleKnowledgeSchema,
70 | BulkKnowledgeSchema,
71 | ]);
72 |
73 | export type AtlasKnowledgeDeleteInput = z.infer<
74 | typeof AtlasKnowledgeDeleteSchema
75 | >;
76 | export type AtlasKnowledgeDeleteResponse = McpToolResponse;
77 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_database_clean/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2 | import { z } from "zod";
3 | import {
4 | BaseErrorCode,
5 | DatabaseExportImportErrorCode,
6 | } from "../../../types/errors.js";
7 | import {
8 | createToolExample,
9 | createToolMetadata,
10 | registerTool,
11 | } from "../../../types/tool.js";
12 | import { atlasDatabaseClean } from "./cleanDatabase.js";
13 | import { AtlasDatabaseCleanSchemaShape } from "./types.js";
14 |
15 | export const registerAtlasDatabaseCleanTool = (server: McpServer) => {
16 | registerTool(
17 | server,
18 | "atlas_database_clean",
19 | "Completely resets the database - permanently removes all data from all entity types (projects, tasks, and knowledge)",
20 | AtlasDatabaseCleanSchemaShape,
21 | atlasDatabaseClean,
22 | createToolMetadata({
23 | examples: [
24 | createToolExample(
25 | { acknowledgement: true },
26 | `{
27 | "success": true,
28 | "message": "Database has been completely reset and schema reinitialized",
29 | "timestamp": "2025-03-23T13:07:55.621Z",
30 | "details": {
31 | "schemaInitialized": true
32 | }
33 | }`,
34 | "Reset the entire database and reinitialize the schema",
35 | ),
36 | ],
37 | requiredPermission: "database:admin",
38 | returnSchema: z.object({
39 | success: z.boolean().describe("Operation success status"),
40 | message: z.string().describe("Result message"),
41 | timestamp: z.string().describe("Operation timestamp"),
42 | details: z
43 | .object({
44 | schemaInitialized: z
45 | .boolean()
46 | .optional()
47 | .describe("Schema reinitialization status"),
48 | deletedRelationships: z
49 | .number()
50 | .optional()
51 | .describe("Number of deleted relationships"),
52 | deletedNodes: z
53 | .number()
54 | .optional()
55 | .describe("Number of deleted nodes"),
56 | })
57 | .optional()
58 | .describe("Detailed operation statistics"),
59 | }),
60 | rateLimit: {
61 | windowMs: 60 * 60 * 1000, // 1 hour
62 | maxRequests: 1, // 1 request per hour (since this is a destructive operation)
63 | },
64 | // Warning: This operation permanently deletes ALL data from the Atlas database
65 | }),
66 | );
67 | };
68 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_list/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 | import {
3 | McpToolResponse,
4 | PriorityLevel,
5 | TaskStatus,
6 | } from "../../../types/mcp.js";
7 | import { Neo4jTask } from "../../../services/neo4j/types.js";
8 |
9 | // Schema for the tool input
10 | export const TaskListRequestSchema = z.object({
11 | projectId: z
12 | .string()
13 | .describe("ID of the project to list tasks for (required)"),
14 | status: z
15 | .union([
16 | z.enum([
17 | TaskStatus.BACKLOG,
18 | TaskStatus.TODO,
19 | TaskStatus.IN_PROGRESS,
20 | TaskStatus.COMPLETED,
21 | ]),
22 | z.array(
23 | z.enum([
24 | TaskStatus.BACKLOG,
25 | TaskStatus.TODO,
26 | TaskStatus.IN_PROGRESS,
27 | TaskStatus.COMPLETED,
28 | ]),
29 | ),
30 | ])
31 | .optional()
32 | .describe("Filter by task status or array of statuses"),
33 | assignedTo: z.string().optional().describe("Filter by assignment ID"),
34 | priority: z
35 | .union([
36 | z.enum([
37 | PriorityLevel.LOW,
38 | PriorityLevel.MEDIUM,
39 | PriorityLevel.HIGH,
40 | PriorityLevel.CRITICAL,
41 | ]),
42 | z.array(
43 | z.enum([
44 | PriorityLevel.LOW,
45 | PriorityLevel.MEDIUM,
46 | PriorityLevel.HIGH,
47 | PriorityLevel.CRITICAL,
48 | ]),
49 | ),
50 | ])
51 | .optional()
52 | .describe("Filter by priority level or array of priorities"),
53 | tags: z
54 | .array(z.string())
55 | .optional()
56 | .describe(
57 | "Array of tags to filter by (tasks matching any tag will be included)",
58 | ),
59 | taskType: z.string().optional().describe("Filter by task classification"),
60 | sortBy: z
61 | .enum(["priority", "createdAt", "status"])
62 | .optional()
63 | .default("createdAt")
64 | .describe("Field to sort results by (Default: createdAt)"),
65 | sortDirection: z
66 | .enum(["asc", "desc"])
67 | .optional()
68 | .default("desc")
69 | .describe("Sort order (Default: desc)"),
70 | page: z
71 | .number()
72 | .int()
73 | .positive()
74 | .optional()
75 | .default(1)
76 | .describe("Page number for paginated results (Default: 1)"),
77 | limit: z
78 | .number()
79 | .int()
80 | .positive()
81 | .max(100)
82 | .optional()
83 | .default(20)
84 | .describe("Number of results per page, maximum 100 (Default: 20)"),
85 | });
86 |
87 | export type TaskListRequestInput = z.infer<typeof TaskListRequestSchema>;
88 |
89 | export interface TaskListResponse {
90 | tasks: Neo4jTask[];
91 | total: number;
92 | page: number;
93 | limit: number;
94 | totalPages: number;
95 | }
96 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_delete/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 | import {
3 | McpToolResponse,
4 | ResponseFormat,
5 | createResponseFormatEnum,
6 | } from "../../../types/mcp.js";
7 |
8 | // Schema for individual project removal
9 | const SingleProjectSchema = z
10 | .object({
11 | mode: z.literal("single"),
12 | id: z
13 | .string()
14 | .describe("Project identifier to permanently remove from the system"),
15 | responseFormat: createResponseFormatEnum()
16 | .optional()
17 | .default(ResponseFormat.FORMATTED)
18 | .describe(
19 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
20 | ),
21 | })
22 | .describe("Remove a specific project entity by its unique identifier");
23 |
24 | // Schema for multi-project cleanup operation
25 | const BulkProjectSchema = z
26 | .object({
27 | mode: z.literal("bulk"),
28 | projectIds: z
29 | .array(z.string())
30 | .min(1)
31 | .describe(
32 | "Collection of project identifiers to remove in a single operation",
33 | ),
34 | responseFormat: createResponseFormatEnum()
35 | .optional()
36 | .default(ResponseFormat.FORMATTED)
37 | .describe(
38 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
39 | ),
40 | })
41 | .describe(
42 | "Batch removal of multiple project entities in a single transaction",
43 | );
44 |
45 | // Schema shapes for tool registration
46 | export const AtlasProjectDeleteSchemaShape = {
47 | mode: z
48 | .enum(["single", "bulk"])
49 | .describe(
50 | "Operation strategy - 'single' for individual removal with detailed feedback, 'bulk' for efficient batch operations with aggregated results",
51 | ),
52 | id: z
53 | .string()
54 | .optional()
55 | .describe(
56 | "Target project identifier for permanent removal including all associated tasks and knowledge (required for mode='single')",
57 | ),
58 | projectIds: z
59 | .array(z.string())
60 | .optional()
61 | .describe(
62 | "Collection of project identifiers to permanently remove in a single atomic transaction (required for mode='bulk')",
63 | ),
64 | responseFormat: createResponseFormatEnum()
65 | .optional()
66 | .describe(
67 | "Desired response format: 'formatted' (default string) or 'json' (raw object)",
68 | ),
69 | } as const;
70 |
71 | // Schema for validation
72 | export const AtlasProjectDeleteSchema = z.discriminatedUnion("mode", [
73 | SingleProjectSchema,
74 | BulkProjectSchema,
75 | ]);
76 |
77 | export type AtlasProjectDeleteInput = z.infer<typeof AtlasProjectDeleteSchema>;
78 | export type AtlasProjectDeleteResponse = McpToolResponse;
79 |
```
--------------------------------------------------------------------------------
/src/webui/styling/base.css:
--------------------------------------------------------------------------------
```css
1 | /* ==========================================================================
2 | Base Styles
3 | ========================================================================== */
4 | body {
5 | font-family: var(--font-family-sans-serif);
6 | margin: 0;
7 | background-color: var(--bg-color);
8 | color: var(--text-color);
9 | line-height: 1.65;
10 | font-size: 16px;
11 | -webkit-font-smoothing: antialiased;
12 | -moz-osx-font-smoothing: grayscale;
13 | transition:
14 | background-color 0.2s ease-out,
15 | color 0.2s ease-out;
16 | }
17 |
18 | /* Visually hidden class for accessibility */
19 | .visually-hidden {
20 | position: absolute;
21 | width: 1px;
22 | height: 1px;
23 | padding: 0;
24 | margin: -1px;
25 | overflow: hidden;
26 | clip: rect(0, 0, 0, 0);
27 | white-space: nowrap;
28 | border: 0;
29 | }
30 |
31 | /* ==========================================================================
32 | Typography
33 | ========================================================================== */
34 | h1,
35 | h2,
36 | h3 {
37 | color: var(--text-color);
38 | margin-top: 0;
39 | font-weight: 600; /* Semi-bold for headings */
40 | }
41 |
42 | h1 {
43 | font-size: 2.25rem; /* 36px */
44 | margin-bottom: var(--spacing-lg);
45 | text-align: center;
46 | color: var(--primary-color);
47 | font-weight: 700; /* Bold for main title */
48 | }
49 |
50 | h2 {
51 | /* Section titles like "Project Details" */
52 | font-size: 1.75rem; /* 28px */
53 | margin-bottom: var(--spacing-md);
54 | padding-bottom: var(--spacing-sm);
55 | border-bottom: 1px solid var(--border-color); /* Softer underline */
56 | }
57 |
58 | h3 {
59 | /* Sub-section titles like "Tasks", "Knowledge Items" */
60 | font-size: 1.375rem; /* 22px */
61 | margin-bottom: var(--spacing-md);
62 | color: var(--text-color);
63 | }
64 |
65 | label {
66 | display: block;
67 | margin-bottom: var(--spacing-sm);
68 | font-weight: 500; /* Medium weight */
69 | color: var(--secondary-text-color);
70 | font-size: 0.9rem;
71 | }
72 |
73 | p {
74 | margin-bottom: var(--spacing-md);
75 | }
76 |
77 | a {
78 | color: var(--primary-color);
79 | text-decoration: none;
80 | transition: color 0.2s ease-out;
81 | }
82 |
83 | a:hover,
84 | a:focus {
85 | color: var(--primary-hover-color);
86 | text-decoration: underline;
87 | outline: none; /* Handled by box-shadow on focus for interactive elements */
88 | }
89 |
90 | pre {
91 | /* General preformatted text styling */
92 | background-color: var(--code-bg-color);
93 | color: var(--text-color);
94 | padding: var(--spacing-sm);
95 | border-radius: var(--border-radius-sm);
96 | white-space: pre-wrap;
97 | word-wrap: break-word;
98 | font-family: var(--font-family-monospace);
99 | font-size: 0.9rem;
100 | border: 1px solid var(--code-border-color);
101 | max-height: 250px;
102 | overflow-y: auto;
103 | margin-top: var(--spacing-xs);
104 | transition:
105 | background-color 0.2s ease-out,
106 | border-color 0.2s ease-out,
107 | color 0.2s ease-out;
108 | }
109 |
```
--------------------------------------------------------------------------------
/src/webui/logic/dom-elements.js:
--------------------------------------------------------------------------------
```javascript
1 | /**
2 | * @fileoverview Centralized DOM element selections.
3 | * @module src/webui/logic/dom-elements
4 | */
5 |
6 | /**
7 | * Object containing references to frequently used DOM elements.
8 | * @type {object}
9 | * @property {HTMLElement} app - The main application container.
10 | * @property {HTMLSelectElement} projectSelect - The project selection dropdown.
11 | * @property {HTMLButtonElement} refreshButton - The button to refresh project list.
12 | * @property {HTMLElement} projectDetailsContainer - Container for project details.
13 | * @property {HTMLElement} detailsContent - Content area for project details.
14 | * @property {HTMLElement} tasksContainer - Container for tasks.
15 | * @property {HTMLElement} tasksContent - Content area for tasks.
16 | * @property {HTMLElement} knowledgeContainer - Container for knowledge items.
17 | * @property {HTMLElement} knowledgeContent - Content area for knowledge items.
18 | * @property {HTMLElement} errorMessageDiv - Div to display error messages.
19 | * @property {HTMLElement} neo4jStatusSpan - Span to display Neo4j connection status.
20 | * @property {HTMLInputElement} themeCheckbox - Checkbox for theme toggling.
21 | * @property {HTMLElement} themeLabel - Label for the theme toggle.
22 | * @property {HTMLButtonElement} taskViewModeToggle - Button to toggle task view mode.
23 | * @property {HTMLButtonElement} taskFlowToggle - Button to toggle task flow view.
24 | * @property {HTMLElement} taskFlowContainer - Container for the task flow diagram.
25 | * @property {HTMLButtonElement} knowledgeViewModeToggle - Button to toggle knowledge view mode.
26 | */
27 | export const dom = {
28 | app: document.getElementById("app"),
29 | projectSelect: document.getElementById("project-select"),
30 | refreshButton: document.getElementById("refresh-button"),
31 | projectDetailsContainer: document.getElementById("project-details-container"),
32 | detailsContent: document.getElementById("details-content"),
33 | tasksContainer: document.getElementById("tasks-container"),
34 | tasksContent: document.getElementById("tasks-content"),
35 | knowledgeContainer: document.getElementById("knowledge-container"),
36 | knowledgeContent: document.getElementById("knowledge-content"),
37 | errorMessageDiv: document.getElementById("error-message"),
38 | neo4jStatusSpan: document.getElementById("neo4j-status"),
39 | themeCheckbox: document.getElementById("theme-checkbox"),
40 | themeLabel: document.querySelector(".theme-label"),
41 | taskViewModeToggle: document.getElementById("task-view-mode-toggle"),
42 | taskFlowToggle: document.getElementById("task-flow-toggle"),
43 | taskFlowContainer: document.getElementById("task-flow-container"),
44 | knowledgeViewModeToggle: document.getElementById(
45 | "knowledge-view-mode-toggle",
46 | ),
47 | };
48 |
```
--------------------------------------------------------------------------------
/src/webui/styling/theme.css:
--------------------------------------------------------------------------------
```css
1 | /* ==========================================================================
2 | Global Variables & Theme Setup
3 | ========================================================================== */
4 | :root {
5 | /* Light Mode (Default) - Modern Minimalist */
6 | --bg-color: #f4f7f9; /* Lighter, softer background */
7 | --text-color: #333; /* Dark grey for text, not pure black */
8 | --primary-color: #007bff; /* Standard blue accent */
9 | --primary-hover-color: #0056b3;
10 | --secondary-text-color: #555; /* Slightly darker secondary text */
11 | --border-color: #e0e0e0; /* Softer borders */
12 | --card-bg-color: #ffffff;
13 | --shadow-color: rgba(0, 0, 0, 0.05); /* Softer shadow */
14 | --error-color: #d9534f;
15 | --error-bg-color: #fdf7f7;
16 | --error-border-color: #f0c9c8;
17 | --success-color: #5cb85c;
18 | --warning-color: #f0ad4e;
19 | --warning-bg-color: #fcf8e3; /* For backgrounds if needed */
20 | --code-bg-color: #f9f9f9; /* Very light grey for code blocks */
21 | --code-border-color: #efefef;
22 | --connection-status-bg: #efefef;
23 | --data-section-bg: var(
24 | --card-bg-color
25 | ); /* Sections same as card for minimalism */
26 | --data-item-border-color: #eaeaea; /* Softer item border */
27 | --button-text-color: #ffffff;
28 | --button-secondary-bg: #6c757d;
29 | --button-secondary-hover-bg: #5a6268;
30 |
31 | --font-family-sans-serif:
32 | "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
33 | "Helvetica Neue", Arial, sans-serif;
34 | --font-family-monospace:
35 | SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
36 | monospace;
37 |
38 | --border-radius-sm: 4px;
39 | --border-radius-md: 8px;
40 | --border-radius-lg: 12px;
41 |
42 | --spacing-xs: 4px;
43 | --spacing-sm: 8px;
44 | --spacing-md: 16px;
45 | --spacing-lg: 24px;
46 | --spacing-xl: 32px;
47 | }
48 |
49 | .dark-mode {
50 | --bg-color: #121212; /* Very dark background */
51 | --text-color: #e0e0e0;
52 | /* --primary-color: #007bff; /* Can adjust for dark mode if needed, e.g., a lighter blue */
53 | /* --primary-hover-color: #0056b3; */
54 | --secondary-text-color: #aaa;
55 | --border-color: #333; /* Darker, subtle borders */
56 | --card-bg-color: #1e1e1e; /* Dark card background */
57 | --shadow-color: rgba(255, 255, 255, 0.03); /* Very subtle light shadow */
58 | --error-color: #e77773;
59 | --error-bg-color: #3d2727;
60 | --error-border-color: #5c4040;
61 | --success-color: #7bc77b;
62 | --warning-color: #f5c76e;
63 | --warning-bg-color: #4a412a; /* For backgrounds if needed */
64 | --code-bg-color: #282828;
65 | --code-border-color: #383838;
66 | --connection-status-bg: #282828;
67 | --data-section-bg: var(--card-bg-color);
68 | --data-item-border-color: #333;
69 | /* --button-text-color: #ffffff; */ /* Usually remains white */
70 | --button-secondary-bg: #495057;
71 | --button-secondary-hover-bg: #343a40;
72 | }
73 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_list/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { KnowledgeFilterOptions } from "../../../services/neo4j/types.js";
2 | import { Neo4jKnowledge } from "../../../services/neo4j/types.js";
3 |
4 | /**
5 | * Query parameters for retrieving and filtering knowledge items
6 | */
7 | export interface KnowledgeListRequest {
8 | /** ID of the project to list knowledge items for (required) */
9 | projectId: string;
10 |
11 | /** Array of tags to filter by (items matching any tag will be included) */
12 | tags?: string[];
13 |
14 | /** Filter by knowledge domain/category */
15 | domain?: string;
16 |
17 | /** Text search query to filter results by content relevance */
18 | search?: string;
19 |
20 | /** Page number for paginated results (Default: 1) */
21 | page?: number;
22 |
23 | /** Number of results per page, maximum 100 (Default: 20) */
24 | limit?: number;
25 | }
26 |
27 | /**
28 | * Response structure for knowledge queries
29 | */
30 | export interface KnowledgeListResponse {
31 | /** Collection of knowledge items matching search criteria */
32 | knowledge: KnowledgeItem[];
33 |
34 | /** Total record count matching criteria (pre-pagination) */
35 | total: number;
36 |
37 | /** Current pagination position */
38 | page: number;
39 |
40 | /** Pagination size setting */
41 | limit: number;
42 |
43 | /** Total available pages for the current query */
44 | totalPages: number;
45 | }
46 |
47 | /**
48 | * Knowledge item entity structure for API responses
49 | */
50 | export interface KnowledgeItem {
51 | /** Neo4j internal node identifier */
52 | identity?: number;
53 |
54 | /** Neo4j node type designations */
55 | labels?: string[];
56 |
57 | /** Core knowledge item attributes */
58 | properties?: {
59 | /** Unique knowledge item identifier */
60 | id: string;
61 |
62 | /** Project this knowledge belongs to */
63 | projectId: string;
64 |
65 | /** Knowledge content */
66 | text: string;
67 |
68 | /** Categorical labels for organization and filtering */
69 | tags?: string[];
70 |
71 | /** Primary knowledge area/discipline */
72 | domain: string;
73 |
74 | /** Reference sources supporting this knowledge */
75 | citations?: string[];
76 |
77 | /** Creation timestamp (ISO format) */
78 | createdAt: string;
79 |
80 | /** Last modification timestamp (ISO format) */
81 | updatedAt: string;
82 | };
83 |
84 | /** Neo4j element identifier */
85 | elementId?: string;
86 |
87 | /** Unique knowledge item identifier */
88 | id: string;
89 |
90 | /** Project this knowledge belongs to */
91 | projectId: string;
92 |
93 | /** Knowledge content */
94 | text: string;
95 |
96 | /** Categorical labels for organization and filtering */
97 | tags?: string[];
98 |
99 | /** Primary knowledge area/discipline */
100 | domain: string;
101 |
102 | /** Reference sources supporting this knowledge */
103 | citations?: string[];
104 |
105 | /** Creation timestamp (ISO format) */
106 | createdAt: string;
107 |
108 | /** Last modification timestamp (ISO format) */
109 | updatedAt: string;
110 |
111 | /** Associated project name (for context) */
112 | projectName?: string;
113 | }
114 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_unified_search/types.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 | import { SearchResultItem } from "../../../services/neo4j/index.js";
3 |
4 | // Schema for the tool input
5 | export const UnifiedSearchRequestSchema = z.object({
6 | property: z
7 | .string()
8 | .optional()
9 | .describe(
10 | "Optional: Target a specific property for search. If specified, a regex-based search is performed on this property (e.g., 'name', 'description', 'text', 'tags', 'urls'). If omitted, a full-text index search is performed across default fields for each entity type (typically includes fields like name, title, description, text, tags, but depends on index configuration).",
11 | ),
12 | value: z.string().describe("The search term or phrase."),
13 | entityTypes: z
14 | .array(z.enum(["project", "task", "knowledge"]))
15 | .optional()
16 | .describe(
17 | "Array of entity types ('project', 'task', 'knowledge') to include in search (Default: all types if omitted)",
18 | ),
19 | caseInsensitive: z
20 | .boolean()
21 | .optional()
22 | .default(true)
23 | .describe(
24 | "For regex search (when 'property' is specified): Perform a case-insensitive search (Default: true). Not applicable to full-text index searches (when 'property' is omitted).",
25 | ),
26 | fuzzy: z
27 | .boolean()
28 | .optional()
29 | .default(true) // Changed default to true for more intuitive "contains" search on specific properties
30 | .describe(
31 | "For regex search (when 'property' is specified): Enables 'contains' matching (Default: true). Set to false for an exact match on the property. For full-text search (when 'property' is omitted): If true, attempts to construct a fuzzy Lucene query (e.g., term~1); if false (default for this case, as Zod default is true but full-text might interpret it differently if not explicitly handled), performs a standard term match.",
32 | ),
33 | taskType: z
34 | .string()
35 | .optional()
36 | .describe(
37 | "Optional filter by project/task classification (applies to project and task types)",
38 | ),
39 | assignedToUserId: z
40 | .string()
41 | .optional()
42 | .describe(
43 | "Optional: Filter tasks by the ID of the assigned user. Only applicable when 'property' is specified (regex search) and 'entityTypes' includes 'task'.",
44 | ),
45 | page: z
46 | .number()
47 | .int()
48 | .positive()
49 | .optional()
50 | .default(1)
51 | .describe("Page number for paginated results (Default: 1)"),
52 | limit: z
53 | .number()
54 | .int()
55 | .positive()
56 | .max(100)
57 | .optional()
58 | .default(20)
59 | .describe("Number of results per page, maximum 100 (Default: 20)"),
60 | });
61 |
62 | export type UnifiedSearchRequestInput = z.infer<
63 | typeof UnifiedSearchRequestSchema
64 | >;
65 |
66 | export interface UnifiedSearchResponse {
67 | results: SearchResultItem[];
68 | total: number;
69 | page: number;
70 | limit: number;
71 | totalPages: number;
72 | }
73 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_database_clean/cleanDatabase.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { BaseErrorCode, McpError } from "../../../types/errors.js";
2 | import { ResponseFormat, createToolResponse } from "../../../types/mcp.js";
3 | import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
4 | import { ToolContext } from "../../../types/tool.js";
5 | import { formatDatabaseCleanResponse } from "./responseFormat.js";
6 | import { AtlasDatabaseCleanInput, AtlasDatabaseCleanSchema } from "./types.js";
7 | import { neo4jDriver } from "../../../services/neo4j/driver.js";
8 |
9 | /**
10 | * Execute a complete database reset operation
11 | * This permanently removes all data from the Neo4j database
12 | *
13 | * @param input No input parameters required
14 | * @param context Tool execution context
15 | * @returns Formatted response with operation results
16 | */
17 | export const atlasDatabaseClean = async (
18 | input: unknown,
19 | context: ToolContext,
20 | ) => {
21 | const reqContext =
22 | context.requestContext ??
23 | requestContextService.createRequestContext({
24 | toolName: "atlasDatabaseClean",
25 | });
26 | try {
27 | // Parse and validate input against schema (should be empty object)
28 | const validatedInput: AtlasDatabaseCleanInput =
29 | AtlasDatabaseCleanSchema.parse(input);
30 |
31 | // Log the operation start
32 | logger.warning("Executing complete database reset operation", reqContext);
33 |
34 | // Track execution metrics
35 | const startTime = Date.now();
36 |
37 | try {
38 | // Execute a very simple query that will delete all relationships and nodes
39 | await neo4jDriver.executeQuery("MATCH (n) DETACH DELETE n");
40 |
41 | // Calculate execution duration
42 | const executionTime = Date.now() - startTime;
43 |
44 | // Log successful operation
45 | logger.warning("Database reset completed successfully", {
46 | ...reqContext,
47 | executionTime: `${executionTime}ms`,
48 | });
49 |
50 | const result = {
51 | success: true,
52 | message:
53 | "Database has been completely reset - all nodes and relationships removed",
54 | timestamp: new Date().toISOString(),
55 | };
56 |
57 | // Conditionally format response
58 | if (validatedInput.responseFormat === ResponseFormat.JSON) {
59 | return createToolResponse(JSON.stringify(result, null, 2));
60 | } else {
61 | return formatDatabaseCleanResponse(result);
62 | }
63 | } catch (error) {
64 | throw new Error(
65 | `Failed to execute database reset: ${error instanceof Error ? error.message : String(error)}`,
66 | );
67 | }
68 | } catch (error) {
69 | // Log error
70 | logger.error("Failed to reset database", error as Error, {
71 | ...reqContext,
72 | inputReceived: input,
73 | });
74 |
75 | // Handle specific error cases
76 | if (error instanceof McpError) {
77 | throw error;
78 | }
79 |
80 | // Convert generic errors to McpError
81 | throw new McpError(
82 | BaseErrorCode.INTERNAL_ERROR,
83 | `Error resetting database: ${error instanceof Error ? error.message : "Unknown error"}`,
84 | );
85 | }
86 | };
87 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_delete/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2 | import { z } from "zod";
3 | import {
4 | createToolExample,
5 | createToolMetadata,
6 | registerTool,
7 | } from "../../../types/tool.js";
8 | import { atlasDeleteTask } from "./deleteTask.js";
9 | import { AtlasTaskDeleteSchemaShape } from "./types.js";
10 |
11 | export const registerAtlasTaskDeleteTool = (server: McpServer) => {
12 | registerTool(
13 | server,
14 | "atlas_task_delete",
15 | "Deletes existing task(s) from the system with support for both single task removal and bulk deletion operations",
16 | AtlasTaskDeleteSchemaShape,
17 | atlasDeleteTask,
18 | createToolMetadata({
19 | examples: [
20 | createToolExample(
21 | {
22 | mode: "single",
23 | id: "task_api_gateway",
24 | },
25 | `{
26 | "success": true,
27 | "message": "Task with ID task_api_gateway removed successfully",
28 | "id": "task_api_gateway"
29 | }`,
30 | "Remove a completed task from the system",
31 | ),
32 | createToolExample(
33 | {
34 | mode: "bulk",
35 | taskIds: ["task_graphql_schema", "task_auth", "task_old_feature"],
36 | },
37 | `{
38 | "success": true,
39 | "message": "Successfully removed 3 tasks",
40 | "deleted": ["task_graphql_schema", "task_auth", "task_old_feature"],
41 | "errors": []
42 | }`,
43 | "Clean up multiple completed or deprecated tasks in a single operation",
44 | ),
45 | ],
46 | requiredPermission: "task:delete",
47 | returnSchema: z.union([
48 | // Single task deletion response
49 | z.object({
50 | id: z.string().describe("Task ID"),
51 | success: z.boolean().describe("Operation success status"),
52 | message: z.string().describe("Result message"),
53 | }),
54 | // Bulk deletion response
55 | z.object({
56 | success: z.boolean().describe("Operation success status"),
57 | message: z.string().describe("Result message"),
58 | deleted: z
59 | .array(z.string())
60 | .describe("IDs of successfully deleted tasks"),
61 | errors: z
62 | .array(
63 | z.object({
64 | taskId: z.string().describe("Task ID that failed to delete"),
65 | error: z
66 | .object({
67 | code: z.string().describe("Error code"),
68 | message: z.string().describe("Error message"),
69 | details: z
70 | .any()
71 | .optional()
72 | .describe("Additional error details"),
73 | })
74 | .describe("Error information"),
75 | }),
76 | )
77 | .describe("Deletion errors"),
78 | }),
79 | ]),
80 | rateLimit: {
81 | windowMs: 60 * 1000, // 1 minute
82 | maxRequests: 15, // 15 requests per minute (either single or bulk)
83 | },
84 | }),
85 | );
86 | };
87 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_list/listTasks.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { TaskService } from "../../../services/neo4j/taskService.js";
2 | import { ProjectService } from "../../../services/neo4j/projectService.js";
3 | import {
4 | BaseErrorCode,
5 | McpError,
6 | ProjectErrorCode,
7 | } from "../../../types/errors.js";
8 | import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
9 | import { ToolContext } from "../../../types/tool.js";
10 | import { TaskListRequestInput, TaskListRequestSchema } from "./types.js";
11 | import { formatTaskListResponse } from "./responseFormat.js";
12 |
13 | export const atlasListTasks = async (input: unknown, context: ToolContext) => {
14 | const reqContext =
15 | context.requestContext ??
16 | requestContextService.createRequestContext({ toolName: "atlasListTasks" });
17 | try {
18 | // Parse and validate input against schema
19 | const validatedInput = TaskListRequestSchema.parse(input);
20 |
21 | // Log operation
22 | logger.info("Listing tasks for project", {
23 | ...reqContext,
24 | projectId: validatedInput.projectId,
25 | });
26 |
27 | // First check if the project exists
28 | const projectExists = await ProjectService.getProjectById(
29 | validatedInput.projectId,
30 | );
31 |
32 | if (!projectExists) {
33 | throw new McpError(
34 | ProjectErrorCode.PROJECT_NOT_FOUND,
35 | `Project with ID ${validatedInput.projectId} not found`,
36 | { projectId: validatedInput.projectId },
37 | );
38 | }
39 |
40 | // Call the task service to get tasks with filters
41 | const tasksResult = await TaskService.getTasks({
42 | projectId: validatedInput.projectId,
43 | status: validatedInput.status,
44 | assignedTo: validatedInput.assignedTo,
45 | priority: validatedInput.priority,
46 | tags: validatedInput.tags,
47 | taskType: validatedInput.taskType,
48 | sortBy: validatedInput.sortBy,
49 | sortDirection: validatedInput.sortDirection,
50 | page: validatedInput.page,
51 | limit: validatedInput.limit,
52 | });
53 |
54 | logger.info("Tasks retrieved successfully", {
55 | ...reqContext,
56 | projectId: validatedInput.projectId,
57 | taskCount: tasksResult.data.length,
58 | totalTasks: tasksResult.total,
59 | });
60 |
61 | // Create the response object with task data
62 | const responseData = {
63 | tasks: tasksResult.data,
64 | total: tasksResult.total,
65 | page: tasksResult.page,
66 | limit: tasksResult.limit,
67 | totalPages: tasksResult.totalPages,
68 | };
69 |
70 | // Return the raw response data object
71 | return responseData;
72 | } catch (error) {
73 | // Handle specific error cases
74 | if (error instanceof McpError) {
75 | throw error;
76 | }
77 |
78 | logger.error("Failed to list tasks", error as Error, {
79 | ...reqContext,
80 | inputReceived: input, // validatedInput might not be defined here
81 | });
82 |
83 | // Convert other errors to McpError
84 | throw new McpError(
85 | BaseErrorCode.INTERNAL_ERROR,
86 | `Error listing tasks: ${error instanceof Error ? error.message : "Unknown error"}`,
87 | );
88 | }
89 | };
90 |
```
--------------------------------------------------------------------------------
/src/services/neo4j/events.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { EventEmitter } from "events";
2 | import { logger, requestContextService } from "../../utils/index.js"; // Updated import path
3 |
4 | /**
5 | * Event types for database operations
6 | */
7 | export enum DatabaseEventType {
8 | WRITE_OPERATION = "write_operation",
9 | READ_OPERATION = "read_operation",
10 | TRANSACTION_COMPLETE = "transaction_complete",
11 | ERROR = "error",
12 | }
13 |
14 | /**
15 | * Database event system to facilitate communication between services
16 | * Uses the publish-subscribe pattern to decouple components
17 | */
18 | class DatabaseEventSystem {
19 | private emitter: EventEmitter;
20 | private static instance: DatabaseEventSystem;
21 |
22 | private constructor() {
23 | this.emitter = new EventEmitter();
24 | // Set a higher limit for listeners to avoid warnings
25 | this.emitter.setMaxListeners(20);
26 |
27 | // Log all events in debug mode
28 | if (process.env.NODE_ENV === "development") {
29 | this.emitter.on(DatabaseEventType.WRITE_OPERATION, (details) => {
30 | const reqContext = requestContextService.createRequestContext({
31 | operation: "DatabaseEvent.WRITE_OPERATION",
32 | eventDetails: details,
33 | });
34 | logger.debug("Database write operation", reqContext);
35 | });
36 |
37 | this.emitter.on(DatabaseEventType.ERROR, (error) => {
38 | const reqContext = requestContextService.createRequestContext({
39 | operation: "DatabaseEvent.ERROR",
40 | eventError: error,
41 | });
42 | logger.debug("Database event error", reqContext);
43 | });
44 | }
45 | }
46 |
47 | /**
48 | * Get the singleton instance
49 | */
50 | public static getInstance(): DatabaseEventSystem {
51 | if (!DatabaseEventSystem.instance) {
52 | DatabaseEventSystem.instance = new DatabaseEventSystem();
53 | }
54 | return DatabaseEventSystem.instance;
55 | }
56 |
57 | /**
58 | * Subscribe to a database event
59 | * @param eventType Event type to subscribe to
60 | * @param listener Function to call when the event occurs
61 | */
62 | public subscribe<T>(
63 | eventType: DatabaseEventType,
64 | listener: (data: T) => void,
65 | ): void {
66 | this.emitter.on(eventType, listener);
67 | }
68 |
69 | /**
70 | * Unsubscribe from a database event
71 | * @param eventType Event type to unsubscribe from
72 | * @param listener Function to remove
73 | */
74 | public unsubscribe<T>(
75 | eventType: DatabaseEventType,
76 | listener: (data: T) => void,
77 | ): void {
78 | this.emitter.off(eventType, listener);
79 | }
80 |
81 | /**
82 | * Publish a database event
83 | * @param eventType Event type to publish
84 | * @param data Event data
85 | */
86 | public publish<T>(eventType: DatabaseEventType, data: T): void {
87 | this.emitter.emit(eventType, data);
88 | }
89 |
90 | /**
91 | * Subscribe to a database event only once
92 | * @param eventType Event type to subscribe to
93 | * @param listener Function to call when the event occurs
94 | */
95 | public subscribeOnce<T>(
96 | eventType: DatabaseEventType,
97 | listener: (data: T) => void,
98 | ): void {
99 | this.emitter.once(eventType, listener);
100 | }
101 | }
102 |
103 | // Export singleton instance
104 | export const databaseEvents = DatabaseEventSystem.getInstance();
105 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_delete/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2 | import { z } from "zod";
3 | import {
4 | createToolExample,
5 | createToolMetadata,
6 | registerTool,
7 | } from "../../../types/tool.js";
8 | import { atlasDeleteProject } from "./deleteProject.js";
9 | import { AtlasProjectDeleteSchemaShape } from "./types.js";
10 |
11 | export const registerAtlasProjectDeleteTool = (server: McpServer) => {
12 | registerTool(
13 | server,
14 | "atlas_project_delete",
15 | "Removes project entities and associated resources from the system with cascading deletion of linked tasks and knowledge items",
16 | AtlasProjectDeleteSchemaShape,
17 | atlasDeleteProject,
18 | createToolMetadata({
19 | examples: [
20 | createToolExample(
21 | {
22 | mode: "single",
23 | id: "proj_ms_migration",
24 | },
25 | `{
26 | "success": true,
27 | "message": "Project with ID proj_ms_migration deleted successfully",
28 | "id": "proj_ms_migration"
29 | }`,
30 | "Remove a completed engineering project from the system",
31 | ),
32 | createToolExample(
33 | {
34 | mode: "bulk",
35 | projectIds: ["proj_graphql", "proj_perf", "proj_deprecated_api"],
36 | },
37 | `{
38 | "success": true,
39 | "message": "Successfully deleted 3 projects",
40 | "deleted": ["proj_graphql", "proj_perf", "proj_deprecated_api"],
41 | "errors": []
42 | }`,
43 | "Clean up multiple completed or deprecated projects in a single atomic operation",
44 | ),
45 | ],
46 | requiredPermission: "project:delete",
47 | returnSchema: z.union([
48 | // Single project deletion response
49 | z.object({
50 | id: z.string().describe("Project ID"),
51 | success: z.boolean().describe("Operation success status"),
52 | message: z.string().describe("Result message"),
53 | }),
54 | // Bulk deletion response
55 | z.object({
56 | success: z.boolean().describe("Operation success status"),
57 | message: z.string().describe("Result message"),
58 | deleted: z
59 | .array(z.string())
60 | .describe("IDs of successfully deleted projects"),
61 | errors: z
62 | .array(
63 | z.object({
64 | projectId: z
65 | .string()
66 | .describe("Project ID that failed to delete"),
67 | error: z
68 | .object({
69 | code: z.string().describe("Error code"),
70 | message: z.string().describe("Error message"),
71 | details: z
72 | .any()
73 | .optional()
74 | .describe("Additional error details"),
75 | })
76 | .describe("Error information"),
77 | }),
78 | )
79 | .describe("Deletion errors"),
80 | }),
81 | ]),
82 | rateLimit: {
83 | windowMs: 60 * 1000, // 1 minute
84 | maxRequests: 10, // 10 requests per minute (either single or bulk)
85 | },
86 | }),
87 | );
88 | };
89 |
```
--------------------------------------------------------------------------------
/src/webui/logic/app-state.js:
--------------------------------------------------------------------------------
```javascript
1 | /**
2 | * @fileoverview Manages global application state and provides utility functions.
3 | * @module src/webui/logic/app-state
4 | */
5 |
6 | /**
7 | * Global application state.
8 | * @type {object}
9 | * @property {object|null} driver - Neo4j driver instance. Initialized by api-service.
10 | * @property {string|null} currentProjectId - ID of the currently selected project.
11 | * @property {object|null} currentProject - Details of the currently selected project.
12 | * @property {Array<object>} currentTasks - List of tasks for the current project.
13 | * @property {Array<object>} currentKnowledgeItems - List of knowledge items for the current project.
14 | * @property {string} tasksViewMode - Current view mode for tasks ('detailed' or 'compact').
15 | * @property {string} knowledgeViewMode - Current view mode for knowledge items ('detailed' or 'compact').
16 | * @property {boolean} showingTaskFlow - Flag indicating if the task flow diagram is visible.
17 | */
18 | export const state = {
19 | driver: null,
20 | currentProjectId: null,
21 | currentProject: null,
22 | currentTasks: [],
23 | currentKnowledgeItems: [],
24 | tasksViewMode: "detailed", // 'detailed' or 'compact'
25 | knowledgeViewMode: "detailed", // 'detailed' or 'compact'
26 | showingTaskFlow: false,
27 | };
28 |
29 | /**
30 | * Utility functions for common tasks.
31 | * @type {object}
32 | */
33 | export const utils = {
34 | /**
35 | * Escapes HTML special characters in a string.
36 | * @param {string|null|undefined} unsafe - The string to escape.
37 | * @returns {string} The escaped string, or "N/A" if input is null/undefined.
38 | */
39 | escapeHtml: (unsafe) => {
40 | if (unsafe === null || typeof unsafe === "undefined") return "N/A";
41 | return String(unsafe).replace(/[&<>"']/g, (match) => {
42 | switch (match) {
43 | case "&":
44 | return "&";
45 | case "<":
46 | return "<";
47 | case ">":
48 | return ">";
49 | case '"':
50 | return """;
51 | case "'":
52 | return "'";
53 | default:
54 | return match;
55 | }
56 | });
57 | },
58 |
59 | /**
60 | * Safely parses a JSON string.
61 | * @param {string|Array<any>} jsonString - The JSON string or an already parsed array.
62 | * @param {Array<any>} [defaultValue=[]] - The default value to return on parsing failure.
63 | * @returns {Array<any>} The parsed array or the default value.
64 | */
65 | parseJsonSafe: (jsonString, defaultValue = []) => {
66 | if (typeof jsonString !== "string") {
67 | return Array.isArray(jsonString) ? jsonString : defaultValue;
68 | }
69 | try {
70 | const parsed = JSON.parse(jsonString);
71 | return Array.isArray(parsed) ? parsed : defaultValue;
72 | } catch (e) {
73 | console.warn("Failed to parse JSON string:", jsonString, e);
74 | return defaultValue;
75 | }
76 | },
77 |
78 | /**
79 | * Formats a date string into a locale-specific string.
80 | * @param {string|null|undefined} dateString - The date string to format.
81 | * @returns {string} The formatted date string, "N/A", or "Invalid Date".
82 | */
83 | formatDate: (dateString) => {
84 | if (!dateString) return "N/A";
85 | try {
86 | return new Date(dateString).toLocaleString();
87 | } catch (e) {
88 | return "Invalid Date";
89 | }
90 | },
91 | };
92 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_delete/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2 | import { z } from "zod";
3 | import {
4 | createToolExample,
5 | createToolMetadata,
6 | registerTool,
7 | } from "../../../types/tool.js";
8 | import { atlasDeleteKnowledge } from "./deleteKnowledge.js";
9 | import { AtlasKnowledgeDeleteSchemaShape } from "./types.js";
10 |
11 | export const registerAtlasKnowledgeDeleteTool = (server: McpServer) => {
12 | registerTool(
13 | server,
14 | "atlas_knowledge_delete",
15 | "Deletes existing knowledge item(s) from the system with support for individual removal and batch operations",
16 | AtlasKnowledgeDeleteSchemaShape,
17 | atlasDeleteKnowledge,
18 | createToolMetadata({
19 | examples: [
20 | createToolExample(
21 | {
22 | mode: "single",
23 | id: "know_graphql_benefits",
24 | },
25 | `{
26 | "success": true,
27 | "message": "Knowledge item with ID know_graphql_benefits removed successfully",
28 | "id": "know_graphql_benefits"
29 | }`,
30 | "Remove a specific knowledge item from the system",
31 | ),
32 | createToolExample(
33 | {
34 | mode: "bulk",
35 | knowledgeIds: [
36 | "know_api_design",
37 | "know_security_best_practices",
38 | "know_deprecated_methods",
39 | ],
40 | },
41 | `{
42 | "success": true,
43 | "message": "Successfully removed 3 knowledge items",
44 | "deleted": ["know_api_design", "know_security_best_practices", "know_deprecated_methods"],
45 | "errors": []
46 | }`,
47 | "Clean up multiple knowledge items in a single operation",
48 | ),
49 | ],
50 | requiredPermission: "knowledge:delete",
51 | returnSchema: z.union([
52 | // Single knowledge deletion response
53 | z.object({
54 | id: z.string().describe("Knowledge ID"),
55 | success: z.boolean().describe("Operation success status"),
56 | message: z.string().describe("Result message"),
57 | }),
58 | // Bulk deletion response
59 | z.object({
60 | success: z.boolean().describe("Operation success status"),
61 | message: z.string().describe("Result message"),
62 | deleted: z
63 | .array(z.string())
64 | .describe("IDs of successfully deleted knowledge items"),
65 | errors: z
66 | .array(
67 | z.object({
68 | knowledgeId: z
69 | .string()
70 | .describe("Knowledge ID that failed to delete"),
71 | error: z
72 | .object({
73 | code: z.string().describe("Error code"),
74 | message: z.string().describe("Error message"),
75 | details: z
76 | .any()
77 | .optional()
78 | .describe("Additional error details"),
79 | })
80 | .describe("Error information"),
81 | }),
82 | )
83 | .describe("Deletion errors"),
84 | }),
85 | ]),
86 | rateLimit: {
87 | windowMs: 60 * 1000, // 1 minute
88 | maxRequests: 10, // 10 requests per minute (either single or bulk)
89 | },
90 | }),
91 | );
92 | };
93 |
```
--------------------------------------------------------------------------------
/src/types/errors.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from "zod";
2 | import { McpContent, McpToolResponse } from "./mcp.js";
3 |
4 | // Base error codes that all tools can use
5 | export enum BaseErrorCode {
6 | UNAUTHORIZED = "UNAUTHORIZED",
7 | RATE_LIMITED = "RATE_LIMITED",
8 | VALIDATION_ERROR = "VALIDATION_ERROR",
9 | INTERNAL_ERROR = "INTERNAL_ERROR",
10 | NOT_FOUND = "NOT_FOUND",
11 | PERMISSION_DENIED = "PERMISSION_DENIED",
12 | SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
13 | CONFIGURATION_ERROR = "CONFIGURATION_ERROR",
14 | INITIALIZATION_FAILED = "INITIALIZATION_FAILED",
15 | FORBIDDEN = "FORBIDDEN",
16 | }
17 |
18 | // Project-specific error codes
19 | export enum ProjectErrorCode {
20 | DUPLICATE_NAME = "DUPLICATE_NAME",
21 | INVALID_STATUS = "INVALID_STATUS",
22 | PROJECT_NOT_FOUND = "PROJECT_NOT_FOUND",
23 | DEPENDENCY_CYCLE = "DEPENDENCY_CYCLE",
24 | INVALID_DEPENDENCY = "INVALID_DEPENDENCY",
25 | }
26 |
27 | // Task-specific error codes
28 | export enum TaskErrorCode {
29 | TASK_NOT_FOUND = "TASK_NOT_FOUND",
30 | INVALID_STATUS = "INVALID_STATUS",
31 | INVALID_PRIORITY = "INVALID_PRIORITY",
32 | INVALID_DEPENDENCY = "INVALID_DEPENDENCY",
33 | DEPENDENCY_CYCLE = "DEPENDENCY_CYCLE",
34 | }
35 |
36 | // Note-specific error codes
37 | export enum NoteErrorCode {
38 | INVALID_TAGS = "INVALID_TAGS",
39 | NOTE_NOT_FOUND = "NOTE_NOT_FOUND",
40 | }
41 |
42 | // Link-specific error codes
43 | export enum LinkErrorCode {
44 | INVALID_URL = "INVALID_URL",
45 | LINK_NOT_FOUND = "LINK_NOT_FOUND",
46 | DUPLICATE_URL = "DUPLICATE_URL",
47 | }
48 |
49 | // Member-specific error codes
50 | export enum MemberErrorCode {
51 | INVALID_ROLE = "INVALID_ROLE",
52 | MEMBER_NOT_FOUND = "MEMBER_NOT_FOUND",
53 | DUPLICATE_MEMBER = "DUPLICATE_MEMBER",
54 | }
55 |
56 | // Skill-specific error codes
57 | export enum SkillErrorCode {
58 | SKILL_NOT_FOUND = "SKILL_NOT_FOUND",
59 | DEPENDENCY_NOT_FOUND = "DEPENDENCY_NOT_FOUND",
60 | MISSING_PARAMETER = "MISSING_PARAMETER",
61 | CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
62 | SKILL_EXECUTION_ERROR = "SKILL_EXECUTION_ERROR",
63 | }
64 |
65 | // Database export/import error codes
66 | export enum DatabaseExportImportErrorCode {
67 | EXPORT_ERROR = "EXPORT_ERROR",
68 | IMPORT_ERROR = "IMPORT_ERROR",
69 | FILE_ACCESS_ERROR = "FILE_ACCESS_ERROR",
70 | INVALID_EXPORT_FORMAT = "INVALID_EXPORT_FORMAT",
71 | RESET_FAILED = "RESET_FAILED",
72 | INVALID_CONFIRMATION_CODE = "INVALID_CONFIRMATION_CODE",
73 | PERMISSION_DENIED = "PERMISSION_DENIED",
74 | }
75 |
76 | // Base MCP error class
77 | export class McpError extends Error {
78 | constructor(
79 | public code:
80 | | BaseErrorCode
81 | | ProjectErrorCode
82 | | TaskErrorCode
83 | | NoteErrorCode
84 | | LinkErrorCode
85 | | MemberErrorCode
86 | | SkillErrorCode
87 | | DatabaseExportImportErrorCode,
88 | message: string,
89 | public details?: Record<string, unknown>,
90 | ) {
91 | super(message);
92 | this.name = "McpError";
93 | }
94 |
95 | toResponse(): McpToolResponse {
96 | const content: McpContent = {
97 | type: "text",
98 | text: `Error [${this.code}]: ${this.message}${
99 | this.details
100 | ? `\nDetails: ${JSON.stringify(this.details, null, 2)}`
101 | : ""
102 | }`,
103 | };
104 |
105 | return {
106 | content: [content],
107 | isError: true,
108 | _type: "tool_response",
109 | };
110 | }
111 | }
112 |
113 | // Error schema for validation
114 | export const ErrorSchema = z.object({
115 | code: z.string(),
116 | message: z.string(),
117 | details: z.record(z.unknown()).optional(),
118 | });
119 |
120 | export type ErrorResponse = z.infer<typeof ErrorSchema>;
121 |
```
--------------------------------------------------------------------------------
/scripts/clean.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * @fileoverview Utility script to clean build artifacts and temporary directories.
5 | * @module scripts/clean
6 | * By default, it removes the 'dist' and 'logs' directories.
7 | * Custom directories can be specified as command-line arguments.
8 | * Works on all platforms using Node.js path normalization.
9 | *
10 | * @example
11 | * // Add to package.json:
12 | * // "scripts": {
13 | * // "clean": "ts-node --esm scripts/clean.ts",
14 | * // "rebuild": "npm run clean && npm run build"
15 | * // }
16 | *
17 | * // Run with default directories:
18 | * // npm run clean
19 | *
20 | * // Run with custom directories:
21 | * // ts-node --esm scripts/clean.ts temp coverage
22 | */
23 |
24 | import { rm, access } from "fs/promises";
25 | import { join } from "path";
26 |
27 | /**
28 | * Represents the result of a clean operation for a single directory.
29 | * @property dir - The name of the directory targeted for cleaning.
30 | * @property status - Indicates if the cleaning was successful or skipped.
31 | * @property reason - If skipped, the reason why.
32 | */
33 | interface CleanResult {
34 | dir: string;
35 | status: "success" | "skipped";
36 | reason?: string;
37 | }
38 |
39 | /**
40 | * Asynchronously checks if a directory exists at the given path.
41 | * @param dirPath - The absolute or relative path to the directory.
42 | * @returns A promise that resolves to `true` if the directory exists, `false` otherwise.
43 | */
44 | async function directoryExists(dirPath: string): Promise<boolean> {
45 | try {
46 | await access(dirPath);
47 | return true;
48 | } catch {
49 | return false;
50 | }
51 | }
52 |
53 | /**
54 | * Main function to perform the cleaning operation.
55 | * It reads command line arguments for target directories or uses defaults ('dist', 'logs').
56 | * Reports the status of each cleaning attempt.
57 | */
58 | const clean = async (): Promise<void> => {
59 | try {
60 | let dirsToClean: string[] = ["dist", "logs"];
61 | const args = process.argv.slice(2);
62 |
63 | if (args.length > 0) {
64 | dirsToClean = args;
65 | }
66 |
67 | console.log(`Attempting to clean directories: ${dirsToClean.join(", ")}`);
68 |
69 | const results = await Promise.allSettled(
70 | dirsToClean.map(async (dir): Promise<CleanResult> => {
71 | const dirPath = join(process.cwd(), dir);
72 |
73 | try {
74 | const exists = await directoryExists(dirPath);
75 |
76 | if (!exists) {
77 | return { dir, status: "skipped", reason: "does not exist" };
78 | }
79 |
80 | await rm(dirPath, { recursive: true, force: true });
81 | return { dir, status: "success" };
82 | } catch (error) {
83 | // Rethrow to be caught by Promise.allSettled's rejection case
84 | throw error;
85 | }
86 | }),
87 | );
88 |
89 | results.forEach((result) => {
90 | if (result.status === "fulfilled") {
91 | const { dir, status, reason } = result.value;
92 | if (status === "success") {
93 | console.log(`Successfully cleaned directory: ${dir}`);
94 | } else {
95 | console.log(`Skipped cleaning directory ${dir}: ${reason}.`);
96 | }
97 | } else {
98 | // The error here is the actual error object from the rejected promise
99 | console.error(
100 | `Error cleaning a directory (details below):\n`,
101 | result.reason,
102 | );
103 | }
104 | });
105 | } catch (error) {
106 | console.error(
107 | "An unexpected error occurred during the clean script execution:",
108 | error instanceof Error ? error.message : error,
109 | );
110 | process.exit(1);
111 | }
112 | };
113 |
114 | clean();
115 |
```
--------------------------------------------------------------------------------
/src/mcp/transports/stdioTransport.ts:
--------------------------------------------------------------------------------
```typescript
1 | /**
2 | * @fileoverview Handles the setup and connection for the Stdio MCP transport.
3 | * Implements the MCP Specification 2025-03-26 for stdio transport.
4 | * This transport communicates directly over standard input (stdin) and
5 | * standard output (stdout), typically used when the MCP server is launched
6 | * as a child process by a host application.
7 | *
8 | * Specification Reference:
9 | * https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx#stdio
10 | *
11 | * --- Authentication Note ---
12 | * As per the MCP Authorization Specification (2025-03-26, Section 1.2),
13 | * STDIO transports SHOULD NOT implement HTTP-based authentication flows.
14 | * Authorization is typically handled implicitly by the host application
15 | * controlling the server process. This implementation follows that guideline.
16 | *
17 | * @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
18 | * @module src/mcp-server/transports/stdioTransport
19 | */
20 |
21 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
23 | import { ErrorHandler, logger, RequestContext } from "../../utils/index.js";
24 |
25 | /**
26 | * Connects a given `McpServer` instance to the Stdio transport.
27 | * This function initializes the SDK's `StdioServerTransport`, which manages
28 | * communication over `process.stdin` and `process.stdout` according to the
29 | * MCP stdio transport specification.
30 | *
31 | * MCP Spec Points Covered by SDK's `StdioServerTransport`:
32 | * - Reads JSON-RPC messages (requests, notifications, responses, batches) from stdin.
33 | * - Writes JSON-RPC messages to stdout.
34 | * - Handles newline delimiters and ensures no embedded newlines in output messages.
35 | * - Ensures only valid MCP messages are written to stdout.
36 | *
37 | * Logging via the `logger` utility MAY result in output to stderr, which is
38 | * permitted by the spec for logging purposes.
39 | *
40 | * @param server - The `McpServer` instance.
41 | * @param parentContext - The logging and tracing context from the calling function.
42 | * @returns A promise that resolves when the Stdio transport is successfully connected.
43 | * @throws {Error} If the connection fails during setup.
44 | */
45 | export async function connectStdioTransport(
46 | server: McpServer,
47 | parentContext: RequestContext,
48 | ): Promise<void> {
49 | const operationContext = {
50 | ...parentContext,
51 | operation: "connectStdioTransport",
52 | transportType: "Stdio",
53 | };
54 | logger.debug("Attempting to connect stdio transport...", operationContext);
55 |
56 | try {
57 | logger.debug("Creating StdioServerTransport instance...", operationContext);
58 | const transport = new StdioServerTransport();
59 |
60 | logger.debug(
61 | "Connecting McpServer instance to StdioServerTransport...",
62 | operationContext,
63 | );
64 | await server.connect(transport);
65 |
66 | logger.info(
67 | "MCP Server connected and listening via stdio transport.",
68 | operationContext,
69 | );
70 | if (process.stdout.isTTY) {
71 | console.log(
72 | `\n🚀 MCP Server running in STDIO mode.\n (MCP Spec: 2025-03-26 Stdio Transport)\n`,
73 | );
74 | }
75 | } catch (err) {
76 | ErrorHandler.handleError(err, { ...operationContext, critical: true });
77 | throw err; // Re-throw after handling to allow caller to react if necessary
78 | }
79 | }
80 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_list/responseFormat.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator
2 | import { KnowledgeListResponse } from "./types.js";
3 |
4 | /**
5 | * Defines a generic interface for formatting data into a string.
6 | */
7 | interface ResponseFormatter<T> {
8 | format(data: T): string;
9 | }
10 |
11 | /**
12 | * Formatter for structured knowledge query responses
13 | */
14 | export class KnowledgeListFormatter
15 | implements ResponseFormatter<KnowledgeListResponse>
16 | {
17 | format(data: KnowledgeListResponse): string {
18 | const { knowledge, total, page, limit, totalPages } = data;
19 |
20 | // Generate result summary section
21 | const summary =
22 | `Knowledge Repository\n\n` +
23 | `Total Items: ${total}\n` +
24 | `Page: ${page} of ${totalPages}\n` +
25 | `Displaying: ${Math.min(limit, knowledge.length)} item(s) per page\n`;
26 |
27 | if (knowledge.length === 0) {
28 | return `${summary}\n\nNo knowledge items matched the specified criteria`;
29 | }
30 |
31 | // Format each knowledge item
32 | const knowledgeSections = knowledge
33 | .map((item, index) => {
34 | const {
35 | id,
36 | projectId,
37 | projectName,
38 | domain,
39 | tags,
40 | text,
41 | citations,
42 | createdAt,
43 | updatedAt,
44 | } = item;
45 |
46 | let knowledgeSection =
47 | `${index + 1}. ${domain || "Uncategorized"} Knowledge\n\n` +
48 | `ID: ${id}\n` +
49 | `Project: ${projectName || projectId}\n` +
50 | `Domain: ${domain}\n`;
51 |
52 | // Add tags if available
53 | if (tags && tags.length > 0) {
54 | knowledgeSection += `Tags: ${tags.join(", ")}\n`;
55 | }
56 |
57 | // Format dates
58 | const createdDate = createdAt
59 | ? new Date(createdAt).toLocaleString()
60 | : "Unknown Date";
61 | const updatedDate = updatedAt
62 | ? new Date(updatedAt).toLocaleString()
63 | : "Unknown Date";
64 |
65 | knowledgeSection +=
66 | `Created: ${createdDate}\n` + `Updated: ${updatedDate}\n\n`;
67 |
68 | // Add knowledge content
69 | knowledgeSection += `Content:\n${text || "No content available"}\n`;
70 |
71 | // Add citations if available
72 | if (citations && citations.length > 0) {
73 | knowledgeSection += `\nCitations:\n`;
74 | citations.forEach((citation, citIndex) => {
75 | knowledgeSection += `${citIndex + 1}. ${citation}\n`;
76 | });
77 | }
78 |
79 | return knowledgeSection;
80 | })
81 | .join("\n\n----------\n\n");
82 |
83 | // Append pagination metadata for multi-page results
84 | let paginationInfo = "";
85 | if (totalPages > 1) {
86 | paginationInfo =
87 | `\n\nPagination Controls\n\n` +
88 | `Viewing page ${page} of ${totalPages}.\n` +
89 | `${page < totalPages ? "Use 'page' parameter to navigate to additional results." : ""}`;
90 | }
91 |
92 | return `${summary}\n\n${knowledgeSections}${paginationInfo}`;
93 | }
94 | }
95 |
96 | /**
97 | * Create a human-readable formatted response for the atlas_knowledge_list tool
98 | *
99 | * @param data The structured knowledge query response data
100 | * @param isError Whether this response represents an error condition
101 | * @returns Formatted MCP tool response with appropriate structure
102 | */
103 | export function formatKnowledgeListResponse(data: any, isError = false): any {
104 | const formatter = new KnowledgeListFormatter();
105 | const formattedText = formatter.format(data as KnowledgeListResponse); // Assuming data is KnowledgeListResponse
106 | return createToolResponse(formattedText, isError);
107 | }
108 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_knowledge_list/listKnowledge.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { McpError } from "../../../types/errors.js";
2 | import { BaseErrorCode } from "../../../types/errors.js";
3 | import { logger, requestContextService } from "../../../utils/index.js"; // Import requestContextService
4 | import {
5 | KnowledgeService,
6 | ProjectService,
7 | } from "../../../services/neo4j/index.js";
8 | import {
9 | KnowledgeItem,
10 | KnowledgeListRequest,
11 | KnowledgeListResponse,
12 | } from "./types.js";
13 |
14 | /**
15 | * Retrieve and filter knowledge items based on specified criteria
16 | *
17 | * @param request The knowledge query parameters including filters and pagination controls
18 | * @returns Promise resolving to structured knowledge items
19 | */
20 | export async function listKnowledge(
21 | request: KnowledgeListRequest,
22 | ): Promise<KnowledgeListResponse> {
23 | const reqContext = requestContextService.createRequestContext({
24 | operation: "listKnowledge",
25 | requestParams: request,
26 | });
27 | try {
28 | const { projectId, tags, domain, search, page = 1, limit = 20 } = request;
29 |
30 | // Parameter validation
31 | if (!projectId) {
32 | throw new McpError(
33 | BaseErrorCode.VALIDATION_ERROR,
34 | "Project ID is required to list knowledge items",
35 | );
36 | }
37 |
38 | // Verify that the project exists
39 | const project = await ProjectService.getProjectById(projectId);
40 | if (!project) {
41 | throw new McpError(
42 | BaseErrorCode.NOT_FOUND,
43 | `Project with ID ${projectId} not found`,
44 | );
45 | }
46 |
47 | // Sanitize pagination parameters
48 | const validatedPage = Math.max(1, page);
49 | const validatedLimit = Math.min(Math.max(1, limit), 100);
50 |
51 | // Get knowledge items with filters
52 | const knowledgeResult = await KnowledgeService.getKnowledge({
53 | projectId,
54 | tags,
55 | domain,
56 | search,
57 | page: validatedPage,
58 | limit: validatedLimit,
59 | });
60 |
61 | // Process knowledge items to ensure consistent structure
62 | const knowledgeItems: KnowledgeItem[] = knowledgeResult.data.map((item) => {
63 | // Handle Neo4j record structure which may include properties field
64 | const rawItem = item as any;
65 | const properties = rawItem.properties || rawItem;
66 |
67 | return {
68 | id: properties.id,
69 | projectId: properties.projectId,
70 | text: properties.text,
71 | tags: properties.tags || [],
72 | domain: properties.domain,
73 | citations: properties.citations || [],
74 | createdAt: properties.createdAt,
75 | updatedAt: properties.updatedAt,
76 | projectName: project.name, // Include project name for context
77 | };
78 | });
79 |
80 | // Construct the response
81 | const response: KnowledgeListResponse = {
82 | knowledge: knowledgeItems,
83 | total: knowledgeResult.total,
84 | page: validatedPage,
85 | limit: validatedLimit,
86 | totalPages: knowledgeResult.totalPages,
87 | };
88 |
89 | logger.info("Knowledge query executed successfully", {
90 | ...reqContext,
91 | projectId,
92 | count: knowledgeItems.length,
93 | total: knowledgeResult.total,
94 | hasTags: !!tags,
95 | hasDomain: !!domain,
96 | hasSearch: !!search,
97 | });
98 |
99 | return response;
100 | } catch (error) {
101 | logger.error("Knowledge query execution failed", error as Error, {
102 | ...reqContext,
103 | detail: (error as Error).message,
104 | });
105 |
106 | if (error instanceof McpError) {
107 | throw error;
108 | }
109 |
110 | throw new McpError(
111 | BaseErrorCode.INTERNAL_ERROR,
112 | `Failed to retrieve knowledge items: ${error instanceof Error ? error.message : String(error)}`,
113 | );
114 | }
115 | }
116 |
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "atlas-mcp-server",
3 | "version": "2.8.15",
4 | "description": "ATLAS (Adaptive Task & Logic Automation System): An MCP server enabling LLM agents to manage projects, tasks, and knowledge via a Neo4j-backed, three-tier architecture. Facilitates complex workflow automation and project management through LLM Agents.",
5 | "type": "module",
6 | "main": "dist/index.js",
7 | "exports": "./dist/index.js",
8 | "files": [
9 | "dist"
10 | ],
11 | "bin": {
12 | "atlas-mcp-server": "dist/index.js"
13 | },
14 | "repository": {
15 | "type": "git",
16 | "url": "git+https://github.com/cyanheads/atlas-mcp-server.git"
17 | },
18 | "bugs": {
19 | "url": "https://github.com/cyanheads/atlas-mcp-server/issues"
20 | },
21 | "homepage": "https://github.com/cyanheads/atlas-mcp-server#readme",
22 | "scripts": {
23 | "build": "tsc && node --loader ts-node/esm scripts/make-executable.ts dist/index.js",
24 | "db:backup": "node --loader ts-node/esm src/services/neo4j/backupRestoreService/scripts/db-backup.ts",
25 | "db:import": "node --loader ts-node/esm src/services/neo4j/backupRestoreService/scripts/db-import.ts",
26 | "dev": "tsc -w",
27 | "docker:down": "docker-compose down",
28 | "docker:logs": "docker-compose logs -f",
29 | "docker:up": "docker-compose up -d",
30 | "docs:generate": "typedoc",
31 | "fetch-spec": "ts-node --esm scripts/fetch-openapi-spec.ts",
32 | "format": "prettier --write \"**/*.{ts,js,json,md,html,css}\"",
33 | "inspector": "mcp-inspector --config mcp.json --server atlas-mcp-server",
34 | "rebuild": "ts-node --esm scripts/clean.ts && npm run build",
35 | "start": "node dist/index.js",
36 | "start:http": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=http node dist/index.js",
37 | "start:stdio": "MCP_LOG_LEVEL=debug MCP_TRANSPORT_TYPE=stdio node dist/index.js",
38 | "tree": "ts-node --esm scripts/tree.ts",
39 | "webui": "npx serve src/webui -l 8000"
40 | },
41 | "keywords": [
42 | "ai-integration",
43 | "agent",
44 | "atlas",
45 | "authentication",
46 | "automation",
47 | "client-server",
48 | "collaboration",
49 | "dependency-tracking",
50 | "graph-database",
51 | "http",
52 | "jwt",
53 | "knowledge-management",
54 | "llm",
55 | "llm-agent",
56 | "mcp",
57 | "model-context-protocol",
58 | "model-context-protocol-server",
59 | "neo4j",
60 | "project-management",
61 | "server",
62 | "task-management",
63 | "three-tier-architecture",
64 | "typescript",
65 | "unified-search",
66 | "workflow-automation"
67 | ],
68 | "author": "cyanheads <[email protected]> (https://github.com/cyanheads/atlas-mcp-server#readme)",
69 | "license": "Apache-2.0",
70 | "engines": {
71 | "node": ">=16.0.0"
72 | },
73 | "dependencies": {
74 | "@modelcontextprotocol/sdk": "^1.12.1",
75 | "@types/node": "^22.15.29",
76 | "@types/node-cron": "^3.0.11",
77 | "chrono-node": "2.8.0",
78 | "commander": "^14.0.0",
79 | "cross-env": "^7.0.3",
80 | "date-fns": "^4.1.0",
81 | "dotenv": "^16.5.0",
82 | "express": "^5.1.0",
83 | "fuzzysort": "^3.1.0",
84 | "ignore": "^7.0.5",
85 | "jsonwebtoken": "^9.0.2",
86 | "nanoid": "^5.1.5",
87 | "neo4j-driver": "^5.28.1",
88 | "node-cron": "^4.1.0",
89 | "node-schedule": "^2.1.1",
90 | "openai": "^5.1.1",
91 | "partial-json": "^0.1.7",
92 | "sanitize-html": "^2.17.0",
93 | "tiktoken": "^1.0.21",
94 | "validator": "^13.15.15",
95 | "winston": "^3.17.0",
96 | "winston-daily-rotate-file": "^5.0.0",
97 | "yargs": "^18.0.0",
98 | "zod": "^3.25.51"
99 | },
100 | "devDependencies": {
101 | "@types/express": "^5.0.2",
102 | "@types/js-yaml": "^4.0.9",
103 | "@types/jsonwebtoken": "^9.0.9",
104 | "@types/node-schedule": "^2.1.7",
105 | "@types/sanitize-html": "^2.16.0",
106 | "@types/validator": "^13.15.1",
107 | "axios": "^1.9.0",
108 | "js-yaml": "^4.1.0",
109 | "prettier": "^3.5.3",
110 | "ts-node": "^10.9.2",
111 | "typedoc": "^0.28.5",
112 | "typescript": "^5.8.3"
113 | }
114 | }
115 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_task_delete/responseFormat.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator
2 |
3 | /**
4 | * Defines a generic interface for formatting data into a string.
5 | */
6 | interface ResponseFormatter<T> {
7 | format(data: T): string;
8 | }
9 |
10 | /**
11 | * Interface for single task deletion response
12 | */
13 | interface SingleTaskDeleteResponse {
14 | id: string;
15 | success: boolean;
16 | message: string;
17 | }
18 |
19 | /**
20 | * Interface for bulk task deletion response
21 | */
22 | interface BulkTaskDeleteResponse {
23 | success: boolean;
24 | message: string;
25 | deleted: string[];
26 | errors: {
27 | taskId: string;
28 | error: {
29 | code: string;
30 | message: string;
31 | details?: any;
32 | };
33 | }[];
34 | }
35 |
36 | /**
37 | * Formatter for individual task removal responses
38 | */
39 | export class SingleTaskDeleteFormatter
40 | implements ResponseFormatter<SingleTaskDeleteResponse>
41 | {
42 | format(data: SingleTaskDeleteResponse): string {
43 | return (
44 | `Task Removal\n\n` +
45 | `Result: ${data.success ? "✅ Success" : "❌ Failed"}\n` +
46 | `Task ID: ${data.id}\n` +
47 | `Message: ${data.message}\n`
48 | );
49 | }
50 | }
51 |
52 | /**
53 | * Formatter for batch task removal responses
54 | */
55 | export class BulkTaskDeleteFormatter
56 | implements ResponseFormatter<BulkTaskDeleteResponse>
57 | {
58 | format(data: BulkTaskDeleteResponse): string {
59 | const { success, message, deleted, errors } = data;
60 |
61 | const summary =
62 | `Task Cleanup Operation\n\n` +
63 | `Status: ${success && errors.length === 0 ? "✅ Complete Success" : errors.length > 0 ? "⚠️ Partial Success / Errors" : "✅ Success (No items or no errors)"}\n` +
64 | `Summary: ${message}\n` +
65 | `Removed: ${deleted.length} task(s)\n` +
66 | `Errors: ${errors.length} error(s)\n`;
67 |
68 | let deletedSection = "";
69 | if (deleted.length > 0) {
70 | deletedSection = `\n--- Removed Tasks (${deleted.length}) ---\n\n`;
71 | deletedSection += deleted.map((id) => `- ${id}`).join("\n");
72 | }
73 |
74 | let errorsSection = "";
75 | if (errors.length > 0) {
76 | errorsSection = `\n--- Errors Encountered (${errors.length}) ---\n\n`;
77 | errorsSection += errors
78 | .map((errorItem, index) => {
79 | return (
80 | `${index + 1}. Failed to remove ID: ${errorItem.taskId}\n` +
81 | ` Error Code: ${errorItem.error.code}\n` +
82 | ` Message: ${errorItem.error.message}` +
83 | (errorItem.error.details
84 | ? `\n Details: ${JSON.stringify(errorItem.error.details)}`
85 | : "")
86 | );
87 | })
88 | .join("\n\n");
89 | }
90 |
91 | return `${summary}${deletedSection}${errorsSection}`.trim();
92 | }
93 | }
94 |
95 | /**
96 | * Create a human-readable formatted response for the atlas_task_delete tool
97 | *
98 | * @param data The structured task removal operation results (SingleTaskDeleteResponse or BulkTaskDeleteResponse)
99 | * @param isError This parameter is effectively ignored as success is determined from data.success. Kept for signature consistency if needed.
100 | * @returns Formatted MCP tool response with appropriate structure
101 | */
102 | export function formatTaskDeleteResponse(data: any, isError = false): any {
103 | const isBulkResponse =
104 | data.hasOwnProperty("deleted") &&
105 | Array.isArray(data.deleted) &&
106 | data.hasOwnProperty("errors");
107 |
108 | let formattedText: string;
109 | let finalIsError: boolean;
110 |
111 | if (isBulkResponse) {
112 | const formatter = new BulkTaskDeleteFormatter();
113 | const bulkData = data as BulkTaskDeleteResponse;
114 | formattedText = formatter.format(bulkData);
115 | finalIsError = !bulkData.success || bulkData.errors.length > 0;
116 | } else {
117 | const formatter = new SingleTaskDeleteFormatter();
118 | const singleData = data as SingleTaskDeleteResponse;
119 | formattedText = formatter.format(singleData);
120 | finalIsError = !singleData.success;
121 | }
122 | return createToolResponse(formattedText, finalIsError);
123 | }
124 |
```
--------------------------------------------------------------------------------
/src/mcp/tools/atlas_project_delete/responseFormat.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { createToolResponse } from "../../../types/mcp.js"; // Import the new response creator
2 |
3 | /**
4 | * Defines a generic interface for formatting data into a string.
5 | */
6 | interface ResponseFormatter<T> {
7 | format(data: T): string;
8 | }
9 |
10 | /**
11 | * Interface for single project deletion response
12 | */
13 | interface SingleProjectDeleteResponse {
14 | id: string;
15 | success: boolean;
16 | message: string;
17 | }
18 |
19 | /**
20 | * Interface for bulk project deletion response
21 | */
22 | interface BulkProjectDeleteResponse {
23 | success: boolean;
24 | message: string;
25 | deleted: string[];
26 | errors: {
27 | projectId: string;
28 | error: {
29 | code: string;
30 | message: string;
31 | details?: any;
32 | };
33 | }[];
34 | }
35 |
36 | /**
37 | * Formatter for individual project removal responses
38 | */
39 | export class SingleProjectDeleteFormatter
40 | implements ResponseFormatter<SingleProjectDeleteResponse>
41 | {
42 | format(data: SingleProjectDeleteResponse): string {
43 | return (
44 | `Project Removal\n\n` +
45 | `Result: ${data.success ? "✅ Success" : "❌ Failed"}\n` +
46 | `Project ID: ${data.id}\n` +
47 | `Message: ${data.message}\n`
48 | );
49 | }
50 | }
51 |
52 | /**
53 | * Formatter for batch project removal responses
54 | */
55 | export class BulkProjectDeleteFormatter
56 | implements ResponseFormatter<BulkProjectDeleteResponse>
57 | {
58 | format(data: BulkProjectDeleteResponse): string {
59 | const { success, message, deleted, errors } = data;
60 |
61 | const summary =
62 | `Project Cleanup Operation\n\n` +
63 | `Status: ${success && errors.length === 0 ? "✅ Complete Success" : errors.length > 0 ? "⚠️ Partial Success / Errors" : "✅ Success (No items or no errors)"}\n` +
64 | `Summary: ${message}\n` +
65 | `Removed: ${deleted.length} project(s)\n` +
66 | `Errors: ${errors.length} error(s)\n`;
67 |
68 | let deletedSection = "";
69 | if (deleted.length > 0) {
70 | deletedSection = `\n--- Removed Projects (${deleted.length}) ---\n\n`;
71 | deletedSection += deleted.map((id) => `- ${id}`).join("\n");
72 | }
73 |
74 | let errorsSection = "";
75 | if (errors.length > 0) {
76 | errorsSection = `\n--- Errors Encountered (${errors.length}) ---\n\n`;
77 | errorsSection += errors
78 | .map((errorItem, index) => {
79 | return (
80 | `${index + 1}. Failed to remove ID: ${errorItem.projectId}\n` +
81 | ` Error Code: ${errorItem.error.code}\n` +
82 | ` Message: ${errorItem.error.message}` +
83 | (errorItem.error.details
84 | ? `\n Details: ${JSON.stringify(errorItem.error.details)}`
85 | : "")
86 | );
87 | })
88 | .join("\n\n");
89 | }
90 |
91 | return `${summary}${deletedSection}${errorsSection}`.trim();
92 | }
93 | }
94 |
95 | /**
96 | * Create a human-readable formatted response for the atlas_project_delete tool
97 | *
98 | * @param data The structured project removal operation results (SingleProjectDeleteResponse or BulkProjectDeleteResponse)
99 | * @param isError This parameter is effectively ignored as success is determined from data.success. Kept for signature consistency if needed.
100 | * @returns Formatted MCP tool response with appropriate structure
101 | */
102 | export function formatProjectDeleteResponse(data: any, isError = false): any {
103 | const isBulkResponse =
104 | data.hasOwnProperty("deleted") &&
105 | Array.isArray(data.deleted) &&
106 | data.hasOwnProperty("errors");
107 |
108 | let formattedText: string;
109 | let finalIsError: boolean;
110 |
111 | if (isBulkResponse) {
112 | const formatter = new BulkProjectDeleteFormatter();
113 | const bulkData = data as BulkProjectDeleteResponse;
114 | formattedText = formatter.format(bulkData);
115 | finalIsError = !bulkData.success || bulkData.errors.length > 0;
116 | } else {
117 | const formatter = new SingleProjectDeleteFormatter();
118 | const singleData = data as SingleProjectDeleteResponse;
119 | formattedText = formatter.format(singleData);
120 | finalIsError = !singleData.success;
121 | }
122 | return createToolResponse(formattedText, finalIsError);
123 | }
124 |
```