mcpField
S
saagarpatel.dev Portfolio

saagarpatel.dev Portfolio

Remote
saagarpatel.devMemory & Knowledge0Updated 2w ago

About saagarpatel.dev Portfolio

saagarpatel.dev Portfolio is a read-only MCP server for AI agents to query Saagar’s writing, projects, public-safe repository profiles, and benchmark results. It bundles a static corpus and offers both HTTP and stdio transports.

Key features

  1. 01BM25 search across the corpus
  2. 02Retrieve full documents by ID
  3. 03Browse projects and repository profiles
  4. 04Query OPERANT calibration results
  5. 05Expose document resources and prompts

Use cases

  1. 01Find Saagar’s essays or notes
  2. 02Review public projects and repository profiles
  3. 03Look up public model calibration results

MCP support

It exposes eight read-only tools, document resources, and two prompts over streamable HTTP or stdio.

Configuration

Remote servers need no local install. Pick your client, then copy the config or install in one click.

Endpointhttps://mcp.saagarpatel.dev/mcp
Copy install command
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.

Packages
npmsaagar-portfolio-mcp0.1.0

Tools

8
ParameterTypeRequiredDescription
limitintegerNoMax results (default 10)
querystringYesSearch terms
sectionenumNoRestrict to one content typeessay | chapter | note | page

Details

From the project README

portfolio-mcp

Glama MCP server

The agent-native layer of saagarpatel.dev: a Model Context Protocol server that lets any AI agent query Saagar's writing, projects, public-safe repo profiles, and benchmark results directly, instead of scraping HTML.

Read-only. Stateless. Public. No auth, no tracking, no database, no runtime egress.

How it fits

The website stays a pure static site. This server is a sibling, not a backend bolted onto it:

  • Layer 0 (in the portfolio-index repo): the build emits a static machine corpus — corpus-index.json, per-document corpus/<id>.json, and .well-known/mcp.json — plus public-safe repo profile artifacts when present, served alongside the HTML. Already public.
  • Layer 1 (this repo, src/index.ts): a stateless Cloudflare Worker that bakes the Layer 0 corpus into its bundle and serves it over MCP (streamable HTTP, the WebStandardStreamableHTTPServerTransport). Zero runtime fetches.
  • Layer 2 (this repo, src/stdio.ts): the same server over stdio, for running locally via npx saagar-portfolio-mcp. Identical tool/resource/prompt surface.

The shared core (src/server.ts) is transport-agnostic; both layers wrap it.

Tool surface

All read-only (readOnlyHint: true). No tool takes a URL or filesystem path (no SSRF / exfil surface).

ToolPurpose
searchBM25 over the whole corpus; optional section filter, limit
get_documentFull Markdown of one document by id
list_corpusThe table of contents; optional type filter
get_profileThe "who is this" card (about / now / uses)
list_projectsCurated public-safe projects + anonymized aggregates
list_repo_profilesPublic-safe repo profile index with freshness and proof counts
get_repo_profileOne repo answering profile by the repoId argument
get_operant_resultsPublic, sanitized OPERANT calibration results (per-model OCS)

Documents are also exposed as Resources (portfolio://essays/{slug}, portfolio://book/{slug}, portfolio://notes/{slug}, portfolio://profile), and there are two Prompts: introduce_saagar and summarize_writing_on (grounded in a live search).

Retrieval

BM25 over a baked index (no embeddings in v1 — the committed corpus contains 166 docs and the calling LLM supplies the semantics). Titles are boosted. Embeddings are a measured Phase 3 upgrade, added only if retrieval quality proves insufficient.

Layout

src/
  types.ts            corpus + projects + operant shapes
  bm25.ts             dependency-free BM25 + snippet (pure)
  tools.ts            createTools(corpus) -> the 8 tools (pure, injectable)
  corpus.ts           loads the baked corpus + accessors
  corpus.generated.ts AUTO-GENERATED by build:corpus
  server.ts           buildServer(): shared MCP core (tools + resources + prompts)
  index.ts            Cloudflare Worker transport (streamable HTTP)
  stdio.ts            Layer 2 stdio transport (the npx CLI)
scripts/
	build-corpus.mjs    bakes Layer 0 and local OPERANT inputs into corpus.generated.ts
  probe-mcp.mjs        probes an MCP HTTP endpoint (saagar-mcp-kit driver + domain calls)
  audit-mcp.sh        connected MCPAudit scan of this server (dogfood)
test/                 vitest: bm25, tools, full-protocol server tests

Develop

From the repository root, use the pinned Node and npm versions from .node-version and package.json. The checked-in public-safe corpus is enough for routine checks; no sibling checkout, local portfolio import, signing key, or Cloudflare credentials are needed.

npm ci
make check

make check runs lint, format validation, typecheck, tests, the stdio build and protocol test, smoke, parity, and a package-content check. See CI for the same aggregate gate. npm run dev starts the local Worker.

npm run build:corpus regenerates source from a sibling checkout or an explicit network URL; URL-mode builds omit OPERANT because its build inputs are not published. Corpus generation is not required for ordinary fixture verification. npm run probe:mcp targets the live Worker by default, and the connected audit starts a local Worker and invokes the separately installed mcp-audit CLI. Keep those separate from local gates; deployment and signing remain operator-gated as described below.

Inspect either transport with the MCP inspector:

npx @modelcontextprotocol/inspector http://localhost:8787/mcp   # Layer 1 (HTTP)
npx @modelcontextprotocol/inspector node dist/stdio.js          # Layer 2 (stdio, after build:cli)

Deploy (Layer 1)

npm run build:corpus && npm run deploy   # wrangler deploy
npm run probe:mcp                        # post-deploy live MCP readback

Operator-gated (needs Cloudflare auth). v1 still deploys to the default portfolio-mcp.<account>.workers.dev URL, and npm run probe:mcp uses that stable Worker URL by default. Public discovery now advertises the verified custom endpoint https://mcp.saagarpatel.dev/mcp; after any deploy, verify both the Worker and the website manifest/readback path before changing .well-known/mcp.json.

wrangler.jsonc pins workers_dev: true so the public Worker URL stays live during any future custom-domain experiments; do not remove it unless the website manifest has already moved to a verified replacement endpoint.

Publish (Layer 2)

npm run build:corpus && npm run build:cli   # -> dist/stdio.js
npm login && npm publish                     # public package: saagar-portfolio-mcp

Once published, anyone can run it locally with npx saagar-portfolio-mcp (no install).

Sign the manifest (optional trust signal)

Ed25519-sign .well-known/mcp.json so an agent or registry can verify it authentically comes from Saagar (via saagar-mcp-kit's signing CLI, Node built-in crypto):

npx mcp-kit-sign gen-key --manifest=../portfolio-index/.well-known/mcp.json  # one-time; private key -> .signing/ (gitignored, NEVER commit)
npm run sign                             # writes <manifest>.sig + publishes mcp-ed25519.pub
npm run sign:verify                      # checks manifest bytes against .sig + public key

Override paths with --manifest=/--key=/--pub=/--sig=. Commit the .sig + mcp-ed25519.pub (never the private key) into portfolio-index next to the manifest, then redeploy the site. Re-run sign whenever the manifest changes (it signs the exact served bytes).

Audit posture

Designed to pass MCPAudit / mcp-trust (Saagar's own tools): only the inbound MCP transport, no shell_execution / file_access / destructive / exfiltration, and no caller-controlled egress (the corpus is baked). All tools are annotated read-only with plain, non-injectable descriptions. bash scripts/audit-mcp.sh runs a connected scan.

Dogfooding this server surfaced a substring-matching false-positive bug in MCPAudit (it matched port inside portfolio://); that fix lives in the MCPAudit repo and cut this server's findings 62 → 14. The genuine tool surface scans clean (high_risk_servers: 0).

Status

Stack

Node.js 24.21.0, npm 12.2.0, TypeScript, Cloudflare Workers, and the MCP SDK.

Known risks

URL-mode corpus builds omit OPERANT, whose inputs are only available to local corpus builds. Worker deployment and package publication are not part of local verification.

Next steps

Keep the published MCP endpoint and signed discovery manifest in sync when an operator authorizes a deployment. Registry publication remains a separate, explicitly authorized release action.

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.