https://github.com/joeymeere/emcp
A framework for building simple MCP servers with custom middleware
https://github.com/joeymeere/emcp
mcp model-context-protocol
Last synced: 4 months ago
JSON representation
A framework for building simple MCP servers with custom middleware
- Host: GitHub
- URL: https://github.com/joeymeere/emcp
- Owner: joeymeere
- License: mit
- Created: 2025-03-02T06:05:00.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2025-03-09T00:02:41.000Z (8 months ago)
- Last Synced: 2025-03-11T06:40:53.208Z (8 months ago)
- Topics: mcp, model-context-protocol
- Language: TypeScript
- Homepage:
- Size: 30.3 KB
- Stars: 10
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-mcp-servers - **emcp** - A framework for building simple MCP servers with custom middleware `typescript` `mcp` `model-context-protocol` `server` `npm install joeymeere/emcp` (🌐 Web Development)
README
# eMCP
A fork of the [LiteMCP](https://github.com/wong2/litemcp) TS library with extended features like built-in authentication handling, and custom middleware.
## Features
This is designed to be a near drop-in replacement for tools like LiteMCP. Because of this, all added features are currently optional.
- All current LiteMCP features
- Built-in authentication handler
- Custom layered middleware support
## Quickstart
Install via Bun or NPM:
```bash
npm i emcp
# or use Bun (preferred)
bun add emcp
```
### Basic Usage
(Optional) Run the examples:
```bash
bun run example:basic
bun run example:auth
bun run example:middleware
bun run example:advanced
```
```ts
const server = new eMCP("mcp-server-with-auth", "1.0.0", {
authenticationHandler: async (request) => {
// implement your custom auth logic here
return true;
},
});
// Request to this tool, or any other resource or prompt will
// require authentication governed by the handler
server.addTool({
name: "add",
description: "Add two numbers",
parameters: z.object({
a: z.number(),
b: z.number(),
}),
execute: async (args) => {
server.logger.debug("Adding two numbers", args);
return args.a + args.b;
},
});
```
### Custom Middleware
```ts
const server = new eMCP("mcp-server-with-middleware", "1.0.0", {
authenticationHandler: async (request) => {
// implement your custom auth logic here
return true;
},
});
// This will time entire req -> res cycle, including middlewares
server.use(async (request, next) => {
const startTime = Date.now();
server.logger.debug("Request started", { method: request.method });
// Wait for all inner middleware and the handler to complete
const response = await next();
const endTime = Date.now();
server.logger.debug("Request completed", {
method: request.method,
duration: `${endTime - startTime}ms`,
});
return response;
});
```
## How Middleware Works
Middleware in eMCP runs in order of registration. Once every middleware handler has hit it's `next()` block, then the standard MCP procedure will occur. Once the server is finished processing, then the order will run in reverse for middleware handlers with code after the `next()` block.
To put it simply, it looks something like this:
```
<---- Request received ----
1. Middleware 1
2. Middleware 2
<---- Pre-processing done ---->
4. Server handler
<---- Post-processing start ---->
5. Middleware 2
6. Middleware 1
---- Response sent ---->
```
If you're familiar with frameworks like Hono, then this will be familiar to you.
## Roadmap
- Ergonomic MCP<->MCP communication
- Integration into frameworks
## Why?
Because I felt like it