@useyona/einvoice-mcp 0.0.0-stage → 0.1.1
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 +201 -2
- package/bin/cli.js +2 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +73 -0
- package/dist/cli.js.map +1 -0
- package/dist/http.d.ts +16 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +41 -0
- package/dist/http.js.map +1 -0
- package/dist/idempotency.d.ts +16 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +31 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +5 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +72 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +16 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +65 -0
- package/dist/resources.js.map +1 -0
- package/dist/result.d.ts +42 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +83 -0
- package/dist/result.js.map +1 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +68 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/index.d.ts +34 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +284 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/schemas.d.ts +877 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +192 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +82 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elyonar
|
|
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
CHANGED
|
@@ -1,3 +1,202 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @useyona/einvoice-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The [Model Context Protocol](https://modelcontextprotocol.io) server for the Yona e-invoicing API. It lets an AI
|
|
4
|
+
assistant (Claude, Cursor, VS Code, Muse and any MCP client) create buyers and invoices, validate them, report them to
|
|
5
|
+
the tax authority and follow their status, with the same API key an integration uses.
|
|
6
|
+
|
|
7
|
+
It runs on your machine over stdio (`npx @useyona/einvoice-mcp`). A hosted endpoint is coming soon.
|
|
8
|
+
|
|
9
|
+
## Before you start
|
|
10
|
+
|
|
11
|
+
- Node.js 20 or later.
|
|
12
|
+
- A Yona API key from the dashboard (API keys). Start with a **sandbox** key (`sk_test_…`): sandbox submissions go to
|
|
13
|
+
the tax authority's test environment and spend sandbox credits only. The key's capabilities decide which tools
|
|
14
|
+
succeed; the `full_integration` preset is the usual choice.
|
|
15
|
+
|
|
16
|
+
## Install and configure
|
|
17
|
+
|
|
18
|
+
The server reads its configuration from the environment:
|
|
19
|
+
|
|
20
|
+
| Variable | Required | Meaning |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `YONA_API_KEY` | yes | Your API key, `sk_test_…` (sandbox) or `sk_live_…` (live). A missing or malformed key stops the server with a message. |
|
|
23
|
+
| `YONA_ALLOW_LIVE` | no | `true` to allow a live key. Without it a live key is refused at start. |
|
|
24
|
+
| `YONA_BASE_URL` | no | Another API host, for testing against a local gateway. Leave it unset. |
|
|
25
|
+
|
|
26
|
+
Keep the key out of shared files: put it in your client's secret or environment settings where it offers one.
|
|
27
|
+
|
|
28
|
+
### Claude Desktop
|
|
29
|
+
|
|
30
|
+
`claude_desktop_config.json` (Settings → Developer → Edit Config):
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"yona": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "@useyona/einvoice-mcp"],
|
|
38
|
+
"env": { "YONA_API_KEY": "sk_test_…" }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Restart Claude Desktop after saving.
|
|
45
|
+
|
|
46
|
+
### Claude Code
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
claude mcp add yona --env YONA_API_KEY=sk_test_… -- npx -y @useyona/einvoice-mcp
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Cursor
|
|
53
|
+
|
|
54
|
+
`~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (one project):
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"yona": {
|
|
60
|
+
"command": "npx",
|
|
61
|
+
"args": ["-y", "@useyona/einvoice-mcp"],
|
|
62
|
+
"env": { "YONA_API_KEY": "sk_test_…" }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### VS Code
|
|
69
|
+
|
|
70
|
+
`.vscode/mcp.json`; VS Code asks for the key once and stores it as a secret:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"inputs": [
|
|
75
|
+
{ "type": "promptString", "id": "yona-api-key", "description": "Yona API key", "password": true }
|
|
76
|
+
],
|
|
77
|
+
"servers": {
|
|
78
|
+
"yona": {
|
|
79
|
+
"type": "stdio",
|
|
80
|
+
"command": "npx",
|
|
81
|
+
"args": ["-y", "@useyona/einvoice-mcp"],
|
|
82
|
+
"env": { "YONA_API_KEY": "${input:yona-api-key}" }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Muse Code
|
|
89
|
+
|
|
90
|
+
`~/.config/muse/settings.json`:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"mcp_servers": {
|
|
95
|
+
"yona": {
|
|
96
|
+
"command": "npx",
|
|
97
|
+
"args": ["-y", "@useyona/einvoice-mcp"],
|
|
98
|
+
"env": { "YONA_API_KEY": "sk_test_…" }
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Hosted (coming soon)
|
|
105
|
+
|
|
106
|
+
A hosted endpoint will serve the same tools over streamable HTTP, with nothing to install:
|
|
107
|
+
|
|
108
|
+
- URL: `https://gp.useyona.com/mcp`
|
|
109
|
+
- Header: `Authorization: Bearer sk_test_…`
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Claude Code, once the endpoint is live
|
|
113
|
+
claude mcp add --transport http yona https://gp.useyona.com/mcp --header "Authorization: Bearer sk_test_…"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
It is not live yet; use the local server until this section says otherwise.
|
|
117
|
+
|
|
118
|
+
## Tools
|
|
119
|
+
|
|
120
|
+
| Tool | What it does | Kind |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `get_organization` | The key's organisation: profile and readiness to report invoices | read |
|
|
123
|
+
| `lookup_tin` | Looks up a tax id with the tax authority | charged |
|
|
124
|
+
| `search_buyers` | Lists saved buyers, by text or verification status | read |
|
|
125
|
+
| `get_buyer` | One buyer | read |
|
|
126
|
+
| `create_buyer` | Saves a buyer | write, charged |
|
|
127
|
+
| `search_items` | Lists saved goods and services | read |
|
|
128
|
+
| `create_item` | Saves a good or service | write |
|
|
129
|
+
| `list_invoices` | Lists invoices, by status, payment status, buyer, date or text | read |
|
|
130
|
+
| `get_invoice` | One invoice | read |
|
|
131
|
+
| `create_invoice` | Creates a **draft** invoice | write, charged |
|
|
132
|
+
| `update_invoice` | Changes a draft | write |
|
|
133
|
+
| `validate_invoice` | Checks a draft or a document with the tax authority's rules, storing nothing | charged |
|
|
134
|
+
| `finalise_invoice` | Freezes a draft for submission | write |
|
|
135
|
+
| `submit_invoice` | Reports an invoice to the tax authority | **destructive**, charged |
|
|
136
|
+
| `get_submission_status` | Where a report stands: accepted, rejected, parked and why | read |
|
|
137
|
+
| `cancel_invoice` | Cancels an issued invoice | **destructive** |
|
|
138
|
+
| `issue_credit_note` | Credits a reported invoice in full, by lines or by amount | **destructive**, charged |
|
|
139
|
+
| `get_download_link` | A short-lived link to the invoice PDF | charged |
|
|
140
|
+
| `create_share_link` | A revocable public link to view an invoice | write |
|
|
141
|
+
| `list_received_invoices` | Invoices other businesses issued to you | read |
|
|
142
|
+
| `get_received_invoice` | One received invoice | read |
|
|
143
|
+
| `get_balance` | The credit balance for the key's mode | read |
|
|
144
|
+
| `list_webhook_deliveries` | Webhook deliveries to your endpoints, to debug an integration | read |
|
|
145
|
+
|
|
146
|
+
**Resources:** `yona://reference/tax-categories`, `yona://reference/units`, `yona://reference/hs-codes` (search with
|
|
147
|
+
`?q=laptop`), `yona://organization`.
|
|
148
|
+
|
|
149
|
+
**Prompts:** `draft_invoice` (a validated draft from a plain description), `explain_rejection` (why the tax authority
|
|
150
|
+
did not accept an invoice, in plain words).
|
|
151
|
+
|
|
152
|
+
A typical session: *"Invoice Acme Ltd for 2 laptops at ₦850,000 each"* → `search_buyers` → `create_invoice` →
|
|
153
|
+
`validate_invoice` → you review → `finalise_invoice` → `submit_invoice` (after you approve) → `get_submission_status`.
|
|
154
|
+
|
|
155
|
+
## Safety
|
|
156
|
+
|
|
157
|
+
- **Mode in every result.** Each tool result carries `"mode": "sandbox"` or `"live"`, so the assistant always knows
|
|
158
|
+
whether an action is real.
|
|
159
|
+
- **Live is opt-in.** A live key is refused at start unless `YONA_ALLOW_LIVE=true`. In live mode a submission is a
|
|
160
|
+
legal filing and spends real credits.
|
|
161
|
+
- **Destructive tools need `confirm: true`.** `submit_invoice`, `cancel_invoice` and `issue_credit_note` are annotated
|
|
162
|
+
as destructive and refuse to run without `confirm: true` in their input, so a client that ignores annotations still
|
|
163
|
+
cannot submit by accident. The assistant is told to set it only after you approve the exact action.
|
|
164
|
+
- **Charged calls are not marked read-only**, so clients that auto-approve read-only tools still ask before spending
|
|
165
|
+
credits.
|
|
166
|
+
- **No double charges on retries.** Writes carry an `Idempotency-Key` derived from the MCP call (its request id, the
|
|
167
|
+
tool and its arguments): a client that retries the same call gets the first result and is charged once.
|
|
168
|
+
- **No secrets in output.** No tool, resource or error returns the key or a token. Errors carry the API's
|
|
169
|
+
`errorCode`, message, `requestId` and field-level reasons only.
|
|
170
|
+
|
|
171
|
+
## Embedding the server
|
|
172
|
+
|
|
173
|
+
The package exports the server for hosts that run their own transport:
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { EInvoice } from '@useyona/einvoice-js';
|
|
177
|
+
import { createYonaMcpServer, handleStreamableHttp } from '@useyona/einvoice-mcp';
|
|
178
|
+
|
|
179
|
+
// Any transport:
|
|
180
|
+
const server = createYonaMcpServer({ client: new EInvoice({ apiKey }), allowLive: false });
|
|
181
|
+
|
|
182
|
+
// Streamable HTTP, stateless, JSON responses (no SSE, no session), one server per request:
|
|
183
|
+
app.post('/mcp', (req, res) => handleStreamableHttp(req, res, { client: clientFor(req), parsedBody: req.body }));
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`handleStreamableHttp` answers `POST` only (`GET` and `DELETE` are 405: there is no session) and 403 for a live client
|
|
187
|
+
without `allowLive`. Build the client per request from the caller's credentials.
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npm install
|
|
193
|
+
npm run lint # types, src and tests
|
|
194
|
+
npm test # jest with coverage
|
|
195
|
+
npm run build # dist/
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`npm run live-check` drives the built server against a local Yona e2e stack (see `scripts/live-check.mjs`).
|
|
199
|
+
|
|
200
|
+
## License
|
|
201
|
+
|
|
202
|
+
MIT
|
package/bin/cli.js
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EInvoice } from '@useyona/einvoice-js';
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
/** A configuration problem the binary reports and exits on. Its message never contains the key. */
|
|
4
|
+
export declare class CliConfigError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/** The binary's configuration, from the environment. */
|
|
8
|
+
export interface CliConfig {
|
|
9
|
+
client: EInvoice;
|
|
10
|
+
allowLive: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Reads `YONA_API_KEY` (required), `YONA_ALLOW_LIVE` (`true` to allow a live key) and
|
|
14
|
+
* `YONA_BASE_URL` (an override for testing against another gateway).
|
|
15
|
+
*/
|
|
16
|
+
export declare function configFromEnv(env: NodeJS.ProcessEnv): CliConfig;
|
|
17
|
+
/** Builds the server from the environment; throws {@link CliConfigError} for a bad configuration. */
|
|
18
|
+
export declare function serverFromEnv(env: NodeJS.ProcessEnv): {
|
|
19
|
+
server: McpServer;
|
|
20
|
+
mode: string;
|
|
21
|
+
};
|
|
22
|
+
/** The `einvoice-mcp` binary: the server over stdio. Diagnostics go to stderr; stdout is the protocol. */
|
|
23
|
+
export declare function main(env?: NodeJS.ProcessEnv): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAoC,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAIvE,mGAAmG;AACnG,qBAAa,cAAe,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAI9B;AAED,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,QAAQ,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,SAAS,CAsB/D;AAED,qGAAqG;AACrG,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAQvF;AAED,0GAA0G;AAC1G,wBAAsB,IAAI,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAW9E"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CliConfigError = void 0;
|
|
4
|
+
exports.configFromEnv = configFromEnv;
|
|
5
|
+
exports.serverFromEnv = serverFromEnv;
|
|
6
|
+
exports.main = main;
|
|
7
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
8
|
+
const einvoice_js_1 = require("@useyona/einvoice-js");
|
|
9
|
+
const server_1 = require("./server");
|
|
10
|
+
const version_1 = require("./version");
|
|
11
|
+
/** A configuration problem the binary reports and exits on. Its message never contains the key. */
|
|
12
|
+
class CliConfigError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'CliConfigError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.CliConfigError = CliConfigError;
|
|
19
|
+
/**
|
|
20
|
+
* Reads `YONA_API_KEY` (required), `YONA_ALLOW_LIVE` (`true` to allow a live key) and
|
|
21
|
+
* `YONA_BASE_URL` (an override for testing against another gateway).
|
|
22
|
+
*/
|
|
23
|
+
function configFromEnv(env) {
|
|
24
|
+
const apiKey = env.YONA_API_KEY?.trim();
|
|
25
|
+
if (!apiKey) {
|
|
26
|
+
throw new CliConfigError('YONA_API_KEY is not set. Create an API key in the Yona dashboard (API keys) and pass it in the ' +
|
|
27
|
+
'environment of this server, e.g. "env": { "YONA_API_KEY": "sk_test_…" } in your MCP client configuration.');
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
(0, einvoice_js_1.modeOfApiKey)(apiKey);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
// The SDK's message describes the expected shape and never echoes the key.
|
|
34
|
+
throw new CliConfigError(`YONA_API_KEY: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
const allowLive = env.YONA_ALLOW_LIVE === 'true';
|
|
37
|
+
try {
|
|
38
|
+
const client = new einvoice_js_1.EInvoice({ apiKey, ...(env.YONA_BASE_URL ? { baseUrl: env.YONA_BASE_URL } : {}) });
|
|
39
|
+
return { client, allowLive };
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error instanceof einvoice_js_1.EInvoiceConfigError)
|
|
43
|
+
throw new CliConfigError(error.message);
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Builds the server from the environment; throws {@link CliConfigError} for a bad configuration. */
|
|
48
|
+
function serverFromEnv(env) {
|
|
49
|
+
const { client, allowLive } = configFromEnv(env);
|
|
50
|
+
try {
|
|
51
|
+
return { server: (0, server_1.createYonaMcpServer)({ client, allowLive }), mode: client.mode };
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (error instanceof server_1.LiveModeRefusedError)
|
|
55
|
+
throw new CliConfigError(error.message);
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** The `einvoice-mcp` binary: the server over stdio. Diagnostics go to stderr; stdout is the protocol. */
|
|
60
|
+
async function main(env = process.env) {
|
|
61
|
+
let built;
|
|
62
|
+
try {
|
|
63
|
+
built = serverFromEnv(env);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
process.stderr.write(`einvoice-mcp: ${error.message}\n`);
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
await built.server.connect(new stdio_js_1.StdioServerTransport());
|
|
71
|
+
process.stderr.write(`einvoice-mcp ${version_1.VERSION}: Yona e-invoicing, ${built.mode} mode, on stdio\n`);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAwBA,sCAsBC;AAGD,sCAQC;AAGD,oBAWC;AAvED,wEAA+E;AAC/E,sDAAiF;AAEjF,qCAAmE;AACnE,uCAAkC;AAElC,mGAAmG;AACnG,MAAa,cAAe,SAAQ,KAAK;IACrC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IACjC,CAAC;CACJ;AALD,wCAKC;AAQD;;;GAGG;AACH,SAAgB,aAAa,CAAC,GAAsB;IAChD,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,IAAI,cAAc,CACpB,iGAAiG;YAC7F,2GAA2G,CAClH,CAAC;IACN,CAAC;IACD,IAAI,CAAC;QACD,IAAA,0BAAY,EAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,2EAA2E;QAC3E,MAAM,IAAI,cAAc,CAAC,iBAAkB,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,SAAS,GAAG,GAAG,CAAC,eAAe,KAAK,MAAM,CAAC;IACjD,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,sBAAQ,CAAC,EAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAC,OAAO,EAAE,GAAG,CAAC,aAAa,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAC,CAAC,CAAC;QAClG,OAAO,EAAC,MAAM,EAAE,SAAS,EAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,iCAAmB;YAAE,MAAM,IAAI,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClF,MAAM,KAAK,CAAC;IAChB,CAAC;AACL,CAAC;AAED,qGAAqG;AACrG,SAAgB,aAAa,CAAC,GAAsB;IAChD,MAAM,EAAC,MAAM,EAAE,SAAS,EAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,CAAC;QACD,OAAO,EAAC,MAAM,EAAE,IAAA,4BAAmB,EAAC,EAAC,MAAM,EAAE,SAAS,EAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAC,CAAC;IACjF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,6BAAoB;YAAE,MAAM,IAAI,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnF,MAAM,KAAK,CAAC;IAChB,CAAC;AACL,CAAC;AAED,0GAA0G;AACnG,KAAK,UAAU,IAAI,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC3D,IAAI,KAAK,CAAC;IACV,IAAI,CAAC;QACD,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAkB,KAAe,CAAC,OAAO,IAAI,CAAC,CAAC;QACpE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACX,CAAC;IACD,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,+BAAoB,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,iBAAO,uBAAuB,KAAK,CAAC,IAAI,mBAAmB,CAAC,CAAC;AACtG,CAAC"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { YonaMcpServerOptions } from './server';
|
|
3
|
+
/** Options of {@link handleStreamableHttp}. */
|
|
4
|
+
export interface StreamableHttpOptions extends YonaMcpServerOptions {
|
|
5
|
+
/** The request body when the host framework already parsed it (Express/NestJS `req.body`). */
|
|
6
|
+
parsedBody?: unknown;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Answers one MCP request over streamable HTTP, stateless, with JSON responses (no SSE, no
|
|
10
|
+
* session): a fresh server and transport per request, closed when the response closes. This is
|
|
11
|
+
* how a host (the hosted Yona MCP service) mounts the server on `POST /mcp`; build `client` per
|
|
12
|
+
* request with the caller's credentials. GET and DELETE answer 405 (there is no session to stream
|
|
13
|
+
* or end); a live client without `allowLive` answers 403.
|
|
14
|
+
*/
|
|
15
|
+
export declare function handleStreamableHttp(req: IncomingMessage, res: ServerResponse, options: StreamableHttpOptions): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,eAAe,EAAE,cAAc,EAAC,MAAM,WAAW,CAAC;AAG/D,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,UAAU,CAAC;AAEnD,+CAA+C;AAC/C,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IAC/D,8FAA8F;IAC9F,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAOD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBnI"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleStreamableHttp = handleStreamableHttp;
|
|
4
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
5
|
+
const server_1 = require("./server");
|
|
6
|
+
function jsonRpcError(res, status, code, message, headers = {}) {
|
|
7
|
+
res.writeHead(status, { 'content-type': 'application/json', ...headers });
|
|
8
|
+
res.end(JSON.stringify({ jsonrpc: '2.0', error: { code, message }, id: null }));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Answers one MCP request over streamable HTTP, stateless, with JSON responses (no SSE, no
|
|
12
|
+
* session): a fresh server and transport per request, closed when the response closes. This is
|
|
13
|
+
* how a host (the hosted Yona MCP service) mounts the server on `POST /mcp`; build `client` per
|
|
14
|
+
* request with the caller's credentials. GET and DELETE answer 405 (there is no session to stream
|
|
15
|
+
* or end); a live client without `allowLive` answers 403.
|
|
16
|
+
*/
|
|
17
|
+
async function handleStreamableHttp(req, res, options) {
|
|
18
|
+
if (req.method !== 'POST') {
|
|
19
|
+
jsonRpcError(res, 405, -32000, 'Method not allowed: this MCP endpoint is stateless and answers POST only.', { allow: 'POST' });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
let server;
|
|
23
|
+
try {
|
|
24
|
+
server = (0, server_1.createYonaMcpServer)({ client: options.client, allowLive: options.allowLive });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error instanceof server_1.LiveModeRefusedError) {
|
|
28
|
+
jsonRpcError(res, 403, -32001, error.message);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true });
|
|
34
|
+
res.on('close', () => {
|
|
35
|
+
void transport.close();
|
|
36
|
+
void server.close();
|
|
37
|
+
});
|
|
38
|
+
await server.connect(transport);
|
|
39
|
+
await transport.handleRequest(req, res, options.parsedBody);
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";;AAuBA,oDAsBC;AA5CD,0FAAiG;AACjG,qCAAmE;AASnE,SAAS,YAAY,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAY,EAAE,OAAe,EAAE,UAAkC,EAAE;IAC1H,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAC,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,EAAC,CAAC,CAAC;IACxE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAC,IAAI,EAAE,OAAO,EAAC,EAAE,EAAE,EAAE,IAAI,EAAC,CAAC,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,oBAAoB,CAAC,GAAoB,EAAE,GAAmB,EAAE,OAA8B;IAChH,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACxB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,2EAA2E,EAAE,EAAC,KAAK,EAAE,MAAM,EAAC,CAAC,CAAC;QAC7H,OAAO;IACX,CAAC;IACD,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACD,MAAM,GAAG,IAAA,4BAAmB,EAAC,EAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAC,CAAC,CAAC;IACzF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,6BAAoB,EAAE,CAAC;YACxC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAC9C,OAAO;QACX,CAAC;QACD,MAAM,KAAK,CAAC;IAChB,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,iDAA6B,CAAC,EAAC,kBAAkB,EAAE,SAAS,EAAE,kBAAkB,EAAE,IAAI,EAAC,CAAC,CAAC;IAC/G,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACjB,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** What identifies one tool call: the MCP request id and, when the transport has one, the session. */
|
|
2
|
+
export interface CallIdentity {
|
|
3
|
+
requestId: string | number;
|
|
4
|
+
sessionId?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The `Idempotency-Key` of a write, derived from the tool call: the MCP request id (plus the session
|
|
8
|
+
* id when there is one), the tool name and its arguments. A client that retries the same call (same
|
|
9
|
+
* request id, same arguments) sends the same key, so the API answers the first result and charges
|
|
10
|
+
* once. The arguments are part of the key because request ids restart at 1 in every stateless HTTP
|
|
11
|
+
* request and in every new stdio process: two different calls must never share a key.
|
|
12
|
+
*
|
|
13
|
+
* The result is `mcp_` + 40 hex characters, inside the API's `[A-Za-z0-9_-]{8,128}`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function deriveIdempotencyKey(tool: string, call: CallIdentity, args: unknown): string;
|
|
16
|
+
//# sourceMappingURL=idempotency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"AAEA,sGAAsG;AACtG,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAeD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAG5F"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deriveIdempotencyKey = deriveIdempotencyKey;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
/** Sorts object keys so equal arguments always serialise the same way. */
|
|
6
|
+
function canonical(value) {
|
|
7
|
+
if (Array.isArray(value))
|
|
8
|
+
return value.map(canonical);
|
|
9
|
+
if (value && typeof value === 'object') {
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const key of Object.keys(value).sort()) {
|
|
12
|
+
out[key] = canonical(value[key]);
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The `Idempotency-Key` of a write, derived from the tool call: the MCP request id (plus the session
|
|
20
|
+
* id when there is one), the tool name and its arguments. A client that retries the same call (same
|
|
21
|
+
* request id, same arguments) sends the same key, so the API answers the first result and charges
|
|
22
|
+
* once. The arguments are part of the key because request ids restart at 1 in every stateless HTTP
|
|
23
|
+
* request and in every new stdio process: two different calls must never share a key.
|
|
24
|
+
*
|
|
25
|
+
* The result is `mcp_` + 40 hex characters, inside the API's `[A-Za-z0-9_-]{8,128}`.
|
|
26
|
+
*/
|
|
27
|
+
function deriveIdempotencyKey(tool, call, args) {
|
|
28
|
+
const material = JSON.stringify([tool, call.sessionId ?? null, String(call.requestId), canonical(args)]);
|
|
29
|
+
return `mcp_${(0, node_crypto_1.createHash)('sha256').update(material).digest('hex').slice(0, 40)}`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=idempotency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":";;AA8BA,oDAGC;AAjCD,6CAAuC;AAQvC,0EAA0E;AAC1E,SAAS,SAAS,CAAC,KAAc;IAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACrE,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAAE,KAAiC,CAAC,GAAG,CAAC,CAAC,CAAC;QAClE,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,oBAAoB,CAAC,IAAY,EAAE,IAAkB,EAAE,IAAa;IAChF,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzG,OAAO,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACrF,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { createYonaMcpServer, LiveModeRefusedError } from './server';
|
|
2
|
+
export type { YonaMcpServerOptions } from './server';
|
|
3
|
+
export { handleStreamableHttp } from './http';
|
|
4
|
+
export type { StreamableHttpOptions } from './http';
|
|
5
|
+
export { TOOLS } from './tools';
|
|
6
|
+
export type { ToolDefinition, ToolContext, ToolOutput } from './tools';
|
|
7
|
+
export { RESOURCE_URIS } from './resources';
|
|
8
|
+
export { PROMPT_NAMES } from './prompts';
|
|
9
|
+
export { deriveIdempotencyKey } from './idempotency';
|
|
10
|
+
export { redact } from './result';
|
|
11
|
+
export { VERSION, SERVER_NAME } from './version';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAE,oBAAoB,EAAC,MAAM,UAAU,CAAC;AACnE,YAAY,EAAC,oBAAoB,EAAC,MAAM,UAAU,CAAC;AACnD,OAAO,EAAC,oBAAoB,EAAC,MAAM,QAAQ,CAAC;AAC5C,YAAY,EAAC,qBAAqB,EAAC,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAC;AAC9B,YAAY,EAAC,cAAc,EAAE,WAAW,EAAE,UAAU,EAAC,MAAM,SAAS,CAAC;AACrE,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAC,YAAY,EAAC,MAAM,WAAW,CAAC;AACvC,OAAO,EAAC,oBAAoB,EAAC,MAAM,eAAe,CAAC;AACnD,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAC;AAChC,OAAO,EAAC,OAAO,EAAE,WAAW,EAAC,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SERVER_NAME = exports.VERSION = exports.redact = exports.deriveIdempotencyKey = exports.PROMPT_NAMES = exports.RESOURCE_URIS = exports.TOOLS = exports.handleStreamableHttp = exports.LiveModeRefusedError = exports.createYonaMcpServer = void 0;
|
|
4
|
+
var server_1 = require("./server");
|
|
5
|
+
Object.defineProperty(exports, "createYonaMcpServer", { enumerable: true, get: function () { return server_1.createYonaMcpServer; } });
|
|
6
|
+
Object.defineProperty(exports, "LiveModeRefusedError", { enumerable: true, get: function () { return server_1.LiveModeRefusedError; } });
|
|
7
|
+
var http_1 = require("./http");
|
|
8
|
+
Object.defineProperty(exports, "handleStreamableHttp", { enumerable: true, get: function () { return http_1.handleStreamableHttp; } });
|
|
9
|
+
var tools_1 = require("./tools");
|
|
10
|
+
Object.defineProperty(exports, "TOOLS", { enumerable: true, get: function () { return tools_1.TOOLS; } });
|
|
11
|
+
var resources_1 = require("./resources");
|
|
12
|
+
Object.defineProperty(exports, "RESOURCE_URIS", { enumerable: true, get: function () { return resources_1.RESOURCE_URIS; } });
|
|
13
|
+
var prompts_1 = require("./prompts");
|
|
14
|
+
Object.defineProperty(exports, "PROMPT_NAMES", { enumerable: true, get: function () { return prompts_1.PROMPT_NAMES; } });
|
|
15
|
+
var idempotency_1 = require("./idempotency");
|
|
16
|
+
Object.defineProperty(exports, "deriveIdempotencyKey", { enumerable: true, get: function () { return idempotency_1.deriveIdempotencyKey; } });
|
|
17
|
+
var result_1 = require("./result");
|
|
18
|
+
Object.defineProperty(exports, "redact", { enumerable: true, get: function () { return result_1.redact; } });
|
|
19
|
+
var version_1 = require("./version");
|
|
20
|
+
Object.defineProperty(exports, "VERSION", { enumerable: true, get: function () { return version_1.VERSION; } });
|
|
21
|
+
Object.defineProperty(exports, "SERVER_NAME", { enumerable: true, get: function () { return version_1.SERVER_NAME; } });
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAAmE;AAA3D,6GAAA,mBAAmB,OAAA;AAAE,8GAAA,oBAAoB,OAAA;AAEjD,+BAA4C;AAApC,4GAAA,oBAAoB,OAAA;AAE5B,iCAA8B;AAAtB,8FAAA,KAAK,OAAA;AAEb,yCAA0C;AAAlC,0GAAA,aAAa,OAAA;AACrB,qCAAuC;AAA/B,uGAAA,YAAY,OAAA;AACpB,6CAAmD;AAA3C,mHAAA,oBAAoB,OAAA;AAC5B,mCAAgC;AAAxB,gGAAA,MAAM,OAAA;AACd,qCAA+C;AAAvC,kGAAA,OAAO,OAAA;AAAE,sGAAA,WAAW,OAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { EInvoice } from '@useyona/einvoice-js';
|
|
3
|
+
export declare const PROMPT_NAMES: readonly ["draft_invoice", "explain_rejection"];
|
|
4
|
+
export declare function registerPrompts(server: McpServer, client: EInvoice): void;
|
|
5
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAGnD,eAAO,MAAM,YAAY,iDAAkD,CAAC;AAE5E,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAyEzE"}
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT_NAMES = void 0;
|
|
4
|
+
exports.registerPrompts = registerPrompts;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const result_1 = require("./result");
|
|
7
|
+
exports.PROMPT_NAMES = ['draft_invoice', 'explain_rejection'];
|
|
8
|
+
function registerPrompts(server, client) {
|
|
9
|
+
server.registerPrompt('draft_invoice', {
|
|
10
|
+
title: 'Draft an invoice',
|
|
11
|
+
description: 'Turns a plain description ("2 laptops at ₦850,000 each for Acme Ltd") into a validated draft invoice.',
|
|
12
|
+
argsSchema: { description: zod_1.z.string().describe('What was sold, to whom, for how much.') },
|
|
13
|
+
}, ({ description }) => ({
|
|
14
|
+
messages: [
|
|
15
|
+
{
|
|
16
|
+
role: 'user',
|
|
17
|
+
content: {
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: [
|
|
20
|
+
`Draft an e-invoice in Yona (${client.mode} mode) from this description:`,
|
|
21
|
+
'',
|
|
22
|
+
description,
|
|
23
|
+
'',
|
|
24
|
+
'Steps:',
|
|
25
|
+
'1. Find the buyer with search_buyers. If there is none, ask me before create_buyer (it is charged); use lookup_tin when the tax id is uncertain.',
|
|
26
|
+
'2. Find matching items with search_items; otherwise write each line with description, unitCode (yona://reference/units), unitPrice in major units and taxCategory (yona://reference/tax-categories, e.g. STANDARD_VAT).',
|
|
27
|
+
'3. Call create_invoice with invoiceKind (B2B, B2C, B2G or G2B), today’s invoiceDate, the currency and the lines. It stays a draft.',
|
|
28
|
+
'4. Call validate_invoice with the new invoiceId and fix what it reports with update_invoice.',
|
|
29
|
+
'5. Show me the draft (buyer, lines, totals, tax). Do NOT call finalise_invoice or submit_invoice unless I explicitly ask.',
|
|
30
|
+
].join('\n'),
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
}));
|
|
35
|
+
server.registerPrompt('explain_rejection', {
|
|
36
|
+
title: 'Explain a rejection',
|
|
37
|
+
description: 'Explains in plain words why the tax authority rejected or parked an invoice, and what to do next.',
|
|
38
|
+
argsSchema: { invoiceId: zod_1.z.string().describe('The invoice id.') },
|
|
39
|
+
}, async ({ invoiceId }, extra) => {
|
|
40
|
+
let status;
|
|
41
|
+
try {
|
|
42
|
+
status = JSON.stringify((0, result_1.compact)(await client.submissions.getStatus(invoiceId, { signal: extra.signal })), null, 2);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const e = error;
|
|
46
|
+
status = `(could not read the status: ${e.errorCode ?? ''} ${e.message ?? String(error)}; call get_submission_status)`;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
messages: [
|
|
50
|
+
{
|
|
51
|
+
role: 'user',
|
|
52
|
+
content: {
|
|
53
|
+
type: 'text',
|
|
54
|
+
text: (0, result_1.redact)([
|
|
55
|
+
`Explain in plain words, for a business owner, why invoice ${invoiceId} was not accepted by the tax authority, and what to do next.`,
|
|
56
|
+
'',
|
|
57
|
+
'Its submission status as Yona last recorded it:',
|
|
58
|
+
status,
|
|
59
|
+
'',
|
|
60
|
+
'Read authorityState, parkReason and the submissions’ errors. Know that:',
|
|
61
|
+
'- "parked" means Yona holds the invoice until something outside it changes; the parkReason says what.',
|
|
62
|
+
'- A message that the buyer’s access points are offline usually means the BUYER’s tax id is not registered for e-invoicing, not an outage: check the buyer with lookup_tin.',
|
|
63
|
+
'- A validation rejection names the field: fix the draft (a reported invoice is corrected with a credit note, never edited).',
|
|
64
|
+
'Do not resubmit, cancel or credit anything without my explicit approval.',
|
|
65
|
+
].join('\n')),
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":";;;AAOA,0CAyEC;AAhFD,6BAAsB;AAGtB,qCAAyC;AAE5B,QAAA,YAAY,GAAG,CAAC,eAAe,EAAE,mBAAmB,CAAU,CAAC;AAE5E,SAAgB,eAAe,CAAC,MAAiB,EAAE,MAAgB;IAC/D,MAAM,CAAC,cAAc,CACjB,eAAe,EACf;QACI,KAAK,EAAE,kBAAkB;QACzB,WAAW,EAAE,uGAAuG;QACpH,UAAU,EAAE,EAAC,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC,EAAC;KAC1F,EACD,CAAC,EAAC,WAAW,EAAC,EAAE,EAAE,CAAC,CAAC;QAChB,QAAQ,EAAE;YACN;gBACI,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACL,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;wBACF,+BAA+B,MAAM,CAAC,IAAI,+BAA+B;wBACzE,EAAE;wBACF,WAAW;wBACX,EAAE;wBACF,QAAQ;wBACR,kJAAkJ;wBAClJ,yNAAyN;wBACzN,oIAAoI;wBACpI,8FAA8F;wBAC9F,2HAA2H;qBAC9H,CAAC,IAAI,CAAC,IAAI,CAAC;iBACf;aACJ;SACJ;KACJ,CAAC,CACL,CAAC;IAEF,MAAM,CAAC,cAAc,CACjB,mBAAmB,EACnB;QACI,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,mGAAmG;QAChH,UAAU,EAAE,EAAC,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAC;KAClE,EACD,KAAK,EAAE,EAAC,SAAS,EAAC,EAAE,KAAK,EAAE,EAAE;QACzB,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACD,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,gBAAO,EAAC,MAAM,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,SAAS,EAAE,EAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACrH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,KAA+C,CAAC;YAC1D,MAAM,GAAG,+BAA+B,CAAC,CAAC,SAAS,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC;QAC3H,CAAC;QACD,OAAO;YACH,QAAQ,EAAE;gBACN;oBACI,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACL,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAA,eAAM,EACR;4BACI,6DAA6D,SAAS,8DAA8D;4BACpI,EAAE;4BACF,iDAAiD;4BACjD,MAAM;4BACN,EAAE;4BACF,yEAAyE;4BACzE,uGAAuG;4BACvG,4KAA4K;4BAC5K,6HAA6H;4BAC7H,0EAA0E;yBAC7E,CAAC,IAAI,CAAC,IAAI,CAAC,CACf;qBACJ;iBACJ;aACJ;SACJ,CAAC;IACN,CAAC,CACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { EInvoice } from '@useyona/einvoice-js';
|
|
3
|
+
/** The resource URIs this server serves. */
|
|
4
|
+
export declare const RESOURCE_URIS: {
|
|
5
|
+
readonly taxCategories: "yona://reference/tax-categories";
|
|
6
|
+
readonly units: "yona://reference/units";
|
|
7
|
+
readonly hsCodes: "yona://reference/hs-codes";
|
|
8
|
+
readonly organization: "yona://organization";
|
|
9
|
+
};
|
|
10
|
+
/** The jurisdiction's code-list type behind each reference resource (`reference.getResource`). */
|
|
11
|
+
export declare const CODE_LIST_OF: {
|
|
12
|
+
readonly "yona://reference/tax-categories": "tax-categories";
|
|
13
|
+
readonly "yona://reference/units": "invoice-quantity-codes";
|
|
14
|
+
};
|
|
15
|
+
export declare function registerResources(server: McpServer, client: EInvoice): void;
|
|
16
|
+
//# sourceMappingURL=resources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAIvE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAInD,4CAA4C;AAC5C,eAAO,MAAM,aAAa;;;;;CAKhB,CAAC;AAEX,kGAAkG;AAClG,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAuBX,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAkD3E"}
|