🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

saagar-portfolio-mcp

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

saagar-portfolio-mcp

Agent-native MCP server over the public saagarpatel.dev corpus — read-only, stateless.

latest
Source
npmnpm
Version
0.1.0
Version published
Maintainers
1
Created
Source

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, 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 — 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
get_operant_resultsPublic, sanitized OPERANT calibration results (per-model OCS)

Documents are also exposed as Resources (portfolio://essays/{slug}, book/{slug}, 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 corpus is ~50 small 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 6 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 (+ OPERANT) into corpus.generated.ts
  probe-mcp.mjs        probes an MCP HTTP endpoint: initialize, tools/list, search, OPERANT
  smoke-mcp.sh        boots wrangler dev, drives the MCP protocol under workerd
  audit-mcp.sh        connected MCPAudit scan of this server (dogfood)
test/                 vitest: bm25, tools, full-protocol server tests

Develop

npm install
npm run build:corpus          # bake from ../portfolio-index (or --url=https://saagarpatel.dev)
npm run typecheck
npm test
npm run dev                   # wrangler dev -> http://localhost:8787/mcp
bash scripts/smoke-mcp.sh     # end-to-end MCP smoke under the real workerd runtime
npm run probe:mcp             # live Worker probe, or set PORTFOLIO_MCP_ENDPOINT

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. Zero dependencies (Node built-in crypto):

node scripts/sign-manifest.mjs gen-key   # one-time; private key -> .signing/ (gitignored, NEVER commit)
node scripts/sign-manifest.mjs sign      # writes <manifest>.sig + publishes mcp-ed25519.pub
node scripts/sign-manifest.mjs verify    # checks manifest bytes against .sig + public key

Defaults target the sibling portfolio-index manifest (override 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

  • Built + verified: Layers 0–2. Shared core + 6 tools + Resources + 2 prompts + get_operant_results. typecheck clean; 26 tests pass (incl. full MCP protocol via the fetch handler); wrangler dev workerd smoke green; live Worker probe green; public discovery advertises mcp.saagarpatel.dev with a valid Ed25519-signed manifest.
  • Gated / next: publish the stdio package (npm publish, after removing "private": true by explicit operator approval only), glama.ai registry listing, and continued signed-manifest readback checks after website manifest changes.

Keywords

mcp

FAQs

Package last updated on 28 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts