You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 873f4f6
Browse filesBrowse the repository at this point in the historyBrowse files
feat(hub)!: pin discovery to the credential's origin via @corbits/credential-http
Replace @corbits/credential-mcp with @corbits/credential-http. Discovery that
sends a secret now pins to the credential's provider apiBaseUrl origin, and a
host allows extra origins per pinned origin with `extraOrigins`. No origin is
allowed by default, which drops the built-in vendor allowance credential-mcp
carried. A keyless credential pins to the URL's origin. OAuth discovery's
fallback now requires the resource-served metadata to name the resource's own
issuer (RFC 8414 §3.3).
BREAKING CHANGE: readCredentialSecret is now readCredential and returns
{ secret, origin? }; discoverMcpServer takes `credential` instead of `secret`;
a credential with a secret whose provider has no apiBaseUrl, or a URL off its
origin without `extraOrigins`, is refused.
Copy file name to clipboardExpand all lines: README.md
+47-20Lines changed: 47 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,7 +21,7 @@ Runs on Node.js 24+ and Bun 1.2+.
21
21
For the `@corbits/mcp/hub` routes, also install:
22
22
23
23
```bash
24
-
bun add @corbits/credential-mcp @intx/authz @intx/crypto @intx/db @intx/hub-api drizzle-orm hono
24
+
bun add @corbits/credential-http @intx/authz @intx/crypto @intx/db @intx/hub-api drizzle-orm hono
25
25
```
26
26
27
27
## Quickstart
@@ -46,25 +46,25 @@ Every client call takes `{ fetch }` as its last argument, for example a fetch th
46
46
47
47
-**Hub:**`@corbits/mcp/hub` mounts a discovery route on an [`@intx/hub-api`](https://github.com/faremeter/interchange/tree/main/packages/hub-api) app and reads tenant credentials from [`@intx/db`](https://github.com/faremeter/interchange/tree/main/packages/db).
48
48
-**Sidecar:**`@corbits/mcp/sidecar-bundle` builds [`@intx/agent`](https://github.com/faremeter/interchange/tree/main/packages/agent) tools from a stored catalog.
49
-
-**Pairs with:**[`@corbits/oauth-core`](https://github.com/corbitsdev/corbits-oauth-core) for the login flow and [`@corbits/credential-mcp`](https://github.com/corbitsdev/corbits-credential-mcp) for the origin-pinned credential provider.
49
+
-**Pairs with:**[`@corbits/oauth-core`](https://github.com/corbitsdev/corbits-oauth-core) for the login flow and [`@corbits/credential-http`](https://github.com/corbitsdev/credential-http) for the origin-pinned credential provider.
|`mcpTools(options, env?)`|`@corbits/mcp`| Discover each server live, then build tools. For hosts that can await; servers use `name` and `credentialHandle`. |
59
-
|`qualifiedName`, `toolDescription`, `isAskExempt`|`@corbits/mcp`| Naming and `ask`-floor rules the tool builders use. |
60
-
|`discoverMcpLoginEntry({ resourceUrl })`|`@corbits/mcp`| Resolve the authorization server (RFC 9728, then RFC 8414). |
61
-
|`registerMcpClient(opts)`|`@corbits/mcp`| Register a loopback public client (RFC 7591). |
62
-
|`mcpClientConfig(entry, opts)`|`@corbits/mcp`| Build the `OAuthClientConfig` oauth-core's login helpers take. |
63
-
|`selectMcpScopes(opts)`|`@corbits/mcp`| Pick scopes in the MCP spec's selection order. |
64
-
|`mcpServers(config)`|`@corbits/mcp/sidecar-bundle`| Build tools from stored catalogs over mediated credentials. |
65
-
|`shapeMcpContent(content)`, `SIDECAR_BUNDLE_ID`|`@corbits/mcp/sidecar-bundle`| Result shaping and the bundle's tool id. |
66
-
|`mountMcpDiscovery(app, opts)`|`@corbits/mcp/hub`| Mount `POST /mcp/discover`. |
67
-
|`discoverMcpServer(args)`, `readCredentialSecret(opts)`|`@corbits/mcp/hub`| The discovery and credential reads the route uses. |
|`mcpTools(options, env?)`|`@corbits/mcp`| Discover each server live, then build tools. For hosts that can await; servers use `name` and `credentialHandle`. |
59
+
|`qualifiedName`, `toolDescription`, `isAskExempt`|`@corbits/mcp`| Naming and `ask`-floor rules the tool builders use. |
60
+
|`discoverMcpLoginEntry({ resourceUrl })`|`@corbits/mcp`| Resolve the authorization server (RFC 9728, then RFC 8414). |
61
+
|`registerMcpClient(opts)`|`@corbits/mcp`| Register a loopback public client (RFC 7591). |
62
+
|`mcpClientConfig(entry, opts)`|`@corbits/mcp`| Build the `OAuthClientConfig` oauth-core's login helpers take. |
63
+
|`selectMcpScopes(opts)`|`@corbits/mcp`| Pick scopes in the MCP spec's selection order. |
64
+
|`mcpServers(config)`|`@corbits/mcp/sidecar-bundle`| Build tools from stored catalogs over mediated credentials. |
65
+
|`shapeMcpContent(content)`, `SIDECAR_BUNDLE_ID`|`@corbits/mcp/sidecar-bundle`| Result shaping and the bundle's tool id. |
66
+
|`mountMcpDiscovery(app, opts)`|`@corbits/mcp/hub`| Mount `POST /mcp/discover`. |
67
+
|`discoverMcpServer(args)`, `readCredential(opts)`|`@corbits/mcp/hub`| The discovery and credential reads the route uses. |
68
68
69
69
`McpToolSchema` validates a catalog entry (`McpTool`). Transport and protocol failures throw `McpError`. OAuth discovery failures throw `OAuthDiscoveryError` from `@corbits/oauth-core`.
Mount `mcpRoutes` on the hub app under `/api/tenants/:tenantId`, behind the hub's auth and tenant middleware.
114
114
115
-
`POST /api/tenants/:tenantId/mcp/discover` with `{ url, credentialId? }` returns `{ data: { serverInfo, tools } }`. `url` must be https (http only on loopback). `credentialId` names a tenant credential whose secret is sent as a bearer; a credential holding `MCP_NO_TOKEN_SENTINEL` from `@corbits/credential-mcp` sends no `authorization` header. Errors: 400 for a bad body or URL, 404 for an unknown credential, 422 when the server fails discovery. `requireGrant` is the host's own grant middleware for this route. The fetch is pinned to the server's origin and refuses redirects, so the secret never leaves that origin.
115
+
`POST /api/tenants/:tenantId/mcp/discover` with `{ url, credentialId? }` returns `{ data: { serverInfo, tools } }`. `url` must be https (http only on loopback). `credentialId` names a tenant credential whose secret is sent as a bearer; a credential holding `MCP_NO_TOKEN_SENTINEL` from `@corbits/credential-http` sends no `authorization` header. Errors: 400 for a bad body or URL, 404 for an unknown credential, 422 when the server fails discovery or the request would leave the credential's origin. `requireGrant` is the host's own grant middleware for this route.
116
+
117
+
When a secret is sent, the fetch is pinned to the origin of the credential's provider `apiBaseUrl`; with no credential or a keyless one, to the URL's origin. Redirects are always refused, so the secret never leaves that origin.
118
+
119
+
#### Extra origins
120
+
121
+
Some servers serve MCP on a different origin from the one their credential is issued for. Nothing is allowed off the pinned origin by default. The host lists extra origins per pinned origin in `extraOrigins`, which is passed through to `@corbits/credential-http`:
A credential pinned to `https://api.example.com` may then be sent to `https://mcp.example.net`; no other credential can.
139
+
140
+
`extraOrigins` is host-wide, not per tenant: an entry applies to every tenant's credential pinned to that origin, so list only origins you trust with all of them. `discoverMcpServer` takes the same option. For the sidecar bundle, configure the same allowance on the credential provider the host registers.
Each catalog entry becomes a tool named `<handle>.<tool>`, with the remote `inputSchema` passed through and the call proxied to `tools/call`. Text content comes back as text and anything else as JSON; `isError` passes through. A handle that does not resolve, or a server that fails `initialize`, fails only that server's calls.
138
163
139
-
`handle` is the credential handle the host binds this server's token to. The bundle resolves it from the runtime `credentials` capability and expects an `http` credential, such as the one `@corbits/credential-mcp`'s provider returns. The package manifest declares the `mcp-server` credential for this.
164
+
`handle` is the credential handle the host binds this server's token to. The bundle resolves it from the runtime `credentials` capability and expects an `http` credential, such as the one `@corbits/credential-http`'s MCP provider returns. The package manifest declares the `mcp-server` credential for this.
140
165
141
166
### Grant access
142
167
@@ -146,7 +171,9 @@ Grant the agent's principal `tool:deepwiki.*` for the whole server, or `tool:dee
146
171
147
172
- Existing server configs, stored catalogs and the `mcp-server` credential keep working unchanged.
148
173
-`@intx/harness` is a required peer. Import `FetchLike` from it; `@corbits/mcp` no longer exports that type.
149
-
-`@intx/db`, `@intx/hub-api`, `drizzle-orm`, `hono` and `@corbits/credential-mcp` are optional peers. Install them if you use `@corbits/mcp/hub`.
174
+
-`@intx/db`, `@intx/hub-api`, `drizzle-orm`, `hono` and `@corbits/credential-http` are optional peers. Install them if you use `@corbits/mcp/hub`. `@corbits/credential-http` replaces `@corbits/credential-mcp`.
175
+
- Discovery with a credential pins to the credential's provider `apiBaseUrl` origin, not to the requested URL's origin. A credential with a secret whose provider has no `apiBaseUrl` is refused, and a URL on another origin needs `extraOrigins`. No origin is allowed by default.
176
+
-`readCredentialSecret` is now `readCredential`, which returns `{ secret, origin? }`. `discoverMcpServer` takes `credential: { secret, origin? }` instead of `secret`.
150
177
-`@intx/agent` and `@intx/harness` peers are `^0.4.0`.
151
178
- Discovery rejects authorization-server metadata whose `issuer` differs from the one the protected resource names.
0 commit comments