flyset

MyMCP

Community flyset
Updated

Local-first MCP host for narrowly scoped integrations, with bundled Mnemosyne memory.

MyMCP

MyMCP is the repository and Python host package for an experimental local MCPserver. Released 0.2.0 identifies the host, application, package,and official tracked client as MyMCP/mymcp. It hosts Mnemosyne, theuser-governed AI memory domain, through a bundled plugin.

Its intended direction is a local, client-neutral MCP host and governance gatewaythat composes narrowly scoped integrations behind one machine-local endpoint.Mnemosyne supplies the current notebook-like memory capability while retainingits explicit user-governed boundaries.

Current Status

This repository currently contains a FastAPI-based MCP host with the Mnemosynememory domain built in. Phase 1 provides kind-qualified contracts,ActivatedTool/PluginContribution composition, trusted internal effect andconsent metadata, host-owned public bindings and list_tools, an immutableHostRuntime with an opaque generation, explicit build_production_runtime,and runtime-bound MCP dispatch through create_app(runtime).

Phase 2's declaration/parity boundary and vertical Mnemosyne extraction areimplemented. The bundled plugin owns its inert manifest, trusted adapter,configuration, memory domain, and memory_* MCP adapters undermymcp/plugins/mnemosyne/. Manifest-v1 parsing remains strict (JSON/UTF-8,duplicate-key, and 64 KiB bound), and bootstrap validates exactmanifest/definition/contribution parity before generation construction.

The plugin's trusted in-process Mnemosyne 0.1.0 adapter supplies canonicalregistrations. Host bootstrap reads only the fixed packaged resource, validatesit against the plugin definition and selected gate-controlled contribution, thenconstructs a runtime. create_production_app() is the local convenience factoryand supported Uvicorn factory target. Ordinary imports are side-effect free; noglobal app, startup/methods modules, static ToolIntegration, or dynamicdiscovery are used.

TRACK_034 delivered the MyMCP 0.2.0 public-host cutover: server/applicationidentity, package metadata, the canonical repository, and the tracked OpenCodepolicy use MyMCP/mymcp. The prior repository URL redirects to the canonicalrepository. Routes and protocol remain unchanged. Mnemosyne permanently retains pluginmnemosyne, memory_* Tools, MNEMOSYNE_* configuration, ~/.mnemosyne, andits storage, record, logging, and consent semantics. Repository/origin/history/tag/placeholder checks, the tracked and ignored OpenCode migration with Claudeexclusion, the normal endpoint and final client reconnect, and isolatedapproved-once and rejected/no-Tools-call checks are complete. The public,non-draft, non-prerelease GitHub releaseMyMCP 0.2.0: public-host cutoveris tagged mymcp-v0.2.0 at c2852bc and contains one wheel,mymcp-0.2.0-py3-none-any.whl, with matching GitHub/local SHA-256531cc9a603d16399b12650fd09d3bc76f43b4d5d1b15fed0377a6197c820e3e7.External installation/activation/isolation, lifecycle, and gateway governanceremain deferred. Seedocs/PLUGIN_ARCHITECTURE.md for the target and migration boundaries.

Implemented tools:

  • list_tools — reports the server version and lists the exposed tools
  • memory_recall — retrieves bounded, relevant, user-approved JSON memory records from one allowlisted local scope directory
  • memory_list — completely and deterministically inventories valid memories in one bounded scope or canonical container without returning record content
  • memory_inspect — returns one exact canonical or legacy memory selected by a versioned structured reference
  • memory_remember — when explicitly enabled, validates and atomically persists one approved canonical version-2 memory
  • memory_revise — when independently enabled, revision-checks and atomically replaces the complete caller-mutable state of one exact canonical version-2 memory
  • memory_archive — when explicitly enabled, revision-checks and archives one exact canonical version-2 memory
  • memory_restore — when explicitly enabled, revision-checks and restores one exact archived canonical version-2 memory
  • memory_forget — when independently enabled, permanently deletes one exact archived canonical version-2 memory at its expected revision

This is not yet a full memory substitute. Amemory_recall request contains a free-form query, exactly one high-levelscope (self, relationship, preference, practice, project, orknowledge), andoptionally 1–10 unique free-form tags. Scope selects one fixed local directory.Query terms and tags rank valid records from that directory; recall never searchesanother scope or accepts a client-supplied path. The Tool schema publishes scopeas an explicit string enum so clients can discover the complete vocabulary.

Matching calls return a normal Tool result with status: ok and at most fivememory records. Results include an inspect-compatible versioned reference, therecord ID, scope, title, content, tags, and matched terms/tags, but never includefilesystem paths or internal scores. A legacy reference contains schema version,scope, and ID. A canonical reference additionally contains namespace ID and thenullable collection ID. An absent scope directory or no relevant record returns{"status":"no_matches","memories":[]}. Invalid arguments retain stable Toolerrors with code invalid_query, invalid_scope, or invalid_tags; unreadableor excessive sources return memory_source_unavailable orcandidate_limit_exceeded Tool errors.

Recall remains read-only. It does not create, update, delete, or automaticallyextract memory, and it does not persist recall requests. Calls remain visiblethrough the MCP client's existing Tool-call/session representation.

Listing Memory

memory_list is registered by default as a read-only Tool for complete boundeddiscovery. It is distinct from both other read operations:

  • recall ranks records by a query, excludes non-matches and archived canonicalrecords, and returns at most five results;
  • listing enumerates every valid selected record without a query or relevancescore, includes archived canonical records, and returns compact metadata indeterministic pages;
  • inspection retrieves the complete user-visible contents of one exact listedor recalled reference.

Every list request requires exactly one scope. Its Tool schema exposes scope,namespace_id, collection_id, page_size, and cursor as top-level objectproperties for clients that do not project properties nested in compositionbranches. Scope uses the same explicit six-value string enum as recall. Fourmutually exclusive conditional branches retain the strict scope-wide/namespaceand initial/continuation request variants. Tool and property descriptions repeatthose combination rules for clients that retain the flat properties but discardcomposition constraints. A scope-wide request includes compatible legacy andcanonical records:

{"scope":"project"}

Supplying namespace_id selects canonical records only. With a namespace,collection selection is omission-sensitive:

{"scope":"project","namespace_id":"mnemosyne"}

Omitted collection_id means collectionless records and every collection inthe namespace. Native JSON null means collectionless records only:

{
  "scope": "project",
  "namespace_id": "mnemosyne",
  "collection_id": null
}

A string selects one exact collection:

{
  "scope": "project",
  "namespace_id": "mnemosyne",
  "collection_id": "decisions"
}

The string "null" is the literal collection ID null; clients must send anactual JSON null for collectionless selection. A collection selector without anamespace is invalid. Requests never accept a path, root, filename, query, tag,sort key, arbitrary filter, content field, or cross-scope selector.

Initial requests may include page_size from 1 through 100; the default is 50.When more selected records remain, repeat the exact selector with the returnedopaque cursor and omit page_size:

{
  "scope": "project",
  "namespace_id": "mnemosyne",
  "collection_id": "decisions",
  "cursor": "<opaque cursor>"
}

A successful response is always status: ok, including an empty inventory:

{
  "status": "ok",
  "memories": [
    {
      "reference": {
        "schema_version": 2,
        "scope": "project",
        "namespace_id": "mnemosyne",
        "collection_id": "decisions",
        "id": "mem_0123456789abcdef0123456789abcdef"
      },
      "title": "Discovery contract",
      "inspectability": "exact",
      "kind": "decision",
      "lifecycle": {"state": "archived"}
    }
  ],
  "page": {
    "number": 1,
    "count": 1,
    "total_count": 1,
    "total_pages": 1,
    "truncated": false,
    "next_cursor": null
  }
}

Legacy items contain only their version-1 reference, nullable title, andinspectability. Canonical items additionally contain kind and lifecycle state,but not lifecycle revision. Listing never returns content, tags, labels,language, provenance, timestamps, paths, fingerprints, retrieval scores, ormatch evidence.

Ordering is fixed: schema version first, then public identity. Collectionlesscanonical records precede collected records within a namespace. Duplicatelegacy sources remain separate countable items and use their unexposed relativepaths only as a final ordering tie-breaker. Their shared reference is markedinspectability: ambiguous; exact inspection continues to returnambiguous_reference for that reference.

Cursors are authenticated, bound to the exact selector and complete selectedvalid-record snapshot, and fixed to the original page size. Selected additions,removals, relocations, byte rewrites, lifecycle changes, or valid/invalidtransitions return status: conflict, code stale_cursor. Cursors also becomestale after a server restart because their key and process marker are notpersisted. Malformed, current-process-tampered, selector-mismatched, or otherwiseincompatible cursors return status: invalid_request, code invalid_cursor.Start a fresh listing after either cursor error.

Other stable errors are invalid_request, invalid_scope,invalid_namespace, invalid_collection, invalid_page_size,candidate_limit_exceeded, memory_source_unavailable, and internal_error.Candidate overflow and unsafe or unavailable selected sources fail without apartial inventory. Listing does not initialize a missing memory root, create anindex or snapshot store, persist cursors, or change any record. Its one terminallog event contains only bounded outcome, selector-presence, count, page, anderror metadata; it omits selector values, IDs, titles, cursors, content, paths,fingerprints, exception details, and tracebacks.

Inspecting Memory

memory_inspect is registered by default as a read-only Tool. It accepts exactlyone reference object and no path, memory root, filename, query, lifecycleselector, or broad list selector. Use the versioned reference returned bymemory_recall or add schema_version: 2 to the canonical identity returned bymemory_remember:

{
  "reference": {
    "schema_version": 2,
    "scope": "project",
    "namespace_id": "mnemosyne",
    "collection_id": "decisions",
    "id": "mem_0123456789abcdef0123456789abcdef"
  }
}

A legacy selector is limited to its actual identity:

{
  "reference": {
    "schema_version": 1,
    "scope": "preference",
    "id": "rainy-weekend"
  }
}

Canonical success returns status: ok, the versioned structured reference, andthe complete user-visible version-2 record: scope, namespace, optionalcollection, kind, language, nullable title, content, tags, provenance,lifecycle, and timestamps. Active and archived records use the same resultshape; exact inspection does not filter archived memory. Legacy success returnsonly its versioned reference and fields that version 1 can represent: schemaversion, ID, nullable title, content, and tags. It does not invent namespace,collection, kind, language, provenance, lifecycle, or timestamps.

Invalid references, missing records, ambiguous legacy IDs, excessive legacycandidates, unsafe or unavailable sources, and unexpected failures returnbounded Tool errors with stable codes: invalid_reference, not_found,ambiguous_reference, candidate_limit_exceeded,memory_source_unavailable, or internal_error. Results never include paths,fingerprints, retrieval scores, storage wrappers, or unrelated records.

Inspection never creates, changes, migrates, archives, restores, or deletes arecord and does not initialize a missing memory root. Its one terminal log eventcontains only the outcome, stable code/field where applicable, reference schemaversion, and scope. It omits IDs, memory text and metadata, complete arguments,paths, exception details, and tracebacks. Shared skipped-record warnings likewisecontain only scope and a bounded reason.

Memory scopes, records, paths, storage, retrieval, listing selection, ordering,pagination, cursor policy, content policy, and lifecycle policy live in theplugin-owned mymcp/plugins/mnemosyne/memory/ domain rather than insideindividual MCP Tools. The domainincludes mutation-disabled revise, archive, restore, and physical-deleteprimitives. memory_remember, memory_revise, pairedmemory_archive / memory_restore, and memory_forget are absent fromdiscovery and dispatch unless their independent operator gates enable them.Enabling one gate does not enable another capability.

The MCP host composes kind-qualified ActivatedTool values intoPluginContribution objects, validates host-owned public bindings, and buildsone immutable HostRuntime. The host binds list_tools to the complete finalsurface and retains trusted origins, effect/consent metadata, plugin inventory,and an opaque runtime generation. Duplicate plugin, capability, or public namesfail composition rather than overwriting a registration.

The explicit production bootstrap reads the fixed packaged inert Mnemosynemanifest, validates exact definition and selected-contribution parity beforegeneration construction, then composes the trusted Mnemosyne 0.1.0 adapter overcanonical registrations. The plugin resolves immutable mutation settings once,selects and orders memory Tools, and lazily resolves the configured root for eachvalidated operation. Runtime-bound MCP dispatch, tools/list, and list_toolsall use the same runtime registry. mymcp/settings.py retains only hostserver/process identity; plugin-owned configuration.py retains the unchangedMNEMOSYNE_*, ~/.mnemosyne/config.toml, and memory-root contracts. Handlersremain narrow operation adapters. Synthetic multi-contribution tests proveordered aggregation, complete reporting, dispatch, and collision rejection.This static bundled-plugin seam preserves Mnemosyne's public server identity,Tool names, schemas, ordering, gates, results, errors, configuration, andstorage contracts. The manifest grants no requested authority. This is notdynamic discovery, adds no public Tool namespacing, and provides no installationor lifecycle system.

Revising Memory

Revision is disabled by default and has an independent gate. Persist it in thefixed settings file or use the process override:

[memory]
revise_enabled = true
export MNEMOSYNE_MEMORY_REVISE_ENABLED=true

Only exact lowercase true and false are accepted. Restart the server andreconnect or restart the MCP client after changing enablement. Clients thatcannot require approval for every complete exact replacement must leaverevision disabled.

Inspect the record immediately before proposing revision. Recall returns aninspect-compatible reference, but inspection supplies the complete currentrecord, lifecycle state, and revision needed for review and approval. Everyrevision request contains six unconditional fields plus collection_label whenthe reference identifies an existing collection:

{
  "reference": {
    "schema_version": 2,
    "scope": "preference",
    "namespace_id": "tea",
    "collection_id": "favorites",
    "id": "mem_0123456789abcdef0123456789abcdef"
  },
  "expected_revision": 3,
  "namespace_label": "Tea",
  "collection_label": "Favorites",
  "title": "Japanese green tea",
  "content": "The user enjoys sencha and gyokuro.",
  "tags": ["tea", "japanese-green-tea"]
}

namespace_label and title may be null, but their keys remain required. Whenreference.collection_id is a string, collection_label is also required andmay be either a replacement string or native JSON null. Whenreference.collection_id is null, the record has no collection andcollection_label may be omitted; an explicit native JSON null remains accepted.The literal string "null" is text, not JSON null. Content is nonblank and atmost 4,000 characters; tags contain zero to ten unique normalized items of atmost 50 characters. Unknown fields, legacy references, paths, patches, languageor identity changes, provenance, lifecycle targets, timestamps, and modelconfirmation/consent fields are rejected.

Clients that stringify structured Tool fields receive the existing one-layercompatibility normalization: a JSON-encoded reference object, tags array, orinteger revision is decoded where its schema position disallows strings. Anullable text position permits real strings, so string "null" is deliberatelynot coerced. Collectionless callers that cannot emit top-level JSON null shouldomit collection_label.

The caller replaces only namespace label, the label of an existing collection,title, content, and tags. Mnemosyne preserves schema version, record ID, scope,namespace kind/ID, collection presence/ID, memory kind, language, provenance,lifecycle state, and created_at. On change, the server increments lifecyclerevision once and updates updated_at. Labels never rename directories orrelocate the record. Revision atomically replaces the same source file andcreates no second record, patch history, backup, diff, or tombstone.

Success returns only status, canonical versioned reference, and lifecycle:

{
  "status": "revised",
  "reference": {
    "schema_version": 2,
    "scope": "preference",
    "namespace_id": "tea",
    "collection_id": "favorites",
    "id": "mem_0123456789abcdef0123456789abcdef"
  },
  "lifecycle": {"state": "active", "revision": 4}
}

revised means one atomic replacement occurred. A current-revision normalizedno-op returns already_current without a write, timestamp update, or revisionincrement; stale revision conflicts before no-op detection. Archived memory maybe revised but remains archived, inspectable, and excluded from normal recall.Active memory remains recall-eligible.

The shared bounded content policy checks every replacement label, title,content value, and tag before storage access. It refuses recognized private-key,credential, authorization-header, JWT-shaped, payment-card, and SSN-shapedvalues with disallowed_content. Compact-token recognition requires JOSEcompact-serialization evidence—a base64url JSON header segment beginning eyJfollowed by two further segments—so ordinary dotted text such as versions,dates, hostnames, and module paths is stored normally. This is signaturedetection, not complete semantic DLP; secrets and sensitive personal dataremain prohibited.

Both memory_revise and memory_remember make a content refusal actionablewithout echoing the rejected value. The Tool error contains the first boundedcaller-visible field, one broad reason, and stable remediation guidance:

{
  "status": "refused",
  "code": "disallowed_content",
  "field": "content",
  "reason": "compact_token_shape",
  "message": "memory field resembles content that Mnemosyne does not store; review the named field and retry only if the user confirms that the formatting is benign"
}

The fixed reason vocabulary is private_key_shape, credential_shape,compact_token_shape, payment_card_shape, andgovernment_identifier_shape. Remember maps namespace IDs/labels tofield: namespace, collection IDs/labels to field: collection, and reportstitle, content, or tags directly. Revision reports its flat replacementfields: namespace_label, collection_label, title, content, or tags.Tags never expose an index.

Only the deterministic first match is reported. Results and logs never includethe matched value, offset, regular expression, provider-specific detector,fingerprint, or rejected content. The metadata is diagnostic, not permission toevade policy: do not obfuscate suspected sensitive data. Retry only after theuser verifies that the formatting is benign and approves the complete revisedcall.

Stable bounded error codes are invalid_reference,invalid_expected_revision, invalid_record, invalid_collection,disallowed_content, mutation_disabled, not_found, revision_conflict,write_conflict, memory_source_unavailable,replacement_outcome_uncertain, and internal_error. Error statuses are,as applicable, invalid_request, refused, policy_error, not_found,conflict, storage_error, uncertain, or internal_error.

replacement_outcome_uncertain means the atomic replacement may already bevisible, but parent-directory durability was not confirmed. Do not retryblindly: inspect the same reference first. If the requested replacement isalready present, do not retry; otherwise use the inspected current revision andobtain new exact per-call approval. If inspection is unavailable, the outcomeremains uncertain.

Logger mcp.memory_revise emits one terminal event containing only outcome,stable code/field where applicable, schema version, scope, and successfullifecycle state/revision. It omits IDs, labels, title, content, tags, completearguments, paths, fingerprints, exception details, and tracebacks.

list_tools prefixes the discovered Tool names with the same static serverversion exposed by MCP initialize and /version, for exampleServer: mymcp 0.2.0.. Restart the server and reconnect the client after anupgrade; a prior marker identifies a stale process.

Archiving and Restoring Memory

Archive and restore are disabled by default and are enabled together. Persistthe operator choice in the same fixed settings file:

[memory]
archive_restore_enabled = true

Or use the process override:

export MNEMOSYNE_MEMORY_ARCHIVE_RESTORE_ENABLED=true

Only exact lowercase true and false are accepted. This gate is independentof remember_enabled; enabling either capability does not enable the other.Restart the server and MCP client after changing enablement.

Each lifecycle request contains exactly the canonical version-2 reference frommemory_inspect and its current positive revision:

{
  "reference": {
    "schema_version": 2,
    "scope": "project",
    "namespace_id": "mnemosyne",
    "collection_id": "decisions",
    "id": "mem_0123456789abcdef0123456789abcdef"
  },
  "expected_revision": 1
}

The request accepts no legacy reference, path, root, filename, query, content,target state, timestamp, or consent field. Inspect immediately before proposingthe mutation so the complete exact reference and current revision can be shownfor approval. A stale revision always returns revision_conflict, even if therecord has since reached the requested state.

Archive changes active to archived, increments revision once, updatesupdated_at, and atomically replaces the same file. Archived memory is excludedfrom normal recall but remains available through exact inspection. Restoreperforms the inverse transition and returns the record to recall. Acurrent-revision archive of archived memory returns already_archived; acurrent-revision restore of active memory returns already_active. Idempotentoutcomes do not write, increment revision, or update metadata.

Success contains only status, canonical versioned reference, and lifecycle:

{
  "status": "archived",
  "reference": {
    "schema_version": 2,
    "scope": "project",
    "namespace_id": "mnemosyne",
    "collection_id": "decisions",
    "id": "mem_0123456789abcdef0123456789abcdef"
  },
  "lifecycle": {"state": "archived", "revision": 2}
}

The four normal statuses are archived, already_archived, restored, andalready_active. Stable bounded error codes are invalid_reference,invalid_expected_revision, mutation_disabled, not_found,revision_conflict, write_conflict, memory_source_unavailable,replacement_outcome_uncertain, and internal_error. Results never exposerecord content, paths, fingerprints, or storage wrappers.

For archive and restore, replacement_outcome_uncertain means the newlifecycle state may already be visible but directory durability was notconfirmed. Inspect the same reference before any newly approved retry. This isdistinct from forget's deletion-specific uncertain outcome.

Each server call logs one terminal event under mcp.memory_archive ormcp.memory_restore. Logs contain only outcome, stable code/field whereapplicable, schema version, scope, and successful lifecycle state/revision. Theyomit IDs, namespace/collection identity, labels, title, content, tags, completearguments, paths, exception details, and tracebacks.

Permanently Forgetting Memory

Forget is disabled by default and has its own gate. It is not enabled byremember or archive/restore. Persist the operator choice in the fixed settingsfile:

[memory]
forget_enabled = true

Or use the exact process override:

export MNEMOSYNE_MEMORY_FORGET_ENABLED=true

Only lowercase true and false are accepted. Restart the server and MCPclient after changing either source. Clients that cannot require approval forevery exact call must leave forget disabled.

Forget accepts the same exact canonical version-2 reference and positiveexpected_revision request shape shown above for lifecycle mutation. It acceptsno legacy reference, path, content, fingerprint, target state, timestamp, orconfirmation field. The record must already be archived at that currentrevision. A stale request returns revision_conflict before state eligibility;a current active record returns not_archived unchanged. Inspect immediatelybefore proposing forget so the complete record, archived state, reference, andcurrent revision can be reviewed for per-call approval.

Success physically removes the one source file, leaves organizationaldirectories intact, creates no tombstone, hidden history, backup, retained hash,or deletion manifest, and returns only:

{
  "status": "forgotten",
  "reference": {
    "schema_version": 2,
    "scope": "project",
    "namespace_id": "mnemosyne",
    "collection_id": "decisions",
    "id": "mem_0123456789abcdef0123456789abcdef"
  }
}

A second call returns not_found; Mnemosyne cannot fabricate idempotent proofwithout a tombstone. Stable bounded codes are invalid_reference,invalid_expected_revision, mutation_disabled, not_archived, not_found,revision_conflict, write_conflict, memory_source_unavailable,deletion_outcome_uncertain, and internal_error.

deletion_outcome_uncertain means unlink may have succeeded but directorydurability was not confirmed. Do not retry blindly. Inspect the same reference:if it is absent, do not retry; if it is present, review it again, require it toremain archived, use its current revision, and obtain new per-call approval. Ifinspection is unavailable, the outcome remains uncertain.

Forgetting is irreversible within Mnemosyne: restore cannot recover a forgottenrecord. Physical source deletion is not secure erasure and does not removefilesystem journal data, snapshots, backups, MCP-client history, logs outsideMnemosyne, or external copies. Logger mcp.memory_forget emits one terminalcontent-free event with only bounded outcome/code/field, schema version, andscope metadata.

Remembering Memory

Remember is disabled by default. With no setting, an accepted disabled setting,or the exact environment value false, tools/list and list_tools omitmemory_remember and direct dispatch treats it as unknown.

Persist the operator's choice in the one fixed local settings file:

~/.mnemosyne/config.toml
[memory]
remember_enabled = true

The file is optional and read-only to Mnemosyne. Startup does not create oredit it or its parent. A missing file, empty document, absent or empty[memory] table, absent key, or TOML boolean false all mean disabled. Thedocument may contain only the optional [memory] table, which may contain onlythe optional TOML booleans remember_enabled, archive_restore_enabled,forget_enabled, and revise_enabled;strings such as "true", unknown keys/tables, and malformed TOML fail startupclosed.

For one process-level override, use:

export MNEMOSYNE_MEMORY_REMEMBER_ENABLED=true

Each environment variable overrides only its matching setting. Mnemosyne parsesall four mutation environment values first; an invalid supplied value failsstartup before file access without being echoed. If any setting remainsunresolved, Mnemosyne reads the strict file at most once for unresolved values.The file is bypassed only when all four environment variables are supplied.Every unresolved setting finally defaults to false.

The server reads enablement once at startup, so restart it after changing eithersource. Restart or reconnect the MCP client as well so it refreshes Tooldiscovery. Enabling the server-side Tool does not establish user consent. Acompatible MCP client must separately show the complete arguments and requireuser approval for every exact call.

The settings source is limited to 16 KiB of UTF-8 TOML. Mnemosyne rejects asymlinked .mnemosyne directory or file, non-directory/non-regular source,unreadable source, and—on POSIX—a directory or file writable by group or others.Use mode 0700 for ~/.mnemosyne and 0600 for config.toml; non-writable0755/0644 modes are also accepted because this file is not a secret store.Configuration failures use stable bounded messages and do not expose suppliedvalues, file contents, parser details, underlying exception text, or theabsolute settings path.

Nine caller-owned fields are always required, including nullable values. TheTool schema publishes those nine plus optional occurred_at in top-levelproperties, while retaining the nine-field top-level required list, so clientsthat keep only a flat object schema can construct both ordinary memories andevents. Six scope-specific oneOf branches additionally narrow namespace kindand memory kind for clients that support composition:

{
  "scope": "project",
  "namespace": {
    "kind": "project",
    "id": "mnemosyne",
    "label": "Mnemosyne"
  },
  "collection": {
    "id": "decisions",
    "label": "Decisions"
  },
  "kind": "decision",
  "language": "en",
  "title": "Remember consent boundary",
  "content": "Durable memory requires approval for each exact Tool call.",
  "tags": ["architecture", "consent"],
  "origin": "user_approved_proposal"
}

For a completed project occurrence, use kind: "event" and include its knownoccurrence instant separately from persistence time:

{
  "scope": "project",
  "namespace": {"kind": "project", "id": "mnemosyne", "label": "Mnemosyne"},
  "collection": {"id": "events", "label": "Events"},
  "kind": "event",
  "language": "en",
  "title": "Track activated",
  "content": "Track 021 moved to active execution.",
  "tags": ["track-021"],
  "origin": "explicit_user_statement",
  "occurred_at": "2026-07-20T15:00:00Z"
}

occurred_at is required exactly for event, rejected for every other kind,and uses strict UTC-second form YYYY-MM-DDTHH:MM:SSZ. It is immutable aftercreation: revision has no occurrence replacement field, and archive/restorepreserve it. Existing non-event version-2 records remain valid without thefield and serialize without an invented null value.

namespace.label, collection, collection.label, language, and titlemay be null, but their keys remain required. Tags are a required zero-to-tenitem array. Namespace/collection IDs are 1–64 safe identifier characters,labels are at most 100 characters, language tags at most 35, title at most 200,content at most 4,000, and each tag at most 50. Unknown fields are rejected atevery level. The allowed dimensions are derived from the shared domain:

Scope Namespace kinds Memory kinds
self aspect attribute
relationship person, group, relationship perspective, summary
preference domain preference
practice domain practice
project project decision, constraint, state, event, question, reference, summary
knowledge topic reference, summary

The shared domain defines writing guidance for every allowed (scope, kind)pair. Complete scope branches publish only their applicable guidance, while thetop-level kind description groups all guidance by scope for clients thatdiscard schema composition. Shared kinds such as summary and referencetherefore retain scope-specific meaning.

Public origin is caller-supplied provenance context: useexplicit_user_statement for a direct user statement oruser_approved_proposal for an approved proposed memory. Origin is not consent;consent remains the MCP client's approval of the complete exact call.recorded_via is instead server-assigned. Callers cannot supply a filesystempath, record ID, persistence timestamps, lifecycle state, revision,recorded_via, or model-authored confirmation/consent field. The event-onlyoccurred_at value is the sole caller-owned structural time.

A new memory returns only its status, structured reference, and lifecycle:

{
  "status": "remembered",
  "reference": {
    "scope": "project",
    "namespace_id": "mnemosyne",
    "collection_id": "decisions",
    "id": "mem_0123456789abcdef0123456789abcdef"
  },
  "lifecycle": {
    "state": "active",
    "revision": 1
  }
}

An exact active duplicate returns already_exists; an archived duplicatereturns existing_archived. Both identify the existing reference/lifecycle andwrite no second file. Validation, content refusal, disabled mutation, candidateoverflow, generated-ID conflict, storage failure, and unexpected failure returnbounded Tool errors with stable codes and no path or submitted content. Contentrefusal uses the bounded field/reason contract documented under revision above.Validation uses invalid_scope, invalid_namespace, invalid_collection,invalid_kind, invalid_record, or invalid_origin; policy refusal usesdisallowed_content; disabled mutation uses mutation_disabled; boundeddiscovery uses candidate_limit_exceeded; publication conflict useswrite_conflict; storage/path failures use memory_source_unavailable; and anunexpected failure uses internal_error.

Event duplicate identity includes occurred_at: otherwise-equal events at thesame occurrence instant are duplicates, while events at different instants aredistinct. Existing non-event duplicate identity is unchanged.

Before duplicate discovery or directory creation, the shared policy rejectsrecognized private-key blocks, declared provider token/API-key prefixes,Basic/Bearer authorization headers, credential assignments andcredential-bearing URLs, compact JWT-shaped values, Luhn-valid 13–19 digitpayment-card values, and SSN-shaped identifiers. It inspectsnamespace/collection IDs and labels, title, content, and tags. This isintentionally bounded signature detection, not semantic DLP: false positivesand false negatives remain possible. Unrecognized secrets and sensitivepersonal facts remain prohibited, and the user must review the exact proposedarguments before approval.

Remember logs one terminal event containing only outcome, stable errorcode/field where applicable, scope, namespace kind, memory kind,collection-present state, origin, and generated ID/lifecycle after a domainresult. Logs never include labels, title, content, tags, language,occurred_at, complete arguments, rejected values, filesystem paths, exceptionmessages, or tracebacks.

Filesystem Memory

The default memory root is:

~/.mnemosyne/memory

No manual first-run initialization is required. When an enabled, valid,policy-accepted memory_remember call reaches canonical creation, Mnemosynelazily creates any missing directories from the nearest existing ancestorthrough the record directory. Every newly created directory uses private mode0700 on POSIX, and the record file uses mode 0600. Existing directories areleft unchanged rather than chmodded.

Resolving either settings source, starting the server, recalling memory,disabled or invalid remember calls, and content-policy refusals do notinitialize the memory root. Filesystem initialization therefore remains behindthe existing operator-enable and per-call consent boundaries.

Set an explicit root for another local location:

export MNEMOSYNE_MEMORY_ROOT=/path/to/memory

The memory domain recognizes only the six fixed scope directories beneath thememory root:

memory/
  self/
  relationship/
  preference/
  practice/
  project/
  knowledge/

Legacy version-1 records remain readable in their existing locations. Theirminimal format is:

{
  "schema_version": 1,
  "id": "rainy-weekend",
  "title": "Rainy weekend activities",
  "content": "On rainy weekend afternoons, the user prefers museums or quiet cafés.",
  "tags": ["leisure", "rainy-day", "weekend"]
}

Version-1 schema_version, id, and content are required; title and tagsare optional. No background migration or rewrite occurs.

Canonical version-2 records are self-contained and use a deterministic path:

<scope>/<namespace-id>/<collection-id?>/<memory-id>.json

For example:

project/mnemosyne/decisions/mem_0123456789abcdef0123456789abcdef.json
{
  "schema_version": 2,
  "id": "mem_0123456789abcdef0123456789abcdef",
  "scope": "project",
  "namespace": {
    "kind": "project",
    "id": "mnemosyne",
    "label": "Mnemosyne"
  },
  "collection": {
    "id": "decisions",
    "label": "Decisions"
  },
  "kind": "decision",
  "language": "en",
  "title": "Shared memory ownership",
  "content": "Canonical memory concepts belong to the shared memory domain.",
  "tags": ["architecture", "memory-domain"],
  "provenance": {
    "origin": "explicit_user_statement",
    "recorded_via": "memory_remember"
  },
  "lifecycle": {
    "state": "active",
    "revision": 1
  },
  "created_at": "2026-07-18T12:00:00Z",
  "updated_at": "2026-07-18T12:00:00Z"
}

Scope, namespace, optional collection, kind, language, content, tags,provenance, persistence timestamps, optional event occurrence time, andlifecycle are separate dimensions. IDs determine paths; mutable labels do not.Record metadata must agree with its location. Unknown fields or mismatched pathsmake a version-2 record invalid.

Canonical project events persist "kind": "event" and a strict"occurred_at" value. Exact inspection returns that field; recall and listingretain their existing relevance and identity ordering rather than becomingchronological views. Mnemosyne does not create timeline resources, infercausality, automatically supersede state, or make event records fullyappend-only. A first-class many-to-many temporal model remains deferred until aconcrete usage need demonstrates it.

Version-2 records are either active or archived; normal recall excludesarchived records. Revision replaces the same file atomically without retaininghidden prior content. Forgetting is physical deletion with no tombstone.Remember creation, complete-state revision, reversible archive/restore, andarchived-only physical forget are exposed through explicit MCP Tools behindindependent default-off gates. Revision atomically replaces the same canonicalfile and retains no hidden prior content.

All record files are limited to 64 KiB, content to 4,000 characters, and titlesto 200 characters. Invalid, oversized, too-deep, or unsafe records are skippedand logged without their content.

Recall retrieval case-folds and tokenizes the query, relative path, title, content, andrecord tags. Exact request-tag overlap has the strongest weight, followed bytitle, path/record-tag, and content matches. Ties are resolved deterministically.Symlinks are rejected, no more than 1,000 candidate files are accepted in onescope, and no more than five records are returned. Files remain the source oftruth: inspect them directly and delete a record by deleting its file.

There is no required manifest or persistent content-bearing index. Exactinspection and complete listing use structured selectors and never accept afilesystem path. Scope-wide listing applies the same 1,000-candidate bound;canonical namespace and collection selectors narrow to their deterministic safecontainer before candidate counting. Collectionless and exact-collectiondiscovery scan only the canonical path level. Listing fails instead of returninga partial inventory when the selected container exceeds the bound.Every mutation remains disabled unless its operator gate enables it and the MCPclient can require approval for every exact call. A model-provided confirmationfield is not consent.

MCP Validation

An MCP request envelope must be an object. Otherwise the server returnsJSON-RPC error -32600 with the message Invalid Request and id: null.When present, its params value must also be an object. Otherwise the serverreturns JSON-RPC error -32602 with the message Invalid params and preservesthe request ID. For tools/call, params.arguments must likewise be an objectwhen present; non-object Tool arguments receive the same -32602 responsebefore Tool selection, schema-aware normalization, or handler dispatch.

MCP notifications omit id and receive HTTP 202 with no JSON-RPC responsebody. notifications/initialized and notifications/cancelled are accepted;cancellation is currently a no-op because tool handlers complete synchronously.

For compatibility with MCP clients that stringify structured Tool arguments,dispatch uses the selected Tool's advertised input schema to remove at most oneextra JSON-encoding layer. Normalization occurs only where the schema disallowsa string and the decoded JSON value has a permitted type. Correctly typed valuesare unchanged; fields that permit strings are never decoded; malformed,wrong-type, or repeatedly encoded values continue to the Tool's normal boundedvalidation. The advertised Tool schemas and canonical memory formats remainunchanged. For memory_list, a stringified page size can therefore normalize toan integer, while collection_id strings—including "null"—remain stringsbecause that field legitimately permits them. Collectionless selection requiresnative JSON null.

Intended Roles

MyMCP is intended to become a local-first MCP host and client-neutral governancegateway. It owns Tool composition, identity, plugin contracts, routing, andreusable host mechanisms without absorbing integration-specific domain policy.

Its approved Tools-only target separates one host-owned logical plugin API fromconcrete bundled implementations and isolated external execution adapters. Itretains qualified (plugin_id, capability_kind, capability_local_id) origininternally and binds that identity to the endpoint's flat MCP Tool name. Hostbootstrap remains explicit. Native installation, lifecycle generations,isolation, authenticated client policy, host-verifiable exact-call approval,and bounded security audit remain unimplemented.

Mnemosyne remains the bundled user-governed memory domain. It gives agentscontrolled access to approved durable records and bounded retrieval whilepermanently preserving its Tool, configuration, storage, record, logging,consent, and memory-domain identity. Its configuration, memory domain, MCPadapters, and plugin composition live under mymcp/plugins/mnemosyne/.

Non-Goals

MyMCP and its built-in Mnemosyne domain are not intended to provide:

  • generic shell execution or unrestricted filesystem access;
  • secret storage;
  • hidden mutation or governance that bypasses visible user consent;
  • a multi-user platform before an explicit threat model supports one;
  • MCPB as the native MyMCP plugin format; or
  • unknown-code loading, lifecycle, marketplace, or isolation claims beforeartifact, supervision, authority, failure, and approval contracts areimplemented and validated.

Running the Server

Clone the canonical MyMCP repository target:

git clone https://github.com/flyset/MyMCP.git
cd MyMCP

The canonical repository is https://github.com/flyset/MyMCP; the former URLredirects here.

The MCP endpoint is exposed at:

http://127.0.0.1:8000/mcp

Additional operational endpoints:

  • http://127.0.0.1:8000/health
  • http://127.0.0.1:8000/version

Create a local virtual environment and install the project in editable mode:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e .

Start the development server with auto-reload:

mymcp-dev

Start the server without auto-reload:

mymcp

The supported direct ASGI target is the application factorymymcp.app:create_production_app with Uvicorn factory mode. The former internalmodule-level target mymcp.app:app no longer exists.

Run the test suite after installing the test extra:

mymcp-test

OpenCode Configuration

The tracked opencode.json registers this server as remote connection and agentmymcp. At both policy levels it denies the broad mymcp_* prefix first, thenallows exactly four read-only Tools (list_tools, memory_recall,memory_inspect, and memory_list), then asks for the five exact mutationTools (remember, revise, archive, restore, and forget). The order matters:OpenCode uses the last matching Tool-name rule and per-agent permissions canoverride top-level rules. The tracked and ignored OpenCode migration is complete;the legacy Claude configuration is excluded. The normal MyMCP endpoint and finalclient reconnect were verified. In isolated checks, one approved mutation wasapproved once and one rejected mutation made no Tools call; neither check changedthe memory root.

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "mymcp_*": "deny",
    "mymcp_list_tools": "allow",
    "mymcp_memory_recall": "allow",
    "mymcp_memory_inspect": "allow",
    "mymcp_memory_list": "allow",
    "mymcp_memory_remember": "ask",
    "mymcp_memory_revise": "ask",
    "mymcp_memory_archive": "ask",
    "mymcp_memory_restore": "ask",
    "mymcp_memory_forget": "ask"
  },
  "mcp": {
    "mymcp": {
      "type": "remote",
      "url": "http://127.0.0.1:8000/mcp",
      "enabled": true
    }
  },
  "agent": {
    "mymcp": {
      "permission": {
        "mymcp_*": "deny",
        "mymcp_list_tools": "allow",
        "mymcp_memory_recall": "allow",
        "mymcp_memory_inspect": "allow",
        "mymcp_memory_list": "allow",
        "mymcp_memory_remember": "ask",
        "mymcp_memory_revise": "ask",
        "mymcp_memory_archive": "ask",
        "mymcp_memory_restore": "ask",
        "mymcp_memory_forget": "ask"
      }
    }
  }
}

This client permission does not enable mutation on the server. The operatormust separately set the applicable remember, revise, archive/restore, or forgetserver gate and restart the server. After changing opencode.json or agentpolicy, quit and restart OpenCode so it reloads configuration and Tool discovery.

For every proposed mutation call, review the complete Tool arguments and chooseonce. Rejecting a mutation prevents the request from reaching Mnemosyne andtherefore produces no write. Do not start OpenCode with --auto or enableinteractive auto-approval while memory mutation is enabled: each bypassesapproval on later exact calls. If either mode was used, disable server mutationand restart both the server and OpenCode before continuing. Any additionalper-agent permission override must preserve this order: broad mymcp_*denial first, explicit lower-breadth read-only allows (including memory_list)next, and the exact mutation asks last.

Integrating Mnemosyne with a Repository

After Mnemosyne's memory Tools are available to an AI client, add a repository-rootMEMORY.md. It is the repository-local operating contract: it tells agents whichproject context to retrieve, where durable records belong, and when records shouldbe created, revised, archived, or forgotten.

Keep the repository, Git history, backlog, and documentation as the authoritativeengineering record. Mnemosyne preserves concise, user-approved orientation,rationale, and delivery history across sessions.

Start with docs/GETTING_STARTED.md for a project memory-map template andintegration guidance. Agents should read docs/MANUAL.md for general safe Tool-useguidance before operating on memory.

Roadmap Shape

The roadmap converges on the complete approved end state rather than freezing abundled-only callable or deferring identity and security boundaries:

  1. Delivered: kind-qualified Tools-only identity, effect/consent metadata,host-owned bindings, immutable HostRuntime, a trusted Mnemosyne adapter,explicit bootstrap, runtime injection, immutable definition contracts, strict64 KiB manifest parsing, complete packaged declaration, exact parity, staticvalidation before generation, wheel inclusion, and the one canonicalMnemosyne implementation under mymcp/plugins/mnemosyne/—without changingpublic behavior.
  2. Released: MyMCP/mymcp 0.2.0 host, application, package, repository,and tracked-client identity preserve all Mnemosyne plugin/domain identities.The public non-draft, non-prerelease release is tagged mymcp-v0.2.0 atc2852bc.
  3. Add side-effect-free native wheel inspection, digest-bound receipts,immutable managed environments, bounded configuration/secret references, andpersisted bindings without granting execution authority.
  4. Add isolated external activation only after a local unknown-code threat model,supervision, killability, resource bounds, and default-denyfilesystem/network enforcement are validated.
  5. Add generation lifecycle, required/optional failures, drain, quarantine,update/rollback and data migration, removal/preservation, and separate purge.
  6. Build authenticated local-client routing, policy-filtered discovery/dispatch,single-use exact-call approval, and bounded security audit behind the onemachine-local endpoint.
  7. Generalize host services only after a second real plugin proves them reusable.

MCPB may later package MyMCP as one complete server. It is not the native MyMCPplugin distribution, manifest, or execution boundary.

See docs/PLUGIN_ARCHITECTURE.md for the target and incremental migration rules.

See VISION.md for MyMCP's broader scope and boundaries. Seedocs/MNEMOSYNE_VISION.md for the built-in memory domain's notebook model,safety contract, and direction.

See docs/ARCHITECTURE.md for the current code organization.

See docs/PLUGIN_ARCHITECTURE.md for the approved plugin end state and roadmapalignment.

See docs/GETTING_STARTED.md for repository-level project-memory integration,and docs/MANUAL.md for operating guidance for agents using memory Tools.

See docs/AI_WORKFLOW.md for contribution and verification gates, anddocs/GLOSSARY.md for canonical terms and public-contract language.

MCP Server · Populars

MCP Server · New

    Cassette-Editor

    Oh My Cassette: Chat Your Raw Clips Into a Finished Cut

    你的随身 AI 剪辑搭档 | Pocket AI co-editor for video montage — AI video editing plugin & MCP server for Claude Code, Codex, Hermes & OpenCode

    Community Cassette-Editor
    trendsmcp-ai

    Trends MCP

    MCP server for live trend data. Query Google Search, YouTube, TikTok, Reddit, Amazon, Wikipedia, News sentiment, Web Traffic, App Downloads, Steam, npm and more. Works with Claude, Cursor, VS Code, GitHub Copilot, ChatGPT, Windsurf, Cline, Raycast and any MCP-compatible.

    Community trendsmcp-ai
    jacob-bd

    Gemini Notebook (formerly Google NotebookLM) CLI & MCP Server

    Programmatic access to Gemini Notebook - via command-line interface (CLI), Model Context Protocol (MCP) server, and AI agent skills.

    Community jacob-bd
    PxyUp

    Fitter — web data for AI agents

    New way for collect information from the API's/Websites

    Community PxyUp
    kayhendriksen

    foehn

    Download MeteoSwiss Open Government Data — weather stations, radar, hail, forecasts and climate series — via Python API, CLI, or MCP server, as DataFrames, Parquet, xarray Datasets or Zarr stores

    Community kayhendriksen