@signdocs-brasil/mcp-server 0.1.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/LICENSE +21 -0
- package/README.md +121 -0
- package/dist/annotations.d.ts +31 -0
- package/dist/annotations.js +29 -0
- package/dist/annotations.js.map +1 -0
- package/dist/bin/stdio.d.ts +2 -0
- package/dist/bin/stdio.js +19 -0
- package/dist/bin/stdio.js.map +1 -0
- package/dist/client.d.ts +35 -0
- package/dist/client.js +80 -0
- package/dist/client.js.map +1 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +38 -0
- package/dist/http/server.js.map +1 -0
- package/dist/resources.d.ts +2 -0
- package/dist/resources.js +91 -0
- package/dist/resources.js.map +1 -0
- package/dist/schemas.d.ts +179 -0
- package/dist/schemas.js +169 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +38 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/documents.d.ts +2 -0
- package/dist/tools/documents.js +22 -0
- package/dist/tools/documents.js.map +1 -0
- package/dist/tools/envelopes.d.ts +2 -0
- package/dist/tools/envelopes.js +59 -0
- package/dist/tools/envelopes.js.map +1 -0
- package/dist/tools/evidence.d.ts +2 -0
- package/dist/tools/evidence.js +13 -0
- package/dist/tools/evidence.js.map +1 -0
- package/dist/tools/helpers.d.ts +20 -0
- package/dist/tools/helpers.js +33 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/signingSessions.d.ts +2 -0
- package/dist/tools/signingSessions.js +70 -0
- package/dist/tools/signingSessions.js.map +1 -0
- package/dist/tools/transactions.d.ts +2 -0
- package/dist/tools/transactions.js +37 -0
- package/dist/tools/transactions.js.map +1 -0
- package/dist/tools/verify.d.ts +2 -0
- package/dist/tools/verify.js +39 -0
- package/dist/tools/verify.js.map +1 -0
- package/dist/tools/webhooks.d.ts +2 -0
- package/dist/tools/webhooks.js +35 -0
- package/dist/tools/webhooks.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SignDocs Brasil
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# SignDocs Brasil — MCP Server
|
|
2
|
+
|
|
3
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) server for the
|
|
4
|
+
**SignDocs Brasil** e-signature API. It lets MCP-capable AI clients (Claude
|
|
5
|
+
Desktop, Claude Code, Cursor, …) create signing sessions, manage multi-signer
|
|
6
|
+
envelopes, upload/download documents, verify signatures, and manage webhooks —
|
|
7
|
+
the same action catalog as the official n8n, Zapier, and Make.com integrations.
|
|
8
|
+
|
|
9
|
+
It is a thin adapter over the official [`@signdocs-brasil/api`](https://www.npmjs.com/package/@signdocs-brasil/api)
|
|
10
|
+
SDK, which owns OAuth2 token exchange, caching, retries, and error handling.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g @signdocs-brasil/mcp-server # or run on demand with npx
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Credentials
|
|
19
|
+
|
|
20
|
+
Create an API credential in the SignDocs dashboard (app.signdocs.com.br → API)
|
|
21
|
+
and expose it as environment variables:
|
|
22
|
+
|
|
23
|
+
| Variable | Required | Default | Notes |
|
|
24
|
+
|---|---|---|---|
|
|
25
|
+
| `SIGNDOCS_CLIENT_ID` | yes | — | OAuth2 client id |
|
|
26
|
+
| `SIGNDOCS_CLIENT_SECRET` | yes | — | OAuth2 client secret |
|
|
27
|
+
| `SIGNDOCS_ENVIRONMENT` | no | `hml` | `hml` (staging) or `production` |
|
|
28
|
+
| `SIGNDOCS_BASE_URL` | no | derived | override the resolved base URL |
|
|
29
|
+
| `SIGNDOCS_SCOPES` | no | full set | space-separated scope override |
|
|
30
|
+
|
|
31
|
+
> Start in `hml`. HML data expires after ~7 days and is safe for testing.
|
|
32
|
+
> Switch to `production` only when you intend to create real, legally-binding
|
|
33
|
+
> signatures.
|
|
34
|
+
|
|
35
|
+
## Connect an AI client
|
|
36
|
+
|
|
37
|
+
**Claude Desktop** (`claude_desktop_config.json`):
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"signdocs": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "@signdocs-brasil/mcp-server"],
|
|
45
|
+
"env": {
|
|
46
|
+
"SIGNDOCS_CLIENT_ID": "your_client_id",
|
|
47
|
+
"SIGNDOCS_CLIENT_SECRET": "your_client_secret",
|
|
48
|
+
"SIGNDOCS_ENVIRONMENT": "hml"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Claude Code**:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
claude mcp add signdocs \
|
|
59
|
+
-e SIGNDOCS_CLIENT_ID=your_client_id \
|
|
60
|
+
-e SIGNDOCS_CLIENT_SECRET=your_client_secret \
|
|
61
|
+
-e SIGNDOCS_ENVIRONMENT=hml \
|
|
62
|
+
-- npx -y @signdocs-brasil/mcp-server
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Tools
|
|
66
|
+
|
|
67
|
+
| Tool | Action | Safety |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `create_signing_session` | Create single-signer session, returns `signingUrl` | ⚠️ binding + quota |
|
|
70
|
+
| `get_signing_session_status` | Poll session status | read |
|
|
71
|
+
| `get_signing_session` | Full session bootstrap | read |
|
|
72
|
+
| `list_signing_sessions` | List by status | read |
|
|
73
|
+
| `cancel_signing_session` | Cancel a session | ⚠️ irreversible |
|
|
74
|
+
| `resend_signing_session_otp` | Resend OTP | write |
|
|
75
|
+
| `create_envelope` | Multi-signer envelope | ⚠️ binding + quota |
|
|
76
|
+
| `get_envelope` | Envelope details | read |
|
|
77
|
+
| `add_session_to_envelope` | Add a signer, returns `signingUrl` | ⚠️ binding + quota |
|
|
78
|
+
| `get_envelope_combined_stamp` | Combined stamped PDF URL | read |
|
|
79
|
+
| `upload_document` | Attach a PDF to a transaction | write |
|
|
80
|
+
| `download_document` | Presigned download URLs | read |
|
|
81
|
+
| `list_transactions` | Search/list transactions | read |
|
|
82
|
+
| `get_transaction` | Transaction details | read |
|
|
83
|
+
| `cancel_transaction` | Cancel a transaction | ⚠️ irreversible |
|
|
84
|
+
| `get_evidence` | Cryptographic evidence | read |
|
|
85
|
+
| `verify_evidence` | Public evidence verification | read |
|
|
86
|
+
| `verify_envelope` | Public envelope verification | read |
|
|
87
|
+
| `verify_document` | Detect signatures in a PDF | ⚠️ PROD-only + quota |
|
|
88
|
+
| `register_webhook` / `list_webhooks` / `delete_webhook` / `test_webhook` | Webhook management | mixed |
|
|
89
|
+
|
|
90
|
+
⚠️ tools carry `destructiveHint` annotations **and** a warning in their
|
|
91
|
+
description so compliant clients prompt the human before invoking them.
|
|
92
|
+
Annotations are only hints — review your client's auto-approval settings.
|
|
93
|
+
|
|
94
|
+
### Not yet exposed
|
|
95
|
+
Trust sessions (`/v1/trust-sessions`) and `resend-invite` are not in
|
|
96
|
+
`@signdocs-brasil/api` v1.6.1 yet; they'll be added when the SDK supports them.
|
|
97
|
+
Digital ICP-Brasil A1 signing runs through the lower-level transaction/advance
|
|
98
|
+
flow rather than a hosted-session profile.
|
|
99
|
+
|
|
100
|
+
## Resources
|
|
101
|
+
|
|
102
|
+
The server exposes grounding resources the model can read on demand:
|
|
103
|
+
|
|
104
|
+
- `signdocs://quickstart` — the minimal signing flow + safety notes
|
|
105
|
+
- `signdocs://policy-profiles` — valid `policyProfile` values and CUSTOM steps
|
|
106
|
+
- `signdocs://webhook-events` — all subscribable event types
|
|
107
|
+
|
|
108
|
+
## Development
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npm install
|
|
112
|
+
npm run build # tsc → dist/
|
|
113
|
+
npm test # vitest (pure unit tests, no network)
|
|
114
|
+
npm run inspect # build + launch MCP Inspector against the stdio server
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Roadmap
|
|
118
|
+
|
|
119
|
+
- **v0.1 (this release):** local stdio server, full tool catalog, env credentials.
|
|
120
|
+
- **Phase 2:** remote Streamable-HTTP transport with per-tenant OAuth (the tool
|
|
121
|
+
layer is already transport-agnostic — see `src/http/server.ts`).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool annotation presets. These are *hints* — clients MAY use them to
|
|
3
|
+
* decide whether to auto-run a tool or prompt the human first. Because not
|
|
4
|
+
* every client honors them, binding/quota tools ALSO carry an explicit warning
|
|
5
|
+
* sentence in their `description` (see tools/*.ts).
|
|
6
|
+
*
|
|
7
|
+
* @see https://modelcontextprotocol.io/specification — Tool annotations
|
|
8
|
+
*/
|
|
9
|
+
export interface ToolAnnotations {
|
|
10
|
+
title?: string;
|
|
11
|
+
/** Tool does not modify state. */
|
|
12
|
+
readOnlyHint?: boolean;
|
|
13
|
+
/** Tool may perform irreversible / consequential changes → clients should confirm. */
|
|
14
|
+
destructiveHint?: boolean;
|
|
15
|
+
/** Repeated identical calls have no additional effect. */
|
|
16
|
+
idempotentHint?: boolean;
|
|
17
|
+
/** Tool talks to an external system (always true here — it's a remote API). */
|
|
18
|
+
openWorldHint?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Pure reads (status, get, list, public verification). */
|
|
21
|
+
export declare const READ_ONLY: ToolAnnotations;
|
|
22
|
+
/** Writes that are not legally binding nor irreversible (upload, resend OTP, register webhook). */
|
|
23
|
+
export declare const WRITE_SAFE: ToolAnnotations;
|
|
24
|
+
/**
|
|
25
|
+
* Legally-binding, quota-consuming, or irreversible actions
|
|
26
|
+
* (create signing session/envelope, cancel, verify-document).
|
|
27
|
+
* Clients SHOULD prompt the human before invoking.
|
|
28
|
+
*/
|
|
29
|
+
export declare const DESTRUCTIVE: ToolAnnotations;
|
|
30
|
+
/** Prefix prepended to descriptions of binding/quota tools so even annotation-blind clients surface the risk. */
|
|
31
|
+
export declare const CONFIRM_WARNING: string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Pure reads (status, get, list, public verification). */
|
|
2
|
+
export const READ_ONLY = {
|
|
3
|
+
readOnlyHint: true,
|
|
4
|
+
destructiveHint: false,
|
|
5
|
+
idempotentHint: true,
|
|
6
|
+
openWorldHint: true,
|
|
7
|
+
};
|
|
8
|
+
/** Writes that are not legally binding nor irreversible (upload, resend OTP, register webhook). */
|
|
9
|
+
export const WRITE_SAFE = {
|
|
10
|
+
readOnlyHint: false,
|
|
11
|
+
destructiveHint: false,
|
|
12
|
+
idempotentHint: false,
|
|
13
|
+
openWorldHint: true,
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Legally-binding, quota-consuming, or irreversible actions
|
|
17
|
+
* (create signing session/envelope, cancel, verify-document).
|
|
18
|
+
* Clients SHOULD prompt the human before invoking.
|
|
19
|
+
*/
|
|
20
|
+
export const DESTRUCTIVE = {
|
|
21
|
+
readOnlyHint: false,
|
|
22
|
+
destructiveHint: true,
|
|
23
|
+
idempotentHint: false,
|
|
24
|
+
openWorldHint: true,
|
|
25
|
+
};
|
|
26
|
+
/** Prefix prepended to descriptions of binding/quota tools so even annotation-blind clients surface the risk. */
|
|
27
|
+
export const CONFIRM_WARNING = '⚠️ This performs a consequential, possibly irreversible action (legally-binding signature ' +
|
|
28
|
+
'request and/or quota consumption). Confirm with the human before calling. ';
|
|
29
|
+
//# sourceMappingURL=annotations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotations.js","sourceRoot":"","sources":["../src/annotations.ts"],"names":[],"mappings":"AAoBA,2DAA2D;AAC3D,MAAM,CAAC,MAAM,SAAS,GAAoB;IACxC,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,IAAI;CACpB,CAAC;AAEF,mGAAmG;AACnG,MAAM,CAAC,MAAM,UAAU,GAAoB;IACzC,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,IAAI;CACpB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAoB;IAC1C,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,IAAI;CACpB,CAAC;AAEF,iHAAiH;AACjH,MAAM,CAAC,MAAM,eAAe,GAC1B,4FAA4F;IAC5F,4EAA4E,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createServer } from '../server.js';
|
|
4
|
+
/**
|
|
5
|
+
* stdio entrypoint. AI clients (Claude Desktop/Code, Cursor, …) launch this
|
|
6
|
+
* binary and speak MCP over stdin/stdout. NEVER write to stdout here — it is
|
|
7
|
+
* the protocol channel; diagnostics go to stderr.
|
|
8
|
+
*/
|
|
9
|
+
async function main() {
|
|
10
|
+
const server = createServer();
|
|
11
|
+
const transport = new StdioServerTransport();
|
|
12
|
+
await server.connect(transport);
|
|
13
|
+
process.stderr.write('[signdocs-mcp] server started on stdio\n');
|
|
14
|
+
}
|
|
15
|
+
main().catch((err) => {
|
|
16
|
+
process.stderr.write(`[signdocs-mcp] fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +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;AAE5C;;;;GAIG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,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
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SignDocsBrasilClient } from '@signdocs-brasil/api';
|
|
2
|
+
/**
|
|
3
|
+
* Thin wrapper that turns environment variables into a configured
|
|
4
|
+
* {@link SignDocsBrasilClient}. The official SDK owns the OAuth2
|
|
5
|
+
* `client_credentials` exchange, token caching, retries and RFC-7807
|
|
6
|
+
* error parsing — this module only resolves config and memoizes the client.
|
|
7
|
+
*/
|
|
8
|
+
export type Environment = 'production' | 'hml';
|
|
9
|
+
/**
|
|
10
|
+
* Full read/write scope set. `verification:write` is only authorized for
|
|
11
|
+
* PRODUCTION credentials, but the token endpoint silently filters out any
|
|
12
|
+
* scope the credential isn't entitled to, so requesting it everywhere is safe.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_SCOPES: string[];
|
|
15
|
+
export interface ResolvedEnv {
|
|
16
|
+
clientId: string;
|
|
17
|
+
clientSecret: string;
|
|
18
|
+
environment: Environment;
|
|
19
|
+
baseUrl: string;
|
|
20
|
+
scopes: string[];
|
|
21
|
+
}
|
|
22
|
+
export declare function resolveEnvironment(raw?: string): Environment;
|
|
23
|
+
export declare function getBaseUrl(environment: Environment, override?: string): string;
|
|
24
|
+
export declare function readEnv(env?: NodeJS.ProcessEnv): ResolvedEnv;
|
|
25
|
+
/** Lazily build and memoize the SDK client. Throws if credentials are missing. */
|
|
26
|
+
export declare function getClient(env?: NodeJS.ProcessEnv): SignDocsBrasilClient;
|
|
27
|
+
/** The resolved environment behind the active client (for diagnostics/guards). */
|
|
28
|
+
export declare function getResolvedEnv(env?: NodeJS.ProcessEnv): ResolvedEnv;
|
|
29
|
+
/** Reset memoized state — used by tests. */
|
|
30
|
+
export declare function resetClientCache(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Assemble the shareable signing link. A session's `url` alone is NOT the
|
|
33
|
+
* link — it must carry the one-time embed token (`clientSecret`) as `?cs=`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildSigningUrl(url: string, clientSecret: string): string;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { SignDocsBrasilClient } from '@signdocs-brasil/api';
|
|
2
|
+
const BASE_URLS = {
|
|
3
|
+
production: 'https://api.signdocs.com.br',
|
|
4
|
+
// NOTE: HML uses the dash form (api-hml), NOT api.hml.
|
|
5
|
+
hml: 'https://api-hml.signdocs.com.br',
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Full read/write scope set. `verification:write` is only authorized for
|
|
9
|
+
* PRODUCTION credentials, but the token endpoint silently filters out any
|
|
10
|
+
* scope the credential isn't entitled to, so requesting it everywhere is safe.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_SCOPES = [
|
|
13
|
+
'transactions:read',
|
|
14
|
+
'transactions:write',
|
|
15
|
+
'steps:write',
|
|
16
|
+
'evidence:read',
|
|
17
|
+
'webhooks:write',
|
|
18
|
+
'verification:write',
|
|
19
|
+
];
|
|
20
|
+
export function resolveEnvironment(raw) {
|
|
21
|
+
const v = (raw ?? 'hml').trim().toLowerCase();
|
|
22
|
+
if (v === 'production' || v === 'prod')
|
|
23
|
+
return 'production';
|
|
24
|
+
if (v === 'hml' || v === 'homologacao' || v === 'homologação' || v === 'staging')
|
|
25
|
+
return 'hml';
|
|
26
|
+
throw new Error(`Invalid SIGNDOCS_ENVIRONMENT "${raw}". Use "production" or "hml".`);
|
|
27
|
+
}
|
|
28
|
+
export function getBaseUrl(environment, override) {
|
|
29
|
+
const trimmed = override?.trim();
|
|
30
|
+
return trimmed ? trimmed : BASE_URLS[environment];
|
|
31
|
+
}
|
|
32
|
+
export function readEnv(env = process.env) {
|
|
33
|
+
const clientId = env.SIGNDOCS_CLIENT_ID?.trim();
|
|
34
|
+
const clientSecret = env.SIGNDOCS_CLIENT_SECRET?.trim();
|
|
35
|
+
if (!clientId || !clientSecret) {
|
|
36
|
+
throw new Error('Missing SignDocs credentials. Set SIGNDOCS_CLIENT_ID and SIGNDOCS_CLIENT_SECRET ' +
|
|
37
|
+
'(get them from app.signdocs.com.br → API).');
|
|
38
|
+
}
|
|
39
|
+
const environment = resolveEnvironment(env.SIGNDOCS_ENVIRONMENT);
|
|
40
|
+
const baseUrl = getBaseUrl(environment, env.SIGNDOCS_BASE_URL);
|
|
41
|
+
const scopesRaw = env.SIGNDOCS_SCOPES?.trim();
|
|
42
|
+
const scopes = scopesRaw ? scopesRaw.split(/\s+/) : DEFAULT_SCOPES;
|
|
43
|
+
return { clientId, clientSecret, environment, baseUrl, scopes };
|
|
44
|
+
}
|
|
45
|
+
let cached;
|
|
46
|
+
let cachedEnv;
|
|
47
|
+
/** Lazily build and memoize the SDK client. Throws if credentials are missing. */
|
|
48
|
+
export function getClient(env = process.env) {
|
|
49
|
+
if (cached)
|
|
50
|
+
return cached;
|
|
51
|
+
const cfg = readEnv(env);
|
|
52
|
+
cachedEnv = cfg;
|
|
53
|
+
cached = new SignDocsBrasilClient({
|
|
54
|
+
clientId: cfg.clientId,
|
|
55
|
+
clientSecret: cfg.clientSecret,
|
|
56
|
+
baseUrl: cfg.baseUrl,
|
|
57
|
+
scopes: cfg.scopes,
|
|
58
|
+
});
|
|
59
|
+
return cached;
|
|
60
|
+
}
|
|
61
|
+
/** The resolved environment behind the active client (for diagnostics/guards). */
|
|
62
|
+
export function getResolvedEnv(env = process.env) {
|
|
63
|
+
if (cachedEnv)
|
|
64
|
+
return cachedEnv;
|
|
65
|
+
cachedEnv = readEnv(env);
|
|
66
|
+
return cachedEnv;
|
|
67
|
+
}
|
|
68
|
+
/** Reset memoized state — used by tests. */
|
|
69
|
+
export function resetClientCache() {
|
|
70
|
+
cached = undefined;
|
|
71
|
+
cachedEnv = undefined;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Assemble the shareable signing link. A session's `url` alone is NOT the
|
|
75
|
+
* link — it must carry the one-time embed token (`clientSecret`) as `?cs=`.
|
|
76
|
+
*/
|
|
77
|
+
export function buildSigningUrl(url, clientSecret) {
|
|
78
|
+
return `${url}?cs=${encodeURIComponent(clientSecret)}`;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAW5D,MAAM,SAAS,GAAgC;IAC7C,UAAU,EAAE,6BAA6B;IACzC,uDAAuD;IACvD,GAAG,EAAE,iCAAiC;CACvC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,mBAAmB;IACnB,oBAAoB;IACpB,aAAa;IACb,eAAe;IACf,gBAAgB;IAChB,oBAAoB;CACrB,CAAC;AAUF,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,CAAC,KAAK,YAAY,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,YAAY,CAAC;IAC5D,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC/F,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,+BAA+B,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAwB,EAAE,QAAiB;IACpE,MAAM,OAAO,GAAG,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjC,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC1D,MAAM,QAAQ,GAAG,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IAChD,MAAM,YAAY,GAAG,GAAG,CAAC,sBAAsB,EAAE,IAAI,EAAE,CAAC;IACxD,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACb,kFAAkF;YAChF,4CAA4C,CAC/C,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,kBAAkB,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;IACnE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAClE,CAAC;AAED,IAAI,MAAwC,CAAC;AAC7C,IAAI,SAAkC,CAAC;AAEvC,kFAAkF;AAClF,MAAM,UAAU,SAAS,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC5D,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACzB,SAAS,GAAG,GAAG,CAAC;IAChB,MAAM,GAAG,IAAI,oBAAoB,CAAC;QAChC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,GAAG,CAAC,MAAM;KACnB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,MAAyB,OAAO,CAAC,GAAG;IACjE,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAChC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACzB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,SAAS,CAAC;IACnB,SAAS,GAAG,SAAS,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,YAAoB;IAC/D,OAAO,GAAG,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAC,EAAE,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 — remote Streamable-HTTP transport (designed, not yet built).
|
|
3
|
+
*
|
|
4
|
+
* The tool/resource layer in ../server.ts is deliberately transport-agnostic,
|
|
5
|
+
* so going remote is purely an entrypoint + auth concern:
|
|
6
|
+
*
|
|
7
|
+
* import { StreamableHTTPServerTransport } from
|
|
8
|
+
* '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
9
|
+
* const server = createServer();
|
|
10
|
+
* const transport = new StreamableHTTPServerTransport({ ...});
|
|
11
|
+
* await server.connect(transport);
|
|
12
|
+
* // node:http handler → transport.handleRequest(req, res, body)
|
|
13
|
+
*
|
|
14
|
+
* Open design decisions to settle before implementing (see plan):
|
|
15
|
+
*
|
|
16
|
+
* 1. AUTH / MULTI-TENANCY. Unlike stdio (one set of env credentials), a
|
|
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.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createHttpServer(): never;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 — remote Streamable-HTTP transport (designed, not yet built).
|
|
3
|
+
*
|
|
4
|
+
* The tool/resource layer in ../server.ts is deliberately transport-agnostic,
|
|
5
|
+
* so going remote is purely an entrypoint + auth concern:
|
|
6
|
+
*
|
|
7
|
+
* import { StreamableHTTPServerTransport } from
|
|
8
|
+
* '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
9
|
+
* const server = createServer();
|
|
10
|
+
* const transport = new StreamableHTTPServerTransport({ ...});
|
|
11
|
+
* await server.connect(transport);
|
|
12
|
+
* // node:http handler → transport.handleRequest(req, res, body)
|
|
13
|
+
*
|
|
14
|
+
* Open design decisions to settle before implementing (see plan):
|
|
15
|
+
*
|
|
16
|
+
* 1. AUTH / MULTI-TENANCY. Unlike stdio (one set of env credentials), a
|
|
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.
|
|
33
|
+
*/
|
|
34
|
+
export function createHttpServer() {
|
|
35
|
+
throw new Error('Remote HTTP transport is not implemented in v0.1. Use the stdio entrypoint (bin/stdio.ts). ' +
|
|
36
|
+
'See src/http/server.ts for the Phase 2 design.');
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/http/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,IAAI,KAAK,CACb,6FAA6F;QAC3F,gDAAgD,CACnD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static MCP resources that ground the agent so it calls tools correctly
|
|
3
|
+
* without guessing. Content is inlined (no filesystem/sibling-repo coupling)
|
|
4
|
+
* so the published package is self-contained.
|
|
5
|
+
*/
|
|
6
|
+
const POLICY_PROFILES = `# SignDocs policy profiles
|
|
7
|
+
|
|
8
|
+
Pass one of these as \`policyProfile\` when creating a signing session or
|
|
9
|
+
adding an envelope signer. An invalid value returns HTTP 400.
|
|
10
|
+
|
|
11
|
+
| profile | steps | typical use |
|
|
12
|
+
|-----------------------|-----------------------------------------|-------------|
|
|
13
|
+
| CLICK_ONLY | clickwrap acceptance | low-risk consent |
|
|
14
|
+
| CLICK_PLUS_OTP | clickwrap + e-mail/SMS one-time code | standard e-signature |
|
|
15
|
+
| BIOMETRIC | facial liveness + match | high-assurance identity |
|
|
16
|
+
| BIOMETRIC_PLUS_OTP | biometric + OTP | strongest hosted assurance |
|
|
17
|
+
| CUSTOM | caller-defined ordered steps | supply \`customSteps\` |
|
|
18
|
+
|
|
19
|
+
When \`policyProfile=CUSTOM\`, set \`customSteps\` to an ordered list of step
|
|
20
|
+
types, e.g. ["CLICKWRAP","OTP","BIOMETRIC_LIVENESS","BIOMETRIC_MATCH"].
|
|
21
|
+
|
|
22
|
+
Digital ICP-Brasil A1 certificate signing is exposed through the transaction/
|
|
23
|
+
advance flow (step type DIGITAL_CERTIFICATE), not as a hosted-session profile.
|
|
24
|
+
`;
|
|
25
|
+
const QUICKSTART = `# SignDocs MCP quickstart
|
|
26
|
+
|
|
27
|
+
Most integrations need only the high-level **signing session** flow:
|
|
28
|
+
|
|
29
|
+
1. \`create_signing_session\` with purpose=DOCUMENT_SIGNATURE, a policyProfile,
|
|
30
|
+
the signer, and the base64 PDF (\`documentBase64\`). The result includes a
|
|
31
|
+
ready-to-share **signingUrl** (the session url + one-time embed token).
|
|
32
|
+
2. Deliver the signingUrl to the signer (or pass \`owner.email\` so SignDocs
|
|
33
|
+
e-mails them automatically), or subscribe to webhooks for completion.
|
|
34
|
+
3. Poll \`get_signing_session_status\` (or rely on webhooks) until COMPLETED.
|
|
35
|
+
4. The COMPLETED status carries an \`evidenceId\` — verify it publicly with
|
|
36
|
+
\`verify_evidence\`.
|
|
37
|
+
|
|
38
|
+
Multiple signers on one document → use \`create_envelope\` then
|
|
39
|
+
\`add_session_to_envelope\` once per signer (signerIndex 0..N-1).
|
|
40
|
+
|
|
41
|
+
Environment: set SIGNDOCS_ENVIRONMENT=hml (default) for testing or
|
|
42
|
+
=production for live, binding signatures. HML data expires after ~7 days and
|
|
43
|
+
the verify_document tool is production-only.
|
|
44
|
+
|
|
45
|
+
⚠️ create_/add_/cancel_ tools take real, quota-consuming, often
|
|
46
|
+
legally-binding actions. Confirm with the human before invoking them.
|
|
47
|
+
`;
|
|
48
|
+
const WEBHOOK_EVENTS = `# SignDocs webhook events
|
|
49
|
+
|
|
50
|
+
Subscribe via \`register_webhook\`. Payloads are signed with HMAC-SHA256 using
|
|
51
|
+
the secret returned at registration (300s replay tolerance).
|
|
52
|
+
|
|
53
|
+
TRANSACTION.CREATED, TRANSACTION.COMPLETED, TRANSACTION.CANCELLED,
|
|
54
|
+
TRANSACTION.FAILED, TRANSACTION.EXPIRED
|
|
55
|
+
STEP.STARTED, STEP.COMPLETED, STEP.FAILED
|
|
56
|
+
SIGNING_SESSION.CREATED, SIGNING_SESSION.COMPLETED, SIGNING_SESSION.CANCELLED,
|
|
57
|
+
SIGNING_SESSION.EXPIRED
|
|
58
|
+
ENVELOPE.CREATED, ENVELOPE.ALL_SIGNED, ENVELOPE.EXPIRED
|
|
59
|
+
QUOTA.WARNING, API.DEPRECATION_NOTICE
|
|
60
|
+
`;
|
|
61
|
+
const RESOURCES = [
|
|
62
|
+
{
|
|
63
|
+
uri: 'signdocs://policy-profiles',
|
|
64
|
+
name: 'policy-profiles',
|
|
65
|
+
title: 'SignDocs policy profiles',
|
|
66
|
+
description: 'Valid policyProfile values and CUSTOM step types.',
|
|
67
|
+
text: POLICY_PROFILES,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
uri: 'signdocs://quickstart',
|
|
71
|
+
name: 'quickstart',
|
|
72
|
+
title: 'SignDocs MCP quickstart',
|
|
73
|
+
description: 'The minimal signing-session flow and safety notes.',
|
|
74
|
+
text: QUICKSTART,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
uri: 'signdocs://webhook-events',
|
|
78
|
+
name: 'webhook-events',
|
|
79
|
+
title: 'SignDocs webhook events',
|
|
80
|
+
description: 'All subscribable webhook event types.',
|
|
81
|
+
text: WEBHOOK_EVENTS,
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
export function registerResources(server) {
|
|
85
|
+
for (const r of RESOURCES) {
|
|
86
|
+
server.registerResource(r.name, r.uri, { title: r.title, description: r.description, mimeType: 'text/markdown' }, async (uri) => ({
|
|
87
|
+
contents: [{ uri: uri.href, mimeType: 'text/markdown', text: r.text }],
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;CAkBvB,CAAC;AAEF,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBlB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;CAYtB,CAAC;AAUF,MAAM,SAAS,GAAqB;IAClC;QACE,GAAG,EAAE,4BAA4B;QACjC,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,0BAA0B;QACjC,WAAW,EAAE,mDAAmD;QAChE,IAAI,EAAE,eAAe;KACtB;IACD;QACE,GAAG,EAAE,uBAAuB;QAC5B,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE,oDAAoD;QACjE,IAAI,EAAE,UAAU;KACjB;IACD;QACE,GAAG,EAAE,2BAA2B;QAChC,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE,uCAAuC;QACpD,IAAI,EAAE,cAAc;KACrB;CACF,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,gBAAgB,CACrB,CAAC,CAAC,IAAI,EACN,CAAC,CAAC,GAAG,EACL,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,EACzE,KAAK,EAAE,GAAQ,EAAE,EAAE,CAAC,CAAC;YACnB,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;SACvE,CAAC,CACH,CAAC;IACJ,CAAC;AACH,CAAC"}
|