solid-mcp
Provides tools for reading, writing, searching, and managing resources in Solid pods, enabling AI models to interact with decentralized data storage.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@solid-mcpshow me the contents of my /notes folder"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@jeswr/solid-mcp
A Model Context Protocol (MCP) server that exposes a Solid pod to MCP clients (Claude Desktop and other MCP hosts) as Resources and Tools.
Pod URLs map 1:1 to MCP resources, and four pod-scope-guarded tools —
solid_list, solid_read, solid_search, solid_write — let an agent browse,
read, search, and (opt-in) write pod data over an injectable authenticated Solid
fetch. The server holds no bespoke crypto: you supply the authenticated
(Solid-OIDC / DPoP) fetch, so token handling stays in vetted upstream libraries.
⚠️ Experimental, AI-agent-generated. Part of the
@jeswrSolid app suite. Read-only by default; review before granting write access to a real pod.
What you get
Resources — every in-pod URL is an MCP resource (the resource
uriis the pod url). Containers are returned as a JSON listing, RDF resources as Turtle, and anything else as text or base64 bytes. Alistcallback browses the pod root.Tools
Tool
Args
Semantics
solid_list{ container }List a container's typed children (
url,name,isContainer,type,mimeType,size,modified).readOnlyHint.solid_read{ url }Read a resource — Turtle for RDF, text or base64 otherwise. Fails closed (401/403).
readOnlyHint.solid_search{ query, scope? }Client-side search: best-effort Type-Index discovery + a bounded recursive container scan, matching url/name and RDF literal values. No server FTS.
readOnlyHint.solid_write{ url, content, contentType }PUT a resource. Disabled unless
readOnly:false.destructiveHint.
Related MCP server: Forgetful
Install
npm install github:jeswr/solid-mcp#mainThe package commits a self-contained dist/ (with @jeswr/fetch-rdf inlined via
esbuild), so it installs and imports directly from a GitHub branch under
ignore-scripts=true with no build step. npm publish is a deferred migration
(see Roadmap).
Auth model (the seam)
The server takes an injectable authenticated fetch and a podRoot:
import { createSolidMcpServer } from "@jeswr/solid-mcp";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = createSolidMcpServer({
fetch: session.fetch, // an authenticated Solid-OIDC / DPoP fetch you provide
podRoot: "https://alice.pod.example/",
webId: "https://alice.pod.example/profile/card#me", // optional, enables Type-Index search
readOnly: true, // DEFAULT — set false to enable solid_write
});
await server.connect(new StdioServerTransport());SolidMcpConfig:
interface SolidMcpConfig {
fetch: typeof fetch; // authenticated Solid fetch (server holds no credentials)
podRoot: string; // absolute http(s) container URL ending in "/"
webId?: string; // optional, for Type-Index-driven search
readOnly?: boolean; // default true (writes disabled)
}Read-only by default; writes are opt-in
solid_write is disabled unless you create the server with readOnly: false.
When read-only, the tool returns an isError result (it never throws out of the
handler), so a client gets a clear "write disabled" message rather than a crash.
Pod-scope / SSRF guard
Every Resource read and every Tool call is confined to podRoot. A URL is rejected
(with a pod-scope violation error) unless its canonical form is within the pod
root — this is the SSRF / capability boundary that stops an agent from using a tool
to reach an arbitrary origin or to escape the pod root via .. path traversal. The
check itself is @jeswr/guarded-fetch's
consolidated pod-scope guard (assertWithinPodScope / createPodScopedFetch): a
segment-boundary same-origin path-prefix check on the WHATWG-normalised, canonical
URL (so encoded and dot-segment escapes are resolved away first, and every redirect
hop is re-checked, not just the initial URL) — wrapped here so its errors keep this
package's pod-scope violation: message prefix.
CLI (M1)
The solid-mcp bin reads configuration from the environment and connects over
stdio:
Env var | Required | Notes |
| yes | absolute http(s) container URL ending in |
| no | enables Type-Index search |
| no | default |
| no | reserved for M2 |
M1 auth scope: a bundled headless client-credentials login is not part of
M1. If the client-credentials env vars are present, the CLI prints a clear message
and falls back to an unauthenticated globalThis.fetch (works for public
resources; protected resources fail closed). For an authenticated session today,
import createSolidMcpServer programmatically and pass your own authenticated
fetch. Bundled headless login is a Roadmap (M2) item.
Claude Desktop config
Add to claude_desktop_config.json (mcpServers):
{
"mcpServers": {
"solid": {
"command": "npx",
"args": ["solid-mcp"],
"env": {
"SOLID_MCP_POD_ROOT": "https://alice.pod.example/",
"SOLID_MCP_WEBID": "https://alice.pod.example/profile/card#me",
"SOLID_MCP_READONLY": "true"
}
}
}
}RDF discipline
The package parses RDF only via @jeswr/fetch-rdf
@solid/object(container listings viaContainerDataset), and serialises withn3.Writer. It never hand-builds or hand-parses RDF.
Anti-silo / typed data
Typed pod data is read through the suite's shared RDF shapes (Activity Streams 2.0,
schema.org, @jeswr/solid-task-model,
…), so an agent reads the same shapes the suite apps write — a task created in
solid-issues, a contact in the Pod Manager, a bookmark in a pod-app are all the same
graph. This is the integration-targets contract: agent access and app access share
one data model rather than per-app silos.
Public API
import {
createSolidMcpServer,
type SolidMcpConfig,
// pod operations (programmatic / testing):
listContainer, readResource, readRdf, search, writeResource,
// auth helpers + scope guard:
normalizePodRoot, requirePodScopedUrl, podScopedUrlOrUndefined, writesEnabled,
// types:
type PodChild, type ReadResult, type ReadRdfResult, type SearchMatch, type SearchOptions,
} from "@jeswr/solid-mcp";The authoritative, diffable snapshot of the whole public surface lives in
etc/solid-mcp.api.md (generated by
API Extractor). npm run api:check fails on any
drift and runs in CI; after an intended API change, regenerate + commit the
report with npm run api:report.
Roadmap (M2)
Streamable-HTTP transport (in addition to stdio).
Per-platform client configs (Cline, Open WebUI, LibreChat MCP server, OpenClaw, …).
Bundled headless client-credentials login so the CLI can run authenticated without a programmatic embed.
Deeper typed-data tools (task / contact / bookmark / calendar shape-aware read + write) over
@jeswr/solid-task-modeland the suite shapes.
Development
npm run lint # biome + check:lockfile-transport
npm run typecheck # tsc --noEmit
npm test # vitest
npm run build # tsc → dist/
npm run check:dist # guard the committed dist/ against src/ drift
npm run check:lockfile-transport # guard package-lock.json against the SSH git transport (#78: npm install rewrites @jeswr github: deps to git+ssh, breaking npm ci)
npm run fix:lockfile-transport # the FIX half of the #78 guard — normalizes an SSH-rewritten lockfile back to HTTPS; run after any npm install/update, before committingAny npm install / npm update re-triggers the #78 rewrite (npm recomputes every git-dependency
resolved URL as SSH on ANY lockfile regen, even one triggered by an unrelated bump — this is why
it recurs on Dependabot PRs here even when the bump is unrelated to @jeswr/fetch-rdf). A
repo-local git config insteadOf does not prevent it (it only changes what the git binary
does when actually invoked, not what npm writes into the lockfile). npm run fix:lockfile-transport
is the durable fix: run it after any install/update, then check:lockfile-transport (or lint)
passes and the lockfile stays committable over HTTPS. Dependabot PRs are additionally auto-fixed by
.github/workflows/normalize-dependabot-lockfile.yml,
which pushes a normalizing commit onto the PR branch if Dependabot's own regenerated lockfile needs it.
License
MIT © Jesse Wright
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jeswr/solid-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server