Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ RUN mkdir src

COPY src/ ./src/
COPY resources ./resources/
COPY plugins ./plugins/

WORKDIR /app/src
#WORKDIR /app/src
# Expose the gRPC port
EXPOSE 50052

# Run the server
CMD ["python", "server.py"]
CMD ["python", "src/server.py"]
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ build:
load:
kind load docker-image $(IMAGE_LOCAL) --name mcp-gateway

podname := $(shell kubectl get pods -A |grep my-extproc | grep -v Terminating | awk '{print $$2}')
podname := $(shell kubectl get pods -A |grep ${IMAGE_BASE} | grep -v Terminating | awk '{print $$2}')
log:
kubectl logs ${podname} -n istio-system -f

Expand Down
8 changes: 5 additions & 3 deletions ext-proc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ spec:
containers:
- name: plugins-adapter
image: plugins-adapter:0.1.0
# command: ["bash", "-c","--"]
# args: ["while true; do sleep 3600; done"]
# imagePullPolicy: IfNotPresent
#command: ["bash", "-c","--"]
#args: ["while true; do sleep 3600; done"]
#imagePullPolicy: IfNotPresent
env:
- name: PLUGINS_SERVER_HOST
value: "0.0.0.0"
Expand All @@ -44,5 +44,7 @@ spec:
value: "./resources/config/config.yaml"
- name: PLUGIN_MANAGER_CONFIG
value: "./resources/config/config.yaml"
- name: PYTHONPATH
value: "./"
ports:
- containerPort: 50052
244 changes: 244 additions & 0 deletions plugins/examples/context_forge/internal/regex_filter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
# Search Replace Plugin for MCP Gateway

> Author: Teryl Taylor
> Version: 0.1.0

A native plugin for MCP Gateway that performs regex-based search and replace operations on prompt arguments and responses.

## Features

- **Pre-fetch Hook**: Modifies prompt arguments before prompt retrieval
- **Post-fetch Hook**: Modifies rendered prompt messages after processing
- **Regex Support**: Full regex pattern matching and replacement
- **Multiple Patterns**: Configure multiple search/replace pairs
- **Chain Transformations**: Apply replacements in sequence

## Installation

The plugin is included with MCP Gateway and requires no additional installation. Simply enable it in your configuration.

## Configuration

Add the plugin to your `plugins/config.yaml`:

```yaml
plugins:
- name: "SearchReplacePlugin"
kind: "plugins.regex_filter.search_replace.SearchReplacePlugin"
description: "Performs text transformations using regex patterns"
version: "0.1"
author: "ContextForge"
hooks: ["prompt_pre_fetch", "prompt_post_fetch"]
tags: ["transformer", "regex", "text-processing"]
mode: "enforce" # enforce | permissive | disabled
priority: 150 # Lower = higher priority
conditions:
- prompts: ["test_prompt", "chat_prompt"] # Apply to specific prompts
server_ids: [] # Apply to all servers
tenant_ids: [] # Apply to all tenants
config:
words:
- search: "crap"
replace: "crud"
- search: "damn"
replace: "darn"
- search: "\\bAI\\b" # Word boundary regex
replace: "artificial intelligence"
```

## Configuration Options

### Plugin Settings

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Unique plugin identifier |
| `kind` | string | Yes | Plugin class path |
| `hooks` | array | Yes | Hook points to enable |
| `mode` | string | No | Execution mode: `enforce`, `permissive`, or `disabled` |
| `priority` | integer | No | Execution order (default: 150) |
| `conditions` | array | No | Conditional execution rules |

### Search/Replace Configuration

| Field | Type | Description |
|-------|------|-------------|
| `words` | array | List of search/replace pairs |
| `words[].search` | string | Regex pattern to search for |
| `words[].replace` | string | Replacement text |

## Usage Examples

### Basic Word Replacement

```yaml
config:
words:
- search: "hello"
replace: "greetings"
- search: "goodbye"
replace: "farewell"
```

### Regex Pattern Matching

```yaml
config:
words:
# Replace email addresses with placeholder
- search: "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"
replace: "[email]"

# Replace phone numbers
- search: "\\b\\d{3}-\\d{3}-\\d{4}\\b"
replace: "[phone]"

# Case-insensitive replacement
- search: "(?i)microsoft"
replace: "MS"
```

### Chained Transformations

```yaml
config:
words:
# These apply in order
- search: "bad"
replace: "not good"
- search: "not good"
replace: "could be better"
# Result: "bad" → "not good" → "could be better"
```

## How It Works

### Pre-fetch Hook
1. Receives prompt name and arguments
2. Applies all configured patterns to each argument value
3. Returns modified arguments for prompt rendering

### Post-fetch Hook
1. Receives rendered prompt messages
2. Applies patterns to message content
3. Returns modified messages

## Testing

### Manual Testing

1. Enable the plugin in your configuration
2. Create a test prompt:
```bash
curl -X POST http://localhost:4444/prompts \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "test_prompt",
"template": "User said: {{ message }}",
"argument_schema": {
"type": "object",
"properties": {"message": {"type": "string"}},
"required": ["message"]
}
}'
```

3. Test the replacement:
```bash
curl -X GET http://localhost:4444/prompts/test_prompt \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"message": "This is crap"}'

# Expected: "User said: This is crud"
```

### Unit Testing

```python
import pytest
from plugins.regex_filter.search_replace import SearchReplacePlugin, SearchReplaceConfig

@pytest.mark.asyncio
async def test_search_replace():
config = PluginConfig(
name="test",
kind="plugins.regex_filter.search_replace.SearchReplacePlugin",
version="0.1",
hooks=["prompt_pre_fetch"],
config={
"words": [
{"search": "foo", "replace": "bar"}
]
}
)

plugin = SearchReplacePlugin(config)
payload = PromptPrehookPayload(
name="test",
args={"message": "foo is foo"}
)

result = await plugin.prompt_pre_fetch(payload, context)
assert result.modified_payload.args["message"] == "bar is bar"
```

## Performance Considerations

- Patterns are compiled once during initialization
- Regex complexity affects performance
- Consider priority when chaining with other plugins
- Use specific prompt conditions to limit scope

## Common Use Cases

1. **Profanity Filter**: Replace inappropriate language
2. **Terminology Standardization**: Ensure consistent terms
3. **PII Redaction**: Simple pattern-based PII removal
4. **Format Normalization**: Standardize date/time formats
5. **Abbreviation Expansion**: Expand common abbreviations

## Troubleshooting

### Patterns Not Matching
- Check regex syntax and escaping
- Test patterns with online regex tools
- Enable debug logging to see transformations

### Performance Issues
- Simplify complex regex patterns
- Reduce number of patterns
- Use prompt conditions to limit scope

### Unexpected Results
- Remember patterns apply in order
- Check for overlapping patterns
- Test with simple inputs first

## Available Hooks

The plugin manifest declares support for:
- `prompt_pre_hook` - Before prompt retrieval
- `prompt_post_hook` - After prompt rendering
- `tool_pre_hook` - Before tool execution (not implemented)
- `tool_post_hook` - After tool execution (not implemented)

Currently only prompt hooks are implemented.

## Contributing

To extend this plugin:

1. Add new transformation strategies
2. Implement tool hooks
3. Add pattern validation
4. Create preset pattern libraries

## License

Apache-2.0

## Support

For issues or questions, please open an issue in the MCP Gateway repository.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
description: "Search replace plugin manifest."
author: "ContextForge"
version: "0.1.0"
available_hooks:
- "prompt_pre_hook"
- "prompt_post_hook"
- "tool_pre_hook"
- "tool_post_hook"
default_configs:
Loading
Loading