{"_id":"@bradsjm/signalwire-admin-mcp","name":"@bradsjm/signalwire-admin-mcp","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@bradsjm/signalwire-admin-mcp","version":"0.1.0","type":"module","publishConfig":{"access":"public"},"engines":{"node":">=20.19.0"},"bin":{"signalwire-admin-mcp":"dist/index.js"},"dependencies":{"@modelcontextprotocol/sdk":"1.29.0","@signalwire/sdk":"2.0.5","zod":"4.4.3"},"devDependencies":{"@types/node":"26.1.1","tsx":"4.23.1","typescript":"5.9.3","vitest":"4.1.10"},"scripts":{"build":"tsc -p tsconfig.build.json","postbuild":"node -e \"fs=require('fs');try{fs.chmodSync('dist/index.js',0o755)}catch{}\"","start":"node dist/index.js","dev":"tsx src/index.ts","typecheck":"tsc --noEmit","test":"pnpm build && vitest run"},"_nodeVersion":"22.23.1","_id":"@bradsjm/signalwire-admin-mcp@0.1.0","dist":{"integrity":"sha512-anj4qFoGU++UA/U9bKJYPGf+eQFSkoe5R8WoyUOb08YD8MQcgRauAdHk8E0udvxdNlvHgrJ9Iop4/Z0HoQ3/xg==","shasum":"0c6dc4b5ced51ff3a3d7e1b25cd3f3a24d56a1e5","tarball":"https://registry.npmjs.org/@bradsjm/signalwire-admin-mcp/-/signalwire-admin-mcp-0.1.0.tgz","fileCount":53,"unpackedSize":273760,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD6td8jm0P8No1cGoVyWQOS7sVr5YMwtIiFcOhqelR1BAIgTzPOmxK2KAIZ75hfVoyocp8oUp4wFd4XEanSwn+y3S0="}]},"_npmUser":{"name":"bradsjm","email":"jb@nrgup.net"},"directories":{},"maintainers":[{"name":"bradsjm","email":"jb@nrgup.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/signalwire-admin-mcp_0.1.0_1784773255541_0.1247008020265461"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-23T02:20:55.335Z","0.1.0":"2026-07-23T02:20:55.707Z","modified":"2026-07-23T02:20:55.911Z"},"maintainers":[{"name":"bradsjm","email":"jb@nrgup.net"}],"readme":"# signalwire-admin-mcp\n\nA [Model Context Protocol](https://modelcontextprotocol.io) server that exposes\nSignalWire administration operations to AI clients over stdio. It lets an MCP-aware\nassistant discover, configure, test, and diagnose SignalWire voice, messaging, and\nknowledge (Datasphere) resources through 15 tools backed by the official\n`@signalwire/sdk` REST client.\n\n- **Transport:** stdio\n- **Runtime:** Node.js ≥ 20.19.0 (ESM, TypeScript)\n- **SDK:** pinned to `@signalwire/sdk` 2.0.5\n\n## Tools\n\nThe server registers exactly these 15 tools. Mutating tools are gated behind\n`SIGNALWIRE_MCP_ALLOW_WRITES`; they return a `blocked` envelope when writes are off.\n\n| Tool | Category | Hint | What it does |\n| --- | --- | --- | --- |\n| `signalwire_find_resources` | Discovery | read-only | Discover phone numbers, Fabric resources, and Datasphere documents |\n| `signalwire_deploy_ai_agent` | Deployment | destructive/idempotent | Create or update a Fabric AI Agent, optionally bind a number |\n| `signalwire_deploy_call_flow_version` | Deployment | destructive | Publish a known version of an existing Call Flow, optionally bind a number |\n| `signalwire_deploy_swml_script` | Deployment | destructive/idempotent | Create or fully replace a managed SWML Script (Calling or Messaging) |\n| `signalwire_connect_webhook` | Deployment | destructive/idempotent | Route a number to externally deployed SWML/cXML at an HTTPS URL |\n| `signalwire_connect_relay_application` | Deployment | destructive/idempotent | Create/update a RELAY registration and connect a number |\n| `signalwire_provision_test_number` | Deployment | — | Purchase one exact number previously returned by discovery |\n| `signalwire_add_knowledge` | Knowledge | — | Add one URL-backed Datasphere document for RAG ingestion |\n| `signalwire_search_knowledge` | Knowledge | read-only | Semantic search over Datasphere documents |\n| `signalwire_run_call_test` | Testing | — | Start one bounded outbound development call that speaks text and hangs up |\n| `signalwire_run_message_test` | Testing | — | Send one text-only development SMS via the Compatibility API |\n| `signalwire_control_call` | Call control | destructive | High-level lifecycle action (end/transfer) on a live test call |\n| `signalwire_exercise_call_feature` | Call control | — | Exercise one non-AI media feature on a live call |\n| `signalwire_control_ai_call` | Call control | destructive | Interact with an AI session running on a live call |\n| `signalwire_diagnose_interaction` | Diagnostics | read-only | Assemble read-only evidence about a past voice call or message |\n\n## Requirements\n\n- Node.js ≥ 20.19.0\n- [pnpm](https://pnpm.io) 11 (the project pins `pnpm@11.16.0`)\n- A SignalWire account with a **Space**, **Project ID**, and a scoped **API token**\n  with the permissions the tools you use require\n\n## Configure\n\nAll configuration is read from the environment via three required variables and one\noptional write-gate flag. Copy `.env.example` and fill in your values:\n\n```ini\nSIGNALWIRE_SPACE=example.signalwire.com\nSIGNALWIRE_PROJECT_ID=00000000-0000-0000-0000-000000000000\nSIGNALWIRE_API_TOKEN=your-scoped-api-token\nSIGNALWIRE_MCP_ALLOW_WRITES=false\n```\n\n| Variable | Required | Notes |\n| --- | --- | --- |\n| `SIGNALWIRE_SPACE` | yes | Bare hostname (e.g. `example.signalwire.com`) or an `https://` URL containing only that host. Paths, ports, query strings, fragments, and credentials are rejected. |\n| `SIGNALWIRE_PROJECT_ID` | yes | Your SignalWire Project ID (UUID). |\n| `SIGNALWIRE_API_TOKEN` | yes | A scoped API token. Its value is never echoed in output or errors. |\n| `SIGNALWIRE_MCP_ALLOW_WRITES` | no | Literal `\"true\"` or `\"false\"`. Defaults to `\"false\"`, which blocks every mutating tool. |\n\nAt startup the server validates all variables and reports every problem in a single\nerror; it exits nonzero on misconfiguration without printing anything to stdout\n(stdout is reserved for MCP JSON-RPC frames).\n\n## Connect from an MCP client\n\nPoint any stdio MCP client (Claude Desktop, Cursor, etc.) at the server. The server is\nconfigured entirely through environment variables, so the two methods below differ only\nin `command`/`args`.\n\n### Global install (recommended)\n\nInstall once with pnpm to put the `signalwire-admin-mcp` command on your `PATH`:\n\n```bash\npnpm add -g @bradsjm/signalwire-admin-mcp\n```\n\nThen reference the command by name — no `args` needed:\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"signalwire-admin-mcp\": {\n      \"command\": \"signalwire-admin-mcp\",\n      \"env\": {\n        \"SIGNALWIRE_SPACE\": \"example.signalwire.com\",\n        \"SIGNALWIRE_PROJECT_ID\": \"00000000-0000-0000-0000-000000000000\",\n        \"SIGNALWIRE_API_TOKEN\": \"your-scoped-api-token\",\n        \"SIGNALWIRE_MCP_ALLOW_WRITES\": \"false\"\n      }\n    }\n  }\n}\n```\n\n### From a local build\n\nClone the repo and build the TypeScript to `dist/`:\n\n```bash\npnpm install\npnpm build\n```\n\nThen point the client at the built entry point:\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"signalwire-admin-mcp\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/signalwire-admin-mcp/dist/index.js\"],\n      \"env\": {\n        \"SIGNALWIRE_SPACE\": \"example.signalwire.com\",\n        \"SIGNALWIRE_PROJECT_ID\": \"00000000-0000-0000-0000-000000000000\",\n        \"SIGNALWIRE_API_TOKEN\": \"your-scoped-api-token\",\n        \"SIGNALWIRE_MCP_ALLOW_WRITES\": \"false\"\n      }\n    }\n  }\n}\n```\n\n## Result envelope\n\nEvery tool returns the same strict result envelope as `structuredContent` (and as\ncompact JSON in a single text block). The shape is enforced in Zod so it cannot drift\nby convention:\n\n```ts\n{\n  status: \"complete\" | \"unchanged\" | \"accepted\" | \"partial\"\n        | \"confirmation_required\" | \"blocked\" | \"not_found\"\n        | \"unsupported\" | \"error\",\n  summary: string,                 // 1–1000 chars\n  resource_id?: string,            // primary durable resource affected\n  call_id?: string,                // voice test correlation\n  message_sid?: string,            // SMS test correlation\n  control_id?: string,             // for stopping a started media feature\n  platform_status?: string,        // latest platform-reported status\n  safe_to_retry?: boolean,         // may the caller repeat after a partial?\n  next_step?: string,              // concrete next action when relevant\n  resources?:  Resource[],         // durable read-back (≤ 20)\n  items?:      Item[],             // discovery / search results (≤ 20)\n  operations?: Operation[],        // per-invocation journal (≤ 20)\n  evidence?:   Evidence[],         // observed facts (≤ 20)\n  inferences?: Inference[],        // reasoned conclusions + confidence (≤ 20)\n  unknowns?:   string[],           // gaps and uncertainties (≤ 20)\n  error?:      Error,              // sanitized failure detail (error status only)\n}\n```\n\nStatus-dependent invariants are enforced: `error` requires `error`, `accepted`\nrequires a correlation id, `confirmation_required`/`blocked`/`not_found`/`unsupported`\nrequire `next_step`, and `partial` requires a non-empty `operations` journal and\n`safe_to_retry`.\n\n## Safety model\n\n- **Write gate.** `SIGNALWIRE_MCP_ALLOW_WRITES=false` (the default) blocks every\n  mutating tool; they return `blocked` with a `next_step` rather than touching state.\n- **Version-locked capability registry.** `src/signalwire/capabilities.ts` is the sole,\n  auditable mapping from each tool/action to the pinned SDK methods it uses. Operations\n  absent from the registry are unsupported — there is no raw-HTTP escape hatch.\n- **Bounded I/O.** Each tool has a strict Zod input schema and only projects bounded,\n  contract-defined fields into output.\n- **Secret redaction.** Sensitive keys (`token`, `authorization`, `secret`,\n  `api_key`, `signed_url`, …) are recursively scrubbed to `[redacted]` before any value\n  reaches output. The API token is never echoed.\n- **Channel discipline.** stdout carries only MCP frames; sanitized audit lines\n  (tool name, elapsed ms, outcome status — no argument values) go to stderr.\n\n## Development\n\n```bash\npnpm install        # install dependencies\npnpm build          # tsc -> dist/, makes dist/index.js executable\npnpm dev            # run src/index.ts directly via tsx\npnpm start          # run the built dist/index.js\npnpm typecheck      # tsc --noEmit\npnpm test           # build, then run the vitest suite\n```\n\n### Project layout\n\n```\nsrc/\n  index.ts            executable entry point (stdio bootstrap)\n  server.ts           MCP server factory; registers all 15 tools\n  config.ts           environment loading + validation\n  signalwire/\n    client.ts         sole RestClient boundary (constructs the SDK client)\n    capabilities.ts   version-locked capability registry\n  core/\n    output.ts         strict result envelope + finalization/redaction\n    schemas.ts        bounded string schemas\n    redaction.ts      secret scrubbing + sanitized audit logging\n    errors.ts         error classification/normalization\n  tools/\n    contracts.ts      every tool input schema + result parser\n    runtime.ts        shared orchestration (write gate, executeTool)\n    inventory.ts      deployment.ts    knowledge.ts\n    testing.ts        call-control.ts  diagnostics.ts\ntests/\n  server-contract.test.ts  stdio.test.ts\n  sdk-compositions.test.ts helpers.ts\n```\n\n## License\n\nPrivate package (`@bradsjm/signalwire-admin-mcp` v0.1.0).\n","readmeFilename":"","_rev":"1-2304f9c66bdbaa1b1b7b421718a7ca94"}