# server mcp

Source: https://apigenie.pl/techdocs/reference/cli-generate_server_mcp

Generate a [Model Context Protocol](https://modelcontextprotocol.io) server in TypeScript from an
OpenAPI document, so that AI agents call the API through typed tools.

> **(experimental, outside the 1.0 compatibility promise)** MCP and its SDK are still moving, and
> tool names and result shapes can change with them. `server mcp` says so in its `--help` and on
> the first line it prints, on the standard error. See the
> [experimental commands](/techdocs/reference/cli-overview#experimental-commands).

## Usage

```sh
apigenie-generator server mcp [...OPTIONS] INPUT_FILE
```

## Description

The input must be an OpenAPI 3.0, 3.1 or 3.2 document; convert Swagger 2.0 documents with
[`apigenie convert`](/techdocs/reference/cli-convert), and bundle documents referencing other files
with [`apigenie bundle`](/techdocs/reference/cli-bundle).

The generated npm package is a server on the official MCP SDK
([`@modelcontextprotocol/server`](https://www.npmjs.com/package/@modelcontextprotocol/server) 2),
which MCP clients (Claude Code, Claude Desktop, IDEs) start and talk to over stdio:

| File             | Content                                                                         |
| ---------------- | ------------------------------------------------------------------------------- |
| `src/client/`    | a [fetch client](/techdocs/reference/cli-generate_client_fetch) of the API, which the tools call |
| `src/schemas.ts` | [Zod](https://zod.dev) (v4) schemas of the components, and of the arguments and results of the tools |
| `src/tools.ts`   | `registerTools(server)`, registering a tool per operation                         |
| `src/config.ts`  | the base URL and the credentials, read from environment variables                |
| `src/runtime.ts` | the call of an operation and its result as a tool result                         |
| `src/server.ts`  | `createServer()`, an `McpServer` with the tools                                  |
| `src/index.ts`   | the entry point (the package's `bin`): the server on stdio                      |
| `README.md`      | the environment variables, the tools, and how to add the server to a client     |

```sh
apigenie-generator server mcp openapi.yaml -o petstore-mcp
cd petstore-mcp && npm install && npm run build
claude mcp add petstore --env PET_STORE_BASE_URL=https://petstore.example.com/v1 -- node "$PWD/dist/index.js"
```

### Tools

Every operation becomes a tool:

- its name is the `operationId`, with other characters than letters, digits, `_` and `-` replaced
  by `_` (at most 64 characters), or the name of the client's function for operations without one;
- its title is the summary, and its description the summary and the description (or the method and
  path), starting with "Deprecated." for deprecated operations;
- its arguments are the parameters, by name, and the request body as `body` (`requestBody` when a
  parameter is named `body`), validated by their schemas before the API is called. Binary bodies,
  and the files of `multipart/form-data` bodies, are base64-encoded strings;
- GET, HEAD and QUERY operations are marked read-only, DELETE operations destructive, and PUT and
  DELETE operations idempotent.

A tool returns the status and the body of the response, as structured content
(`{ "status": 200, "body": ... }`) described by the tool's output schema, and as JSON text. Binary
bodies are returned as an embedded resource, with `{ status, contentType, size }`. A failed request
is an error result with the status and the body of the response, and so is a response the API
document doesn't describe, which lists what doesn't match.

Operations with `x-mcp: false`, on the operation or its path item, don't become tools, nor do
operations marked `x-internal: true` (unless `internal_operations` is set) or disabled with
`x-apigenie`.

```yaml
paths:
  /admin/reset:
    post:
      x-mcp: false
```

### Environment variables

The server reads the base URL of the API and the credentials of its security schemes from
environment variables, prefixed by the API title in upper snake case (`PET_STORE` for "Pet Store",
see `env_prefix`):

| Variable                                         | Value                                                 |
| ------------------------------------------------ | ----------------------------------------------------- |
| `<PREFIX>_BASE_URL`                              | base URL of the API; the first server of the document by default |
| `<PREFIX>_<SCHEME>`                              | API key of an `apiKey` scheme                          |
| `<PREFIX>_<SCHEME>_TOKEN`                        | token of an HTTP `bearer` scheme                       |
| `<PREFIX>_<SCHEME>_USERNAME`, `..._PASSWORD`     | user name and password of an HTTP `basic` scheme      |
| `<PREFIX>_<SCHEME>_ACCESS_TOKEN`                 | access token of an `oauth2` or `openIdConnect` scheme |

`<SCHEME>` is the name of the scheme in upper snake case (`apiKey` gives `API_KEY`). The generated
`README.md` lists the variables of the API. Mutual TLS is not supported.

### Mock server

With `--mock`, the package also contains the document (`openapi.json`) and an `npm run mock`
script serving it with [`apigenie-server`](/techdocs/reference/cli-server), and the tools call
`http://127.0.0.1:4010` when no base URL is set, with the placeholder `mock` for the credentials
that aren't set (the mock server only checks that they are present): a demo of the tools needs no
running API and no credentials.

```sh
apigenie-generator server mcp openapi.yaml -o petstore-mcp --mock
cd petstore-mcp && npm install && npm run build
npm run mock    # in another terminal
```

## Extensions

| Extension | Effect |
| --------- | ------ |
| `x-mcp` | `false` on an operation or its path item: the operation isn't a tool |
| `x-internal` | `true` on an operation or its path item leaves it out, unless `internal_operations` is set |
| `x-apigenie.codegen.disabled` | `true` on an operation or its path item leaves it out |

The extensions can live in an overlay for this target instead of in the document, e.g.
`mcp.overlay.yaml`:

```yaml
overlay: 1.0.0
info:
  title: MCP tools
  version: 1.0.0
actions:
  - target: $.paths['/admin/reset'].post
    update:
      x-mcp: false
```

```sh
apigenie-generator server mcp openapi.yaml --overlay mcp.overlay.yaml -o out
```

## Options

### -c, --config

Path to the configuration file to use. See the "Configuration" section for more information.

### --overlay OVERLAY

Path to an OpenAPI Overlay (1.0 to 1.2) applied to the input before generating, e.g. one setting the
extensions of the "Extensions" section. Can be repeated: the overlays apply in order, after those
listed under `commands.generate.server_mcp.overlay` in the configuration file (with paths relative
to it). Warnings and errors about a value an overlay set point to the overlay.

### --strict

Makes an overlay action whose target selects nothing an error (exit status 2, nothing is generated)
instead of a warning (`OVERLAY:LINE:COL: action #N (TARGET) selects no nodes.`).

### -o, --output

Directory where the package is generated.

### --package-name

Name of the package and of the MCP server, `<title>-mcp` by default.

### --package-version

Version of the package and of the MCP server, the version of the API by default.

### --mock

Make the tools call `apigenie-server` mocking the API when no base URL is set, as described
above. Same as `mock: true`.

## Configuration

```yaml
version: '1.0'
commands:
  generate:
    server_mcp:
      include_tags: [pets, store]
      env_prefix: PETSTORE
```

| Option                | Description                                                                                                  |
| --------------------- | ------------------------------------------------------------------------------------------------------------ |
| `include_tags`        | only the operations with one of these tags become tools (a list or a comma-separated string); all by default |
| `exclude_tags`        | the operations with one of these tags don't become tools                                                     |
| `internal_operations` | `true` also makes tools of the operations marked `x-internal: true` (default: `false`)                       |
| `env_prefix`          | prefix of the environment variables, e.g. `PETSTORE`; the API title in upper snake case by default           |
| `output_schema`       | `false` leaves out the output schemas of the tools (default: `true`)                                        |
| `mock`                | `true` points the tools at `apigenie-server` by default, as `--mock` does (default: `false`)                 |
