Uprising
Filesystem-driven MCP server that transforms directories into living AI capabilities.
Turn a folder of definitions into a complete Model Context Protocol server. Uprising discovers your tools, resources, and prompts—awakening them for the coming robot uprising.
Quick Start
npm install uprisingCreate your server directory:
my-server/
├── instructions.md # Server instructions (optional)
├── package.json # Metadata (optional)
├── tools/ # Executable capabilities
│ ├── example.js
│ ├── another.mdx
│ └── simple.md # Not supported - tools need exec logic
├── resources/ # Data providers
│ ├── docs.js
│ ├── api.mdx
│ └── guide.md # ✅ Plain markdown works!
└── prompts/ # Templated conversations
├── helper.js
├── advanced.mdx
└── simple.md # ✅ Plain markdown works!You can use the provided CLI to start the MCP server, providing it with the directory that contains your MCP setup:
npx uprising ./my-serverOr in code:
import { start } from 'uprising';
await start('./my-server', {
myConfig: 'value'
});Table of Contents
- Tools - Executable capabilities
- Resources - Data providers
- Prompts - Templated conversations
- Instructions - Server-level guidance
- Template Variables - Available interpolation data
- Best Practices - Recommended patterns
- CLI Usage - Command line interface
- MCP Integration - Connect to MCP clients
Tools
Tools are executable capabilities. They require an exec function, so they must be authored in JavaScript/TypeScript or MDX (plain .md is not supported).
JavaScript Tool
// tools/deploy.js
import { z } from 'zod';
export default {
title: 'Deploy Application',
description: 'Deploy an application to a specific environment',
inputSchema: {
app: z.string().min(1),
env: z.enum(['dev', 'staging', 'prod']).default('dev'),
force: z.boolean().optional()
},
async exec({ app, env, force }) {
// Your logic here
return {
content: [{
type: 'text',
text: `Deploying ${app} to ${env}${force ? ' (forced)' : ''}`
}]
};
}
};Key points:
- ✅ Must export an
execasync function - ✅ Use Zod schemas for
inputSchema(not JSON Schema) - ✅ Return
{ content: [{ type: 'text', text: '...' }] } - Can export a function that receives
{ config, server, root, package } - Should be part of the
toolsfolder.
MDX Tool
---
title: Deploy Application
description: Deploy to environments
annotations:
category: deployment
---
{async ({ app, env, force }, ctx) => {
const timestamp = new Date().toISOString();
return {
content: [{
type: 'text',
text: `Deploying ${app} to ${env}${force ? ' (forced)' : ''}`
}],
structuredContent: {
status: 'deployed',
deployedAt: timestamp
}
};
}}
{JSON.stringify({ status: 'deployed', env: 'prod' })}
MDX Components:
- `` - Define input parameters
- `` - Define output structure (optional)
- `` - Execution function (required)
- `
- Usage examples withand`
Tool MDX Component Props
``
| Prop | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Identifier for the input parameter. Must be unique within the tool and becomes the object key passed to exec. |
type | string | ❌ | Expected data type. Supports string, number, integer, boolean, array, and object. Defaults to string. Supplying a Zod schema instance is also supported. |
required | boolean | ❌ | When true, the generated Zod schema marks the parameter as required. Defaults to optional. |
default | any | ❌ | Provides a default value on the Zod schema (ignored if required is true). |
enum | any[] | ❌ | Restricts the value to the provided choices. Values are stringified before constructing the enum schema. |
minimum / maximum | number | ❌ | Applies numeric bounds or string length limits, depending on the type. |
items | object | ❌ | Defines the element schema when type="array". Accepts the same shape options as `` itself. |
label / description | string | ❌ | Optional metadata useful for documentation or future UIs. Currently not interpreted by the runtime. |
All additional props are forwarded to the schema builder, which ignores unknown options.
``
| Prop | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Identifier for the output field; used to build the tool's outputSchema. |
type | string | ❌ | Same options as `, defaulting to string`. Supplying a Zod schema instance is also supported. |
enum | any[] | ❌ | Restricts the returned value to the provided options. |
minimum / maximum | number | ❌ | Applies bounds identical to ``. |
items | object | ❌ | Element schema when type="array". |
label / description | string | ❌ | Optional metadata. |
Unlike inputs, default values are ignored for outputs to prevent masking missing data.
``
- children: supply an async function (or array containing one). The first function child is captured and used as the tool's
exechandler. Receives(args, context)just like JavaScript tools.
``
- title: optional string shown alongside the example.
- children: include exactly one `
and oneto document inputs and outputs. Multiple` blocks are allowed per tool.
``
| Prop | Type | Required | Description |
|---|---|---|---|
arguments | object | ❌ | Captured wholesale and stored with the example. Use this to show sample payloads. |
| _any_ | any | ❌ | Additional props are preserved, enabling custom documentation consumers to read extra metadata. |
The component has no rendered body; it simply records the provided props.
``
- children: place sample output (any MDX content). Text is flattened to plain strings for storage.
- mime: optional string describing the sample response type.
Resources
Resources provide data. They can be authored in JavaScript/TypeScript, MDX, or plain Markdown.
JavaScript Resource
// resources/docs.js
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
export default {
title: 'Documentation',
description: 'Access project documentation',
uri: 'docs://{section}',
async read({ params }) {
const content = await loadDoc(params.section);
return {
contents: [{
uri: params.uri,
mimeType: 'text/markdown',
text: content
}]
};
},
async list() {
return {
resources: [
{ uri: 'docs://getting-started', name: 'Getting Started' },
{ uri: 'docs://api', name: 'API Reference' }
]
};
}
};Key points:
- ✅ Must export a
readasync function - ✅ Provide
uriortemplatefor URI pattern - Optional
list()function for resource discovery - Return
{ contents: [{ uri, mimeType, text }] } - Should be part of the
resourcesfolder.
MDX Resource
---
title: API Documentation
description: REST API reference
uri: api://{version}/{endpoint}
mime: text/markdown
---
# API Endpoint: {params.endpoint}
Version: {params.version}
Access this endpoint at `{{ config.apiBaseUrl }}/{{ params.version }}/{{ params.endpoint }}`
MDX Components:
- `` - Resource content
- `
+ ` - Discoverable resources
- `` - Override metadata dynamically
- `` - Embed other resources
Resource MDX Component Props
``
- mime: optional MIME type override for the rendered body. Defaults to the front-matter
mimeortext/markdown. - children: main resource content; flattened to plain text.
`
`
- Acts as a container for `` children. It does not accept its own props.
``
| Prop | Type | Required | Description |
|---|---|---|---|
params | object | ❌ | Parameter values applied when generating URIs from templates (e.g., { version: 'v1' }). |
uri | string | ❌ | Explicit URI for the listing item. When omitted, the discovery layer resolves the URI from the parent file path and params. |
title | string | ❌ | Human-friendly name surfaced in discovery responses. |
description | string | ❌ | Additional detail shown alongside the listing entry. |
name | string | ❌ | Override for the resource's registration name. |
``
- title: overrides the resource title after front-matter is parsed.
- description: overrides the resource description.
``
- uri: required. Embeds a reference to another resource and renders as
[uri]in the body.
Plain Markdown Resource
---
title: Getting Started Guide
description: How to get started
uri: resource://guides/getting-started
mime: text/markdown
author: Engineering Team
version: 1.2.0
---
# Getting Started
Welcome to {{ package.name }}!
**Guide Version:** {{ version }}
**Author:** {{ author }}
**Server Config:** {{ config.environment }}
This guide will help you get up and running quickly.Key points:
- ✅ Front-matter defines
uri,mime, and metadata - ✅ Body is plain Markdown with
{{ template }}variables - ✅ Access to
frontMatter,params,config,package - Perfect for static documentation
Prompts
Prompts are templated conversations. They can be authored in JavaScript/TypeScript, MDX, or plain Markdown.
JavaScript Prompt
// prompts/code-review.js
import { z } from 'zod';
export default {
title: 'Code Review Assistant',
description: 'Help review code with specific focus areas',
argsSchema: {
language: z.string(),
focusAreas: z.array(z.string()).default([]),
severity: z.enum(['strict', 'moderate', 'lenient']).default('moderate')
},
async exec({ language, focusAreas, severity }) {
return {
messages: [
{
role: 'system',
content: {
type: 'text',
text: `You are a ${severity} code reviewer specializing in ${language}.`
}
},
{
role: 'user',
content: {
type: 'text',
text: `Please review this code. Focus on: ${focusAreas.join(', ') || 'general best practices'}.`
}
}
]
};
}
};Key points:
- ✅ Must export an
execasync function - ✅ Use Zod schemas for
argsSchema(not JSON Schema) - ✅ Return
{ messages: [{ role, content: { type, text } }] } - Can include
resourcesarray for embeddings - Should be part of the
promptsfolder.
MDX Prompt
---
title: Code Review Assistant
description: Help review code
argsSchema:
language: string
focusAreas:
type: array
items: string
severity:
type: string
enum: [strict, moderate, lenient]
---
You are a {args.severity ?? 'moderate'} code reviewer specializing in {args.language}.
Please review this code.
Focus areas: {args.focusAreas?.join(', ') ?? 'general best practices'}
MDX Components:
- `
- Add messages (roles:assistant,user,system,tool`) - `` - Define prompt arguments (generates Zod schemas)
- `` - Embed or link resources
Prompt MDX Component Props
``
| Prop | Type | Required | Description |
|---|---|---|---|
role | string | ❌ | Sets the message role. Supports assistant, user, system, and tool. Defaults to assistant. |
name | string | ❌ | Optional identifier for the message. Useful when multiple tool messages need to be distinguished. |
| _children_ | MDX | ❌ | Body text for the message; flattened to plain strings. |
``
| Prop | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Argument key exposed to the prompt consumer. Must be unique. |
type | string | ❌ | One of string, number, integer, boolean, array, or object. Defaults to string. |
label | string | ❌ | Friendly display label. Stored with the schema for use by clients. |
description | string | ❌ | Longer help text for UI presentation. |
required | boolean | ❌ | Marks the argument as mandatory. Defaults to optional. |
default | any | ❌ | Provides a default value when omitted. |
enum | any[] | ❌ | Restricts the argument to a discrete set of values. |
items | object | ❌ | Element schema when type="array". |
minimum / maximum | number | ❌ | Applies numeric or length bounds, mirroring ``. |
Unknown props are forwarded to the schema builder and currently ignored.
``
| Prop | Type | Required | Description |
|---|---|---|---|
uri | string | ✅ | Identifies the resource to associate with the prompt. |
mode | string | ❌ | Either link (default) or embed. embed records the URI for inclusion in prompt outputs and emits [uri] inline. |
Plain Markdown Prompt
---
title: Code Review Assistant
description: Review code with AI assistance
author: Engineering Team
argsSchema:
language: string
severity: string
---
You are a {{ severity }} code reviewer specializing in {{ args.language }}.
Please review the following code carefully and provide feedback.
**Reviewer:** {{ author }}
**Project:** {{ package.name }}Key points:
- ✅ Front-matter defines
argsSchemaand metadata - ✅ Body becomes a single
assistantrole message - ✅ Template variables:
{{ args.* }},{{ config.* }},{{ package.* }}, and any front-matter fields - Perfect for simple, single-message prompts
Instructions
The instructions.md file at your server root provides server-level guidance to AI clients.
Example
---
title: My AI Server
version: 2.0
team: Engineering
---
# {{ title }}
Version {{ version }} - Maintained by {{ team }}
This server provides tools and resources for {{ package.description }}.
**Environment:** {{ config.environment }}
**Server Path:** {{ dir }}
## Available Capabilities
Use the tools in this server to automate deployment, access documentation, and get code review assistance.Template variables:
...frontMatter- Any fields from front-matterconfig- Server configuration objectpackage- Contents ofpackage.jsondir- Absolute path to server root
Template Variables
All .md files support {{ variable }} interpolation with dot notation.
Common Variables
| Variable | Available In | Description |
|---|---|---|
args.* | Prompts | Arguments passed to prompt |
params.* | Resources | URI template parameters |
config.* | All | Server configuration |
package.* | All | package.json contents |
dir | Instructions | Server root directory |
context.* | Prompts, Resources | Execution context |
...frontMatter | All | Any custom front-matter fields |
Examples
{{ args.task }} # Prompt argument
{{ params.id }} # Resource URI parameter
{{ config.apiKey }} # Server configuration
{{ package.name }} # From package.json
{{ package.version }} # Package version
{{ title }} # From front-matter
{{ author }} # Custom front-matter field
{{ config.database.host }} # Nested with dot notationNote: Objects are automatically JSON stringified: {{ config.database }} → {"host":"localhost","port":5432}
Schema Definitions
Zod Schemas (JavaScript)
Required format for JavaScript tools and prompts:
import { z } from 'zod';
export default {
inputSchema: {
name: z.string().min(1),
age: z.number().int().positive(),
email: z.string().email().optional(),
tags: z.array(z.string()).default([])
},
exec: async ({ name, age, email, tags }) => { ... }
};Simple Schemas (Front-matter)
For MDX and MD files, use simplified schema syntax in front-matter:
argsSchema:
name: string # Simple type
age:
type: integer
minimum: 0
email:
type: string
format: email
tags:
type: array
items: string
default: []Uprising automatically converts these to Zod validators.
Supported types: string, number, integer, boolean, array, object
Supported modifiers: minimum, maximum, enum, default, required, format
Best Practices
1. Choose the Right Format
| Format | Use When | Example |
|---|---|---|
| JavaScript | Complex logic, TypeScript needed, external APIs | Tools with business logic |
| MDX | Interactive examples, structured I/O, complex prompts | Tools with demos, multi-message prompts |
| Markdown | Static content, simple templates | Documentation resources, basic prompts |
2. Schema Design
// ✅ DO: Use descriptive names and validation
inputSchema: {
deploymentTarget: z.string().min(1),
environment: z.enum(['dev', 'staging', 'prod']),
config: z.object({ ... }).optional()
}
// ❌ DON'T: Use JSON Schema format
inputSchema: {
type: 'object',
properties: { ... } // ❌ This will error!
}3. Tool Organization
tools/
├── deployment/
│ ├── deploy.js
│ └── rollback.js
├── testing/
│ └── run-tests.js
└── utilities/
└── format-code.jsTool names will be: deployment-deploy, deployment-rollback, testing-run-tests, utilities-format-code
4. Error Handling
async exec({ input }) {
try {
const result = await doSomething(input);
return {
content: [{ type: 'text', text: result }]
};
} catch (error) {
// Errors are automatically caught and formatted
throw new Error(`Failed to process: ${error.message}`);
}
}Uprising automatically wraps errors in proper MCP format.
5. Configuration
// tools/api-call.js
export default ({ config }) => ({
title: 'Call API',
description: 'Make API requests',
inputSchema: { endpoint: z.string() },
async exec({ endpoint }) {
const baseUrl = config.apiBaseUrl ?? 'https://api.example.com';
const response = await fetch(`${baseUrl}${endpoint}`);
// ...
}
});Access config by exporting a factory function.
6. Dynamic Resources
// resources/user/[id].js
export default {
title: 'User Profile',
description: 'Get user by ID',
uri: 'user://{id}', // {id} from file path [id].js
async read({ params }) {
const user = await db.users.find(params.id);
return {
contents: [{
uri: params.uri,
mimeType: 'application/json',
text: JSON.stringify(user, null, 2)
}]
};
}
};Use [param] in folder/file names for Next.js-style dynamic segments.
Directory Layout
my-server/
├── instructions.md # Server instructions (optional)
├── package.json # Metadata (optional)
│
├── tools/ # Tools must be .js or .mdx
│ ├── simple-tool.js # Basic JavaScript tool
│ ├── advanced-tool.mdx # MDX with examples
│ └── nested/
│ └── subtool.js # → tool name: "nested-subtool"
│
├── resources/ # Can be .js, .mdx, or .md
│ ├── static-doc.md # Plain markdown (static)
│ ├── dynamic-doc.mdx # MDX with components
│ ├── api.js # JavaScript (dynamic)
│ └── users/
│ └── [id].js # → URI: "resource://users/{id}"
│
└── prompts/ # Can be .js, .mdx, or .md
├── simple.md # Single-message prompt
├── complex.mdx # Multi-message with components
└── custom.js # Full controlFile Naming:
- Filename becomes the registration name (e.g.,
deploy-app.js→deploy-app) - Override with
nameproperty in definition - Nested paths use dashes (e.g.,
api/users.js→api-users) [param]syntax creates URI templates with{param}
Tool Reference
Required Properties
{
exec: async (args, context) => { ... } // Required
}Optional Properties
{
name: 'custom-name', // Override filename
title: 'Human Title', // Display name
description: 'What it does', // Description
inputSchema: { ... }, // Zod schemas for inputs
outputSchema: { ... }, // Zod schemas for outputs (MDX only)
annotations: { ... } // Custom metadata
}Context Object
async exec(args, context) {
context.config // Server configuration
context.server // Uprising instance
context.root // Server directory
context.package // package.json data
}Resource Reference
Required Properties
{
read: async ({ params, variables }) => { ... }, // Required
uri: 'scheme://{param}' // Required (or template)
}Optional Properties
{
name: 'custom-name', // Override filename
title: 'Human Title', // Display name
description: 'What it provides', // Description
template: 'scheme://{param}', // Alternative to uri
list: async () => { ... }, // Resource discovery
mime: 'text/markdown' // MIME type override
}Prompt Reference
Required Properties
{
exec: async (args, context) => { ... } // Required
}Optional Properties
{
name: 'custom-name', // Override filename
title: 'Human Title', // Display name
description: 'What it does', // Description
argsSchema: { ... }, // Zod schemas for arguments
annotations: { ... } // Custom metadata
}Return Format
{
messages: [
{
role: 'system' | 'assistant' | 'user' | 'tool',
content: { type: 'text', text: '...' },
name: 'optional-name' // Optional
}
],
resources: [ // Optional - resources to embed
{ uri: 'resource://...' }
]
}CLI Usage
Start Server
npx uprising ./my-serverWith Configuration
Pass JSON configuration via environment variable or config file (if supported by your MCP client).
MCP Integration
Claude Desktop
Add to ~/.config/claude/servers (or platform-specific path):
{
"my-server": {
"command": "npx",
"args": ["uprising", "/absolute/path/to/my-server"]
}
}VS Code / Cursor
Configure in your MCP settings with the uprising command.
Custom Integration
import { Uprising } from 'uprising';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const uprising = new Uprising('./my-server', {
apiKey: process.env.API_KEY,
environment: 'production'
});
await uprising.start(new StdioServerTransport());API Validation
Uprising validates definitions during discovery and throws clear errors:
Common Errors
Missing exec function:
Error: Tool "my-tool" in tools/my-tool.js must have an 'exec' function.Using JSON Schema instead of Zod:
Error: Tool "my-tool" uses JSON Schema format for 'inputSchema', but Uprising expects Zod schemas.
Expected: { name: z.string(), ... }
Got: { type: 'object', properties: { ... }, ... }
Fix: Import 'zod' and use Zod schema objects.Wrong method name for resources:
Error: Resource "my-resource" must have a 'read' function.Advanced Features
Factory Functions
Export a function to access configuration:
// tools/configured-tool.js
export default ({ config, server, root, package }) => ({
title: 'Configured Tool',
inputSchema: { ... },
async exec(args) {
// Access config.myValue, server, etc.
}
});Resource Listings
export default {
uri: 'resource://docs/{section}',
async read({ params }) { ... },
async list() {
return {
resources: [
{ uri: 'resource://docs/api', name: 'API Docs', title: 'API' },
{ uri: 'resource://docs/guide', name: 'Guide', title: 'User Guide' }
]
};
}
};Multiple Definitions in One File
// resources/api/endpoints.js
export default [
{
name: 'users-api',
uri: 'api://users',
read: async () => { ... }
},
{
name: 'products-api',
uri: 'api://products',
read: async () => { ... }
}
];Structured Tool Output
async exec({ input }) {
return {
content: [{ type: 'text', text: 'Success!' }],
structuredContent: {
status: 'completed',
processedAt: new Date().toISOString(),
result: { ... }
}
};
}Debugging
Enable diagnostic logging:
DIAGNOSTICS='uprising:*' npx uprising ./my-serverOr specific namespaces:
DIAGNOSTICS='uprising:mcp' npx uprising ./my-serverPackage.json
Uprising uses package.json for server metadata if present:
{
"name": "my-ai-server",
"version": "1.0.0",
"description": "Custom AI capabilities",
"type": "module"
}These values become available in templates and default server info.
Exports
import {
Uprising, // Main class
start, // Convenience starter
template, // Templating helper
Mdx // MDX loaders (advanced)
} from 'uprising';Requirements
- Node.js 18+ (ESM support required)
zodpackage for schema definitions
License
MIT
