1. Conduid
  2. Files
  3. Mcp.js
MCP server · Files

Mcp.js

The MCP server I run every day: a rootless Podman sandbox, a persistent memory, a read only mailbox and a Moltbook account behind one endpoint. Built on the official TypeScript SDK v2, speaking the 2026-07-28 and 2025 protocol revisions.

Unclaimed files
34Low

Scored 5 days ago · breakdown

About Mcp.js

Mcp.js is an MCP server published by ServeurpersoCom in the Files category: the MCP server I run every day: a rootless Podman sandbox, a persistent memory, a read only mailbox and a Moltbook account behind one endpoint. Built on the official TypeScript SDK v2, speaking the 2026-07-28 and 2025 protocol revisions.

The repository has 5 stars and 0 forks, with the last commit 2 days ago. Recent commit activity is the strongest signal that reported issues will get attention.

Install

From source
git clone https://github.com/ServeurpersoCom/mcp.js

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Ask AI

✦

Ask AI about Mcp.js

Powered by Claude · Grounded in docs

I know everything about Mcp.js. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

Static checks derived from the repository yesterday. Heuristics on the source, not an audit.

  • ✓README presentThe repository ships documentation.
  • !License declaredNo license file. Legally you have no right to use it in a product.
  • !Tests presentNo tests found. Behaviour changes may go unnoticed between versions.
  • ✓Dependencies pinnedA lockfile pins dependency versions.
  • !No dynamic code executionSource scan found eval or shell execution. Review how tool inputs reach it before granting credentials.

1 check has not been run yet.

README

mcp.js

The Model Context Protocol server I run every day, published as it is. It serves a Podman sandbox, a persistent memory, a read only mailbox and an agent account on Moltbook to any MCP client, behind one endpoint. Built on the official TypeScript SDK v2 (@modelcontextprotocol/server), it speaks the 2026-07-28 revision of the protocol and the 2025 ones on the same endpoint, each client getting the newest revision it knows.

  • llama.cpp Svelte WebUI (native MCP client)
  • OpenAI ChatGPT (web, custom MCP server)
  • Anthropic Claude (web, custom MCP server)
  • any OpenAI compatible chat UI without an MCP client, through the bridge

Four servers, the two transports of the specification (stdio, Streamable HTTP), every server aggregated behind one endpoint, zero framework.

Rootless Podman

The sandbox runs under rootless Podman, the minimum I recommend to work cleanly with an AI: no daemon running as root, the container belongs to an unprivileged user, and the LLM reaches only what its volumes mount.

Install

Requires Node.js 20+, and Podman for the sandbox.

git clone https://github.com/ServeurpersoCom/mcp.js
cd mcp.js
npm install

Layout

config.json        transport, credentials, and the identity served
core/              protocol, auth, and the three transports
core/transports/   stdio, Streamable HTTP
servers/sandbox/   bash_tool, view, create_file, str_replace in a Podman container
servers/memory/    a persistent memory in plain files
servers/email/     a read only mailbox over IMAPS
servers/moltbook/  an agent account on Moltbook
mcp-bridge/        an OpenAI compatible proxy that runs the tools for MCP-less UIs
main.js            binds every server to one transport

Every server under servers/ is loaded at startup and their tools and prompts are served together, so a client connects once and sees them all. Adding a server means adding a directory under servers/, never touching core/. Removing one means deleting its directory.

Two servers exposing the same tool or prompt name is a naming mistake, and startup fails saying which name and which two servers. A tool declared in a tools.json without its handler fails startup the same way.

Every call passes the law of its tool schema in the core before the handler runs: an argument the schema does not declare, a required one missing, a string that is not one, or one shorter than its minLength, is refused by name (Unknown argument x, Path argument required), the same way for every tool of every server.

Run

node main.js stdio              # local MCP clients
node main.js streamable-http    # HTTP, port 8083

main.js takes a transport name, defaulting to stdio, and serves every server under servers/. The HTTP transport binds 127.0.0.1: put a reverse proxy in front to reach it from elsewhere.

Both transports build a fresh server for each exchange: one per HTTP request, one per stdio connection. The opening exchange selects the revision, 2026-07-28 for a client that probes with server/discover, a 2025 one for a client that sends initialize.

Config

Settings come from two files with disjoint roles. The root config.json holds the transport, the credentials and the identity the aggregate answers with. A servers/<name>/config.json holds that server's prompts and its own settings block, nothing else.

The published files hold every setting I run with, secrets aside: the authentication secrets are empty, so the server refuses to start until you set them, and the service credentials read changeme. example.com stands for my domain.

Root:

{
	"auth": {
		"mode": "oauth+static",
		"clientId": "",
		"clientSecret": "",
		"password": "",
		"staticToken": "",
		"storeDir": "data/oauth"
	},
	"streamable_http": { "host": "127.0.0.1", "port": 8083 },
	"mcp": {
		"serverName": "mcp-sandbox",
		"serverVersion": "1.0.0",
		"serverIcons": [
			{
				"src": "https://www.example.com/favicon-light.png",
				"mimeType": "image/png",
				"theme": "light"
			},
			{
				"src": "https://www.example.com/favicon-dark.png",
				"mimeType": "image/png",
				"theme": "dark"
			}
		]
	}
}

One endpoint serves them all, so ports and identity belong to the root and a server never carries them. prompts holds the templates a server publishes over prompts/list and prompts/get, gathered from every server. serverIcons is optional: it rides into the initialize response on a 2025 connection and into the _meta of every response on a 2026 one.

Auth

auth.mode selects the scheme for the HTTP transport. Stdio is never authenticated, it speaks over local pipes only.

Mode What is accepted
none No authentication, anyone who reaches the port
static A long lived bearer token
oauth The OAuth 2.1 flow only
oauth+static Either of the two

static suits clients that cannot run an interactive flow. Every request carries Authorization: Bearer <staticToken>, matched in constant time.

oauth implements the smallest surface an MCP connector needs: dynamic client registration, a consent form gated by password, and token exchange with PKCE S256. clientId, clientSecret, password and storeDir must all be set. Issued tokens are stored under storeDir, one file per token, so connectors stay authorized across restarts; rm -rf data/oauth revokes them all.

The server aborts at startup on an unknown mode, on static with an empty staticToken, or on an OAuth mode missing one of its settings.

Generate solid secrets:

openssl rand -hex 32

Discovery follows RFC 9728: a request without a valid token gets a 401 carrying a WWW-Authenticate header that points at /.well-known/oauth-protected-resource on the host the request came in on. Serve that document, and the matching /.well-known/oauth-authorization-server, from your reverse proxy.

Servers

sandbox

A Debian container, built from Containerfile and declared in pod.yaml, run rootless by podman.hostUser. Every command enters it through podman exec, the script on stdin, under a timeout.

Name Action
bash_tool Run a bash command: exit code, duration, a kill at the timeout named
view Read a file with line numbers and an optional range, list a directory, show an image
create_file Create a file, its directories made, empty or not
str_replace Replace a unique string in a file, its other bytes untouched

All four take a mandatory description argument so the LLM states its intent on every call.

The results read like the tools of the KiSS backend: the output then Exit code 0 (12 ms) or Killed after 300 s, numbered lines then 120 lines, a listing then 14 entries, 3 hidden, an image after Image image/png 4000x3000, 812345 bytes, sent as image/jpeg 1920x1440, 301234 bytes, Created x, 3 lines, 52 bytes, Replaced at line 42 of x, 10 -> 14 bytes. An image goes as KiSS sends it: a JPEG that fits as it is, a WebP as it is or not at all, an opaque PNG that fits as it is when lighter than its JPEG, any other as a JPEG within maxDimension pixels, turned upright and laid on white, through libvips (sharp); one over maxMegapixels is never decoded. Long output keeps its head and its tail with the hidden bytes counted. Files travel as base64 both ways, so a file in any encoding keeps its bytes, and a binary one is refused rather than mangled.

sandbox-manager.js drives the pod: build, destroy, start, stop, reset (a fresh container from the existing image), status, logs, shell. paths names the host directories mounted as /mnt/inputs, /mnt/workspace and /mnt/outputs.

memory

A memory that outlives conversations: one Markdown file per entry under data/<group>/<slug>.md, an index of one line per entry. memory_open reads the index or the named entries, memory_write creates or edits an entry anchored on a unique string, memory_drop removes one. Every write goes to a temporary file then a rename.

email

A read only mailbox: email_folders, email_list (one line per message, filtered on the server, paged by uid) and email_read (the headers a client shows, or the raw block for provenance questions). Every folder opens with EXAMINE, so nothing changes and reading leaves a message unseen.

{
	"host": "192.168.0.2",
	"port": 993,
	"servername": "mail.example.com",
	"ca": "mail.example.com.pem",
	"user": "pascal",
	"password": "changeme"
}

IMAPS only, the certificate always checked. servername is the name the certificate carries when host is an address. ca pins the certificate of a server that signs its own, Dovecot out of the box: copy its public half next to config.json under that name. Leave ca empty for a server whose certificate a public authority signed.

moltbook

An agent account on Moltbook, the social network for AI agents: home, feed, posts, comments, search, profiles, communities, votes, follows, and the verification challenge of each new post. The API key stays in config.json and never reaches the model.

Bridge

mcp-bridge/ serves /v1/chat/completions in front of an OpenAI compatible endpoint (proxy.apiUrl, llama-server for me) and runs the tool calls of the model itself, through the servers of this repository over stdio (or any MCP server over Streamable HTTP, given its url and headers), until the model answers. A chat UI without an MCP client gets the tools that way, each call and its result shown in the conversation.

node mcp-bridge/main.js

Client setup

llama.cpp Svelte WebUI (Streamable HTTP)

In the MCP settings panel, add the server:

  • URL: https://your-host/your-path
  • Header: Authorization: Bearer <staticToken>

OpenAI ChatGPT / Anthropic Claude web (Streamable HTTP)

Declare the server as a custom connector with its URL; the OAuth flow asks for password once.

Claude Desktop (stdio)

{
	"mcpServers": {
		"mcp": {
			"command": "node",
			"args": ["/path/to/mcp.js/main.js", "stdio"]
		}
	}
}

Status

Personal Swiss army knife. Evolves with my needs and what friends and users ask for. Issues and PRs welcome.

License

MIT.

README fetched from the repository yesterday. The original is authoritative.

Questions

About Mcp.js

How do I install Mcp.js?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is Mcp.js safe to use with an AI agent?

Its trust score is 34 out of 100 (low). It passes 2 of the 5 static security checks run so far; the failures are listed above. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Mcp.js still maintained?

Yes — the last commit was 2 days ago. The repository has 5 stars and 0 forks.