Run an MCP server on Azion
Build a Model Context Protocol server with the MCP SDK and Hono, run it as an Azion function, and deploy it with the Azion CLI.
You can run your own Model Context Protocol (MCP) server as an Azion function and deploy it with the Azion CLI. To connect a coding agent to the MCP servers that Azion hosts, refer to MCP server quickstart.
MCP is an open specification that uses JSON-RPC to standardize how applications and AI agents communicate. A server exposes three kinds of capabilities: tools (actions), resources (data such as files or API responses), and prompts (shared prompt templates). Any compatible client can list and call the tools, read the resources, and fetch the prompts. A language model can then call your functions and read your data. For more information, refer to the MCP documentation.
The server on this page uses the MCP SDK for TypeScript, @modelcontextprotocol/sdk, which implements the protocol. Hono routes the HTTP requests. The SDK’s WebStandardStreamableHTTPServerTransport answers them over streamable HTTP and works with the Fetch API Request and Response objects that a function receives and returns. For the other transports the protocol defines, refer to Transports.
Prerequisites
- An Azion account. To create one, refer to Create an account.
- The Azion CLI, installed and logged in. For the setup, refer to Azion CLI quickstart.
- Node.js and npm. The CLI runs Azion Bundler with
npxto build the project, and npm installs the packages the server imports.
Create and deploy the server
The CLI creates a Hono project from a template. You replace the template’s entry with the MCP server, run it locally, and deploy it. The server uses the high-level McpServer class, which registers each tool, resource, and prompt with one method call.
To create, run, and deploy the server:
Run azion init with a name for the project:
At Choose a preset:, select Hono. You can type Hono to filter the list. At Choose a template:, select Hono Boilerplate. Answer Y to install the dependencies, and n to the local development server and to the deploy. The command prints this output:
The project is in the my-mcp-server folder, and its entry is src/index.ts. For every question and the flags that skip them, refer to Azion CLI init.
The template installs hono only. Go to the project folder. Install the MCP SDK and version 3 of zod, which the SDK uses:
npm adds the two packages to the dependencies of package.json, next to hono.
Replace the contents of src/index.ts with the following code. It registers an add tool and a greeting resource, and it answers MCP requests on POST /mcp:
Each request gets a new server and a new transport with no session ID, so the server keeps no state between requests. An McpServer instance connects to one transport at a time, so the code creates it in getServer() for each request. On an error, the handler logs the error and returns the JSON-RPC error -32603, Internal server error, with HTTP status 500.
From the project folder, start the local development server:
The command builds src/index.ts and serves the function on port 3333:
The server keeps running until you stop it. For the flags of the command, refer to Azion CLI dev.
In a second terminal, send an MCP initialize request to http://localhost:3333/mcp. The client must accept both JSON and an event stream:
The server answers with one event that holds its name and capabilities:
To list the tools, send a tools/list request to the same URL:
The result lists the add tool with the input schema that the code declares:
Stop the local server, or open a second terminal, and deploy the project from the project folder:
The CLI uploads and builds the project. At the end, it prints the URL of the project’s domain, in the form https://xxxxxxxxxx.map.azionedge.net. For the deploy output and its flags, refer to Azion CLI deploy.
The MCP server runs on Azion’s distributed infrastructure and answers at https://<your-domain>/mcp, where <your-domain> is the domain that azion deploy printed. The first deploy can take several minutes to answer from every location. Later deploys take about two minutes.
Read the deploy configuration
azion deploy creates the resources that azion.config.ts declares, and azion init wrote that file from the Hono template. It builds src/index.ts with the typescript preset and with polyfills turned on. The build writes the function to .edge/functions/index.js, which the file names ./functions/index.js. An application runs that function on every path through a request rule named Execute Function, and a workload serves the application:
The CLI fills each $ name when it creates the resource, and it records the resource IDs in azion/azion.json. For every setting in the file, refer to azion.config.js.
A project folder that azion init did not create has neither file, and azion build refuses to build it with Azion configuration not found. Run azion link in that folder first, then azion build and azion deploy. For the questions azion link asks, refer to Azion CLI link.
Connect a client to the server
An MCP client needs the URL of the server: https://<your-domain>/mcp after the deploy, or http://localhost:3333/mcp while azion dev runs. The path is /mcp because the server’s Hono route is app.post('/mcp', …).
Configure the client as for the Azion MCP servers, with your URL in place of https://docs-mcp.azion.com/mcp. For the client settings, refer to MCP server quickstart. The example server checks no credentials, so the client sends no Authorization header, and anyone with the URL can call its tools.
Use the Server class
The SDK’s low-level Server class replaces the register methods of McpServer with request handlers. You write the handler for each MCP method yourself, which gives you full control over each response. Each capability needs one handler that lists it and one that calls or reads it:
| Capability | McpServer method | Server list handler | Server call or read handler |
|---|---|---|---|
| Tools | registerTool | ListToolsRequestSchema | CallToolRequestSchema |
| Resources | registerResource | ListResourcesRequestSchema | ReadResourceRequestSchema |
| Prompts | registerPrompt | ListPromptsRequestSchema | GetPromptRequestSchema |
Register each handler with server.setRequestHandler(<schema>, async (request) => { ... }). The schemas come from @modelcontextprotocol/sdk/types.js, which also exports the schemas of the other MCP methods. For more information, refer to the MCP SDK for TypeScript.
The following src/index.ts serves the tools and prompts of the HubSpot MCP server package, @hubspot/mcp-server. It declares the tools, prompts, and resources capabilities and registers four handlers. The route, the transport, and the error handling are the same as in the McpServer server. Add the package to the project before you build it:
The HubSpot package reads a HubSpot access token from the PRIVATE_APP_ACCESS_TOKEN environment variable. Without the variable, azion dev builds the project and then stops with HubSpot access token is required.
Run and deploy this server with the same azion dev and azion deploy commands as the McpServer server.
Prepare the server for agents
An agent chooses a tool from its name and description, and calls it with the inputs its schema declares. Check these points before you give the URL to others:
| Area | Practice |
|---|---|
| Tool names | Name each tool with a verb and a noun, such as search_docs or create_rule. |
| Tool descriptions | Say when an agent uses the tool and how. |
| Tool inputs | Declare a type for every parameter, and validate each value before you use it. |
| Errors | Return a message that says what failed. |
| Repeated calls | Make each tool safe to call more than once. |
| Responses | Cache data that tools read often, paginate large results, set timeouts on long operations, and compress large responses. |
| Access | Limit the number of requests each token can send, and log every sensitive operation. |
| Output | Remove sensitive data from a response before you return it. |
For a larger example of a server built with Hono and the MCP SDK, refer to the aziontech/mcp-server repository.