What Is an MCP Gateway? Trying Out the Open-Source ContextForge as an Entry Point for Asking AI About Business System Data

What Is an MCP Gateway? Trying Out the Open-Source ContextForge as an Entry Point for Asking AI About Business System Data

Outlines the MCP Gateway concept, centralizing authentication, auditing and cost control when AI agents access business systems, and tries the OSS ContextForge to expose an existing web API via MCP and call it.
2026.08.31

This page has been translated by machine translation. View original

Requests to let AI agents reference data in internal business systems have been increasing. For example, the data you want to reference is scattered across various business systems: customer management such as Salesforce, file sharing, accounting, expense reimbursement, and so on.

You might think, "Why not just connect the AI agent directly to each system?" But as the number of targets grows, problems gradually appear. In this article, I'll organize those problems, introduce a concept that emerged as a solution called MCP Gateway, and then try out the OSS implementation ContextForge hands-on.

MCP Gateway is a category in which multiple vendors and OSS projects have already released products with similar definitions. It is a layer that sits between AI agents and a group of MCP servers and takes on cross-cutting controls such as authentication and access control all in one place. This article is intended for readers who have used MCP (Model Context Protocol, a standard protocol for connecting AI agents with external tools) but have not looked into the Gateways that bundle them.
For MCP itself, we also explain it on our company blog, so please refer to that.

https://dev.classmethod.jp/articles/shuntaka-mcp-study/

What's the problem with direct connections?

First, let's consider a setup where the AI agent is connected directly to each business system.

It looks simple at first glance, but as the number of systems grows, the following problems pile up.

  • Configuration becomes cumbersome: For each client or agent, you have to register and manage the connection targets one by one
  • Authentication is fragmented: Authentication methods and token management differ from system to system, and you have to handle each of them
  • No audit logs: There is no place to record across systems who accessed which system's data and how much
  • Costs are unpredictable: If API usage is pay-as-you-go, the agent can call the APIs as much as it likes, and costs can skyrocket
  • Access control is coarse: Fine-grained control such as "this agent can access only this data" is difficult, so it tends to be all-allow or all-deny

What's even more troublesome is that, in order to connect to AI agents via MCP, in many cases you need a conversion layer that makes an existing Web API speak MCP (an MCP wrapper) for each system. If you build and operate these individually, wrappers proliferate, and the problems above get spread out across as many systems as you have.

Solving these one by one is quite a painful task.

"MCP Gateway" solves these problems

This is where the concept of MCP Gateway has recently emerged.

An MCP Gateway is a single, governed entry point that sits between AI agents and a group of business systems. By ensuring that every tool call passes through this "checkpoint," you can consolidate authentication, auditing, and control in one place.

The problems listed earlier map neatly onto the features that an MCP Gateway provides.

Problem with direct connection Solution with MCP Gateway
Cumbersome configuration Aggregate and route multiple systems into a single endpoint
Fragmented authentication Centralize authentication and authorization at the entry point
No audit logs Record all calls in one place (audit logs and observability)
Unpredictable costs Enforce call limits with rate limiting and quotas, and reduce duplicate calls with caching
Coarse access control Per-tool access control

Note that if you only want to expose existing Web APIs as MCP, you can achieve that by writing MCP servers yourself. The value of putting an MCP Gateway in between is that, after gathering that conversion in one place, you can apply authentication, auditing, and control together.

How to realize it: SaaS / OSS / DIY

There are broadly three ways to realize an MCP Gateway.

  • SaaS (managed): Leave operations to the vendor. You don't need to build authentication, governance, or scaling yourself, and you can get started quickly. For example, Amazon Bedrock AgentCore Gateway is a fully managed service that can convert existing REST APIs (OpenAPI specifications) and Lambda functions into MCP-compatible tools and expose them from a single endpoint, and it also handles authentication on both the client side and the tool side
  • OSS (self-hosted): Host it yourself. You can customize freely, but operations are your own responsibility. ContextForge, which we cover this time, falls into this category
  • DIY: Build everything yourself. It's hard to choose unless your requirements are special

These three options are, in the end, a trade-off of "how much you build yourself." The order is: SaaS requires minimal building, OSS requires self-operation, and DIY means building everything.

Building the governance layer completely from scratch means shouldering even availability and keeping up with the MCP specification, which is quite a heavy choice. Realistically, leaning toward SaaS or OSS is reasonable.

This time, we'll look at ContextForge as an OSS that you can host yourself and that also supports MCP conversion of existing Web APIs and extension via plugins.

What is ContextForge?

ContextForge (IBM/mcp-context-forge) is an OSS AI Gateway / registry / proxy released by IBM. It can bring not only MCP servers but also A2A (Agent2Agent, a protocol for connecting AI agents with each other) servers and REST/gRPC APIs under one roof and expose them as a unified endpoint.

https://github.com/IBM/mcp-context-forge

The following features are relevant to this article's use case of an "entry point to internal systems."

  • MCP-ifying existing Web APIs: You can register REST APIs as MCP tools. You can set, per tool, a mapping that passes tool parameters to HTTP headers and a timeout (timeout_ms, default 20000 milliseconds) (REST Passthrough)
  • Rate limiting: You can set an upper limit on tool calls with TOOL_RATE_LIMIT (default 100 calls/minute). It is counted per tool and per client (Configuration)
  • Caching: With the Cached Tool Result plugin, you can cache the results of idempotent tools with a TTL (cached_tool_result)
  • Plugin mechanism: It can be extended with a plugin framework called CPEX (ContextForge Plugin Extensions). PII masking, content moderation, circuit breakers, retries, and more are provided as standard (Plugins)
  • Auditing and observability: Traces can be sent to an external backend via OpenTelemetry (OTLP) (OTEL_ENABLE_OBSERVABILITY, disabled by default. Configuration). Authentication and authorization events can be recorded in the security_events table with SECURITY_LOGGING_ENABLED (Security Features)

Trying it out: MCP-ifying an existing Web API with ContextForge

From here, we'll actually start up ContextForge, register an existing Web API as an MCP tool, and go as far as calling it through the MCP Gateway.

Instead of an "existing internal REST API," we'll use SampleAPIs, a dummy API service that can be used without authentication. We'll treat GET https://api.sampleapis.com/coffee/hot as if it were an internal business API.

The configuration we'll build looks like this.

Note that this time we're at the stage of "getting a feel for whether this OSS can meet our requirements," not "how to set up production operations," so we'll go with a minimal configuration of a single container (SQLite). The official docker-compose.yml is a configuration designed for production operation, with large resource requirements and a large amount of configuration, and it was excessive for checking the features. What I cut to arrive at the minimal configuration is summarized as a supplement at the end of the article.

Starting ContextForge

You can start it with a single container, but there are two points to note beforehand.

Note 1: Use strong values for secrets

v1.0.8 validates JWT_SECRET_KEY and AUTH_ENCRYPTION_SECRET at startup, and the process won't start unless the conditions are met (regardless of development or production). The conditions are "at least 32 characters," "a certain level of entropy or higher," and "not a known weak value." For that reason, the command below generates strong values with openssl rand -base64 48.

Note 2: Explicitly enable the Admin UI

MCPGATEWAY_UI_ENABLED and MCPGATEWAY_ADMIN_API_ENABLED are false by default. When trying it with docker run, set both to true so that you can open /admin.

With the above in mind, the startup command looks like this.

$ docker run -d --name mcpgateway-minimal \
    -p 4444:4444 -v "$(pwd)/data-minimal:/data" \
    -e HOST=0.0.0.0 \
    -e DATABASE_URL="sqlite:////data/mcp.db" \
    -e JWT_SECRET_KEY="$(openssl rand -base64 48)" \
    -e AUTH_ENCRYPTION_SECRET="$(openssl rand -base64 48)" \
    -e PLATFORM_ADMIN_EMAIL=admin@example.com \
    -e PLATFORM_ADMIN_PASSWORD=changeme \
    -e MCPGATEWAY_UI_ENABLED=true \
    -e MCPGATEWAY_ADMIN_API_ENABLED=true \
    -e GUNICORN_WORKERS=2 \
    -e EXPOSE_ERROR_DETAILS=true \
    ghcr.io/ibm/mcp-context-forge:v1.0.8

Once it has started, verify with a health check (/health requires no authentication). The base URL for the minimal configuration is http://localhost:4444.

$ export BASE_URL="http://localhost:4444"
$ curl -s ${BASE_URL}/health
Execution result
{
  "status": "healthy",
  "mcp_runtime": {
    "mode": "python",
    "mounted": "python",
    "boot_mode": "off",
    "boot_mounted": "python",
    "effective_mode": "off",
    "override_active": false,
    "override_version": 0,
    "cluster_propagation": "disabled",
    "boot_reconcile_status": "ok",
    "pod_id": "86a9db64527a",
    "rust_build_included": false,
    "rust_runtime_enabled": false,
    "session_core_mode": "python",
    "event_store_mode": "python",
    "resume_core_mode": "python",
    "live_stream_core_mode": "python",
    "affinity_core_mode": "python",
    "session_auth_reuse_mode": "python",
    "rust_session_core_enabled": false,
    "rust_event_store_enabled": false,
    "rust_resume_core_enabled": false,
    "rust_live_stream_core_enabled": false,
    "rust_affinity_core_enabled": false,
    "rust_session_auth_reuse_enabled": false
  }
}

Logging in to the Admin UI

Now that the environment is ready, let's first open the Admin UI. When you access http://localhost:4444/admin in a browser, the login screen is displayed.

ContextForge login screen

Enter the values of PLATFORM_ADMIN_EMAIL and PLATFORM_ADMIN_PASSWORD that you specified at startup (admin@example.com / changeme). On the first login you can't go straight into the admin screen; it switches to a screen asking you to change the password. It's designed so that you can't keep using the initial password, so set a new password here.

Once the change is done, the System Overview screen opens.

ContextForge admin screen (System Overview)

The running version, the MCP runtime status, and metrics such as execution counts and success rates are listed. The left sidebar is a list of the registration targets we'll be working with from here (MCP Servers, Virtual Servers, Tools, Prompts, ...). At this point, there are 0 registered tools and 0 virtual servers, and we'll be adding one business API here.

Understanding the authentication model

Before registering tools and connecting clients, let's organize where ContextForge's authentication applies. Authentication is divided into two layers.

  • ① Client → MCP Gateway: A JWT (Bearer token) is required to connect to the MCP Gateway. Because AUTH_REQUIRED, which requires authentication on all API routes, is true by default (Configuration), tools can't be called without authentication even in this configuration, where nothing is specified in the startup command.
  • ② MCP Gateway → business API: Authentication for each business API. SampleAPIs, which we use this time, happens to require no authentication, but in real operation you would have the MCP Gateway hold and attach API keys or OAuth.

The benefit of the MCP Gateway, "consolidating authentication in one place," comes from this structure: in ①, client authentication is received centrally, and in ②, the MCP Gateway manages the credentials of each API on their behalf.

Below, we'll first issue a JWT token for ① from the Admin UI.

Issuing a JWT token

You can issue a JWT token from the token management screen of the Admin UI. Tokens issued from the screen are registered in the DB, and can be listed and revoked later.

In the Admin UI we logged in to earlier, open "API Tokens" under "ORGANIZATION" in the sidebar.

API Tokens in the sidebar

Specify a name and an expiration, then click "Create Token" to issue it.

Token issuance form in the Admin UI

The expiration is not optional but required, and the form also states "an expiration is required by server policy (REQUIRE_TOKEN_EXPIRATION=true)." It's designed so that you can't create a token without an expiration.

In "Token Scoping," you can narrow the scope this token allows. This time, I specified tools.read, tools.execute in Permissions, making it a token that allows only viewing and executing tools. You can also restrict it to a specific virtual server (Server ID) and restrict the source IP (IP Restrictions).

After issuing, the token string is displayed. This screen is shown only once, so make a note of it here.

Display screen of the issued token

Issued tokens are listed. You can check the creation date, expiration, last-used time, and scope, and you can revoke with "Revoke" and view usage with "Usage Stats."

Token list in the Admin UI

Put the token you noted into an environment variable. You'll use it later as the authentication header (Authorization: Bearer <TOKEN>) when connecting from a client.

$ export TOKEN="<<YOUR_TOKEN>>"

Registering an existing Web API as an MCP tool

Now for the main part. We'll register the SampleAPIs endpoint in ContextForge as a REST tool. When you open "Tools" under "MCP" in the sidebar, there is a form called "Add New Tool from REST API" below the list. This is the entry point for MCP-ifying an existing Web API.

Add New Tool from REST API form

I entered only the following three items.

  • Name: sample-coffee-hot
  • URL: https://api.sampleapis.com/coffee/hot
  • Description: A description of the tool. It's the text the LLM reads when choosing a tool, so write what the tool can do

Integration Type is REST and Request Type is GET by default, so I left them as they are. If you enter url, the base_url and path_template used internally are extracted automatically. Headers, Input Schema, Output Schema, and Json Path Filter can be left empty and it still registers. For an API that requires authentication, choose Basic / Bearer Token / Custom Headers under "Authentication Type" and have it hold the credentials here (SampleAPIs this time requires no authentication, so it stays None).

At the bottom of the form, specify tags and visibility, then click "Add Tool." Visibility has three options: Public / Team / Private, and the default is Public.

Bottom of the form and the Add Tool button

Once registered, it appears in the tool list.

List of registered tools

A Tool ID is assigned, the Source shows the registration source URL, and the Status shows REST Public Online. The Name shown here (sample-coffee-hot) becomes the name used when calling the tool from an MCP client.

You can also verify operation from the screen. From "Actions" in the list, choose "Test" and click "Run Tool," and the result of calling the API through the MCP Gateway is returned as a JSON-RPC response.

Execution result in Test Tool

With isError: false, the SampleAPIs coffee list (such as Black Coffee) is included as text in result.content. api.sampleapis.com/coffee/hot, which was just a REST API, can now be handled as an MCP tool via ContextForge.

Grouping into a virtual server

Registered tools can be grouped as a virtual server and exposed to clients as a single MCP endpoint. Open "Virtual Servers" in the sidebar and use the "Add New Server" form below the list.

Enter a name and description, and check the tools you want to expose under "Associated Tools." The sample-coffee-hot we registered earlier is listed here. Resources and Prompts can be bundled in the same way, but this time it's tools only.

Add New Server form

If you leave Server ID empty, it's generated automatically (specify "Custom UUID" only if you want to carry over an existing ID). Enabling "Enable OAuth 2.0 for MCP Client Authentication" lets MCP clients authenticate via OAuth/SSO through the browser. This time we connect with a JWT token, so I left it off.

When you click "Add Server," the virtual server is added to the list.

List of virtual servers

"1 tool" is displayed, showing that this virtual server has one tool. Opening "View" from "Actions" lets you check the information needed to connect.

Details of the virtual server

The Server ID and a URL containing it are displayed. The MCP endpoint to connect to from a client is this URL with /mcp appended to the end.

http://localhost:4444/servers/<<YOUR_SERVER_UUID>>/mcp

This <<YOUR_SERVER_UUID>> and the JWT token from earlier become the connection information used when connecting from a client.

Connecting from Claude Desktop

We'll connect to the virtual server we created from Claude Desktop, as an actual AI client.

Here I'd like to pause on "where the connection originates from." Claude Desktop has a connector feature that registers a remote MCP server by URL, but that connection originates from Anthropic's cloud, so it can't reach the MCP Gateway running on localhost this time. The same goes for a setup that places the MCP Gateway inside an internal network: if you set it up somewhere unreachable from the internet, this route can't be used.

So this time we'll use the method of writing it in the configuration file. Only stdio format can be written in Claude Desktop's configuration file, so we put in mcp-remote, which receives over stdio and bridges to HTTP.

First, write the token you put in the TOKEN environment variable earlier out to a header file.

$ echo "Authorization: Bearer ${TOKEN}" > ~/.contextforge-headers.txt
$ chmod 600 ~/.contextforge-headers.txt

Next, add the following to the configuration file claude_desktop_config.json (on macOS, ~/Library/Application Support/Claude/claude_desktop_config.json). Replace <<YOUR_SERVER_UUID>> with the ID of the virtual server and <<YOUR_USERNAME>> with your own username.

claude_desktop_config.json
{
  "mcpServers": {
    "contextforge": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "http://localhost:4444/servers/<<YOUR_SERVER_UUID>>/mcp",
        "--allow-http",
        "--transport", "http-only",
        "--header-file", "/Users/<<YOUR_USERNAME>>/.contextforge-headers.txt"
      ]
    }
  }
}

For details on the flags of mcp-remote and how to pass the authentication header, refer to the official README.

https://www.npmjs.com/package/mcp-remote

When you restart Claude Desktop, the registered business API tool becomes available from Claude.

Executing the tool from Claude Desktop via ContextForge

From the AI client's perspective, the connection target is just a single ContextForge endpoint. Behind it, multiple business systems can be bundled, and the connection to the MCP Gateway is authenticated with a JWT. This is the concrete form of a "governed entry point."

Seeing "what was called, and how much" on the Metrics screen

Another benefit of going through the MCP Gateway is that records of calls are gathered in one place. With direct connections, you have no choice but to go look at each API's logs individually, whereas ContextForge lets you view calls that passed through the MCP Gateway together in "Metrics" under "MONITORING" in the sidebar.

Let's open it after having run the tool from earlier a few times.

Overview tab of the Metrics screen

The cards at the top show entity counts (users, teams, MCP resources, collected metrics), and below them are execution-related indicators: total executions, success rate, average response time, and error rate.

Furthermore, "Top Performers" ranks the most-used tools, resources, prompts, and virtual servers. For each tool, the execution count, average response time, success rate, and last-used time are shown, so you can tell "which APIs are being used and which are slow" from this screen alone. Below that is a breakdown for each of Tools / Resources / Prompts / Servers (success and failure counts, failure rate, average response time, last execution time).

Switching the tabs at the top of the screen shows other perspectives. The "Activity" tab lets you check the state of API tokens, the number of sessions, and the number of collected metrics.

Activity tab of the Metrics screen

Active / Revoked / Total of issued tokens, the number of MCP sessions, and "Token Logs," which is the number of token usage log entries. You can trace whose token is being used and how much.

The "Security" tab shows the counts of authentication events and audit logs.

Security tab of the Metrics screen

Auth Events are authentication events such as logins, and in this environment the logins I redid are counted. Audit Logs accumulate when AUDIT_TRAIL_ENABLED is enabled, and since it's disabled this time, there are 0 entries.

The numbers themselves are small because this is a test environment, but the fact that just by routing through one MCP Gateway, per-tool usage records and response times are collected automatically is valuable in itself. With direct connections, for this kind of "which API was called, how much, and how fast," you have no choice but to cross-reference the logs on each API side.

Supplement: You can operate it from either the UI or the API

All the operations so far were done from the Admin UI, but the same things can be done from the REST API. Since the Admin UI itself calls this API, whatever you can do on the screen you can also do with the API. This is suited to cases where you want to manage tool and virtual server registration as code, or push it in from CI/CD.

The list of endpoints can be viewed as-is at /docs (Swagger UI) and /redoc of the running MCP Gateway. If your browser is already logged in to the Admin UI, you can open it directly.

http://localhost:4444/docs

For concrete usage, the API Usage Guide in the official documentation collects examples for each endpoint.

https://ibm.github.io/mcp-context-forge/manage/api-usage/

Supplement: What I cut to make the minimal configuration

The official docker-compose.yml is a configuration designed for production operation. Even without specifying a profile, it brings up the Gateway (3 replicas), nginx, PostgreSQL, pgbouncer, Redis, a job for DB migration, a sample MCP server and its registration job. Adding the monitoring profile further adds Prometheus, Grafana, Loki, Tempo, pgAdmin, and so on, and the sso profile adds Keycloak.

This time, I replaced these as follows and reduced it to a single container.

Full configuration This time's minimal configuration
PostgreSQL + pgbouncer (connection pool) SQLite (DATABASE_URL="sqlite:////data/mcp.db")
Redis (CACHE_TYPE=redis) Keep the default CACHE_TYPE=database. Don't start Redis
nginx (TLS termination and caching, exposed on 8080) Expose the Gateway's 4444 as-is
One-shot job for migration Not needed since the SQLite file is created at startup
Sample MCP server and auto-registration job Not needed since I register the sample Web API myself
Gateway 3 replicas / GUNICORN_WORKERS=24 1 container / GUNICORN_WORKERS=2
Monitoring stack (monitoring profile) Check on the Admin UI's Metrics screen

Conversely, there are parts where the defaults aren't enough with docker run, so I've added them explicitly.

  • MCPGATEWAY_UI_ENABLED / MCPGATEWAY_ADMIN_API_ENABLED: Both are false by default, so set them to true to use the Admin UI
  • JWT_SECRET_KEY / AUTH_ENCRYPTION_SECRET: Their strength is validated at startup, so pass generated values
  • EXPOSE_ERROR_DETAILS=true: By default validation errors are masked and only {"detail": "An error occurred, please try again."} is returned, so I made details visible during verification (this is a setting that should be hidden in production)

There are also corresponding limitations from the cuts. Since I removed nginx and exposed it directly over HTTP, a secure cookie warning appears on the login screen. With SQLite and a single container, sharing across multiple instances and scaling can't be verified. Since there is no monitoring stack, metrics are limited to what's visible from the Admin UI. It was sufficient for the purpose of checking "whether the features meet the requirements," but for verifying a production configuration you would need to build the full configuration separately.

Conclusion

Starting from the theme of referencing internal business systems from AI agents, I looked at the concept of MCP Gateway and its OSS implementation, ContextForge, hands-on.

To reiterate, the process of converting Web APIs to MCP is necessary one way or another, but the essence of MCP Gateway is that it can bundle that conversion and consolidate governance such as authentication, auditing, rate limiting, and caching in one place. In particular, for business systems where API usage is pay-as-you-go, cost control through rate limiting and caching becomes effective. In real operation, rather than governing everything uniformly, you could also consider a mixed approach such as routing only the systems with high cost risk through the Gateway.

If you're starting to struggle with managing a growing number of MCP servers, I think trying MCP-ifying and bundling one existing API locally once will give you a feel for where an MCP Gateway is effective. Please give it a try.

I hope this blog is helpful to someone.

References

  • ContextForge (IBM/mcp-context-forge)

https://github.com/IBM/mcp-context-forge

  • ContextForge official documentation

https://ibm.github.io/mcp-context-forge/

  • SampleAPIs used as the subject

https://sampleapis.com/

  • mcp-remote (a bridge between stdio ⇄ remote MCP)

https://www.npmjs.com/package/mcp-remote


AI白書2026 配布中

クラスメソッドが独自に行なったAI診断調査をもとに、企業のAI活用の現在地を調査レポートとしてまとめました。企業規模別の活用度傾向に加え、規模を超えてAI活用を進める企業に共通する取り組みまで、自社の現在地を捉えるためのヒントにぜひ。

AI白書2026

無料でダウンロードする

Share this article