MCP Hub
Back to servers

apcore-mcp

Automatic MCP Server & OpenAI Tools Bridge for apcore

npm531/wk
Stars
1
Updated
Mar 2, 2026

Quick Install

npx -y apcore-mcp
apcore-mcp logo

apcore-mcp

Automatic MCP Server & OpenAI Tools Bridge for apcore.

Converts apcore module registries into Model Context Protocol (MCP) tool definitions and OpenAI-compatible function calling formats — zero boilerplate required.

Features

  • MCP Server — Expose apcore modules as MCP tools over stdio, Streamable HTTP, or SSE
  • OpenAI Tools — Convert modules to OpenAI function calling format with strict mode support
  • Schema Conversion — Inline $defs/$ref from Pydantic-generated JSON Schema
  • Annotation Mapping — Map module annotations to MCP hints and OpenAI description suffixes
  • Approval Mechanism — Built-in elicitation-based approval flow for sensitive tool executions
  • Error Mapping — Sanitize internal errors for safe client-facing responses
  • Dynamic Registration — Listen for registry changes and update tools at runtime
  • Tool Explorer — Browser-based UI for browsing schemas and testing tools interactively
  • CLI — Launch an MCP server from the command line

Requirements

  • Node.js >= 18.0.0

Installation

npm install apcore-mcp

apcore-js is included as a direct dependency — no separate install needed.

Quick Start

Programmatic API

import { serve, toOpenaiTools } from "apcore-mcp";

// Launch MCP server over stdio
await serve(executor);

// Launch over Streamable HTTP
await serve(executor, {
  transport: "streamable-http",
  host: "127.0.0.1",
  port: 8000,
});

// Export OpenAI tool definitions
const tools = toOpenaiTools(registry, {
  embedAnnotations: true,
  strict: true,
});

CLI

# stdio (default)
npx apcore-mcp --extensions-dir ./extensions

# Streamable HTTP
npx apcore-mcp --extensions-dir ./extensions --transport streamable-http --port 8000

# SSE
npx apcore-mcp --extensions-dir ./extensions --transport sse --port 8000

CLI Arguments

ArgumentDefaultDescription
--extensions-dir(required)Path to apcore extensions directory
--transportstdiostdio, streamable-http, or sse
--host127.0.0.1Host for HTTP transports
--port8000Port for HTTP transports (1-65535)
--nameapcore-mcpMCP server name
--versionpackage versionMCP server version
--log-levelINFODEBUG, INFO, WARNING, ERROR
--exploreroffEnable the browser-based Tool Explorer UI (HTTP only)
--explorer-prefix/explorerURL prefix for the explorer UI
--allow-executeoffAllow tool execution from the explorer UI
--jwt-secretJWT secret key for Bearer token authentication
--jwt-algorithmHS256JWT algorithm
--jwt-audienceExpected JWT audience claim
--jwt-issuerExpected JWT issuer claim
--jwt-require-authtrueRequire auth (use --no-jwt-require-auth for permissive mode)
--exempt-paths/health,/metricsComma-separated paths exempt from auth

MCP Client Configuration

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "apcore": {
      "command": "npx",
      "args": ["apcore-mcp", "--extensions-dir", "/path/to/your/extensions"]
    }
  }
}

Claude Code

Add to .mcp.json in your project root:

{
  "mcpServers": {
    "apcore": {
      "command": "npx",
      "args": ["apcore-mcp", "--extensions-dir", "./extensions"]
    }
  }
}

Cursor

Add to .cursor/mcp.json in your project root:

{
  "mcpServers": {
    "apcore": {
      "command": "npx",
      "args": ["apcore-mcp", "--extensions-dir", "./extensions"]
    }
  }
}

Remote HTTP access

npx apcore-mcp --extensions-dir ./extensions \
    --transport streamable-http \
    --host 0.0.0.0 \
    --port 9000

Connect any MCP client to http://your-host:9000/mcp.

API Reference

serve(registryOrExecutor, options?)

Launch an MCP Server that exposes all apcore modules as tools.

function serve(
  registryOrExecutor: Registry | Executor,
  options?: {
    transport?: "stdio" | "streamable-http" | "sse";
    host?: string;
    port?: number;
    name?: string;
    version?: string;
    dynamic?: boolean;
    validateInputs?: boolean;
    tags?: string[] | null;
    prefix?: string | null;
    logLevel?: "DEBUG" | "INFO" | "WARNING" | "ERROR" | "CRITICAL";
    onStartup?: () => void | Promise<void>;
    onShutdown?: () => void | Promise<void>;
    metricsCollector?: MetricsExporter;
    explorer?: boolean;
    explorerPrefix?: string;
    allowExecute?: boolean;
    authenticator?: Authenticator;
    exemptPaths?: string[];
    approvalHandler?: unknown;
  }
): Promise<void>;

Tool Explorer

When explorer: true is passed to serve(), a browser-based Tool Explorer UI is mounted on HTTP transports. It provides an interactive page for browsing tool schemas and testing tool execution.

await serve(registry, {
  transport: "streamable-http",
  explorer: true,
  allowExecute: true,
});
// Open http://127.0.0.1:8000/explorer/ in a browser

Endpoints:

EndpointDescription
GET /explorer/Interactive HTML page (self-contained, no external dependencies)
GET /explorer/toolsJSON array of all tools with name, description, annotations
GET /explorer/tools/<name>Full tool detail with inputSchema
POST /explorer/tools/<name>/callExecute a tool (requires allowExecute: true)
  • HTTP transports only (streamable-http, sse). Silently ignored for stdio.
  • Execution disabled by default — set allowExecute: true to enable Try-it.
  • Custom prefix — use explorerPrefix: "/browse" to mount at a different path.
  • Authorization UI — Swagger-UI-style Authorization input field. Paste a Bearer token to authenticate tool execution requests. Generated cURL commands automatically include the Authorization header.

JWT Authentication

apcore-mcp supports JWT Bearer token authentication for HTTP-based transports.

Programmatic Usage

import { serve, JWTAuthenticator } from "apcore-mcp";

const authenticator = new JWTAuthenticator({
  secret: "your-secret-key",
  algorithms: ["HS256"],
  audience: "my-app",
  issuer: "auth-service",
  // Map custom claims to Identity fields
  claimMapping: {
    id: "sub",
    type: "type",
    roles: "roles",
    attrs: ["email", "org"],  // Extra claims → Identity.attrs
  },
  // Claims that must be present in the token (default: ["sub"])
  requireClaims: ["sub", "email"],
  // Set to false for permissive mode (allow unauthenticated requests)
  requireAuth: true,
});

await serve(executor, {
  transport: "streamable-http",
  authenticator,
  // Custom exempt paths (default: ["/health", "/metrics"])
  exemptPaths: ["/health", "/metrics", "/status"],
});

CLI Flags

FlagDefaultDescription
--jwt-secretJWT secret key for Bearer token authentication
--jwt-algorithmHS256JWT algorithm
--jwt-audienceExpected audience claim
--jwt-issuerExpected issuer claim
--jwt-require-authtrueRequire auth. Use --no-jwt-require-auth for permissive mode
--exempt-paths/health,/metricsComma-separated paths exempt from auth

curl Examples

# Authenticated request
curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-jwt-token>" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'

# Health check (always exempt)
curl http://localhost:8000/health

toOpenaiTools(registryOrExecutor, options?)

Export apcore modules as OpenAI-compatible tool definitions.

function toOpenaiTools(
  registryOrExecutor: Registry | Executor,
  options?: {
    embedAnnotations?: boolean;
    strict?: boolean;
    tags?: string[];
    prefix?: string;
  }
): OpenAIToolDef[];

Options:

  • embedAnnotations — Append annotation metadata to tool descriptions (default: false)
  • strict — Enable OpenAI strict mode: adds additionalProperties: false, makes all properties required, wraps optional properties with nullable (default: false)
  • tags — Filter modules by tags
  • prefix — Filter modules by ID prefix

Architecture

src/
├── index.ts              # Public API: serve(), toOpenaiTools()
├── cli.ts                # CLI entry point
├── types.ts              # TypeScript interfaces
├── helpers.ts            # reportProgress() / elicit() helpers
├── adapters/
│   ├── schema.ts         # JSON Schema $ref inlining
│   ├── annotations.ts    # Module annotations -> MCP hints
│   ├── errors.ts         # Error sanitization
│   ├── idNormalizer.ts   # Dot-notation <-> dash-notation
│   └── approval.ts       # Elicitation-based approval handler
├── auth/
│   ├── jwt.ts            # JWT Bearer token authenticator
│   ├── storage.ts        # AsyncLocalStorage identity propagation
│   └── types.ts          # Authenticator / Identity interfaces
├── converters/
│   └── openai.ts         # OpenAI tool definition converter
├── explorer/
│   ├── handler.ts        # Explorer HTTP route handler
│   └── html.ts           # Self-contained HTML/CSS/JS page
└── server/
    ├── factory.ts        # MCP Server creation & handler registration
    ├── router.ts         # Tool call execution routing
    ├── context.ts        # BridgeContext for executor call chains
    ├── transport.ts      # Transport lifecycle (stdio/HTTP/SSE)
    └── listener.ts       # Dynamic registry event listener

Examples

See examples/README.md for runnable demos covering both class-based modules and zero-code-intrusion wrapping via the module() factory.

# Launch all 5 example modules with the Tool Explorer UI
npx tsx examples/run.ts
# Open http://127.0.0.1:8000/explorer/

Development

# Install dependencies
npm install

# Type check
npm run typecheck

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Build
npm run build

# Watch mode
npm run dev

Testing

313 tests across 23 test suites.

License

Apache-2.0

Reviews

No reviews yet

Sign in to write a review