{"id":50322987,"url":"https://github.com/olesyastorchakprojects/thinking_memory_hub","last_synced_at":"2026-05-29T04:01:31.876Z","repository":{"id":360199989,"uuid":"1247488016","full_name":"olesyastorchakprojects/thinking_memory_hub","owner":"olesyastorchakprojects","description":"MCP-based memory server and LangGraph backend for note storage, search, and messenger integrations.","archived":false,"fork":false,"pushed_at":"2026-05-25T11:33:06.000Z","size":1260,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-25T13:28:03.263Z","etag":null,"topics":["fastapi","langfuse","langgraph","llm","mcp","postgresql","python","slack-bot"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/olesyastorchakprojects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-23T11:38:01.000Z","updated_at":"2026-05-25T11:38:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/olesyastorchakprojects/thinking_memory_hub","commit_stats":null,"previous_names":["olesyastorchakprojects/thinking_memory_hub"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/olesyastorchakprojects/thinking_memory_hub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olesyastorchakprojects%2Fthinking_memory_hub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olesyastorchakprojects%2Fthinking_memory_hub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olesyastorchakprojects%2Fthinking_memory_hub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olesyastorchakprojects%2Fthinking_memory_hub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/olesyastorchakprojects","download_url":"https://codeload.github.com/olesyastorchakprojects/thinking_memory_hub/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olesyastorchakprojects%2Fthinking_memory_hub/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33635961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","langfuse","langgraph","llm","mcp","postgresql","python","slack-bot"],"created_at":"2026-05-29T04:01:25.496Z","updated_at":"2026-05-29T04:01:31.851Z","avatar_url":"https://github.com/olesyastorchakprojects.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Thinking Memory Hub\n\nThinking Memory Hub is a Python memory system built around three core ideas:\n\n- MCP as the stable tool boundary for memory operations\n- LangGraph as the orchestration layer for user-facing workflows\n- Langfuse as the observability layer for LLM-powered orchestration\n\nAt the storage boundary, the project exposes a PostgreSQL-backed MCP server. At the application boundary, it uses LangGraph-driven backend flows to classify user intent, build typed requests, call MCP tools, and return user-facing responses.\n\nThe project is designed for messenger integrations. Slack is the first implemented channel, and the backend architecture allows the same MCP and LangGraph core to support additional messengers.\n\nThe storage server currently publishes four MCP tools:\n\n- `notes.save`\n- `notes.search`\n- `notes.update`\n- `tags.search`\n\nThe repository also contains a backend HTTP API that accepts natural-language requests and routes them through LangGraph workflows backed by the remote MCP memory server.\n\n## Architecture\n\nThe core boundary in this project is:\n\n```text\napp/backend code -\u003e MCP memory server -\u003e Postgres\n```\n\nThe higher-level runtime flow is:\n\n```text\nuser message\n  -\u003e backend API\n  -\u003e intent classification\n  -\u003e structured input extraction\n  -\u003e LangGraph workflow\n  -\u003e remote MCP tool call\n  -\u003e PostgreSQL storage/query\n```\n\nLangfuse instrumentation spans the backend orchestration and LLM calls within that flow.\n\nResponsibilities:\n\n- `app/memory_server/` owns MCP transport, tool registration, request validation, and storage calls\n- `app/memory_server/storage_client.py` owns SQL, transactions, and PostgreSQL access\n- `app/backend/` owns the REST API, intent routing, LangGraph orchestration, and remote MCP calls\n- `Langfuse` owns observability for backend traces and LLM generations\n\n## Current Scope\n\nThe normative implementation scope is defined in `docs/specs/`.\n\nCurrent scope includes:\n\n- an MCP memory server exposed over Streamable HTTP via `FastMCP`\n- a LangGraph-backed backend that orchestrates natural-language memory workflows\n- Langfuse-backed observability for backend request traces and model calls\n- a Slack integration that turns the backend into a conversational assistant inside a messenger\n- PostgreSQL-backed note persistence with tags\n- a backend REST API with `GET /api/health`\n- a backend REST API with `POST /api/message`\n- a Slack Events API endpoint, enabled when Slack credentials are configured\n\n## Tech Stack\n\n- Python 3.11+\n- FastMCP / MCP Python SDK\n- FastAPI\n- LangGraph\n- Pydantic\n- psycopg + psycopg_pool\n- PostgreSQL\n- Langfuse\n\n## Repository Layout\n\n```text\napp/\n  backend/\n  memory_server/\ndb/\n  schema.sql\ndocs/\n  index.md\n  specs/\ntests/\n  integration/\n```\n\nKey entrypoints:\n\n- `app/memory_server/main.py`\n- `app/memory_server/server.py`\n- `app/memory_server/mcp_tools.py`\n- `app/memory_server/storage_client.py`\n- `app/backend/main.py`\n- `app/backend/message_service.py`\n- `app/backend/message_graph.py`\n- `app/backend/search_notes_graph.py`\n- `app/backend/search_tags_graph.py`\n- `app/backend/update_note_graph.py`\n\n## Source of Truth\n\nWhen working on the project, treat `docs/specs/` as normative.\n\nRecommended reading order:\n\n1. `docs/index.md`\n2. `docs/specs/mcp_server.md`\n3. `docs/specs/data_contracts.md`\n4. `docs/specs/mcp_tool_definitions.md`\n5. `docs/specs/storage_client_interface.md`\n\nBackend-specific contracts are documented in:\n\n- `docs/specs/backend_api.md`\n- `docs/specs/backend_server.md`\n- `docs/specs/backend_save_graph.md`\n- `docs/specs/backend_search_notes_graph.md`\n\n## Why MCP + LangGraph\n\nThis project was written around the combination of MCP and LangGraph, not just as a CRUD note service.\n\nMCP gives the system a clean tool contract:\n\n- the memory server publishes a small, typed, stable tool surface\n- backend and external clients can call memory operations without knowing SQL or schema details\n- storage concerns stay behind the MCP boundary\n\nLangGraph gives the system a clean orchestration model:\n\n- each user intent is executed as an explicit graph instead of ad-hoc controller logic\n- graph nodes validate inputs, call MCP tools, and assemble final responses step by step\n- workflows can evolve from simple single-tool executions into richer multi-step reasoning flows\n\nIn this architecture:\n\n- PostgreSQL is the persistence engine\n- MCP is the application protocol between orchestration and storage capabilities\n- LangGraph is the place where higher-level behavior lives\n- Langfuse is where LLM workflow execution becomes traceable and inspectable\n- messenger adapters are the user-facing entrypoints that can sit on top of the same orchestration core\n\n## LangGraph Workflows\n\nThe backend defines a separate graph per intent:\n\n- `save_note`\n- `search_notes`\n- `search_tags`\n- `update_note`\n\nThese graphs are assembled in [`app/backend/message_service.py`](app/backend/message_service.py), which:\n\n- classifies the incoming message intent\n- extracts typed structured input for that intent\n- invokes the matching LangGraph workflow\n- validates the final backend response\n\nCurrent graph implementations live in:\n\n- [`app/backend/message_graph.py`](app/backend/message_graph.py)\n- [`app/backend/search_notes_graph.py`](app/backend/search_notes_graph.py)\n- [`app/backend/search_tags_graph.py`](app/backend/search_tags_graph.py)\n- [`app/backend/update_note_graph.py`](app/backend/update_note_graph.py)\n\nTypical graph shape for save/search flows:\n\n```text\nvalidate typed input\n  -\u003e execute one MCP tool call\n  -\u003e build final response\n```\n\nThe update flow is already a bit richer:\n\n```text\nvalidate update input\n  -\u003e resolve target note\n  -\u003e execute MCP update\n  -\u003e build final response\n```\n\nThis layer can be extended as more memory workflows are added.\n\n## Messenger Integrations\n\nThe system is designed to work as a memory assistant inside messengers, not only as a standalone API.\n\nThe current project includes one messenger integration:\n\n- Slack\n\nThe architecture supports additional channels because the layers are already separated:\n\n- messenger adapter receives a user message\n- backend turns it into structured intent-driven workflow execution\n- LangGraph orchestrates the flow\n- MCP provides the stable memory tool boundary\n- the storage server stays unchanged regardless of which messenger sent the request\n\nThis separation keeps messenger-specific concerns, such as webhook verification or reply formatting, out of the memory server itself.\n\n## Slack Integration\n\nSlack is the first implemented messenger integration in the current project scope.\n\n![Slack integration demo](docs/images/slack.png)\n\nCapabilities:\n\n- receives Slack Events API requests on `/slack/events`\n- verifies Slack signatures before processing events\n- handles Slack `url_verification`\n- processes `app_mention` events\n- strips the bot mention and forwards the remaining user text into `MessageService`\n- posts the backend response back to Slack, typically in the same thread context\n- deduplicates repeated Slack event deliveries in memory\n\nOperational characteristics:\n\n- users can interact with the memory system from a real conversation surface\n- the same LangGraph workflows used by the HTTP API are reused from Slack\n- the messenger UX stays thin while the real logic remains in MCP, LangGraph, and the backend service layer\n\nCurrent limitations:\n\n- Slack is the only implemented messenger right now\n- the current Slack flow is centered on `app_mention`\n- direct messages are not wired yet\n\nSlack-specific implementation lives in:\n\n- [`app/backend/slack.py`](app/backend/slack.py)\n- [`docs/slack_setup.md`](docs/slack_setup.md)\n\n## Observability With Langfuse\n\nLangfuse is part of the backend design.\n\nThe current implementation uses it to observe the orchestration pipeline around LangGraph and LLM calls:\n\n- [`app/backend/message_service.py`](app/backend/message_service.py) creates a top-level `process_message` trace\n- that `trace_id` is propagated into intent classification and structured input extraction\n- [`app/backend/model_client.py`](app/backend/model_client.py) records generation spans for model calls\n- model spans capture request input, output, token usage, and calculated input/output cost\n\nThis gives the project visibility into:\n\n- which user message triggered which workflow\n- which intent was selected\n- which extractor/classifier/model span ran under the same trace\n- how much token usage and estimated cost each LLM step produced\n\nSummary:\n\n- LangGraph defines the workflow\n- MCP defines the tool boundary\n- Langfuse lets you inspect what happened while that workflow was running\n\n## MCP Surface\n\nThe MCP server is intentionally small and typed. Each tool handler validates input, calls exactly one storage method, and serializes a typed result.\n\nPublished tools:\n\n- `notes.save`\n- `notes.search`\n- `notes.update`\n- `tags.search`\n\nThe server implementation is centered in:\n\n- [`app/memory_server/server.py`](app/memory_server/server.py)\n- [`app/memory_server/mcp_tools.py`](app/memory_server/mcp_tools.py)\n- [`app/memory_server/storage_client.py`](app/memory_server/storage_client.py)\n\n## Data Model\n\nNotes are stored as structured records with:\n\n- `id`\n- `raw_text`\n- `normalized_text`\n- `note_kind`\n- `source_ref`\n- `created_at`\n- `updated_at`\n- `tags`\n\nSupported `note_kind` values:\n\n- `note`\n- `question`\n- `task`\n- `reading`\n- `watch`\n\nTag search returns aggregated tag results with usage counts derived from matching notes.\n\n## Database\n\nSchema lives in [`db/schema.sql`](db/schema.sql).\n\nThe schema creates:\n\n- `notes`\n- `tags`\n- `note_tags`\n\nIt also enables required PostgreSQL extensions:\n\n- `pgcrypto`\n- `pg_trgm`\n\n`pg_trgm` is used for similarity search in note and tag queries.\n\n## Setup\n\n### 1. Create a virtual environment\n\n```bash\npython -m venv .venv\nsource .venv/bin/activate\npip install -e '.[dev]'\n```\n\n### 2. Create a PostgreSQL database\n\nCreate a database and apply the schema:\n\n```bash\npsql \"$DATABASE_URL\" -f db/schema.sql\n```\n\n### 3. Configure environment variables\n\nFor the MCP memory server:\n\n```bash\nexport MEMORY_SERVER_HOST=127.0.0.1\nexport MEMORY_SERVER_PORT=8001\nexport DATABASE_URL=postgresql://user:pass@localhost:5432/thinking_memory_hub\n```\n\nFor the backend API:\n\n```bash\nexport BACKEND_HOST=127.0.0.1\nexport BACKEND_PORT=8081\nexport MEMORY_SERVER_URL=http://127.0.0.1:8001/mcp\nexport TOGETHER_URL=https://api.together.xyz\nexport TOGETHER_API_KEY=your_api_key\nexport TOGETHER_MODEL=openai/gpt-oss-20b\n```\n\nOptional Slack variables:\n\n```bash\nexport SLACK_SIGNING_SECRET=...\nexport SLACK_BOT_TOKEN=...\nexport SLACK_API_BASE_URL=https://slack.com/api\n```\n\nNotes:\n\n- `MEMORY_SERVER_URL` must be an HTTP URL pointing at the MCP server endpoint\n- Slack settings must be provided together or omitted together\n- Langfuse can be enabled through the SDK's standard environment-based configuration\n- integration tests use `TEST_DATABASE_URL`\n\n## Running\n\n### Start the MCP memory server\n\n```bash\nPYTHONPATH=app python -m memory_server.main\n```\n\nEquivalent project script:\n\n```bash\nmemory-server\n```\n\nThe server uses Streamable HTTP and publishes the MCP tool surface used by the LangGraph backend:\n\n- `notes.save`\n- `notes.search`\n- `notes.update`\n- `tags.search`\n\n### Start the backend API\n\n```bash\nPYTHONPATH=app python -m backend.main\n```\n\nEquivalent project script:\n\n```bash\nbackend-server\n```\n\nThe backend exposes:\n\n- `GET /api/health`\n- `POST /api/message`\n- `POST /slack/events` when Slack credentials are configured\n\nInternally, `POST /api/message` runs:\n\n- intent classification\n- structured input extraction\n- a LangGraph workflow for the selected intent\n- Langfuse tracing around orchestration and LLM generations\n- one or more MCP tool calls to the memory server\n\nWhen Slack is enabled, `/slack/events` adds:\n\n- Slack request signature verification\n- event filtering and deduplication\n- message formatting and reply delivery back to Slack\n\n## Example Requests\n\n### Backend health check\n\n```bash\ncurl http://127.0.0.1:8081/api/health\n```\n\n### Backend message request\n\n```bash\ncurl -X POST http://127.0.0.1:8081/api/message \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"text\":\"show notes about postgres from last week\"}'\n```\n\n## Testing\n\nRun unit tests:\n\n```bash\nPYTHONPATH=app pytest\n```\n\nRun integration tests against a dedicated PostgreSQL database:\n\n```bash\nTEST_DATABASE_URL=postgresql://user:pass@localhost:5432/thinking_memory_hub_test PYTHONPATH=app pytest -m integration\n```\n\nTest expectations:\n\n- unit tests do not require a live database\n- integration tests are opt-in\n- integration tests apply `db/schema.sql` to the test database\n\n## Implementation Notes\n\nSome project rules that are helpful to know before editing code:\n\n- MCP tool handlers validate input, call exactly one storage method, and serialize output\n- SQL and transactions belong in `app/memory_server/storage_client.py`\n- data models and enums belong in `app/memory_server/models.py`\n- configuration loading belongs in `app/memory_server/config.py`\n- the backend must call the memory server through MCP rather than touching PostgreSQL directly\n- backend orchestration logic belongs in LangGraph workflows rather than leaking into low-level storage code\n- observability for backend LLM orchestration should stay aligned with the existing Langfuse tracing flow\n\n## Documentation\n\nStart with [`docs/index.md`](docs/index.md).\n\nAdditional operational docs:\n\n- [`docs/slack_setup.md`](docs/slack_setup.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folesyastorchakprojects%2Fthinking_memory_hub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Folesyastorchakprojects%2Fthinking_memory_hub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folesyastorchakprojects%2Fthinking_memory_hub/lists"}