@vayacore/mcp
v0.1.2
Published
Model Context Protocol server for VayaPin — VayaPin pin resolution, Google Maps, and AfterShip tools over a single MCP namespace, future-proofed against the 128-tool client ceiling.
Downloads
312
Maintainers
Readme
@vayapin/mcp
Model Context Protocol server for VayaPin. Gives any MCP-compatible agent (Claude Desktop, Cursor, n8n, Zapier, …) VayaPin pin resolution plus Google Maps and AfterShip tools through a single tool namespace, authenticated with a Personal Access Token.
Status: v0.1.2 — published to the VayaPin Verdaccio registry (
@vayapin/mcponhttps://npm.vayapin.app), to public npmjs.com (@vayacore/mcp), and listed in the official MCP Registry asapp.vayapin/mcp. Ships 8 P1 tools over one MCP namespace:resolve_pin,preview_pin,confirm_pin(VayaPin),geocode,reverse_geocode,place_search,place_details(Google Maps via BYOK proxy), andtrack_package(AfterShip via BYOK proxy), plus asystem_healthsanity tool.
Install
@vayapin/mcp lives on the VayaPin registry (https://npm.vayapin.app) and is
public — no registry token needed. Map only the @vayapin scope to that
registry (its dependencies resolve from the public npm registry as usual). Add one
line to your .npmrc:
# .npmrc
@vayapin:registry=https://npm.vayapin.appThen install or run it like any package:
npm install @vayapin/mcp # into a project
npx -y @vayapin/mcp # no installDon't point your default registry at
npm.vayapin.app(npm install --registry https://npm.vayapin.app …). That routes this package's dependencies through the private registry too, which requires auth — only the@vayapinscope is public. The scoped.npmrcline above is the supported path. (AVAYAPIN_PATis still required at runtime to call the API — see below.)
Public distribution — @vayacore/mcp on npmjs.com
The package is also published to the public npm registry as
@vayacore/mcp — no .npmrc
scope line required. This is the canonical install for outside developers and the
artifact referenced by the official MCP registry.
npx -y @vayacore/mcp # no install, no .npmrc
npm install @vayacore/mcp # into a projectWhy two names? The
@vayapinnpm org was unavailable on npmjs.com, so the public scope is@vayacore(we own that org). The Verdaccio build keeps the internal@vayapin/mcpname. Both ship the identical build; pick whichever registry you already use. The two are kept in lockstep byscripts/publish-npmjs.sh.
Registry status: listed in the official
MCP Registry as app.vayapin/mcp
(domain-verified via vayapin.app). Submission flow + reproduction:
registry-submission.md.
Configure (MCP client config)
Add the @vayapin scope line to your ~/.npmrc (above) so npx can resolve the
package, then:
{
"mcpServers": {
"vayapin": {
"command": "npx",
"args": ["-y", "@vayapin/mcp"],
"env": {
"VAYAPIN_PAT": "vayapin_pat_..."
// optional: "VAYAPIN_MCP_SLICE": "<slice-name>"
// optional: "VAYAPIN_MCP_API_URL": "https://api.vayapin.app/api/v1"
}
}
}
}Generate a PAT on the VayaPin developer portal (POST /api/v1/auth/pat/request).
A 401 at runtime means the token is missing/expired/revoked — regenerate it.
Environment variables
| Var | Required | Default | Purpose |
|---|---|---|---|
| VAYAPIN_PAT | yes | — | Personal Access Token, sent as Authorization: Bearer. |
| VAYAPIN_MCP_SLICE | no | — | Name of a tool slice to expose (see ceiling lift). Unset → all tools. |
| VAYAPIN_MCP_API_URL | no | https://api.vayapin.app/api/v1 | Override for staging / self-host. |
The 128-tool ceiling lift — how it works, and why this shape
Many MCP clients inject the entire tool list into the model's system prompt on every turn. Past roughly 128 tools some clients (Claude Desktop, Cursor, Antigravity, certain OpenAI Responses deployments) silently drop the tool injection or burn a large slice of the context budget. A server that naively registers its whole catalog breaks for those clients as it grows.
This server is built so it never hits that wall, using a well-established pattern for large MCP catalogs. Two halves:
- Named tool-slice allowlist, selected by an env var (implemented here).
The full catalog is assembled internally, but an env var
(
VAYAPIN_MCP_SLICE) names a frozen allowlist of tool names, and the server exposes only that slice. This keeps the advertised tool count under any client's ceiling even as the catalog grows. - Atomic per-product packages (deferred; not needed at 8 tools). A future
option is to publish thin per-product wrapper packages — each registering only
its product's slice, with tool implementations shared from one core package. We
keep tools as data objects in group modules (
src/tools/*.ts) so this split is available later without rework.
Mechanism (this package)
- The server uses the low-level
ServerAPI with manualListTools/CallToolhandlers — not the high-levelserver.tool()helper. This is what lets us control exactly which tools are advertised. - Tools are plain data:
{ name, description, inputSchema, execute }(src/tools/types.ts). The MCP layer never seesexecute. - Tool groups register into a catalog via
register()/registerAll()(src/tools/registry.ts), wired from the append-only aggregation pointsrc/tools/index.ts. - At boot,
applySlice(catalog, VAYAPIN_MCP_SLICE)filters the catalog. BothListToolsandCallTooloperate on the filtered set, so a hidden tool is neither listed nor callable (calling one returnsMethodNotFound). - No slice set → full catalog. Unknown slice name → full catalog + a stderr warning (fail-open).
Note — no "meta-tool". We deliberately avoid a single runtime
list_toolsmeta-tool in favour of static named slices, which are simpler and fixed for the process lifetime. The ceiling-lift proof lives intests/registry.test.ts("ceiling lift" describe block): 200 stub tools + a 100-tool slice ⇒ exactly 100 exposed.
Adding a tool (for tasks 4.2 / 4.3 / 4.4)
- Create
src/tools/<group>.tsexporting<group>Tools(client): ToolDefinition[]. Copysrc/tools/system.tsas the template. - Add one import + one
registerAll(<group>Tools(client))line tosrc/tools/index.ts(append-only — the Orchestrator union-merges this file). - Add a test under
tests/.
Use snake_case tool names per VayaPin Product Definition v10 §6.1. Keep descriptions one line — they cost context on every client turn.
Layout
src/
server.ts entrypoint — boots Server over stdio, wires the registry
auth.ts PAT loading + Bearer header (no token logging, no auto-refresh)
api/client.ts undici HTTP client for api.vayapin.app/api/v1 (structured errors)
tools/
types.ts ToolDefinition + JSON-Schema types (spec §6.1)
registry.ts catalog + named-slice ceiling lift + ListTools/CallTool wiring
index.ts append-only tool aggregation point
system.ts system_health tool (canonical example group)
tests/ vitest: registry (ceiling), auth, api client, server bootDevelop
npm ci
npm run build # tsc → dist/
npm test # vitest
npm test -- registry # just the ceiling-lift proof