diff --git a/docs/mra_reference.rst b/docs/mra_reference.rst
index fd049f5db67d57a00bc4e6b94e8f4c31a3cb7fcb..f8b856238ac00fa39164e47550b4c15d3a688cc2 100644
--- a/docs/mra_reference.rst
+++ b/docs/mra_reference.rst
@@ -72,12 +72,6 @@ See `Mapfile specification`_ for more information about the Mapfile.
 Operations
 ----------
 
-For current version of MapServer Rest API, manipulate a ``mapfile`` is not implemented.
-And so, you can't create, modify or delete a mapfile.
-Please use the `mapfile model`_ and just give us some time to implement this operations.
-
-.. _Mapfile model: https://github.com/neogeo-technologies/mra/blob/develop/docs/model.map
-
 ``/maps.<format>``
 ^^^^^^^^^^^^^^^^^^
 
@@ -88,7 +82,9 @@ Please use the `mapfile model`_ and just give us some time to implement this ope
 +========+=================================+=============+====================+
 | GET    | List all mapfiles               | 200         | XML, JSON, HTML    |
 +--------+---------------------------------+-------------+--------------------+
-| POST   | *TODO: Create a new mapfile*    |             |                    |
+| POST   | Create a new mapfile            | 201 with    | XML, JSON          |
+|        |                                 | ``location``|                    |
+|        |                                 | header      |                    |
 +--------+---------------------------------+-------------+--------------------+
 | PUT    |                                 | 405         |                    |
 +--------+---------------------------------+-------------+--------------------+
@@ -98,7 +94,7 @@ Please use the `mapfile model`_ and just give us some time to implement this ope
 
 *Exceptions:*
 
-*	*TODO: POST for a mapfile already exist: 409 Conflict*
+*	POST for a mapfile already exist: 409 Conflict
 
 
 ``/maps/<map>.<format>``
@@ -116,7 +112,7 @@ Please use the `mapfile model`_ and just give us some time to implement this ope
 +--------+---------------------------------+-------------+--------------------+
 | PUT    | *TODO: Modify mapfile <map>*    |             |                    |
 +--------+---------------------------------+-------------+--------------------+
-| DELETE | *TODO: Delete mapfile <map>*    |             |                    |
+| DELETE | Delete mapfile <map>            |             |                    |
 +--------+---------------------------------+-------------+--------------------+
 
 *Exceptions:*
diff --git a/src/mapfile.py b/src/mapfile.py
index 34e98247b65d42ee8a6b2b33dfb6e2a8d0af30e6..b9665ddda868d8c0f9fbfca6dcfdbc63c1a10d00 100644
--- a/src/mapfile.py
+++ b/src/mapfile.py
@@ -721,15 +721,22 @@ class Mapfile(MetadataMixin):
         # We have one workspace that represents the file.
         self.__default_workspace = MapfileWorkspace(self)
 
-
     def save(self, path=None):
         if path is None:
             path = self.path
         self.ms.save(path)
 
+    def delete(self, path=None):
+        if path is None:
+            path = self.path
+        os.remove(path)
+
     def rawtext(self):
         open(self.path, "r").read()
 
+    def update(self, configuration):
+        raise NotImplemented()
+
     # Layers:
 
     def iter_ms_layers(self, attr={}, meta={}, mra={}):
diff --git a/src/maptools.py b/src/maptools.py
index 3ab59418a424b64299cc71324491776274da64f0..fb18c58bd29ced8fb5a074e78bb737dbfd93015b 100644
--- a/src/maptools.py
+++ b/src/maptools.py
@@ -24,7 +24,96 @@
 #                                                                       #
 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
+from webapp import KeyExists
+import metadata
+
 import mapscript
+import os.path
+
+def create_mapfile(path, map_name, data):
+    if os.path.exists("%s.map" % path):
+        raise KeyExists(map_name)
+
+    mf = mapscript.mapObj()
+    mf.name = map_name
+    
+    # The following could be defined in <mapfile.py>:
+
+    mf.web.metadata.set("ows_name", map_name)
+    mf.web.metadata.set("ows_title", data.get("title", map_name))
+    mf.web.metadata.set("ows_abstract", data.get("abstract", ""))
+
+    # Set default values:
+    # It should be configurable to the future.
+
+    # mf.web.metadata.set("ows_keywordlist", "")
+    # mf.web.metadata.set("ows_keywordlist_vocabulary", "")
+    # + ows_keywordlist_[vocabulary’s name]_items
+    # mf.web.metadata.set("wms_onlineresource", "")
+    # mf.web.metadata.set("wfs_onlineresource", "")
+    # mf.web.metadata.set("wms_service_onlineresource", "")
+    # mf.web.metadata.set("wfs_service_onlineresource", "")
+    mf.web.metadata.set("wms_srs", "EPSG:4326")
+    mf.web.metadata.set("wfs_srs", "EPSG:4326")
+    mf.web.metadata.set("wms_bbox_extended", "true")
+    # mf.web.metadata.set("wms_resx", "")
+    # mf.web.metadata.set("wms_resy", "")
+    mf.web.metadata.set("wms_enable_request", "GetCapabilities !GetMap !GetFeatureInfo !GetLegendGraphic")
+    mf.web.metadata.set("wfs_enable_request", "GetCapabilities !DescribeFeatureType !GetFeature")
+    mf.web.metadata.set("ows_sld_enabled", "true")
+    # mf.web.metadata.set("ows_schemas_location", "")
+    # mf.web.metadata.set("ows_updatesequence", "")
+    # mf.web.metadata.set("ows_addresstype", "")
+    # mf.web.metadata.set("ows_address", "")
+    # mf.web.metadata.set("ows_city", "")
+    # mf.web.metadata.set("ows_stateorprovince", "")
+    # mf.web.metadata.set("ows_postcode", "")    
+    # mf.web.metadata.set("ows_contactperson", "")
+    # mf.web.metadata.set("ows_contactposition", "")
+    # mf.web.metadata.set("ows_contactorganization", "")
+    # mf.web.metadata.set("ows_contactelectronicmailaddress", "")
+    # mf.web.metadata.set("ows_contactfacsimiletelephone", "")
+    # mf.web.metadata.set("ows_contactvoicetelephone, "")"
+    # mf.web.metadata.set("wms_fees", "")
+    # mf.web.metadata.set("wfs_fees", "")
+    # mf.web.metadata.set("wms_accessconstraints", "")
+    # mf.web.metadata.set("wfs_accessconstraints", "")
+    # mf.web.metadata.set("ows_attribution_logourl_format", "")
+    # mf.web.metadata.set("ows_attribution_logourl_height", "")
+    # mf.web.metadata.set("ows_attribution_logourl_href", "")
+    # mf.web.metadata.set("ows_attribution_logourl_width", "")
+    # mf.web.metadata.set("ows_attribution_onlineresource", "")
+    # mf.web.metadata.set("ows_attribution_title", "")
+    mf.web.metadata.set("wms_encoding", "UTF-8")
+    mf.web.metadata.set("wfs_encoding", "UTF-8")
+    # mf.web.metadata.set("wms_getcapabilities_version", "")
+    # mf.web.metadata.set("wfs_getcapabilities_version", "")
+    # mf.web.metadata.set("wms_getmap_formatlist", "")
+    # mf.web.metadata.set("wms_getlegendgraphic_formatlist", "")
+    # mf.web.metadata.set("wms_feature_info_mime_type", "")
+    # mf.web.metadata.set("wms_timeformat", "")
+    # mf.web.metadata.set("wms_languages", "")
+    # mf.web.metadata.set("wms_layerlimit", "")
+    # mf.web.metadata.set("wms_rootlayer_abstract", "")
+    # mf.web.metadata.set("wms_rootlayer_keywordlist", "")
+    # mf.web.metadata.set("wms_rootlayer_title", "")
+    # mf.web.metadata.set("wfs_maxfeatures", "")
+    # mf.web.metadata.set("wfs_feature_collection", "")
+    # mf.web.metadata.set("wfs_namespace_uri", "")
+    # mf.web.metadata.set("wfs_namespace_prefix", "")
+    # ...
+
+    mf.status = mapscript.MS_ON
+    mf.setSize(256,256)
+    mf.maxsize = 4096
+    mf.resolution = 96
+    mf.imagetype = 'png'
+    mf.imagecolor.setRGB(255,255,255)
+    mf.setProjection("init=epsg:4326")
+    mf.setExtent(-180,-90,180,90)
+    mf.units = mapscript.MS_DD
+
+    mf.save("%s.map" % path)
 
 def create_def_polygon_class(layer, s_name='default_polygon'):
     layer.classgroup = s_name
diff --git a/src/server.py b/src/server.py
index 33388990818ce75f5c9034922c9ff72f47f08c53..ab31b3887d67da0bfe6ae99754ec4cba330047f9 100755
--- a/src/server.py
+++ b/src/server.py
@@ -37,6 +37,7 @@ import webapp
 from webapp import HTTPCompatible, urlmap, get_data
 
 import tools
+import maptools
 from tools import get_mapfile, get_mapfile_workspace, get_config, href
 
 from pyxml import Entries
@@ -87,11 +88,15 @@ class mapfiles(object):
         return {"mapfiles": mapfiles}
 
     @HTTPCompatible()
-    def POST(self, map_name, format):
-        data = get_data()
+    def POST(self, format):
+        data = get_data(name="mapfile", mandatory=["name"], authorized=["name", "title", "abstract"])
+
+        map_name = data.pop("name")
+        path = tools.mk_mapfile_path(map_name)
+
+        with webapp.mightConflict("Mapfile", mapfile=map_name):
+            maptools.create_mapfile(path, map_name, data)
 
-        # TODO: Create mapfile
-        raise NotImplemented()
         webapp.Created("%s/maps/%s%s" % (web.ctx.home, map_name, (".%s" % format) if format else ""))
 
 
@@ -108,6 +113,30 @@ class named_mapfile(object):
                     "content": data})
             } if format != "map" else data
 
+    @HTTPCompatible()
+    def PUT(self, map_name, format):
+        mf = get_mapfile(map_name)
+        path = tools.mk_mapfile_path(map_name)
+
+        data = get_data(name="mapfile", mandatory=["name"], authorized=["name", "title", "abstract"])
+        if map_name != data.pop("name"):
+            raise webapp.Forbidden("Can't change the name of a mapfile.")
+        
+        with webapp.mightConflict("Mapfile", mapfile=map_name):
+            mf.update(data)
+
+        mf.save()
+
+    @HTTPCompatible()
+    def DELETE(self, map_name, format):
+        mf = get_mapfile(map_name)
+        path = tools.mk_mapfile_path(map_name)
+
+        # TODO: We need to check if this mapfile is empty.
+
+        with webapp.mightConflict("Mapfile", mapfile=map_name):
+            mf.delete()
+
 
 class workspaces(object):
     @HTTPCompatible()
diff --git a/src/tools.py b/src/tools.py
index 8429aa69e7b8916c0d84dbf0a955cdf66600a5d7..1d3590d6de48c407de35087cd2eadd024f9c97e6 100644
--- a/src/tools.py
+++ b/src/tools.py
@@ -49,6 +49,7 @@ def get_config(key=None, mode='r'):
             exit('Error in configuration file: %s' % exc)
     return __config if key == None else __config[key] if key in __config else {}
 
+
 def get_mapfile_paths():
     """Generates a list of mapfile paths managed by Mapserver REST API."""
 
@@ -86,6 +87,9 @@ def safe_path_join(root, *args):
         raise webapp.Forbidden(message="path '%s' outside root directory." % (args))
     return full_path
 
+def get_mapfile_path(*args):
+    return safe_path_join(get_config('storage')['mapfiles'], *args)
+
 def get_resource_path(*args):
     return safe_path_join(get_config('storage')['resources'], *args)
 
@@ -118,14 +122,18 @@ def iter_styles(mapfile=None):
             if f not in used_styles:
                 yield f
 
-
 def mk_path(path):
     dirs = os.path.dirname(path)
     if not os.path.isdir(dirs):
         os.makedirs(dirs)
 
+def mk_mapfile_path(name, *args):
+    path = get_mapfile_path(name, *args)
+    mk_path(path)
+    return path
+
 def mk_ds_data_path(ws_name, name, *args):
-    path = get_dws_data_path(name, *args)
+    path = get_ds_data_path(name, *args)
     mk_path(path)
     return path