AI Agent History RAG MCP Server
This server provides persistent, searchable memory for AI coding agent and chat history using RAG (Retrieval-Augmented Generation), solving context loss across sessions.
Core Search Capabilities
Semantic & Hybrid Search (
search_conversations): Query past conversations using natural language, combining vector similarity and BM25 full-text search with RRF reranking. Supports filtering by project/date, optional query analysis, and result synthesis.File Change Tracking (
search_file_changes): Find specific file modifications (edits/writes) across all sessions, with filtering by file path, project, date, and operation type.Session Summaries (
get_session_summary): Retrieve summaries of past sessions by ID, recency, or project to quickly understand what was discussed or worked on.
Monitoring & Diagnostics
Index Status (
get_index_status): Check indexed chunk counts, unique projects, watched/pending files, and cache statistics.Server Status (
get_server_status): Get comprehensive health info including version, uptime, component health, performance metrics, embedder config, and recent errors.
Multi-Agent & Multi-Machine Support
Ingests history from Claude Code, Codex, Gemini CLI, Google Antigravity, ChatGPT, and Claude App exports.
Supports single-machine or centralized multi-machine deployments with client registry, offline resilience, and automatic sync.
Real-time, incremental indexing — only new content is processed.
Infrastructure
Configurable embeddings (Ollama, OpenAI, vLLM, LiteLLM, Vertex AI).
Storage backends: LanceDB (local) or Cloud Spanner (production).
PSK-based authentication with key rotation, web dashboard, and Prometheus metrics.
doctorandinstallcommands for troubleshooting and setup.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@AI Agent History RAG MCP Serversearch my Claude Code sessions for the fix I applied to the payment service"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
AI Agent History RAG
AI Agent History RAG is a native Go daemon and MCP proxy for searchable history from Claude Code, Codex, Gemini, Antigravity, ChatGPT exports, and Claude app exports. Production storage is Cloud Spanner with a registered Vertex embedding model. The daemon has no local-storage or unauthenticated production mode.
Supported native entrypoints
Platform | Operator entrypoint | Lifecycle |
Container |
| Docker owns process restart; |
macOS |
| Per-user LaunchAgent runs |
Linux |
| Per-user systemd unit runs |
Windows |
| Per-user logon task runs |
MCP |
| Authenticated STDIO proxy to the loopback daemon. |
The repository's Compose file is retained as a compatibility artifact and is not a supported native production operator entrypoint. Use the Dockerfile or a platform installer until that artifact is separately migrated.
Related MCP server: hive-memory
Build
go build -o bin/history-ragd ./cmd/history-ragd
go test ./...For a Windows binary from another platform:
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o bin/history-ragd.exe ./cmd/history-ragdProduction contract
Every service installer validates the following values before registering a native process. Deployment identities are inputs; never place real values in repository files.
CLAUDE_HISTORY_RAG_RUNTIME_CONTRACT=production
CLAUDE_HISTORY_RAG_STORAGE_BACKEND=spanner
CLAUDE_HISTORY_RAG_SPANNER_PROJECT=<project>
CLAUDE_HISTORY_RAG_SPANNER_INSTANCE=<instance>
CLAUDE_HISTORY_RAG_SPANNER_DATABASE=<database>
CLAUDE_HISTORY_RAG_SPANNER_EMBEDDING_MODE=spanner
CLAUDE_HISTORY_RAG_SPANNER_EMBEDDING_MODEL_ID=ConversationEmbeddingModel
CLAUDE_HISTORY_RAG_EMBEDDING_PROVIDER=vertex
CLAUDE_HISTORY_RAG_EMBEDDING_MODEL=gemini-embedding-001
CLAUDE_HISTORY_RAG_EMBEDDING_DIMENSION=3072
CLAUDE_HISTORY_RAG_STATUS_SERVER_HOST=127.0.0.1
CLAUDE_HISTORY_RAG_STATUS_SERVER_PORT=4680
CLAUDE_HISTORY_RAG_CREDENTIALS_SOURCE=application_default
CLAUDE_HISTORY_RAG_CREDENTIALS_PROFILE=impersonated_service_account
CLAUDE_HISTORY_RAG_CREDENTIALS_IDENTITY=<service-account-email>
CLAUDE_HISTORY_RAG_SERVER_PSK=<bearer-secret>The host runtime uses the well-known, owner-protected impersonated ADC carrier.
Credential-file overrides, emulator configuration, and ambient Cloud SDK
configuration are rejected. In particular, leave GOOGLE_APPLICATION_CREDENTIALS,
CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE, CLOUDSDK_CONFIG, and
SPANNER_EMULATOR_HOST unset.
The carrier may retain the legacy authorized_user source or use a
device-bound service_account source. The latter is accepted only inside the
validated impersonation carrier; its target identity, scope, quota project,
source shape, and owner-only file ACL are checked before any Google client is
constructed. Do not commit a carrier, private key, refresh token, or machine
path to this repository.
Source roots
The daemon watches exactly these six source families. Platform installers create missing directories and generate owner-protected native configuration.
Source | Default root |
Claude Code |
|
Codex |
|
Gemini |
|
Antigravity |
|
ChatGPT export |
|
Claude app export |
|
ChatGPT and Claude app exports belong in their respective drop folders. The watcher preserves source identity and rejects unsafe path changes.
Container
Copy .env.docker.example to a private environment file, replace each
placeholder, then build and run the native image:
docker build --tag history-ragd:local .
docker run --rm --env-file .env.docker -p 4680:4680 history-ragd:localThe container binds 0.0.0.0:4680 only inside its network namespace and
requires authentication. Its Docker healthcheck calls /live; it does not
pretend a missing Spanner dependency is ready. Mount persistent source and state
volumes when operating beyond a smoke test.
Host service installation
Host services bind only 127.0.0.1:4680; do not open that listener to the
network. Build the binary first, export the production contract, then install.
macOS
HISTORY_RAGD_BIN="$PWD/bin/history-ragd" ./scripts/install-launchd.sh
./scripts/uninstall-launchd.shLinux
HISTORY_RAGD_BIN="$PWD/bin/history-ragd" ./scripts/install-systemd.sh
./scripts/uninstall-systemd.shWindows
.\scripts\install-windows.ps1 -HistoryRagdPath "$PWD\bin\history-ragd.exe"
.\scripts\uninstall-windows.ps1See Windows operator notes. Windows Task Scheduler validation requires a Windows host; the repository cross-build verifies only that the native executable can be produced.
Liveness and readiness
GET /live is intentionally unauthenticated and answers only whether the
process listener is alive:
curl --fail http://127.0.0.1:4680/liveGET /health and GET /status require a bearer credential. They are readiness
checks: they return 200 only when both Spanner storage and the source watcher
are ready, otherwise 503. They never expose credentials or source paths.
curl --fail -H "Authorization: Bearer $CLAUDE_HISTORY_RAG_SERVER_PSK" \
http://127.0.0.1:4680/healthMCP proxy
Use the native STDIO proxy only after the loopback daemon is running with the same production contract:
./scripts/history-rag-mcp-native.sh --validate-only
./scripts/history-rag-mcp-native.shTroubleshooting
/livefails: inspect the platform service manager and its native process./livesucceeds but/healthreturns 503: confirm Spanner reachability and that all six watcher roots are available to the service user./healthreturns 401: supply the configured bearer secret; do not disable authentication to diagnose the issue.Installer rejects credentials: remove the forbidden ambient credential and emulator overrides, then verify the well-known impersonated ADC carrier.
A source root is rejected: replace links with an owned real directory; the watcher intentionally refuses identity changes.
Verification
./scripts/docs-native-contract.test.sh
go test -race ./internal/history/config ./internal/history/watch ./internal/history/api ./cmd/history-ragd
go vet ./...
go build ./...
go test ./...The exact native contract and its bounded API surface are recorded in docs/NATIVE_COMPATIBILITY_CONTRACT.md.
Available Tools
5 toolsget_index_statusA
Get status of the RAG index.
Use when user asks about memory system health or
why something isn't being found.
Returns:
Dict with index statistics including:
- total_chunks: Number of indexed chunks
- projects_indexed: Number of unique projects
- watched_files: Number of files being tracked
- pending_files: Number of files in queue for processing
- status: Overall health status
- cache_stats: Search cache statistics (if enabled)
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided. The description implies a safe read-only operation but does not explicitly state it is non-destructive or disclose any behavioral traits beyond return values, such as authentication needs or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is succinct, uses bullet points for return fields, and front-loads the core purpose. Every sentence adds value without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has no parameters and no output schema, the description adequately describes what the tool returns. However, it lacks mention of error conditions or behavior when the index is not initialized, which would enhance completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has no parameters, and schema description coverage is 100%. The description does not need to add parameter semantics, so it fully meets expectations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it gets the status of the RAG index, with a specific verb ('Get status') and resource ('RAG index'). It distinguishes from sibling tools like 'get_server_status' by focusing on memory system health.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance: 'Use when user asks about memory system health or why something isn't being found.' This clearly indicates when to invoke the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_server_statusA
Get comprehensive MCP server status and health information.
Use when you need to check server health, performance metrics,
indexing progress, or debug issues with the memory system.
Args:
detail_level: "basic" for summary info, "full" for detailed metrics
including performance, cache stats, and errors
Returns:
Dict with comprehensive server status including:
- server: Version, uptime, PID, platform info
- health: Overall status (healthy/degraded/unhealthy) and component checks
- database: Chunk counts, size (full detail only)
- indexing: Progress, files pending/indexed/failed (full detail only)
- performance: Memory, CPU, query metrics (full detail only)
- cache: Hit rates, size (full detail only)
- embedder: Model info, loaded status (full detail only)
- file_watcher: Running status, queue info (full detail only)
- errors: Recent errors and counts (full detail only)
- configuration: Current settings (full detail only)
| Name | Required | Description | Default |
|---|---|---|---|
| detail_level | No | basic |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does not explicitly state that the tool is read-only or safe for repeated calls, but the return structure implies a non-destructive health check. This is adequate but could be more explicit about side effects or permission requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections: purpose, usage, args, returns. It is somewhat lengthy but every sentence provides value. It could be slightly more concise without losing clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has no output schema, the description provides a comprehensive list of return fields covering server, health, database, indexing, performance, cache, embedder, file_watcher, errors, and configuration. This is more than sufficient for an AI agent to understand the tool's output. The single parameter is fully covered. Sibling tools are distinct, so no missing context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The one parameter 'detail_level' is fully explained in the description with examples of values ('basic', 'full') and what each returns. The schema only provides name, type, and default, so the description adds essential semantic meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Get comprehensive MCP server status and health information.' It uses a specific verb and resource, and is distinct from siblings like get_index_status, get_session_summary, etc. No confusion about what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Use when you need to check server health, performance metrics, indexing progress, or debug issues with the memory system.' This provides clear context for when to use the tool, though it does not explicitly mention when not to use it or list alternatives beyond the sibling context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_session_summaryA
Get summary of conversation session(s).
Use for:
- "What did we work on in the last session?"
- "Summarize our recent conversations"
Args:
session_id: Specific session ID, or None for recent
project_filter: Limit to specific project
count: Number of sessions to summarize
Returns:
Dict with session summaries
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | ||
| session_id | No | ||
| project_filter | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must fully disclose behavioral traits. It only states the return type ('Dict with session summaries') and parameter explanations, but omits whether the operation is read-only, destructive, or has any side effects, rate limits, or prerequisites. This is insufficient for a tool with no annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short (7 lines) and well-structured: purpose, usage examples, args, returns. Every sentence adds value, and the key information is front-loaded. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of an output schema, the description only vaguely mentions 'Dict with session summaries' without detailing the structure or keys. It also does not cover pagination, error behavior, or performance implications. For a tool with 3 parameters and no additional schema, this is adequate but has notable gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has no descriptions for its 3 parameters, so the description takes on the full burden. It clearly explains each parameter's meaning and default behavior (e.g., 'session_id: Specific session ID, or None for recent'), adding essential semantics beyond the raw schema types and defaults.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Get summary of conversation session(s)' with a specific verb and resource. It provides concrete usage examples that distinguish it from siblings like search_conversations, which is for searching individual messages rather than summarizing entire sessions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit use cases ('What did we work on in the last session?', 'Summarize our recent conversations') that help an agent determine when to invoke this tool. However, it does not explicitly state when not to use it or compare it to alternatives, leaving some ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_conversationsA
Search conversation history for relevant context.
Use this to find:
- Previous discussions about a topic
- Decisions made in earlier sessions
- Context that was compacted away
Args:
query: Natural language query
project_filter: Limit to specific project path
date_from: Inclusive lower timestamp bound. Accepts ISO-8601 datetime
or date-only values such as 2026-06-13.
date_to: Inclusive upper timestamp bound. Accepts ISO-8601 datetime
or date-only values such as 2026-06-15.
limit: Maximum results (default 5, min 1, max 50)
use_hybrid: Use hybrid search (vector + BM25) for better results
(default True)
enable_analysis: Enable query analysis and result evaluation for
improved relevance (default True). Adds 'analysis' and 'evaluation'
to response.
enable_synthesis: Enable result synthesis to combine multiple results
into a coherent summary (default False). Adds 'synthesis' to response
with key_points and deduplicated content.
include_debug: Include detailed timing metrics and decision tracking
in response (default False). Useful for debugging and performance
analysis. Adds 'metrics' to response.
Returns:
Dict with results list and metadata. When enable_analysis=True, includes:
- analysis: Query intent, detected technologies, key terms
- evaluation: Relevance score, completeness assessment
When enable_synthesis=True, includes:
- synthesis: Primary content, key points, code snippets
When include_debug=True, includes:
- metrics: Timing data (query_analysis_ms, search_ms, etc.), decisions made
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| date_to | No | ||
| date_from | No | ||
| use_hybrid | No | ||
| include_debug | No | ||
| project_filter | No | ||
| enable_analysis | No | ||
| enable_synthesis | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Describes return value structure based on flags (analysis, synthesis, debug) and mentions default behaviors. With no annotations, this adequately discloses read-only search behavior and result shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with main purpose, Args, and Returns sections. Slightly long but each line adds value; front-loaded purpose sentence is effective.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers search functionality, parameter details, and return variations comprehensively. Lacks error handling or rate limits, but adequate given no output schema and 9 parameters.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
All 9 parameters are thoroughly described in the Args section, including types, defaults, and effects (e.g., date_from: ISO-8601, enable_analysis: adds 'analysis' and 'evaluation'). Schema coverage is 0%, so description fully compensates.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states 'Search conversation history for relevant context' and lists specific use cases (previous discussions, decisions, compacted context), effectively distinguishing from sibling tools like search_file_changes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Use this to find:' list of scenarios, guiding when to invoke. Does not explicitly mention when not to use or alternatives, but the context is sufficiently clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_file_changesA
Find file modifications in conversation history.
Use this when user asks:
- "What did we change in auth.dart?"
- "Show me recent edits to the config files"
- "What files did we create?"
Args:
file_path: Filter by file path (supports partial match)
query: Semantic query about changes
project_filter: Limit to specific project
operation_filter: Filter by "edit" or "write"
date_from: Inclusive lower timestamp bound. Accepts ISO-8601 datetime
or date-only values such as 2026-06-13.
date_to: Inclusive upper timestamp bound. Accepts ISO-8601 datetime
or date-only values such as 2026-06-15.
limit: Maximum results (default 10, min 1, max 50)
Returns:
Dict with file change results
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | No | ||
| date_to | No | ||
| date_from | No | ||
| file_path | No | ||
| project_filter | No | ||
| operation_filter | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It does not explicitly state that the tool is read-only or disclose any side effects, auth requirements, or rate limits. Basic behavior (finding modifications) is described, but safety profile is missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: purpose first, then usage examples, then parameter list with clear labels, and finally returns. It is front-loaded and every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers parameters well but lacks detail about the return structure beyond 'Dict with file change results'. No output schema is provided, and the description does not explain ordering, pagination, or format of results. For a search tool, this is a gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description adds meaning for all 7 parameters: explains partial match for file_path, semantic query, project/operation filters, date format (ISO-8601), and limit bounds. This compensates for the sparse schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it finds file modifications in conversation history, with example user queries. It distinguishes from siblings like search_conversations by focusing on file changes, but does not explicitly differentiate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides example queries ('What did we change in auth.dart?') and a parameter list, giving clear context for when to use the tool. However, it does not mention when not to use it or suggest alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
get_index_status - First observed
get_server_status - First observed
get_session_summary - First observed
search_conversations - First observed
search_file_changes
TDQS
Scored across 5 tools
Most tools have distinct purposes, but get_index_status and get_server_status overlap in indexing and database information, potentially causing confusion. Detailed descriptions help differentiate them.
All tool names follow a consistent verb_noun pattern with underscores (get_* and search_*), making them predictable and clear.
Five tools cover the necessary functionality for a RAG memory system without being too few or too many, earning each tool's place.
The tool set covers monitoring and search operations well, but lacks a tool to retrieve full conversation transcripts or manage indexing, which are minor gaps.
Maintenance
Related MCP Connectors
Persistent memory for AI agents. Search, store, and recall across sessions.
Shared memory for coding agents. Stop re-explaining your codebase every session.
Universal persistent memory and knowledge retrieval layer for AI agents and LLMs.
Universal memory for AI agents and tools. Save, organize and search context anywhere.
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides persistent memory for AI agents using hybrid search (vector embeddings + BM25) with neural reranking, enabling storage and retrieval of insights, debugging solutions, and patterns across coding sessions.8MIT
- AlicenseNot gradedqualityCmaintenanceProvides AI coding agents with persistent, graph-connected memory across projects, enabling cross-project context retrieval via synaptic connections and hybrid search.6 npm8MIT
- AlicenseNot gradedqualityDmaintenanceProvides long-term memory for AI coding agents, enabling them to remember, search, and organize information across sessions and platforms like Claude Code, ChatGPT, and Cursor.14 npm8MIT
- AlicenseNot gradedqualityCmaintenanceProvides persistent, searchable memory and knowledge capture for AI-assisted development, enabling agents to retain decisions, bugs, and patterns across sessions and projects.MIT