{"_id":"toolbox","_rev":"10-fb3e3a923588bb75520c56da49b3eece","name":"toolbox","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"toolbox","version":"0.1.0","keywords":["helpers","detectMimeType","getAvg","getMax","getMin","getRandomNum","getRandomNums","getSum","getUid","removeDuplicates","shuffle","hex","rgb","color","utility","utilities","random","uid","random number","random numbers"],"author":{"name":"František Hába","email":"hello@frantisekhaba.com"},"_id":"toolbox@0.1.0","maintainers":[{"name":"baggz","email":"hello@frantisekhaba.com"}],"homepage":"https://github.com/Baggz/Toolbox","bugs":{"url":"https://github.com/Baggz/Toolbox/issues","email":"hello@frantisekhaba.com"},"dist":{"shasum":"6a5a631356aeb516219838716f263fd7d1f022ba","tarball":"https://registry.npmjs.org/toolbox/-/toolbox-0.1.0.tgz","integrity":"sha512-v23xAgTlBmpd7dmPTNue4LYCwjIQkGZcyrOBnf3pzbLaJaJ1WAI3AlIi/XFL+YKbC+aBHHjGA/3A2OUbYq7jgQ==","signatures":[{"sig":"MEUCIEhE92W/aPLEvrtYnzPCzSY5BSTtYXrZ0wIdoPIXOP4OAiEAk7y3GOnotj5HtSwsYdQn8ZdKi2sGuZJ0/jdLuuJaQxI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"engines":{"node":">= 0.3.0"},"scripts":{"test":"nodeunit tests/"},"_npmUser":{"name":"baggz","email":"hello@frantisekhaba.com"},"licenses":[{"url":"https://github.com/Baggz/Toolbox/blob/master/README.md","type":"MIT"}],"repository":{"url":"git://github.com/Baggz/Toolbox.git","type":"git"},"_npmVersion":"1.0.105","description":"A collection of useful JavaScript utilities","directories":{},"_nodeVersion":"v0.4.11","dependencies":{},"_defaultsLoaded":true,"devDependencies":{"nodeunit":"0.5.1"},"_engineSupported":true},"0.1.1":{"name":"toolbox","version":"0.1.1","keywords":["helpers","detectMimeType","getAvg","getMax","getMin","getRandomNum","getRandomNums","getSum","getUid","removeDuplicates","shuffle","hex","rgb","color","utility","utilities","random","uid","random number","random numbers"],"author":{"name":"František Hába","email":"hello@frantisekhaba.com"},"_id":"toolbox@0.1.1","maintainers":[{"name":"baggz","email":"hello@frantisekhaba.com"}],"homepage":"https://github.com/Baggz/Toolbox","bugs":{"url":"https://github.com/Baggz/Toolbox/issues","email":"hello@frantisekhaba.com"},"dist":{"shasum":"449f79229757aa6a8f74fa59f26356c8b5279348","tarball":"https://registry.npmjs.org/toolbox/-/toolbox-0.1.1.tgz","integrity":"sha512-7wZKk5pViqaeZBeN3Wnkf7FN3jWPQxQeJrCmQW1L7QGaCe2jDxRWjTUFMjaP1gzC9wc87mwfbHl4+OgPWkcMEw==","signatures":[{"sig":"MEUCICzYTRGw9jz0Ovb/GYSC23tL49tXF6LYqlp/g6TE9d9tAiEAquWRLheJDoBzlKcuEJtZdk1ldfKJRYp8LG8G9gjekOE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"./src/toolbox.js","engines":{"node":">= 0.3.0"},"scripts":{"test":"nodeunit tests/"},"_npmUser":{"name":"baggz","email":"hello@frantisekhaba.com"},"licenses":[{"url":"https://github.com/Baggz/Toolbox/blob/master/README.md","type":"MIT"}],"repository":{"url":"git://github.com/Baggz/Toolbox.git","type":"git"},"_npmVersion":"1.0.105","description":"A collection of useful JavaScript utilities","directories":{},"_nodeVersion":"v0.4.11","dependencies":{},"_defaultsLoaded":true,"devDependencies":{"nodeunit":"0.5.1"},"_engineSupported":true},"0.2.0":{"name":"toolbox","version":"0.2.0","description":"A handy toolbox for connecting to third-party MCP servers","keywords":["mcp","model","context","protocol","clerk","auth"],"homepage":"https://github.com/clerk/toolbox#readme","bugs":{"url":"https://github.com/clerk/toolbox/issues"},"repository":{"type":"git","url":"git+https://github.com/clerk/toolbox.git"},"license":"MIT","author":{"name":"Clerk"},"type":"module","main":"dist/","exports":{"./index":{"import":"./dist/index.js","types":"./dist/index.d.ts"},"./nextjs":{"import":"./dist/nextjs/index.js","types":"./dist/nextjs/index.d.ts"},"./nextjs/server":{"import":"./dist/nextjs/server.js","types":"./dist/nextjs/server.d.ts"},"./nextjs/auth":"./dist/nextjs/auth","./nextjs/auth/self-storage":{"import":"./dist/nextjs/auth/self-storage.js","types":"./dist/nextjs/auth/self-storage.d.ts"},"./storage":"./dist/storage","./storage/fs":{"import":"./dist/storage/fs.js","types":"./dist/storage/fs.d.ts"},"./storage/redis":{"import":"./dist/storage/redis.js","types":"./dist/storage/redis.d.ts"},"./storage/postgres":{"import":"./dist/storage/postgres.js","types":"./dist/storage/postgres.d.ts"},"./storage/sqlite":{"import":"./dist/storage/sqlite.js","types":"./dist/storage/sqlite.d.ts"}},"scripts":{"build":"tsup","prepublishOnly":"npm run build","watch":"tsup --watch"},"publishConfig":{"access":"public"},"dependencies":{"@modelcontextprotocol/sdk":"^1.12.0","eventsource-parser":"^3.0.2","psl":"^1.15.0","zod":"^3.25.56"},"devDependencies":{"@types/better-sqlite3":"^7.6.0","@types/node":"^22.15.21","@types/pg":"^8.10.0","@types/psl":"^1.1.3","@types/react":"^19.1.8","better-sqlite3":"^8.7.0","next":"^15.3.2","pg":"^8.11.0","redis":"^4.0.0","tsup":"^8.5.0","typescript":"^5.8.3"},"peerDependencies":{"better-sqlite3":"^8.7.0","pg":"^8.11.0","react":"^19.1.0","redis":"^4.0.0"},"peerDependenciesMeta":{"redis":{"optional":true},"pg":{"optional":true},"better-sqlite3":{"optional":true},"react":{"optional":true}},"tsup":{"entry":["src/index.ts","src/nextjs/index.ts","src/nextjs/server.ts","src/nextjs/auth/self-storage.ts","src/storage/fs.ts","src/storage/redis.ts","src/storage/postgres.ts","src/storage/sqlite.ts"],"format":["esm"],"dts":true,"clean":true,"external":["redis","pg","better-sqlite3"]},"_id":"toolbox@0.2.0","gitHead":"2fc17730d8063d5bbea02970db9b4ea6fe7e3709","_nodeVersion":"22.10.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-ZWYWT2Em0gKE6/PW0dSXLnb6IUbeR6+0x7l6Gv3ZkC35FOhVhBQQTuHQE6oZq67u1JnHVre7/Pc88AS4U/DqSw==","shasum":"17e812faee9e0bb9f814a5a35cb17c123c8b9f39","tarball":"https://registry.npmjs.org/toolbox/-/toolbox-0.2.0.tgz","fileCount":22,"unpackedSize":103299,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAHUV64MKMaBeLxphdRzETL3UUVSVpcipSXZlwu+66R3AiEAlRwACsWbx/+Qu2QYejpMWDEbrYSmD9Ue88eMirM7ixU="}]},"_npmUser":{"name":"colinclerk","email":"colin@clerk.dev","actor":{"name":"colinclerk","email":"colin@clerk.dev","type":"user"}},"directories":{},"maintainers":[{"name":"colinclerk","email":"colin@clerk.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/toolbox_0.2.0_1751056262111_0.8027097634426139"},"_hasShrinkwrap":false}},"time":{"created":"2011-11-14T22:23:37.654Z","modified":"2025-06-27T20:31:02.471Z","0.1.0":"2011-11-14T22:23:39.681Z","0.1.1":"2011-11-25T22:23:52.280Z","0.2.0":"2025-06-27T20:31:02.304Z"},"bugs":{"url":"https://github.com/clerk/toolbox/issues"},"author":{"name":"Clerk"},"homepage":"https://github.com/clerk/toolbox#readme","keywords":["mcp","model","context","protocol","clerk","auth"],"repository":{"type":"git","url":"git+https://github.com/clerk/toolbox.git"},"description":"A handy toolbox for connecting to third-party MCP servers","maintainers":[{"name":"colinclerk","email":"colin@clerk.dev"}],"readme":"> [!NOTE]\n> Toolbox is still in development. There will not be semver guarantees until 1.0.0.\n\n# Toolbox\n\nToolbox is a production-grade library for connecting to MCP servers that require authentication.\n\n## What makes Toolbox production-grade?\n\nToolbox was built with an emphasis on security and practical credential management. There are two critical differences compared to other utilities for leveraging MCP servers:\n\n### Access and refresh tokens stay on the server\n\nAccess and refresh tokens for users are never sent to the frontend, which ensures they cannot be compromised in an XSS attack.\n\n### Only one OAuth Client is registered per OAuth Server\n\nWhen using MCP, the service provider should manage a single OAuth Server, while your agent should operate one OAuth Client.\n\nThis is preferred over implementations that dynamically register a new OAuth Client for each user, since it allows providers to understand which activity is coming from your agent.\n\n## Installation\n\n```bash\nnpm install toolbox\n```\n\n## Quick Start\n\n### 1. Mount the handler\n\nCreate a Next.js API route at `app/toolbox/route.ts`:\n\n```typescript\nimport { Toolbox } from \"toolbox/nextjs/server\";\nimport { SelfStorageAuthProvider } from \"toolbox/nextjs/auth/self-storage\";\nimport fsStore from \"toolbox/storage/fs\";\n\nconst toolbox = new Toolbox({\n  auth: new SelfStorageAuthProvider({\n    store: fsStore,\n    userId: \"u_12345\", // Replace with your user ID\n    oauthClientName: \"My App\",\n    oauthClientUri: \"https://myapp.com\",\n    discoveryOptions: {\n      resourceVsProtectedResourceMetadata: \"any\",\n    },\n  }),\n  store: fsStore,\n});\n\nexport const { GET, POST } = toolbox.handlers();\n```\n\n### 2. Manage connections with `useToolbox()`\n\nUse the React hook in your components:\n\n```typescript\nimport { useToolbox } from \"toolbox/nextjs\";\n\nexport default function MyComponent() {\n  const { toolbox, isLoaded } = useToolbox();\n\n  const handleAddServer = async (event: React.FormEvent<HTMLFormElement>) => {\n    event.preventDefault();\n    const formData = new FormData(event.currentTarget);\n    await toolbox.addServer(formData);\n  };\n\n  if (!isLoaded) return <div>Loading...</div>;\n\n  return (\n    <div>\n      {toolbox.servers.map((server) => (\n        <div key={server.id}>\n          <h3>{server.url}</h3>\n          <p>Status: {server.authorization.status}</p>\n          {server.authorization.status === \"requires_connection\" && (\n            <button\n              onClick={async () => {\n                const result = await server.generateAuthorizationUrl();\n                if (\"authorizationUrl\" in result) {\n                  window.location.href = result.authorizationUrl;\n                }\n              }}\n            >\n              Connect\n            </button>\n          )}\n        </div>\n      ))}\n\n      <form onSubmit={handleAddServer}>\n        <input name=\"url\" placeholder=\"MCP Server URL\" required />\n        <button type=\"submit\">Add Server</button>\n      </form>\n    </div>\n  );\n}\n```\n\n### 3. Pass the MCP context to your AI solution\n\nComing soon.\n\n## Configuration Options\n\n### Auth Providers\n\nToolbox supports multiple authentication providers:\n\n- **SelfStorageAuthProvider**: Stores OAuth credentials and tokens in your configured data store\n- **ClerkAuthProvider**: Uses Clerk to manage credentials and token (coming soon)\n\n### Data Stores\n\nChoose from multiple storage backends:\n\n- **File System**: `toolbox/storage/fs` (default, good for development)\n- **Redis**: `toolbox/storage/redis`\n- **PostgreSQL**: `toolbox/storage/postgres`\n- **SQLite**: `toolbox/storage/sqlite`\n\n### Server Status\n\nMCP servers can have the following authorization statuses:\n\n- `not_required`: Server doesn't require authentication\n- `discovery_failed`: Failed to discover OAuth configuration\n- `requires_registration`: Client registration needed\n- `requires_connection`: User needs to authorize\n- `connected`: Fully authenticated and ready to use\n\n## API Reference\n\n### useToolbox(toolboxUrl?: string)\n\nReturns an object with:\n\n- `toolbox`: Object containing servers and methods\n- `isLoaded`: Boolean indicating if data has loaded\n\n### toolbox.servers\n\nArray of MCP server objects with:\n\n- `id`: Unique server identifier\n- `url`: Server endpoint URL\n- `authorization`: OAuth configuration and status\n- `hasAccessToken`: Whether user has authorized access\n- `retryDiscovery()`: Retry OAuth discovery\n- `generateAuthorizationUrl()`: Generate OAuth authorization URL\n\n### toolbox.addServer(formData: FormData)\n\nAdd a new MCP server. FormData should contain:\n\n- `url`: The MCP server endpoint URL\n\n## Examples\n\nSee the [nextjs-selfstorage example](./examples/nextjs-selfstorage) for a complete working implementation.\n\nThe output of toolbox is an array of connected MCP servers and the OAuth access tokens necessary to communicate with them.\n\nWe'll provide helpers to pass that data to your preferred AI solution.\n","license":"MIT","readmeFilename":"README.md"}