apcore-mcp 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/README.md +183 -0
- package/dist/adapters/annotations.d.ts +37 -0
- package/dist/adapters/annotations.d.ts.map +1 -0
- package/dist/adapters/annotations.js +70 -0
- package/dist/adapters/annotations.js.map +1 -0
- package/dist/adapters/errors.d.ts +31 -0
- package/dist/adapters/errors.d.ts.map +1 -0
- package/dist/adapters/errors.js +113 -0
- package/dist/adapters/errors.js.map +1 -0
- package/dist/adapters/idNormalizer.d.ts +21 -0
- package/dist/adapters/idNormalizer.d.ts.map +1 -0
- package/dist/adapters/idNormalizer.js +25 -0
- package/dist/adapters/idNormalizer.js.map +1 -0
- package/dist/adapters/index.d.ts +8 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +8 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/schema.d.ts +43 -0
- package/dist/adapters/schema.d.ts.map +1 -0
- package/dist/adapters/schema.js +106 -0
- package/dist/adapters/schema.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +131 -0
- package/dist/cli.js.map +1 -0
- package/dist/converters/index.d.ts +6 -0
- package/dist/converters/index.d.ts.map +1 -0
- package/dist/converters/index.js +5 -0
- package/dist/converters/index.js.map +1 -0
- package/dist/converters/openai.d.ts +93 -0
- package/dist/converters/openai.d.ts.map +1 -0
- package/dist/converters/openai.js +174 -0
- package/dist/converters/openai.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/server/factory.d.ts +56 -0
- package/dist/server/factory.d.ts.map +1 -0
- package/dist/server/factory.js +110 -0
- package/dist/server/factory.js.map +1 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +8 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/listener.d.ts +59 -0
- package/dist/server/listener.d.ts.map +1 -0
- package/dist/server/listener.js +99 -0
- package/dist/server/listener.js.map +1 -0
- package/dist/server/router.d.ts +28 -0
- package/dist/server/router.d.ts.map +1 -0
- package/dist/server/router.js +50 -0
- package/dist/server/router.js.map +1 -0
- package/dist/server/transport.d.ts +63 -0
- package/dist/server/transport.d.ts.map +1 -0
- package/dist/server/transport.js +181 -0
- package/dist/server/transport.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/aipartnerup/apcore-mcp/main/apcore-mcp-logo.svg" alt="apcore-mcp logo" width="200"/>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
# apcore-mcp
|
|
6
|
+
|
|
7
|
+
Automatic MCP Server & OpenAI Tools Bridge for [apcore](https://github.com/aipartnerup/apcore).
|
|
8
|
+
|
|
9
|
+
Converts apcore module registries into [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) tool definitions and [OpenAI-compatible function calling](https://platform.openai.com/docs/guides/function-calling) formats — zero boilerplate required.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **MCP Server** — Expose apcore modules as MCP tools over stdio, Streamable HTTP, or SSE
|
|
14
|
+
- **OpenAI Tools** — Convert modules to OpenAI function calling format with strict mode support
|
|
15
|
+
- **Schema Conversion** — Inline `$defs`/`$ref` from Pydantic-generated JSON Schema
|
|
16
|
+
- **Annotation Mapping** — Map module annotations to MCP hints and OpenAI description suffixes
|
|
17
|
+
- **Error Mapping** — Sanitize internal errors for safe client-facing responses
|
|
18
|
+
- **Dynamic Registration** — Listen for registry changes and update tools at runtime
|
|
19
|
+
- **CLI** — Launch an MCP server from the command line
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- Node.js >= 18.0.0
|
|
24
|
+
- apcore (peer dependency)
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install apcore-mcp
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### Programmatic API
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { serve, toOpenaiTools } from "apcore-mcp";
|
|
38
|
+
|
|
39
|
+
// Launch MCP server over stdio
|
|
40
|
+
await serve(executor);
|
|
41
|
+
|
|
42
|
+
// Launch over Streamable HTTP
|
|
43
|
+
await serve(executor, {
|
|
44
|
+
transport: "streamable-http",
|
|
45
|
+
host: "127.0.0.1",
|
|
46
|
+
port: 8000,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Export OpenAI tool definitions
|
|
50
|
+
const tools = toOpenaiTools(registry, {
|
|
51
|
+
embedAnnotations: true,
|
|
52
|
+
strict: true,
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### CLI
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# stdio (default)
|
|
60
|
+
npx apcore-mcp --extensions-dir ./extensions
|
|
61
|
+
|
|
62
|
+
# Streamable HTTP
|
|
63
|
+
npx apcore-mcp --extensions-dir ./extensions --transport streamable-http --port 8000
|
|
64
|
+
|
|
65
|
+
# SSE
|
|
66
|
+
npx apcore-mcp --extensions-dir ./extensions --transport sse --port 8000
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### CLI Arguments
|
|
70
|
+
|
|
71
|
+
| Argument | Default | Description |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `--extensions-dir` | *(required)* | Path to apcore extensions directory |
|
|
74
|
+
| `--transport` | `stdio` | `stdio`, `streamable-http`, or `sse` |
|
|
75
|
+
| `--host` | `127.0.0.1` | Host for HTTP transports |
|
|
76
|
+
| `--port` | `8000` | Port for HTTP transports (1-65535) |
|
|
77
|
+
| `--name` | `apcore-mcp` | MCP server name |
|
|
78
|
+
| `--version` | package version | MCP server version |
|
|
79
|
+
| `--log-level` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
|
80
|
+
|
|
81
|
+
## API Reference
|
|
82
|
+
|
|
83
|
+
### `serve(registryOrExecutor, options?)`
|
|
84
|
+
|
|
85
|
+
Launch an MCP Server that exposes all apcore modules as tools.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
function serve(
|
|
89
|
+
registryOrExecutor: Registry | Executor,
|
|
90
|
+
options?: {
|
|
91
|
+
transport?: "stdio" | "streamable-http" | "sse";
|
|
92
|
+
host?: string;
|
|
93
|
+
port?: number;
|
|
94
|
+
name?: string;
|
|
95
|
+
version?: string;
|
|
96
|
+
}
|
|
97
|
+
): Promise<void>;
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `toOpenaiTools(registryOrExecutor, options?)`
|
|
101
|
+
|
|
102
|
+
Export apcore modules as OpenAI-compatible tool definitions.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
function toOpenaiTools(
|
|
106
|
+
registryOrExecutor: Registry | Executor,
|
|
107
|
+
options?: {
|
|
108
|
+
embedAnnotations?: boolean;
|
|
109
|
+
strict?: boolean;
|
|
110
|
+
tags?: string[];
|
|
111
|
+
prefix?: string;
|
|
112
|
+
}
|
|
113
|
+
): OpenAIToolDef[];
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Options:**
|
|
117
|
+
|
|
118
|
+
- `embedAnnotations` — Append annotation metadata to tool descriptions (default: `false`)
|
|
119
|
+
- `strict` — Enable OpenAI strict mode: adds `additionalProperties: false`, makes all properties required, wraps optional properties with nullable (default: `false`)
|
|
120
|
+
- `tags` — Filter modules by tags
|
|
121
|
+
- `prefix` — Filter modules by ID prefix
|
|
122
|
+
|
|
123
|
+
## Architecture
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
src/
|
|
127
|
+
├── index.ts # Public API: serve(), toOpenaiTools()
|
|
128
|
+
├── cli.ts # CLI entry point
|
|
129
|
+
├── types.ts # TypeScript interfaces
|
|
130
|
+
├── adapters/
|
|
131
|
+
│ ├── schema.ts # JSON Schema $ref inlining
|
|
132
|
+
│ ├── annotations.ts # Module annotations -> MCP hints
|
|
133
|
+
│ ├── errors.ts # Error sanitization
|
|
134
|
+
│ └── idNormalizer.ts # Dot-notation <-> dash-notation
|
|
135
|
+
├── converters/
|
|
136
|
+
│ └── openai.ts # OpenAI tool definition converter
|
|
137
|
+
└── server/
|
|
138
|
+
├── factory.ts # MCP Server creation & handler registration
|
|
139
|
+
├── router.ts # Tool call execution routing
|
|
140
|
+
├── transport.ts # Transport lifecycle (stdio/HTTP/SSE)
|
|
141
|
+
└── listener.ts # Dynamic registry event listener
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Development
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Install dependencies
|
|
148
|
+
npm install
|
|
149
|
+
|
|
150
|
+
# Type check
|
|
151
|
+
npm run typecheck
|
|
152
|
+
|
|
153
|
+
# Run tests
|
|
154
|
+
npm test
|
|
155
|
+
|
|
156
|
+
# Run tests with coverage
|
|
157
|
+
npm run test:coverage
|
|
158
|
+
|
|
159
|
+
# Build
|
|
160
|
+
npm run build
|
|
161
|
+
|
|
162
|
+
# Watch mode
|
|
163
|
+
npm run dev
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Testing
|
|
167
|
+
|
|
168
|
+
100 tests across 10 test suites with 96%+ line coverage:
|
|
169
|
+
|
|
170
|
+
| Module | Coverage |
|
|
171
|
+
|---|---|
|
|
172
|
+
| annotations.ts | 100% |
|
|
173
|
+
| idNormalizer.ts | 100% |
|
|
174
|
+
| factory.ts | 100% |
|
|
175
|
+
| router.ts | 100% |
|
|
176
|
+
| errors.ts | 98.8% |
|
|
177
|
+
| schema.ts | 97.0% |
|
|
178
|
+
| openai.ts | 91.7% |
|
|
179
|
+
| listener.ts | 89.7% |
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
Apache-2.0
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnnotationMapper - Maps apcore module annotations to MCP tool annotations.
|
|
3
|
+
*
|
|
4
|
+
* Converts between apcore's annotation format and the MCP protocol's
|
|
5
|
+
* hint-based annotation system. Also provides description suffix generation
|
|
6
|
+
* and approval requirement checking.
|
|
7
|
+
*/
|
|
8
|
+
import type { ModuleAnnotations, McpAnnotationsDict } from "../types.js";
|
|
9
|
+
export declare class AnnotationMapper {
|
|
10
|
+
/**
|
|
11
|
+
* Convert apcore module annotations to MCP annotations dict.
|
|
12
|
+
*
|
|
13
|
+
* Returns default values when annotations are null:
|
|
14
|
+
* - read_only_hint: false
|
|
15
|
+
* - destructive_hint: false
|
|
16
|
+
* - idempotent_hint: false
|
|
17
|
+
* - open_world_hint: true
|
|
18
|
+
* - title: null
|
|
19
|
+
*/
|
|
20
|
+
toMcpAnnotations(annotations: ModuleAnnotations | null): McpAnnotationsDict;
|
|
21
|
+
/**
|
|
22
|
+
* Generate a description suffix string from annotations.
|
|
23
|
+
*
|
|
24
|
+
* Returns a formatted string like:
|
|
25
|
+
* `\n\n[Annotations: readonly=true, destructive=false, ...]`
|
|
26
|
+
*
|
|
27
|
+
* Returns an empty string if annotations are null.
|
|
28
|
+
*/
|
|
29
|
+
toDescriptionSuffix(annotations: ModuleAnnotations | null): string;
|
|
30
|
+
/**
|
|
31
|
+
* Check whether the annotations indicate the module requires approval.
|
|
32
|
+
*
|
|
33
|
+
* Returns false if annotations are null.
|
|
34
|
+
*/
|
|
35
|
+
hasRequiresApproval(annotations: ModuleAnnotations | null): boolean;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=annotations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../src/adapters/annotations.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEzE,qBAAa,gBAAgB;IAC3B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI,GAAG,kBAAkB;IAoB3E;;;;;;;OAOG;IACH,mBAAmB,CAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI,GAAG,MAAM;IAgBlE;;;;OAIG;IACH,mBAAmB,CAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO;CAOpE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnnotationMapper - Maps apcore module annotations to MCP tool annotations.
|
|
3
|
+
*
|
|
4
|
+
* Converts between apcore's annotation format and the MCP protocol's
|
|
5
|
+
* hint-based annotation system. Also provides description suffix generation
|
|
6
|
+
* and approval requirement checking.
|
|
7
|
+
*/
|
|
8
|
+
export class AnnotationMapper {
|
|
9
|
+
/**
|
|
10
|
+
* Convert apcore module annotations to MCP annotations dict.
|
|
11
|
+
*
|
|
12
|
+
* Returns default values when annotations are null:
|
|
13
|
+
* - read_only_hint: false
|
|
14
|
+
* - destructive_hint: false
|
|
15
|
+
* - idempotent_hint: false
|
|
16
|
+
* - open_world_hint: true
|
|
17
|
+
* - title: null
|
|
18
|
+
*/
|
|
19
|
+
toMcpAnnotations(annotations) {
|
|
20
|
+
if (annotations === null) {
|
|
21
|
+
return {
|
|
22
|
+
read_only_hint: false,
|
|
23
|
+
destructive_hint: false,
|
|
24
|
+
idempotent_hint: false,
|
|
25
|
+
open_world_hint: true,
|
|
26
|
+
title: null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
read_only_hint: annotations.readonly,
|
|
31
|
+
destructive_hint: annotations.destructive,
|
|
32
|
+
idempotent_hint: annotations.idempotent,
|
|
33
|
+
open_world_hint: annotations.open_world,
|
|
34
|
+
title: null,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate a description suffix string from annotations.
|
|
39
|
+
*
|
|
40
|
+
* Returns a formatted string like:
|
|
41
|
+
* `\n\n[Annotations: readonly=true, destructive=false, ...]`
|
|
42
|
+
*
|
|
43
|
+
* Returns an empty string if annotations are null.
|
|
44
|
+
*/
|
|
45
|
+
toDescriptionSuffix(annotations) {
|
|
46
|
+
if (annotations === null) {
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
const parts = [
|
|
50
|
+
`readonly=${annotations.readonly}`,
|
|
51
|
+
`destructive=${annotations.destructive}`,
|
|
52
|
+
`idempotent=${annotations.idempotent}`,
|
|
53
|
+
`requires_approval=${annotations.requires_approval}`,
|
|
54
|
+
`open_world=${annotations.open_world}`,
|
|
55
|
+
];
|
|
56
|
+
return `\n\n[Annotations: ${parts.join(", ")}]`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Check whether the annotations indicate the module requires approval.
|
|
60
|
+
*
|
|
61
|
+
* Returns false if annotations are null.
|
|
62
|
+
*/
|
|
63
|
+
hasRequiresApproval(annotations) {
|
|
64
|
+
if (annotations === null) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return annotations.requires_approval;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=annotations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annotations.js","sourceRoot":"","sources":["../../src/adapters/annotations.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,OAAO,gBAAgB;IAC3B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,WAAqC;QACpD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,OAAO;gBACL,cAAc,EAAE,KAAK;gBACrB,gBAAgB,EAAE,KAAK;gBACvB,eAAe,EAAE,KAAK;gBACtB,eAAe,EAAE,IAAI;gBACrB,KAAK,EAAE,IAAI;aACZ,CAAC;QACJ,CAAC;QAED,OAAO;YACL,cAAc,EAAE,WAAW,CAAC,QAAQ;YACpC,gBAAgB,EAAE,WAAW,CAAC,WAAW;YACzC,eAAe,EAAE,WAAW,CAAC,UAAU;YACvC,eAAe,EAAE,WAAW,CAAC,UAAU;YACvC,KAAK,EAAE,IAAI;SACZ,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,mBAAmB,CAAC,WAAqC;QACvD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAa;YACtB,YAAY,WAAW,CAAC,QAAQ,EAAE;YAClC,eAAe,WAAW,CAAC,WAAW,EAAE;YACxC,cAAc,WAAW,CAAC,UAAU,EAAE;YACtC,qBAAqB,WAAW,CAAC,iBAAiB,EAAE;YACpD,cAAc,WAAW,CAAC,UAAU,EAAE;SACvC,CAAC;QAEF,OAAO,qBAAqB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,mBAAmB,CAAC,WAAqC;QACvD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,WAAW,CAAC,iBAAiB,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErrorMapper - Maps apcore errors to MCP-compatible error responses.
|
|
3
|
+
*
|
|
4
|
+
* Handles ModuleError instances with specific error codes, sanitizes
|
|
5
|
+
* internal error details, and formats schema validation errors with
|
|
6
|
+
* field-level detail.
|
|
7
|
+
*/
|
|
8
|
+
import type { McpErrorResponse } from "../types.js";
|
|
9
|
+
export declare class ErrorMapper {
|
|
10
|
+
/**
|
|
11
|
+
* Convert an error to an MCP error response.
|
|
12
|
+
*
|
|
13
|
+
* Duck-types the error to check for ModuleError properties (code, message, details).
|
|
14
|
+
* Applies sanitization and formatting rules based on the error code.
|
|
15
|
+
*/
|
|
16
|
+
toMcpError(error: unknown): McpErrorResponse;
|
|
17
|
+
/**
|
|
18
|
+
* Duck-type check for ModuleError-like objects.
|
|
19
|
+
*
|
|
20
|
+
* Checks for `code` (string), `message` (string), and `details` properties.
|
|
21
|
+
*/
|
|
22
|
+
private _isModuleError;
|
|
23
|
+
/**
|
|
24
|
+
* Format a schema validation error message with field-level details.
|
|
25
|
+
*
|
|
26
|
+
* Extracts the `errors` array from details and formats each entry
|
|
27
|
+
* as "field: message" lines appended to the base message.
|
|
28
|
+
*/
|
|
29
|
+
private _formatValidationError;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/adapters/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AASpD,qBAAa,WAAW;IACtB;;;;;OAKG;IACH,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB;IAuD5C;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAetB;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;CA4B/B"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErrorMapper - Maps apcore errors to MCP-compatible error responses.
|
|
3
|
+
*
|
|
4
|
+
* Handles ModuleError instances with specific error codes, sanitizes
|
|
5
|
+
* internal error details, and formats schema validation errors with
|
|
6
|
+
* field-level detail.
|
|
7
|
+
*/
|
|
8
|
+
/** Internal error codes that should be sanitized to a generic message. */
|
|
9
|
+
const INTERNAL_ERROR_CODES = new Set([
|
|
10
|
+
"CALL_DEPTH_EXCEEDED",
|
|
11
|
+
"CIRCULAR_CALL",
|
|
12
|
+
"CALL_FREQUENCY_EXCEEDED",
|
|
13
|
+
]);
|
|
14
|
+
export class ErrorMapper {
|
|
15
|
+
/**
|
|
16
|
+
* Convert an error to an MCP error response.
|
|
17
|
+
*
|
|
18
|
+
* Duck-types the error to check for ModuleError properties (code, message, details).
|
|
19
|
+
* Applies sanitization and formatting rules based on the error code.
|
|
20
|
+
*/
|
|
21
|
+
toMcpError(error) {
|
|
22
|
+
// Duck-type check for ModuleError-like objects
|
|
23
|
+
if (this._isModuleError(error)) {
|
|
24
|
+
const code = error.code;
|
|
25
|
+
const details = error.details;
|
|
26
|
+
// Internal error codes -> generic message
|
|
27
|
+
if (INTERNAL_ERROR_CODES.has(code)) {
|
|
28
|
+
return {
|
|
29
|
+
is_error: true,
|
|
30
|
+
error_type: code,
|
|
31
|
+
message: "Internal error occurred",
|
|
32
|
+
details: null,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// ACL denied -> sanitized access denied
|
|
36
|
+
if (code === "ACL_DENIED") {
|
|
37
|
+
return {
|
|
38
|
+
is_error: true,
|
|
39
|
+
error_type: "ACL_DENIED",
|
|
40
|
+
message: "Access denied",
|
|
41
|
+
details: null,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Schema validation error -> formatted with field-level details
|
|
45
|
+
if (code === "SCHEMA_VALIDATION_ERROR") {
|
|
46
|
+
const message = this._formatValidationError(details);
|
|
47
|
+
return {
|
|
48
|
+
is_error: true,
|
|
49
|
+
error_type: "SCHEMA_VALIDATION_ERROR",
|
|
50
|
+
message,
|
|
51
|
+
details,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// Other known ModuleError codes -> pass through
|
|
55
|
+
return {
|
|
56
|
+
is_error: true,
|
|
57
|
+
error_type: code,
|
|
58
|
+
message: error.message,
|
|
59
|
+
details,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Unknown/unexpected exceptions -> generic error
|
|
63
|
+
return {
|
|
64
|
+
is_error: true,
|
|
65
|
+
error_type: "INTERNAL_ERROR",
|
|
66
|
+
message: "Internal error occurred",
|
|
67
|
+
details: null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Duck-type check for ModuleError-like objects.
|
|
72
|
+
*
|
|
73
|
+
* Checks for `code` (string), `message` (string), and `details` properties.
|
|
74
|
+
*/
|
|
75
|
+
_isModuleError(error) {
|
|
76
|
+
if (error === null || typeof error !== "object") {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const obj = error;
|
|
80
|
+
return (typeof obj["code"] === "string" &&
|
|
81
|
+
typeof obj["message"] === "string" &&
|
|
82
|
+
"details" in obj);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Format a schema validation error message with field-level details.
|
|
86
|
+
*
|
|
87
|
+
* Extracts the `errors` array from details and formats each entry
|
|
88
|
+
* as "field: message" lines appended to the base message.
|
|
89
|
+
*/
|
|
90
|
+
_formatValidationError(details) {
|
|
91
|
+
const baseMessage = "Schema validation failed";
|
|
92
|
+
if (details === null) {
|
|
93
|
+
return baseMessage;
|
|
94
|
+
}
|
|
95
|
+
const errors = details["errors"];
|
|
96
|
+
if (!Array.isArray(errors) || errors.length === 0) {
|
|
97
|
+
return baseMessage;
|
|
98
|
+
}
|
|
99
|
+
const fieldErrors = errors
|
|
100
|
+
.map((err) => {
|
|
101
|
+
if (err !== null && typeof err === "object") {
|
|
102
|
+
const entry = err;
|
|
103
|
+
const field = entry["field"] ?? "unknown";
|
|
104
|
+
const message = entry["message"] ?? "validation error";
|
|
105
|
+
return ` ${String(field)}: ${String(message)}`;
|
|
106
|
+
}
|
|
107
|
+
return ` ${String(err)}`;
|
|
108
|
+
})
|
|
109
|
+
.join("\n");
|
|
110
|
+
return `${baseMessage}:\n${fieldErrors}`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/adapters/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModuleIDNormalizer - Converts between apcore module IDs and MCP tool names.
|
|
3
|
+
*
|
|
4
|
+
* apcore uses dot-separated module IDs (e.g. "myorg.tools.search")
|
|
5
|
+
* while MCP tool names use hyphens (e.g. "myorg-tools-search").
|
|
6
|
+
*/
|
|
7
|
+
export declare class ModuleIDNormalizer {
|
|
8
|
+
/**
|
|
9
|
+
* Normalize an apcore module ID to an MCP-compatible tool name.
|
|
10
|
+
*
|
|
11
|
+
* Replaces dots (`.`) with hyphens (`-`).
|
|
12
|
+
*/
|
|
13
|
+
normalize(moduleId: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Denormalize an MCP tool name back to an apcore module ID.
|
|
16
|
+
*
|
|
17
|
+
* Replaces hyphens (`-`) with dots (`.`).
|
|
18
|
+
*/
|
|
19
|
+
denormalize(toolName: string): string;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=idNormalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idNormalizer.d.ts","sourceRoot":"","sources":["../../src/adapters/idNormalizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAa,kBAAkB;IAC7B;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAInC;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAGtC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModuleIDNormalizer - Converts between apcore module IDs and MCP tool names.
|
|
3
|
+
*
|
|
4
|
+
* apcore uses dot-separated module IDs (e.g. "myorg.tools.search")
|
|
5
|
+
* while MCP tool names use hyphens (e.g. "myorg-tools-search").
|
|
6
|
+
*/
|
|
7
|
+
export class ModuleIDNormalizer {
|
|
8
|
+
/**
|
|
9
|
+
* Normalize an apcore module ID to an MCP-compatible tool name.
|
|
10
|
+
*
|
|
11
|
+
* Replaces dots (`.`) with hyphens (`-`).
|
|
12
|
+
*/
|
|
13
|
+
normalize(moduleId) {
|
|
14
|
+
return moduleId.replaceAll(".", "-");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Denormalize an MCP tool name back to an apcore module ID.
|
|
18
|
+
*
|
|
19
|
+
* Replaces hyphens (`-`) with dots (`.`).
|
|
20
|
+
*/
|
|
21
|
+
denormalize(toolName) {
|
|
22
|
+
return toolName.replaceAll("-", ".");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=idNormalizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idNormalizer.js","sourceRoot":"","sources":["../../src/adapters/idNormalizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,OAAO,kBAAkB;IAC7B;;;;OAIG;IACH,SAAS,CAAC,QAAgB;QACxB,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAC,QAAgB;QAC1B,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter classes for converting between apcore and MCP/OpenAI formats.
|
|
3
|
+
*/
|
|
4
|
+
export { SchemaConverter } from "./schema.js";
|
|
5
|
+
export { AnnotationMapper } from "./annotations.js";
|
|
6
|
+
export { ErrorMapper } from "./errors.js";
|
|
7
|
+
export { ModuleIDNormalizer } from "./idNormalizer.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter classes for converting between apcore and MCP/OpenAI formats.
|
|
3
|
+
*/
|
|
4
|
+
export { SchemaConverter } from "./schema.js";
|
|
5
|
+
export { AnnotationMapper } from "./annotations.js";
|
|
6
|
+
export { ErrorMapper } from "./errors.js";
|
|
7
|
+
export { ModuleIDNormalizer } from "./idNormalizer.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SchemaConverter - Converts apcore module schemas to MCP-compatible JSON Schema.
|
|
3
|
+
*
|
|
4
|
+
* Handles deep copying, inlining $ref references, and ensuring schemas
|
|
5
|
+
* have the required `type: "object"` for MCP tool input/output schemas.
|
|
6
|
+
*/
|
|
7
|
+
import type { JsonSchema, ModuleDescriptor } from "../types.js";
|
|
8
|
+
export declare class SchemaConverter {
|
|
9
|
+
/**
|
|
10
|
+
* Convert a module descriptor's input_schema to an MCP-compatible schema.
|
|
11
|
+
*/
|
|
12
|
+
convertInputSchema(descriptor: ModuleDescriptor): JsonSchema;
|
|
13
|
+
/**
|
|
14
|
+
* Convert a module descriptor's output_schema to an MCP-compatible schema.
|
|
15
|
+
*/
|
|
16
|
+
convertOutputSchema(descriptor: ModuleDescriptor): JsonSchema;
|
|
17
|
+
/**
|
|
18
|
+
* Apply all schema transformations: deep copy, inline $ref, ensure object type.
|
|
19
|
+
*/
|
|
20
|
+
_convertSchema(schema: JsonSchema): JsonSchema;
|
|
21
|
+
/**
|
|
22
|
+
* Recursively inline `$ref` references using the provided $defs map.
|
|
23
|
+
*
|
|
24
|
+
* Handles dicts (objects), arrays, and primitive values.
|
|
25
|
+
* Skips the `$defs` key itself during traversal.
|
|
26
|
+
*/
|
|
27
|
+
_inlineRefs(node: unknown, defs: Record<string, JsonSchema>): unknown;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a `$ref` path (e.g. `#/$defs/MyType`) against the $defs map.
|
|
30
|
+
*
|
|
31
|
+
* Returns a deep copy of the resolved definition to avoid mutation.
|
|
32
|
+
* Throws Error if the ref format is invalid or the definition is not found.
|
|
33
|
+
*/
|
|
34
|
+
_resolveRef(refPath: string, defs: Record<string, JsonSchema>): JsonSchema;
|
|
35
|
+
/**
|
|
36
|
+
* Ensure the schema has `type: "object"`.
|
|
37
|
+
*
|
|
38
|
+
* - Empty schema -> `{ type: "object", properties: {} }`
|
|
39
|
+
* - Schema without `type` -> adds `type: "object"`
|
|
40
|
+
*/
|
|
41
|
+
_ensureObjectType(schema: JsonSchema): JsonSchema;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/adapters/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEhE,qBAAa,eAAe;IAC1B;;OAEG;IACH,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,GAAG,UAAU;IAI5D;;OAEG;IACH,mBAAmB,CAAC,UAAU,EAAE,gBAAgB,GAAG,UAAU;IAI7D;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU;IAe9C;;;;;OAKG;IACH,WAAW,CACT,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAC/B,OAAO;IA8BV;;;;;OAKG;IACH,WAAW,CACT,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAC/B,UAAU;IAoBb;;;;;OAKG;IACH,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU;CAclD"}
|