@signdocs-brasil/mcp-server 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -3
- package/dist/bin/http.d.ts +2 -0
- package/dist/bin/http.js +35 -0
- package/dist/bin/http.js.map +1 -0
- package/dist/bin/stdio.js +2 -1
- package/dist/bin/stdio.js.map +1 -1
- package/dist/client.d.ts +50 -0
- package/dist/client.js +71 -0
- package/dist/client.js.map +1 -1
- package/dist/http/server.d.ts +29 -29
- package/dist/http/server.js +160 -36
- package/dist/http/server.js.map +1 -1
- package/dist/http/shared.d.ts +31 -0
- package/dist/http/shared.js +67 -0
- package/dist/http/shared.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/lambda.d.ts +51 -0
- package/dist/lambda.js +96 -0
- package/dist/lambda.js.map +1 -0
- package/dist/schemas.d.ts +6 -6
- package/dist/server.d.ts +7 -5
- package/dist/server.js +13 -12
- package/dist/server.js.map +1 -1
- package/dist/tools/documents.d.ts +2 -1
- package/dist/tools/documents.js +3 -4
- package/dist/tools/documents.js.map +1 -1
- package/dist/tools/envelopes.d.ts +2 -1
- package/dist/tools/envelopes.js +6 -6
- package/dist/tools/envelopes.js.map +1 -1
- package/dist/tools/evidence.d.ts +2 -1
- package/dist/tools/evidence.js +2 -3
- package/dist/tools/evidence.js.map +1 -1
- package/dist/tools/signingSessions.d.ts +2 -1
- package/dist/tools/signingSessions.js +8 -8
- package/dist/tools/signingSessions.js.map +1 -1
- package/dist/tools/transactions.d.ts +2 -1
- package/dist/tools/transactions.js +4 -5
- package/dist/tools/transactions.js.map +1 -1
- package/dist/tools/verify.d.ts +2 -1
- package/dist/tools/verify.js +5 -7
- package/dist/tools/verify.js.map +1 -1
- package/dist/tools/webhooks.d.ts +2 -1
- package/dist/tools/webhooks.js +5 -6
- package/dist/tools/webhooks.js.map +1 -1
- package/package.json +22 -6
package/README.md
CHANGED
|
@@ -105,6 +105,76 @@ The server exposes grounding resources the model can read on demand:
|
|
|
105
105
|
- `signdocs://policy-profiles` — valid `policyProfile` values and CUSTOM steps
|
|
106
106
|
- `signdocs://webhook-events` — all subscribable event types
|
|
107
107
|
|
|
108
|
+
## Remote HTTP transport (multi-tenant)
|
|
109
|
+
|
|
110
|
+
The same tools are also served over **Streamable HTTP** so a single deployment
|
|
111
|
+
can serve many AI agents/tenants — each authenticates per session with its own
|
|
112
|
+
SignDocs credentials (no shared secret baked into the server).
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npm run start:http # or: signdocs-mcp-http (listens on PORT, default 3000)
|
|
116
|
+
# or containerized:
|
|
117
|
+
docker build -t signdocs-mcp . && docker run -p 3000:3000 signdocs-mcp
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Endpoint:** `POST /mcp` (Streamable HTTP). Auth is required on the MCP
|
|
121
|
+
`initialize` request, via the `Authorization` header:
|
|
122
|
+
|
|
123
|
+
- `Authorization: Bearer <token>` — a SignDocs OAuth2 access token (from
|
|
124
|
+
`/oauth2/token`), passed straight through to the API.
|
|
125
|
+
- `Authorization: Basic base64(clientId:clientSecret)` — the server runs the
|
|
126
|
+
`client_credentials` exchange for you.
|
|
127
|
+
|
|
128
|
+
Pick the environment per session with `X-SignDocs-Environment: hml|production`
|
|
129
|
+
(defaults to the server's configured default).
|
|
130
|
+
|
|
131
|
+
The server behaves as an **OAuth 2.0 Resource Server**: it serves
|
|
132
|
+
`GET /.well-known/oauth-protected-resource` (RFC 9728, pointing at the SignDocs
|
|
133
|
+
authorization server) and answers an unauthenticated `initialize` with `401` +
|
|
134
|
+
`WWW-Authenticate`. The SignDocs API remains the authoritative token validator.
|
|
135
|
+
`GET /healthz` is an unauthenticated health probe.
|
|
136
|
+
|
|
137
|
+
Example client config (Bearer):
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"mcpServers": {
|
|
142
|
+
"signdocs-remote": {
|
|
143
|
+
"type": "http",
|
|
144
|
+
"url": "https://your-host.example/mcp",
|
|
145
|
+
"headers": {
|
|
146
|
+
"Authorization": "Bearer <signdocs_access_token>",
|
|
147
|
+
"X-SignDocs-Environment": "hml"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Server env vars:** `PORT`, `HOST`, `SIGNDOCS_ENVIRONMENT` (default env),
|
|
155
|
+
`MCP_PUBLIC_URL` (for resource metadata behind a proxy), `MCP_CORS_ORIGIN`,
|
|
156
|
+
`MCP_DNS_REBINDING_PROTECTION=true` + `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS`
|
|
157
|
+
(recommended in production).
|
|
158
|
+
|
|
159
|
+
> Sessions are held in process memory, so run a single instance or use sticky
|
|
160
|
+
> routing. For multi-instance/serverless, front it with sticky sessions or swap
|
|
161
|
+
> the session map for a shared store + EventStore (resumability). Deploying onto
|
|
162
|
+
> the existing `external-api` Lambda + API Gateway as a NestedStack is the
|
|
163
|
+
> intended production path.
|
|
164
|
+
|
|
165
|
+
### AWS Lambda
|
|
166
|
+
|
|
167
|
+
For serverless hosting, `@signdocs-brasil/mcp-server/lambda` exports
|
|
168
|
+
`createLambdaHandler` — an API Gateway HTTP API v2 handler that runs the MCP
|
|
169
|
+
transport **statelessly** (one server per invocation, no session store), with the
|
|
170
|
+
same Bearer/Basic auth. SignDocs hosts this on `mcp-hml.signdocs.com.br` /
|
|
171
|
+
`mcp.signdocs.com.br`.
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { createLambdaHandler } from '@signdocs-brasil/mcp-server/lambda';
|
|
175
|
+
export const handler = createLambdaHandler({ defaultEnvironment: 'hml' });
|
|
176
|
+
```
|
|
177
|
+
|
|
108
178
|
## Development
|
|
109
179
|
|
|
110
180
|
```bash
|
|
@@ -116,6 +186,10 @@ npm run inspect # build + launch MCP Inspector against the stdio server
|
|
|
116
186
|
|
|
117
187
|
## Roadmap
|
|
118
188
|
|
|
119
|
-
- **v0.1
|
|
120
|
-
- **
|
|
121
|
-
|
|
189
|
+
- **v0.1:** local stdio server, full tool catalog, env credentials.
|
|
190
|
+
- **v0.2 (this release):** remote Streamable-HTTP transport with per-session,
|
|
191
|
+
per-tenant auth (Bearer passthrough or Basic client-credentials) and OAuth
|
|
192
|
+
Resource Server discovery. Tool layer is shared between both transports.
|
|
193
|
+
- **Next:** deploy the HTTP transport onto `external-api` (Lambda + API Gateway
|
|
194
|
+
NestedStack); optional edge JWT validation + shared-store sessions for
|
|
195
|
+
horizontal scale.
|
package/dist/bin/http.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createHttpServer } from '../http/server.js';
|
|
3
|
+
import { resolveEnvironment } from '../client.js';
|
|
4
|
+
/**
|
|
5
|
+
* Remote HTTP entrypoint. Unlike the stdio server, credentials are NOT read
|
|
6
|
+
* from env — each request carries its own (Bearer token or Basic client
|
|
7
|
+
* credentials), so one deployment serves many tenants.
|
|
8
|
+
*/
|
|
9
|
+
function envDefault() {
|
|
10
|
+
try {
|
|
11
|
+
return resolveEnvironment(process.env.SIGNDOCS_ENVIRONMENT);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return 'hml';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const port = Number(process.env.PORT ?? 3000);
|
|
18
|
+
const host = process.env.HOST ?? '0.0.0.0';
|
|
19
|
+
const server = createHttpServer({
|
|
20
|
+
defaultEnvironment: envDefault(),
|
|
21
|
+
corsOrigin: process.env.MCP_CORS_ORIGIN,
|
|
22
|
+
publicUrl: process.env.MCP_PUBLIC_URL,
|
|
23
|
+
enableDnsRebindingProtection: process.env.MCP_DNS_REBINDING_PROTECTION === 'true',
|
|
24
|
+
allowedHosts: process.env.MCP_ALLOWED_HOSTS?.split(',').map((h) => h.trim()).filter(Boolean),
|
|
25
|
+
allowedOrigins: process.env.MCP_ALLOWED_ORIGINS?.split(',').map((o) => o.trim()).filter(Boolean),
|
|
26
|
+
});
|
|
27
|
+
server.listen(port, host, () => {
|
|
28
|
+
process.stderr.write(`[signdocs-mcp-http] listening on http://${host}:${port}/mcp (default env: ${envDefault()})\n`);
|
|
29
|
+
});
|
|
30
|
+
for (const sig of ['SIGINT', 'SIGTERM']) {
|
|
31
|
+
process.on(sig, () => {
|
|
32
|
+
server.close(() => process.exit(0));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/bin/http.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAoB,MAAM,cAAc,CAAC;AAEpE;;;;GAIG;AACH,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,SAAS,CAAC;AAE3C,MAAM,MAAM,GAAG,gBAAgB,CAAC;IAC9B,kBAAkB,EAAE,UAAU,EAAE;IAChC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;IACvC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;IACrC,4BAA4B,EAAE,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,MAAM;IACjF,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;IAC5F,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;CACjG,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;IAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,IAAI,IAAI,IAAI,sBAAsB,UAAU,EAAE,KAAK,CAAC,CAAC;AACvH,CAAC,CAAC,CAAC;AAEH,KAAK,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE;QACnB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/bin/stdio.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { createServer } from '../server.js';
|
|
4
|
+
import { getStdioContext } from '../client.js';
|
|
4
5
|
/**
|
|
5
6
|
* stdio entrypoint. AI clients (Claude Desktop/Code, Cursor, …) launch this
|
|
6
7
|
* binary and speak MCP over stdin/stdout. NEVER write to stdout here — it is
|
|
7
8
|
* the protocol channel; diagnostics go to stderr.
|
|
8
9
|
*/
|
|
9
10
|
async function main() {
|
|
10
|
-
const server = createServer();
|
|
11
|
+
const server = createServer(getStdioContext());
|
|
11
12
|
const transport = new StdioServerTransport();
|
|
12
13
|
await server.connect(transport);
|
|
13
14
|
process.stderr.write('[signdocs-mcp] server started on stdio\n');
|
package/dist/bin/stdio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/bin/stdio.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/bin/stdio.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C;;;;GAIG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,YAAY,CAAC,eAAe,EAAE,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;AACnE,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SignDocsBrasilClient } from '@signdocs-brasil/api';
|
|
2
|
+
import type { TokenCache, CachedToken } from '@signdocs-brasil/api';
|
|
2
3
|
/**
|
|
3
4
|
* Thin wrapper that turns environment variables into a configured
|
|
4
5
|
* {@link SignDocsBrasilClient}. The official SDK owns the OAuth2
|
|
@@ -33,3 +34,52 @@ export declare function resetClientCache(): void;
|
|
|
33
34
|
* link — it must carry the one-time embed token (`clientSecret`) as `?cs=`.
|
|
34
35
|
*/
|
|
35
36
|
export declare function buildSigningUrl(url: string, clientSecret: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* What every tool handler needs to talk to SignDocs. In the stdio server this
|
|
39
|
+
* is built once from env; in the remote HTTP server it is built per-request so
|
|
40
|
+
* each tenant is fully isolated (no shared client/token across requests).
|
|
41
|
+
*/
|
|
42
|
+
export interface ToolContext {
|
|
43
|
+
client: SignDocsBrasilClient;
|
|
44
|
+
environment: Environment;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A {@link TokenCache} pre-seeded with a caller-supplied access token. The SDK's
|
|
48
|
+
* AuthHandler checks the cache before exchanging credentials, so seeding it makes
|
|
49
|
+
* the SDK use the presented bearer directly and never call `/oauth2/token`.
|
|
50
|
+
* The SignDocs API remains the real validator — an invalid/expired token yields
|
|
51
|
+
* a 401 from the API, surfaced to the caller.
|
|
52
|
+
*/
|
|
53
|
+
export declare class StaticTokenCache implements TokenCache {
|
|
54
|
+
private readonly token;
|
|
55
|
+
constructor(accessToken: string, ttlMs?: number);
|
|
56
|
+
get(): CachedToken | null;
|
|
57
|
+
set(): void;
|
|
58
|
+
delete(): void;
|
|
59
|
+
}
|
|
60
|
+
export type BuildClientOptions = {
|
|
61
|
+
mode: 'credentials';
|
|
62
|
+
clientId: string;
|
|
63
|
+
clientSecret: string;
|
|
64
|
+
environment: Environment;
|
|
65
|
+
baseUrlOverride?: string;
|
|
66
|
+
scopes?: string[];
|
|
67
|
+
} | {
|
|
68
|
+
mode: 'bearer';
|
|
69
|
+
bearer: string;
|
|
70
|
+
environment: Environment;
|
|
71
|
+
baseUrlOverride?: string;
|
|
72
|
+
scopes?: string[];
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Build a fresh, request-scoped SDK client. `credentials` mode lets the SDK run
|
|
76
|
+
* the OAuth2 client_credentials exchange; `bearer` mode passes a pre-issued
|
|
77
|
+
* access token straight through via {@link StaticTokenCache}.
|
|
78
|
+
*/
|
|
79
|
+
export declare function buildClient(opts: BuildClientOptions): SignDocsBrasilClient;
|
|
80
|
+
/**
|
|
81
|
+
* Build the tool context for the stdio server from environment variables.
|
|
82
|
+
* Credentials are resolved lazily (on first API call); the environment is read
|
|
83
|
+
* eagerly but does not require credentials.
|
|
84
|
+
*/
|
|
85
|
+
export declare function getStdioContext(env?: NodeJS.ProcessEnv): ToolContext;
|
package/dist/client.js
CHANGED
|
@@ -77,4 +77,75 @@ export function resetClientCache() {
|
|
|
77
77
|
export function buildSigningUrl(url, clientSecret) {
|
|
78
78
|
return `${url}?cs=${encodeURIComponent(clientSecret)}`;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* A {@link TokenCache} pre-seeded with a caller-supplied access token. The SDK's
|
|
82
|
+
* AuthHandler checks the cache before exchanging credentials, so seeding it makes
|
|
83
|
+
* the SDK use the presented bearer directly and never call `/oauth2/token`.
|
|
84
|
+
* The SignDocs API remains the real validator — an invalid/expired token yields
|
|
85
|
+
* a 401 from the API, surfaced to the caller.
|
|
86
|
+
*/
|
|
87
|
+
export class StaticTokenCache {
|
|
88
|
+
token;
|
|
89
|
+
constructor(accessToken, ttlMs = 60 * 60 * 1000) {
|
|
90
|
+
this.token = { accessToken, expiresAt: Date.now() + ttlMs };
|
|
91
|
+
}
|
|
92
|
+
get() {
|
|
93
|
+
return this.token;
|
|
94
|
+
}
|
|
95
|
+
set() {
|
|
96
|
+
/* no-op: the token is fixed for this request */
|
|
97
|
+
}
|
|
98
|
+
delete() {
|
|
99
|
+
/* no-op */
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build a fresh, request-scoped SDK client. `credentials` mode lets the SDK run
|
|
104
|
+
* the OAuth2 client_credentials exchange; `bearer` mode passes a pre-issued
|
|
105
|
+
* access token straight through via {@link StaticTokenCache}.
|
|
106
|
+
*/
|
|
107
|
+
export function buildClient(opts) {
|
|
108
|
+
const baseUrl = getBaseUrl(opts.environment, opts.baseUrlOverride);
|
|
109
|
+
const scopes = opts.scopes ?? DEFAULT_SCOPES;
|
|
110
|
+
if (opts.mode === 'bearer') {
|
|
111
|
+
return new SignDocsBrasilClient({
|
|
112
|
+
clientId: 'mcp-bearer-passthrough',
|
|
113
|
+
clientSecret: 'unused', // never used: the token cache short-circuits exchange
|
|
114
|
+
baseUrl,
|
|
115
|
+
scopes,
|
|
116
|
+
tokenCache: new StaticTokenCache(opts.bearer),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return new SignDocsBrasilClient({
|
|
120
|
+
clientId: opts.clientId,
|
|
121
|
+
clientSecret: opts.clientSecret,
|
|
122
|
+
baseUrl,
|
|
123
|
+
scopes,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A client proxy that defers construction until first use, so the stdio server
|
|
128
|
+
* can start and list tools/resources even with no credentials — a missing-cred
|
|
129
|
+
* error surfaces only when a tool actually calls the API.
|
|
130
|
+
*/
|
|
131
|
+
function lazyClient(factory) {
|
|
132
|
+
let instance;
|
|
133
|
+
return new Proxy({}, {
|
|
134
|
+
get(_target, prop, receiver) {
|
|
135
|
+
instance ??= factory();
|
|
136
|
+
return Reflect.get(instance, prop, receiver);
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Build the tool context for the stdio server from environment variables.
|
|
142
|
+
* Credentials are resolved lazily (on first API call); the environment is read
|
|
143
|
+
* eagerly but does not require credentials.
|
|
144
|
+
*/
|
|
145
|
+
export function getStdioContext(env = process.env) {
|
|
146
|
+
return {
|
|
147
|
+
client: lazyClient(() => getClient(env)),
|
|
148
|
+
environment: resolveEnvironment(env.SIGNDOCS_ENVIRONMENT),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
80
151
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/http/server.d.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
+
import { type Server } from 'node:http';
|
|
2
|
+
import { type Environment } from '../client.js';
|
|
1
3
|
/**
|
|
2
|
-
* Phase 2 — remote Streamable-HTTP transport (
|
|
4
|
+
* Phase 2 — remote Streamable-HTTP transport (stateful sessions).
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
+
* One deployment serves many tenants. A session is established on the MCP
|
|
7
|
+
* `initialize` request, which MUST carry credentials:
|
|
8
|
+
* - `Authorization: Bearer <token>` → a SignDocs OAuth2 access token, passed through.
|
|
9
|
+
* - `Authorization: Basic <base64(clientId:clientSecret)>` → server runs client_credentials.
|
|
10
|
+
* Environment via `X-SignDocs-Environment: hml|production` (default = server default).
|
|
6
11
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* await server.connect(transport);
|
|
12
|
-
* // node:http handler → transport.handleRequest(req, res, body)
|
|
12
|
+
* The tenant's SDK client is bound to that session; follow-up requests are routed
|
|
13
|
+
* by the `Mcp-Session-Id` header. Acts as an OAuth Resource Server: advertises the
|
|
14
|
+
* SignDocs authorization server (RFC 9728) and challenges unauthenticated initialize
|
|
15
|
+
* requests with WWW-Authenticate. The SignDocs API is the real token validator.
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* hosted server serves many tenants. The MCP server should act as an
|
|
18
|
-
* OAuth Resource Server: each connecting AI presents its own SignDocs
|
|
19
|
-
* bearer token (issued by the existing /oauth2/token AS). Validate it with
|
|
20
|
-
* the same ES256/KMS verifier external-api uses (auth-middleware.ts) and
|
|
21
|
-
* build a PER-REQUEST SDK client scoped to that tenant — do NOT reuse the
|
|
22
|
-
* process-wide getClient() singleton, which would cross tenant boundaries.
|
|
23
|
-
*
|
|
24
|
-
* 2. DEPLOYMENT. Reuse the external-api Lambda + API Gateway pattern via a new
|
|
25
|
-
* NestedStack (the Core stack is at the CFN 500-resource limit — follow the
|
|
26
|
-
* EnvelopeHandlersStack precedent), or a small container behind the same WAF.
|
|
27
|
-
*
|
|
28
|
-
* 3. SESSION MODE. Stateless (sessionIdGenerator: undefined) fits serverless;
|
|
29
|
-
* confirm against the MCP spec version current at build time, plus DCR /
|
|
30
|
-
* protected-resource metadata discovery needs.
|
|
31
|
-
*
|
|
32
|
-
* Intentionally not wired up yet so the v0.1 stdio package stays dependency-light.
|
|
17
|
+
* Sessions live in process memory, so a single instance (or sticky routing) is
|
|
18
|
+
* assumed. For multi-instance/serverless, front with sticky sessions or swap this
|
|
19
|
+
* map for a shared store + an EventStore for resumability.
|
|
33
20
|
*/
|
|
34
|
-
export
|
|
21
|
+
export interface HttpServerOptions {
|
|
22
|
+
/** Environment when a request doesn't specify one. Default 'hml'. */
|
|
23
|
+
defaultEnvironment?: Environment;
|
|
24
|
+
/** CORS Access-Control-Allow-Origin. Default '*'. */
|
|
25
|
+
corsOrigin?: string;
|
|
26
|
+
/** Public base URL for resource metadata (e.g. https://mcp.signdocs.com.br). Derived from the request if unset. */
|
|
27
|
+
publicUrl?: string;
|
|
28
|
+
/** DNS-rebinding protection — enable in production and pair with allowedHosts/Origins. Default false. */
|
|
29
|
+
enableDnsRebindingProtection?: boolean;
|
|
30
|
+
allowedHosts?: string[];
|
|
31
|
+
allowedOrigins?: string[];
|
|
32
|
+
}
|
|
33
|
+
/** Build (but do not start) the remote HTTP MCP server. Call `.listen(port)`. */
|
|
34
|
+
export declare function createHttpServer(options?: HttpServerOptions): Server;
|
package/dist/http/server.js
CHANGED
|
@@ -1,38 +1,162 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
import { createServer as createNodeHttpServer, } from 'node:http';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
4
|
+
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { createServer as createMcpServer } from '../server.js';
|
|
6
|
+
import { extractAuthFromHeaders, environmentFromHeaders, buildContextForAuth, protectedResourceMetadata as buildProtectedResourceMetadata, wwwAuthenticate, headerValue, UNAUTHORIZED_BODY, } from './shared.js';
|
|
7
|
+
function applyCors(res, opts) {
|
|
8
|
+
res.setHeader('Access-Control-Allow-Origin', opts.corsOrigin);
|
|
9
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
10
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, X-SignDocs-Environment');
|
|
11
|
+
res.setHeader('Access-Control-Expose-Headers', 'Mcp-Session-Id, WWW-Authenticate');
|
|
12
|
+
}
|
|
13
|
+
function sendJson(res, status, body, extra) {
|
|
14
|
+
res.writeHead(status, { 'Content-Type': 'application/json', ...extra });
|
|
15
|
+
res.end(JSON.stringify(body));
|
|
16
|
+
}
|
|
17
|
+
function publicBase(req, opts) {
|
|
18
|
+
if (opts.publicUrl)
|
|
19
|
+
return opts.publicUrl.replace(/\/$/, '');
|
|
20
|
+
const fwd = req.headers['x-forwarded-proto'];
|
|
21
|
+
const proto = (Array.isArray(fwd) ? fwd[0] : fwd)?.split(',')[0] ?? 'http';
|
|
22
|
+
const host = req.headers.host ?? 'localhost';
|
|
23
|
+
return `${proto}://${host}`;
|
|
24
|
+
}
|
|
25
|
+
function challenge(req, res, opts) {
|
|
26
|
+
res.setHeader('WWW-Authenticate', wwwAuthenticate(`${publicBase(req, opts)}/.well-known/oauth-protected-resource`));
|
|
27
|
+
sendJson(res, 401, UNAUTHORIZED_BODY);
|
|
28
|
+
}
|
|
29
|
+
function readBody(req) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const chunks = [];
|
|
32
|
+
req.on('data', (c) => chunks.push(c));
|
|
33
|
+
req.on('end', () => {
|
|
34
|
+
const raw = Buffer.concat(chunks).toString('utf8');
|
|
35
|
+
if (!raw)
|
|
36
|
+
return resolve(undefined);
|
|
37
|
+
try {
|
|
38
|
+
resolve(JSON.parse(raw));
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
reject(err);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
req.on('error', reject);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
async function startSession(req, res, opts, sessions, body) {
|
|
48
|
+
const auth = extractAuthFromHeaders(req.headers);
|
|
49
|
+
if (!auth) {
|
|
50
|
+
challenge(req, res, opts);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const environment = environmentFromHeaders(req.headers, opts.defaultEnvironment);
|
|
54
|
+
const ctx = buildContextForAuth(auth, environment);
|
|
55
|
+
const server = createMcpServer(ctx);
|
|
56
|
+
const transport = new StreamableHTTPServerTransport({
|
|
57
|
+
sessionIdGenerator: () => randomUUID(),
|
|
58
|
+
enableJsonResponse: true,
|
|
59
|
+
enableDnsRebindingProtection: opts.enableDnsRebindingProtection ?? false,
|
|
60
|
+
...(opts.allowedHosts ? { allowedHosts: opts.allowedHosts } : {}),
|
|
61
|
+
...(opts.allowedOrigins ? { allowedOrigins: opts.allowedOrigins } : {}),
|
|
62
|
+
onsessioninitialized: (sid) => {
|
|
63
|
+
sessions.set(sid, { transport, server });
|
|
64
|
+
},
|
|
65
|
+
onsessionclosed: (sid) => {
|
|
66
|
+
sessions.delete(sid);
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
transport.onclose = () => {
|
|
70
|
+
if (transport.sessionId)
|
|
71
|
+
sessions.delete(transport.sessionId);
|
|
72
|
+
};
|
|
73
|
+
await server.connect(transport);
|
|
74
|
+
await transport.handleRequest(req, res, body);
|
|
75
|
+
}
|
|
76
|
+
async function handlePost(req, res, opts, sessions) {
|
|
77
|
+
let body;
|
|
78
|
+
try {
|
|
79
|
+
body = await readBody(req);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
sendJson(res, 400, { error: 'invalid_json', error_description: 'Request body is not valid JSON.' });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const sessionId = headerValue(req.headers, 'mcp-session-id');
|
|
86
|
+
const existing = sessionId ? sessions.get(sessionId) : undefined;
|
|
87
|
+
if (existing) {
|
|
88
|
+
await existing.transport.handleRequest(req, res, body);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (isInitializeRequest(body)) {
|
|
92
|
+
await startSession(req, res, opts, sessions, body);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
sendJson(res, 400, {
|
|
96
|
+
error: 'invalid_session',
|
|
97
|
+
error_description: 'Missing or unknown Mcp-Session-Id. Send an initialize request first.',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async function handle(req, res, opts, sessions) {
|
|
101
|
+
applyCors(res, opts);
|
|
102
|
+
const method = req.method ?? 'GET';
|
|
103
|
+
if (method === 'OPTIONS') {
|
|
104
|
+
res.writeHead(204);
|
|
105
|
+
res.end();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const path = new URL(req.url ?? '/', 'http://localhost').pathname;
|
|
109
|
+
if (method === 'GET' && path === '/healthz') {
|
|
110
|
+
sendJson(res, 200, { status: 'ok', transport: 'streamable-http', sessions: sessions.size });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (method === 'GET' && path === '/.well-known/oauth-protected-resource') {
|
|
114
|
+
sendJson(res, 200, buildProtectedResourceMetadata(`${publicBase(req, opts)}/mcp`, opts.defaultEnvironment));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (path !== '/mcp') {
|
|
118
|
+
sendJson(res, 404, { error: 'not_found' });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (method === 'POST') {
|
|
122
|
+
await handlePost(req, res, opts, sessions);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// GET (SSE stream) and DELETE (session teardown) require an established session.
|
|
126
|
+
if (method === 'GET' || method === 'DELETE') {
|
|
127
|
+
const sessionId = headerValue(req.headers, 'mcp-session-id');
|
|
128
|
+
const session = sessionId ? sessions.get(sessionId) : undefined;
|
|
129
|
+
if (!session) {
|
|
130
|
+
sendJson(res, 400, { error: 'invalid_session', error_description: 'Unknown or missing Mcp-Session-Id.' });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
await session.transport.handleRequest(req, res);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
sendJson(res, 405, { error: 'method_not_allowed' }, { Allow: 'GET, POST, DELETE, OPTIONS' });
|
|
137
|
+
}
|
|
138
|
+
/** Build (but do not start) the remote HTTP MCP server. Call `.listen(port)`. */
|
|
139
|
+
export function createHttpServer(options = {}) {
|
|
140
|
+
const opts = {
|
|
141
|
+
...options,
|
|
142
|
+
defaultEnvironment: options.defaultEnvironment ?? 'hml',
|
|
143
|
+
corsOrigin: options.corsOrigin ?? '*',
|
|
144
|
+
};
|
|
145
|
+
const sessions = new Map();
|
|
146
|
+
return createNodeHttpServer((req, res) => {
|
|
147
|
+
handle(req, res, opts, sessions).catch((err) => {
|
|
148
|
+
try {
|
|
149
|
+
if (!res.headersSent) {
|
|
150
|
+
sendJson(res, 500, { error: 'internal_error', message: err instanceof Error ? err.message : String(err) });
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
res.end();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
/* response already torn down */
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
37
161
|
}
|
|
38
162
|
//# sourceMappingURL=server.js.map
|
package/dist/http/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/http/server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/http/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Environment, type ToolContext } from '../client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Transport-agnostic auth/discovery helpers shared by the long-running HTTP
|
|
4
|
+
* server (http/server.ts) and the Lambda adapter (lambda.ts). Everything here
|
|
5
|
+
* works off a plain header map so it serves both Node IncomingMessage headers
|
|
6
|
+
* and API Gateway event headers.
|
|
7
|
+
*/
|
|
8
|
+
export type AuthResult = {
|
|
9
|
+
mode: 'bearer';
|
|
10
|
+
bearer: string;
|
|
11
|
+
} | {
|
|
12
|
+
mode: 'credentials';
|
|
13
|
+
clientId: string;
|
|
14
|
+
clientSecret: string;
|
|
15
|
+
};
|
|
16
|
+
export type HeaderMap = Record<string, string | string[] | undefined>;
|
|
17
|
+
export declare function headerValue(headers: HeaderMap, name: string): string | undefined;
|
|
18
|
+
/** Parse the Authorization header into a Bearer token or Basic client credentials. */
|
|
19
|
+
export declare function extractAuthFromHeaders(headers: HeaderMap): AuthResult | null;
|
|
20
|
+
/** Resolve the SignDocs environment from the X-SignDocs-Environment header, else fallback. */
|
|
21
|
+
export declare function environmentFromHeaders(headers: HeaderMap, fallback: Environment): Environment;
|
|
22
|
+
/** Build a request-scoped tool context (fresh SDK client) from parsed auth. */
|
|
23
|
+
export declare function buildContextForAuth(auth: AuthResult, environment: Environment): ToolContext;
|
|
24
|
+
/** RFC 9728 protected-resource metadata pointing at the SignDocs authorization server. */
|
|
25
|
+
export declare function protectedResourceMetadata(resourceUrl: string, environment: Environment): Record<string, unknown>;
|
|
26
|
+
/** WWW-Authenticate challenge value pointing a client at the resource metadata. */
|
|
27
|
+
export declare function wwwAuthenticate(metadataUrl: string): string;
|
|
28
|
+
export declare const UNAUTHORIZED_BODY: {
|
|
29
|
+
error: string;
|
|
30
|
+
error_description: string;
|
|
31
|
+
};
|