Skip to main content
Glama
README.md
# โšก Priostack Agent Context Network (ACN)

> **Zero-setup, model-agnostic long-term memory and multi-agent context sharing over MCP.**

[![PyPI version](https://img.shields.io/pypi/v/priostack.svg)](https://pypi.org/project/priostack/)
[![CI](https://github.com/ideaswave/priostack/actions/workflows/ci.yml/badge.svg)](https://github.com/ideaswave/priostack/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Priostack ACN treats an agent's long-term memory as a **network resource** instead of something
bolted to one LLM vendor. It is a **Model Context Protocol (MCP)** server, reached over JSON-RPC 2.0,
where agents self-register, keep isolated context spaces, store typed facts, read them back, and share
them with other agents through scoped, revocable capability grants.

The public server is live at **`https://priostack.com/mcp`** (a discoverable Streamable-HTTP MCP
endpoint; `https://priostack.com/acn/rpc` is a working alias).

---

## ๐Ÿ”ฅ What it gives you

- ๐Ÿค– **Zero-setup onboarding** โ€” an agent self-registers via `noetic.register` and gets a bearer
  token. No dashboard, no UI, no credit card.
- ๐ŸŒ **Model-agnostic memory** โ€” the same context serves an OpenAI, Anthropic, or local-model agent;
  memory is decoupled from the model.
- ๐Ÿค **Scoped multi-agent sharing** โ€” grant another agent explicit content rights (`read`, `quote`,
  `write`, `share`, `export`, ...) on a space, or let it `request_access` and approve it. Grants are
  revocable and forward-only.
- ๐Ÿง  **Typed facts** โ€” store `declaration`s (rules/policies), `observation`s (measured facts), and
  `measurement`s, keeping "what is asserted" separate from "what was observed".
- ๐Ÿ”Œ **Native MCP** โ€” connect Claude Desktop, Cursor, or any MCP client by URL, or use one of the
  SDKs below.

---

## ๐Ÿš€ Quickstart (Python)

```bash
pip install priostack
```

```python
from priostack import ACNClient

with ACNClient() as acn:                       # defaults to https://priostack.com/mcp
    acn.register(display_name="my-agent")      # self-register; token captured on the client
    acn.connect()                              # open a session; session id captured internally

    space = acn.create_space(display_name="prod-memory")
    acn.store(space.space_id, objects=[
        {"content": "Refunds over $500 require manager approval.", "type": "declaration"},
        {"content": "Export pipeline latency was 1.8s at 14:02 UTC.", "type": "observation"},
    ])

    hits = acn.fetch(space.space_id, query="refund")   # substring content reader
    for content in hits.contents():
        print(content)
```

> **Persist the token.** `register()` returns a bearer token that is shown once. Store it (and the
> space id) and reconnect later with `ACNClient(token=...)` instead of registering again.

More runnable examples in [`examples/`](examples/): [multi-agent sharing](examples/context_sharing.py),
[request & approve access](examples/request_and_approve.py),
[fetch & recall](examples/fetch_and_recall.py),
[revoke & rotate](examples/revoke_and_rotate.py), and memory integrations for
[LangChain](examples/langchain_memory.py), [CrewAI](examples/crewai_memory.py), and a
[Claude agent](examples/claude_agent_memory.py).

Every example honours **`PRIOSTACK_ENDPOINT`**, so one exported variable points them all at a
self-hosted node, a staging one, or a local one:

```bash
export PRIOSTACK_ENDPOINT=http://127.0.0.1:8091/rpc
```

---

## ๐Ÿงฉ Agent-framework quickstarts

Each one is a complete arc โ€” register, create a space, store, **share it with a second agent**, read
it back โ€” and each runs on its own: the ACN calls are real, and the framework half is skipped with a
message when the framework (or an LLM key) is not installed.

| Framework | Quickstart | What it shows |
| :--- | :--- | :--- |
| **CrewAI** | [`examples/crewai_quickstart.py`](examples/crewai_quickstart.py) | Every crew member has its **own ACN identity**; the researcher owns the space and grants the writer `read` + `quote` |
| **LangGraph** | [`examples/langgraph_quickstart.py`](examples/langgraph_quickstart.py) | Memory that **outlives the graph run** โ€” run 2 answers from what run 1 stored โ€” then a reviewer agent is granted `read` on the same space |
| **AutoGen** | [`examples/autogen_quickstart.py`](examples/autogen_quickstart.py) | The **pull** handshake: the analyst discovers a published space, requests `read` with a reason, and the archivist approves |

```bash
pip install priostack
python examples/crewai_quickstart.py          # works with or without crewai installed
```

---

## ๐Ÿค Multi-agent context sharing

An owner grants another agent scoped access to a space. The grant subject is the grantee's **agent
id** (returned by `register()`), and the grantee must **reconnect** afterward to pick up the widened
scope.

```python
# Owner stores knowledge and grants read + quote to a worker agent.
grant = owner.grant_access(space.space_id, worker_agent_id, rights=["read", "quote"])

worker.connect()                       # reconnect to apply the grant
print(worker.fetch(space.space_id, query="refund").contents())

owner.revoke_access(grant.capability_ref)   # immediate, forward-only
```

Prefer a pull model? The consumer calls `request_access(space_id, rights=["read"])`, the owner
`list_requests()` and `approve_request(request_id)`. See
[`examples/request_and_approve.py`](examples/request_and_approve.py).

---

## ๐ŸŒ SDKs in 15 languages

Python is the reference SDK (this repo root, on PyPI). Idiomatic clients for 14 more languages live
under [`clients/`](clients/), each with its own quickstart and README and each implementing the exact
same wire contract ([`clients/SPEC.md`](clients/SPEC.md)).

| Language | Path | HTTP + JSON stack |
| :--- | :--- | :--- |
| Python | [`/`](src/priostack) ยท PyPI `priostack` | `requests` |
| JavaScript (Node โ‰ฅ20) | [`clients/javascript`](clients/javascript) | built-in `fetch` |
| TypeScript | [`clients/typescript`](clients/typescript) | global `fetch` (typed) |
| Java (Maven) | [`clients/java`](clients/java) | `java.net.http` + Jackson |
| Go | [`clients/go`](clients/go) | stdlib `net/http` |
| C# / .NET 8 | [`clients/csharp`](clients/csharp) | `HttpClient` + `System.Text.Json` |
| PHP (Composer) | [`clients/php`](clients/php) | curl |
| Ruby | [`clients/ruby`](clients/ruby) | stdlib `net/http` |
| Rust | [`clients/rust`](clients/rust) | `reqwest` + `serde` |
| Kotlin (Gradle) | [`clients/kotlin`](clients/kotlin) | `java.net.http` |
| Swift (SwiftPM) | [`clients/swift`](clients/swift) | `URLSession` + `Codable` |
| C++17 | [`clients/cpp`](clients/cpp) | libcurl + nlohmann/json |
| Dart | [`clients/dart`](clients/dart) | `package:http` |
| Scala | [`clients/scala`](clients/scala) | `java.net.http` + uPickle |
| Shell | [`clients/shell`](clients/shell) | `curl` + `jq` |

Each client ships **two quickstarts**: a solo one (register โ†’ create space โ†’ store โ†’ fetch) and a
sharing one (`share_quickstart` โ€” two agents, one space, an explicit grant, then a revoke), because
an agent that only ever talks to itself is not using a network.

Each client unwraps the MCP envelope, captures the session id, raises typed errors on tool denials,
and reuses one HTTP connection. **Every one of the 15 sharing quickstarts has been run end-to-end
against a live ACN node** โ€” registering two agents, granting, reading and revoking โ€” and every client
builds in CI (see [`.github/workflows/ci.yml`](.github/workflows/ci.yml)).

---

## ๐Ÿ› ๏ธ Use it from an MCP client (Claude Desktop, Cursor)

The ACN is a discoverable Streamable-HTTP MCP server, so an MCP client connects by URL. Ready-made
configs are in [`examples/mcp_config/`](examples/mcp_config/).

**Claude Desktop** (Settings โ†’ Developer โ†’ Edit Config), via the `mcp-remote` bridge:

```json
{
  "mcpServers": {
    "priostack-acn": { "command": "npx", "args": ["-y", "mcp-remote", "https://priostack.com/mcp"] }
  }
}
```

**Cursor** (native remote MCP by URL):

```json
{ "mcpServers": { "priostack-acn": { "url": "https://priostack.com/mcp" } } }
```

Sanity-check discovery yourself:

```bash
curl -s https://priostack.com/mcp -H 'Content-Type: application/json' -H 'Accept: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools | length'
```

---

## ๐Ÿ“– API reference (JSON-RPC 2.0)

Endpoint: `https://priostack.com/mcp` (alias `https://priostack.com/acn/rpc`).

Every call is a `tools/call`:

```json
{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"noetic.store","arguments":{ "sessionId":"...", "space":"space-1", "objects":[...] }}}
```

The response wraps the result envelope as text; unwrap it as
`JSON.parse(response.result.content[0].text)` to get `{ok, outcome, data, detail?}`. On `ok:false`
the `outcome` is one of `not-found`, `invalid-query`, `capability-denied`, `policy-denied`,
`requires-governance`, `stale-base`, `integrity-fault`, `conflict`, `capacity-exhausted`,
`not-implemented`. (Every SDK above does this unwrapping and error mapping for you.)

| Method | Purpose | Key arguments | Notes |
| :--- | :--- | :--- | :--- |
| `noetic.register` | Self-register an agent | `displayName` | returns `data.token` (shown once) |
| `noetic.connect` | Open a session | `token`, `maxResponseTokens` | returns `data.SessionID` (**PascalCase**) |
| `noetic.create_space` | Create a context space | `sessionId`, `displayName`, `defaultRights` | returns `data.spaceId` |
| `noetic.store` | Persist typed facts | `sessionId`, `space`, `objects[]` | `type` โˆˆ declaration \| observation \| measurement |
| `noetic.fetch` | **Read stored content back** | `sessionId`, `space`, `query`, `limit` | substring filter; this is the reader |
| `noetic.grant` | Grant scoped access | `sessionId`, `subjectPrincipal`, `resource`, `rights[]`, `worldMutation` | space arg is `resource`; grantee reconnects |
| `noetic.revoke` | Revoke a capability | `sessionId`, `capabilityRef` | immediate, forward-only |
| `noetic.request_access` | Ask for access | `sessionId`, `space`, `rights[]`, `reason` | rights arg is `rights` |
| `noetic.list_requests` | List pending requests | `sessionId` | owner side |
| `noetic.approve_request` | Approve a request | `sessionId`, `requestId`, `rights[]` | mints the grant |
| `noetic.discover` | List public spaces | `query`, `limit` | no session required |
| `noetic.metrics` | Usage for the session | `sessionId` | account + space gauges |
| `noetic.rotate_token` | Mint a fresh token | `sessionId` | retires the old token |
| `noetic.disconnect` | End the session | `sessionId` | durable facts are kept |

> **`fetch` vs `query`:** `noetic.fetch` returns stored **content** (substring-filtered). `noetic.query`
> is a *geometric* divergence probe over the memory, not a content read โ€” don't reach for it to read
> facts back.

There are ~40 tools in total; every SDK exposes a generic `call(method, arguments)` escape hatch to
reach the ones not wrapped explicitly.

---

## ๐Ÿ“š Documentation

| | |
|---|---|
| [What the Agent Context Network is](https://priostack.com/agent-context-network) | The concept, the permission model, FAQ |
| [API & tools reference](https://priostack.com/docs-agent-context-network) | Every MCP tool, grouped by what it does |
| [Integration guides](https://priostack.com/integrations) | Claude, Cursor, LangChain, CrewAI, OpenAI-compatible agents |
| [Developer hub](https://priostack.com/developers) | MCP, Python and HTTP entry points |
| [Tutorials](https://priostack.com/tutorials) | Step-by-step walkthroughs |
| [Free plan and limits](https://priostack.com/pricing) | Free to use: 5 spaces, 500,000 objects and 500,000 queries a month per agent account |

---

## ๐Ÿงช Development

```bash
pip install -e ".[dev]"
pytest                     # unit tests (mocked transport, no network)
ruff check src tests
./scripts/check-links.sh   # every link in the docs still resolves
```

CI (GitHub Actions) runs the Python test suite, builds/type-checks every language client, and
checks the documentation links on each pull request.

---

## ๐Ÿ“„ License

MIT. See [`LICENSE`](LICENSE).

TDQS

C2.4/5.0

Scored across 40 tools

Disambiguation2/5

Many tools have overlapping or highly specialized purposes that are hard to distinguish without deep domain knowledge (e.g., noetic.observe vs noetic.query vs noetic.reason vs noetic.ground; noetic.propose vs noetic.simulate vs noetic.materialize). The descriptions use dense jargon, making it difficult for an agent to reliably select the right tool.

Naming Consistency3/5

The naming is mostly consistent with a noetic. prefix and verb-style names (connect, disconnect, query, commit, grant, revoke). However, some names are abstract or inconsistent in style (e.g., noetic.orient, noetic.territory, noetic.focus, noetic.ground) and don't follow a clear verb_noun pattern like others.

Tool Count2/5

40 tools is a very large surface for a single server, and many tools are highly specialized or overlapping. While the server appears to cover a complex domain, the count feels excessive and would likely overwhelm an agent, especially with many niche operations (e.g., noetic.orient, noetic.territory, noetic.metrics).

Completeness4/5

The tool set covers a broad lifecycle: registration, connection, spaces, grants, access requests, assertions, checkpoints, commits, and receipts. There are some potential gaps (e.g., no explicit tool for deleting a space or revoking a session), but the surface is fairly comprehensive for the apparent domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues