Skip to main content
Glama
yaghobieh

@forgedevstack/forge-mcp

by yaghobieh
README.md
# @forgedevstack/forge-mcp

Tiny helper for building API-key-protected stdio [MCP](https://modelcontextprotocol.io) servers. Wraps the official `@modelcontextprotocol/sdk` so you define tools with plain JSON schemas — no zod, no boilerplate — and get a working server with one call.

Part of the [ForgeStack](https://github.com/yaghobieh) family of libraries.

## Install

```bash
npm install @forgedevstack/forge-mcp
```

## A working MCP server in under 20 lines

```ts
import { createMcpServer, textResult } from '@forgedevstack/forge-mcp';

const { start } = createMcpServer({
  name: 'my-server',
  version: '1.0.0',
  apiKey: { envVar: 'MY_API_KEY' },
  tools: [
    {
      name: 'echo',
      description: 'Echo a message',
      inputSchema: { type: 'object', properties: { message: { type: 'string' } }, required: ['message'] },
      handler: (args) => textResult(String(args.message)),
    },
  ],
});

start();
```

## API

### `createMcpServer(options): ForgeMcpServer`

| Option | Type | Description |
|---|---|---|
| `name` | `string` | Server name reported to MCP clients |
| `version` | `string` | Server version reported to MCP clients |
| `tools` | `McpToolDefinition[]` | Tools exposed via `tools/list` and `tools/call` |
| `apiKey` | `ApiKeyConfig` (optional) | API key resolution; omit if no key is needed |

Returns `{ server, apiKey, start }`:

- `server` — the underlying SDK `Server` instance for advanced use
- `apiKey` — the resolved API key (pass it to your API clients inside handlers)
- `start()` — connects a `StdioServerTransport` and begins serving

The API key is resolved eagerly, so a misconfigured server fails fast at startup instead of on the first tool call.

### Tool definition

```ts
interface McpToolDefinition {
  name: string;
  description: string;
  inputSchema: JsonSchema;
  handler: (args: Record<string, unknown>) => Promise<McpToolResult> | McpToolResult;
}
```

`inputSchema` is a plain JSON schema object (`type`, `properties`, `required`, `items`, `enum`, ...). Handler exceptions are caught and returned as `isError` results, and calls to unknown tool names return an `isError` result instead of crashing the server.

### API key config

```ts
interface ApiKeyConfig {
  envVar?: string;
  value?: string;
  required?: boolean;
}
```

Precedence: `value` first, then `process.env[envVar]` (default env var: `MCP_API_KEY`). When `apiKey` is passed and the key is missing, `createMcpServer` throws unless `required: false`.

### Helpers

- `textResult(text)` — `{ content: [{ type: 'text', text }] }`
- `errorResult(text)` — same, with `isError: true`
- `resolveApiKey(config)` — standalone key resolution, same rules as above
- `DEFAULT_API_KEY_ENV_VAR` — `'MCP_API_KEY'`

## Wiring into an MCP client

Point your MCP client (Cursor, Claude Desktop, etc.) at your server script and pass the key through `env`:

```json
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/path/to/my-server.js"],
      "env": { "MY_API_KEY": "your-key-here" }
    }
  }
}
```

## License

MIT