doroseek
Doroseek is a simple AI app built with Deno and Fresh, providing OpenAI compatible endpoints and acting as an MCP server and proxy.
Doroseek
A simple AI app built with Deno and Fresh.
- Access all your OpenAI Compatible endpoints with the same base URL and API
key. And you can share the
Doroseek
API key with others to access the endpoints. - As MCP server with several build-in servers.
- As MCP Proxy server, connect to other MCP server.
Features
- OpenAI Compatible endpoints
- Manage endpoints and API keys
- Generate
Doroseek
API keys - Assign alias to models
- route
- manage route:
/{key}
- OpenAI Compatible route:
/api
- manage route:
- MCP SSE Server
- sequentialthinking - Sequential Thinking
- think - Think Tool MCP Server
- route
/mcp/{server}/sse?apiKey={apiKey}
- MCP Proxy Server
- route
- stdio:
/mcp/proxy/sse?apiKey={apiKey}&transport=stdio&command=&args=&env=
- sse:
/mcp/proxy/sse?apiKey={apiKey}&transport=sse&url=
- stdio:
- examples
- Sequential Thinking:
/mcp/proxy/sse?apiKey={apiKey}&transport=stdio&command=npx&args=-y @modelcontextprotocol/server-sequential-thinking&env={}
- Sequential Thinking:
- route
New Core Features (MCP Based)
Doroseek
now includes several powerful MCP-based services for advanced use cases:
- Intranet Penetration (Tunneling): Expose local services to the internet.
- Multi-User Communication Rooms: Enable real-time communication between multiple clients.
- Resource Sharing: Upload and share small files or data snippets.
These features leverage WebSockets for real-time communication and Deno KV for persistence where applicable.
1. Intranet Penetration (Tunneling)
Concept:
This feature allows you to expose services running on your private network (e.g., a local development server, a database, or any TCP/HTTP service) to the public internet through a secure tunnel established with your Doroseek
instance.
Local Agent:
To use this feature, a local agent (client software) must be run on the machine where the private services are accessible. Doroseek
itself can also run in this "Agent Mode". For details on configuring and running Doroseek
as a local agent, see the Agent Mode section below. The agent is responsible for connecting to a remote Doroseek
instance (acting as a relay), managing the tunnel, and forwarding traffic between the relay and the local services.
Registration Process (Agent to Relay):
-
Connection: The local agent establishes a WebSocket connection to the
Doroseek
MCP server:wss://your-doroseek-instance/mcp/tunnel/register?apiKey=<your_api_key>
An API key is mandatory for registration.
-
Registration Message: After the WebSocket connection is established, the agent sends a
register
message. This message details the services it wishes to expose. Exampleregister
message from agent:{ "type": "register", "data": { "services": [ { "type": "http", "local_port": 3000, "subdomain_or_path": "my-web-app" }, { "type": "http", "local_port": 8080, "subdomain_or_path": "api-service" } // Other types like 'tcp' might be supported by the agent protocol in the future. ] } }
-
Server Response: Upon successful registration,
Doroseek
responds with aregistered
message containing the uniquetunnelId
and the public base URL for accessing the tunneled services. Exampleregistered
message from server:{ "type": "registered", "data": { "tunnelId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "public_base_url": "https://your-doroseek-instance/t/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } }
Accessing Tunneled Services:
Once the tunnel is established, your local services can be accessed via the public URLs derived from the public_base_url
and the subdomain_or_path
defined during registration. For example, if your-doroseek-instance
is example.com
and a service was registered with subdomain_or_path: 'my-web-app'
, it might be accessible via:
https://example.com/t/<tunnelId>/my-web-app/...
The exact URL structure depends on how the public-facing routing (/t/:tunnelId/...
) is configured to map to specific services.
Local Agent Responsibilities (High-Level):
- Initiate and maintain the WebSocket connection to
/mcp/tunnel/register
. - Send the
register
message with service definitions. - Listen for
httpRequest
messages fromDoroseek
over the WebSocket. EachhttpRequest
message will contain:requestId
: A unique ID for the request.data
: An object withmethod
,path
,headers
, andbody
of the incoming public request.
- Upon receiving an
httpRequest
, the agent makes a corresponding request to its local service (e.g.,http://localhost:3000/some/path
). - Once the local service responds, the agent sends an
httpResponse
message back toDoroseek
over the WebSocket, including the originalrequestId
and the response details (status, headers, body). - (WebSocket proxying through the tunnel is planned for future enhancements but is currently stubbed in
Doroseek
's public-facing tunnel route).
2. Multi-User Communication Rooms
Concept: Enable real-time, bi-directional communication between multiple clients. This can be used as a backend for features like live chat in web applications, collaborative editing, or other multi-user interactive experiences.
Connecting to a Room:
Clients connect to a room using a WebSocket connection. The roomId
is specified in the path.
- WebSocket Endpoint:
wss://your-doroseek-instance/mcp/room/:roomId?apiKey=<optional_api_key>
- Authentication:
- Anonymous Access: Currently, clients can connect without an API key.
- API Key Authenticated Access: If an
apiKey
is provided in the query string, it is validated. This allows associating users with an API key owner if needed.
Core Functionality:
- Joining a Room: A user joins a room by successfully establishing a WebSocket connection to the room's endpoint.
- On join, the server sends a
ServerRoomInfoMessage
to the joining user, containing a list of users already in the room. - Other users in the room receive a
ServerUserJoinedMessage
.
- On join, the server sends a
- Leaving a Room: When a user's WebSocket connection is closed, they are automatically removed from the room.
- Other users in the room receive a
ServerUserLeftMessage
.
- Other users in the room receive a
- Sending Chat Messages: Clients send chat messages over the WebSocket.
Example
ClientChatMessage
from client:{ "type": "chatMessage", "payload": { "roomId": "your-target-room-id", // Though roomId is in path, can be in payload "message": "Hello everyone!" } }
- Receiving Messages: Clients listen for messages from the server.
ServerChatMessage
: A chat message sent by another user in the room.{ "type": "chatMessage", "payload": { "roomId": "the-room-id", "fromUserId": "user-id-of-sender", "message": "Hello everyone!", "timestamp": "2023-01-01T12:00:00.000Z" } }
ServerUserJoinedMessage
: Notifies that a new user has joined.ServerUserLeftMessage
: Notifies that a user has left.
Conceptual Client-Side Interaction Example (JavaScript):
const roomId = "my-chat-room";
const apiKey = "your-optional-api-key"; // Or leave undefined for anonymous
const socket = new WebSocket(`wss://your-doroseek-instance/mcp/room/${roomId}?apiKey=${apiKey}`);
socket.onopen = () => {
console.log("Connected to room:", roomId);
// Send a chat message
socket.send(JSON.stringify({
type: "chatMessage",
payload: { roomId, message: "Hi from client!" }
}));
};
socket.onmessage = (event) => {
const serverMessage = JSON.parse(event.data);
console.log("Received message:", serverMessage);
if (serverMessage.type === "chatMessage") {
// Display chat: serverMessage.payload.fromUserId, serverMessage.payload.message
} else if (serverMessage.type === "userJoined") {
// Update user list
} // etc.
};
socket.onclose = () => {
console.log("Disconnected from room:", roomId);
};
socket.onerror = (error) => {
console.error("WebSocket error:", error);
};
3. Resource Sharing
Concept:
Allows users to upload small files or data snippets (e.g., configuration files, JSON data, small images) to Doroseek
and share them via a unique, publicly accessible URL.
Upload Process (MCP WebSocket):
-
Endpoint: Connect via WebSocket to
/mcp/fileshare/upload
.wss://your-doroseek-instance/mcp/fileshare/upload?apiKey=<your_api_key>
A valid API key is required for uploading files.
-
Message Flow:
- Client -> Server:
ClientInitiateUploadMessage
The client first sends a message to initiate the upload, providing metadata about the file.{ "type": "initiateUpload", "payload": { "filename": "config.json", "filetype": "application/json", "size": 1024 // Size in bytes } }
- Server -> Client:
ServerUploadReadyMessage
If the server accepts the upload (e.g., size is within limits), it responds with a uniqueresourceId
.{ "type": "uploadReady", "payload": { "resourceId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } }
- Client -> Server:
ClientFileDataMessage
The client sends the actual file data, base64 encoded.{ "type": "fileData", "payload": { "resourceId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "data": "eyJrZXkiOiAidmFsdWUifQ==" // Base64 encoded content of the file } }
- Server -> Client:
ServerUploadCompleteMessage
Upon successfully saving the file data, the server confirms completion and provides the download URL.{ "type": "uploadComplete", "payload": { "resourceId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "downloadUrl": "https://your-doroseek-instance/shared/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } }
- Client -> Server:
Download Process (HTTP GET):
- URL Format: Files can be downloaded via a simple HTTP GET request to:
https://your-doroseek-instance/shared/:resourceId
- Authentication: By default, downloading does not require an API key. The link is publicly accessible if known.
Limitations:
- File Size Limit: Currently, this feature is intended for small files. Due to the use of Deno KV as a backend for storing file data directly, individual file sizes are effectively limited to Deno KV's value size limit, which is typically around 60KB. Uploads exceeding this will be rejected. Chunked uploading for larger files is a potential future enhancement.
Running locally
This section describes running Doroseek
in its default Server Mode. For running Doroseek
as a local agent for the Tunneling feature, see the Agent Mode section.
Server Mode Configuration
copy .env.example to .env
# .env
ADMIN_KEY=the_admin_key_here
MCP_MAX_DURATION=60
By default, the project allows any key to create its corresponding settings, if
you need to restrict access to only a specific key, you need to set the
ADMIN_KEY
environment variable.
The MCP SSE connection can keep MCP_MAX_DURATION
second.
Set the db if needed
// services/database.ts
export const db = await Deno.openKv("./db");
Running in Server Mode
To run the app in its default server mode, ensure DOROSEEK_AGENT_MODE_ENABLED
is not set to "true"
.
You will need to install Deno. Then run from the root of this repository:
deno task start
Agent Mode (for Intranet Penetration)
Doroseek
can also operate in Agent Mode. In this mode, it does not start the Fresh web server. Instead, it acts as a local client agent that connects to a remote Doroseek
instance (acting as a relay server) to expose services from your private network to the internet.
This is an alternative running mode to its default server mode. When Agent Mode is enabled and configured correctly, Doroseek
will exclusively perform agent duties.
Agent Mode Configuration
To enable and configure Agent Mode, you need to set the following environment variables:
-
DOROSEEK_AGENT_MODE_ENABLED
:- Set to
"true"
to enable Agent Mode. If this is not set to"true"
,Doroseek
will attempt to start in Server Mode.
- Set to
-
DOROSEEK_RELAY_URL
:- The WebSocket URL of the remote
Doroseek
instance (acting as the relay server) to which this agent should connect. This URL should point to the relay's tunnel registration endpoint. - Example:
wss://your-remote-doroseek.com/mcp/tunnel/register
- The WebSocket URL of the remote
-
DOROSEEK_AGENT_API_KEY
:- The API key that this agent will use to authenticate with the remote
Doroseek
relay server. This API key must be recognized and authorized by the relay server.
- The API key that this agent will use to authenticate with the remote
-
DOROSEEK_AGENT_SERVICES_JSON
:-
A JSON string defining an array of local services that this agent should expose through the tunnel.
-
Each service object in the array must have the following fields:
id
(string): A unique identifier for the service (chosen by you, e.g., "my-web").name
(string): A user-friendly name for the service (e.g., "My Local Web Server").type
(string): The type of service. Currently, only"http"
is supported by the agent's HTTP handler.local_host
(string): The hostname or IP address of the local service (e.g.,"localhost"
,"127.0.0.1"
).local_port
(number): The port number on which the local service is running (e.g.,8080
).subdomainOrPath
(string): A string that will be used by the relay server to form the public URL for this service. It should not contain/
or spaces. It effectively becomes a path segment on the relay's public tunnel URL.- For example, if the relay provides a base URL like
https://<relay-public-domain>/t/<tunnelId>
, and you setsubdomainOrPath
to"myweb"
, your service will be accessible athttps://<relay-public-domain>/t/<tunnelId>/myweb/...
.
- For example, if the relay provides a base URL like
-
Example
DOROSEEK_AGENT_SERVICES_JSON
value:[ { "id": "web1", "name": "My Local Web Server", "type": "http", "local_host": "localhost", "local_port": 8080, "subdomainOrPath": "myweb" }, { "id": "api2", "name": "Backend API", "type": "http", "local_host": "127.0.0.1", "local_port": 3000, "subdomainOrPath": "myapi" } ]
To set this as an environment variable, the JSON string typically needs to be compact (no newlines) and properly escaped if set in certain shell environments. For example, in a
.env
file or shell:DOROSEEK_AGENT_SERVICES_JSON='[{"id":"web1","name":"My Local Web Server","type":"http","local_host":"localhost","local_port":8080,"subdomainOrPath":"myweb"},{"id":"api2","name":"Backend API","type":"http","local_host":"127.0.0.1","local_port":3000,"subdomainOrPath":"myapi"}]'
-
Running in Agent Mode
- Set all the required environment variables listed above. Ensure
DOROSEEK_AGENT_MODE_ENABLED
is set to"true"
. - Run the application using the standard command:
deno task start
- If the configuration is valid,
Doroseek
will start in Agent Mode. You will not see the usual Fresh server startup logs (e.g., "Listening on http://localhost:8000/"). - Instead, look for log messages indicating Agent Mode operation, such as:
[Main] Doroseek starting in Agent Mode.
[Agent Config] Agent configuration loaded successfully.
[Agent Connector] Initialized with Relay URL: wss://your-remote-doroseek.com/mcp/tunnel/register
[Agent Connector] Attempting to connect to ...
[Agent Connector] WebSocket connection established.
[Agent Connector] Sent registration request: ...
[Agent Connector] Successfully registered. Tunnel ID: <your-tunnel-id>, Public URL: <your-public-base-url>
[Main] Agent is connected and registered with the relay.
[Main] Tunnel ID: <your-tunnel-id>
[Main] Public Base URL: <your-public-base-url>
- Service 'My Local Web Server' (web1) accessible via: <your-public-base-url>/myweb
- Service 'Backend API' (api2) accessible via: <your-public-base-url>/myapi
Interaction with the Relay (Agent Perspective)
- The agent (this
Doroseek
instance running in Agent Mode) establishes a WebSocket connection to theDOROSEEK_RELAY_URL
, which should be the/mcp/tunnel/register
endpoint of a remoteDoroseek
instance running in Server Mode. - It sends a registration message detailing the local services defined in
DOROSEEK_AGENT_SERVICES_JSON
. - The remote relay server, upon successful registration, provides the agent with a unique
tunnelId
and apublic_base_url
. - Subsequently, when the relay server receives public HTTP requests matching the tunnel, it forwards these requests (as
httpRequest
messages) to the agent over the established WebSocket tunnel. - The agent processes these
httpRequest
messages, makes requests to the configured local services, and sendshttpResponse
messages back to the relay. - The agent also responds to
ping
messages from the relay withpong
messages, indicating its status and the health of its primary local service.
Tunnel Health Check API
To monitor the status of an established tunnel and the underlying local service, Doroseek
provides a Health Check API endpoint.
-
Endpoint:
GET /tunnel/:tunnelId/status
-
Description: This endpoint allows you to query the current status of a specific tunnel identified by
:tunnelId
. It checks both the WebSocket connection from the relay to the local agent and the agent's ability to reach its configured local service(s). -
Authentication: This endpoint does not currently require specific API key authentication, but the
tunnelId
must be valid and known to the system. Access control can be layered on top via standard reverse proxy or gateway mechanisms if needed. -
Response Body (
HealthStatusReport
): The API returns a JSON object with the following structure:{ "tunnelId": "string", // The ID of the tunnel checked "tunnelStatus": "connected" | "disconnected" | "unknown", "localServiceStatus": "ok" | "error" | "unconfigured" | "timeout" | "unknown" | "agent_unresponsive", "checkedByInstanceId": "string", // ID of the relay instance that performed/reported the check "timestamp": "string" // ISO 8601 timestamp of when the check was performed }
tunnelId
: The ID of the tunnel that was checked.tunnelStatus
:"connected"
: The relay server has an active WebSocket connection to the local agent for this tunnel."disconnected"
: The relay server does not have an active WebSocket connection to the local agent."unknown"
: The status of the tunnel could not be determined (e.g., tunnel ID not found in the primary database).
localServiceStatus
:"ok"
: The local agent responded to a health check ping and reported its primary configured local service is reachable."error"
: The local agent responded, but reported an error when trying to check its local service."unconfigured"
: The local agent responded, but has no local services configured to check, or the service type is not checkable by the agent."timeout"
: The local agent responded, but its attempt to check the local service timed out."agent_unresponsive"
: The relay server is connected to the agent, but the agent did not respond to a health check ping within the expected time."unknown"
: The status of the local service could not be determined (e.g., becausetunnelStatus
is not"connected"
).
checkedByInstanceId
: The unique ID of the relay server instance that performed or last reported the health status. Useful in multi-instance deployments.timestamp
: The ISO 8601 timestamp of when the health status was determined.
-
Example Usage: Request:
GET /tunnel/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/status
Example Response:
{ "tunnelId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "tunnelStatus": "connected", "localServiceStatus": "ok", "checkedByInstanceId": "yyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy", "timestamp": "2023-10-27T10:30:00.000Z" }
Another Example (Agent connected, but local service is down):
{ "tunnelId": "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz", "tunnelStatus": "connected", "localServiceStatus": "error", "checkedByInstanceId": "wwwwwww-wwww-wwww-wwww-wwwwwwwwwwww", "timestamp": "2023-10-27T10:35:00.000Z" }
Related MCP Servers
View all research_and_data servers →Sequential Thinking
by modelcontextprotocol
An MCP server implementation that provides a tool for dynamic and reflective problem-solving through a structured thinking process.
exa-mcp-server
by exa-labs
A Model Context Protocol (MCP) server allows AI assistants to use the Exa AI Search API for real-time web searches in a secure manner.
arxiv-mcp-server
by blazickjp
The ArXiv MCP Server provides a bridge between AI assistants and arXiv's research repository through the Model Context Protocol (MCP).
sitemcp
by ryoppippi
SiteMCP is a tool that fetches an entire site and uses it as a Model Context Protocol (MCP) Server.
Sequential Thinking MCP Server
by modelcontextprotocol
An MCP server implementation that provides a tool for dynamic and reflective problem-solving through a structured thinking process.
firecrawl-mcp-server
by mendableai
Firecrawl MCP Server is a Model Context Protocol server implementation that integrates with Firecrawl for web scraping capabilities.
mcp-compass
by liuyoshio
MCP Compass is a discovery and recommendation service for exploring Model Context Protocol servers using natural language queries.