FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat: expose JSS as an MCP server (--mcp) — proposed v0.0.200 · Issue #490 · JavaScriptSolidServer/JavaScriptSolidServer · GitHub

Repository navigation

feat: expose JSS as an MCP server (--mcp) — proposed v0.0.200 #490

Closed

Description

Why

The agent ecosystem (Claude Desktop, Cursor, custom agents, …) has no shared answer for sovereign, ACL-gated storage. Every agent today bolts on its own DB, vector store, or secrets vault. Solid's pitch — user-owned data, queryable, access-controlled — is exactly what agents need, but the wire connecting them doesn't exist yet.

MCP (Model Context Protocol) is becoming that wire. If JSS speaks MCP, every MCP-compatible agent gets a sovereign data layer for free, with WAC, WebIDs, and Nostr identities all already in place.

Thesis statement: "MCP needs a backend. Solid is the backend."

This is the proposed v0.0.200 capstone — completing the feature-development phase before consolidation.

What

```bash
jss start --mcp # exposes /mcp endpoint speaking MCP
```

Initial tools

Tiny surface to start; expand once the foundation is in:

Tool Maps to
`list_resources` LDP container GET (lists `ldp:contains`)
`read_resource` GET resource (any content type, including JSON-LD)
`write_resource` PUT / POST resource
`subscribe` Existing JSS WebSocket notifications wrapped as MCP events

Deferred: `query` (SPARQL or JSON-LD frame), `delete_resource`, `patch_resource`.

Auth

Reuse existing JSS layers — no new auth code:

  • WebID-OIDC + DPoP — for Claude Desktop and other browser-OIDC agents
  • NIP-98 — for Nostr-native agents
  • Bearer token — for headless agents / CI

The MCP server enforces WAC the same way every other JSS endpoint does. `acl:agent did:agent:claude` can grant a specific agent specific resources. `acl:agentClass` with a new `acl:Agent` term could grant agent-class-wide access.

Wire format

MCP supports stdio, HTTP+SSE, and WebSocket transports. HTTP+SSE is the natural fit — JSS already serves HTTP, and SSE composes with the existing notification infrastructure. Stdio is irrelevant (JSS is a long-running daemon).

Scope estimate

~500 lines. The protocol is thin, JSS already has all the backend primitives. The work is an adapter layer:

  • MCP handshake (initialize, list_tools, capabilities)
  • Tool dispatch (route MCP tool calls to existing JSS internals)
  • SSE event stream wrapping the WS notification pipe

Why it's distinctive

  • No other Solid server has this
  • No other MCP server has WAC, WebID, or sovereign storage
  • The combination is what's unique — Solid's strength (data sovereignty) becomes MCP's missing piece

Acceptance

  • `jss start --mcp` exposes `/mcp` endpoint
  • Claude Desktop can register the endpoint as an MCP server and read/write a resource
  • WAC applies: agent without `acl:Write` gets 403 on `write_resource`
  • `subscribe` emits events on resource changes via SSE
  • Tested end-to-end with at least one external MCP-compatible client
  • `docs/mcp.md` covers wiring up Claude Desktop / generic MCP clients

Out of scope (for v0.0.200)

  • `query` tool (deferred to v0.0.201+)
  • Agent-class WAC term (`acl:Agent`) — proposed but not blocking
  • MCP "prompts" or "resources" surface (we expose tools first)
  • Local LLM hosting / inference inside JSS

Activity

  1. melvincarvalho commented on May 18, 2026

    ContributorAuthor

    Charlie as the use case — MCP as the first-class API for deployed bots

    Reframing this issue so the user-visible payoff comes first, with MCP as the substrate that makes it possible.

    The thesis

    Pods host bots. Bots speak MCP. The pod is the bot's world.

    Once a pod runs MCP, any deployed bot — Charlie, a forum-moderator, a calendar agent, a research assistant — gets a uniform way to:

    • Read its instructions from the pod. A SKILL.md (Anthropic skill format) at e.g. /private/bots/charlie/SKILL.md is the bot's system prompt + tool description, loaded fresh from the pod every session. Owners edit a markdown file; the bot picks up the change. No re-deploy.
    • Discover its tools by URL. Pod resources are the toolbox. /public/contacts/, /private/notes/, /public/apps/forum/ — each container/document is reachable via MCP read_resource/write_resource/list_resources. The bot doesn't need a custom adapter per data type; everything's JSON-LD over HTTP.
    • Find its own docs. Bot docs live in the pod (SKILL.md, /private/bots/charlie/manual.md, linked apps' docs/). MCP list_resources + read_resource is how the bot learns its environment.
    • Talk to other bots. Charlie on pod A can call MCP tools exposed by Charlie on pod B, gated by WAC. Bot-to-bot federation falls out for free — same protocol, same identity model (did:nostr: or WebID), same ACL primitives. No new wire.
    • Operate in agent-native tooling. Claude Desktop / Cursor / custom agents register the pod's MCP endpoint the same way they register any other MCP server. The user's pod becomes a tool surface for any agent they trust.

    What Charlie looks like

    <pod>/private/bots/charlie/
      SKILL.md              # "You are Charlie, a helper bot. Your owner is <webid>.
                            #  When asked X, do Y. Tools are at /mcp."
      config.jsonld         # bot identity (did:nostr:...), model preference, etc.
      memory/               # conversation history, learned facts
      
    <pod>/public/apps/charlie/   # the user-facing chat UI (a solid-apps repo)
    

    Owner opens /public/apps/charlie/, logs in via xlogin, chats. The UI POSTs prompts to the LLM (BYO key) which is configured to use the pod's /mcp endpoint as its tool surface. Every action Charlie takes is WAC-gated against Charlie's did:nostr: agent identity — owner can revoke /private/finance/ access with one ACL edit and Charlie no longer sees it.

    Why this framing matters

    The boring framing: "JSS speaks MCP." Capability-equivalent but framed at the wrong level — MCP is plumbing, no one buys plumbing.

    The Charlie framing: "JSS 0.0.200: your pod now has bots." MCP is the footnote that makes it portable. Same bot code works on every JSS pod because every JSS pod speaks the same protocol — that's the network effect.

    It also makes JSS the first pod server where agent identity is a first-class WAC subject. Granting an agent access to a resource is the same operation as granting a human access to a resource. That's a genuinely novel primitive — and it's only possible because the Solid stack already has identity, ACL, and resource-orientation. MCP just exposes it to agents.

    Updated acceptance criteria

    • `jss start --mcp` exposes `/mcp` (the substrate)
    • `solid-apps/charlie` ships a reference bot that uses the local MCP endpoint
    • Bot identity is a `did:nostr:` (or WebID) WAC subject; owner controls access via ordinary ACL edits
    • Charlie reads its system prompt from a pod-resident `SKILL.md`
    • Two Charlies on different pods can call each other's MCP tools (proving bot-to-bot)
    • Claude Desktop registers a JSS pod as an MCP server and successfully reads/writes resources

    Inspiration: TimBL on agent-pod interaction — https://www.w3.org/DesignIssues/Works.html

  2. melvincarvalho commented on May 18, 2026

    ContributorAuthor

    Cross-reference: #205 already raised this in March under "Agent Charlie — AI assistant with Solid pod data access," citing the same TimBL link. Same vision, different architecture.

    #205's shape (server-owned agent):

    • `/agent/` endpoint inside JSS
    • JSS holds LLM API keys / makes the LLM call
    • Token-metered per query (pay-as-you-go)
    • Pod data serialised into LLM context server-side

    This issue's shape (pod as tool surface):

    • `/mcp` endpoint inside JSS
    • LLM client lives anywhere (Claude Desktop, Cursor, `solid-apps/charlie` running in the browser)
    • Pod is a tool surface — agent calls `read_resource` / `write_resource` over MCP
    • No vendor lock-in, no server-held API keys, no token metering coupling

    Both compose. `/mcp` is the lower primitive; `/agent/` (#205) could be built on top of it later as a JSS-hosted convenience for users who don't want to run their own LLM client.

    Proposal: keep #205 open as the user-facing "Charlie as a hosted service" follow-on. Land #490's `--mcp` substrate first because it's the foundation everything else builds on.

  3. melvincarvalho commented on May 18, 2026

    ContributorAuthor

    Folding SKILL.md into the MCP design (extensible + future-proofed)

    Making skill discovery a first-class concern of the MCP server, not an afterthought a bot has to figure out.

    Convention

    Skills live at well-known paths the MCP server knows about:

    Path Scope
    `/SKILL.md` Pod-wide. Owner's instructions to any bot operating on this pod.
    `/public/apps//SKILL.md` Per-app. Each installed Solid app may ship a SKILL.md describing how bots should interact with it.
    `/private/bots//SKILL.md` Per-bot. The bot's own system prompt + scope + tool description.

    This is the minimum convention. The MCP server walks these paths and exposes them via dedicated tools — the bot doesn't have to know the convention to find skills, the MCP server does that for it.

    Format: SKILL.md vs SKILL.jsonld (future-proofing)

    Both are first-class:

    • SKILL.md — Anthropic's skill format. Markdown with optional YAML frontmatter. Today's bots understand this.
    • SKILL.jsonld — JSON-LD typed skill descriptor. `@type: skill:Skill` with `skill:format`, `skill:source`, `skill:scope`, etc. Lets new skill vocabularies extend without breaking discovery.

    The MCP server returns both when listing. Each entry declares its format:

    ```json
    {
    "@id": "/private/bots/charlie/SKILL.md",
    "skill:format": "anthropic.skill.v1",
    "skill:scope": ["read_resource", "write_resource", "subscribe"],
    "schema:name": "Charlie"
    }
    ```

    New formats (`openai.tool.v1`, `w3c.future.skill.v2`, …) plug in by declaring a new `skill:format` value. Existing bots that don't recognise a format skip it gracefully. The discovery channel stays stable; the payload evolves.

    New MCP tools (first-class, sit alongside CRUD)

    Tool Returns
    `list_skills` Index of all SKILL files the server finds, with format + scope + source path
    `get_skill` The skill body (markdown or JSON-LD) for a specific entry
    `get_pod_skill` Convenience: returns the pod-wide `/SKILL.md` if it exists

    Crucially, these are additions on top of regular `read_resource` — a bot that doesn't speak the skill vocabulary can still find SKILL.md via plain CRUD. But for skill-aware bots, the dedicated tools give a typed, structured way in.

    Optional index for performance (`.well-known/skills.jsonld`)

    Walking conventions on every `list_skills` call is fine at small scale. If a pod has hundreds of skills, the MCP server can opportunistically cache results in `/.well-known/skills.jsonld` — a JSON-LD index of every skill on the pod. Same data, faster lookup. The format:

    ```json
    {
    "@context": { "skill": "urn:skill:", "schema": "https://schema.org/" },
    "@type": "skill:SkillIndex",
    "skill:items": [ /* … */ ]
    }
    ```

    This is an optimisation, not a requirement. Bots use `list_skills` and don't care which path the server took to answer.

    What this gives us

    • Findability: any MCP-speaking bot can ask "what skills does this pod offer?" without prior knowledge of paths or filenames
    • Extensibility: new skill formats plug in via the `skill:format` declaration without changing the tool surface
    • Future-proofing: JSON-LD vocabulary means new properties (capabilities, prerequisites, model requirements, signatures, …) can be added incrementally
    • Composability: a bot can compose multiple SKILL files — pod-wide + per-app — for the full picture

    Tool count update

    Adding skills to the surface brings the total to ~20 tools across CRUD / ACL / discovery / docs / skills / subscribe / federation. Still a single-PR sized substrate.

  4. added a commit that references this issue on May 18, 2026
    2cb34c6
  5. melvincarvalho commented on May 18, 2026

    ContributorAuthor

    v0.0.200 shipped the substrate. Three follow-up issues filed for the Tier-2 gaps surfaced by the live-fire smoke (the "hour with jspod --mcp" journo session):

    All three are MCP-server-level features and live in this repo. The jspod/nosdav-server wrappers just need flag passthrough when JSS gains the next set of MCP-related flags (none anticipated for these three — they're new tools, not new server flags).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL