> ## Documentation Index
> Fetch the complete documentation index at: https://artemiscity.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Agentic Memory Layer (MCP server)

> Run the Obsidian-backed MCP server that gives Artemis City agents a persistent, versioned memory bus.

The **Artemis Agentic Memory Layer** is a Model Context Protocol (MCP) server that exposes an Obsidian vault to agents over a small, authenticated REST API. It lets agents read, write, search, tag, and reorganize notes as a shared, versioned source of truth — the long-term memory bus for Artemis City.

Use this integration when you want agents to:

* Persist context, plans, or reflections across sessions.
* Coordinate with other agents around a single knowledge store.
* Read structured human-curated notes (instructions, personas, capability docs) at runtime.
* Maintain a queryable graph of tasks, tags, and frontmatter metadata.

The Python-side client and trust-aware wrapper that calls this server are documented in [Memory Integration](/Documentation/memory/MEMORY_INTEGRATION). This page documents the MCP server itself: how to deploy it, how to configure it, and the endpoints it exposes.

## How it fits

```text theme={null}
┌─────────────────┐   HTTPS + Bearer   ┌──────────────────────┐   Local REST   ┌───────────────┐
│ Artemis agents  │ ─────────────────▶ │  Agentic Memory MCP  │ ─────────────▶ │ Obsidian vault│
│ (Python / LLM)  │ ◀───────────────── │       server         │ ◀───────────── │  + REST plugin│
└─────────────────┘   JSON responses   └──────────────────────┘                └───────────────┘
```

The MCP server is a thin translation layer. It accepts MCP-style tool invocations over HTTP, authenticates them against a shared key, and forwards them to the Obsidian Local REST API plugin running on the host vault.

## Prerequisites

* **Node.js 18+** (or Docker) on the host running the MCP server.
* **Obsidian** with the **Local REST API** community plugin installed and enabled.
* An API key generated from the Local REST API plugin settings.
* A second secret (`MCP_API_KEY`) that agents present when calling this server.

## Configuration

The server reads configuration from environment variables (typically a `.env` file or the `environment:` block in `docker-compose.yml`).

| Variable            | Required | Default | Description                                                                 |
| ------------------- | -------- | ------- | --------------------------------------------------------------------------- |
| `MCP_API_KEY`       | Yes      | —       | Shared secret agents send as `Authorization: Bearer <key>`.                 |
| `OBSIDIAN_BASE_URL` | Yes      | —       | URL of the Obsidian Local REST API (for example `https://127.0.0.1:27124`). |
| `OBSIDIAN_API_KEY`  | Yes      | —       | API key from the Obsidian Local REST API plugin.                            |
| `PORT`              | No       | `3000`  | Port the MCP server listens on.                                             |
| `MCP_LOG_LEVEL`     | No       | `info`  | One of `debug`, `info`, `warn`, `error`.                                    |

<Note>
  The server exits on startup if `MCP_API_KEY`, `OBSIDIAN_BASE_URL`, or `OBSIDIAN_API_KEY` is missing.
</Note>

### `OBSIDIAN_BASE_URL` by environment

| Environment                                              | Value                                                 |
| -------------------------------------------------------- | ----------------------------------------------------- |
| MCP server on the host, Obsidian on the host             | `https://127.0.0.1:27124`                             |
| MCP server in Docker, Obsidian on host (macOS / Windows) | `https://host.docker.internal:27124`                  |
| MCP server in Docker, Obsidian on host (Linux)           | `https://<host-ip>:27124` or use `network_mode: host` |

Replace `27124` with the port shown in your Local REST API plugin settings.

## Deployment

### Docker (recommended)

Use the bundled `docker-compose.yml` to build and run the server:

```bash theme={null}
docker-compose up --build
```

The server is then reachable at `http://localhost:3000` and forwards requests to your vault at `OBSIDIAN_BASE_URL`.

### Local Node.js

```bash theme={null}
npm install
npm run dev      # hot-reload, development
# or
npm run build && npm start   # production build
```

### Health check

The server exposes an unauthenticated health endpoint:

```bash theme={null}
curl http://localhost:3000/health
# {"status":"ok"}
```

## Authentication

Every `/api/*` request must include the bearer token:

```http theme={null}
Authorization: Bearer <MCP_API_KEY>
```

Missing or mismatched tokens return `403 Forbidden`. Combine this with [Trust-Based Access Control](/Documentation/memory/MEMORY_INTEGRATION) on the client side so agent-level trust scores gate which operations are even attempted.

## API endpoints

All endpoints are `POST`, accept `application/json`, and live under `/api`. Responses use a consistent envelope:

```json theme={null}
{ "success": true, "data": { ... } }
```

or, on failure:

```json theme={null}
{ "success": false, "error": "..." }
```

| Endpoint                 | Body fields                                    | Purpose                                           |
| ------------------------ | ---------------------------------------------- | ------------------------------------------------- |
| `/api/getContext`        | `path`                                         | Read the full content of a note.                  |
| `/api/appendContext`     | `path`, `content`                              | Append content to a note (creates it if missing). |
| `/api/updateNote`        | `path`, `content`                              | Replace the entire body of a note.                |
| `/api/searchNotes`       | `query`                                        | Full-text search across the vault.                |
| `/api/listNotes`         | *(none)*                                       | List all note paths in the vault.                 |
| `/api/deleteNote`        | `path`                                         | Delete a note.                                    |
| `/api/manageFrontmatter` | `path`, `key`, `value`                         | Upsert a YAML frontmatter key.                    |
| `/api/manageTags`        | `path`, `tags[]`, `action` (`add` or `remove`) | Add or remove tags.                               |
| `/api/searchReplace`     | `path`, `search`, `replace`                    | In-place search and replace in a note.            |

### Example: read a note

```bash theme={null}
curl -X POST http://localhost:3000/api/getContext \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $MCP_API_KEY" \
  -d '{ "path": "Daily/2026-05-20.md" }'
```

```json theme={null}
{
  "success": true,
  "data": {
    "path": "Daily/2026-05-20.md",
    "content": "# Daily Notes\n\n- Reviewed agent reflections\n- ..."
  }
}
```

### Example: append agent context

```bash theme={null}
curl -X POST http://localhost:3000/api/appendContext \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $MCP_API_KEY" \
  -d '{
        "path": "Agents/artemis/journal.md",
        "content": "\n- 2026-05-20: Completed reflection cycle."
      }'
```

### Example: tag a note

```bash theme={null}
curl -X POST http://localhost:3000/api/manageTags \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $MCP_API_KEY" \
  -d '{ "path": "Projects/atp.md", "tags": ["urgent", "review"], "action": "add" }'
```

## Calling the server from Python

Most Artemis agents talk to the memory layer through the Python `MemoryClient`, which wraps these endpoints and adds trust enforcement:

```python theme={null}
from memory.integration import MemoryClient

client = MemoryClient(
    base_url="http://localhost:3000",
    api_key="your_mcp_api_key",
)

# Read a note
response = client.get_context("Daily/2026-05-20.md")
if response.success:
    print(response.data["content"])

# Persist a reflection
client.store_agent_context(
    "artemis",
    "Completed ATP integration successfully",
)
```

See [Memory Integration](/Documentation/memory/MEMORY_INTEGRATION) for the full client surface, trust levels, and context-loading helpers.

## Security considerations

* **Treat both keys as secrets.** `MCP_API_KEY` grants full vault access via this server; `OBSIDIAN_API_KEY` grants direct vault access via the plugin.
* **Default binding is `localhost`.** If you expose the server to a wider network, put it behind a firewall, reverse proxy, or mTLS.
* **Self-signed certificates.** The server is configured to accept the plugin's self-signed HTTPS cert (`rejectUnauthorized: false`). For production, terminate TLS at a trusted proxy.
* **Validate agent inputs.** The server performs minimal validation. Sanitize paths and content on the client side, and combine with trust scoring before issuing write or delete operations.

## Troubleshooting

| Symptom                                  | Likely cause                                                                                |
| ---------------------------------------- | ------------------------------------------------------------------------------------------- |
| Server exits on boot with `… is not set` | A required env var is missing. Check `.env` or the compose `environment:` block.            |
| `ECONNREFUSED` from the server           | Obsidian is closed, the Local REST API plugin is disabled, or `OBSIDIAN_BASE_URL` is wrong. |
| `403 Forbidden: Invalid API Key`         | The agent's `Authorization` header does not match `MCP_API_KEY`.                            |
| `Unauthorized` from Obsidian             | `OBSIDIAN_API_KEY` is wrong or was rotated in the plugin settings.                          |
| Note operations fail                     | Path does not match the exact vault path (including the `.md` extension).                   |

On Linux hosts running the MCP server in Docker, `host.docker.internal` does not resolve by default — use the host's bridge IP (often `172.17.0.1`) or set `network_mode: host` in compose.


## Related topics

- [Artemis Agentic Memory Layer](/Documentation/memory/MEMORY_INTEGRATION.md)
- [Secrets and environment setup](/Documentation/operations/secrets-setup.md)
- [Changelog](/Changelog/changelog.md)
- [LIVING_CITY](/Documentation/Introduction/LIVING_CITY.md)
- [Memory Lawyer Protocol](/Documentation/concepts/memory_lawyer.md)
