Add HTTP transport + bearer auth + Docker/Compose for self-hosting
Restore the Streamable HTTP transport (kept alongside stdio) guarded by a shared bearer token (MCP_AUTH_TOKEN, constant-time check; /health stays open for probes). Add mcp-server/Dockerfile, root docker-compose.yml and .dockerignore to run it as a container on the Gitea box. README documents hosting + connecting Claude Desktop via mcp-remote. Verified HTTP 401-without/200-with-token locally; npm ci validated for the image build. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,9 +6,16 @@ reuses the same core client as the skill
|
||||
(`../.claude/skills/sharepoint-lists/scripts/lib/graph.mjs`) — one source of
|
||||
truth for the Graph logic.
|
||||
|
||||
**Transport: stdio only.** This server is meant to run locally and be launched
|
||||
by a local Claude app (Claude Desktop / Claude Code / Cowork). It has no network
|
||||
listener by design, so it cannot be reached remotely or from web chat.
|
||||
## Transports
|
||||
|
||||
| Transport | Use | How the client connects |
|
||||
|---|---|---|
|
||||
| **stdio** (default) | local Claude apps on the same machine | the app launches `node index.mjs` |
|
||||
| **Streamable HTTP** (`--http`) | hosted in a container, reached over the network | client → HTTP `POST /mcp` (bearer token) |
|
||||
|
||||
stdio is for same-machine use. To run as a hosted service (e.g. Docker on
|
||||
another box), use the HTTP transport — a stdio client can't attach to a process
|
||||
on a different machine.
|
||||
|
||||
## Tools
|
||||
|
||||
@@ -25,25 +32,75 @@ listener by design, so it cannot be reached remotely or from web chat.
|
||||
|
||||
Set `SP_READONLY=true` to register only the read tools.
|
||||
|
||||
## Setup
|
||||
## Configuration
|
||||
|
||||
Credentials come from the environment or `mcp-server/.env` (git-ignored). See
|
||||
`.env.example` and `../.claude/skills/sharepoint-lists/references/setup.md`.
|
||||
|
||||
| Var | Required | Notes |
|
||||
|---|---|---|
|
||||
| `SP_TENANT_ID` / `SP_CLIENT_ID` / `SP_CLIENT_SECRET` | yes | app registration |
|
||||
| `SP_SITE_URL` | no | default site so tools can omit `site` |
|
||||
| `SP_READONLY` | no | `true` → read-only tool set |
|
||||
| `MCP_AUTH_TOKEN` | HTTP only | shared bearer token required on `/mcp`; empty = unauthenticated |
|
||||
| `PORT` | HTTP only | listen port (default 3838) |
|
||||
|
||||
## Run locally
|
||||
|
||||
```bash
|
||||
cd mcp-server
|
||||
npm install
|
||||
cp .env.example .env # then fill in SP_TENANT_ID / SP_CLIENT_ID / SP_CLIENT_SECRET
|
||||
cp .env.example .env # fill in credentials
|
||||
npm start # stdio
|
||||
npm run start:http # Streamable HTTP on :3838
|
||||
```
|
||||
|
||||
Credentials and the optional `SP_SITE_URL` default are documented in
|
||||
`../.claude/skills/sharepoint-lists/references/setup.md`. The server loads
|
||||
`mcp-server/.env` automatically (by its own path), so the client app does not
|
||||
need to pass credentials.
|
||||
## Run as a container (Docker Compose)
|
||||
|
||||
## Connect it
|
||||
From the **repo root** (the build context needs the shared `graph.mjs`):
|
||||
|
||||
### Claude Desktop (primary)
|
||||
Add an entry to `claude_desktop_config.json`
|
||||
(`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS),
|
||||
then fully quit and reopen Claude Desktop:
|
||||
```bash
|
||||
# 1. Create mcp-server/.env with SP_* creds + a token:
|
||||
# echo "MCP_AUTH_TOKEN=$(openssl rand -hex 32)" >> mcp-server/.env
|
||||
# 2. Build + start:
|
||||
docker compose up -d --build
|
||||
# 3. Check:
|
||||
curl -s http://localhost:3838/health # {"ok":true,...}
|
||||
```
|
||||
|
||||
The service restarts automatically and has a healthcheck. The port is published
|
||||
on all interfaces; restrict it in `docker-compose.yml` (or via firewall) and rely
|
||||
on `MCP_AUTH_TOKEN` for auth.
|
||||
|
||||
## Connect a client
|
||||
|
||||
### Claude Desktop → remote HTTP server (via `mcp-remote`)
|
||||
|
||||
Desktop speaks stdio, so bridge to the remote HTTP server with `mcp-remote` in
|
||||
`~/Library/Application Support/Claude/claude_desktop_config.json`, then restart
|
||||
Desktop:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"sharepoint-lists": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y", "mcp-remote",
|
||||
"http://192.168.101.12:3838/mcp",
|
||||
"--allow-http",
|
||||
"--header", "Authorization: Bearer ${SP_MCP_TOKEN}"
|
||||
],
|
||||
"env": { "SP_MCP_TOKEN": "<your MCP_AUTH_TOKEN>" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`--allow-http` permits the plain-HTTP LAN URL (no TLS). The token must match the
|
||||
container's `MCP_AUTH_TOKEN`.
|
||||
|
||||
### Claude Desktop → local stdio (no container)
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -56,16 +113,15 @@ then fully quit and reopen Claude Desktop:
|
||||
}
|
||||
```
|
||||
|
||||
Use the absolute path to `node` (Claude Desktop doesn't inherit your shell PATH).
|
||||
|
||||
### Claude Code
|
||||
The project `.mcp.json` at the repo root already registers this server; from the
|
||||
repo root, Claude Code will offer to start it. Ensure `mcp-server/.env` is filled in.
|
||||
|
||||
## Notes
|
||||
The repo-root `.mcp.json` registers the local stdio server automatically.
|
||||
|
||||
- App-only auth means there is no per-user permission check — every caller acts
|
||||
as the app. Keeping this stdio-only (no network listener) is the intended
|
||||
containment.
|
||||
- Field formats for writes (person/lookup/choice/date) are documented in
|
||||
## Security notes
|
||||
|
||||
- App-only auth = the server has full access to the granted SharePoint sites
|
||||
with no per-user check. Anyone who can reach an unauthenticated `/mcp` has that
|
||||
access — always set `MCP_AUTH_TOKEN` for the HTTP transport.
|
||||
- `/health` is intentionally unauthenticated (liveness only; returns no data).
|
||||
- Field formats for writes (person/lookup/choice/date) are in
|
||||
`../.claude/skills/sharepoint-lists/references/graph-api.md`.
|
||||
|
||||
Reference in New Issue
Block a user