@afora/mcp 0.0.0-stage → 0.0.4

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.
@@ -0,0 +1,12 @@
1
+ export interface RunResult {
2
+ readonly code: number | null;
3
+ readonly output: string;
4
+ /** The command could not be started. */
5
+ readonly missing: boolean;
6
+ readonly timedOut: boolean;
7
+ }
8
+ /** Runs a command, collecting stdout and stderr; never rejects. */
9
+ export declare function run(command: string, args: readonly string[], options: {
10
+ cwd: string;
11
+ timeoutMs: number;
12
+ }): Promise<RunResult>;
@@ -0,0 +1,18 @@
1
+ import { type ProviderCatalogEntry, type StageCatalogEntry } from "@afora/codegen";
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ export interface ServerOptions {
4
+ /** The project directory; every write stays inside it. The current directory by default. */
5
+ readonly project?: string;
6
+ /** `src/app.ts#App`: an application to extract the spec from when there is no afora.json. */
7
+ readonly app?: string;
8
+ /** External providers the spec's `provider.use` may name; `inMemory` is built in. */
9
+ readonly providers?: readonly ProviderCatalogEntry[];
10
+ /** External stages an output's `pipe` may name; `select` and `openapi` are built in. */
11
+ readonly stages?: readonly StageCatalogEntry[];
12
+ }
13
+ /**
14
+ * An MCP server for the project: tools to read, edit, validate and generate
15
+ * its afora.json, and resources with the schema, the catalog and a guide.
16
+ * Connect it to any transport.
17
+ */
18
+ export declare function createServer(options?: ServerOptions): Promise<Server>;
package/dist/sink.d.ts ADDED
@@ -0,0 +1,83 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ /** The options of the `mcpTools` sink. JSON, so the stage can live in an `afora.json`. */
3
+ export interface McpToolsOptions {
4
+ /** Name of the MCP server that `server()` creates. */
5
+ readonly name: string;
6
+ /** Version of the MCP server that `server()` creates. */
7
+ readonly version: string;
8
+ /** Prepended to every tool name, e.g. `"blog_"`. Empty by default. */
9
+ readonly prefix?: string;
10
+ /** Operation ids to expose (`"Users.register"`); every operation when omitted. */
11
+ readonly include?: readonly string[];
12
+ /**
13
+ * The context of an operation, by key: `{ token: "authorization" }` fills
14
+ * `context.token` from the value named `authorization` in the `extra` of
15
+ * the call (`extra.values`). A missing value leaves the key out.
16
+ */
17
+ readonly context?: {
18
+ readonly [contextKey: string]: string;
19
+ };
20
+ }
21
+ /** One MCP tool: what `tools/list` returns for it. */
22
+ export interface McpToolDefinition {
23
+ readonly name: string;
24
+ readonly description: string;
25
+ /** JSON Schema of the operation input: an inline object, with no `$ref`. */
26
+ readonly inputSchema: {
27
+ readonly type: "object";
28
+ readonly [key: string]: unknown;
29
+ };
30
+ /** The operation id the tool runs (`"Users.register"`). */
31
+ readonly operation: string;
32
+ }
33
+ /**
34
+ * What the host knows about a call. `values` feeds the `context` mapping of
35
+ * the options; `register` fills it from the HTTP headers (lower-case names)
36
+ * and the string entries of the request `_meta`.
37
+ */
38
+ export interface McpCallExtra {
39
+ readonly values?: Readonly<Record<string, string | undefined>>;
40
+ }
41
+ /** The result of a tool call, as MCP expects it. */
42
+ export interface McpToolResult {
43
+ readonly isError?: true;
44
+ readonly content: readonly {
45
+ readonly type: "text";
46
+ readonly text: string;
47
+ }[];
48
+ }
49
+ /** What the `mcpTools` sink builds. */
50
+ export interface McpTools {
51
+ readonly tools: readonly McpToolDefinition[];
52
+ /** Runs a tool. Never throws: an unknown tool or an error is `isError: true`. */
53
+ call(name: string, args?: unknown, extra?: McpCallExtra): Promise<McpToolResult>;
54
+ /** Handles `tools/list` and `tools/call` on a low-level MCP SDK `Server`. */
55
+ register(server: Server): Server;
56
+ /** A new `Server` (capability `tools`) with the tools registered. */
57
+ server(): Server;
58
+ }
59
+ /**
60
+ * MCP tools for the operations, one per operation, named
61
+ * `{prefix}{command}_{operation}` in snake case (`users_register`).
62
+ *
63
+ * - `inputSchema` is the JSON Schema of the operation input (inline).
64
+ * - A call runs `operation.invoke(args, { context })`. The context comes from
65
+ * `extra.values` through the `context` option; richer rules, such as
66
+ * authentication, are a `transform` stage that wraps `invoke`.
67
+ * - Success is one text content with the response as JSON (`outputValueOf`:
68
+ * sensitive values masked). An error is `isError: true` with the
69
+ * `problemOf` JSON as text, whose `status` is the one of `statusOf`
70
+ * (the output `statuses` first); invalid input is a 400 with `issues`.
71
+ * - The result has `tools`, `call(name, args, extra)`, `register(server)`
72
+ * (handlers on a low-level SDK `Server`) and `server()` (a ready one).
73
+ */
74
+ export declare const mcpTools: import("@afora/core").SinkFactory<McpTools, McpToolsOptions>;
75
+ /** The runtime catalog of this module: the stage name `mcpTools` resolves to the sink. */
76
+ export declare const McpStages: import("@afora/core").IStageCatalog<Readonly<Record<string, import("@afora/core").StageFactory>>>;
77
+ /** The catalog entries codegen reads (`--stages @afora/mcp`). */
78
+ export declare const stages: readonly [{
79
+ readonly name: "mcpTools";
80
+ readonly module: "@afora/mcp";
81
+ readonly export: "mcpTools";
82
+ readonly kind: "sink";
83
+ }];
@@ -0,0 +1,24 @@
1
+ import { type CodegenOptions, type ProviderCatalogEntry, type ResolvedSpec, type Spec, type SpecIssue, type StageCatalogEntry } from "@afora/codegen";
2
+ export interface Project {
3
+ /** The real path of the project directory. */
4
+ readonly root: string;
5
+ /** `src/app.ts#App`: where to extract the spec from when there is no afora.json. */
6
+ readonly app?: string;
7
+ /** External providers `use` may name in the spec (`inMemory` is built in). */
8
+ readonly providers?: readonly ProviderCatalogEntry[];
9
+ /** External stages an output's `pipe` may name (`select` and `openapi` are built in). */
10
+ readonly stages?: readonly StageCatalogEntry[];
11
+ }
12
+ /** What codegen needs from the project besides the spec. */
13
+ export declare function codegenOptionsOf(project: Project): CodegenOptions;
14
+ /** The project directory, resolved; it must exist. */
15
+ export declare function openProject(directory: string, app?: string, providers?: readonly ProviderCatalogEntry[], stages?: readonly StageCatalogEntry[]): Promise<Project>;
16
+ /** The spec on disk, or undefined when there is none. */
17
+ export declare function readSpec(project: Project): Promise<Spec | undefined>;
18
+ /** Writes the spec, tab-indented with its keys in a stable order. Confined to the project. */
19
+ export declare function writeSpec(project: Project, spec: Spec): Promise<void>;
20
+ /** Validates `spec` as the project's, resolving what it extends. */
21
+ export declare function validateInProject(project: Project, spec: unknown): Promise<{
22
+ issues: SpecIssue[];
23
+ extended: Record<string, ResolvedSpec>;
24
+ }>;
@@ -0,0 +1,12 @@
1
+ import { type Project } from "./spec-file.js";
2
+ type Json = Record<string, unknown>;
3
+ /** A tool: the name and description an agent sees, the JSON Schema of its input and its handler. */
4
+ export interface ToolDefinition {
5
+ readonly name: string;
6
+ readonly description: string;
7
+ readonly inputSchema: Json;
8
+ readonly readOnly: boolean;
9
+ handle(args: Json, project: Project): Promise<unknown>;
10
+ }
11
+ export declare const tools: readonly ToolDefinition[];
12
+ export {};
@@ -0,0 +1,28 @@
1
+ export interface Diagnostic {
2
+ readonly file: string;
3
+ readonly line: number;
4
+ readonly column: number;
5
+ readonly code: string;
6
+ readonly message: string;
7
+ }
8
+ export type TypecheckResult = {
9
+ readonly ran: true;
10
+ /** No diagnostic in the generated files. */
11
+ readonly ok: boolean;
12
+ /** Only the diagnostics of generated files are listed. */
13
+ readonly diagnostics: readonly Diagnostic[];
14
+ /** How many errors the rest of the project has (not listed). */
15
+ readonly otherErrors: number;
16
+ } | {
17
+ readonly ran: false;
18
+ readonly reason: string;
19
+ };
20
+ /** Parses the output of `tsc --noEmit` (default, non-pretty format). */
21
+ export declare function parseDiagnostics(output: string): (Diagnostic & {
22
+ readonly path: string;
23
+ })[];
24
+ /**
25
+ * Runs `tsc --noEmit -p <root>` when the project has a tsconfig.json, and
26
+ * keeps only the diagnostics of `files` (paths relative to `root`).
27
+ */
28
+ export declare function typecheck(root: string, files: readonly string[]): Promise<TypecheckResult>;
package/package.json CHANGED
@@ -1,6 +1,63 @@
1
1
  {
2
- "name": "@afora/mcp",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@afora/mcp",
3
+ "version": "0.0.4",
4
+ "description": "An MCP server that lets an agent discover the afora catalog, edit afora.json, validate it, generate the code and check the result.",
5
+ "keywords": [
6
+ "afora",
7
+ "mcp",
8
+ "model-context-protocol",
9
+ "codegen",
10
+ "agents"
11
+ ],
12
+ "author": "Alan Reis <alanreisanjo@gmail.com> (https://github.com/Hoyasumii)",
13
+ "license": "MIT",
14
+ "homepage": "https://github.com/afora-framework/core/tree/main/packages/mcp#readme",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/afora-framework/core.git",
18
+ "directory": "packages/mcp"
19
+ },
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "module": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js",
28
+ "default": "./dist/index.js"
29
+ },
30
+ "./package.json": "./package.json"
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "bin": {
36
+ "afora-mcp": "dist/bin.js"
37
+ },
38
+ "engines": {
39
+ "bun": ">=1.4.4",
40
+ "node": ">=22"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public",
44
+ "provenance": true
45
+ },
46
+ "scripts": {
47
+ "typecheck": "bun check",
48
+ "build": "rm -rf dist && bun build ./src/index.ts ./src/bin.ts ./src/extract-child.ts --outdir ./dist --target node --format esm --packages external --tsconfig-override tsconfig.build.json && tsc -p tsconfig.build.json && bun ../../scripts/add-dts-extensions.ts dist",
49
+ "test": "bun test"
50
+ },
51
+ "dependencies": {
52
+ "@afora/codegen": "^0.0.4",
53
+ "@modelcontextprotocol/sdk": "^1.32.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/bun": "^1.4.4",
57
+ "typebox": "^1.4.3"
58
+ },
59
+ "peerDependencies": {
60
+ "@afora/core": ">=0.0.1",
61
+ "typebox": "^1"
62
+ }
63
+ }